diff --git a/Surf-Fins-10inch.scad b/Surf-Fins-10inch.scad new file mode 100644 index 0000000..8e210ec --- /dev/null +++ b/Surf-Fins-10inch.scad @@ -0,0 +1,556 @@ + +include ; +include ; +include ; +include ; +include ; + +include ; +include ; +include ; +include ; +include + + +/** + * Kitesurf Fins mold + * + * + * + * Requirements : + * - The plunger normaly should be twice the height of the part + * + */ + +/************************************************/ +/* Parameters */ +/************************************************/ + +/* [Fin Specs] */ + +// Height +fin_height = 254; // 10 inches in mm +// Top Width +fin_width = 270; // Width at the top in mm +// Base Width +fin_base = 130; // Width at the base in mm + + +// Define top point +fin_top_withdraw = 35; +fin_edge_withdraw = 15; + +fin_start_angle = 70; // 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_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=20; + +/* [Debugging] */ + +// Showing all layers +show_debug_layers = false; + +// Draw master profile +draw_profile = false; + +// Draw Fin +build_fin = false; + +/* [Mold] */ + +// Mold base height +mold_base_height = 10; +mold_top_height = 5; +mold_extra_width = 15; + +mold_piston_height = 10; + +resin_escape_diameter=4; + +// Diameter for screw holes in mm +merge_holes_diameter = 6; +piston_depth = 5; + +/* [Rendering] */ + +// Rendering parts +render_fin = false; +render_mold = true; +render_drill_template = false; + +parts = "all"; // [all, top, bottom] + + +mold_part = "all"; // [all, top, bottom] +// Scaling +scale_factor = 1.0; // [0.1:0.1:2] + +// Printable rendering +printable = true; + +$fn=64; + +/*************/ +/* Constants */ +/*************/ +/* [Hidden] */ +// Define the offset value as a constant +OFFSET = 0.01; +CLEARING = 0.1; +INCH=2.54; +X=0; +Y=1; +Z=2; + +/************************************************/ +/* Derived variable */ + +mold_width = fin_height +2 * mold_extra_width; +mold_length = fin_width +2 * mold_extra_width; +mold_height = mold_base_height; + +drilling_length = mold_base_height+mold_piston_height+2*OFFSET; + +start = [0,0]; + +pt1 = [ + adj_ang_to_opp(fin_height,fin_sweep)+fin_base/2, + fin_height +]; // Top + +top_point = [ fin_width-fin_top_withdraw,fin_height ]; + +//pt1_x = adj_ang_to_opp(fin_height,fin_sweep)+fin_base/2; +//pt1_y = fin_height; + + + +edge_point = [fin_width ,fin_height-fin_edge_withdraw ]; +counter_edge_point = [fin_width -70 ,fin_height-100 ]; +tail_point = [fin_width -95 ,fin_height-175 ]; +end_point = [fin_base ,0 ]; + +/******************/ +/* Profile points */ +/******************/ + profile_points = [ + // ***************** + // INITIAL POINT + // ***************** + start, // Point 0 + //[opp_ang_to_adj(fin_height/3,fin_start_angle),fin_height/3], // Handle 0 + handle(start,70,80), + // ***************** + // TOP POINT + // ***************** + top_point + [-fin_width/3,2], // Handle 1 (Start) + top_point, // Top Point + top_point + [+fin_base/7 ,0], // Handle Top (end) + // ***************** + // EDGE POINT + // ***************** + edge_point + [0,15], + edge_point, + edge_point + [0,-15], // Point Edge Point + // ***************** + // COUNTER EDGE POINT + // ***************** + handle(counter_edge_point,60,30), + counter_edge_point, // Point Counter Edge + handle(counter_edge_point,240,30), + // ***************** + // TAIL Point + // ***************** + handle(tail_point,60 ,40), + tail_point, + handle(tail_point,60+180,40), + // ***************** + // END POINT + // ***************** + handle([fin_base,0],75,40), + [fin_base,0] // End point +]; + + +profile_path = translate_path( asCurve(profile_points),-fin_width/2 ); + + +/** + * 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 ){ + + debugPoint (start, "Start", "Red" ); + debugPoint (top_point, "Top", "Blue" ); + debugPoint (edge_point, "Edge", "Brown" ); + debugPoint (counter_edge_point, "Counter Edge", "Brown" ); + debugPoint (tail_point, "Tail", "Yellow" ); + debugPoint (end_point, "End", "Yellow" ); + + + 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); +} + + +// ***************** +// * Fin Drawing * +// ***************** +if ( render_fin ) { + scale([scale_factor, scale_factor, scale_factor]) + buildFin( fin_thickness ); +} + +/** + * Render Mold + */ +if ( render_mold ) buildMold(); +if ( render_drill_template ) buildDrillTemplate(); + + + +/** + * Build mold + * + */ +module buildMold() { + // Bottom mold + if (mold_part != "top") + + difference() { + case(mold_base_height,true); + // Piston + down(piston_depth-OFFSET) fwd(20) bottomInsert(); + } + // Top Mold + if (mold_part != "bottom") + up(printable ? 0 : 60) fwd(printable ? fin_height+50 : 0) down(mold_base_height) mirror([0,0,printable ? 1 : 0 ]) { + difference() { + union() { + // case + case(mold_top_height,false); + // Piston + mirror([1,0,0]) + down(mold_top_height+piston_depth-OFFSET) fwd(20) topPiston(); + }; + resin_escape(40); + } + } +} + +/** + * Mold Case + * + * @param height - Height of the case + * @param bottom - Is bottom or top + */ +module case( height , bottom=true ) { + difference() { + diff() cuboid( [ mold_length, mold_width, height ], + rounding=4, + edges=[bottom ? BOTTOM: TOP], + anchor=TOP ){ + // Drills + align(BOTTOM,[FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],inset=10,overlap=-OFFSET) + color("orange") + tag("remove") + drilling(); + }; + // Material holes + mirror([bottom ? 0:1,0,0]) + back(38) left(55) + color("Red") + up(OFFSET) + rounded_triangle(radius=3, height=height+2*OFFSET); + // Length hole + fwd(32) cuboid([120,10,50],rounding=5); + // Side holes + left(67) cuboid([10,40,50],rounding=5); + right(67) cuboid([10,40,50],rounding=5); + } +} + +/** + * Drill template + * + */ +module buildDrillTemplate() { + + spacing = 38.5; + drill_depth = 15; + drill_diameter = 6; + template_height = 5; + + p1 = 20; + p2 = p1-spacing; + + mirror([0,0,printable ? 1 : 0]) difference() { + + left(1) color ("Orange") cuboid([fin_width+7,15,10],rounding=3); + down(OFFSET) { + hull(){ + left(28) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + left(55) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + } + hull(){ + left(12) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + left(-10) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + } + hull(){ + left(-27) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + left(-53) cylinder(h=template_height+2*OFFSET,r=drill_diameter/2); + } + } + xrot(-90) buildFin(fin_thickness + 2*CLEARING ); + //left(60) cylinder(h=20,r=6/2); + up(template_height+OFFSET) + { + left(p1) + cylinder(h=drill_depth+template_height,r=drill_diameter/2,orient=DOWN); + left(p2) + cylinder(h=drill_depth,r=drill_diameter/2,orient=DOWN); + } + } +} + + + + +module rounded_triangle(radius, height) { + triangle_points = [[0, 0], [75, 0], [0, -35]]; // Equilateral triangle with side length 100 + rounded_shape = round_corners( triangle_points, r=radius ); + mirror([0,0,1]) linear_extrude(height = height) polygon(rounded_shape); +} + + + +// ***************** +// * Bottom insert * +// ***************** +module bottomInsert() { + debug=true; + //layer_profile = pathProcess(profile_path); + layer_profile = profile_path; + skin( [ layer_profile,expandPath(layer_profile,3) ], z=[0,piston_depth], slices=0 ) + //up(debug ? 2 : 0) + up(OFFSET) + buildFinSide(true) + ; +} + +// ***************** +// * Top piston * +// ***************** +module topPiston() { + debug=true; + layer_profile = profile_path; + difference() { + skin( [ layer_profile,expandPath(layer_profile,3) ], z=[0,piston_depth], slices=0 ); + down(OFFSET) + buildFinSide(false); + } +} + +/** + * Build fin + * + */ +module buildFin( thickness ) { + union() { + if (parts != "bottom") buildFinSide( thickness ); + if (parts != "top") buildFinSide( thickness , true ); + } +} + +/** + * Build fin side + * + * @param flip - Define it it is top or bottom fin side + */ +module buildFinSide(thickness,flip=false) { + mirror([0,0,flip ? 1 : 0]) + color(flip ? "Gray" : "LightGray") /*up(fin_thickness/4)*/ /*down(fin_thickness) */ + ellipse_extrude( thickness / 2 ) + polygon(profile_path); +} + +module resin_escape(length) { + color ("Blue") cylinder(h=length, r=resin_escape_diameter/2); +} + +// ***************** +// * Drilling * +// ***************** +module drilling(){ + /*fwd(20)*/ color("Red") /*up(mold_piston_height+5)*/ up(-OFFSET) + orient(DOWN) + threaded_rod( + d=merge_holes_diameter, + l=drilling_length, + pitch=1.5, + anchor=BOTTOM, + //orient=BOTTOM + + ); +} + + +module subtracted(anchor) { + color("Red") fwd(40) left(40) cube([fin_width+100,fin_height+100,20],anchor=anchor); +} + + +// Draw fin profile +if (draw_profile) drawProfile( profile_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=0.2); +} + + + + +/** + * 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]]); + + +/** + * Function to translate a path manually along X and Y + */ +function translate_path(path, dx=0, dy=0) = + [for (p = path) [p[0] + dx, p[1] + dy]]; + + + +// Function to print points of a path +module print_path_points(path) { + for (i = [0:len(path)-1]) { + echo(str("\t Point ", i, ": [", path[i][0], ", ", path[i][1], "]")); + } +} + +echo ("**********************"); +echo ("* Configuration *"); +echo ("**********************"); +echo ("Base thickness" ,str(base_tickness," mm")); + + + +function asCurve(points) = bezier_curve(points/*,N=3*/,splinesteps=128); + +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); + +// Surf Fin profile +fin_profile = pathProfile( profile_points ); + +function expandPath(path,delta) = + offset( + deduplicate(path), + delta=delta, + chamfer=false, + same_length=true + ) + ; + + +function inches_to_cm(inches) = inches * 2.54; + + +echo ("pt1",pt1); +echo ("pt1[X]",pt1[X]); +echo ("pt1[Y]",pt1[Y]); +echo ("X",X); +echo ("Y",Y); + + + + + + + + + + + + + + + + diff --git a/common.scad b/common.scad new file mode 100644 index 0000000..95e6b10 --- /dev/null +++ b/common.scad @@ -0,0 +1,42 @@ + + + +// Constants + +// Cooordinates +X=0; +Y=1; +Z=2; + +// Offset +OFFSET=0.01; + + +/* + * Handle for bézier point + * + * @param point - Point to manage + * @param angle - Angle starting as 3h00 + * @param strength - Handle distance from manage point + */ + +function handle(point,angle,strength) = [ + point[0] + polar_to_xy(strength,angle)[0] , + point[1] + polar_to_xy(strength,angle)[1] + ]; + + + + +module debugPoint(point, id, color) { + translate(point) { + color(color) sphere(r = 1.5); + + translate([3, 3, 0.6]) { + color("white") + scale([0.2, 0.2, 1]) + linear_extrude(height = 0.1) + text(str(id), size = 20, halign = "center", valign = "center"); + } + } +}