2019-06-08 17:10:47 -04:00
//
// NopSCADlib Copyright Chris Palmer 2018
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
2020-12-24 11:04:59 -05:00
//! Bill Of Materials generation via echo and the `bom.py` script. Also handles exploded assembly views and posing.
2020-04-07 12:02:10 -04:00
//! Assembly instructions can precede the module definition that makes the assembly.
2019-06-08 17:10:47 -04:00
//!
2020-04-04 07:06:14 -04:00
//! Assembly views shown in the instructions can be large or small and this is deduced by looking at the size of the printed parts involved and if any routed
//! parts are used.
2020-12-24 11:04:59 -05:00
//! This heuristic isn't always correct, so the default can be overridden by setting the `big` parameter of `assembly` to `true` or `false`.
2020-04-04 07:06:14 -04:00
//!
//! The example below shows how to define a vitamin and incorporate it into an assembly with sub-assemblies and make an exploded view.
//! The resulting flat BOM is shown but heirachical BOMs are also generated for real projects.
2019-06-08 17:10:47 -04:00
//
function bom_mode ( n = 1 ) = $ _bom >= n && ( is_undef ( $ on_bom ) || $ on_bom ) ; //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well
2020-12-24 11:04:59 -05:00
function exploded ( ) = is_undef ( $ exploded_parent ) ? $ exploded : 0 ; //! Returns the value of `$exploded` if it is defined, else `0`
2019-06-08 17:10:47 -04:00
function show_supports ( ) = ! $ preview || exploded ( ) ; //! True if printed support material should be shown
module no_explode ( ) let ( $ exploded_parent = true ) children ( ) ; //! Prevent children being exploded
module no_pose ( ) let ( $ posed = true ) children ( ) ; //! Force children not to be posed even if parent is
2020-12-24 11:04:59 -05:00
module explode ( d , explode_children = false , offset = [ 0 , 0 , 0 ] ) { //! Explode children by specified Z distance or vector `d`, option to explode grand children
2019-06-08 17:10:47 -04:00
v = is_list ( d ) ? d : [ 0 , 0 , d ] ;
o = is_list ( offset ) ? offset : [ 0 , 0 , offset ] ;
2019-06-11 07:38:00 -04:00
if ( $ exploded && is_undef ( $ exploded_parent ) && norm ( v ) ) {
2019-06-08 17:10:47 -04:00
translate ( o ) // Draw the line first in case the child is transparent
2019-06-11 07:38:00 -04:00
color ( "yellow" ) hull ( ) {
2019-06-08 17:10:47 -04:00
sphere ( 0.2 ) ;
translate ( v * $ exploded )
sphere ( 0.2 ) ;
}
translate ( v * $ exploded )
let ( $ exploded_parent = explode_children ? undef : true )
children ( ) ;
}
else
children ( ) ;
}
2020-12-24 11:04:59 -05:00
module pose ( a = [ 55 , 0 , 25 ] , t = [ 0 , 0 , 0 ] , exploded = undef ) //! Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only.
2019-06-08 17:10:47 -04:00
if ( is_undef ( $ pose ) || ! is_undef ( $ posed ) || ( ! is_undef ( exploded ) && exploded ! = ! ! exploded ( ) ) )
children ( ) ;
else
let ( $ posed = true ) // only pose the top level
rotate ( [ 55 , 0 , 25 ] )
rotate ( [ - a . x , 0 , 0 ] )
rotate ( [ 0 , - a . y , 0 ] )
rotate ( [ 0 , 0 , - a . z ] )
translate ( - t )
children ( ) ;
2020-12-24 11:04:59 -05:00
module pose_hflip ( exploded = undef ) //! Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only.
2019-07-19 05:37:10 -04:00
if ( is_undef ( $ pose ) || ! is_undef ( $ posed ) || ( ! is_undef ( exploded ) && exploded ! = ! ! exploded ( ) ) )
children ( ) ;
else
let ( $ posed = true ) // only pose the top level
hflip ( )
children ( ) ;
2020-12-24 11:04:59 -05:00
module pose_vflip ( exploded = undef ) //! Pose an STL or assembly for rendering to png by flipping around the X axis, `exploded = true for` just the exploded view or `false` for unexploded only.
2019-07-19 05:37:10 -04:00
if ( is_undef ( $ pose ) || ! is_undef ( $ posed ) || ( ! is_undef ( exploded ) && exploded ! = ! ! exploded ( ) ) )
children ( ) ;
else
let ( $ posed = true ) // only pose the top level
vflip ( )
children ( ) ;
2019-06-08 17:10:47 -04:00
2020-12-24 11:04:59 -05:00
module assembly ( name , big = undef ) { //! Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams.
2020-04-04 07:06:14 -04:00
if ( bom_mode ( ) ) {
args = is_undef ( big ) ? "" : str ( "(big=" , big , ")" ) ;
echo ( str ( "~" , name , "_assembly" , args , "{" ) ) ;
}
2019-06-08 17:10:47 -04:00
no_pose ( )
if ( is_undef ( $ child_assembly ) )
let ( $ child_assembly = true )
children ( ) ;
else
no_explode ( )
children ( ) ;
if ( bom_mode ( ) )
echo ( str ( "~}" , name , "_assembly" ) ) ;
}
2020-12-24 11:04:59 -05:00
module stl_colour ( colour = pp1_colour , alpha = 1 ) { //! Colour an stl where it is placed in an assembly. `alpha` can be used to make it appear transparent.
2020-04-05 11:18:24 -04:00
$ stl_colour = colour ;
2020-04-07 12:02:10 -04:00
color ( colour , alpha )
2020-04-05 11:18:24 -04:00
children ( ) ;
}
2020-12-24 11:04:59 -05:00
module stl ( name ) { //! Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it
2020-04-05 11:18:24 -04:00
if ( bom_mode ( ) ) {
colour = is_undef ( $ stl_colour ) ? pp1_colour : $ stl_colour ;
echo ( str ( "~" , name , ".stl(colour='" , colour , "')" ) ) ;
}
2019-06-08 17:10:47 -04:00
}
2020-12-24 11:04:59 -05:00
module dxf ( name ) { //! Name a dxf that will appear on the BOM, there needs to a module named `<name>_dxf` to make it
2020-04-07 17:07:28 -04:00
if ( bom_mode ( ) ) {
if ( is_undef ( $ dxf_colour ) )
echo ( str ( "~" , name , ".dxf" ) ) ;
else
echo ( str ( "~" , name , ".dxf(colour='" , $ dxf_colour , "')" ) ) ;
}
2019-06-08 17:10:47 -04:00
}
2020-12-24 11:04:59 -05:00
function value_string ( value ) = is_string ( value ) ? str ( "\"" , value , "\"" ) : str ( value ) ; //! Convert `value` to a string or quote it if it is already a string
2019-06-08 17:10:47 -04:00
2020-12-24 11:04:59 -05:00
function arg ( value , default , name = "" ) = //! Create string for arg if not default, helper for `vitamin()`
2019-06-08 17:10:47 -04:00
value = = default ? ""
: name ? str ( ", " , name , " = " , value_string ( value ) )
: str ( ", " , value_string ( value ) ) ;
module vitamin ( description ) { //! Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "wigit(42): Type 42 widget"
if ( bom_mode ( 2 ) )
echo ( str ( "~" , description , ! is_undef ( $ hidden ) ? " - not shown" : "" ) ) ;
}
module not_on_bom ( on = false ) //! Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled
let ( $ on_bom = on )
children ( ) ;
module hidden ( ) //! Make item invisible, except on the BOM
scale ( 1 / sqr ( 1024 ) )
let ( $ hidden = true )
children ( ) ;