1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-09-03 20:32:35 +02:00

Compare commits

...

83 Commits

Author SHA1 Message Date
Chris Palmer
26b2b63b6e Merge branch 'martinbudden-rocker' 2021-01-02 10:13:23 +00:00
Chris Palmer
611772d960 Updated readme for rocker. 2021-01-02 10:12:54 +00:00
Chris Palmer
b6e648b485 Merge branch 'rocker' of https://github.com/martinbudden/NopSCADlib into martinbudden-rocker 2021-01-02 10:10:03 +00:00
Chris Palmer
e224ee0ad2 Removed z fight in printed box test. 2021-01-02 10:04:24 +00:00
Chris Palmer
10c3df466b screw_polysink can now have h = 0 to get just the cone. 2021-01-02 10:04:03 +00:00
Chris Palmer
029265e1b9 Add rr_green to global_defs. 2020-12-31 12:27:46 +00:00
Martin Budden
49f6da767a Added size and slot convenience functions. Added non-rounded hole. 2020-12-31 11:59:41 +00:00
Chris Palmer
171dff723f Updated gallery pictures 2020-12-30 19:05:14 +00:00
Chris Palmer
85a7494813 Updated gallery images 2020-12-30 09:49:17 +00:00
Chris Palmer
46937e403e Better use of Python regex facilities. 2020-12-30 09:48:46 +00:00
Chris Palmer
8f2532d61b Merge branch 'martinbudden-gt2x16_pulley' 2020-12-29 22:29:57 +00:00
Chris Palmer
84fa528ff7 Updated images and readme for new pulley. 2020-12-29 22:29:11 +00:00
Chris Palmer
807850aac5 Merge branch 'gt2x16_pulley' of https://github.com/martinbudden/NopSCADlib into martinbudden-gt2x16_pulley 2020-12-29 21:45:47 +00:00
Chris Palmer
4ea0883965 Blurb divider now three or more asterisks. 2020-12-29 21:42:05 +00:00
Martin Budden
103ad1827e Added GT2x16_pulley. 2020-12-29 17:25:18 +00:00
Chris Palmer
816adb07e7 Typo. 2020-12-29 12:22:45 +00:00
Chris Palmer
06e1c1a3da Documented project description blurb and openscad.py. 2020-12-29 12:20:32 +00:00
Chris Palmer
46ff632bbb Better screw test layout. 2020-12-29 11:30:14 +00:00
Chris Palmer
fc47b1d9db Merge branch 'martinbudden-m5_cs_cap' 2020-12-28 21:25:11 +00:00
Chris Palmer
de6589a2ef Updated images and readme for M5_cs_cap_screw. 2020-12-28 21:24:04 +00:00
Chris Palmer
c2b3eb6580 Merge branch 'm5_cs_cap' of https://github.com/martinbudden/NopSCADlib into martinbudden-m5_cs_cap 2020-12-28 20:56:50 +00:00
Chris Palmer
ba586b3685 Example images update to match new contersink screws and teardrops. 2020-12-28 20:50:38 +00:00
Chris Palmer
8d22940506 Project blurb can now be split with into sections with markdown horizonal rules
made with asterisks.
If an image is include in the first section the default image is supressed.
2020-12-28 20:49:37 +00:00
Martin Budden
f6f4fcc7e8 Added M5_cs_cap screw 2020-12-28 20:24:46 +00:00
Chris Palmer
31bfa3b268 Merge branch 'master' of https://github.com/nophead/NopSCADlib.git 2020-12-26 20:09:06 +00:00
Chris Palmer
ec44fe96b4 openscad.py now works from the command line. 2020-12-26 20:08:47 +00:00
Chris
9e50d1217d Merge pull request #118 from martinbudden/carriage_fix
Fixed error in carriage_size function.
2020-12-26 19:46:20 +00:00
Martin Budden
87c8bbb9a5 Fixed error in carriage_size function. 2020-12-26 19:42:29 +00:00
Chris Palmer
ed1cc8b488 Fixed typo. 2020-12-24 16:23:22 +00:00
Chris Palmer
4cac382581 Single backtick now used for all code quotes. 2020-12-24 16:04:59 +00:00
Chris Palmer
04b98a3786 One backquote instead of three for code markup test. 2020-12-24 15:19:07 +00:00
Chris Palmer
6f8ff606fa Removed woven_sheet() from the readme.
Removed redundent code.
2020-12-24 09:01:51 +00:00
Chris Palmer
acd5de0fbd Fixed extra BOM entries for woven sheet.
Added render colour to BOM for 3D sheets.
2020-12-24 08:56:54 +00:00
Chris Palmer
cc1e3baaf6 Reimplemeted woven sheets with an eye to speed and interface consistancy. 2020-12-23 21:44:05 +00:00
Chris Palmer
ab50b6f9a6 Merge branch 'woven_sheet' of https://github.com/martinbudden/NopSCADlib 2020-12-23 16:50:30 +00:00
Chris Palmer
d9cb604f92 Merge branch 'martinbudden-carriage_size' 2020-12-23 16:48:55 +00:00
Chris Palmer
52d2a49e1c Updated readme for carriage_size(). 2020-12-23 16:48:26 +00:00
Martin Budden
85cb54ef31 Added sheet with checkerboard texture to simulate carbon fiber. 2020-12-23 07:47:41 +00:00
Martin Budden
cd4447a2e6 Added carriage_size convenience function. 2020-12-23 07:06:58 +00:00
Chris Palmer
9699a70cf5 Merge branch 'martinbudden-rounded_right_triangle' 2020-12-22 13:02:14 +00:00
Chris Palmer
6d79e587aa Updated readme and image for rounded_right_triangle. 2020-12-22 13:00:49 +00:00
Chris Palmer
15b3b3a8c2 Merge branch 'rounded_right_triangle' of https://github.com/martinbudden/NopSCADlib into martinbudden-rounded_right_triangle 2020-12-22 12:39:17 +00:00
Chris Palmer
ec891c8013 Merge branch 'martinbudden-dogbone_xy' 2020-12-22 12:35:35 +00:00
Chris Palmer
c7811f21e0 dogbone_rectangle_x() and dogbone_rectangle_y() added. 2020-12-22 12:34:08 +00:00
Martin Budden
782deccf6b Simplified dogbone rectangles. 2020-12-22 10:34:45 +00:00
Martin Budden
69da4c1c23 Added offset parameters to dogbone_square. 2020-12-22 10:09:43 +00:00
Martin Budden
dad2bccbaa Added a rounded right triangle. 2020-12-22 00:02:00 +00:00
Martin Budden
0a00f244e4 Added dogbones with circles offset in x and y directions. 2020-12-21 23:28:39 +00:00
Chris Palmer
76ea28e88e Merge branch 'martinbudden-render_if' 2020-12-20 21:30:39 +00:00
Chris Palmer
44cf9e910b Updated readme for render_if() 2020-12-20 21:30:05 +00:00
Chris Palmer
0261362794 Merge branch 'render_if' of https://github.com/martinbudden/NopSCADlib into martinbudden-render_if 2020-12-20 17:25:39 +00:00
Chris Palmer
2e6b55bcbc Merge branch 'martinbudden-rounded_rectangle_xyz' 2020-12-20 17:24:13 +00:00
Chris Palmer
20901f0356 Updated rounded_rectangle pictures and readme. 2020-12-20 17:24:00 +00:00
Chris Palmer
77ffdcb1ac Merge branch 'rounded_rectangle_xyz' of https://github.com/martinbudden/NopSCADlib into martinbudden-rounded_rectangle_xyz 2020-12-20 16:50:51 +00:00
Chris Palmer
6ab4bad97a Polyhole no longer adds an extra twist when layers is small. 2020-12-20 10:37:41 +00:00
Martin Budden
14c6219733 Added rounded_rectangles in the XZ and YZ planes. 2020-12-20 09:16:40 +00:00
Martin Budden
b21b7b9de0 Added render_if module. 2020-12-20 08:53:42 +00:00
Chris Palmer
73d814d2fe poly_cylinder() now has a twist parameter. 2020-12-18 09:22:39 +00:00
Chris Palmer
fa658d9eaa Moved polysink test to avoid clash in the big picture. 2020-12-17 07:28:02 +00:00
Chris
6d3f54b7a5 Merge pull request #107 from martinbudden/hanging_hole_rounding
Fixed rounding error in hangin_hole assert.
2020-12-16 21:58:40 +00:00
Chris Palmer
157ff60e19 screw_polysink now has an alternating layer option to be more printable inverted.
The screws test now tests polysinks and has printable sample.
2020-12-16 20:53:04 +00:00
Martin Budden
cbd3cf29af Fixed rounding error in hangin_hole assert. 2020-12-16 19:27:03 +00:00
Chris Palmer
bf618bb482 Whitespace fixes. 2020-12-13 10:29:54 +00:00
Chris Palmer
1e6f0a5c4d Added link to block article about screw_polysink(). 2020-12-12 10:58:54 +00:00
Chris Palmer
53c3cdb598 Added screw_polysink(). 2020-12-12 09:46:46 +00:00
Chris Palmer
f4857f6862 6mm screws added to the screw_longer_than() list. 2020-12-11 11:40:32 +00:00
Chris Palmer
1acc8d01c0 Fixed MGN5 rail hole dimension. 2020-12-11 08:39:28 +00:00
Chris Palmer
344e8d1583 Fixed countersink shape. 2020-12-10 23:27:27 +00:00
Chris Palmer
dd757a1461 screw_head_depth() now defaults to all of a cs head if no diameter specified. 2020-12-10 17:29:48 +00:00
Chris Palmer
b4f8892b1a Cs screw head shape more accurate. 2020-12-10 16:33:26 +00:00
Chris Palmer
4b033d9945 Drag chain screw positions no longer mirrored to allow teardrop holes.
Previously the lugs were mirrored but that caused mirrored teardrops in mating parts.
2020-12-05 11:33:53 +00:00
Chris Palmer
d5a711f4cc Typo in drag_chain 2020-12-04 12:08:55 +00:00
Chris Palmer
42b76ab8d3 drag_chain_link() now checks it has children when it should. 2020-12-01 18:46:14 +00:00
Chris Palmer
f18044915d Fixed nan length for rounded_polygon with zero radius corners. 2020-11-30 21:52:42 +00:00
Chris Palmer
17b12c7f31 views.py now uses enumerate() to be more Pythonic. 2020-11-29 12:21:38 +00:00
Chris Palmer
18ff4c6d46 DiBond6 sheet now grey. 2020-11-29 10:39:35 +00:00
Chris Palmer
2eecce819c Removed comment about sweep path restriction that is no longer relevant. 2020-11-29 10:22:49 +00:00
Chris Palmer
f7d81738bb pp2_colour and pp3_colour less saturated to show details better. 2020-11-29 09:49:05 +00:00
Chris Palmer
6d44124bab Made drag_chain_assembly big. 2020-11-27 23:11:47 +00:00
Chris Palmer
9bb9f09dca Simplified some of the code in box.scad in response to comments from SCA2D. 2020-11-27 18:23:44 +00:00
Chris Palmer
773a53829f Fixed drag_chains exploding when they shouldn't do. 2020-11-27 18:14:04 +00:00
Chris Palmer
07766d8cf0 Added printed press_fit.scad. 2020-11-27 18:13:01 +00:00
Chris Palmer
ceac5cdb27 Fixed bug in rail screw placement when putting screws in the middle.
Rail test can now move the carriages with customiser.
2020-11-26 14:24:46 +00:00
128 changed files with 6338 additions and 5276 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,28 +112,38 @@ 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.
That only has the a small set of utilities and the global settings in [global_defs.scad](../global_defs.scad) plus screws, nuts and washers that are required by a lot of other vitamins.
Any other vitamins used need to be included explicitly. One can copy the includes or use a line from [NopSCADlib/lib.scad](../lib.scad).
### Project Description
A description of the project can be placed in comments in Markdown format before the first include file.
By default this is followed by a picture of the main assembly unless the description contains any pictures.
The description can be divided into two or three sections using //! ***, which is a Markdown horizontal rule in a comment.
If there is a second section it is placed after the table of contents and a third section will be placed after the parts list.
If an actual horizontal rule is desired the alternative Markdown markup //! --- can be used.
### Parametric parts.
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 +154,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 +192,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
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.
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 original 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 +226,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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View File

@@ -43,11 +43,11 @@ Bench power supply built around an ATX PSU.
* The green LED shows the power good signal.
* Dummy loads keep the outputs in range.
![](Lab_ATX_PSU.png)
<a name="TOP"></a>
## Laser Load
15kV dummy load for testing CO2 laser PSUs
@@ -77,11 +77,11 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
## Mains Box
Mains isolated and variable supply with metering.
![](Mains_Box.png)
<a name="TOP"></a>
## SunBot
A solar tracker to keep a solar panel pointing at the sun.
@@ -95,13 +95,15 @@ WiFi enabled remote control turntable for photography
![](Turntable.png)
Was actually made from DiBond but shown made with carbon fibre here.
<a name="TOP"></a>
## Variac
Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp8266-spi-spy](https://hydraraptor.blogspot.com/2018/04/esp8266-spi-spy.html)
![](Variac.png)

View File

@@ -26,7 +26,7 @@
// Setting $bom after including lib overrides bom in the libs but not in the local file.
// Setting $_bom in the local file overrides it in the local file but not in the libs.
//
//function is_undef(x) = x == undef;
rr_green = [0, 146/255, 0]; // RepRap logo colour
$_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well
$exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view
@@ -34,9 +34,9 @@ layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // lay
extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing
nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects
pp1_colour = is_undef($pp1_colour) ? [0, 146/255, 0] : $pp1_colour; // printed part colour 1, RepRap logo colour
pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // printed part colour 2
pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3
pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour
pp2_colour = is_undef($pp2_colour) ? "Crimson" : $pp2_colour; // printed part colour 2
pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour; // printed part colour 3
pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4
show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction
show_threads = is_undef($show_threads) ? false : $show_threads; // show screw threads

View File

@@ -90,6 +90,7 @@ use <utils/gears.scad>
use <utils/hanging_hole.scad>
use <utils/fillet.scad>
use <utils/rounded_polygon.scad>
use <utils/rounded_right_triangle.scad>
use <utils/layout.scad>
use <utils/round.scad>
use <utils/offset.scad>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

After

Width:  |  Height:  |  Size: 860 KiB

View File

@@ -78,6 +78,7 @@ use <tests/opengrab.scad>
use <tests/panel_meters.scad>
use <tests/PCBs.scad>
use <tests/pillars.scad>
use <tests/press_fit.scad>
use <tests/PSUs.scad>
use <tests/pulleys.scad>
use <tests/rails.scad>
@@ -137,9 +138,12 @@ cable_grommets_y = 0;
translate([x5, cable_grommets_y])
cable_grommets();
translate([x5 + 80, cable_grommets_y])
translate([x5 + 50, cable_grommets_y])
ribbon_clamps();
translate([x5 + 95, cable_grommets_y])
press_fits();
translate([x5, cable_grommets_y + 60])
fixing_blocks();
@@ -427,7 +431,7 @@ translate([x4 + 175, belts_y, -20])
translate([x4, rails_y + 130])
rails();
translate([800, fans_y + 50])
translate([770, fans_y + 50])
cable_strips();
translate([x4, kp_pillow_blocks_y])

View File

@@ -23,7 +23,7 @@
//! together. The box panels can be customised to have holes and parts mounted on them by overriding the
//! definitions of `box_base()`, `box_front()`, etc.
//!
//! `box.scad` should be ```use```d and `box_assembly.scad` ```include```d.
//! `box.scad` should be `use`d and `box_assembly.scad` `include`d.
//!
//! A box is defined with a list that specifies the inside dimensions, top, bottom and side sheet materials, the
//! screw type and printed part wall thickness. This diagram shows how the various dimensions are labelled:
@@ -109,7 +109,7 @@ module grill_hole_positions(width, height, r = 1000) {
}
}
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set `poly` `true` for printing, `false` for milling.
extrude_if(h)
if(poly)
grill_hole_positions(width, height, r)
@@ -121,11 +121,12 @@ module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered arr
module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
t = box_sheet_slot(type);
inset = box_corner_gap(type) + box_profile_overlap(type);
difference() {
union() {
quadrant(box_hole_inset(type) + box_boss_r(type), box_boss_r(type)); // inside corner
translate([box_corner_gap(type) + box_profile_overlap(type), box_corner_gap(type) + box_profile_overlap(type)])
translate([inset, inset])
rotate(180)
quadrant(box_profile_overlap(type) + box_corner_rad(type), box_corner_rad(type)); // outside corner
}
@@ -212,33 +213,39 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
feet = bottom && box_feet(type);
t = box_sheet_slot(type);
outset = box_outset(type);
inset = box_inset(type);
inner_r = box_sheet_r(type);
foot_height = box_corner_gap(type) + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
cgap = box_corner_gap(type);
foot_height = cgap + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
foot_length = box_corner_rad(type) * 2;
height = box_bezel_height(type, bottom);
foot_extension = foot_height - height;
difference() {
w = box_width(type);
d = box_depth(type);
translate_z(-box_profile_overlap(type)) difference() {
rounded_rectangle([box_width(type) + 2 * outset, box_depth(type) + 2 * outset, feet ? foot_height : height], box_corner_rad(type), false);
tw = w + 2 * outset;
td = d + 2 * outset;
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type), false);
//
// Remove edges between the feet
//
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) - 2 * foot_length, box_depth(type) + 2 * outset + 1, 1], center = true);
cube([w - 2 * foot_length, td + 1, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) - 2 * (foot_length - foot_extension), box_depth(type) + 2 * outset + 1, 1], center = true);
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
}
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * foot_length, 1], center = true);
cube([tw + 1, d - 2 * foot_length, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * (foot_length - foot_extension), 1], center = true);
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
}
}
//
@@ -247,28 +254,28 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
translate_z(-box_profile_overlap(type))
linear_extrude(2 * box_profile_overlap(type), center = true)
for(i = [-1, 1]) {
translate([i * (box_width(type) / 2 + t / 2 - sheet_slot_clearance / 2), 0])
square([t, box_depth(type) - 2 * box_corner_gap(type)], center = true);
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
square([t, d - 2 * cgap], center = true);
translate([0, i * (box_depth(type) / 2 + t / 2 - sheet_slot_clearance / 2)])
square([box_width(type) - 2 * box_corner_gap(type), t], center = true);
translate([0, i * (d + t - sheet_slot_clearance) / 2])
square([w - 2 * cgap, t], center = true);
}
//
// recess for top / bottom panel
//
translate_z(box_corner_gap(type))
rounded_rectangle([box_width(type) + bezel_clearance, box_depth(type) + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
translate_z(cgap)
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
//
// leave plastic over the corner profiles
//
translate_z(-box_profile_overlap(type) - 1)
linear_extrude(box_profile_overlap(type) + box_corner_gap(type) + 2)
linear_extrude(box_profile_overlap(type) + cgap + 2)
union() {
difference() {
square([box_width(type) - 2 * box_inset(type),
box_depth(type) - 2 * box_inset(type)], center = true);
square([w - 2 * inset,
d - 2 * inset], center = true);
box_corner_quadrants(type, box_width(type), box_depth(type));
box_corner_quadrants(type, w, d);
}
box_screw_hole_positions(type)
poly_circle(screw_clearance_radius(box_screw(type)));
@@ -291,7 +298,9 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
dw = bw - 2 * dowel_wall;
dh = box_bezel_height(type, bottom) - dowel_h_wall;
dh2 = box_profile_overlap(type) + box_corner_gap(type) - dowel_h_wall;
profile_overlap = box_profile_overlap(type);
dh2 = profile_overlap + box_corner_gap(type) - dowel_h_wall;
end_clearance = 0.5;
module male() {
@@ -299,14 +308,14 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
linear_extrude(dowel_length - 2 * end_clearance, center = true)
difference() {
union() {
h = dh - layer_height;
h1 = dh - layer_height;
h2 = dh2 - layer_height;
hull() {
translate([bw / 2, h / 2])
square([dw - 1, h], center = true);
translate([bw / 2, h1 / 2])
square([dw - 1, h1], center = true);
translate([bw / 2, (h - 1) / 2])
square([dw, h - 1], center = true);
translate([bw / 2, (h1 - 1) / 2])
square([dw, h1 - 1], center = true);
}
hull() {
@@ -318,7 +327,7 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
}
}
translate([bw2 / 2, 0])
square([box_sheet_slot(type), 2 * box_profile_overlap(type)], center = true);
square([box_sheet_slot(type), 2 * profile_overlap], center = true);
}
}
@@ -359,7 +368,7 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
render() difference() {
union() {
clip(xmin = 0, xmax = w, ymin = 0, ymax = h)
translate([tw / 2 - x * w, th / 2 - y * h, box_profile_overlap(type)])
translate([tw / 2 - x * w, th / 2 - y * h, profile_overlap])
box_bezel(type, bottom);
if(x < cols - 1 && y == 0)
@@ -419,10 +428,14 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
}
}
module box_screw_hole_positions(type)
module box_screw_hole_positions(type) {
inset = box_hole_inset(type);
w = box_width(type) / 2 - inset;
d = box_depth(type) / 2 - inset;
for(x = [-1, 1], y = [-1, 1])
translate([x * (box_width(type) / 2 - box_hole_inset(type)), y * (box_depth(type) / 2 - box_hole_inset(type))])
translate([x * w, y * d])
children();
}
module box_base_blank(type) { //! Generates a 2D template for the base sheet
dxf("box_base");
@@ -551,25 +564,25 @@ module box_shelf_bracket_section(type, rows, cols, x, y) { //! Generates section
children();
}
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, ```sheet``` can be set to override the type
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, `sheet` can be set to override the type
dxf("box_left");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, ```sheet``` can be set to override the type
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, `sheet` can be set to override the type
dxf("box_right");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, ```sheet``` can be set to override the type
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, `sheet` can be set to override the type
dxf("box_front");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, ```sheet``` can be set to override the type
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, `sheet` can be set to override the type
dxf("box_back");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);

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.
//
@@ -63,7 +63,7 @@ function drag_chain_outer_size(type) = //! Link outer dimensions
let(s = drag_chain_size(type), z = s.z + drag_chain_bwall(type) + drag_chain_twall(type))
[s.x + z, s.y + 4 * drag_chain_wall(type) + 2 * clearance, z];
function screw_lug_radius(screw) = //! Radius if a screw lug
function screw_lug_radius(screw) = //! Radius of a screw lug
corrected_radius(screw_clearance_radius(screw)) + 3.1 * extrusion_width;
module screw_lug(screw, h = 0) //! Create a D shaped lug for a screw
@@ -88,17 +88,12 @@ module drag_chain_screw_positions(type, end) {//! Place children at the screw po
R = os.z / 2;
x0 = end ? R + norm([drag_chain_cam_x(type), R - drag_chain_twall(type)]) + clearance + r : r;
x1 = end ? os.x - r : os.x - 2 * R - clearance - r;
for(i = [0 : 3]) {
x = i % 2;
y = bool2int(i > 1);
for(i = [0 : 3], x = [x0, x1, x0, x1][i], y = [-1, -1, 1, 1][i])
if(drag_chain_screw_lists(type)[bool2int(end)][i])
translate([(x0 + x1) / 2, 0])
mirror([x, 0])
mirror([0, y])
translate([(x1 - x0) / 2, s.y / 2 + r])
translate([x, y * (s.y / 2 + r)])
let($a = [180, 0, 180, 0][i])
children();
}
}
function drag_chain_cam_x(type) = // how far the cam sticks out
let(s = drag_chain_size(type),
@@ -108,8 +103,7 @@ function drag_chain_cam_x(type) = // how far the cam sticks out
twall = drag_chain_twall(type)
) min(sqrt(max(sqr(cam_r) - sqr(r - twall), 0)), r);
module drag_chain_link(type, start = false, end = false) { //! One link of the chain, special case for start and end
module drag_chain_link(type, start = false, end = false, check_kids = true) { //! One link of the chain, special case for start and end
stl(str(drag_chain_name(type), "_drag_chain_link", start ? "_start" : end ? "_end" : ""));
s = drag_chain_size(type);
@@ -220,14 +214,20 @@ module drag_chain_link(type, start = false, end = false) { //! One link of the c
if(start || end) {
drag_chain_screw_positions(type, end)
rotate($a)
screw_lug(drag_chain_screw(type), os.z);
if(check_kids) {
custom = drag_chain_screw_lists(type)[bool2int(end)] == [0, 0, 0, 0];
assert($children == bool2int(custom), str("wrong number of children for ", end ? "end" : "start", " STL customisation: ", $children));
}
children();
}
}
if(start || end)
translate_z(-eps)
drag_chain_screw_positions(type, end)
rotate($a)
poly_cylinder(r = screw_clearance_radius(drag_chain_screw(type)), h = os.z + 2 * eps, center = false);
}
@@ -250,9 +250,8 @@ module drag_chain_link(type, start = false, end = false) { //! One link of the c
}
}
//! 1. Remove the support material from the links with side cutters.
//! 1. Clip the links together with the special ones at the ends.
module drag_chain_assembly(type, pos = 0) { //! Drag chain assembly
// Need to use a wrapper because can't define nested modules in an assembly
module _drag_chain_assembly(type, pos = 0) {
s = drag_chain_size(type);
x = (1 + exploded()) * s.x;
r = drag_chain_radius(type) * x / s.x;
@@ -279,7 +278,7 @@ module drag_chain_assembly(type, pos = 0) { //! Drag chain assembly
module link(n) // Position and colour link with origin at the hinge hole
translate([-z / 2, 0, -z / 2]) {
stl_colour(n < 0 || n == npoints - 1 ? pp3_colour : n % 2 ? pp1_colour : pp2_colour)
drag_chain_link(type, start = n == -1, end = n == npoints - 1)
drag_chain_link(type, start = n == -1, end = n == npoints - 1, check_kids = false)
let($fasteners = 0) children();
let($fasteners = 1) children();
}
@@ -287,8 +286,8 @@ module drag_chain_assembly(type, pos = 0) { //! Drag chain assembly
screws = drag_chain_screw_lists(type);
custom_start = screws[0] == [0, 0, 0, 0];
custom_end = screws[1] == [0, 0, 0, 0];
assert($children == bool2int(custom_start) + bool2int(custom_end), "wrong number of children for end customisation");
assembly(str(drag_chain_name(type), "_drag_chain")) {
assert($children == bool2int(custom_start) + bool2int(custom_end), str("wrong number of children for end customisation: ", $children));
for(i = [0 : npoints - 2]) let(v = points[i + 1] - points[i])
translate(points[i])
rotate([0, -atan2(v.z, v.x), 0])
@@ -305,4 +304,18 @@ module drag_chain_assembly(type, pos = 0) { //! Drag chain assembly
if(custom_end)
children(custom_start ? 1 : 0);
}
//! 1. Remove the support material from the links with side cutters.
//! 1. Clip the links together with the special ones at the ends.
module drag_chain_assembly(type, pos = 0) //! Drag chain assembly
assembly(str(drag_chain_name(type), "_drag_chain"), big = true)
if($children == 2)
_drag_chain_assembly(type, pos) {
children(0);
children(1);
}
else if($children == 1)
_drag_chain_assembly(type, pos)
children(0);
else
_drag_chain_assembly(type, pos);

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>

50
printed/press_fit.scad Normal file
View File

@@ -0,0 +1,50 @@
//
// NopSCADlib Copyright Chris Palmer 2020
// 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/>.
//
//
//! Utility for making printed press fit connectors to join printed parts.
//!
//! Add solvent or glue to make a permanent fixture.
//
include <../core.scad>
interference = 0.0;
bridge_droop = layer_height; //sqrt(4 * layer_height * filament_width / PI) - layer_height;
module press_fit_socket(w = 5, h = 50, horizontal = false) { //! Make a square hole to accept a peg
h = horizontal ? h : h + bridge_droop;
cube([w, w, 2 * h], center = true);
}
module press_fit_peg(h, w = 5, horizontal = false) { //! Make a rounded chamfered peg for easy insertion
module chamfered_square(w, horizontal) {
h = horizontal ? w - bridge_droop : w;
rounded_square([w, h], 1);
}
translate_z(-eps)
linear_extrude(height = h + eps - layer_height)
chamfered_square(w + interference, horizontal);
translate_z(h - layer_height - eps)
linear_extrude(height = layer_height + eps)
chamfered_square(w - layer_height, horizontal);
}

4774
readme.md

File diff suppressed because it is too large Load Diff

View File

@@ -39,8 +39,6 @@ def _scrape_blurb(lines):
if b:
break
text += t
if len(text):
text += '\n'
return text
def scrape_blurb(scad_file):
@@ -49,6 +47,16 @@ def scrape_blurb(scad_file):
lines = file.readlines()
return _scrape_blurb(lines)
def split_blurb(lines):
""" Split blurb on horizontal rules."""
blurbs = [""]
for line in lines.split('\n')[:-1]:
if re.match(r'\*{3,}',line):
blurbs.append("")
else:
blurbs[-1] += line + '\n'
return blurbs
def scrape_module_blurb(lines):
""" Find the Markup lines before the last function or module. """
text = ""

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,8 @@ 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)
else:
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

@@ -52,7 +52,7 @@ def gallery(force):
if os.path.isfile(document):
with open(document, 'rt') as readme:
for line in readme.readlines():
match = re.match(r"^.*!(\[.*\]\(.*\)).*$", line)
match = re.search(r"!(\[.*\]\(.*\))", line)
if match:
image = match.group(0)
if image.startswith('![Main Assembly](assemblies/'):

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,14 +18,14 @@
#
#
# Run openscad
#! Run `openscad.exe` and capture `stdout` and `stderr` in `openscad.log` as well as printing to the console.
#
from __future__ import print_function
import subprocess, sys
def run_list(args, silent = False):
cmd = ["openscad"] + args
def run_list(args, silent = False, verbose = False):
cmd = ["openscad.exe"] + args
if not silent:
for arg in cmd:
print(arg, end=" ")
@@ -33,7 +33,7 @@ def run_list(args, silent = False):
with open("openscad.log", "w") as log:
rc = subprocess.call(cmd, stdout = log, stderr = log)
for line in open("openscad.log", "rt"):
if 'ERROR:' in line or 'WARNING:' in line:
if verbose or 'ERROR:' in line or 'WARNING:' in line:
print(line[:-1])
if rc:
sys.exit(rc)
@@ -43,3 +43,6 @@ def run(*args):
def run_silent(*args):
run_list(list(args), True);
if __name__ == '__main__':
run_list(sys.argv[1:], True, True)

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,23 @@
# 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. |
| `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`. |
| `openscad.py` | Run `openscad.exe` and capture `stdout` and `stderr` in `openscad.log` as well as printing to the console. |
| `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

@@ -35,6 +35,7 @@ import json
import blurb
import bom
import shutil
import re
from colorama import Fore
def is_assembly(s):
@@ -217,11 +218,16 @@ def views(target, do_assemblies = None):
if not main_file:
raise Exception("can't find source for main_assembly")
text = blurb.scrape_blurb(source_dir + '/' + main_file)
blurbs = blurb.split_blurb(text)
if len(text):
print(text, file = doc_file, end = '')
print(blurbs[0], file = doc_file)
else:
if print_mode:
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
#
# Only add the image if the first blurb section doesn't contain one.
#
if not re.search(r'\!\[.*\]\(.*\)', blurbs[0], re.MULTILINE):
print('![Main Assembly](assemblies/%s.png)\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file)
eop(print_mode, doc_file, first = True)
#
@@ -234,6 +240,8 @@ def views(target, do_assemblies = None):
cap_name = titalise(name)
print('1. [%s](#%s)' % (cap_name, name), file = doc_file)
print(file = doc_file)
if len(blurbs) > 1:
print(blurbs[1], file = doc_file)
eop(print_mode, doc_file)
#
# Global BOM
@@ -283,6 +291,8 @@ def views(target, do_assemblies = None):
print("| %s | %s |" % (pad(grand_total, 2, 1), pad('Total %s count' % headings[t], 2)), file = doc_file)
print(file = doc_file)
if len(blurbs) > 2:
print(blurbs[2], file = doc_file)
eop(print_mode, doc_file)
#
# Assembly instructions
@@ -308,8 +318,7 @@ def views(target, do_assemblies = None):
if printed:
print('### 3D Printed parts', file = doc_file)
keys = sorted(list(printed.keys()))
for i in range(len(keys)):
p = keys[i]
for i, p in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
if (i % 3) == 2 or i == len(printed) - 1:
n = (i % 3) + 1
@@ -324,8 +333,7 @@ def views(target, do_assemblies = None):
if routed:
print("### CNC Routed parts", file = doc_file)
keys = sorted(list(routed.keys()))
for i in range(len(keys)):
r = keys[i]
for i, r in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
if (i % 3) == 2 or i == len(routed) - 1:
n = (i % 3) + 1
@@ -340,8 +348,7 @@ def views(target, do_assemblies = None):
if sub_assemblies:
print("### Sub-assemblies", file = doc_file)
keys = sorted(list(sub_assemblies.keys()))
for i in range(len(keys)):
a = keys[i]
for i, a in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
if (i % 3) == 2 or i == len(keys) - 1:
n = (i % 3) + 1

View File

@@ -26,6 +26,12 @@ module dogbones() {
#translate([15, 0])
dogbone_rectangle([10, 20, 5], center = false);
#translate([30, 0])
dogbone_rectangle_x([10, 20, 5], center = false);
#translate([45, 0])
dogbone_rectangle_y([10, 20, 5], center = false);
sq = 3;
translate([-5 + sq / 2 + eps, -10 + sq / 2 + eps])
%cube([sq, sq, 1], center = true);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 136 KiB

BIN
tests/png/press_fit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 181 KiB

View File

@@ -21,7 +21,6 @@ include <../utils/core/core.scad>
use <../vitamins/rod.scad>
include <../vitamins/sheets.scad>
module polyholes() {
module positions()
for(i = [1 : 10]) {
translate([(i * i + i) / 2 + 3 * i , 8])
@@ -34,17 +33,48 @@ module polyholes() {
children();
}
stl_colour(pp1_colour) linear_extrude(3, center = true)
module polyhole_stl() {
stl("polyhole");
linear_extrude(3, center = true)
difference() {
square([100, 27]);
positions()
poly_circle(r = $r);
}
}
module alt_polyhole_stl() {
holes = [2.5, 2, 1.5];
n = len(holes);
size = [n * 10, 10, 10];
difference() {
translate([-size.x / n / 2, $preview ? 0 : -size.y / 2])
cube($preview ? [size.x, size.y / 2, size.z] : size);
for(i = [0 : n - 1])
translate([i * 10, 0])
if(i % 2)
translate_z(size.z)
poly_cylinder(r = holes[i] / 2, h = 2 * size.z, center = true, twist = i + 1);
else
poly_cylinder(r = holes[i] / 2, h = size.z, center = false, twist = i + 1);
}
}
module polyholes() {
stl_colour(pp1_colour)
polyhole_stl();
positions()
rod(d = 2 * $r, l = 8 * $r + 5);
//
// Alternating polyholes
//
translate([30, -40])
alt_polyhole_stl();
//
// Poly rings
//
ir = 3 / 2;
@@ -74,4 +104,11 @@ module polyholes() {
}
}
if($preview)
polyholes();
else {
polyhole_stl();
translate([50, -20])
alt_polyhole_stl();
}

71
tests/press_fit.scad Normal file
View File

@@ -0,0 +1,71 @@
//
// NopSCADlib Copyright Chris Palmer 2020
// 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/>.
//
include <../printed/press_fit.scad>
module press_fits()
{
thickness = 2;
width = 20;
vthickness = 4;
translate([0, width + 2])
difference() {
cube([width, width, thickness]);
for(x = [0.25, 0.75])
for(y = [0.25, 0.75])
translate([x * width, y * width])
press_fit_socket();
}
union() {
cube([width, width, thickness]);
for(x = [0.25, 0.75])
for(y = [0.25, 0.75])
translate([x * width, y * width, thickness])
press_fit_peg(h = thickness);
}
translate([width + 2, width + 2])
difference() {
cube([width, vthickness, width]);
for(x = [0.25, 0.75])
for(y = [0.25, 0.75])
translate([x, 0, y] * width)
rotate([90, 0, 0])
press_fit_socket();
}
translate([width + 2, 0])
union() {
cube([width, width, thickness]);
for(x = [0.25, 0.75])
for(y = [0.25, 0.75])
translate([x * width, y * width, thickness])
press_fit_peg(h = vthickness, horizontal = true);
}
}
press_fits();

View File

@@ -107,7 +107,7 @@ assembly("box1") {
screw_and_washer(foot_screw(foot), 6);
}
translate_z(height + top_thickness + base_thickness + eps) vflip()
translate_z(height + top_thickness + base_thickness + 2 * eps) vflip()
%render() box1_base_stl();
}

View File

@@ -23,6 +23,7 @@ use <../utils/layout.scad>
use <../vitamins/nut.scad>
sheet = 3;
pos = 1; //[-1 : 0.1 : 1]
module rails()
layout([for(l = rails) carriage_width(rail_carriage(l))], 20)
@@ -33,7 +34,7 @@ module rails()
nut = screw_nut(screw);
washer = screw_washer(screw);
rail_assembly(rail, length, rail_travel(rail, length) / 2, $i<2 ? grey(20) : "green", $i<2 ? grey(20) : "red");
rail_assembly(rail, length, pos * rail_travel(rail, length) / 2, $i<2 ? grey(20) : "green", $i<2 ? grey(20) : "red");
rail_screws(rail, length, sheet + nut_thickness(nut, true) + washer_thickness(washer));

View File

@@ -25,6 +25,12 @@ module rounded_rectangles() {
translate([40, 0])
rounded_rectangle([30, 20, 10], 3);
translate([80, 0])
rounded_rectangle_xz([30, 20, 10], 3);
translate([120, 0])
rounded_rectangle_yz([30, 20, 10], 3);
}
rounded_rectangles();

View File

@@ -0,0 +1,31 @@
//
// 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/>.
//
include <../global_defs.scad>
use <../utils/rounded_right_triangle.scad>
module rounded_right_triangles() {
rounded_right_triangle(10, 20, 5, 0.5);
translate([20, 0])
rounded_right_triangle(10, 20, 5, 0.5, offset = true);
}
rounded_right_triangles();

View File

@@ -18,7 +18,28 @@
//
include <../core.scad>
module screws()
module polysink_stl() {
stl("polysink");
cs_screws = [for(list = screw_lists, screw = list) if(screw_head_type(screw) == hs_cs_cap) screw];
n = len(cs_screws);
size = [n * 20, 20, 10];
difference() {
translate([-size.x / n / 2, $preview ? 0 : -size.y / 2])
cube($preview ? [size.x, size.y / 2, size.z] : size);
for(i = [0 : n - 1])
let(s = cs_screws[i])
translate([i * 20, 0]) {
translate_z(size.z)
screw_polysink(s, 2 * size.z + 1);
screw_polysink(s, 2 * size.z + 1, alt = true);
}
}
}
module screws() {
for(y = [0 : len(screw_lists) -1])
for(x = [0 : len(screw_lists[y]) -1]) {
screw = screw_lists[y][x];
@@ -31,7 +52,12 @@ for(y = [0 : len(screw_lists) -1])
screw(screw, length);
}
}
translate([20, 40, -15])
polysink_stl();
}
if($preview)
let($show_threads = true)
screws();
else
polysink_stl();

View File

@@ -20,12 +20,30 @@ include <../utils/core/core.scad>
use <../utils/layout.scad>
include <../vitamins/sheets.scad>
include <../vitamins/screws.scad>
width = 30;
2d = true;
module sheets()
layout([for(s = sheets) width], 5)
render_sheet(sheets[$i]) sheet(sheets[$i], width, width, 2);
let(sheet = sheets[$i], w = sheet_is_woven(sheet) ? width : undef)
if(2d)
render_2D_sheet(sheet, w = w, d = w)
difference() {
sheet_2D(sheet, width, width, 2);
circle(3);
}
else
render_sheet(sheet, w = w, d = w)
difference() {
sheet(sheet, width, width, 2);
translate_z(sheet_thickness(sheet) / 2)
screw_countersink(M3_cs_cap_screw);
}
if($preview)
sheets();

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,7 +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 extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D
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
if(h)
linear_extrude(h, center = center, convexity = 2) // 3D
children();
@@ -74,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

@@ -22,6 +22,16 @@
//! it gets the linear dimensions right. See <https://hydraraptor.blogspot.com/2011/02/polyholes.html>
//!
//! The module provides `poly_circle()`, `poly_cylinder()` and `poly_ring()` that is useful for making printed washers and pillars.
//!
//! `poly_cylinder()` has a `twist` parameter which can be set to make the polygon rotate each layer.
//! This can be used to mitigate the number of sides being small and make small holes stronger and more round, but is quite slow due to the
//! large increase in the number of facets.
//! When set to 1 the polygons alternate each layer, when set higher the rotation takes `twist + 1` layers to repeat.
//! A small additional rotation is added to make the polygon rotate one more side over the length of the hole to make it appear round when
//! veiwed end on.
//!
//! When `twist` is set the resulting cylinder is extended by `eps` at each end so that the exact length of the hole can be used without
//! leaving a scar on either surface.
//
function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius
function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle
@@ -32,7 +42,24 @@ module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the corre
circle(r = corrected_radius(r,n), $fn = n);
}
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false) {//! Make a cylinder adjusted to print the correct size
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
if(twist) {
slices = ceil(h / layer_height);
twists = min(twist + 1, slices);
sides = sides ? sides : sides(r);
rot = 360 / sides / twists * (twists < slices ? (1 + 1 / slices) : 1);
if(center)
for(side = [0, 1])
mirror([0, 0, side])
poly_cylinder(r = r, h = h / 2, sides = sides, twist = twist);
else
render(convexity = 5)
for(i = [0 : slices - 1])
translate_z(i * layer_height - eps)
rotate(rot * i)
poly_cylinder(r = r, h = layer_height + 2 * eps, sides = sides);
}
else
extrude_if(h, center)
poly_circle(r, sides);

View File

@@ -20,14 +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[2], center = center)
rounded_square([size[0], size[1]], r, xy_center);
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.
{
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.
{
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

@@ -23,24 +23,36 @@
//
include <../utils/core/core.scad>
module dogbone_square(size, r = cnc_bit_r, center = true) //! Square with circles at the corners
module dogbone_square(size, r = cnc_bit_r, center = true, x_offset, y_offset) //! Square with circles at the corners, with optional offsets
{
x_offset = is_undef(x_offset) ? r / sqrt(2) : x_offset;
y_offset = is_undef(y_offset) ? r / sqrt(2) : y_offset;
union() {
square(size, center = center);
if(r > 0) {
origin = center ? [0, 0] : size / 2;
offset = r / sqrt(2);
for(x = [-1, 1], y = [-1, 1])
translate(origin + [x * (size.x / 2 - offset), y * (size.y / 2 - offset)])
translate(origin + [x * (size.x / 2 - x_offset), y * (size.y / 2 - y_offset)])
drill(r, 0);
}
}
}
module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners
module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true, x_offset, y_offset) //! Rectangle with cylinders at the corners
{
extrude_if(h = size.z, center = center)
dogbone_square([size.x, size.y], r, xy_center);
dogbone_square([size.x, size.y], r, xy_center, x_offset, y_offset);
}
module dogbone_rectangle_x(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the x direction
{
dogbone_rectangle(size = size, r = r, center = center, x_offset = 0, y_offset = r);
}
module dogbone_rectangle_y(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the y direction
{
dogbone_rectangle(size = size, r = r, center = center, x_offset = r, y_offset = 0);
}

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) {
@@ -35,7 +35,7 @@ module hanging_hole(z, ir, h = 100, h2 = 100) { //! Hole radius ```ir``` hanging
poly_cylinder(r - eps, h - layer_height);
}
}
assert(z % layer_height == 0, str(z));
assert(z - layer_height * floor(z / layer_height) < eps, str(z));
infill_angle = z % (2 * layer_height) ? -45 : 45;
below = min(z + eps, h2);
big = 1000;

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],
@@ -60,7 +60,7 @@ function rounded_polygon_length(points, tangents) = //! Calculate the length giv
v1 = p1 - c,
v2 = p2 - c,
r = abs(corner.z),
a = acos((v1 * v2) / sqr(r))) PI * (cross(v1,v2) <= 0 ? a : 360 - a) * r / 180]
a = acos((v1 * v2) / sqr(r))) r ? PI * (cross(v1, v2) <= 0 ? a : 360 - a) * r / 180 : 0]
)
sumv(concat(straights, arcs));

Some files were not shown because too many files have changed in this diff Show More