scad/parametric_butt_hinge_3.8.scad

1711 lines
63 KiB
OpenSCAD

// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Title: Parametric Butt Hinge
// Version: 3.8
// Release Date: 2021-05-08 (ISO 8601)
// Author: Rohin Gosling
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
//
// Description:
//
// - Parametric butt hinge, designed to be printed in one step.
//
// - While the entire working hinge may be printed in one step, it is also possible to disabled the internal fused pin, and leave a shaft
// which may be used in the case where an external pin is desired.
//
// Release Notes:
//
// - Version 3.8
// * Corrected the title comment at the top of the file from to refernce the correct project title, "Parametric Butt Hinge".
// * Previous versions had the title comment, "Parametric Caged Bearing". This was an old copy and paste error that made it
// all the way through to version 3.7. Fixed now.
//
// - Version 3.7
// * Added a comment for the "knuckle_count" parameter, to notify users to always set an odd knuckle count in order to ensure that the unified
// pin is supported by male knuckles on both ends. An even number of knuckles will leave one end of the unified pin unsupported by a male knuckle.
// * Added a constraint to the "knuckle_count" parameter, to force an odd knuckle count. Even knuckle counts are now incemented to next odd number.
// Example:
// - A knuckle count of 4, will be incremented to 5.
// - A knuckle count of 10 will, with be incremented to 11
//
// - Version 3.6
// * Removed extended ASCII characters to make the source code compatible with the UTF-8 encoding required by the Thingiverse Customizer.
//
// - Version 3.5
// * For hexagonal counterbores, the hexagonal cut has been rotated 90 degrees, to reduce the need for support material.
// The overhang angle for hexagonal counterbore is 60 degrees.
//
// - Version 3.4
// * Added support for linear and parabolic gusset curves.
// * Factored out all SCG (Solid Constructive Geometry) overlap constants, and consolidated them into one global constant, "SCG_OVERLAP".
//
// - Version 3.3
// * Placed pin shaft parameters into their own parameter group in the Thingiverse Customizer.
//
// - Version 3.2
// * Added support for independently configurable top and bottom pin shaft counterbores.
// * Added an assembly option to flip the model about the z-axis.
// Usefull for viewing the top and bottom pin shaft counterbores.
// * Configured the hinge throw angle Thingiverse Customizer parameter step size, to 5 degrees.
//
// - Version 3.1
// * Added a counterbore feature for the pin shaft.
// - While this feature may be enabled for one piece hinges that have the fused pin enabled, it is primarily designed for use with two
// piece configurations that have their pin disabled. For instance, when the hinge is to be assembled using an external pin.
// - In the case where a hinge is to be assembled using an external pin, it may be desired to have a pin shaft counterbore, where the end
// caps of the knuckle joint array are counterbored, in order to allow the pin or bolt heads of the pin shaft, to be set flush with the
// top and bottom edges of the hinge leaves.
// - To accommodate both hexagonal and square bolt heads and nuts, the counterbore may be set to any one of circular, square or hexagonal.
// * Added private text feature.
// - A public parameter for the Thingiverse Customizer has not been added yet, however, users may set the 'text_enabled' local variable
// in the 'leaf' module to 'true', which will enable a single row of inscribed text on each leaf.
// - By default this feature will only work when exactly 4 fastener holes have been selected via the 'fastener_count' parameter, simply
// because there is a nice open space available between the fastener holes for placing text, when 4 fastener holes are chosen.
// - Text for the male and female leaves may be specified independently.
//
// - Version 3.0
// * Added a parameter to disable the hinge pin, for when users would like to assemble with an external pin.
// * Changed the main Thingiverse Customizer parameter group name from "Hinge Options", to "Assembly Options".
// * Added a parameter to set the hinge throw angle.
// Users can now set the throw angle, either for analysis and visualisation purposes, or for when the hinge is to be printed vertically
// standing up on edge, in which case a throw angle of 120 degrees may be used to help keep the hinge stable on the build plate.
// * Corrected spelling errors in the comments.
//
// - Version 2.9
// * Added support for parabolic knuckle gussets to strengthen the knuckle joints.
// Knuckle gussets may now be toggled on and off with the 'enable_knuckle_gusset' parameter.
//
// - Version 2.8
// * Added the parameter, 'fastener_column_count', to enable single column fastener arrangements, that can be used for
// piano hinge style fastener arrangements.
//
// - Version 2.7
// * Rewrote the knuckle cutter module using mode generic math, that enables more parametizable control over knuckle joint
// dimensions and configuration.
//
// - Version 2.6
// * Added support for countersunk fastener holes. Now users can select either counterbore or countersunk.
// dimensions and configuration.
// * Started tracking release updates.
//
// - Version 1.0 - 2.5
// * N/A - Release updates not tracked.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Constants:
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// System constants.
C_CONSTANT = 0 + 0; // Used to hide constant values from Thingiverse. Add to other constants to hide them as well.
C_NONE = C_CONSTANT + 0;
// Leaf gender.
C_FEMALE = C_CONSTANT + 0;
C_MALE = C_CONSTANT + 1;
// SCG constants.
SCG_OVERLAP = C_CONSTANT + 0.01; // Used for overlapping Boolean operations in order to avoid Boolean edge artefacts.
C_NEGATIVE = C_CONSTANT + 0; // Used for subtractive Boolean tools.
C_POSITIVE = C_CONSTANT + 1; // Used for additive Boolean tools.
// Bolt head shapes.
C_CIRCULAR = C_CONSTANT + 0;
C_SQUARE = C_CONSTANT + 1;
C_HEXAGONAL = C_CONSTANT + 2;
// Curve Type
C_FUNCTION_LINEAR = C_CONSTANT + 1; // y = ax + b
C_FUNCTION_CIRCULAR = C_CONSTANT + 2; // r2 = x2 + y2
C_FUNCTION_PARABOLIC = C_CONSTANT + 3; // y = a2(x - j)2 + k ...Vertex form.
// Minimum and maximum constraints.
C_MIN_HINGE_WIDTH = C_CONSTANT + 1.0;
C_MIN_HINGE_HEIGHT = C_CONSTANT + 1.0;
C_MIN_LEAF_GAUGE = C_CONSTANT + 1.0;
C_MIN_COMPONENT_CLEARENCE = C_CONSTANT + 0.1;
C_MAX_COMPONENT_CLEARENCE = C_CONSTANT + 1.0;
C_MIN_KNUCKLE_COUNT = C_CONSTANT + 3;
C_MAX_KNUCKLE_COUNT = C_CONSTANT + 15;
C_MIN_KNUCKLE_GUSSET_WIDTH = C_CONSTANT + 1.0;
C_MIN_FASTENER_MARGIN = C_CONSTANT + 1.0;
C_MIN_PIN_DIAMETER = C_CONSTANT + 1.0;
C_MIN_COUNTER_SINK_DEPTH_STOP = C_CONSTANT + 1.0;
C_MIN_FASTENER_THREAD_DIAMETER = C_CONSTANT + 0.0;
C_MIN_FASTENER_COUNT = C_CONSTANT + 3;
C_MIN_FASTENER_COLUMN_COUNT = C_CONSTANT + 1;
C_MAX_FASTENER_COLUMN_COUNT = C_CONSTANT + 2;
C_MIN_TESSELLATION = C_CONSTANT + 32;
C_MAX_TESSELLATION = C_CONSTANT + 256;
C_MIN_THROW_ANGLE = C_CONSTANT + -90;
C_MAX_THROW_ANGLE = C_CONSTANT + 180;
C_DEFAULT_THROW_ANGLE = C_CONSTANT + 0;
C_MIN_PIN_SHAFT_COUNTERBORE_DIAMETER = C_CONSTANT + 0.1;
C_MIN_PIN_SHAFT_COUNTERBORE_WALL_THICKNESS = C_CONSTANT + 0.3;
C_MIN_PIN_SHAFT_COUNTERBORE_DEPTH = C_CONSTANT + 0.0;
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Thingiverse Parameters.
//
// - These parameters are used to integrate with the Thingiverse Customizer, and should only be used by the
// class member variables specified in the "Model parameters" section below.
//
// - These Thingiverse Parameters should never be accessed from inside any module. We do this to enforce
// principles of object orientation.
//
// - By separating concerns between variables exposed to Thingiverse vs. variables used internally by the
// SCAD model (class), we are better able to manage the ordering and grouping of variables exposed to
// Thingiverse, vs. the ordering of variables used internally by the model.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
/* [Assembly Options] */
enable_male_leaf = 1; // [ 0:No, 1:Yes ]
enable_female_leaf = 1; // [ 0:No, 1:Yes ]
enable_fillet = 1; // [ 0:No, 1:Yes ]
// Turn this off to omit the hinge pin from the female leaf.
enable_pin = 0; // [ 0:No, 1:Yes ]
// Turn this off to set a custom pin diameter. Auto pin size is equal to the leaf gauge.
enable_auto_pin_size = 1; // [ 0:No, 1:Yes ]
enable_pin_shaft_counterbore = 0; // [ 0:No, 1:Yes ]
enable_fasteners = 1; // [ 0:No, 1:Yes ]
knuckle_gusset_type = 0; // [ 0:None, 1:Linear, 2:Circular, 3:Parabolic ]
// From +180 degrees fully closed, to -90 degrees fully opened. Default = 0 (ie. Opened flat).
throw_angle = 90.0; // [ -90 : 5 : 180 ]
// Rotates the model 180 degrees about the z-axis.
flip_model = 0; // [ 0:No, 1:Yes ]
// Recommended value is 64 or greater.
resolution = 128;
component_color = "Silver";
/* [Hinge Parameters] */
hinge_width = 25.0;
leaf_height = 20.0;
// Leaf and knuckle thickness. Values greater than 3mm recommended.
leaf_gauge = 5.0;
// Recomended values between 0.3 and 4.0. Better quality below 3.0, tough to loosen.
component_clearance = 0.4;
// Knuckle count must be an odd number, so that the pin is supported on both ends.
knuckle_count = 3; // [3:2:31]
// Manual pin diameter setting. Only has effect, if "Enable Auto Pin Size" is set to "No".
pin_diameter = 2.0;
parametric_pin_diameter = ( enable_auto_pin_size == 1 ) ? leaf_gauge : pin_diameter;
/* [Pin Shaft Parameters] */
top_pin_shaft_counterbore_diameter = 6.5;
top_pin_shaft_counterbore_depth = 2.5;
top_pin_shaft_counterbore_shape = 0; // [ 0:Circular, 1:Square, 2:Hexagonal ]
bottom_pin_shaft_counterbore_diameter = 6.0;
bottom_pin_shaft_counterbore_depth = 2.5;
bottom_pin_shaft_counterbore_shape = 2; // [ 0:Circular, 1:Square, 2:Hexagonal ]
/* [Fastener Parameters] */
// For countersunk, the chamfer angle may be adjusted using the other parameters.
fstener_head_type = 0; // [ 0:Counterbored, 1:Countersunk ]
counter_sink_depth = 2.5;
fastener_thread_diameter = 3.5;
// Add 0.5mm to 1.0mm to the fastener head diameter, to allow for head clearance.
fastener_head_diameter = 4.5;
fastener_count = 3; // [3:32]
fastener_column_count = 2; // [1,2]
// Distance from the edge of the head diameter, to the edges of the leaves.
fastener_margin = 3;
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Model parameters and geometric constraints. (Class member variables).
//
// - If we treat an OpenSCAD file as though it is an object oriented class, then we can prefix global variables
// with "m_", to denote class membership.
// - As an alternative to "m_", we could also use "this_" as a standard. However, "m_" is shorter and faster to type.
// - Another advantage of this convention, is that we can arrange parameters meant for display in Thingiverse, in
// an order that makes sense to the user, while arranging the member versions of the parameters in an order
// that better accommodates constraint computation.
//
// - Once we have defined global variables as member variables of a class, in this case the class represented
// by the SCAD file, then we are free to better manage global vs local scope of class member
// variables, vs. local module (method) variables.
//
// - Thingiverse only integrates constant literal values. So as long as we reference other parameters or
// initialize variables as expressions, then none of these will appear in the Thingiverse customizer.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Assembly Options.
m_male_leaf_enabled = ( enable_male_leaf == 1 ) ? true : false;
m_female_leaf_enabled = ( enable_female_leaf == 1 ) ? true : false;
m_leaf_fillet_enabled = ( enable_fillet == 1 ) ? true : false;
m_pin_enabled = ( enable_pin == 1 ) ? true : false;
m_pin_auto_size_enabled = ( enable_auto_pin_size == 1 ) ? true : false;
m_pin_shaft_counterbore_enabled = ( enable_pin_shaft_counterbore == 1 ) ? true : false;
m_fasteners_enabled = ( enable_fasteners == 1 ) ? true : false;
m_knuckle_gusset_type = knuckle_gusset_type;
m_flip_model = ( flip_model == 1 ) ? true : false;
m_throw_angle = clip ( throw_angle, C_MIN_THROW_ANGLE, C_MAX_THROW_ANGLE );
// Leaf Parameters.
m_hinge_width = ( hinge_width <= C_MIN_HINGE_WIDTH ) ? C_MIN_HINGE_WIDTH : hinge_width;
m_leaf_width = m_hinge_width / 2.0;
m_leaf_height = ( leaf_height <= C_MIN_HINGE_HEIGHT ) ? C_MIN_HINGE_HEIGHT : leaf_height;
m_leaf_gauge = clip ( leaf_gauge, C_MIN_LEAF_GAUGE, m_leaf_width/2.0 );
// Mechanical Properties.
m_component_clearance = clip ( component_clearance, C_MIN_COMPONENT_CLEARENCE, C_MAX_COMPONENT_CLEARENCE );
m_knuckle_outer_radius = m_leaf_gauge * 2.0;
m_knuckle_count = clip ( 1 + 2 * floor ( knuckle_count / 2 ), C_MIN_KNUCKLE_COUNT, C_MAX_KNUCKLE_COUNT );
m_fastener_margin = clip ( fastener_margin, C_MIN_FASTENER_MARGIN, ( m_leaf_width - m_leaf_gauge - fastener_head_diameter )/2.0 );
m_knuckle_gusset_width = clip ( m_fastener_margin, C_MIN_KNUCKLE_GUSSET_WIDTH, m_leaf_width - m_leaf_gauge - m_component_clearance );
// Pin Parameters.
m_pin_diameter = clip ( pin_diameter, C_MIN_PIN_DIAMETER, 2.0*m_leaf_gauge - C_MIN_PIN_DIAMETER );
m_parametric_pin_diameter = ( m_pin_auto_size_enabled == true ) ? m_leaf_gauge : m_pin_diameter;
m_top_pin_shaft_counterbore_diameter = clip ( top_pin_shaft_counterbore_diameter, C_MIN_PIN_SHAFT_COUNTERBORE_DIAMETER, 2.0*m_leaf_gauge - C_MIN_PIN_SHAFT_COUNTERBORE_WALL_THICKNESS );
m_top_pin_shaft_counterbore_depth = clip ( top_pin_shaft_counterbore_depth, C_MIN_PIN_SHAFT_COUNTERBORE_DEPTH, 0.66*( m_leaf_height / ( m_knuckle_count + m_component_clearance )) );
m_top_pin_shaft_counterbore_shape = top_pin_shaft_counterbore_shape;
m_bottom_pin_shaft_counterbore_diameter = clip ( bottom_pin_shaft_counterbore_diameter, C_MIN_PIN_SHAFT_COUNTERBORE_DIAMETER, 2.0*m_leaf_gauge - C_MIN_PIN_SHAFT_COUNTERBORE_WALL_THICKNESS );
m_bottom_pin_shaft_counterbore_depth = clip ( bottom_pin_shaft_counterbore_depth, C_MIN_PIN_SHAFT_COUNTERBORE_DEPTH, 0.8*( m_leaf_height / m_knuckle_count) );
m_bottom_pin_shaft_counterbore_shape = bottom_pin_shaft_counterbore_shape;
// Fastener parameters.
m_fstener_head_type = fstener_head_type;
m_counter_sink_depth = clip ( counter_sink_depth, 0.0, m_leaf_gauge - C_MIN_COUNTER_SINK_DEPTH_STOP );
m_fastener_head_diameter = clip ( fastener_head_diameter, fastener_thread_diameter, m_leaf_width - m_leaf_gauge - m_component_clearance - 2.0*m_fastener_margin );
m_fastener_thread_diameter = clip ( fastener_thread_diameter, C_MIN_FASTENER_THREAD_DIAMETER, m_fastener_head_diameter );
m_fastener_column_count = clip ( fastener_column_count, C_MIN_FASTENER_COLUMN_COUNT, C_MAX_FASTENER_COLUMN_COUNT );
m_fastener_count = clip ( fastener_count, C_MIN_FASTENER_COUNT, m_fastener_column_count*( m_leaf_height - 2.0*m_fastener_margin )/(m_fastener_head_diameter + m_component_clearance));
m_leaf_fillet_radius = m_fastener_head_diameter / 2.0 + m_fastener_margin;
// Model parameters.
m_resolution = clip ( resolution, C_MIN_TESSELLATION, C_MAX_TESSELLATION );
m_component_color = component_color;
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// DEBUG: Console Output.
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
C_DEBUG_ENABLED = false;
if ( C_DEBUG_ENABLED )
{
echo ( m_hinge_width = m_hinge_width );
echo ( m_leaf_width = m_leaf_width );
echo ( absolute_leaf_width = m_leaf_width - m_leaf_gauge );
echo ( m_leaf_height = m_leaf_height );
echo ( m_leaf_gauge = m_leaf_gauge );
echo ( m_component_clearance = m_component_clearance );
echo ( m_knuckle_outer_radius = m_knuckle_outer_radius );
echo ( m_knuckle_count = m_knuckle_count );
echo ( m_knuckle_gusset_width = m_knuckle_gusset_width );
echo ( m_leaf_fillet_radius = m_leaf_fillet_radius );
echo ( m_fastener_margin = m_fastener_margin );
echo ( m_pin_diameter = m_pin_diameter );
echo ( m_parametric_pin_diameter = m_parametric_pin_diameter );
echo ( absolute_pin_diameter = m_parametric_pin_diameter - m_component_clearance / 2.0 );
echo ( m_pin_shaft_counterbore_diameter = m_pin_shaft_counterbore_diameter );
echo ( m_pin_shaft_counterbore_depth = m_pin_shaft_counterbore_depth );
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: Main
// Module Type: Model
//
// Description:
//
// - Program entry point.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
main();
module main ()
{
// Initialize model resolution.
$fn = m_resolution;
// Generate hinge assembly.
rotate ( [ 0.0, 0.0, ( m_flip_model ) ? 180.0 : 0.0 ] )
{
if ( m_female_leaf_enabled ) rotate ( [ 0.0, -m_throw_angle, 0.0 ] ) leaf ( C_FEMALE );
if ( m_male_leaf_enabled ) leaf ( C_MALE );
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: leaf.
// Module Type: Component.
//
// Description:
//
// - Creates a hinge leaf component, whose gender may be selected through the gender argument.
//
// - Note:
// The text option is not made public to the Thingiverse Customizer at this time.
// However, you can add and configure text here in the code.
//
// Parameters:
//
// - gender:
// The gender (male, female), of the leaf. The female leaf holds the pin.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module leaf ( gender )
{
// Text configuration.
text_enabled = false;
text_string_female = "0.4";
text_string_male = "RG";
text_female_font_size = 8;
text_male_font_size = 8;
// Compute the gender angle.
// - 0 degrees for female, and 180 degrees for male.
// - In other words, we leave the female leaf un-rotated, but we rotate the male leaf 180 degrees, to place it at an
// opposing orientation to the female.
gender_angle = ( gender == C_FEMALE ) ? 0 : 180;
// Create leaves.
rotate ( [ 0, 0, gender_angle ] )
{
color ( m_component_color )
difference ()
{
// Cut pin hole.
workpiece_leaf_knuckle_pin ( gender );
// Cut fstener holes.
if ( m_fasteners_enabled )
{
tool_cutter_fastener_set ( m_fastener_count, m_fastener_column_count, 0 );
}
// Cut pin shaft counterbore into female leaf.
if ( m_pin_shaft_counterbore_enabled && gender == C_FEMALE )
{
tool_cutter_pin_shaft_counterbore
(
diameter_top = m_top_pin_shaft_counterbore_diameter,
depth_top = m_top_pin_shaft_counterbore_depth,
shape_top = m_top_pin_shaft_counterbore_shape,
diameter_bottom = m_bottom_pin_shaft_counterbore_diameter,
depth_bottom = m_bottom_pin_shaft_counterbore_depth,
shape_bottom = m_bottom_pin_shaft_counterbore_shape
);
}
// Cut text.
// - We will only cut text into the leaves, if we are using exactly 4 fasteners per leaf.
// - All other leaf counts will not leave enough space for the text to fit easily. So we only add text, if we are using 4 fasteners.
if ( text_enabled && m_fastener_count == 4 )
{
if ( gender == C_FEMALE ) tool_cutter_text ( text_string_female, text_female_font_size );
if ( gender == C_MALE ) tool_cutter_text ( text_string_male, text_male_font_size );
}
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_leaf_knuckle_pin
// Module Type: Workpiece.
//
// Description:
//
// - This module creates the workpiece used to construct either a male or female leaves.
//
// Parameters:
//
// - gender:
// The gender (male, female), of the leaf. The female leaf holds the pin.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_leaf_knuckle_pin ( gender )
{
// Initialize local variables.
d = m_parametric_pin_diameter;
c = m_component_clearance;
e = SCG_OVERLAP;
// Combine pin with leaf and knuckle.
if ( gender == C_FEMALE )
{
if ( m_pin_enabled )
{
// Fuse the pin to the female leaf by default.
union ()
{
dc = d - c/2.0;
workpiece_leaf_knuckle ( C_FEMALE );
pin ( dc, m_leaf_height - e );
}
}
else
{
// Cut a hole for an external pin if selected by the user.
difference ()
{
dc = d + c/2.0;
workpiece_leaf_knuckle ( C_FEMALE );
pin ( dc, m_leaf_height + e );
}
}
}
else
{
// Cut a hole for the pin to pass throug in the male leaf.
difference ()
{
dc = d + c/2.0;
workpiece_leaf_knuckle ( C_MALE );
pin ( dc, m_leaf_height + e );
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: pin
// Module Type: Component.
//
// Description:
//
// - Hinge pin component.
//
// Parameters:
//
// - diameter:
// Diameter of the cylinder used to create the pin.
//
// - length:
// Length of the cylinder used to create the pin.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module pin ( diameter, length )
{
rotate ( [ 90, 0, 0 ] )
{
// Initialize pin dimensions.
tx = 0;
ty = 0;
tz = -length/2;
// Create pin.
translate ( [ tx, ty, tz ] )
{
cylinder ( d = diameter, h = length );
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_leaf_knuckle
// Module Type: Workpiece.
//
// Description:
//
// - Workpiece used to cut away knuckle structures.
//
// Parameters:
//
// - gender:
// The gender (male, female), of the leaf. The female leaf holds the pin.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_leaf_knuckle ( gender )
{
// Initialize local variables.
gender_flipped = ( gender == C_MALE ) ? C_FEMALE : C_MALE;
w = m_leaf_width;
l = m_leaf_height;
h = m_leaf_gauge;
r = m_leaf_fillet_radius;
d = m_knuckle_outer_radius;
// Create workpiece.
difference ()
{
difference ()
{
// leaf and knuckle work piece.
translate ( [ 0, -l/2, 0 ] )
{
union ()
{
// Leaf.
workpiece_leaf ( w, l, h, r );
// Knuckle.
rotate ( [ -90, 0, 0 ] ) cylinder ( d = d, h = l );
// Gusset array.
if ( m_knuckle_gusset_type != C_NONE )
{
translate ( [ 0, l/2, 0 ] )
workpiece_gusset_array
(
gender = gender,
curve = m_knuckle_gusset_type,
scg_type = C_POSITIVE,
fill_component_clearance = false
);
}
}
}
// Cut knuckle gaps.
tool_cutter_knuckle_array
(
gender = gender,
fill_component_clearance = true,
size = 2.0*m_leaf_gauge + m_component_clearance
);
}
// Cut opposing gusset groves.
if ( m_knuckle_gusset_type != C_NONE )
{
workpiece_gusset_array
(
gender = gender_flipped,
curve = m_knuckle_gusset_type,
scg_type = C_NEGATIVE,
fill_component_clearance = true
);
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_leaf
// Module Type: Workpiece.
//
// Description:
//
// - Workpiece used to cut away leaf structures.
//
// Parameters:
//
// - w:
// Width of a single leaf.
//
// - l:
// Length of the leaf.
//
// - h:
// Height of the leaf.
//
// - r:
// Radius of the hinge knuckle.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_leaf ( w, l, h, r )
{
translate ( [ 0, 0, -h ] )
{
union ()
{
if ( m_leaf_fillet_enabled )
{
// Leaf.
cube ( [ w-r, l, h] );
translate ( [ 0, r, 0 ] ) cube ( [ w, l-2*r, h] );
// Fillet corcers.
translate ( [ w - r, r, 0 ] ) cylinder ( r = r, h = h );
translate ( [ w - r, l-r, 0 ] ) cylinder ( r = r, h = h );
}
else
{
// Leaf.
cube ( [ w, l, h] );
}
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_gusset_array
// Module Type: Workpiece.
//
// Description:
//
// - Create an array of cutting blocks. Mostly used to cut gusset workpiece into individual gusset positives or negatives.
//
// Parameters:
//
// - gender:
// Specifies the number of knuckle joints based on hinge leaf gender.
//
// - scg_type:
// Solid Constructive Geometry type.
// If C_POSITIVE, then add to the base work piece.
// If C_NAGATIVE, then subtract from the base workpiece.
//
// - fill_component_clearance:
// If true, then create wide cutting blocks that fill in the component clearance.
// If false, then create narrow cutting blocks that leave space for the component clearance.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_gusset_array ( gender, curve, scg_type, fill_component_clearance )
{
// Compute cutting block size.
cutting_block_size = m_leaf_gauge + m_knuckle_gusset_width;
leaf_height = ( scg_type == C_NEGATIVE ) ? m_leaf_height + SCG_OVERLAP : m_leaf_height;
// Compute cutting block translation.
xt = cutting_block_size/2.0;
yt = 0.0;
zt = 0.0;
// Create gusset array.
difference ()
{
// Create a solid cylindrical gusset cylinder.
workpiece_gusset
(
width = m_knuckle_gusset_width,
height = leaf_height,
knuckle_radus = m_leaf_gauge,
curve = curve,
scg_type = scg_type
);
// Use the knuckle array cutter tool, to cut knuckle gaps into the gusset to match the dimensions of the knuckles.
translate ( [ xt, yt, zt ] )
tool_cutter_knuckle_array
(
gender = gender,
fill_component_clearance = !fill_component_clearance,
size = cutting_block_size
);
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_gusset
// Module Type: Workpiece
//
// Description:
//
// - Knuckle gusset used to strengthen the knuckle joints.
//
// Parameters:
//
// - width
// The length of the gusset, as measured from the edge of the knuckle.
// We name it "width", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - height
// The thickness of the gusset.
// We name this "height", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - knuckle_radus
// Outer radius of the knuckles. This is also the same value as the leaf gauge.
//
// - curve
// The mathematical function used to describe the shape of the gusset.
// - Linear
// - Parabolic
// - Circular
//
// - scg_type
// Solid Constructive Geometry (SCG) mode.
// - If set to 0 or C_NEGATVE, to create the version of the component used for cutting away from the leaves.
// - If set to 1 or C_POSITIVE, to create the version of the component used for adding to the leaves and knuckles.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_gusset ( width, height, knuckle_radus, curve, scg_type )
{
if ( curve == C_FUNCTION_LINEAR ) workpiece_gusset_linear ( width, height, knuckle_radus, scg_type );
else if ( curve == C_FUNCTION_CIRCULAR ) workpiece_gusset_circular ( width, height, knuckle_radus, scg_type );
else if ( curve == C_FUNCTION_PARABOLIC ) workpiece_gusset_parabolic ( width, height, knuckle_radus, scg_type );
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_gusset_linear
// Module Type: Workpiece
//
// Description:
//
// - Linear knuckle gusset, called by workpiece_gusset.
//
// Parameters:
//
// - width
// The length of the gusset, as measured from the edge of the knuckle.
// We name it "width", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - height
// The thickness of the gusset.
// We name this "height", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - knuckle_radus
// Outer radius of the knuckles. This is also the same value as the leaf gauge.
//
// - scg_type
// Solid Constructive Geometry (SCG) mode.
// - If set to 0 or C_NEGATVE, to create the version of the component used for cutting away from the leaves.
// - If set to 1 or C_POSITIVE, to create the version of the component used for adding to the leaves and knuckles.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_gusset_linear ( width, height, knuckle_radus, scg_type )
{
CENTER = true;
DEBUG_ENABLED = true;
// Initialize input values.
w = width; // Gusset width.
h = height; // Hinge leaf height.
r = knuckle_radus; // Knuckle radius is equal to the leaf gauge.
s = w + r; // Cartesian position of the point where the gusset curve merges with the leaf.
g = m_leaf_gauge; // Leafe gauge.
c = SCG_OVERLAP; // Amount to overlap unions in order to prevent Boolean anomalies.
// Compute gusset tangent curve.
x = r*r/s;
y = sqrt ( r*r - x*x );
a = y/( x - s );
b = -a*s;
// Compute work piece translation and dimensions.
wp_xd = 0; // Work piece origin x.
wp_yd = 0; // Work piece origin y.
wp_zd = -g + c; // Work piece origin z.
wp_w = s; // Work piece width (x axis length).
wp_g = g + y - c; // Work piece gauge (y access length. i.e. thickness).
wp_h = h; // Work piece height (y axis length).
// Compute cutting tool translation and dimensions.
ct_xd = 0;
ct_yd = 0;
ct_zd = 0;
ct_w0 = x;
ct_w1 = s;
ct_g0 = y;
ct_g1 = 0;
ct_h = h + 2*c;
// Compute and configure orientation.
test_yd = 0;
zs = ( scg_type == C_POSITIVE ) ? 1.0 : -1.0;
scale ( [ 1.0, -1.0, zs ] )
difference()
{
translate ( [ wp_xd, wp_yd + test_yd, wp_zd ] ) rotate ( [ 90, 0, 0 ] )
{
linear_extrude ( height = wp_h, center = CENTER ) rectangle ( w = wp_w, h = wp_g );
}
translate ( [ ct_xd, ct_yd + test_yd, ct_zd ] ) rotate ( [ 90, 0, 0 ] )
{
linear_extrude ( height = ct_h, center = CENTER ) triangle ( [ [ ct_w0, ct_g0 ],[ ct_w1+c, ct_g0+c ],[ ct_w1, ct_g1 ] ] );
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_gusset_circular
// Module Type: Workpiece
//
// Description:
//
// - Linear knuckle gusset, called by workpiece_gusset.
//
// Parameters:
//
// - width
// The length of the gusset, as measured from the edge of the knuckle.
// We name it "width", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - height
// The thickness of the gusset.
// We name this "height", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - knuckle_radus
// Outer radius of the knuckles. This is also the same value as the leaf gauge.
//
// - scg_type
// Solid Constructive Geometry (SCG) mode.
// - If set to 0 or C_NEGATVE, to create the version of the component used for cutting away from the leaves.
// - If set to 1 or C_POSITIVE, to create the version of the component used for adding to the leaves and knuckles.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_gusset_circular ( width, height, knuckle_radus, scg_type )
{
CENTER = true;
// Initialize input values.
w = width; // Gusset width.
g = knuckle_radus; // Knuckle radius is equal to the leaf gauge.
c = SCG_OVERLAP; // Amount to overlap unions in order to prevent Boolean anomalies.
// Compute gusset radius. The radius of the circle, that is tangential to the knuckle cylinder.
r = ( 2.0*g*w + w*w ) / ( 2.0*g );
// Compute gusset height. The point of intersection between the knuckle cylinder and the gusset cutter.
h = ( g*r ) / sqrt ( g*g + 2.0*g*w + r*r + w*w );
// Compute intersection point between knuckle and gusset cutting tool, using gusset height.
// The coordinate of the intersection point are, p(x,h), where h is the vertical value of the coordinate.
x = h*( g + w ) / r;
// Compute gusset cutting tool translation.
ctxd = g + w;
ctyd = c;
ctzd = r;
ctt = height + 2.0*x;
// Compute gusset work piece translation and dimensions.
wpw = g + w -x;
wph = h + c;
wpxd = x;
wpyd = 0.0;
wpzd = 0.0 - c;
wpt = height;
// Initialize cutting plane and component scaling.
xr = 90.0;
yr = 0.0;
zr = 0.0;
xs = 1.0;
ys = -1.0;
zs = ( scg_type == C_POSITIVE ) ? 1.0 : -1.0;
// Generate gusset.
color ( "silver" )
scale ( [ xs, ys, zs ] )
difference ()
{
translate ( [ wpxd, wpyd, wpzd ] ) rotate ( [ xr, yr, zr ] ) linear_extrude ( height = wpt, center = CENTER ) rectangle ( w = wpw, h = wph );
translate ( [ ctxd, ctyd, ctzd ] ) rotate ( [ xr, yr, zr ] ) linear_extrude ( height = ctt, center = CENTER ) circle ( r = r );
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: workpiece_gusset_parabolic
// Module Type: Workpiece
//
// Description:
//
// - Parabolic knuckle gusset, called by workpiece_gusset.
//
// Parameters:
//
// - width
// The length of the gusset, as measured from the edge of the knuckle.
// We name it "width", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - height
// The thickness of the gusset.
// We name this "height", in order to maintain dimension naming consistency with the rest of the hinge dimensions.
//
// - knuckle_radus
// Outer radius of the knuckles. This is also the same value as the leaf gauge.
//
// - scg_type
// Solid Constructive Geometry (SCG) mode.
// - If set to 0 or C_NEGATVE, to create the version of the component used for cutting away from the leaves.
// - If set to 1 or C_POSITIVE, to create the version of the component used for adding to the leaves and knuckles.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module workpiece_gusset_parabolic ( width, height, knuckle_radus, scg_type )
{
CENTER = true;
DEBUG_ENABLED = true;
RESOLUTION = m_resolution / C_MIN_TESSELLATION;
// Initialize input values.
w = width; // Gusset width.
h = height; // Hinge leaf height.
r = knuckle_radus; // Knuckle radius is equal to the leaf gauge.
s = w + r; // Cartesian position of the point where the gusset curve merges with the leaf.
g = m_leaf_gauge; // Leafe gauge.
c = SCG_OVERLAP; // Amount to overlap unions in order to prevent Boolean anomalies.
// Compute parabolic point of contact with the knuckle cylinder.
i = sqrt ( 8.0*r*r + s*s ); // Common root.
x = ( i - s )/2.0; // x intercept.
y = sqrt ( r*r - x*x ); // y intercept.
// Compute coefficient 'a' of vertex form parabola.
// y = a2(x-s)2
an = root4 ( 2.0 ) * root4 ( s*( i - s ) - 2.0*r*r ); // Numerator.
ad = sqrt ( s*( 5.0*s - 3.0*i ) + 4.0*r*r ); // Denominator.
a = an / ad; // Coefficient 'a' of, y = a2(x-s)2
// Compute work piece translation and dimensions.
wp_xd = 0; // Work piece origin x.
wp_yd = 0; // Work piece origin y.
wp_zd = -g + c; // Work piece origin z.
wp_w = s; // Work piece width (x axis length).
wp_g = g + y - c; // Work piece gauge (y access length. i.e. thickness).
wp_h = h; // Work piece height (y axis length).
// Compute cutting tool translation and dimensions.
ct_xd = 0;
ct_yd = 0;
ct_zd = 0;
ct_w0 = x;
ct_w1 = s;
ct_g0 = y;
ct_g1 = 0;
ct_h = h + 2*c;
// Compute positive or negative tool orientation. We flip the tool by using a negative unit scale.
test_yd = 0;
zs = ( scg_type == C_POSITIVE ) ? 1.0 : -1.0;
scale ( [ 1.0, -1.0, zs ] )
// Create gusset work piece.
difference()
{
// Work piece.
translate ( [ wp_xd, wp_yd + test_yd, wp_zd ] ) rotate ( [ 90, 0, 0 ] )
{
linear_extrude ( height = wp_h, center = CENTER ) rectangle ( w = wp_w, h = wp_g );
}
// Parabolic cutting tool.
translate ( [ ct_xd, ct_yd + test_yd, ct_zd ] ) rotate ( [ 90, 0, 0 ] )
{
linear_extrude ( height = ct_h, center = CENTER ) parabolic_conic_section ( a, s, 0, s, RESOLUTION );
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: tool_cutter_fastener
// Module Type: Cutting Tool.
//
// Description:
//
// - Cutting tool used to cut fastener holes into leaf workpiece.
//
// Parameters:
//
// - z_offset:
// Depth of the cut.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module tool_cutter_fastener ( z_offset, )
{
// Initialize local variables.
id = m_fastener_thread_diameter; // Inner diameter.
od = m_fastener_head_diameter; // Outer diameter.
t = m_fstener_head_type; // 0 = Fillister (Pan head), 1 = flat countersunk.
d = m_counter_sink_depth; // Depth of head counter sink.
z0 = z_offset - m_leaf_gauge; // Vertical position of head.
z1 = z_offset - m_counter_sink_depth; // Vertical position of thread.
h0 = m_leaf_gauge; // Height of head.
h1 = m_counter_sink_depth; // Height of thread.
c = SCG_OVERLAP;
// Create cutting tool.
union ()
{
// Thread
translate ( [ 0, 0, z0 - c ] )
{
cylinder ( d = id, h = h0 + 2.0*c );
}
// Head.
union ()
{
// Fastener head.
translate ( [ 0, 0, z1 ] )
{
// Fillister (Pan head).
if ( t == 0 )
{
d_top = od;
d_bottom = od;
h = h1 + c;
cylinder ( d2 = d_top, d1 = d_bottom, h = h );
}
// Flat countersunk.
if ( t == 1 )
{
d_top = od + c;
d_bottom = id;
h = h1 + c;
cylinder ( d2 = d_top, d1 = d_bottom, h = h );
}
}
// Cutting tool extention.
translate ( [ 0, 0, c ] )
{
cylinder ( d = od, h = m_leaf_gauge );
}
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: tool_cutter_fastener_set
// Module Type: Cutting Tool.
//
// Description:
//
// - Cutting tool used to cut fastener holes into leaf workpiece.
//
// Parameters:
//
// - fastener_count:
// Number of fastener holes to be cut into a single leaf.
// The total number of fastener holes on the whole hinge, will be twice the value of fastener_count.
// i.e. 'fastener_count' holes, on each leaf.
//
// - fastener_column_count:
// Number of fastener column per leaf. This value can be either 1, or 2.
//
// - z_offset:
// Depth of the cut.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module tool_cutter_fastener_set ( fastener_count, fastener_column_count, z_offset )
{
// Relative origin.
xo = m_leaf_gauge + m_component_clearance/2 + m_fastener_head_diameter/2 + m_fastener_margin;
yo = -m_leaf_height/2 + m_fastener_head_diameter/2 + m_fastener_margin;
// Column offsets.
col0 = 0;
col1 = m_leaf_width - m_fastener_head_diameter/2 - m_fastener_margin - xo;
// Loop configuration.
even = ( fastener_count % 2 ) ? false : true;
n1 = fastener_count - 1;
n2 = round ( fastener_count / 2 ) - 1;
k1 = ( m_leaf_height - m_fastener_head_diameter - 2*m_fastener_margin ) / n1;
k2 = ( m_leaf_height - m_fastener_head_diameter - 2*m_fastener_margin ) / n2;
// Generate fastener cutting tool.
// One column of fastener holes, if we have selected one fastener hole column.
if ( fastener_column_count == 1 )
{
for ( row = [ 0 : n1 ] )
{
cx = ( col0 + col1 ) / 2.0;
tx = xo + cx;
ty = yo + row * k1;
tz = 0;
translate ( [ tx, ty, tz ] ) tool_cutter_fastener ( z_offset );
}
}
// Two columns of fastener holes, if we have selected two fastener hole column.
if ( fastener_column_count == 2 )
{
for ( col = [ 0 : 1 ] )
{
// Column 0, offset translation when we have an odd number of fasteners.
if ( col == 0 )
{
m = ( even ) ? 0 : 1;
for ( row = [ 0 : n2 - m ] )
{
cx = ( col == 0 ) ? col0 : col1;
tx = xo + cx;
ty = ( even ) ? yo + row * k2 : yo + row * k2 + k2/2;
tz = 0;
translate ( [ tx, ty, tz ] ) tool_cutter_fastener ( z_offset );
}
}
// Column 1.
if ( col == 1 )
{
for ( row = [ 0 : n2 ] )
{
cx = ( col == 0 ) ? col0 : col1;
tx = xo + cx;
ty = yo + row * k2;
tz = 0;
translate ( [ tx, ty, tz ] ) tool_cutter_fastener ( z_offset );
}
}
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: tool_cutter_text.
// Module Type: Tool cutter.
//
// Description:
//
// - Inscribes a string of text onto a surface.
//
// Parameters:
//
// - string:
// The string of text we would like to inscribes.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module tool_cutter_text ( string, size )
{
// create text cutter.
font = "Ariel:style=Bold";
height = 0.15*6.0;
xd = 20.0;
yd = 0.0;
zd = height;
translate ( [ xd, yd, -zd ] )
{
rotate ( [ 0.0, 0.0, -90.0 ] )
{
linear_extrude ( height = height + SCG_OVERLAP )
{
text ( string, font = font, size = size, valign = "center", halign = "center" );
}
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: tool_cutter_knuckle_array
// Module Type: Cutting tool.
//
// Description:
//
// - Create an array of cutting blocks. Mostly used to cut gusset workpiece into individual gusset positives or negatives.
//
// Parameters:
//
// - gender:
// Specifies the number of knuckle joints based on hinge leaf gender.
//
// - fill_component_clearance:
// If true, then create wide cutting blocks that fill in the component clearance.
// If false, then create narrow cutting blocks that leave space for the component clearance.
//
// - size:
// Specifies the dimension used for the x and z axes.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module tool_cutter_knuckle_array ( gender, fill_component_clearance, size )
{
// Initialize local variables.
n = m_knuckle_count;
h = m_leaf_height;
c = m_component_clearance;
e = SCG_OVERLAP;
// Compute knuckle width and segment width.
k = ( h + c )/n - c;
s = ( fill_component_clearance ) ? k + 2.0*c : k;
// Compute segment offset.
o = ( fill_component_clearance ) ? c : 0.0;
// Generate block array.
a = 0;
b = ( gender == C_MALE ) ? n/2 : n/2-1;
g = ( gender == C_MALE ) ? 0.0 : k + c;
for ( i = [ a : b ] )
{
// Compute translation index.
ki = g + 2.0*i*(k + c ) - h/2.0 - o;
// Initialize translation.
xt = -size/2.0;
yt = ki;
zt = -size/2.0;
// Initialize cutting block dimensions.
cube_x = size;
cube_y = s;
cube_z = 2.0*size;
// Create cutting block.
color ( "red" )
translate ( [ xt, yt, zt ] )
cube ( [ cube_x, cube_y, cube_z ] );
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: tool_cutter_pin_shaft_counterbore
// Module Type: Cutting tool.
//
// Description:
//
// - Cuts a counterbore into the endcaps of the pin shaft.
// - If the model is being printed in its default orientation, open and flat on the build plate, then support material may be required
// for the counterbore.
//
// Parameters:
//
// - diameter:
// Specifies the diameter of the counterbore.
// For square and hexagonal counterbore shapes, the diameter refers to the inscribed circle of those shapes.
//
// - depth:
// Specifies the depth of the cut.
//
// - shape:
// The shame of the counterbore.
// - Circular
// - Square
// - Hexagonal
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module tool_cutter_pin_shaft_counterbore ( diameter_top, depth_top, shape_top, diameter_bottom, depth_bottom, shape_bottom )
{
// Local constants.
TOP_COUNTER_BORE_ENABLED = true;
BOTTOM_COUNTER_BORE_ENABLED = true;
// Initialize local variables.
d0 = diameter_bottom;
d1 = diameter_top;
h0 = depth_bottom + SCG_OVERLAP;
h1 = depth_top + SCG_OVERLAP;
// Compute diameter of polygon, inscribed by a circle of radius d/2.
s = 6; // Polygon sides.
a = 360.0/(2.0*s); // Half the angle between each point of the polygon.
x0 = d0/2.0; // Bottom: Run of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
y0 = x0*tan ( a ); // Bottom: Rise of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
r0 = sqrt ( x0*x0 + y0*y0 ); // Bottom: Hypotenuse of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
x1 = d1/2.0; // Top: Run of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
y1 = x1*tan ( a ); // Top: Rise of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
r1 = sqrt ( x1*x1 + y1*y1 ); // Top: Hypotenuse of the right angle triangle who hypotenuse is equal to half the radius of our new circle.
// Compute cutting tool translation.
xd = 0.0;
yd0 = ( h0 - m_leaf_height )/2.0 - SCG_OVERLAP;
yd1 = -( h1 - m_leaf_height )/2.0 + SCG_OVERLAP;
zd = 0.0;
// Compute polygon rotation angle.
rx = 90.0;
ry = ( s%2 == 0 ) ? a+90 : -a/2.0;
rz = 0.0;
// Create top counterbore cutting tool.
if ( BOTTOM_COUNTER_BORE_ENABLED )
{
color ( "red" )
if ( shape_bottom == C_CIRCULAR )
{
translate ( [ xd, yd0, zd ] ) rotate ( [ rx, ry, rz ] ) cylinder ( h = h0, r = d0/2.0, center = true );
}
else if ( shape_bottom == C_SQUARE )
{
translate ( [ xd, yd0, zd ] ) cube ( [ diameter_bottom, h0, diameter_bottom ], center = true );
}
else if ( shape_bottom == C_HEXAGONAL )
{
translate ( [ xd, yd0, zd ] ) rotate ( [ rx, ry+90, rz ] ) cylinder ( h = h0, r = r0, center = true, $fn = s );
}
}
// Create bottom counterbore cutting tool.
if ( TOP_COUNTER_BORE_ENABLED )
{
color ( "red" )
if ( shape_top == C_CIRCULAR )
{
translate ( [ xd, yd1, zd ] ) rotate ( [ rx, ry, rz ] ) cylinder ( h = h1, r = d1/2.0, center = true );
}
else if ( shape_top == C_SQUARE )
{
translate ( [ xd, yd1, zd ] ) cube ( [ diameter_top, h1, diameter_top ], center = true );
}
else if ( shape_top == C_HEXAGONAL )
{
translate ( [ xd, yd1, zd ] ) rotate ( [ rx, ry, rz ] ) cylinder ( h = h1, r = r1, center = true, $fn = s );
}
}
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: parabolic_conic_section.
// Module Type: 2D Shape.
//
// Description:
//
// - Creates a parabolic conic section object.
//
// Parameters:
//
// - radius:
// Radius of the cylinder sector.
//
// - a:
// Coefficient of the vertex form parabola, y = a2(x-b)2.
//
// - x:
// x Coordinate of parabola turning point.
// Note:
// For the sake of simplifying the actual parabolic function used in the recursive
// function "parabolic_vector", we use a call to "translate" to set the vertex, rather than the parabolic function its self.
//
// - y:
// y Coordinate of parabola turning point.
// Note:
// For the sake of simplifying the actual parabolic function used in the recursive
// function "parabolic_vector", we use a call to "translate" to set the vertex, rather than the parabolic function its self.
//
// - domain:
// The input domain x, over which to compute the parabolic function.
//
// - resolution:
// The input domain step size, is used to control the resolution of the shape.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module parabolic_conic_section ( a, x, y, domain, resolution )
{
// Generate 2D geometry
t = 0.0;
n = resolution;
i = 0;
d = domain;
v = [];
points = parabolic_vector ( a, t, n, i, d, v );
// Generate 3D object.
translate ( [ x, y, 0 ] )
polygon ( points );
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: triangle.
// Module Type: 2D Shape.
//
// Description:
//
// - Creates a 2D triangle from three vertices.
//
// Parameters:
//
// - x0, x1, x2
// x coordinates of vertices 0 through 2.
//
// - y0, y1, y2
// y coordinates of vertices 0 through 2.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module triangle ( v )
{
polygon ( points = v );
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: Rectangle.
// Module Type: 2D Shape.
//
// Description:
//
// - Creates a 2D rectangle.
//
// Parameters:
//
// - w
// Rectangle width.
//
// - h
// Rectangle height.
//
// - center
// Center the rectangle about the origin (0,0,0) if true, else place the rectangle in the positive quadrant.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
module rectangle ( w, h, center )
{
scale ( [ w, h ] ) square ( size = 1.0, center = center );
}
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Function: root4
//
// Description:
//
// - Compute the 4th root of x.
//
// Return Value:
//
// - Return the 4th root of x.
//
// Parameters:
//
// - x
// Input value.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
function root4 ( x ) = ( x >= 0 ) ? sqrt ( sqrt ( x ) ) : 0;
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Function: Clip
//
// Description:
//
// - Clips an input value, to a minimum and maximum value.
//
// x_min <= x <= x_max
//
// Parameters:
//
// - x
// Input value.
//
// - x_min
// Minimal value constraint. Any x less than x_min, is set to x_min.
//
// - x_max
// Maximum value constraint. Any x greater than x_max, is set to x_max.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
function clip ( x, x_min, x_max ) = ( x < x_min ) ? x_min : ( x > x_max ) ? x_max : x;
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Function: Generate a parabolic vector point array.
//
// Description:
//
// - Recursive function to generate an array of 2D points on a parabolic curve.
//
// - The parabolic vertex form is used.
//
// y = a2(x-b)2
//
// Where,
//
// a is the horizontal scale of the parabola.
// (b,c) is the Cartesian position of the turning point.
//
//
// Parameters:
//
// - a
// Horizontal scale of the parabola.
//
// - x
// Horizontal input domain.
//
// - n
// Tessellation factor. Number of points to compute for each half of the parabola object, with both halves sharing the turning point.
// For example:
// - A tessellation factor of 1, will compute 3 points in total. Two for each half, with one out of the two on each half being the
// Shared turning point.
// - A tessellation factor of 2, with compute 5 points in total, 3 for each half with a shared turning point.
//
// - i
// Point index. Initialize to zero.
//
// - d
// Input domain. The x range over which to compute the function.
// -d <= x <= d
//
// - v
// Vector that will be populated with geometry points. Initialize to empty vector, [].
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
function parabolic_vector ( a, x, n, i, d, v ) =
(
i > 2.0*d*n
// Recursive terminating condition:
// Return an empty vector.
? concat ( v, [] )
// Recursive general condition:
// Compute the next point on the parabolic path.
// x = i/n - 1
// y = a2(i/n - 1)2
: parabolic_vector ( a, x, n, i + 1, d, concat ( v, [ [ i/n - d, a*a*(i/n - d)*(i/n - d) ] ] ) )
);
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Function: funtion_name
//
// Description:
//
// - Function description.
//
// Return Value:
//
// - Description of return value.
//
// Parameters:
//
// - x
// Argument x description.
//
// - y
// Argument y description.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Module: module_name
// Module Type: [ 2D Shape, Profile, Tool, Workpiece, Component ]
// Description:
//
// - Module description.
//
// Parameters:
//
// - x
// Argument x description.
//
// - y
// Argument y description.
//
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------