// title : SK8CAD for Roarockit Builders
// author : Beau Trifiro
// license : Copyright 2020 - present, Open Source Skateboards
// description: Skateboard and mold customizer
// last edit : 1/26/21
function getParameterDefinitions()
{
return ([
/*{ name: 'mold', type: 'choice', caption: 'Select Mold', values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], captions: ['None',
'Asymmetrical - Small',
'Asymmetrical - Mid',
'Freestyle - Modern Era',
'Freestyle - SF',
'Freestyle - Sweden',
'Freestyle - RadRat',
'Mellow Symmetrical',
'Medium/Mellow Symmetrical',
'Medium Symmetrical',
'Steep Symmetrical',
'Shark',
'XL Medium'], initial: 0},*/
{ name: 'display_title', caption: '<span class="category">Display</span>', type: 'group', class: 'category'},
{ name: 'display_item', caption: 'Show ', type: 'choice', values: [0, 1], initial: 0, captions: ['Mold', 'Board']},
//{ name: 'templates', caption: '<hr> <span class="category">Pre-Designed Templates</span> <br> <button style="font-size: 10px;">Template specs</button>', type: 'group'},
//{ name: 'profile_choice', caption: 'Select Profile', type: 'choice', values: [0, 1, 2, 3], initial: 0, captions: ['None', '8.25" Street Deck', 'Longboard Dancer', 'Cruiser']},
//{ name: 'mold_choice', caption: 'Select Mold', type: 'choice', values: [0, 1, 2, 3], initial: 0, captions: ['None', 'Street Deck', 'Longboard Dancer', 'Cruiser']},
{ name: 'mold_design', caption: '<hr> <span class="category">Choose Your Mold</span>', type: 'group'},
{ name: 'mold_size', caption: 'Size', type: 'choice', values: [0, 1], initial: 0, captions: ['9.5" x 34" x 3"', '12" x 47" x 2"']},
{ name: 'board_design', caption: '<hr> <span class="category">Design Your Board</span> <br> <p style="font-size: 11px; font-weight: normal;"> Board Length: <span id="lengthDisplay"> </span>" <br> <span style="font-size: 9px; font-weight: normal;"> (To change this, update wheelbase,<br> nose length, and tail length.) </span> </p>', type: 'group'},
{ name: 'profile', type: 'checkbox', checked: false, caption: 'Show Board Outline, Only <br>(Faster rendering)'},
{ name: 'width', type: 'float', initial: 8.25, step: 0.125, caption: 'Width, inches'},
{ name: 'wheelbase', type: 'float', initial: 14.0, step: 0.125, caption: 'Wheelbase, inches'},
{ name: 'nose_length', type: 'float', initial: 6.75, step: 0.125, caption: 'Nose Length, inches'},
{ name: 'tail_length', type: 'float', initial: 6.75, step: 0.125, caption: 'Tail Length, inches'},
{ name: 'concave_drop', type: 'float', initial: 0.4, step: 0.1, max: 0.6, min: 0.0, caption: 'Concave Drop, in.'}, // concave_radius=0, make flat board
{ name: 'kicknose_angle', type: 'float', initial: 20.0, step: 1, min: 0, max: 25.0, caption: 'Kicknose, deg.'},
{ name: 'kicktail_angle', type: 'float', initial: 20.0, step: 1, min: 0, max: 25.0, caption: 'Kicktail, deg.'},
{ name: 'nose_radius', type: 'float', initial: 6, step: 1, max: 20, min: 4, caption: 'Nose Radius, in.'},
{ name: 'tail_radius', type: 'float', initial: 6, step: 1, max: 20, min: 4, caption: 'Tail Radius, in.'},
{ name: 'kick_gap', type: 'float', initial: 1, step: 0.125, max: 3, min: 0, caption: 'Kick Gap'},
{ name: 'taperN', type: 'float', initial: 6.75, step: 0.125, caption: 'Nose Taper Point, in.'},
{ name: 'taperT', type: 'float', initial: 6.75, step: 0.125, caption: 'Tail Taper Point, in.'},
{ name: 'nose_adjust', type: 'slider', class: 'paramSlider', min: 50, max: 100, initial: 70, step: 1, caption: 'Nose Shape'},
{ name: 'tail_adjust', type: 'slider', class: 'paramSlider', min: 50, max: 100, initial: 75, step: 1, caption: 'Tail Shape'},
{ name: 'cutout_specs', caption: '<hr> <span class="category">Wheel Cutouts</span>', type: 'group'},
{ name: 'make_cutouts', type: 'checkbox', checked: false, caption: 'Make Cutouts'},
{ name: 'noseLipX', type: 'slider', class: 'paramSlider', min: 5, max: 18, step: 0.5, initial: 14.5, caption: 'Nose Cutout Depth'},
{ name: 'noseLipY', type: 'slider', class: 'paramSlider', min: -2, max: 4, step: 0.5, initial: 1, caption: 'Nose Cutout Width'},
{ name: 'noseY', type: 'slider', class: 'paramSlider', min: 2, max: 9, initial: 6, step: 0.5, caption: 'Nose Width'},
{ name: 'tailLipX', type: 'slider', class: 'paramSlider', min: 5, max: 18, step: 0.5, initial: 14.5, caption: 'Tail Cutout Depth'},
{ name: 'tailLipY', type: 'slider', class: 'paramSlider', min: -2, max: 4, step: 0.5, initial: 1, caption: 'Tail Cutout Width'},
{ name: 'tailY', type: 'slider', class: 'paramSlider', min: 2, max: 9, initial: 6, step: 0.5, caption: 'Tail Width'},
{ name: 'resolution', type: 'float', initial: 0.25, step: 0.0625, caption: '<hr>Model Resolution<br><span style="font-size: 9px;">(For advanced users)</span><hr>'}
]);
}
/*
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 mold = parameters.mold;
var display = parameters.display_item;
var mold_size;
var showProfile = parameters.profile;
//var profile_choice = parameters.profile_choice;
//var mold_choice = parameters.mold_choice;
var mold_choice = '0';
var profile_choice = mold_choice;
var make_cutouts;
var width;
var wheelbase;
var tail_length;
var nose_length;
var nose_shape;
var tail_shape;
var taperN;
var taperT;
var noseLipX;
var noseLipY;
var noseY;
var tailLipX;
var tailLipY;
var tailY;
var concave_drop;
var concave_radius;
var kicknose_angle;
var kicktail_angle;
var kicknose_radius;
var kicktail_radius;
var kick_gap;
var thickness = 0.4375;
var bolt_pattern_width = 1.625;
var bolt_pattern_length = 2.125;
var nose_transition_length;
var tail_transition_length;
nose_transition_length = 4;
tail_transition_length = 4;
var mold_length;
var mold_width;
var mold_height;
if (profile_choice == '0') {
width = parameters.width;
wheelbase = parameters.wheelbase;
tail_length = parameters.tail_length;
nose_length = parameters.nose_length;
nose_shape = parameters.nose_adjust/100;
tail_shape = parameters.tail_adjust/100;
taperN = parameters.taperN;
taperT = parameters.taperT;
noseLipX = parameters.noseLipX;
noseLipY = parameters.noseLipY;
noseY = parameters.noseY;
tailLipX = parameters.tailLipX;
tailLipY = parameters.tailLipY;
tailY = parameters.tailY;
make_cutouts = parameters.make_cutouts;
}
else {
switch (profile_choice) {
case '1': //street deck;
width = 8.25;
wheelbase = 14;
tail_length = 6.75;
nose_length = 6.75;
nose_shape = 70/100;
tail_shape = 70/100;
taperN = 6.75;
taperT = 6.75;
noseLipX = parameters.noseLipX;
noseLipY = parameters.noseLipY;
noseY = parameters.noseY;
tailLipX = parameters.tailLipX;
tailLipY = parameters.tailLipY;
tailY = parameters.tailY;
make_cutouts = false;
break;
case '2': //dancer
width = 9;
wheelbase = 30;
tail_length = 5;
nose_length = 5;
nose_shape = 70/100;
tail_shape = 70/100;
taperN = 15;
taperT = 15;
noseLipX = 15;
noseLipY = 1;
noseY = 6;
tailLipX = 15;
tailLipY = 1;
tailY = 6;
make_cutouts = true;
break;
case '3': //cruiser
width = 8.25;
wheelbase = 15;
tail_length = 6.5;
nose_length = 5;
nose_shape = 60/100;
tail_shape = 82/100;
taperN = 10;
taperT = 12;
noseLipX = 15;
noseLipY = 1;
noseY = 6;
tailLipX = 15;
tailLipY = 1;
tailY = 6;
make_cutouts = false;
break;
}
}
if (mold_choice == '0') {
concave_drop = parseFloat(parameters.concave_drop);
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = parameters.kicknose_angle;
kicktail_angle = parameters.kicktail_angle;
kicknose_radius = parameters.nose_radius;
kicktail_radius = parameters.tail_radius;
kick_gap = parseFloat(parameters.kick_gap);
mold_size = parameters.mold_size;
}
else {
switch (mold_choice) {
case '1': //street deck
concave_drop = 0.375;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 20;
kicktail_angle = 20;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '0';
break;
case '2': //dancer
concave_drop = 0.125;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 12;
kicktail_angle = 12;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '1';
break;
case '3': //cruiser
concave_drop = 0.25;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 12;
kicktail_angle = 21;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '0';
break;
}
}
switch (mold_size) {
case '0':
mold_length = 34;
mold_width = 9.5;
mold_height = 3;
break;
case '1':
mold_length = 47;
mold_width = 12;
mold_height = 2;
break;
}
/*switch (mold) {
case '0':
kick_to_kick = 21; //placeholder, not used
break;
case '1': //13-16-11A22-05
concave_radius = 16.25;
kicknose_angle = 11;
kicktail_angle = 22;
nose_transition_length = 4.5;
tail_transition_length = 4.5;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 19.25;
break;
case '2': //asymmetrical - mid
concave_radius = 22.875;
kicknose_angle = 16;
kicktail_angle = 19;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 8;
kick_to_kick = 20.25;
break;
case '3': //13-20-21-05
concave_radius = 20;
kicknose_angle = 21;
kicktail_angle = 21;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 20.375;
break;
case '4': //14-34-15-06
concave_radius = 34;
kicknose_angle = 15;
kicktail_angle = 15;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 6;
kick_to_kick = 19.5;
break;
case '5': //14-62-14-09
concave_radius = 62;
kicknose_angle = 14;
kicktail_angle = 14;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.25;
break;
case '6': //14-33-18-10
concave_radius = 33;
kicknose_angle = 18;
kicktail_angle = 18;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 10;
kicktail_radius = 10;
kick_to_kick = 20.25;
break;
case '7': //14-20-18-09
concave_radius = 20;
kicknose_angle = 18;
kicktail_angle = 18;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.25;
break;
case '8': //14-20-20-09
concave_radius = 20;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.125;
break;
case '9': //medium
concave_radius = 20;
kicknose_angle = 19;
kicktail_angle = 19;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 6;
kick_to_kick = 20.25;
break;
case '10': //14-18-21-05
concave_radius = 18;
kicknose_angle = 21;
kicktail_angle = 21;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 21.125;
break;
case '11': //big medium (hammerhead)
concave_radius = 19;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 21.25;
break;
case '12': //XL medium
concave_radius = 25;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 22.25;
break;
}
*/
kick_to_kick = wheelbase + (2*bolt_pattern_length)+ (2*kick_gap);
var kicknose_length = (wheelbase/2) + bolt_pattern_length + nose_length - (kick_to_kick/2);
var kicktail_length = (wheelbase/2) + bolt_pattern_length + tail_length - (kick_to_kick/2);
var slice_thickness = parseFloat(parameters.resolution);
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;
var depth = 1;
console.log("test");
if (showProfile == true) {
if (make_cutouts == false) {
skateboard = make_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth);
}
else {
skateboard = make_lb_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, depth, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
}
}
else {
if (display == 1) {
skateboard = make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([0,0,thickness]);
if (kicknose_angle !== 0) {
skateboard = skateboard.union(make_kicknose_curve(kicknose_radius, thickness, width, kicknose_angle, nose_transition_length, concave_length));
}
else {
skateboard = skateboard.union(make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([concave_length,0,thickness]));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(make_kicktail_curve(kicktail_radius, thickness, width, kicktail_angle, tail_transition_length, concave_length));
}
else {
skateboard = skateboard.union(make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([-concave_length,0,thickness]));
}
if (kicknose_angle !== 0) {
skateboard = skateboard.union(make_kicknose_section(wheelbase, bolt_pattern_length, nose_length, kicknose_length, kicknose_radius_length, width, kicknose_radius_height, thickness, kicknose_angle, nose_transition_length, concave_length));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(make_kicktail_section(wheelbase, bolt_pattern_length, tail_length, kicktail_length, kicktail_radius_length, width, kicktail_radius_height, thickness, kicktail_angle, tail_transition_length, concave_length));
}
if (concave_radius!==0) {
if (kicknose_angle !== 0) {
skateboard = skateboard.union(
((rotate([0,0,90], make_transition_section(nose_transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)))).translate([concave_length/2+nose_transition_length,0,0]));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(
((rotate([0,0,-90], make_transition_section(tail_transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)))).translate([-(concave_length/2+tail_transition_length),0,0]));
}
}
var profile;
if (make_cutouts == false) {
profile = make_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, 10);
}
else {
profile = make_lb_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, 10, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
}
skateboard = skateboard.intersect(profile);
}
else {
if (kicknose_angle !== 0) {
kicknose = make_mold_kicknose_curve(kicknose_radius, mold_width, kicknose_angle, nose_transition_length, concave_length, kicknose_length);
}
else {
kicknose = make_mold_concave(concave_radius, mold_height, concave_length, mold_width,flat_concave_length).translate([concave_length,0,0]);
}
if (kicktail_angle !== 0) {
kicktail = make_mold_kicktail_curve(kicktail_radius, mold_width, kicktail_angle, tail_transition_length, concave_length, kicktail_length);
}
else {
kicktail = make_mold_concave(concave_radius, mold_height, concave_length, mold_width,flat_concave_length).translate([-concave_length,0,0]);
}
var mold = color([0.7,0.7,0.7],make_mold_concave(concave_radius, mold_height, concave_length, mold_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_mold_transition_section(nose_transition_length, mold_height+2, slice_thickness, mold_width, min_radius, number_of_segments);
var tail_transition = mirror([1,0,0], make_mold_transition_section(tail_transition_length, mold_height+2, slice_thickness, mold_width, min_radius, number_of_segments));
if (kicknose_angle !== 0) {
mold = mold.union(color([0.2,0.2,0.2],nose_transition.translate([concave_length/2+nose_transition_length,0,0])));
}
if (kicktail_angle !== 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+nose_length-tail_length)/2,0,-mold_height/2])));
skateboard = mold;
}
}
var mDia = 0.5; //notch diameter
if (display == '0') {
skateboard = skateboard.subtract(make_markers(mold_width, wheelbase, nose_length, tail_length, bolt_pattern_length, mDia, kick_gap, nose_transition_length, tail_transition_length));
}
if (display !== '0' || showProfile == true) {
skateboard = skateboard.subtract(make_wheelbase(bolt_pattern_length, bolt_pattern_width,wheelbase));
}
skateboard = color([0,0.99,0],skateboard);
return skateboard;
}
function make_origin(origin)
{
var result = new CSG();
var height = 20;
result = union(
cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2]),
union(
rotate([-90,0,0],cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2])),
rotate([0,90,0],cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2]))
)
);
return result;
}
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_bolt_pattern(bolt_pattern_length, bolt_pattern_width)
{
var result = new CSG();
result = (cylinder({d: 0.1875, h: 6, center: false}).translate([bolt_pattern_length/2,bolt_pattern_width/2,0])).union(cylinder({d: 0.1875, h: 6, center: false}).translate([bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: 0.1875, h: 6, center: false}).translate([-bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: 0.1875, h: 6, center: false}).translate([-bolt_pattern_length/2,bolt_pattern_width/2,0]));
return result;
}
function make_wheelbase(bolt_pattern_length, bolt_pattern_width, wheelbase)
{
var result = new CSG();
result = (make_bolt_pattern(bolt_pattern_length,bolt_pattern_width).translate([(wheelbase/2)+(bolt_pattern_length/2),0,-1])).union(make_bolt_pattern(bolt_pattern_length,bolt_pattern_width).translate([-((wheelbase/2)+(bolt_pattern_length/2)),0,-1]));
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=
difference(
difference(
difference(
(rotate([90,0,90], difference(
cylinder({r: (concave_radius + thickness), h: concave_length, center: true, fn: 500}),
cylinder({r: concave_radius, h:concave_length+2, center: true, fn: 500}).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_mold_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_kicknose_curve(kicknose_radius, thickness, width, kicknose_angle, nose_transition_length, concave_length)
{
var result = new CSG();
result =
difference(
difference(
rotate([90,0,90], difference(
cylinder({r: kicknose_radius+thickness, h: width, center: false, fn: 100}),
cylinder({r: kicknose_radius, h: width+2, center: false, fn: 100}).translate([0,0,-1])
)),
rotate([0,0,90], cube({size: [kicknose_radius*2, width*4, kicknose_radius*4], center: false}).translate([-kicknose_radius*2, -width*2, -kicknose_radius-2])
)),
mirror([1,0,0], rotate([0, kicknose_angle, -90], cube({size: [kicknose_radius*2, width*4, kicknose_radius*4], center: false}).translate([-kicknose_radius*2, -width*2, -kicknose_radius*2])))
).translate([0,0,kicknose_radius+thickness]);
result = rotate([0,0,-90],(result.translate([-width/2,0,0])));
result = result.translate([concave_length/2+nose_transition_length,0,0]);
return result;
}
function make_kicktail_curve(kicktail_radius, thickness, width, kicktail_angle, tail_transition_length, concave_length)
{
var result = new CSG();
result =
mirror([0,1,0],
difference(
difference(
rotate([90,0,90], difference(
cylinder({r: kicktail_radius+thickness, h: width, center: false, fn: 100}),
cylinder({r: kicktail_radius, h: width+2, center: false, fn: 100}).translate([0,0,-1])
)),
rotate([0,0,90], cube({size: [kicktail_radius*2, width*4, kicktail_radius*4], center: false}).translate([-kicktail_radius*2, -width*2, -kicktail_radius-2])
)),
mirror([1,0,0], rotate([0, kicktail_angle, -90], cube({size: [kicktail_radius*2, width*4, kicktail_radius*4], center: false}).translate([-kicktail_radius*2, -width*2, -kicktail_radius*2])))
).translate([0,0,kicktail_radius+thickness])
);
result = rotate([0,0,-90],(result.translate([-width/2,0,0])));
result = result.translate([-concave_length/2-tail_transition_length,0,0]);
return result;
}
function make_mold_kicknose_curve(kicknose_radius, width, kicknose_angle, nose_transition_length, concave_length, kicknose_length)
{
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*2], 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.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_mold_kicktail_curve(kicktail_radius, width, kicktail_angle, tail_transition_length, concave_length, kicktail_length)
{
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*2], 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]})).translate([0,-width,0]));
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_kicknose_section(wheelbase, bolt_pattern_length, nose_length, kicknose_length, kicknose_radius_length, width, kicknose_radius_height, thickness, kicknose_angle, nose_transition_length, concave_length)
{
var result = new CSG();
result = mirror([0,0,1], cube({size: [kicknose_length, width, thickness]}));
result = rotate([0,-kicknose_angle,0],result);
result = result.translate([concave_length/2+nose_transition_length+kicknose_radius_length,-width/2,kicknose_radius_height+thickness]);
return result;
}
function make_kicktail_section(wheelbase, bolt_pattern_length, tail_length, kicktail_length, kicktail_radius_length, width, kicktail_radius_height, thickness, kicktail_angle, tail_transition_length, concave_length)
{
var result = new CSG();
result = mirror([0,0,1], cube({size: [kicktail_length, width, thickness]}));
result = rotate([0,-kicktail_angle,0],result);
result = mirror([1,0,0], result);
result = result.translate([-(concave_length/2+tail_transition_length+kicktail_radius_length),-width/2,kicktail_radius_height+thickness]);
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); //concave depth
var flat_y = 0; //no concave
//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
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=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)));
}
*/
// 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);
console.log(x_val + ',' + y_val);
var reg_radius = (Math.pow((width/2),2) + Math.pow(y_val,2))/(2*y_val);
var reg_half_angle = asin((width/2)/reg_radius);
var reg_segment_angle = reg_half_angle/number_of_segments;
var sub_radius = reg_radius+thickness;
var sub_half_angle = asin((width/2)/sub_radius);
var sub_segment_angle = sub_half_angle/number_of_segments;
result = result.union(
linear_extrude({height: x_val-x_val_last, center: false},
polygon({ //currently set up for 20 segments per full arc:
points: [
[(sub_radius*sin(sub_segment_angle*0)),(sub_radius*cos(sub_segment_angle*0))],
[(sub_radius*sin(sub_segment_angle*1)),(sub_radius*cos(sub_segment_angle*1))],
[(sub_radius*sin(sub_segment_angle*2)),(sub_radius*cos(sub_segment_angle*2))],
[(sub_radius*sin(sub_segment_angle*3)),(sub_radius*cos(sub_segment_angle*3))],
[(sub_radius*sin(sub_segment_angle*4)),(sub_radius*cos(sub_segment_angle*4))],
[(sub_radius*sin(sub_segment_angle*5)),(sub_radius*cos(sub_segment_angle*5))],
[(sub_radius*sin(sub_segment_angle*6)),(sub_radius*cos(sub_segment_angle*6))],
[(sub_radius*sin(sub_segment_angle*7)),(sub_radius*cos(sub_segment_angle*7))],
[(sub_radius*sin(sub_segment_angle*8)),(sub_radius*cos(sub_segment_angle*8))],
[(sub_radius*sin(sub_segment_angle*9)),(sub_radius*cos(sub_segment_angle*9))],
[(sub_radius*sin(sub_segment_angle*10)),(sub_radius*cos(sub_segment_angle*10))],
[(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))]
]
})).translate([0,-sub_radius,x_val_last])
);
x_val_last = x_val;
slice_adj = slice_adj + slice_thickness;
}
result = result.union(mirror([1,0,0],result));
result = rotate([-90,0,0],result);
return result;
}
function make_mold_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
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=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);
console.log(x_val + ',' + y_val);
var reg_radius = (Math.pow((width/2),2) + Math.pow(y_val,2))/(2*y_val);
// console.log("reg_radius is ");
console.log(reg_radius);
//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;
}
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;
}
Please consider donating.
Skatebird will be stoked for any contribution you can afford.
...
CNC Machined Foam Mold
Mold Info: Molds are CNC machined using Roarockit high-density foam blanks. The top surface will have clear tape applied as a mold release, and 1/2" diameter notches will be made as shown to aid with board alignment.
Shipping: Molds ship in about 5-7 business days. Default shipping is economy ground - contact us if you'd like to know about alternative shipping methods, to pick up your mold, or for larger order quantities.
International customers: Please contact us for a shipping quote to place your order.
If you'd like additional customization - wheel flares, rocker, camber, alternative concaves, etc., please contact us for our design services. There's typically a $100 design fee for such features.