Single backtick now used for all code quotes.

This commit is contained in:
Chris Palmer 2020-12-24 16:04:59 +00:00
parent 04b98a3786
commit 4cac382581
49 changed files with 2459 additions and 2459 deletions

View File

@ -22,37 +22,37 @@ The 7 SEGMENT.TTF font from the docs directory is needed for simulating 7 segmen
## Installation
OpenSCAD has to be setup to find libraries by setting the ```OPENSCADPATH``` environment variable to where you want to file your libraries and NopSCADlib needs to be installed
in the directory it points to. This can be done with ```git clone https://github.com/nophead/NopSCADlib.git``` while in that directory or, if you don't want to use GIT,
OpenSCAD has to be setup to find libraries by setting the `OPENSCADPATH` environment variable to where you want to file your libraries and NopSCADlib needs to be installed
in the directory it points to. This can be done with `git clone https://github.com/nophead/NopSCADlib.git` while in that directory or, if you don't want to use GIT,
by downloading https://github.com/nophead/NopSCADlib/archive/master.zip and unzipping it to a directory called NopSCADlib.
The ```NopSCADlib/scripts``` directory needs to be added to the executable search path, ```PATH``` on Windows and ```path``` on Linux and Mac.
The `NopSCADlib/scripts` directory needs to be added to the executable search path, `PATH` on Windows and `path` on Linux and Mac.
The installation can be tested by opening ```NopSCADlib/libtest.scad``` in the OpenSCAD GUI. It should render all the objects in the library in about 1 minute.
The installation can be tested by opening `NopSCADlib/libtest.scad` in the OpenSCAD GUI. It should render all the objects in the library in about 1 minute.
Running ```tests``` from the command line will run all the tests in the ```tests``` directory and build the ```readme.md``` catalog for GitHub and render it to ```readme.html```
Running `tests` from the command line will run all the tests in the `tests` directory and build the `readme.md` catalog for GitHub and render it to `readme.html`
for local preview.
## Directory structure
| Path | Contents |
|:-----|:------|
| ```NopSCADlib``` | Top level scad files, e.g. ```lib.scad``` |
| ```NopSCADlib/doc``` | Documentation like this that is not automatically generated |
| ```NopSCADlib/examples``` | Example projects |
| ```NopSCADlib/gallery``` | Pictures of items that have been made with the library |
| ```NopSCADlib/printed``` | Scad files for making reusable printed parts |
| ```NopSCADlib/scripts``` | Python scripts |
| ```NopSCADlib/tests``` | A stand alone test for each type of vitamin and most of the utilities |
| ```NopSCADlib/utils``` | Utility scad files |
| ```NopSCADlib/utils/core``` | Core utilities used by nearly everything |
| ```NopSCADlib/vitamins``` | Generally a pair of .scad files for each type of vitamin. The plural version contains object definitions to be included and it uses the singular version. |
| `NopSCADlib` | Top level scad files, e.g. `lib.scad` |
| `NopSCADlib/doc` | Documentation like this that is not automatically generated |
| `NopSCADlib/examples` | Example projects |
| `NopSCADlib/gallery` | Pictures of items that have been made with the library |
| `NopSCADlib/printed` | Scad files for making reusable printed parts |
| `NopSCADlib/scripts` | Python scripts |
| `NopSCADlib/tests` | A stand alone test for each type of vitamin and most of the utilities |
| `NopSCADlib/utils` | Utility scad files |
| `NopSCADlib/utils/core` | Core utilities used by nearly everything |
| `NopSCADlib/vitamins` | Generally a pair of .scad files for each type of vitamin. The plural version contains object definitions to be included and it uses the singular version. |
## Making a project
Each project has its own directory and that is used to derive the project's name.
There should also be a subdirectory called ```scad``` with a scad file in it that contains the main assembly.
There should also be a subdirectory called `scad` with a scad file in it that contains the main assembly.
A skeleton project looks like this: -
//! Project description in Markdown format before the first include.
@ -72,30 +72,30 @@ A skeleton project looks like this: -
Other scad files can be added to the scad directory and included or used as required.
* Subassemblies can be added in the same format as ```main_assembly()```, i.e. a module called ```something_assembly()```, taking no parameters and calling ```assembly("something")```
* Subassemblies can be added in the same format as `main_assembly()`, i.e. a module called `something_assembly()`, taking no parameters and calling `assembly("something")`
with the rest of its contents passed as children.
It needs to be called directly or indirectly from ```main_assembly()``` to appear in the view and on the BOM.
Assembly instructions should be added directly before the module definition in comments marked with ```//!```.
It needs to be called directly or indirectly from `main_assembly()` to appear in the view and on the BOM.
Assembly instructions should be added directly before the module definition in comments marked with `//!`.
* Any printed parts should be made by a module called ```something_stl()```, taking no parameters and calling ```stl("something")``` so they appear on the BOM when called from
an assembly. Printed parts are usually ```color```ed and ```render```ed at the point they are used in the assembly.
* Any printed parts should be made by a module called `something_stl()`, taking no parameters and calling `stl("something")` so they appear on the BOM when called from
an assembly. Printed parts are usually `color`ed and `render`ed at the point they are used in the assembly.
* Any 2D routed parts should be made by a module called ```something_dxf()```, taking no parameters and calling ```dxf("something")``` so they appear on the BOM when called from an
assembly. They are generally made from a ```sheet_2D()``` with holes subtracted from it. That will also put the sheet material on the BOM.
They are then expanded to 3D using ```render_2D_sheet()``` when they are placed in an assembly.
* Any 2D routed parts should be made by a module called `something_dxf()`, taking no parameters and calling `dxf("something")` so they appear on the BOM when called from an
assembly. They are generally made from a `sheet_2D()` with holes subtracted from it. That will also put the sheet material on the BOM.
They are then expanded to 3D using `render_2D_sheet()` when they are placed in an assembly.
When ```make_all``` is run from the top level directory of the project it will create the following sub-directories and populate them:-
When `make_all` is run from the top level directory of the project it will create the following sub-directories and populate them:-
| Directory | Contents |
|:----------|:---------|
| assemblies | For each assembly: an assembled view and an exploded assembly view, in large and small formats |
| bom | A flat BOM in ```bom.txt``` for the whole project, flat BOMs in text format for each assembly and a hierarchical BOM in JSON format: ```bom.json```.|
| bom | A flat BOM in `bom.txt` for the whole project, flat BOMs in text format for each assembly and a hierarchical BOM in JSON format: `bom.json`.|
| deps | Dependency files for each scad file in the project, so that subsequent builds can be incremental |
| dxfs | DXF files for all the CNC routed parts in the project and small PNG images of them |
| stls | STL files for all the printed parts in the project and small PNG images of them |
It will also make a Markdown assembly manual called ```readme.md``` suitable for GitHub, a version rendered to HTML for viewing locally called ```readme.html``` and a second
HTML version called ```printme.html```. This has page breaks instead of horizontal rules between sections and can be converted to PDF using Chrome to make a stand alone manual.
It will also make a Markdown assembly manual called `readme.md` suitable for GitHub, a version rendered to HTML for viewing locally called `readme.html` and a second
HTML version called `printme.html`. This has page breaks instead of horizontal rules between sections and can be converted to PDF using Chrome to make a stand alone manual.
Each time OpenSCAD is run to produce STL files, DXF files or assembly views, the time it takes is recorded and compared with the previous time.
At the end the times are printed with the delta from the last run and coloured red or green if they have got significantly faster or slower.
@ -112,7 +112,7 @@ All the vitamins and utilities are included if you include [NopSCADlib/lib.scad]
Printed parts are not included and need to be used or included explicitly, their documentation states which files need to be included rather than used.
This is the easiest way to use the library and is reasonably efficient because the only files included are the object list definitions, all the functions and modules are used, so
get shared if other files in the project include ```lib.scad``` as well, or if you have multiple projects open in the same instance of OpenSCAD.
get shared if other files in the project include `lib.scad` as well, or if you have multiple projects open in the same instance of OpenSCAD.
One downside is that any change to the library will mean all the project files need regenerating.
A more optimised approach for large projects is to include [NopSCADlib/core.scad](../core.scad) instead.
@ -123,17 +123,17 @@ Any other vitamins used need to be included explicitly. One can copy the include
Modules that generate parts and assemblies need to take no parameters so that they can be called from the framework to make the STL files and assembly views, etc.
Sometimes parts or asemblies need to be parametric, for example fan guards take the fan as a parameter.
To work around this the ```fan_guard()``` module calls the ```stl()``` module with a variable name which has a suffix of the fan width, e.g. "fan_guard_60".
To work around this the `fan_guard()` module calls the `stl()` module with a variable name which has a suffix of the fan width, e.g. "fan_guard_60".
This ensures that if there are different sized fans in the same project the STL files have unique names.
It is then up to the user to add a wrapper to their project called ```fan_guard_60_stl()``` that calls ```fan_guard()``` with a 60mm fan: -
It is then up to the user to add a wrapper to their project called `fan_guard_60_stl()` that calls `fan_guard()` with a 60mm fan: -
module fan_guard_60_stl() fan_guard(fan60x15);
Calling ```fan_guard(fan60x15)``` draws a fan guard for a 60mm fan and puts ```fan_guard_60.stl``` on the BOM. The framework then looks for a module ```fan_guard_60_stl()``` to
Calling `fan_guard(fan60x15)` draws a fan guard for a 60mm fan and puts `fan_guard_60.stl` on the BOM. The framework then looks for a module `fan_guard_60_stl()` to
generate it.
This is OK if the fan will always be 60mm but what if the project is parametric and the fan size can vary?
To cater for that ```fan_guard()``` can be passed a ```name``` parameter to name the STL.
To cater for that `fan_guard()` can be passed a `name` parameter to name the STL.
For example a 3D printer might have a bed cooling fan and different sized machines might have different size fans.
bed_fan = fan80x38;
@ -144,7 +144,7 @@ In this case the STL file has a constant name related to its use, regardless of
### Assembly boundaries
The ```assembly()``` module is used to mark assemblies that correspond to a step of construction.
The `assembly()` module is used to mark assemblies that correspond to a step of construction.
Each assembly named in this way gets a page in the build manual with a list of the parts and sub-assemblies that it uses, an exploded view,
some build instructions and then the assembled view.
This doesn't always correspond with how one would want to structure the code.
@ -182,26 +182,26 @@ This is achieved by having a pair of modules: -
screw_and_washer(screw, screw_length, true);
}
Notice how the first module ```handle_assembly()``` uses ```assembly()``` and has a build instruction. It isn't used directly in a project though, ```handle_fastened_assembly()``` is
Notice how the first module `handle_assembly()` uses `assembly()` and has a build instruction. It isn't used directly in a project though, `handle_fastened_assembly()` is
what is actually called from the parent assembly.
Because it doesn't have a call to ```assembly()```, the fasteners are added to the parent but the STL and the inserts become a sub-assembly.
Because it doesn't have a call to `assembly()`, the fasteners are added to the parent but the STL and the inserts become a sub-assembly.
When the parent assembly is shown exploded the handle's screws will be exploded but the inserts won't. They only explode when the sub-assembly is shown exloded.
Note also the ```pose([225, 0, 150], [0, 0, 14])``` call before the ```assembly()``` call. This allows the sub-assembly to be posed differently in its build step but doesn't
Note also the `pose([225, 0, 150], [0, 0, 14])` call before the `assembly()` call. This allows the sub-assembly to be posed differently in its build step but doesn't
affect its orientation in the parent assembly. The pose parameters are the rotation and the translation taken from the GUI.
### Exploded diagrams
A lot of vitamins explode themselves when ```$explode=1```. This is done with module ```explode()``` that can be passed a Z offset, or a 3D vector that gives the displacement
A lot of vitamins explode themselves when `$explode=1`. This is done with module `explode()` that can be passed a Z offset, or a 3D vector that gives the displacement
and it draws a line from the origial position to the exploded position. The line can be offset from the origin of the component by specifying an offset vector.
Often user assemblies need to add ```explode()``` in various places to explode printed parts, for example.
Often user assemblies need to add `explode()` in various places to explode printed parts, for example.
### Creating vitamins
Most vitamins are parametric and use a named list of properties to describe them is a pseudo OO style.
These lists are passed to every function or module related to the vitamin as the first parameter called ```type```.
These lists are passed to every function or module related to the vitamin as the first parameter called `type`.
They need to be included in the user code, so that the list names are visible. The functions and modules however only need to be used, not included.
This leads to a pair of files for each vitamin. One with a plural name that defines the objects and then uses the file with a singular name
@ -216,50 +216,50 @@ These functions take a particular form, so they can be scraped out and added to
function spring_od(type) = type[1]; //! Outside diameter
Other functions and modules with ```//!``` comments will be added to the documentation as functions and modules.
Other functions and modules with `//!` comments will be added to the documentation as functions and modules.
Functions and modules without these special comments are considered private and do not appear in the documentation.
A vitamin announces itself to the BOM by calling the ```vitamin()``` module with a string description composed of two parts separated by a colon.
A vitamin announces itself to the BOM by calling the `vitamin()` module with a string description composed of two parts separated by a colon.
The first part is a string representation of the module instantiation.
This is used in the documentation to show how to instantiate every part available.
To facilitate this the first element in the type list is the name of the list as a string and is simply accessed as ```type[0]```.
To facilitate this the first element in the type list is the name of the list as a string and is simply accessed as `type[0]`.
The part of the description after the colon is free format text that appears on the BOM. Since vitamins are listed alphabetically starting the description with the broad
category of the part and leaving the more refined description to the end generates tidier parts lists.
For example ```Screw M3 pan x 30mm``` ensures all the screws appear together and are ordered by their diameter before length, although ```M3 x 30mm pan screw``` would be
For example `Screw M3 pan x 30mm` ensures all the screws appear together and are ordered by their diameter before length, although `M3 x 30mm pan screw` would be
more natural.
Vitamins are only ever previewed, so they are optimised to draw quickly in F5 and don't need to worry about being manifold.
In OpenCSG 3D difference and intersection are relatively slow and the negative volumes interfere with nearby objects when they are composed into assemblies. For this reason as much
as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in ```render()``` so that CGAL will compute a polyhedron
as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in `render()` so that CGAL will compute a polyhedron
that is cached and reused. This will be very slow the first time it renders but very fast afterwards.
### Panels and Platters
The ```stls``` and ```dxfs``` scripts produce a file for each part but often it is desirable to print or route collections of parts laid out together.
This can be done by adding scad files to folders called ```platters``` for STL files and ```panels``` for DXF files.
These can aggregate and lay out parts by including ```NopSCADlib/core.scad``` and using modules ```use_stl(name)``` and ```use_dxf(name)```.
The `stls` and `dxfs` scripts produce a file for each part but often it is desirable to print or route collections of parts laid out together.
This can be done by adding scad files to folders called `platters` for STL files and `panels` for DXF files.
These can aggregate and lay out parts by including `NopSCADlib/core.scad` and using modules `use_stl(name)` and `use_dxf(name)`.
These modules import the already generated singular STL and DXF files, so they are relatively fast. The name does not include the suffix.
The scad files typically also need to include other files from the project to get the dimensions of the parts to calculate their positions.
The composite part files have the same name as the scad file that generates them, with the suffix changed to ```.stl``` or ```.dxf```.
The composite part files have the same name as the scad file that generates them, with the suffix changed to `.stl` or `.dxf`.
The generated files are placed in ```stls/printed``` and ```dxfs/routed```.
Any parts that are not covered by the platters / panels are copied into the ```printed``` / ```routed``` directories, so that they contain everything to be made.
The generated files are placed in `stls/printed` and `dxfs/routed`.
Any parts that are not covered by the platters / panels are copied into the `printed` / `routed` directories, so that they contain everything to be made.
### Multiple configurations
Some parametric designs might have several configurations, for example a 3D printer with different size options. If several configurations need to be supported at the
same time multiple sets of BOMS, STLS and DXFs need to be generated in separate diectories. NopSCADlib supports this by having multiple configuration files named
```config_<target_name>.scad```. All the scripts take an optional first parameter that selects one of these config files by specifying ```target_name```.
`config_<target_name>.scad`. All the scripts take an optional first parameter that selects one of these config files by specifying `target_name`.
The target config file is selected by generating ```target.scad``` that includes ```config_<target_name>.scad```.
The rest of the project includes ```target.scad``` to use the configuration.
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc.) are placed in a sub-directory called ```<target_name>```.
The target config file is selected by generating `target.scad` that includes `config_<target_name>.scad`.
The rest of the project includes `target.scad` to use the configuration.
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc.) are placed in a sub-directory called `<target_name>`.
### Other libraries
The build scripts need to be able to locate the source files where the modules to generate the STL files and assemblies reside. They will search all the scad files
in the project plus any ```printed``` directories outside the project. This covers the printed parts in NopSCADlib but also allows other libraries of printed parts.
in the project plus any `printed` directories outside the project. This covers the printed parts in NopSCADlib but also allows other libraries of printed parts.
Other libraries of vitamins and utilities can be used provided they follow the same convensions of NopSCADlib. The build scripts don't need to search those.

View File

@ -18,7 +18,7 @@
//
//
// The assembly is ```include```d so the panel definitions can be overridden to add holes and components.
// The assembly is `include`d so the panel definitions can be overridden to add holes and components.
// The _box_module also needs to be wrapped in the file that uses it so it can be called without
// parameters to make the assembly views. E.g. module box_assembly() _box_assembly(box);
//

View File

@ -21,7 +21,7 @@
//! A box made from CNC cut panels butted together using printed fixing blocks. Useful for making large
//! boxes with minimal 3D printing. More blocks are added as the box gets bigger.
//!
//! Needs to be ```include```d rather than ```use```d to allow the panel definitions to be overridden to add holes
//! Needs to be `include`d rather than `use`d to allow the panel definitions to be overridden to add holes
//! and mounted components.
//!
//! A list specifies the internal dimensions, screw type, top, bottom and side sheet types and the block

View File

@ -25,10 +25,10 @@
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//!
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting ```show_block``` to false.
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting `show_block` to false.
//! This allows the block and one set of fasteners to be on one assembly and the other fasteners on the mating assemblies.
//!
//! Star washers can be omitted by setting ```star_washers``` to false.
//! Star washers can be omitted by setting `star_washers` to false.
//
include <../core.scad>
use <../vitamins/insert.scad>

View File

@ -27,7 +27,7 @@
//! The ends can have screw lugs with four screw positions to choose from, specified by a list of two arrays of four bools.
//! If none are enabled then a child object is expected to customise the end and this gets unioned with the blank end.
//! If both ends are customised then two children are expected.
//! Each child is called twice, once with ```$fasteners``` set to 0 to augment the STL and again with ```$fasteners``` set to 1 to add
//! Each child is called twice, once with `$fasteners` set to 0 to augment the STL and again with `$fasteners` set to 1 to add
//! to the assembly, for example to add inserts.
//

View File

@ -17,7 +17,7 @@
// If not, see <https://www.gnu.org/licenses/>.
//
//! Pintable fan finger guard to match the specified fan. To be ```include```d, not ```use```d.
//! Pintable fan finger guard to match the specified fan. To be `include`d, not `use`d.
//!
//! The ring spacing as well as the number of spokes can be specified, if zero a gasket is generated instead of a guard.
//

View File

@ -25,10 +25,10 @@
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//!
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting ```show_block``` to false.
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting `show_block` to false.
//! This allows the block and one set of fasteners to be on one assembly and the other fasteners on the mating assemblies.
//!
//! Star washers can be omitted by setting ```star_washers``` to false.
//! Star washers can be omitted by setting `star_washers` to false.
//
include <../core.scad>
use <../vitamins/insert.scad>

View File

@ -25,8 +25,8 @@
//!
//! Opening the test in OpenSCAD with its customiser enabled allows these parameters to be played with.
//!
//! Note setting ```thickness1``` or ```thickness2``` to zero in the ```hinge_fastened_assembly()``` removes the screws from one side or the other and
//! setting ```show_hinge``` to false removes the hinge.
//! Note setting `thickness1` or `thickness2` to zero in the `hinge_fastened_assembly()` removes the screws from one side or the other and
//! setting `show_hinge` to false removes the hinge.
//! This allows the hinges and one set of screws to belong to one assembly and the other set of screws to another assembly.
//
include <../core.scad>

4578
readme.md

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ def doc_scripts():
print(
'''
# Python scripts
These are located in the ```scripts``` subdirectory, which needs to be added to the program search path.
These are located in the `scripts` subdirectory, which needs to be added to the program search path.
They should work with both Python 2 and Python 3.
@ -60,7 +60,7 @@ They should work with both Python 2 and Python 3.
break
if not blurb:
print("Missing description for", file)
print("| ```%s``` | %s |" % (file, blurb), file = doc_file)
print("| `%s` | %s |" % (file, blurb), file = doc_file)
with open(dir + "/readme.html", "wt") as html_file:
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)

View File

@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Generates all the files for a project by running ```bom.py```, ```stls.py```, ```dxfs.py```, ```render.py``` and ```views.py```.
#! Generates all the files for a project by running `bom.py`, `stls.py`, `dxfs.py`, `render.py` and `views.py`.
import sys

View File

@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Panelises DXF files so they can be routed together by running scad files found in the ```panels``` directory.
#! Panelises DXF files so they can be routed together by running scad files found in the `panels` directory.
from __future__ import print_function
import sys

View File

@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Generates build plates of STL files for efficient printing by running scad files found in the ```platters``` directory.
#! Generates build plates of STL files for efficient printing by running scad files found in the `platters` directory.
from __future__ import print_function
import sys

View File

@ -1,22 +1,24 @@
# Python scripts
These are located in the ```scripts``` subdirectory, which needs to be added to the program search path.
These are located in the `scripts` subdirectory, which needs to be added to the program search path.
They should work with both Python 2 and Python 3.
| Script | Function |
|:---|:---|
| ```bom.py``` | Generates BOM files for the project. |
| ```c14n_stl.py``` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
| ```doc_scripts.py``` | Makes this document and doc/usage.md. |
| ```dxfs.py``` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
| ```gallery.py``` | Finds projects and adds them to the gallery. |
| ```make_all.py``` | Generates all the files for a project by running ```bom.py```, ```stls.py```, ```dxfs.py```, ```render.py``` and ```views.py```. |
| ```panels.py``` | Panelises DXF files so they can be routed together by running scad files found in the ```panels``` directory. |
| ```platters.py``` | Generates build plates of STL files for efficient printing by running scad files found in the ```platters``` directory. |
| ```render.py``` | Renders STL and DXF files to PNG for inclusion in the build instructions. |
| ```set_config.py``` | Sets the target configuration for multi-target projects that have variable configurations. |
| ```stls.py``` | Generates STL files for all the printed parts listed on the BOM or a specified list. |
| ```svgs.py``` | Generates SVG files for all the routed parts listed on the BOM or a specified list. |
| ```tests.py``` | Runs all the tests in the tests directory and makes the readme file with a catalog of the results. |
| ```views.py``` | Generates exploded and unexploded assembly views and scrapes build instructions to make readme.md, readme.html and printme.html files for the project. |
| `bom.py` | Generates BOM files for the project. |
| `c14n_stl.py` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
| `doc_scripts.py` | Makes this document and doc/usage.md. |
| `dxf.py` | |
| `dxf2pdf.py` | |
| `dxfs.py` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
| `gallery.py` | Finds projects and adds them to the gallery. |
| `make_all.py` | Generates all the files for a project by running `bom.py`, `stls.py`, `dxfs.py`, `render.py` and `views.py`. |
| `panels.py` | Panelises DXF files so they can be routed together by running scad files found in the `panels` directory. |
| `platters.py` | Generates build plates of STL files for efficient printing by running scad files found in the `platters` directory. |
| `render.py` | Renders STL and DXF files to PNG for inclusion in the build instructions. |
| `set_config.py` | Sets the target configuration for multi-target projects that have variable configurations. |
| `stls.py` | Generates STL files for all the printed parts listed on the BOM or a specified list. |
| `svgs.py` | Generates SVG files for all the routed parts listed on the BOM or a specified list. |
| `tests.py` | Runs all the tests in the tests directory and makes the readme file with a catalog of the results. |
| `views.py` | Generates exploded and unexploded assembly views and scrapes build instructions to make readme.md, readme.html and printme.html files for the project. |

View File

@ -219,7 +219,7 @@ def tests(tests):
if things:
body += ['### %s\n| %s | Description |\n|:--- |:--- |' % (thing.title(), heading)]
for item in sorted(things):
body += ['| ```%s``` | %s |' % (item, things[item])]
body += ['| `%s` | %s |' % (item, things[item])]
body += ['']
body += ["![%s](%s)\n" %(base_name, png_name)]
@ -252,7 +252,7 @@ def tests(tests):
desc = ''
if thing == "vitamins":
vit = item.split(':')
name = '```' + vit[0] + '```' if vit[0] else ''
name = '`' + vit[0] + '`' if vit[0] else ''
while '[[' in name and ']]' in name:
i = name.find('[[')
j = name.find(']]') + 2

View File

@ -22,14 +22,14 @@
//
include <../global_defs.scad>
function bezier(t, v) = //! Returns a point at distance ```t``` [0 - 1] along the curve with control points ```v```
function bezier(t, v) = //! Returns a point at distance `t` [0 - 1] along the curve with control points `v`
(len(v) > 2) ? bezier(t, [for (i = [0 : len(v) - 2]) v[i] * (1 - t) + v[i + 1] * (t)])
: v[0] * (1 - t) + v[1] * (t);
function bezier_path(v, steps = 100) = //! Returns a Bezier path from control points ```v``` with ```steps``` segments
function bezier_path(v, steps = 100) = //! Returns a Bezier path from control points `v` with `steps` segments
[for(i = [0 : steps], t = i / steps) bezier(t, v)];
function bezier_length(v, delta = 0.01, t = 0, length = 0) = //! Calculate the length of a Bezier curve from control points ```v```
function bezier_length(v, delta = 0.01, t = 0, length = 0) = //! Calculate the length of a Bezier curve from control points `v`
t > 1 ? length
: bezier_length(v, delta, t + delta, length + norm(bezier(t, v) - bezier(t + delta, v)));
@ -37,7 +37,7 @@ function adjust_bezier(v, r) =
let(extension = (v[1] - v[0]) * (r - 1))
[v[0], v[1] + extension, v[2] + extension, v[3]];
function adjust_bezier_length(v, l, eps = 0.001, r1 = 1.0, r2 = 1.5, l1, l2) = //! Adjust Bezier control points ```v``` to get the required curve length ```l```
function adjust_bezier_length(v, l, eps = 0.001, r1 = 1.0, r2 = 1.5, l1, l2) = //! Adjust Bezier control points `v` to get the required curve length `l`
let(l1 = l1 != undef ? l1 : bezier_length(adjust_bezier(v, r1)),
l2 = l2 != undef ? l2 : bezier_length(adjust_bezier(v, r2))
) abs(l1 - l) < eps ? adjust_bezier(v, r1)
@ -45,10 +45,10 @@ function adjust_bezier_length(v, l, eps = 0.001, r1 = 1.0, r2 = 1.5, l1, l2) = /
abs(r - r1) < abs(r - r2) ? adjust_bezier_length(v, l, eps, r, r1, undef, l1)
: adjust_bezier_length(v, l, eps, r, r2, undef, l2);
function bezier_min_z(v, steps = 100, z = inf, i = 0) = //! Calculate the minimum z coordinate of a Bezier curve from control points ```v```
function bezier_min_z(v, steps = 100, z = inf, i = 0) = //! Calculate the minimum z coordinate of a Bezier curve from control points `v`
i <= steps ? bezier_min_z(v, steps, min(z, bezier(i / steps, v).z), i + 1) : z;
function adjust_bezier_z(v, z, eps = 0.001, r1 = 1, r2 = 1.5, z1, z2) = //! Adjust Bezier control points ```v``` to get the required minimum ```z```
function adjust_bezier_z(v, z, eps = 0.001, r1 = 1, r2 = 1.5, z1, z2) = //! Adjust Bezier control points `v` to get the required minimum `z`
let(z1 = z1 != undef ? z1 : bezier_min_z(adjust_bezier(v, r1)),
z2 = z2 != undef ? z2 : bezier_min_z(adjust_bezier(v, r2))
) abs(z1 - z) < eps ? adjust_bezier(v, r1)

View File

@ -20,25 +20,25 @@
//
//! Catenary curve to model hanging wires, etc.
//!
//! Although the equation of the curve is simply ```y = a cosh(x / a)``` there is no explicit formula to calculate the constant ```a``` or the range of ```x``` given the
//! Although the equation of the curve is simply `y = a cosh(x / a)` there is no explicit formula to calculate the constant `a` or the range of `x` given the
//! length of the cable and the end point coordinates. See <https://en.wikipedia.org/wiki/Catenary#Determining_parameters>. The Newton-Raphson method is used to find
//! ```a``` numerically, see <https://en.wikipedia.org/wiki/Newton%27s_method>.
//! `a` numerically, see <https://en.wikipedia.org/wiki/Newton%27s_method>.
//!
//! The coordinates of the lowest point on the curve can be retrieved by calling ```catenary_points()``` with ```steps``` equal to zero.
//! The coordinates of the lowest point on the curve can be retrieved by calling `catenary_points()` with `steps` equal to zero.
//
include <core/core.scad>
use <maths.scad>
function catenary(t, a) = let(u = argsinh(t)) a * [u, cosh(u)]; //! Parametric catenary function linear along the length of the curve.
function catenary_s(d, a) = 2 * a * sinh(d / a); //! Length of a symmetric catenary with width ```2d```.
function catenary_ds_by_da(d, a) = 2 * sinh(d / a) - 2 * d / a * cosh(d / a); //! First derivative of the length with respect to ```a```.
function catenary_s(d, a) = 2 * a * sinh(d / a); //! Length of a symmetric catenary with width `2d`.
function catenary_ds_by_da(d, a) = 2 * sinh(d / a) - 2 * d / a * cosh(d / a); //! First derivative of the length with respect to `a`.
function catenary_find_a(d, l, a = 1, best_e = inf, best_a = 1) = //! Find the catenary constant ```a```, given half the horizontal span and the length.
function catenary_find_a(d, l, a = 1, best_e = inf, best_a = 1) = //! Find the catenary constant `a`, given half the horizontal span and the length.
assert(l > 2 * d, "Not long enough to span the gap") assert(d) let(error = abs(catenary_s(d, a) - l))
error >= best_e && error < 0.0001 ? best_a
: catenary_find_a(d, l, max(a - (catenary_s(d, a) - l) / catenary_ds_by_da(d, a), d / argsinh(1e99)), error, a);
function catenary_points(l, x, y, steps = 100) = //! Returns a list of 2D points on the curve that goes from the origin to ```(x,y)``` and has length ```l```.
function catenary_points(l, x, y, steps = 100) = //! Returns a list of 2D points on the curve that goes from the origin to `(x,y)` and has length `l`.
let(
d = x / 2,
a = catenary_find_a(d, sqrt(sqr(l) - sqr(y))), // Find a to get the correct length

View File

@ -18,24 +18,24 @@
//
//
//! Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing.
//! Bill Of Materials generation via echo and the `bom.py` script. Also handles exploded assembly views and posing.
//! Assembly instructions can precede the module definition that makes the assembly.
//!
//! 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.
//! This heuristic isn't always correct, so the default can be overridden by setting the ```big``` parameter of ```assembly``` to ```true``` or ```false```.
//! This heuristic isn't always correct, so the default can be overridden by setting the `big` parameter of `assembly` to `true` or `false`.
//!
//! 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.
//
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
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of ```$exploded``` if it is defined, else ```0```
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of `$exploded` if it is defined, else `0`
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
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector ```d```, option to explode grand children
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector `d`, option to explode grand children
v = is_list(d) ? d : [0, 0, d];
o = is_list(offset) ? offset : [0, 0, offset];
if($exploded && is_undef($exploded_parent) && norm(v)) {
@ -55,7 +55,7 @@ module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode
children();
}
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.
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.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
@ -67,7 +67,7 @@ module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an
translate(-t)
children();
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.
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.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
@ -75,7 +75,7 @@ module pose_hflip(exploded = undef) //! Pose an STL or assembly for render
hflip()
children();
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.
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.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
@ -84,7 +84,7 @@ module pose_vflip(exploded = undef) //! Pose an STL or assembly for render
children();
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.
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.
if(bom_mode()) {
args = is_undef(big) ? "" : str("(big=", big, ")");
echo(str("~", name, "_assembly", args, "{"));
@ -101,20 +101,20 @@ module assembly(name, big = undef) { //! Name an assembly that will appear on
echo(str("~}", name, "_assembly"));
}
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.
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.
$stl_colour = colour;
color(colour, alpha)
children();
}
module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named ```<name>_stl``` to make it
module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it
if(bom_mode()) {
colour = is_undef($stl_colour) ? pp1_colour : $stl_colour;
echo(str("~", name, ".stl(colour='", colour, "')"));
}
}
module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named ```<name>_dxf``` to make it
module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named `<name>_dxf` to make it
if(bom_mode()) {
if(is_undef($dxf_colour))
echo(str("~", name, ".dxf"));
@ -123,9 +123,9 @@ module dxf(name) { //! Name a dxf that will appear on the B
}
}
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
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
function arg(value, default, name = "") = //! Create string for arg if not default, helper for ```vitamin()```
function arg(value, default, name = "") = //! Create string for arg if not default, helper for `vitamin()`
value == default ? ""
: name ? str(", ", name, " = ", value_string(value))
: str(", ", value_string(value));

View File

@ -29,11 +29,11 @@ function mm(x) = x;
function cm(x) = x * 10.0; //! cm to mm conversion
function m(x) = x * 1000.0; //! m to mm conversion
function sqr(x) = x * x; //! Returns the square of ```x```
function sqr(x) = x * x; //! Returns the square of `x`
function echoit(x) = echo(x) x; //! Echo expression and return it, useful for debugging
function no_point(str) = chr([for(c = str(str)) if(c == ".") ord("p") else ord(c)]);//! Replace decimal point in string with 'p'
function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if ```x``` is an element in the ```list```
function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if ```x``` is not a list
function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if `x` is an element in the `list`
function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if `x` is not a list
function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius
function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes
function limit(x, min, max) = max(min(x, max), min); //! Force x in range min <= x <= max
@ -52,14 +52,14 @@ function slice(list, start = 0, end = undef) = let( //! Slice a list or string w
) is_string(list) ? slice_str(list, start, end) : [for(i = [start : 1 : end - 1]) list[i]];
module render_if(render = true, convexity = 2) //! Renders an object if ```render``` is true, otherwise leaves it unrendered
module render_if(render = true, convexity = 2) //! Renders an object if `render` is true, otherwise leaves it unrendered
if (render)
render(convexity = convexity)
children();
else
children();
module extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D
module extrude_if(h, center = true) //! Extrudes 2D object to 3D when `h` is nonzero, otherwise leaves it 2D
if(h)
linear_extrude(h, center = center, convexity = 2) // 3D
children();
@ -81,7 +81,7 @@ module semi_circle(r, d = undef) //! A semi circle in the pos
square([2 * sq, sq]);
}
module right_triangle(width, height, h, center = true) //! A right angled triangle with the 90&deg; corner at the origin. 3D when ```h``` is nonzero, otherwise 2D
module right_triangle(width, height, h, center = true) //! A right angled triangle with the 90&deg; corner at the origin. 3D when `h` is nonzero, otherwise 2D
extrude_if(h, center = center)
polygon(points = [[0,0], [width, 0], [0, height]]);

View File

@ -20,29 +20,28 @@
//
//! Rectangle with rounded corners.
//
module rounded_square(size, r, center = true) //! Like ```square()``` but with with rounded corners
module rounded_square(size, r, center = true) //! Like `square()` but with with rounded corners
{
$fn = r2sides4n(r);
offset(r) offset(-r) square(size, center = center);
}
module rounded_rectangle(size, r, center = true, xy_center = true) //! Like ```cube()``` but corners rounded in XY plane and separate centre options for xy and z.
module rounded_rectangle(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
{
linear_extrude(size.z, center = center)
rounded_square([size.x, size.y], r, xy_center);
}
module rounded_rectangle_xz(size, r, center = true, xy_center = true) //! Like ```cube()``` but corners rounded in XZ plane and separate centre options for xy and z.
module rounded_rectangle_xz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z.
{
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
rotate([90, 0, 0])
rounded_rectangle([size.x, size.z, size.y], r, center = true, xy_center = true);
}
module rounded_rectangle_yz(size, r, center = true, xy_center = true) //! Like ```cube()``` but corners rounded in YX plane and separate centre options for xy and z.
module rounded_rectangle_yz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z.
{
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
rotate([90, 0, 90])
rounded_rectangle([size.y, size.z, size.x], r, center = true, xy_center = true);
}

View File

@ -20,7 +20,7 @@
//! Redefines `sphere()` to always have a vertex on all six half axes I.e. vertices at the poles and the equator and `$fn` a multiple of four.
//! This ensures `hull` and `minkowski` results have the correct dimensions when spheres are placed at the corners.
module sphere(r = 1, d = undef) { //! Override ```sphere``` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled
module sphere(r = 1, d = undef) { //! Override `sphere` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled
R = is_undef(d) ? r : d / 2;
rotate_extrude($fn = r2sides4n(R))
rotate(-90)

View File

@ -24,7 +24,7 @@
//! Using teardrop_plus() or setting the plus option on other modules will elongate the teardrop vertically by the layer height, so when sliced the staircase tips
//! do not intrude into the circle. See <https://hydraraptor.blogspot.com/2020/07/horiholes-2.html>
//
module teardrop(h, r, center = true, truncate = true, chamfer = 0, plus = false) { //! For making horizontal holes that don't need support material, set ```truncate = false``` to make traditional RepRap teardrops that don't even need bridging
module teardrop(h, r, center = true, truncate = true, chamfer = 0, plus = false) { //! For making horizontal holes that don't need support material, set `truncate = false` to make traditional RepRap teardrops that don't even need bridging
module teardrop_2d(r, truncate) {
er = layer_height / 2 - eps; // Extrustion edge radius
R = plus ? r + er : r; // Corrected radius

View File

@ -24,17 +24,17 @@
//! <https://khkgears.net/new/gear_knowledge/gear_technical_reference/calculation_gear_dimensions.html>
//! and <https://www.tec-science.com/mechanical-power-transmission/involute-gear/calculation-of-involute-gears/>
//!
//! ```involute_gear_profile()``` returns a polygon that can have the bore and spokes, etc, subtracted from it before linear extruding it to 3D.
//! Helical gears can be made using ```twist``` and bevel gears using ```scale``` parameters of ```linear_extrude()```.
//! `involute_gear_profile()` returns a polygon that can have the bore and spokes, etc, subtracted from it before linear extruding it to 3D.
//! Helical gears can be made using `twist` and bevel gears using `scale` parameters of `linear_extrude()`.
//!
//! Gears with less than 19 teeth (when pressure angle is 20) are profile shifted to avoid undercutting the tooth root. 7 teeth is considered
//! the practical minimum.
//!
//! The clearance between tip and root defaults to module / 6, but can be overridden by setting the ```clearance``` parameter.
//! The clearance between tip and root defaults to module / 6, but can be overridden by setting the `clearance` parameter.
//!
//! The origin of the rack is the left end of the pitch line and its width is below the pitch line. I.e. it does not include the addendum.
//!
//! ```involute_worm_profile()``` returns a tooth profile that can be passed to ```thread()``` to make worms.
//! `involute_worm_profile()` returns a tooth profile that can be passed to `thread()` to make worms.
//
include <core/core.scad>
use <maths.scad>

View File

@ -22,7 +22,7 @@
//
include <../utils/core/core.scad>
module hanging_hole(z, ir, h = 100, h2 = 100) { //! Hole radius ```ir``` hanging at the specified ```z``` value above a void who's shape is given by a 2D child
module hanging_hole(z, ir, h = 100, h2 = 100) { //! Hole radius `ir` hanging at the specified `z` value above a void who's shape is given by a 2D child
module polyhole(r, h, n = 8) {
if(h > 0)
rotate(180 / n) {

View File

@ -20,7 +20,7 @@
//
//! Utilities for depicting the staircase slicing of horizontal holes made with [`teardrop_plus()`](#teardrops), see <https://hydraraptor.blogspot.com/2020/07/horiholes-2.html>
//!
//! ```horicylinder()``` makes cylinders that fit inside a round hole. Layers that are less than 2 filaments wide and layers that need more than a 45 degree overhang are omitted.
//! `horicylinder()` makes cylinders that fit inside a round hole. Layers that are less than 2 filaments wide and layers that need more than a 45 degree overhang are omitted.
//
include <../utils/core/core.scad>

View File

@ -22,11 +22,11 @@
//
include <../global_defs.scad>
function layout_offset(widths, i, gap = 2) = //! Calculate the offset for the ```i```th item
function layout_offset(widths, i, gap = 2) = //! Calculate the offset for the `i`th item
i == 0 ? widths[0] / 2
: layout_offset(widths, i - 1, gap) + widths[i - 1] / 2 + gap + widths[i] / 2;
module layout(widths, gap = 2, no_offset = false) //! Layout children passing ```$i```
module layout(widths, gap = 2, no_offset = false) //! Layout children passing `$i`
translate([no_offset ? -widths[0] / 2 : 0, 0])
for($i = [0 : 1 : len(widths) - 1])
translate([layout_offset(widths, $i, gap), 0])

View File

@ -33,7 +33,7 @@ function argcosh(x) = ln(x + sqrt(sqr(x) - 1)); //! inverse hyperbolic cosine
function argtanh(x) = ln((1 + x) / (1 - x)) / 2;//! inverse hyperbolic tangent
function argcoth(x) = ln((x + 1) / (x - 1)) / 2;//! inverse hyperbolic cotangent
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z```
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Generate a 4x4 translation matrix, `v` can be `[x, y]`, `[x, y, z]` or `z`
: v
: [0, 0, v])
[ [1, 0, 0, u.x],
@ -41,7 +41,7 @@ function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Gen
[0, 0, 1, u.z],
[0, 0, 0, 1] ];
function rotate(a, v) = //! Generate a 4x4 rotation matrix, ```a``` can be a vector of three angles or a single angle around ```z```, or around axis ```v```
function rotate(a, v) = //! Generate a 4x4 rotation matrix, `a` can be a vector of three angles or a single angle around `z`, or around axis `v`
is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a],
cx = cos(av[0]),
cy = cos(av[1]),
@ -80,7 +80,7 @@ function rot2_z(a) = //! Generate a 2x2 matrix to rotate around z
[ [ c, -s],
[ s, c] ];
function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matrix that scales by ```v```, which can be a vector of xyz factors or a scalar to scale all axes equally
function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matrix that scales by `v`, which can be a vector of xyz factors or a scalar to scale all axes equally
[
[s.x, 0, 0, 0],
[0, s.y, 0, 0],
@ -88,11 +88,11 @@ function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matr
[0, 0, 0, 1]
];
function vec3(v) = [v.x, v.y, v.z]; //! Return a 3 vector with the first three elements of ```v```
function vec4(v) = [v.x, v.y, v.z, 1]; //! Return a 4 vector with the first three elements of ```v```
function vec3(v) = [v.x, v.y, v.z]; //! Return a 3 vector with the first three elements of `v`
function vec4(v) = [v.x, v.y, v.z, 1]; //! Return a 4 vector with the first three elements of `v`
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]); //! Apply 4x4 transform to a 3 vector by extending it and cropping it again
function transform_points(path, m) = [for(p = path) transform(p, m)]; //! Apply transform to a path
function unit(v) = let(n = norm(v)) n ? v / n : v; //! Convert ```v``` to a unit vector
function unit(v) = let(n = norm(v)) n ? v / n : v; //! Convert `v` to a unit vector
function transpose(m) = [ for(j = [0 : len(m[0]) - 1]) [ for(i = [0 : len(m) - 1]) m[i][j] ] ]; //! Transpose an arbitrary size matrix

View File

@ -24,7 +24,7 @@
//! If `chamfer_base` is true then the bottom edge is made suitable for 3D printing by chamfering when the angle gets shallower than 45 degrees.
include <../utils/core/core.scad>
module offset_3D(r, chamfer_base = false) { //! Offset 3D shape by specified radius ```r```, positive or negative.
module offset_3D(r, chamfer_base = false) { //! Offset 3D shape by specified radius `r`, positive or negative.
module ball(r)
if(chamfer_base)
rotate_extrude()

View File

@ -22,7 +22,7 @@
//
include <../utils/core/core.scad>
module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when ```center``` is ```true```.
module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when `center` is `true`.
h = is_list(w) ? w.y : w;
w = is_list(w) ? w.x : w;
offset_w = center ? r - w : 0;

View File

@ -40,7 +40,7 @@ module rounded_corner(r, h, r2, ir = 0) { //! 2D version
}
}
module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius ```r```, height ```h```, optional internal radius ```ir``` and optional ```angle```
module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius `r`, height `h`, optional internal radius `ir` and optional `angle`
{
rotate_extrude(angle = angle)
rounded_corner(r, h, r2, ir);

View File

@ -48,7 +48,7 @@ function rounded_polygon_tangents(points) = //! Compute the straight sections ne
function sumv(v, i = 0, sum = 0) = i == len(v) ? sum : sumv(v, i + 1, sum + v[i]);
// the cross product of 2D vectors is the area of the parallelogram between them. We use the sign of this to decide if the angle is bigger than 180.
function rounded_polygon_length(points, tangents) = //! Calculate the length given the point list and the list of tangents computed by ``` rounded_polygon_tangents```
function rounded_polygon_length(points, tangents) = //! Calculate the length given the point list and the list of tangents computed by ` rounded_polygon_tangents`
let(
len = len(points),
indices = [0 : len - 1],

View File

@ -22,7 +22,7 @@
//
include <../utils/core/core.scad>
module sector(r, start_angle, end_angle) { //! Create specified sector given radius ```r```, ```start_angle``` and ```end_angle```
module sector(r, start_angle, end_angle) { //! Create specified sector given radius `r`, `start_angle` and `end_angle`
R = r * sqrt(2) + 1;
if(end_angle > start_angle)

View File

@ -172,10 +172,10 @@ function arc_points(r, a = [90, 0, 180], al = 90) = //! Generate the points of a
let(sides = ceil(r2sides(r) * al / 360), tf = rotate(a))
[for(i = [0 : sides]) let(t = i * al / sides) transform([r * sin(t), r * cos(t), 0], tf)];
function before(path1, path2) = //! Translate ```path1``` so its end meets the start of ```path2``` and then concatenate
function before(path1, path2) = //! Translate `path1` so its end meets the start of `path2` and then concatenate
let(end = len(path1) - 1, offset = path2[0] - path1[end])
concat([for(i = [0 : end - 1]) path1[i] + offset], path2);
function after(path1, path2) = //! Translate ```path2``` so its start meets the end of ```path1``` and then concatenate
function after(path1, path2) = //! Translate `path2` so its start meets the end of `path1` and then concatenate
let(end1 = len(path1) - 1, end2 = len(path2) - 1, offset = path1[end1] - path2[0])
concat(path1, [for(i = [1 : end2]) path2[i] + offset]);

View File

@ -20,7 +20,7 @@
//
//! Utilities for making threads with sweep. They can be used to model screws, nuts, studding, leadscrews, etc, and also to make printed threads.
//!
//! The ends can be tapered, flat or chamfered by setting the ```top``` and ```bot``` parameters to -1 for tapered, 0 for a flat cut and positive to
//! The ends can be tapered, flat or chamfered by setting the `top` and `bot` parameters to -1 for tapered, 0 for a flat cut and positive to
//! specify a chamfer angle.
//!
//! Threads are by default solid, so the male version is wrapped around a cylinder and the female inside a tube. This can be suppressed to just get the helix, for
@ -32,8 +32,8 @@
//! a cylinder. To get around this a colour can be passed to thread that is used to colour the cylinder and then toned down to colour the helix.
//!
//! Making the ends requires a CGAL intersection, which make threads relatively slow. For this reason they are generally disabled when using the GUI but can
//! be enabled by setting ```$show_threads``` to ```true```. When the tests are run, by default, threads are enabled only for things that feature them like screws.
//! This behaviour can be changed by setting a ```NOPSCADLIB_SHOW_THREADS``` environment variable to ```false``` to disable all threads and ```true``` to enable all threads.
//! be enabled by setting `$show_threads` to `true`. When the tests are run, by default, threads are enabled only for things that feature them like screws.
//! This behaviour can be changed by setting a `NOPSCADLIB_SHOW_THREADS` environment variable to `false` to disable all threads and `true` to enable all threads.
//! The same variable also affects the generation of assembly diagrams.
//!
//! Threads obey the $fn, $fa, $fs variables.

View File

@ -28,11 +28,11 @@ module ring(or, ir) //! Create a ring with specified external and internal radii
circle4n(ir);
}
module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height ```h```
module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height `h`
linear_extrude(h, center = center, convexity = 5)
ring(or, ir);
module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2, weft) {//! Create a woven tube with specified external and internal radii, height ```h```, colours, warp and weft
module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2, weft) {//! Create a woven tube with specified external and internal radii, height `h`, colours, warp and weft
colour2 = colour2 ? colour2 : colour * 0.8;
weft = weft ? weft : warp;
warp_count = max(floor(PI * or / warp), 0.5);
@ -68,4 +68,3 @@ module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2,
}
}
}

View File

@ -74,7 +74,7 @@ module orientate_axial(length, height, pitch, wire_d) { // Orient horizontal or
}
}
module ax_res(type, value, tol = 5, pitch = 0) { //! Through hole axial resistor. If ```pitch``` is zero the minimum is used. If below the minimum the resistor is placed vertical.
module ax_res(type, value, tol = 5, pitch = 0) { //! Through hole axial resistor. If `pitch` is zero the minimum is used. If below the minimum the resistor is placed vertical.
vitamin(str("ax_res(", type[0], ", ", value, arg(tol, 5, "tol"), "): Resistor ", value, " Ohms ", tol, "% ",ax_res_wattage(type), "W"));
wire_d = ax_res_wire(type);

View File

@ -24,7 +24,7 @@
//! To make the back of the belt run against a smooth pulley on the outside of the loop specify a negative pitch radius.
//!
//! By default the path is a closed loop but a gap length and position can be specified to make open loops.
//! To draw the gap its XY position is specified by ```gap_pos```. ```gap_pos.z``` can be used to specify a rotation if the gap is not at the bottom of the loop.
//! To draw the gap its XY position is specified by `gap_pos`. `gap_pos.z` can be used to specify a rotation if the gap is not at the bottom of the loop.
//!
//! Individual teeth are not drawn, instead they are represented by a lighter colour.
//

View File

@ -209,7 +209,7 @@ module al_clad_resistor_assembly(type, value, sleeved = true) { //* Draw alumini
function TO220_thickness() = 1.5; //! Thickness of the tab of a TO220
module TO220(description, leads = 3, lead_length = 16) { //! Draw a TO220 package, use ```description``` to describe what it is
module TO220(description, leads = 3, lead_length = 16) { //! Draw a TO220 package, use `description` to describe what it is
width = 10.2;
inset = 1.5;
hole = 3.3;

View File

@ -122,7 +122,7 @@ module fan_hole_positions(type, z = undef) { //! Position children at the screw
children();
}
module fan_holes(type, poly = false, screws = true, h = 100) { //! Make all the holes for the fan, or just the aperture if ```screws``` is false. Set ```poly``` true for poly_holes.
module fan_holes(type, poly = false, screws = true, h = 100) { //! Make all the holes for the fan, or just the aperture if `screws` is false. Set `poly` true for poly_holes.
hole_pitch = fan_hole_pitch(type);
screw = fan_screw(type);

View File

@ -89,7 +89,7 @@ module insert(type) { //! Draw specified insert
}
}
module insert_hole(type, counterbore = 0, horizontal = false) { //! Make a hole to take an insert, ```counterbore``` is the extra length for the screw
module insert_hole(type, counterbore = 0, horizontal = false) { //! Make a hole to take an insert, `counterbore` is the extra length for the screw
h = insert_hole_length(type);
render(convexity = 2)

View File

@ -21,7 +21,7 @@
//! LED strip lights that can be cut to size.
//!
//! The definitions are for the full length but they can be cut to size by specifying how many segments,
//! which can by calcuated using ```light_strip_segments(type, max_length)```.
//! which can by calcuated using `light_strip_segments(type, max_length)`.
//!
//! The `light_strip_clip()` module makes a clip to go around the light that can be incorporated into a printed bracket to hold it.
//

View File

@ -20,7 +20,7 @@
//
//! Microview OLED display with on board AVR by geekammo / Sparkfun.
//!
//! ```microview()``` generates the model. ```microview(true)``` makes an object to cut out a panel aperture for it.
//! `microview()` generates the model. `microview(true)` makes an object to cut out a panel aperture for it.
//!
//! Uses STL files copyright geekammo and licenced with MIT license, see [microview/LICENSE.txt](vitamins/microview/LICENSE.txt).
//

View File

@ -20,12 +20,12 @@
//
//! Nitrile rubber O-rings.
//!
//! Just a black torus specified by internal diameter, ```id``` and ```minor_d``` plus a BOM entry.
//! Can be shown stretched by specifying the ```actual_id```.
//! Just a black torus specified by internal diameter, `id` and `minor_d` plus a BOM entry.
//! Can be shown stretched by specifying the `actual_id`.
//
include <../utils/core/core.scad>
module O_ring(id, minor_d, actual_id = 0) { //! Draw O-ring with specified internal diameter and minor diameter. ```actual_id``` can be used to stretch it around something.
module O_ring(id, minor_d, actual_id = 0) { //! Draw O-ring with specified internal diameter and minor diameter. `actual_id` can be used to stretch it around something.
vitamin(str("O_ring(", id, ", ", minor_d, "): O-ring nitrile ", id, "mm x ", minor_d, "mm"));
D = actual_id > id ? actual_id : id; // allow it to be stretched

View File

@ -47,7 +47,7 @@ function carriage_pitch_y(type) = type[6]; //! Screw hole y pitch
function carriage_screw(type) = type[7]; //! Carriage screw type
function carriage_screw_depth(type) = 2 * screw_radius(carriage_screw(type)); //! Carriage thread depth
function rail_holes(type, length) = //! Number of holes in a rail given its ```length```
function rail_holes(type, length) = //! Number of holes in a rail given its `length`
floor((length - 2 * rail_end(type)) / rail_pitch(type)) + 1;
module rail_hole_positions(type, length, first = 0, screws = 100, both_ends = true) { //! Position children over screw holes

View File

@ -20,7 +20,7 @@
//
//! Machine screws and wood screws with various head styles.
//!
//! For an explanation of ```screw_polysink()``` see <https://hydraraptor.blogspot.com/2020/12/sinkholes.html>.
//! For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2020/12/sinkholes.html>.
//
include <../utils/core/core.scad>

View File

@ -63,7 +63,7 @@ module scs_bearing_block(type) { //! Draw the specified SCS bearing block
bearing = scs_bearing(type);
clip = scs_circlip(type);
module right_trapezoid(base, top, height, h = 0, center = true) {//! A right angled trapezoid with the 90&deg; corner at the origin. 3D when ```h``` is nonzero, otherwise 2D
module right_trapezoid(base, top, height, h = 0, center = true) {//! A right angled trapezoid with the 90&deg; corner at the origin. 3D when `h` is nonzero, otherwise 2D
extrude_if(h, center = center)
polygon(points = [ [0,0], [base, 0], [top, height], [0, height] ]);
}

View File

@ -36,7 +36,7 @@ function smd_100th(x) = //! Convert dimension to 1/100" notation
function smd_size(size) = //! Convert size to 1/100" notation
str(smd_100th(size.x), smd_100th(size.y));
module smd_led(type, colour, cutout) { //! Draw an SMD LED with specified ```colour```
module smd_led(type, colour, cutout) { //! Draw an SMD LED with specified `colour`
size = smd_led_size(type);
vitamin(str("smd_led(", type[0], ", ", colour, "): SMD LED ", smd_size(size), " ", colour));

View File

@ -68,7 +68,7 @@ module cable_tie_holes(cable_r, h = 100) { //! Holes to thread a ziptie through
drill(r, 0);
}
module cable_tie(cable_r, thickness) { //! A ziptie threaded around cable radius ```cable_r``` and through a panel with specified ```thickness```.
module cable_tie(cable_r, thickness) { //! A ziptie threaded around cable radius `cable_r` and through a panel with specified `thickness`.
translate_z(cable_r)
rotate([-90, 0, 90])
ziptie(small_ziptie, cable_r, thickness);

View File

@ -30,7 +30,7 @@ function ziptie_latch(type) = type[3]; //! Latch dimensions
function ziptie_colour(type) = type[4]; //! Colour
function ziptie_tail(type) = type[5]; //! The length without teeth
module ziptie(type, r, t = 0) //! Draw specified ziptie wrapped around radius ```r``` and optionally through panel thickness ```t```
module ziptie(type, r, t = 0) //! Draw specified ziptie wrapped around radius `r` and optionally through panel thickness `t`
{
latch = ziptie_latch(type);
lx = latch.x / 2;