// title : Fingerboard Mold V2
// author : Beau Trifiro
// description: Fingerboard Mold Design Tool
// file : 210818-FB-MOLD-V2
// (C) 2020 - present
function getParameterDefinitions()
{
return ([
{ name: 'mold_design', caption: 'Mold Design', type: 'group'},
{ name: 'resolution', type: 'slider', class: 'paramSlider', initial: 10, step: 1, min: 1, max:20, caption: 'Model Resolution'},
{ name: 'mold_width', type: 'slider', class: 'paramSlider', initial: 4, step: 0.1, min: 1, max: 6, caption: 'Mold Width, cm'},
{ name: 'mold_length', type: 'slider', class: 'paramSlider', initial: 12, step: 0.1, min: 8, max: 15, caption: 'Mold Length, cm'},
{ name: 'mold_height', type: 'slider', class: 'paramSlider', initial: 3, step: 0.1, min: 1, max: 4, caption: 'Mold Height (Core), cm'},
{ name: 'wheelbase', type: 'slider', class: 'paramSlider', initial: 45, step: 1, min: 30, max: 100, caption: 'Wheelbase, mm'},
{ name: 'deck_width', type: 'slider', class: 'paramSlider', initial: 30, step: 1, max: 50, min: 20, caption: 'Deck Width, mm'},
{ name: 'concave_drop', type: 'float', initial: 2.0, step: 0.1, caption: 'Concave Drop, mm'},
{ name: 'transition_length', type: 'slider', class: 'paramSlider', initial: 15, step: 1, min: 10, max: 22, caption: 'Transition Length, mm'},
{ name: 'kick_gap', type: 'slider', class: 'paramSlider', initial: 2, step: 0.5, min: 1, max: 4, caption: 'Kick Gap, mm'},
// { name: 'nose_transition_length', type: 'slider', initial: 15, step: 1, min: 10, max: 22, caption: 'Nose Transition Length, mm'},
// { name: 'tail_transition_length', type: 'slider', initial: 15, step: 1, min: 10, max: 22, caption: 'Tail Transition Length, mm'},
//{ name: 'offset', type: 'float', initial: 0.0, step: 0.1, caption: 'Extend Tail, inches'},
{ name: 'kicknose_angle', type: 'slider', class: 'paramSlider', initial: 20, step: 1, min: 0, max: 30, caption: 'Kicknose, deg.'},
{ name: 'kicktail_angle', type: 'slider', class: 'paramSlider', initial: 20, step: 1, min: 0, max: 30, caption: 'Kicktail, deg.'},
// { name: 'nose_flatness', type: 'float', initial: 0.75, step: 0.05, max: 1.00, min: 0.00, caption: 'Nose Shape (max: 1, min: 0)'},
// { name: 'tail_flatness', type: 'float', initial: 0.75, step: 0.05, max: 1.00, min: 0.00, caption: 'Tail Shape (max: 1, min: 0)'},
{ name: 'nose_radius', type: 'slider', class: 'paramSlider', initial: 20, step: 1, min: 1, max: 100, caption: 'Nose Radius, mm'},
{ name: 'tail_radius', type: 'slider', class: 'paramSlider', initial: 20, step: 1, min: 1, max: 100, caption: 'Tail Radius, mm'},
//{ name: 'transition_resolution', type: 'float', initial: .05, step: .03125, caption: 'Transition Resolution, in. (smaller=smoother)'},
//{ name: 'make_notches', type: 'checkbox', checked: false, caption: 'Make alignment notches'},
{ name: 'make_holes', type: 'checkbox', checked: false, caption: 'Make truck holes'},
//{ name: 'hole_depth', type: 'float', initial: 0.25, step: 0.125, caption: 'Truck hole depth, in.'},
{ name: 'hole_diameter', type: 'float', initial: 1.7, step: 0.05, caption: 'Truck hole diameter, mm'},
{ name: 'hole_pattern_length', type: 'float', initial: 7.5, step: 0.05, caption: 'Truck hole pattern length, mm'},
{ name: 'hole_pattern_width', type: 'float', initial: 5.5, step: 0.05, caption: 'Truck hole pattern width, mm'},
/*{ name: 'board_color', type: 'color', initial: "#00aadd", caption: 'Color!'}*/
/*{ name: 'nose_x_adjust', type: 'float', initial: 0.25, caption: 'Nose X Adjustment (0 to 1)'},
{ name: 'nose_y_adjust', type: 'float', initial: 0.67, caption: 'Nose Y Adjustment (0 to 1)'},
{ name: 'tail_x_adjust', type: 'float', initial: 0.25, caption: 'Tail X Adjustment (0 to 1)'},
{ name: 'tail_y_adjust', type: 'float', initial: 0.67, caption: 'Tail Y Adjustment (0 to 1)'}
*/
{name: 'thickness', type: 'float', initial: 3.0, step: 0.5, min: 0, max: 6, caption: 'Mold Offset, mm'},
{name: 'negHeight', type: 'slider', class: 'paramSlider', initial: 2, step: 0.5, min: 1, max: 6, caption: 'Cavity Minimum Thickness'},
{name: 'invert', type: 'checkbox', checked: false, caption: 'Show Opposite Mold (Cavity)'},
{ name: 'template_design', caption: 'Template Design', type: 'group'},
{ name: 'showTemplate', type: 'checkbox', checked: false, caption: 'Show Template'},
{ name: 'show_profile', type: 'checkbox', checked: false, caption: 'Show Profile, Only?'},
{ name: 'nose_length', type: 'slider', class: 'paramSlider', initial: 20, step: 1, max: 30, min: 5, caption: 'Nose Length, mm'},
{ name: 'tail_length', type: 'slider', class: 'paramSlider', initial: 20, step: 1, max: 30, min: 5, caption: 'Tail Length, mm'},
{ name: 'taperN', type: 'slider', class: 'paramSlider', initial: 37, step: 1, max: 45, min: 5, caption: 'Nose Taper Point, mm'},
{ name: 'taperT', type: 'slider', class: 'paramSlider', initial: 37, step: 1, max: 45, min: 5, caption: 'Tail Taper Point, mm'},
{ name: 'nose_flatness', type: 'slider', class: 'paramSlider', initial: 75, step: 5, max: 100, min: 50, caption: 'Nose Shape'},
{ name: 'tail_flatness', type: 'slider', class: 'paramSlider', initial: 75, step: 5, max: 100, min: 50, caption: 'Tail Shape'},
{ name: 'shift', type: 'float', initial: 0, step: 0.125, caption: 'Shift Profile, in.
(Single kick molds only!)'},
{ name: 'cutout_specs', caption: '
Wheel Cutouts ', type: 'group'},
{ name: 'make_cutouts', type: 'checkbox', checked: false, caption: 'Make Cutouts'},
{ name: 'noseLipX', type: 'slider', class: 'paramSlider', min: 5, max: 50, step: 0.25, initial: 45, caption: 'Nose Cutout Depth'},
{ name: 'noseLipY', type: 'slider', class: 'paramSlider', min: -10, max: 20, step: 0.25, initial: 8, caption: 'Nose Cutout Width'},
{ name: 'noseY', type: 'slider', class: 'paramSlider', min: 1, max: 20, initial: 11, step: 0.25, caption: 'Nose Width'},
{ name: 'tailLipX', type: 'slider', class: 'paramSlider', min: 5, max: 50, step: 0.25, initial: 39, caption: 'Tail Cutout Depth'},
{ name: 'tailLipY', type: 'slider', class: 'paramSlider', min: -10, max: 20, step: 0.25, initial: 11, caption: 'Tail Cutout Width'},
{ name: 'tailY', type: 'slider', class: 'paramSlider', min: 1, max: 20, initial: 20, step: 0.25, caption: 'Tail Width'},
]);
}
/*
Interactive parametric models
It is possible to make certain parameters editable in the browser. This allows users not familiar with JavaScript to create customized STL files.
To do so, add a function getParameterDefinitions() to your .jscad source. This function should return an array with parameter definitions. Currently 6 parameters types are supported: float, int, text, longtext, bool and choice. The user edited values of the parameters will be supplied as an object parameter to the main() function of your .jscad file.
*/
function main (parameters)
{
var width = parseFloat(parameters.mold_width);
// var deck_width = parameters.width;
var wheelbase = parseFloat(parameters.wheelbase/10);
var thickness = parseFloat(parameters.thickness)/10; //how many decks to be pressed at once
var negHeight = parseFloat(parameters.negHeight);
var inverse = parameters.invert;
var showTemplate = parameters.showTemplate;
var deck_width = parseFloat(parameters.deck_width)/10;
var concave_radius, kicknose_radius, kicktail_radius;
var concave_drop = parseFloat(parameters.concave_drop)/10;
var taperN = parseFloat(parameters.taperN)/10;
var taperT = parseFloat(parameters.taperT)/10;
if (inverse == false) {
concave_radius = (Math.pow((deck_width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
kicknose_radius = parseFloat(parameters.nose_radius)/10;
kicktail_radius = parseFloat(parameters.tail_radius)/10;
}
else {
concave_radius = ((Math.pow((deck_width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop)) + thickness;
kicknose_radius = parseFloat(parameters.nose_radius/10) + thickness;
kicktail_radius = parseFloat(parameters.tail_radius/10) + thickness;
}
var nose_transition_length = parseFloat(parameters.transition_length)/10;
var tail_transition_length = parseFloat(parameters.transition_length)/10;
var mold_width = parseFloat(parameters.mold_width);
var mold_length = parseFloat(parameters.mold_length);
var mold_height = parseFloat(parameters.mold_height);
var show_profile = parameters.show_profile;
var shift = parameters.shift;
var make_cutouts = parameters.make_cutouts;
var noseLipX = parameters.noseLipX/10;
var noseLipY = parameters.noseLipY/10;
var noseY = parameters.noseY/10;
var tailLipX = parameters.tailLipX/10;
var tailLipY = parameters.tailLipY/10;
var tailY = parameters.tailY/10;
var bolt_pattern_width = parameters.hole_pattern_width/10; // 5mm - not to scale
var bolt_pattern_length = parameters.hole_pattern_length/10; // 8mm - not to scale
//var bolt_diameter = 0.24; //not to scale
//var hole_diameter = bolt_diameter;
var hole_depth = mold_height*10;
//var hole_depth = parameters.hole_depth;
var hole_diameter = parseFloat(parameters.hole_diameter)/10;
var make_holes = parameters.make_holes;
var kick_gap = parseFloat(parameters.kick_gap)/10;
var concave_length = wheelbase + (bolt_pattern_length*2) + (kick_gap*2) - nose_transition_length - tail_transition_length;
//var concave_length = length - (kicktail_length + kicknose_length + nose_transition_length + tail_transition_length);
var offset = 0; // parameters.offset;
var tail_length = (mold_length - (concave_length + nose_transition_length + tail_transition_length))/2;
var nose_length = (mold_length - (concave_length + nose_transition_length + tail_transition_length))/2;
if (showTemplate == true) {
tail_length = parseFloat(parameters.tail_length)/10;
nose_length = parseFloat(parameters.nose_length)/10;
}
var kicktail_length = tail_length-kick_gap;
var kicknose_length = nose_length-kick_gap;
var kicknose_angle = parameters.kicknose_angle;
var kicktail_angle = parameters.kicktail_angle;
var nose_shape = parseFloat(parameters.nose_flatness)/100;
var tail_shape = parseFloat(parameters.tail_flatness)/100;
/* var board_color = parameters.board_color;*/
var mold_offset = thickness;
var thickness = mold_height;
var slice_thickness = parseFloat(parameters.resolution)/100;
//var slice_thickness = 0.02;
var min_radius = concave_radius;
var length = wheelbase + (bolt_pattern_length*2) + tail_length + nose_length;
//var concave_length = length - (kicktail_length + kicknose_length + nose_transition_length + tail_transition_length);
var flat_concave_length = concave_length + nose_transition_length + tail_transition_length;
//find kicknose translation parameters
var kicknose_hypotenuse = 2*(kicknose_radius*sin(kicknose_angle/2));
var kicknose_radius_length = kicknose_hypotenuse*cos(kicknose_angle/2);
var kicknose_radius_height = kicknose_hypotenuse*sin(kicknose_angle/2);
//find kicktail translation parameters
var kicktail_hypotenuse = 2*(kicktail_radius*sin(kicktail_angle/2));
var kicktail_radius_length = kicktail_hypotenuse*cos(kicktail_angle/2);
var kicktail_radius_height = kicktail_hypotenuse*sin(kicktail_angle/2);
var number_of_segments = 10; //for transition section resolution
var skateboard = make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([0,0,thickness]);
kicknose = make_kicknose_curve(kicknose_radius, width, kicknose_angle, nose_transition_length, concave_length, kicknose_length, mold_height);
kicktail = make_kicktail_curve(kicktail_radius, width, kicktail_angle, tail_transition_length, concave_length, kicktail_length, mold_height);
var mold = color([0.7,0.7,0.7],make_concave(concave_radius, thickness, concave_length, width, flat_concave_length));
mold = mold.union(color([.5,.5,.5],kicknose));
mold = mold.union(color([.5,.5,.5],kicktail));
if (concave_radius !== 0) {
var nose_transition = make_transition_section(nose_transition_length, thickness+2, slice_thickness, width, min_radius, number_of_segments);
var tail_transition = mirror([1,0,0], make_transition_section(tail_transition_length, thickness+2, slice_thickness, width, min_radius, number_of_segments));
mold = mold.union(color([0.2,0.2,0.2],nose_transition.translate([concave_length/2+nose_transition_length,0,0])));
mold = mold.union(color([0.2,0.2,0.2],tail_transition.translate([-concave_length/2-tail_transition_length,0,0])));
}
mold = mold.intersect(color([0.7,0.7,0.7], cube({size: [mold_length, mold_width, mold_height], center: true}).translate([(nose_transition_length-tail_transition_length)/2-offset,0,-mold_height/2])));
var bolt_pattern = make_bolt_pattern(bolt_pattern_length, bolt_pattern_width, -hole_depth, hole_diameter).translate([(bolt_pattern_length/2)+(wheelbase/2),0,0]);
bolt_pattern = bolt_pattern.union(make_bolt_pattern(bolt_pattern_length, bolt_pattern_width, -hole_depth, hole_diameter).translate([-((bolt_pattern_length/2)+(wheelbase/2)),0,0]));
var mDia = 0.5; //notch diameter
var make_notches = parameters.make_notches;
if (make_notches == true) {
mold = mold.subtract(make_markers(mold_width, wheelbase, nose_length, tail_length, bolt_pattern_length, mDia, kick_gap, nose_transition_length, tail_transition_length));
}
mold = mold.translate([0,0,mold_height]);
var neg_mold_height = mold_height + negHeight;
if (inverse == false) {
var mold_copy = mold;
mold = mold.union(color([0.4,0.4,0.4],(cube({size: ([mold_length+2.4, mold_width-2.02, mold_height])}).translate([-(mold_length+2.4)/2,-(mold_width-2.02)/2,0])).subtract(cube({size: [mold_length, mold_width, mold_height+mold_offset+2]}).translate([-mold_length/2,-mold_width/2,0]))));
var clearance1 = cube({size: [2,(mold_width-(mold_width-2.02))/2,mold_height]}).translate([mold_length/2-0.02,(mold_width/2)-((mold_width-(mold_width-2.02))/2),0]);
clearance1 = clearance1.union(cube({size: [2,(mold_width-(mold_width-2.02))/2,mold_height]}).translate([-(mold_length/2-0.02)-2,(mold_width/2)-((mold_width-(mold_width-2.02))/2),0]));
var clearance2 = clearance1;
clearance1 = mirror([0,1,0], clearance1);
mold = mold.subtract(clearance1);
mold = mold.subtract(clearance2);
var logo = rotate([0,0,90],make_logo()).translate([mold_length/2+0.6,0,mold_height]);
mold = mold.subtract(logo);
//uncomment below for reference size
//mold = mold.union(cube({size: [0.1,0.1,0.1], center: true}).translate([mold_length/2+0.05,0,mold_height+mold_offset+1]));
}
if (inverse == true) {
mold = mold.intersect(cube({size: [mold_length-0.02, mold_width, mold_height]}).translate([-(mold_length-0.02)/2, -mold_width/2, 0]));
mold = (color([0.4,0.4,0.4],cube({size: [mold_length-0.02, mold_width, neg_mold_height], center: true}).translate([0,0,(neg_mold_height)/2])).subtract(mold));
mold = rotate([180,0,0],mold);
mold = mold.translate([0,0,neg_mold_height]);
var slots = (color([0.4,0.4,0.4],(cube({size: ([1.1, mold_width, negHeight+1.5+mold_offset])}).translate([-(mold_length-0.02)/2-1.1,-(mold_width)/2,0]))));
slots = slots.union(color([0.4,0.4,0.4],(cube({size: ([1.1, mold_width, negHeight+1.5+mold_offset])}).translate([((mold_length-0.02)/2),-(mold_width)/2,0]))));
slots = color([0.4,0.4,0.4],slots.subtract(cube({size: [mold_length+3, mold_width-2, negHeight+2]}).translate([-(mold_length+3)/2, -(mold_width-2)/2,0])));
mold = mold.union(slots);
}
if (showTemplate == true) {
if (show_profile == true) {
var profile;// = (((make_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, 5))));
if (make_cutouts == false) {
profile = make_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, 0.1).translate([shift,0,0]);
}
else {
profile = make_lb_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, 0.1, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY).translate([shift,0,0]);
}
var mold = profile;
//var skateboard = make_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, 0.1);
}
else {
var depth = mold_height+10;
var profile;
if (make_cutouts == false) {
profile = make_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth).translate([shift,0,0]);
}
else {
profile = make_lb_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, depth, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY).translate([shift,0,0]);
}
mold = mold.intersect(profile);//(make_profile(deck_width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth));
}
}
if (make_holes == true) {
mold = mold.subtract(bolt_pattern);
}
return color([0.7,0.7,0.7],mold);
}
function make_markers(width, wheelbase, nose_length, tail_length, boltL, mDia, kick_gap, noseT, tailT) {
var result = new CSG();
result = sphere({r: mDia/2, center: true});
result = result.translate([(wheelbase/2+boltL+kick_gap+((noseT-tailT)/2)),(width/2),0]);
result = result.union(sphere({r: mDia/2, center: true}).translate([(wheelbase/2+boltL+kick_gap+((noseT-tailT)/2)),-(width/2),0]));
result = result.union(sphere({r: mDia/2, center: true}).translate([-(wheelbase/2+boltL+kick_gap-((noseT-tailT)/2)),-(width/2),0]));
result = result.union(sphere({r: mDia/2, center: true}).translate([-(wheelbase/2+boltL+kick_gap-((noseT-tailT)/2)),(width/2),0]));
return result;
}
function make_concave(concave_radius, thickness, concave_length, width, flat_concave_length)
{
var result = new CSG();
if(concave_radius==0){
result = cube({size:[flat_concave_length,width,thickness]});
result = result.translate([-flat_concave_length/2,-width/2,-thickness]);
return result;
}
else{
result = rotate([90,0,90],cylinder({r: concave_radius, h: concave_length, center: true, fn: 500})).translate([0,0,-concave_radius]);
return result;
/*result=
difference(
difference(
difference(
(rotate([90,0,90], difference(
cylinder({r: (concave_radius + thickness), h: concave_length, center: true, fn: 100}),
cylinder({r: concave_radius, h:concave_length+2, center: true, fn: 100}).translate([0,0,1])))
).translate([-concave_length/2,0,concave_radius]),
cube({size: [concave_length*2, concave_radius*4, concave_radius*4]}).translate([-concave_length, -concave_radius * 2 + 10, concave_radius])
),
cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0])
),
mirror([0,1,0], cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0]))
);
return result.translate([concave_length/2,0,0]);*/
}
}
function make_bolt_pattern(bolt_pattern_length, bolt_pattern_width, hole_depth, hole_diameter)
{
var result = new CSG();
result = (cylinder({d: hole_diameter, h: hole_depth, center: false}).translate([bolt_pattern_length/2,bolt_pattern_width/2,0])).union(cylinder({d: hole_diameter, h: hole_depth, center: false}).translate([bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: hole_diameter, h: hole_depth, center: false}).translate([-bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: hole_diameter, h: hole_depth, center: false}).translate([-bolt_pattern_length/2,bolt_pattern_width/2,0]));
result = result.translate([0,0,-hole_depth/2]);
return result;
}
function make_kicknose_curve(kicknose_radius, width, kicknose_angle, nose_transition_length, concave_length, kicknose_length, mold_height)
{
var result = new CSG();
result = rotate([90,0,0],cylinder({r: kicknose_radius, h:width, center: false, fn: 500}));
result = difference(result,cube({size: [kicknose_radius*2, width*4, kicknose_radius*4]}).translate([-kicknose_radius*2, -width*2, -kicknose_radius-2]))
result = result.subtract((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+kicknose_radius, width, kicknose_radius], center: false}).translate([0,-width,0]))));
result = result.subtract(cube({size: [kicknose_radius+2,width,kicknose_radius], center: false}).translate([0,-width,-kicknose_radius]));
// result = result.union(rotate([0,kicknose_angle,0],cube({size:[kicknose_length+10,width,kicknose_radius]})).translate([0,-width,0]));
result = result.union(rotate([0,kicknose_angle,0],cube({size:[kicknose_length+10,width,kicknose_radius*4]}).translate([0,0,-kicknose_radius*3])).translate([0,-width,0]));
// result = result.union(cube({size:[kicknose_length*2,width,mold_height], center: false}).translate([0,-width,-kicknose_radius-(mold_height/2)]));
result = result.subtract(cube({size: ([kicknose_length*2,width*2,mold_height*4]), center: false}).translate([-kicknose_length*2,-width*1.5,-mold_height*4+kicknose_radius]));
result = result.translate([(concave_length/2+nose_transition_length),width/2,-kicknose_radius]);
// result = result.intersect((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+10, width, kicknose_radius*4], center: false}))).translate([-(kicknose_length+10)/2,0,0]));
//result = result.union((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+10, width, kicknose_radius*2], center: false}))).translate([-(kicknose_length+10)/2,0,0]));
return result;
}
function make_kicktail_curve(kicktail_radius, width, kicktail_angle, tail_transition_length, concave_length, kicktail_length, mold_height)
{
var result = new CSG();
result = rotate([90,0,0],cylinder({r: kicktail_radius, h:width, center: false, fn: 500}));
result = difference(result,cube({size: [kicktail_radius*2, width*4, kicktail_radius*4]}).translate([-kicktail_radius*2, -width*2, -kicktail_radius-2]))
result = result.subtract((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+kicktail_radius, width, kicktail_radius], center: false}).translate([0,-width,0]))));
result = result.subtract(cube({size: [kicktail_radius+2,width,kicktail_radius], center: false}).translate([0,-width,-kicktail_radius]));
result = result.union(rotate([0,kicktail_angle,0],cube({size:[kicktail_length+10,width,kicktail_radius*4]}).translate([0,0,-kicktail_radius*3])).translate([0,-width,0]));
result = result.subtract(cube({size: ([kicktail_length*2,width*2,mold_height*4]), center: false}).translate([-kicktail_length*2,-width*1.5,-mold_height*4+kicktail_radius]));
result = mirror([1,0,0], result);
result = result.translate([(-(concave_length/2+tail_transition_length)),width/2,-kicktail_radius]);
//result = result.intersect((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+10, width, kicktail_radius*4], center: false}))).translate([-(kicktail_length+10)/2,0,0]));
//result = result.union((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+10, width, kicktail_radius*2], center: false}))).translate([-(kicktail_length+10)/2,0,0]));
return result;
}
function make_transition_section(transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)
{
var result = new CSG();
var number_of_steps = transition_length/slice_thickness;
var concave_depth = (2*min_radius-sqrt(pow(2*min_radius,2)-(4*1*pow(width,2)/4)))/(2*1);
var mid_depth = concave_depth/2;
var mid_radius = (pow(mid_depth,2)+(pow(width,2)/4))/(2*mid_depth);
// var max_radius = pow(mid_radius,2);
//if poor transition, uncomment the following and comment the above:
var max_radius = 6*mid_radius;
var correction = mid_radius;
var radius_range = max_radius - min_radius;
var radius_offset = min_radius;
var sub_radius_range = (max_radius+thickness) - (min_radius+thickness);
var sub_radius_offset = min_radius+thickness;
//y values for edges of arc
var normal_y = ((2*min_radius)-Math.sqrt(Math.pow(2*min_radius,2)-(4*Math.pow((width/2),2))))/(2);
var flat_y = 0;
//for start and end tangency, plot hollow cylindrical arcs as a sigmoid function... y = 1/(1+e^x). Adjust for the radius size (multiply by the range), then offset for the minimum (add min_radius)
//1/16/21 EDIT: change to cubic Bezier curve
// B(t) = [(1-t)^3]P0 + 3[(1-t)^2]tP1 + 3[(1-t)t^2]P2 + (t^3)P3
var i_range = 1; //range for t, which must be 0 <= t <= 1
var i_size = i_range/number_of_steps; //change in x value per change in step
//console.log('# steps = ' +number_of_steps);
//console.log('i_size = '+i_size);
var origin_x = 0;
var origin_y = 0;
var a = 0; //initial t value of Bezier
a = a+i_size; //prevent dividing by 0
var x0 = 0;
var x1 = transition_length/4;
var x2 = transition_length*(2/3);
var x3 = transition_length;
var y0 = 0;
var y1 = 0;
var y2 = concave_depth;
var y3 = concave_depth;
var slice_adj = 0;
var x_val_last = 0;
for (var i = a; i < (i_range+i_size); i=i+i_size) //starting at 0, going until 1, increment at i_size
{
/*if (i < 0) {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i*1.25)));
}
else {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i)));
}*/
//(x - h)^2 + (y - k)^2 = R^2, where (h,k) is the center of the concave circle
//we know h = 0, since it is in line with the bottom of the circle
//we know two points: (0,0) and (width/2,y_val)
//Two equations:
//(0 - 0)^2 + (0 - k)^2 = R^2
// ---> k = R
//(width/2 - 0)^2 + (y_val - R)^2 = R^2
//(width/2)^2 + y_val^2 - 2R*y_val = 0
//2R*y_val = (width/2)^2 + y_val^2
// 1/16/21 EDIT: Bezier curve:
var t = i;
var x_val = ((Math.pow((1-t),3))*x0)+(3*(Math.pow((1-t),2))*t*x1)+(3*((1-t))*Math.pow(t,2)*x2)+(Math.pow(t,3)*x3);
var y_val = ((Math.pow((1-t),3))*y0)+(3*(Math.pow((1-t),2))*t*y1)+(3*((1-t))*Math.pow(t,2)*y2)+(Math.pow(t,3)*y3);
var reg_radius = (Math.pow((width/2),2) + Math.pow(y_val,2))/(2*y_val);
// console.log("reg_radius is ");
//var reg_radius = radius_offset+(radius_range/(1+Math.exp(i)));
var reg_half_angle = asin((width/2)/reg_radius);
var reg_segment_angle = reg_half_angle/number_of_segments;
//console.log("half angle is ");
// console.log(reg_half_angle);
result = result.union(
linear_extrude({height: x_val-x_val_last, center: false},
polygon({ //currently set up for 20 segments per full arc:
points: [
[(reg_radius*sin(reg_segment_angle*10)),(reg_radius*cos(reg_segment_angle*10))],
[(reg_radius*sin(reg_segment_angle*9)),(reg_radius*cos(reg_segment_angle*9))],
[(reg_radius*sin(reg_segment_angle*8)),(reg_radius*cos(reg_segment_angle*8))],
[(reg_radius*sin(reg_segment_angle*7)),(reg_radius*cos(reg_segment_angle*7))],
[(reg_radius*sin(reg_segment_angle*6)),(reg_radius*cos(reg_segment_angle*6))],
[(reg_radius*sin(reg_segment_angle*5)),(reg_radius*cos(reg_segment_angle*5))],
[(reg_radius*sin(reg_segment_angle*4)),(reg_radius*cos(reg_segment_angle*4))],
[(reg_radius*sin(reg_segment_angle*3)),(reg_radius*cos(reg_segment_angle*3))],
[(reg_radius*sin(reg_segment_angle*2)),(reg_radius*cos(reg_segment_angle*2))],
[(reg_radius*sin(reg_segment_angle*1)),(reg_radius*cos(reg_segment_angle*1))],
[(reg_radius*sin(reg_segment_angle*0)),(reg_radius*cos(reg_segment_angle*0))],
[(reg_radius*sin(reg_segment_angle*0)),(reg_radius*cos(reg_segment_angle*0))-5],
[(reg_radius*sin(reg_segment_angle*10)),(reg_radius*cos(reg_segment_angle*10))-5]
]
})).translate([0,-reg_radius,x_val_last])
//each slice is slice_thickness wide, so move that much each time
);
x_val_last = x_val;
slice_adj = slice_adj + slice_thickness;
//console.log("i is " + i);
}
result = result.union(mirror([1,0,0],result));
result = rotate([90,0,-90],result);
result = result.translate([0,0,0]);
return result;
}
function make_profile(width, wheelbase, boltL, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth)
{
var profile = new CSG.Path2D([[0,(width/2)],[(((wheelbase/2)+boltL+nose_length)-taperN),(width/2)]]);
profile = profile.appendBezier([[((((wheelbase/2)+boltL+nose_length)-taperN)+(nose_shape*(taperN))),(width/2)],[((wheelbase/2)+boltL+nose_length),(nose_shape*(width/2))],[((wheelbase/2)+boltL+nose_length),0]], {resolution: 100});
profile = profile.appendBezier([[((wheelbase/2)+boltL+nose_length),(-(nose_shape*(width/2)))],[((((wheelbase/2)+boltL+nose_length)-taperN)+(nose_shape*(taperN))),(-(width/2))],[(((wheelbase/2)+boltL+nose_length)-taperN),(-(width/2))]], {resolution: 100});
profile = profile.appendPoint([0,(-(width/2))]);
profile = profile.appendPoint([-(((wheelbase/2)+boltL+tail_length)-taperT),-(width/2)]);
profile = profile.appendBezier([[-((((wheelbase/2)+boltL+tail_length)-taperT)+(tail_shape*(taperT))),-(width/2)],[-((wheelbase/2)+boltL+tail_length),-(tail_shape*(width/2))],[-((wheelbase/2)+boltL+tail_length),0]], {resolution: 100});
profile = profile.appendBezier([[-((wheelbase/2)+boltL+tail_length),((tail_shape*(width/2)))],[-((((wheelbase/2)+boltL+tail_length)-taperT)+(tail_shape*(taperT))),((width/2))],[-(((wheelbase/2)+boltL+tail_length)-taperT),((width/2))]], {resolution: 100});
profile = profile.appendPoint([0,(width/2)]);
profile = profile.close();
var skateboard = profile.innerToCAG();
skateboard = linear_extrude({height: depth}, skateboard);
return skateboard;
}
function make_lb_profile(width, wheelbase, boltL, nose_length, tail_length, length, taperN, taperT, depth, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
{
var res = 100; //resolution of bezier curves
var profile = new CSG.Path2D([[0,(width/2)],[(((wheelbase/2)+boltL+nose_length)-taperN),(width/2)]]);
profile = profile.appendBezier([[(noseLipX),(width/2)],[(noseLipX),(noseLipY)],[((wheelbase/2)+boltL+nose_length),(noseY)],[((wheelbase/2)+boltL+nose_length),0]], {resolution: res});
profile = profile.appendBezier([[((wheelbase/2)+boltL+nose_length),(-noseY)],[noseLipX,(-noseLipY)],[noseLipX,(-(width/2))],[(((wheelbase/2)+boltL+nose_length)-taperN),-(width/2)]], {resolution: res});
profile = profile.appendPoint([0,(-(width/2))]);
profile = profile.appendPoint([-(((wheelbase/2)+boltL+tail_length)-taperT),-(width/2)]);
profile = profile.appendBezier([[(-tailLipX),-(width/2)],[(-tailLipX),(-tailLipY)],[-(((wheelbase/2)+boltL+tail_length)),-(tailY)],[-(((wheelbase/2)+boltL+tail_length)),0]], {resolution: res});
profile = profile.appendBezier([[-(((wheelbase/2)+boltL+tail_length)),(tailY)],[-tailLipX,(tailLipY)],[-tailLipX,((width/2))],[-((((wheelbase/2)+boltL+tail_length))-taperT),(width/2)]], {resolution: res});
profile = profile.appendPoint([0,(width/2)]);
profile = profile.close();
var skateboard = profile.innerToCAG();
skateboard = linear_extrude({height: depth}, skateboard);
return skateboard;
}
function make_logo() {
var cag0 = new CAG();
var cag1 = new CAG();
var cag2 = new CAG();
var cag3 = new CAG();
var cag20 = cag3;
cag2 = cag2.union(cag20);
var cag3 = new CAG();
var cag21 = cag3;
cag2 = cag2.union(cag21);
var cag3 = new CAG();
var cag30 = new CAG();
var cag301 = new CSG.Path2D([[272.73907,-885.95367]],false);
cag301 = cag301.appendBezier([[265.95745000000005,-885.13183],[259.51701,-882.76426],[253.92006000000003,-879.0355999999999]]);
cag301 = cag301.appendBezier([[241.10355000000004,-870.4972999999999],[233.81635000000003,-856.41487],[234.32472000000004,-841.1678499999999]]);
cag301 = cag301.appendBezier([[234.59822000000005,-832.96485],[237.00109000000003,-825.3881499999999],[241.47632000000004,-818.61758]]);
cag301 = cag301.appendBezier([[246.36129000000005,-811.2271],[253.20178000000004,-805.61239],[261.55103,-802.1401599999999]]);
cag301 = cag301.appendBezier([[264.76976,-800.80158],[269.38961,-799.6299899999999],[273.15364000000005,-799.1977499999999]]);
cag301 = cag301.appendBezier([[275.23095000000006,-798.95921],[280.60429000000005,-798.95921],[282.68160000000006,-799.1977499999999]]);
cag301 = cag301.appendBezier([[301.1161400000001,-801.31468],[316.05948000000006,-814.5449699999999],[320.41098000000005,-832.6019799999999]]);
cag301 = cag301.appendBezier([[321.69828000000007,-837.94373],[321.8970100000001,-844.4969899999999],[320.9390000000001,-850.0139699999999]]);
cag301 = cag301.appendBezier([[318.86692000000005,-861.9467799999999],[311.97881000000007,-872.4241099999998],[301.8055100000001,-879.1174499999998]]);
cag301 = cag301.appendBezier([[296.1110700000001,-882.8639899999998],[289.7736000000001,-885.1590499999999],[282.9032400000001,-885.9627099999999]]);
cag301 = cag301.appendBezier([[280.4519000000001,-886.2494699999999],[275.1409900000001,-886.2447399999999],[272.7390700000001,-885.9537099999999]]);
cag301 = cag301.close();
switch (cag301.getTurn()) {
default:
case "clockwise":
cag301 = cag301.innerToCAG();
cag30 = cag30.union(cag301);
break;
case "counter-clockwise":
cag301 = cag301.innerToCAG();
cag30 = cag30.subtract(cag301);
break;
}
var cag302 = new CSG.Path2D([[255.63449,-851.00316]],false);
cag302 = cag302.appendPoint([255.63449,-843.473]);
cag302 = cag302.appendPoint([251.48519,-843.473]);
cag302 = cag302.appendPoint([247.33593,-843.473]);
cag302 = cag302.appendPoint([247.33593,-851.00316]);
cag302 = cag302.appendPoint([247.33593,-858.53333]);
cag302 = cag302.appendPoint([251.48519,-858.53333]);
cag302 = cag302.appendPoint([255.63449,-858.53333]);
cag302 = cag302.close();
switch (cag302.getTurn()) {
default:
case "clockwise":
cag302 = cag302.innerToCAG();
cag30 = cag30.union(cag302);
break;
case "counter-clockwise":
cag302 = cag302.innerToCAG();
cag30 = cag30.subtract(cag302);
break;
}
var cag303 = new CSG.Path2D([[308.4993,-851.00316]],false);
cag303 = cag303.appendPoint([308.4993,-843.473]);
cag303 = cag303.appendPoint([304.35002000000003,-843.473]);
cag303 = cag303.appendPoint([300.20076,-843.473]);
cag303 = cag303.appendPoint([300.20076,-851.00316]);
cag303 = cag303.appendPoint([300.20076,-858.53333]);
cag303 = cag303.appendPoint([304.35002000000003,-858.53333]);
cag303 = cag303.appendPoint([308.4993,-858.53333]);
cag303 = cag303.close();
switch (cag303.getTurn()) {
default:
case "clockwise":
cag303 = cag303.innerToCAG();
cag30 = cag30.union(cag303);
break;
case "counter-clockwise":
cag303 = cag303.innerToCAG();
cag30 = cag30.subtract(cag303);
break;
}
var cag304 = new CSG.Path2D([[297.43458,-850.9263599999999]],false);
cag304 = cag304.appendPoint([297.43458,-847.16127]);
cag304 = cag304.appendPoint([293.22109,-847.16127]);
cag304 = cag304.appendPoint([289.00762000000003,-847.16127]);
cag304 = cag304.appendPoint([285.8217,-844.43351]);
cag304 = cag304.appendPoint([282.63577000000004,-841.70574]);
cag304 = cag304.appendPoint([283.54233000000005,-841.59662]);
cag304 = cag304.appendBezier([[284.04093000000006,-841.5366200000001],[285.8665500000001,-841.34099],[287.5992600000001,-841.16192]]);
cag304 = cag304.appendBezier([[293.51664000000005,-840.55035],[299.6444400000001,-839.36307],[305.40607000000006,-837.71184]]);
cag304 = cag304.appendBezier([[307.03138000000007,-837.2460500000001],[308.3922600000001,-836.8649300000001],[308.43025000000006,-836.8649300000001]]);
cag304 = cag304.appendBezier([[308.46825000000007,-836.8649300000001],[308.49935000000005,-835.0669],[308.49935000000005,-832.86932]]);
cag304 = cag304.appendBezier([[308.49935000000005,-830.67175],[308.4444500000001,-828.87373],[308.37725000000006,-828.87373]]);
cag304 = cag304.appendBezier([[308.31005000000005,-828.87373],[306.90970000000004,-829.31683],[305.26529000000005,-829.85839]]);
cag304 = cag304.appendBezier([[287.52269000000007,-835.70163],[268.38804000000005,-835.7007199999999],[250.56528000000006,-829.8553899999999]]);
cag304 = cag304.appendBezier([[248.91825000000006,-829.3152399999999],[247.51786000000007,-828.8733199999999],[247.45333000000005,-828.8733199999999]]);
cag304 = cag304.appendBezier([[247.38883000000004,-828.8733199999999],[247.33598000000006,-830.66086],[247.33598000000006,-832.84565]]);
cag304 = cag304.appendPoint([247.33598000000006,-836.81797]);
cag304 = cag304.appendPoint([250.67844000000005,-837.76284]);
cag304 = cag304.appendBezier([[256.66209000000003,-839.4543],[262.38624000000004,-840.56304],[268.23603,-841.16363]]);
cag304 = cag304.appendBezier([[269.96873000000005,-841.34153],[271.79176,-841.53619],[272.28718000000003,-841.5962000000001]]);
cag304 = cag304.appendPoint([273.18795000000006,-841.7053300000001]);
cag304 = cag304.appendPoint([270.0222800000001,-844.4330900000001]);
cag304 = cag304.appendPoint([266.85660000000007,-847.1608500000001]);
cag304 = cag304.appendPoint([262.6286600000001,-847.1608500000001]);
cag304 = cag304.appendPoint([258.40071000000006,-847.1608500000001]);
cag304 = cag304.appendPoint([258.40071000000006,-850.9259300000001]);
cag304 = cag304.appendPoint([258.40071000000006,-854.6910200000001]);
cag304 = cag304.appendPoint([277.91767000000004,-854.6910200000001]);
cag304 = cag304.appendPoint([297.43463,-854.6910200000001]);
cag304 = cag304.close();
switch (cag304.getTurn()) {
default:
case "clockwise":
cag304 = cag304.innerToCAG();
cag30 = cag30.union(cag304);
break;
case "counter-clockwise":
cag304 = cag304.innerToCAG();
cag30 = cag30.subtract(cag304);
break;
}
cag3 = cag3.union(cag30);
var cag22 = cag3;
cag22 = cag22.translate([37.375645,-55.558391]);
cag2 = cag2.union(cag22);
var cag10 = cag2;
cag1 = cag1.union(cag10);
var cag00 = cag1;
cag0 = cag0.union(cag00);
cag0 = scale(0.01,cag0);
var solid = linear_extrude({height: 10, center: true}, cag0);
solid = cube({size: [20,20,0.2], center: true}).subtract(solid);
return solid;
}