From 290e9efbaabd882a91bbeccf7e370483007cc1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dante=20Ursini?= Date: Mon, 13 Jan 2025 20:11:35 -0300 Subject: [PATCH] Kitesurf fins --- Kitesurf-Fins.json | 88 + Kitesurf-Fins.scad | 344 + Readme.md | 2 + SurfFins.json | 38 +- SurfFins.scad | 149 +- stl/SurfFins_0.2_bottom.stl | Bin 0 -> 41384 bytes stl/SurfFins_0.2_top.stl | Bin 0 -> 41384 bytes stl/gcode/SurfFins_0.2_super_quality.gcode | 17025 +++++++++++++++++++ 8 files changed, 17558 insertions(+), 88 deletions(-) create mode 100644 Kitesurf-Fins.json create mode 100644 Kitesurf-Fins.scad create mode 100644 stl/SurfFins_0.2_bottom.stl create mode 100644 stl/SurfFins_0.2_top.stl create mode 100644 stl/gcode/SurfFins_0.2_super_quality.gcode diff --git a/Kitesurf-Fins.json b/Kitesurf-Fins.json new file mode 100644 index 0000000..18e2ad6 --- /dev/null +++ b/Kitesurf-Fins.json @@ -0,0 +1,88 @@ +{ + "fileFormatVersion": "1", + "parameterSets": { + "New set 1": { + "$fn": "32", + "base_extra_thickness": "80", + "base_tickness": "9", + "draw_fin": "false", + "draw_profile": "true", + "fin_back_angle": "20", + "fin_back_height": "30", + "fin_back_strength": "30", + "fin_back_widthdraw": "20", + "fin_back_withraw": "20", + "fin_base": "200", + "fin_counter_angle": "30", + "fin_counter_strength": "20", + "fin_end_angle": "110", + "fin_end_strength": "30", + "fin_height": "250", + "fin_start_angle": "70", + "fin_sweep": "25", + "fin_thickness": "5", + "fin_top_withdraw": "30", + "fin_width": "240", + "fin_width_tip": "5", + "parts": "all", + "scale_factor": "1", + "show_debug_layers": "false" + }, + "New set 2": { + "$fn": "32", + "base_extra_thickness": "80", + "base_tickness": "8", + "draw_fin": "false", + "draw_profile": "true", + "fin_back_angle": "20", + "fin_back_height": "30", + "fin_back_strength": "30", + "fin_back_widthdraw": "20", + "fin_back_withraw": "20", + "fin_base": "120", + "fin_counter_angle": "30", + "fin_counter_strength": "20", + "fin_end_angle": "110", + "fin_end_strength": "30", + "fin_height": "61", + "fin_start_angle": "70", + "fin_sweep": "25", + "fin_thickness": "8", + "fin_top_withdraw": "30", + "fin_width": "240", + "fin_width_tip": "5", + "parts": "all", + "scale_factor": "1", + "show_debug_layers": "false" + }, + "New set 3": { + "$fn": "32", + "base_extra_thickness": "80", + "base_tickness": "8", + "draw_fin": "true", + "draw_profile": "true", + "fin_back_angle": "20", + "fin_back_height": "30", + "fin_back_strength": "30", + "fin_back_widthdraw": "20", + "fin_back_withraw": "20", + "fin_base": "114", + "fin_counter_angle": "30", + "fin_counter_strength": "10", + "fin_edge_angle": "30", + "fin_edge_strength": "30", + "fin_end_angle": "110", + "fin_end_strength": "30", + "fin_height": "51", + "fin_start_angle": "60", + "fin_sweep": "25", + "fin_thickness": "8", + "fin_top_withdraw": "10", + "fin_width": "120", + "fin_width_tip": "5", + "parts": "all", + "scale_factor": "1", + "show_debug_layers": "true" + } + } +} diff --git a/Kitesurf-Fins.scad b/Kitesurf-Fins.scad new file mode 100644 index 0000000..dd61d3d --- /dev/null +++ b/Kitesurf-Fins.scad @@ -0,0 +1,344 @@ + +include ; +include ; +include ; +include ; + + +/************************************************/ +/* Parameters */ +/************************************************/ + +/* [Fin Specs] */ + +fin_height = 51; // 10 inches in mm +fin_width = 120; // Width at the base in mm +fin_top_withdraw = 10; +fin_back_withraw = 20; + +fin_start_angle = 60; // Angle [Point 0 ] +fin_sweep = 25; // Sweep Angle [Point 1] + +fin_edge_angle = 30; +fin_edge_strength = 30; + +fin_counter_angle = 30; // counter angle [Point 2] +fin_counter_strength = 10; // Length [Point 2] + +// Length at the base in mm +fin_base = 114; + + +fin_width_tip = 5; // Width at the tip in mm +fin_thickness = 8; // Thickness of the fin in mm + +fin_end_angle = 110; +fin_end_strength = 30; + +// Back +fin_back_height = 30; // Percent height +fin_back_widthdraw = 20; // Percent height +fin_back_angle = 20; // back angle +fin_back_strength=30; + +/* [Base Specs] */ + +base_tickness=8; +base_extra_thickness=80; + + +/* [Debugging] */ + +// Showing all layers +show_debug_layers = false; + +// Draw master profile +draw_profile = true; + +// Draw Fin +draw_fin = false; + +/* [Rendering] */ + +// Rendering parts +parts="all"; // [all, top, bottom] + +// Scaling +scale_factor = 1.0; // [0.1:0.1:2] + + +$fn=64; +/************************************************/ + + +pt1_x = adj_ang_to_opp(fin_height,fin_sweep)+fin_base/2; +pt1_y = fin_height; + +echo ("counterTop(fin_width,fin_top_withdraw)",counterTop(fin_width,fin_top_withdraw,fin_height)); + +echo ("handleEnd(fin_width,fin_top_withdraw,fin_counter_angle,fin_counter_strength)",handleEnd(fin_width,fin_top_withdraw,fin_counter_angle,fin_counter_strength)); +echo ("xAngleFactor(-20)",xAngleFactor(-20)); + +echo("polar_to_x : ",polar_to_xy(100, 180)); + +back_point = [fin_width-7,fin_height/2]; +tail_point = [fin_width-3,fin_height/5]; + +edge_point = [fin_width-fin_top_withdraw,fin_height-2]; +counter_edge_point = [fin_width-6,fin_height-8]; + + +control_points = [ + // ***************** + // INITIAL POINT + // ***************** + [0,0], // Point 0 + [opp_ang_to_adj(fin_height/3,fin_start_angle),fin_height/3], // Handle 0 + // ***************** + // TOP POINT + // ***************** + [pt1_x-fin_base/5,pt1_y], // Handle 1 (Start) + [pt1_x,pt1_y], // Point 1 + [pt1_x+fin_base/7,pt1_y], // Handle 1 (End) + // ***************** + // EDGE POINT + // ***************** + //counterTop(fin_width,fin_top_withdraw,fin_height), // [250,220], // Point 2 + handle(edge_point,140 /*degree*/,4), + edge_point, // [250,220], // Point 2 + handle(edge_point,-45 /*degree*/,4), + // ***************** + // COUNTER EDGE POINT + // ***************** + //counterTop(fin_width,fin_top_withdraw,fin_height), // [250,220], // Point 2 + handle(counter_edge_point,120 /*degree*/,4), + counter_edge_point, // [250,220], // Point 2 + handle(counter_edge_point,-110 /*degree*/,13), + + // ***************** + // BACK Point + // ***************** + //counterTop(fin_width,fin_top_withdraw,fin_height), // [250,220], // Point 2 + /* + handle(back_point,90 ,6), + back_point, + handle(back_point,-90 ,6), + */ + + // ***************** + // TAIL Point + // ***************** + + handle(tail_point,115 ,10), + tail_point, + //handle(tail_point,-90,10), + handle(tail_point,0,0), + //tailPoint(), + // ***************** + // BACK POINT + // ***************** + /* + handle(backPoint(),fin_back_angle,fin_back_strength), + backPoint(), + handle(backPoint(),-fin_back_angle,fin_back_strength), + */ + // ***************** + // END POINT + // ***************** + //endHandle(fin_end_angle), // End Handle + handle([fin_base,0],60 /*degree*/,3), + [fin_base,0] // End point +]; + + + +function handle(point,angle,strength) = [ + //point[0] + adj_ang_to_opp(strength,angle) /** xAngleFactor(angle)*/, + //point[1] + /*(angle>0 ? strength :-strength)*/ strength * yAngleFactor(angle), + point[0] + polar_to_xy(strength,angle)[0] , + point[1] + polar_to_xy(strength,angle)[1] + ]; + +function xAngleFactor(angle) = angle > 0 && angle < 180 ? 1 : -1; +function yAngleFactor(angle) = angle > -90 && angle < 90 ? 1 : -1; + +function counterTop(x,withdraw,height) = [x-withdraw, height ]; +function handleStart(x,withdraw,angle,strength) = [x+adj_ang_to_opp(strength,angle), x-withdraw +strength]; +function handleEnd(x,withdraw,angle,strength) = [x-adj_ang_to_opp(strength,angle), x-withdraw -strength]; +function endHandle(angle)= + angle < 90 ? + [fin_base + adj_ang_to_opp(fin_end_strength,90-angle),fin_end_strength] + : + [fin_base - adj_ang_to_opp(fin_end_strength,angle-90),fin_end_strength] + ; +function backPoint() = [fin_base-(fin_back_widthdraw/100*fin_base),fin_back_height/100*fin_height]; + + + + +function decrease_y(points, percentage) = [ for (p = points) [p[0], p[1] * (1 - percentage/100)]]; + +function pathProfile(points) = bezpath_curve(points,N=3); + +function remove_last(arr) = select(arr, 0, len(arr) - 2); + + +// Surf Fin profile +fin_profile = pathProfile( control_points ); + +// **************** +// * Slicing * +// **************** + +layer_0 = pathProcess(addBase(fin_profile)); // Master layer with base +layer_1 = pathProcess(offset(layer_0,delta=-5,chamfer=true)); +layer_2 = pathProcess(offset(layer_1,delta=-7,chamfer=false)); +layer_3 = pathProcess(offset(layer_2,delta=-5,chamfer=false)); +layer_4 = pathProcess(offset(layer_3,delta=-5,chamfer=false)); + + +//echo ("layer_2",layer_2); +//echo ("layer_3",layer_3); + + +layers = [layer_0,layer_1,layer_2,layer_3]; + + + +function pathProcess(path) = subdivide_path(path,200); +function pathProcess3(path) = path; + + + + +// **************** +// * Fin Drawing * +// **************** +if (draw_fin) { + + scale([scale_factor, scale_factor, scale_factor]) build(); +} + +module build() { + union(){ + //cube([50,50,90]); + difference(){ + union() { + if (parts != "bottom") buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); + if (parts != "top") zflip() buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); + } + color("Red") cube([fin_base+20,base_extra_thickness+20,base_tickness+20],anchor=LEFT+BACK); + } + } +} + + +module subtracted(anchor) { + color("Red") fwd(40) left(40) cube([fin_width+100,fin_height+100,20],anchor=anchor); +} + + +/** + * Build fin side + * + * @param layers - Layers path as array + * @param thickness - thickness of half fin + */ +module buildFinSide(layers,thickness,flip=false) { + color("Grey") + skin(layers,slices=0,z=layerHeights(len(layers),thickness)); +} + +echo ("layerHeights(3,thickness):",layerHeights(3,base_tickness/2)); + +if (show_debug_layers) { + left(300) { + showDebugPath(layer_0); + showDebugPath(layer_1); + showDebugPath(layer_2); + + assert(is_path(layer_3),"Layer 3 is not a path"); + showDebugPath(layer_3); + showDebugPath(layer_4); + } + //showDebugPath(layer_3); + +} +if (draw_profile) { + // Draw fin profile + drawProfile( control_points, true ); +} + + +/** + * Displays debug information for a path by visualizing its self-crossings. + * + * @param path - The input path to analyze for self-crossings. + * + * This module: + * - Splits the path at points where it intersects itself. + * - Renders each segment of the split path with different colors for easy identification. + */ +module showDebugPath(path) { + assert(is_path(path),"Path to show is not a path"); + assert(is_path_simple(path),"Path is not simple"); + rainbow(split_path_at_self_crossings(path)) + stroke($item, closed=false, width=1); +} + + +/** + * Draws a profile based on Bezier path points with optional debug visualization. + * + * @param points - Array of points defining the Bezier path. + * @param debug - Boolean flag to enable/disable debug visualization. Defaults to true. + * + * This module: + * - Calculates the closest point on the Bezier path to a fixed point. + * - Draws the Bezier path with debug information if debug is true. + * - Optionally shows spheres at specific points for debugging (currently commented out). + */ +module drawProfile( points,debug = true ){ + pt = [100,0]; + pos = bezpath_closest_point(points, pt); + xy = bezpath_points(points,pos[0],pos[1]); + debug_bezier(points, N=3,width=0.2); + //color("red") translate(pt) sphere(r=6); + //color("blue") translate(xy) sphere(r=6); +} + +/** + * Adds a base to the given path by extending it with additional points. + * + * @param path - The original path to which the base will be added. + * @return A new path with an added base. + * + * This function concatenates: + * - The original path (`pathProfile`). + * - A point `fin_base` which might represent the start or end of the base. + * - Points for additional thickness (`-base_extra_thickness`) at both ends of the base. + */ +function addBase(path) = concat(path,[[fin_base,-base_extra_thickness],[0,-base_extra_thickness]]); + + +/** + * Calculates heights for n layers where the first layer starts at 0 and the last at fin_thickness. + * + * @param n - Number of layers. + * @param fin_thickness - The total height to be divided. + * @return An array where each element represents the height of the top of each layer. + */ +function layerHeights(n, fin_thickness) = + let( + layer_height = fin_thickness / (n - 1) + ) + [ for (i = [0 : n-1]) i * layer_height ]; + + + +echo ("**********************"); +echo ("* Configuration *"); +echo ("**********************"); +echo ("Layers count" ,len(layers)); +echo ("Base thickness" ,str(base_tickness," mm")); +echo ("Layers heights" ,layerHeights(len(layers),base_tickness/2)); diff --git a/Readme.md b/Readme.md index f034d18..fec16a1 100644 --- a/Readme.md +++ b/Readme.md @@ -7,3 +7,5 @@ A project to create mold and makes surf fins in Fiber glass ## Box The box is designed using library [Fin Base](https://github.com/hrobeers/finbases) + +![](https://user-images.githubusercontent.com/2812522/105723055-9fd71100-5f26-11eb-8a9e-b892212b240b.jpg) diff --git a/SurfFins.json b/SurfFins.json index 9f3072b..6fab547 100644 --- a/SurfFins.json +++ b/SurfFins.json @@ -1,11 +1,45 @@ { "fileFormatVersion": "1", "parameterSets": { - "New set 1": { + "New set 1": "", + "Final": "", + "New set 2": { "$fn": "32", + "base_extra_thickness": "80", + "base_tickness": "9.1999999999999993", + "draw_box": "true", "draw_fin": "true", "draw_profile": "false", - "show_debug_layers": "true" + "fin_back_angle": "20", + "fin_back_height": "30", + "fin_back_strength": "30", + "fin_back_widthdraw": "20", + "fin_back_withraw": "20", + "fin_base": "200", + "fin_counter_angle": "30", + "fin_counter_strength": "20", + "fin_end_angle": "110", + "fin_end_strength": "30", + "fin_height": "250", + "fin_start_angle": "70", + "fin_sweep": "25", + "fin_thickness": "5", + "fin_top_withdraw": "30", + "fin_width": "240", + "fin_width_tip": "5", + "height": "25", + "mirror_vec": "[1, 1, 0]", + "parts": "top", + "pin_back": "9", + "pin_depth": "16.399999999999999", + "pin_dia": "3", + "scale_factor": "0.20000000000000001", + "screw_dia": "4.5", + "screw_pos": "9.5999999999999996", + "show_debug_layers": "false", + "tab_height": "13", + "thick": "9.1999999999999993", + "thick_cut": "1" } } } diff --git a/SurfFins.scad b/SurfFins.scad index e1f8284..bd6afb9 100644 --- a/SurfFins.scad +++ b/SurfFins.scad @@ -49,7 +49,7 @@ base_extra_thickness=80; /* [US Box] */ // Dimensions in mm //length = 180; -length=fin_base; +//length=fin_base; height = 25; thick = 9.2; mirror_vec = [1,1,0]; @@ -78,7 +78,6 @@ thick_cut = 1; - /* [Debugging] */ //Showing all layers @@ -90,6 +89,16 @@ draw_profile = false; draw_fin = true; draw_box = true; +/* [Rendering] */ + +// Rendering parts +parts="all"; // [all, top, bottom] + +// Scaling +scale_factor = 1.0; // [0.1:0.1:2] + + + $fn=32; /************************************************/ @@ -158,34 +167,61 @@ fin_profile = pathProfile( control_points ); layer_0 = addBase(fin_profile); // Master layer with base layer_1 = offset(layer_0,delta=-10,chamfer=true); -//layer_2 = offset(layer_0,delta=-20,chamfer=true); -layer_2 = offset(layer_1,delta=-15,chamfer=true); -//layer_3 = offset(layer_2,delta=-2,chamfer=true); - -layers= [layer_0,layer_1,layer_2]; -echo ("Layers count ",len(layers)); +layer_2 = offset(layer_1,delta=-15,chamfer=false); +layer_3 = offset(layer_2,delta=-10,chamfer=false); +layer_4 = offset(layer_3,delta=-10,chamfer=false); -// **************** -// * Box Drawing * -// **************** -if (draw_box) { - xflip() finfit(length, mirror_vec); -} +echo ("layer_2",layer_2); +echo ("layer_3",layer_3); + + +layers = [layer_0,layer_1,layer_2,layer_3]; +echo ("**********************"); +echo ("* Configuration *"); +echo ("**********************"); +echo ("Layers count" ,len(layers)); +echo ("Base thickness" ,str(base_tickness," mm")); +echo ("Layers heights" ,layerHeights(len(layers),base_tickness/2)); + // **************** // * Fin Drawing * // **************** if (draw_fin) { - difference(){ - union() { - buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); - zflip() buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); - + + scale([scale_factor, scale_factor, scale_factor]) build(); +} + +module build() { + union(){ + //cube([50,50,90]); + difference(){ + union() { + if (parts != "bottom") buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); + if (parts != "top") zflip() buildFinSide([layer_0,layer_1,layer_2],base_tickness/2); + } + color("Red") cube([fin_base+20,base_extra_thickness+20,base_tickness+20],anchor=LEFT+BACK); } - color("Red") cube([fin_base+20,base_extra_thickness+20,base_tickness+20],anchor=LEFT+BACK); - } + // **************** + // * Box Drawing * + // **************** + if (draw_box) { + difference() { + xflip() finfit(fin_base, mirror_vec); + if (parts == "top") + subtracted(TOP+LEFT+FRONT); + if (parts == "bottom") + subtracted(BOTTOM+LEFT+FRONT); + } + } + }; +}; + + +module subtracted(anchor) { + color("Red") fwd(40) left(40) cube([fin_width+100,fin_height+100,20],anchor=anchor); } @@ -196,80 +232,21 @@ if (draw_fin) { * @param thickness - thickness of half fin */ module buildFinSide(layers,thickness,flip=false) { - //right(200) - color("Grey") skin(layers,slices=0,z=layerHeights(len(layers),thickness)); + color("Grey") + skin(layers,slices=0,z=layerHeights(len(layers),thickness)); } - echo ("layerHeights(3,thickness):",layerHeights(3,base_tickness/2)); - - - - -if (false) { - - - - - - up (80) color("Green") polygon(path2); - - //path2[0][1] = 0; - - /* - path2b = concat( - [[0, 0]], // New first point - [for (i = [1:len(path2)-1]) path2[i]] // Rest of the points unchanged - ); - path3b = concat( - [[0, 0]], // New first point - [for (i = [1:len(path3)-1]) path3[i]] // Rest of the points unchanged - ); - echo("path2",path2); - echo("path2b",path2b); - */ - - //path2 = bezpath_curve(decrease_y(control_points,10),N=3); - - //path2 = offset_path(path, -20, closed=true); - - - if (false) up (10) color("Red") %polygon(path2); - if (false) up (12) color("Blue") %polygon(path3); - - - if (false) up(50) color("Green") offset_sweep(path, height=20, bottom=os_circle(r=10), top=os_circle(r=10), steps=15); - - sinwave = os_profile(points=[for(theta=[0:5:720]) [4*sin(theta), theta/700*15]]); - - if (false) up(80) color("Yellow") offset_sweep(path, height=20, top=sinwave, $fn=32); - - - lin_path=[[300,0,0],[300,20,0],[300,100,0]]; - //lin_path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ]; - - //up(80) path_extrude(lin_path) circle(r=30, $fn=6); //path; - //up(80) path_extrude(lin_path) [polygon(path),polygon(path2)]; //path; - - //skin([octagon(4), circle($fn=70,r=2)], z=[0,3], slices=10); - - - - - /* - path_extrude2d(path, caps=true, closed=false) - move_copies([[-3.5,1.5],[0.0,3.0],[3.5,1.5]]) - circle(r=1.5); - */ -} - - if (show_debug_layers) { left(300) { showDebugPath(layer_0); showDebugPath(layer_1); showDebugPath(layer_2); + + assert(is_path(layer_3),"Layer 3 is not a path"); + showDebugPath(layer_3); + showDebugPath(layer_4); } //showDebugPath(layer_3); diff --git a/stl/SurfFins_0.2_bottom.stl b/stl/SurfFins_0.2_bottom.stl new file mode 100644 index 0000000000000000000000000000000000000000..6c8fbdf51564493a94bda7e6b3f2a1be00e13dcc GIT binary patch literal 41384 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 literal 0 HcmV?d00001 diff --git a/stl/SurfFins_0.2_top.stl b/stl/SurfFins_0.2_top.stl new file mode 100644 index 0000000000000000000000000000000000000000..67e49858f463b509a644e5205bfdf0bca6b0c97a GIT binary patch literal 41384 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 QES5~CRNYoctLxYPKQCT58vp