Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
055b4e7102 | ||
|
00d6efc315 | ||
|
985b6c08d2 | ||
|
1f55097bdd | ||
|
136584d086 | ||
|
225ea9b451 | ||
|
d341ce499e | ||
|
e7376e28c4 | ||
|
e238eaa473 | ||
|
28d8cba98c | ||
|
04e94a859a | ||
|
e696dc4718 | ||
|
30955eb350 |
30
CHANGELOG.md
@@ -3,6 +3,36 @@
|
||||
This changelog is generated by `changelog.py` using manually added semantic version tags to classify commits as breaking changes, additions or fixes.
|
||||
|
||||
|
||||
### [v19.7.0](https://github.com/nophead/NopSCADlib/releases/tag/v19.7.0 "show release") Additions [...](https://github.com/nophead/NopSCADlib/compare/v19.6.0...v19.7.0 "diff with v19.6.0")
|
||||
* 2022-02-08 [`1f55097`](https://github.com/nophead/NopSCADlib/commit/1f55097bdd3e4d0164a48dd7ebb3fc5370250ac4 "show commit") [C.P.](# "Chris Palmer") Support for twisted cables.
|
||||
Sweep now distbutes twists in proportion to segments lengths.
|
||||
Added `spiral_paths(),` `segmented_path()` and `rounded_path_vertices()` functions.
|
||||
Added `show_path(path)` module.
|
||||
|
||||
### [v19.6.0](https://github.com/nophead/NopSCADlib/releases/tag/v19.6.0 "show release") Additions [...](https://github.com/nophead/NopSCADlib/compare/v19.5.1...v19.6.0 "diff with v19.5.1")
|
||||
* 2022-02-06 [`225ea9b`](https://github.com/nophead/NopSCADlib/commit/225ea9b45160195bdf316e7ffdb383a63f898d3c "show commit") [C.P.](# "Chris Palmer") Added `rounded_path()` function to `sweep.scad`.
|
||||
|
||||
#### [v19.5.1](https://github.com/nophead/NopSCADlib/releases/tag/v19.5.1 "show release") Fixes [...](https://github.com/nophead/NopSCADlib/compare/v19.5.0...v19.5.1 "diff with v19.5.0")
|
||||
* 2022-02-06 [`d341ce4`](https://github.com/nophead/NopSCADlib/commit/d341ce499e56972ff5267d3187387fe7df9d4130 "show commit") [C.P.](# "Chris Palmer") Added `render()` to `pocket_handle()`.
|
||||
|
||||
* 2022-02-06 [`e7376e2`](https://github.com/nophead/NopSCADlib/commit/e7376e28c44355efa425b98aa0511ccdf0b63301 "show commit") [C.P.](# "Chris Palmer") Fixed corner block assembly names when overridden.
|
||||
|
||||
* 2022-02-06 [`e238eaa`](https://github.com/nophead/NopSCADlib/commit/e238eaa473bac72136507d15c57f6156560d6cfe "show commit") [C.P.](# "Chris Palmer") Removed unused, undocumented function.
|
||||
|
||||
### [v19.5.0](https://github.com/nophead/NopSCADlib/releases/tag/v19.5.0 "show release") Additions [...](https://github.com/nophead/NopSCADlib/compare/v19.4.1...v19.5.0 "diff with v19.4.1")
|
||||
* 2022-02-01 [`04e94a8`](https://github.com/nophead/NopSCADlib/commit/04e94a859aa0d21f840c992b487a901f096790a4 "show commit") [C.P.](# "Chris Palmer") Added `earth_rot` parameter to `NEMA_screws()`.
|
||||
|
||||
#### [v19.4.1](https://github.com/nophead/NopSCADlib/releases/tag/v19.4.1 "show release") Fixes [...](https://github.com/nophead/NopSCADlib/compare/v19.4.0...v19.4.1 "diff with v19.4.0")
|
||||
* 2022-02-01 [`e696dc4`](https://github.com/nophead/NopSCADlib/commit/e696dc471845550eb94e1b648d8b109cc11a9bf1 "show commit") [C.P.](# "Chris Palmer") Fixed stupid bug in `euler()`.
|
||||
|
||||
### [v19.4.0](https://github.com/nophead/NopSCADlib/releases/tag/v19.4.0 "show release") Additions [...](https://github.com/nophead/NopSCADlib/compare/v19.3.0...v19.4.0 "diff with v19.3.0")
|
||||
* 2022-01-29 [`f33a067`](https://github.com/nophead/NopSCADlib/commit/f33a0675f5b9f6a5ebe1c4b9755e894d1e2b7994 "show commit") [C.P.](# "Chris Palmer") Updated images and readme.
|
||||
|
||||
* 2022-01-29 [`5223415`](https://github.com/nophead/NopSCADlib/commit/52234154294011d4cc312f9ff98716f484d20a41 "show commit") [C.P.](# "Chris Palmer") Ball bearing test now two rows.
|
||||
|
||||
* 2022-01-28 [`f87f3f5`](https://github.com/nophead/NopSCADlib/commit/f87f3f51ee778ef7ca30319d1d6ff3f4013e8258 "show commit") [M.B.](# "Martin Budden") Added support for flanged bearings.
|
||||
Also added some new cartridge bearings.
|
||||
|
||||
### [v19.3.0](https://github.com/nophead/NopSCADlib/releases/tag/v19.3.0 "show release") Additions [...](https://github.com/nophead/NopSCADlib/compare/v19.2.0...v19.3.0 "diff with v19.2.0")
|
||||
* 2022-01-29 [`1ee80f4`](https://github.com/nophead/NopSCADlib/commit/1ee80f4a908ff9939d06186f3b22f54f726fc4d2 "show commit") [C.P.](# "Chris Palmer") Ribbon clamps can now be made to hold multiple ribbons.
|
||||
|
||||
|
@@ -86,7 +86,6 @@ function box_screw_length(type, top) =
|
||||
let(s = top ? box_top_sheet(type) : box_base_sheet(type))
|
||||
screw_length(box_screw(type), sheet_thickness(s) + box_corner_gap(type) + box_profile_overlap(type) - 1, washers = 2, insert = true, longer = true);
|
||||
|
||||
function box_wall_clearance(type) = box_sheet_slot(type) / 2 - sheet_thickness(box_sheets(type)) / 2;
|
||||
function box_margin(type) = box_profile_overlap(type) + box_corner_gap(type); //! How much the bezel intrudes on the specified height
|
||||
function box_intrusion(type) = box_hole_inset(type) + box_boss_r(type); //! Corner profile intrusion
|
||||
function sheet_reduction(type) = 2 * box_corner_gap(type) + sheet_end_clearance;
|
||||
|
@@ -121,7 +121,7 @@ module corner_block(screw = def_screw, name = false) { //! Generate the STL for
|
||||
}
|
||||
|
||||
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
|
||||
assembly(str("corner_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
assembly(name ? name : str("corner_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
insert = screw_insert(screw);
|
||||
|
||||
stl_colour(name ? pp2_colour : pp1_colour)
|
||||
@@ -256,7 +256,7 @@ module 2screw_block(screw = def_screw, name = false) { //! Generate the STL for
|
||||
}
|
||||
|
||||
module 2screw_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
|
||||
assembly(str("2screw_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
assembly(name ? name : str("2screw_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
insert = screw_insert(screw);
|
||||
|
||||
stl_colour(name ? pp2_colour : pp1_colour)
|
||||
|
@@ -137,7 +137,7 @@ module pocket_handle_assembly(type) { //! Assembly with fasteners in place
|
||||
|
||||
translate_z(f.z + t / 2) hflip() {
|
||||
stl_colour(pp1_colour)
|
||||
pocket_handle(type);
|
||||
render() pocket_handle(type);
|
||||
|
||||
pocket_handle_hole_positions(type) {
|
||||
translate_z(f.z + t)
|
||||
|
33
readme.md
@@ -108,7 +108,7 @@ Axial components for PCBs.
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `ax_res(type, value, tol = 5, pitch = 0)` | Through hole axial resistor. If `pitch` is zero the minimum is used. If below the minimum the resistor is placed vertical. |
|
||||
| `wire_link(d, l, h = 1, tail = 3)` | Draw a wire jumper link. |
|
||||
| `wire_link(d, l, h = 1, tail = 3)` | Draw a wire jumper link. If `l` is zero then a vertical wire is drawn. |
|
||||
|
||||

|
||||
|
||||
@@ -123,6 +123,7 @@ Axial components for PCBs.
|
||||
| 1 | `ax_res(res1_2, 8200)` | Resistor 8200 Ohms 5% 0.5W |
|
||||
| 1 | `ax_res(res1_2, 8250, tol = 1)` | Resistor 8250 Ohms 1% 0.5W |
|
||||
| 1 | `wire_link(0.8, 10.16)` | Wire link 0.8mm x 0.4" |
|
||||
| 1 | `wire_link(0.8, 0, h = 5)` | Wire link 0.8mm x 8mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -2441,6 +2442,8 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
|
||||
| 1 | `smd_resistor(RES0603, 1K)` | SMD resistor 0603 1K 0.1W |
|
||||
| 1 | `smd_resistor(RES0805, 1K)` | SMD resistor 0805 1K 0.125W |
|
||||
| 1 | `smd_resistor(RES1206, 1K)` | SMD resistor 1206 1K 0.25W |
|
||||
| 1 | `smd_sot(SOT223)` | SOT223 package LM117 |
|
||||
| 1 | `smd_sot(SOT23)` | SOT23 package 2N7000 |
|
||||
| 1 | `square_button(button_4p5mm)` | Square button 4.5mm |
|
||||
| 1 | `square_button(button_6mm)` | Square button 6mm |
|
||||
| 1 | `pcb(TMC2130)` | TMC2130 |
|
||||
@@ -2457,6 +2460,7 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
|
||||
| 2 | `vero_pin()` | Vero board pin |
|
||||
| 1 | `wire_link(0.8, 5.08, h = 10.16)` | Wire link 0.8mm x 0.2" |
|
||||
| 1 | `wire_link(0.8, 10.16)` | Wire link 0.8mm x 0.4" |
|
||||
| 1 | `wire_link(0.8, 0, h = 5)` | Wire link 0.8mm x 8mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -3634,6 +3638,13 @@ Surface mount components for PCBs.
|
||||
| `smd_res_end_cap(type)` | End cap width |
|
||||
| `smd_res_power(type)` | Power rating in Watts |
|
||||
| `smd_res_size(type)` | Body length, width and height |
|
||||
| `smd_sot_lead_pitch(type)` | Lead pitch |
|
||||
| `smd_sot_lead_size(type)` | Lead width, foot depth, lead thickness |
|
||||
| `smd_sot_lead_span(type)` | Total span of leads |
|
||||
| `smd_sot_lead_z(type)` | Top of lead frame from top |
|
||||
| `smd_sot_size(type)` | Body length, width and height |
|
||||
| `smd_sot_tab_width(type)` | The wide lead at the top |
|
||||
| `smd_sot_z(type)` | Height above PCB surface |
|
||||
|
||||
### Functions
|
||||
| Function | Description |
|
||||
@@ -3645,9 +3656,10 @@ Surface mount components for PCBs.
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `smd_capacitor(type, height)` | Draw an SMD capacitor with specified height |
|
||||
| `smd_capacitor(type, height, value = undef)` | Draw an SMD capacitor with specified height |
|
||||
| `smd_led(type, colour, cutout)` | Draw an SMD LED with specified `colour` |
|
||||
| `smd_resistor(type, value)` | Draw an SMD resistor with specified value |
|
||||
| `smd_sot(type, value)` | Draw an SMD transistor |
|
||||
|
||||

|
||||
|
||||
@@ -3662,6 +3674,8 @@ Surface mount components for PCBs.
|
||||
| 1 | `smd_resistor(RES0603, 1R0)` | SMD resistor 0603 1R0 0.1W |
|
||||
| 1 | `smd_resistor(RES0805, 10M)` | SMD resistor 0805 10M 0.125W |
|
||||
| 1 | `smd_resistor(RES1206, 100K)` | SMD resistor 1206 100K 0.25W |
|
||||
| 1 | `smd_sot(SOT223)` | SOT223 package FZT851 |
|
||||
| 1 | `smd_sot(SOT23)` | SOT23 package 2N7000 |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -3876,7 +3890,7 @@ NEMA stepper motor model.
|
||||
| `NEMA(type, shaft_angle = 0, jst_connector = false)` | Draw specified NEMA stepper motor |
|
||||
| `NEMA_outline(type)` | 2D outline |
|
||||
| `NEMA_screw_positions(type, n = 4)` | Positions children at the screw holes |
|
||||
| `NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef)` | Place screws and optional earth tag |
|
||||
| `NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef, earth_rot = undef)` | Place screws and optional earth tag |
|
||||
|
||||

|
||||
|
||||
@@ -4227,6 +4241,7 @@ Veroboard with mounting holes, track breaks, removed tracks, solder points and c
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `vero(name, assembly, holes, strips, pitch = inch(0.1)` | Constructor |
|
||||
| `vero_length(type)` | Length of the board |
|
||||
| `vero_size(type)` | Board size |
|
||||
| `vero_thickness(type)` | Thickness of the substrate |
|
||||
@@ -4237,6 +4252,7 @@ Veroboard with mounting holes, track breaks, removed tracks, solder points and c
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `solder_meniscus(type, ir = 0.3, r = undef)` | Draw a solder meniscus |
|
||||
| `vero_cutouts(type, angle = undef)` | Make cutouts to clear components |
|
||||
| `vero_grid_pos(type, x, y)` | Convert grid position to offset from the centre |
|
||||
| `vero_mounting_hole_positions(type)` | Positions children at the mounting holes |
|
||||
@@ -6565,6 +6581,12 @@ Subsequent rotations use the minimum rotation method.
|
||||
The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up.
|
||||
An additional twist around the path can be specified. If the path is closed this should be a multiple of 360.
|
||||
|
||||
`rounded_path()` can be used to generate a path of lines connected by arcs, useful for wire runs, etc.
|
||||
The vertices specify where the the path would be without any rounding.
|
||||
Each vertex, apart from the first and the last, has an associated radius and the path shortcuts the vertex with an arc specified by the radius.
|
||||
|
||||
`spiral_paths()` makes a list of new paths that spiral around a given path. It can be used to make twisted wires that follow a rounded_path, for example.
|
||||
|
||||
[utils/sweep.scad](utils/sweep.scad) Implementation.
|
||||
|
||||
[tests/sweep.scad](tests/sweep.scad) Code for this example.
|
||||
@@ -6580,12 +6602,17 @@ An additional twist around the path can be specified. If the path is closed this
|
||||
| `helical_twist_per_segment(r, pitch, sides)` | Calculate the twist around Z that rotate_from_to() introduces |
|
||||
| `path_length(path, i = 0, length = 0)` | Calculated the length along a path |
|
||||
| `rectangle_points(w, h)` | Generate the points of a rectangle |
|
||||
| `rounded_path(path)` | Convert a rounded_path, consisting of a start coordinate, vertex / radius pairs and then an end coordinate, to a path of points for sweep. |
|
||||
| `rounded_path_vertices(path)` | Show the unrounded version of a rounded_path for debug |
|
||||
| `segmented_path(path, min_segment)` | Add points to a path to enforce a minimum segment length |
|
||||
| `skin_faces(points, npoints, facets, loop, offset = 0)` | Create the mesh for the swept volume without end caps |
|
||||
| `spiral_paths(path, n, r, twists, start_angle)` | Create a new paths which sprial around the given path. Use for making twisted cables |
|
||||
| `sweep(path, profile, loop = false, twist = 0)` | Generate the point list and face list of the swept volume |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `show_path(path)` | Show a path using a chain of hulls for debugging, duplicate points are highlighted. |
|
||||
| `sweep(path, profile, loop = false, twist = 0, convexity = 1)` | Draw a polyhedron that is the swept volume |
|
||||
|
||||

|
||||
|
@@ -59,7 +59,7 @@ test_pcb = ["test_pcb", "Test PCB",
|
||||
[ [3, 3], [3, -3], [-3, 3], [-3, -3] ],
|
||||
// components
|
||||
[
|
||||
[ 20, -5, 180, "trimpot10"],
|
||||
[ 20, -5, 180, "trimpot10"],
|
||||
[ 20, -15, 90, "trimpot10", true],
|
||||
[ 10, 2, 90, "smd_led", LED0805, "red"],
|
||||
[ 13, 2, 90, "smd_led", LED0603, "orange"],
|
||||
@@ -69,6 +69,8 @@ test_pcb = ["test_pcb", "Test PCB",
|
||||
[ 25, 2, 90, "smd_cap", CAP1206, 1.5],
|
||||
[ 28, 2, 90, "smd_cap", CAP0805, 1.0],
|
||||
[ 31, 2, 90, "smd_cap", CAP0603, 0.7],
|
||||
[ 16, 6, -90, "smd_sot", SOT23, "2N7000"],
|
||||
[ 28, 20, -90, "smd_sot", SOT223, "LM117"],
|
||||
|
||||
[ 10, 10, 0, "2p54header", 4, 1],
|
||||
[ 25, 10, 0, "2p54header", 5, 1, false, "blue" ],
|
||||
@@ -99,6 +101,7 @@ test_pcb = ["test_pcb", "Test PCB",
|
||||
[ 65, 22, 0, "ax_res", res1_2, 100000],
|
||||
[ 55, 22, 0, "vero_pin"],
|
||||
[ 55, 17, 0, "vero_pin", true],
|
||||
[ 55, 9, 0, "link", 0, 5],
|
||||
|
||||
[ 80, 9, 0, "link", inch(0.2), inch(0.4)],
|
||||
[ 80, 12, 0, "ax_res", res1_8, 1000000, 1, inch(0.1)],
|
||||
|
@@ -33,6 +33,11 @@ module smds() {
|
||||
layout([for(c = smd_capacitors) smd_cap_size(c).x], 1)
|
||||
let(c = smd_capacitors[$i])
|
||||
smd_capacitor(c, smd_cap_size(c).y * 0.8);
|
||||
|
||||
translate([0, 12])
|
||||
layout([for(s = smd_sots) smd_sot_size(s).x], 1)
|
||||
let(s = smd_sots[$i])
|
||||
smd_sot(s, ["2N7000", "FZT851"][$i]);
|
||||
}
|
||||
|
||||
if($preview)
|
||||
|
@@ -28,6 +28,9 @@ module axials() {
|
||||
rotate(90)
|
||||
wire_link(0.8, inch(0.4));
|
||||
|
||||
pcb_grid(pcb, 0, 7)
|
||||
wire_link(0.8, 0, 5);
|
||||
|
||||
for(i = [0 : len(ax_resistors) - 1]) {
|
||||
pcb_grid(pcb, 2 * i + 2, 1 + [0, 0.5, 1.5][i])
|
||||
rotate(90)
|
||||
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 276 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 189 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 150 KiB |
@@ -32,22 +32,33 @@ loop_y = transform_points(loop, rotate([0, -90, $t * 360]));
|
||||
|
||||
loop_z = transform_points(loop, rotate([$t * 360, 0, 0]));
|
||||
|
||||
sweep(loop_z, L_points, loop = true);
|
||||
color("yellow") {
|
||||
sweep(loop_z, L_points, loop = true);
|
||||
|
||||
sweep(loop_x, L_points, loop = true);
|
||||
|
||||
sweep(loop_y, L_points, loop = true);
|
||||
sweep(loop_x, L_points, loop = true);
|
||||
|
||||
sweep(loop_y, L_points, loop = true);
|
||||
}
|
||||
|
||||
knot = [ for(i=[0:.2:359])
|
||||
[ (19*cos(3*i) + 40)*cos(2*i),
|
||||
(19*cos(3*i) + 40)*sin(2*i),
|
||||
19*sin(3*i) ] ];
|
||||
|
||||
sweep(knot, L_points, loop = true);
|
||||
color("red") sweep(knot, L_points, loop = true);
|
||||
|
||||
p = transform_points([[0,0,0], [20,0,5], [10,30,4], [0,0,0], [0,0,20]], scale(10));
|
||||
n = 100;
|
||||
path = bezier_path(p, n);
|
||||
|
||||
rotate(45) sweep(path, circle_points(5, $fn = 64));
|
||||
color("blue") rotate(45) sweep(path, circle_points(5, $fn = 64));
|
||||
|
||||
vertices = [[-170, 0, 0], [-170, 170, 0], 10, [-170, 170, 30], 20, [-50, 170, 31], 10, [-130, 100, 40]];
|
||||
rounded_path = rounded_path(vertices);
|
||||
|
||||
show_path(rounded_path_vertices(vertices));
|
||||
|
||||
paths = spiral_paths(rounded_path, 2, 1.5, 15, 0);
|
||||
for(i = [0 : len(paths) - 1])
|
||||
color(["red", "green"][i])
|
||||
sweep(paths[i], circle_points(1.5, $fn = 64));
|
||||
|
@@ -103,11 +103,11 @@ function reverse(v) = let(n = len(v) - 1) n < 0 ? [] : [for(i = [0 : n]) v[n - i
|
||||
|
||||
function angle_between(v1, v2) = acos(v1 * v2 / (norm(v1) * norm(v2))); //! Return the angle between two vectors
|
||||
|
||||
// https://www.gregslabaugh.net/publications/euler.pdf
|
||||
// http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
|
||||
function euler(R) = let(ay = asin(-R[2][0]), cy = cos(ay)) //! Convert a rotation matrix to a Euler rotation vector.
|
||||
cy ? [ atan2(R[2][1] / cy, R[2][2] / cy), ay, atan2(R[1][0] / cy, R[0][0] / cy) ]
|
||||
: R[2][0] < 0 ? [atan2( R[0][1], R[0][2]), 180, 0]
|
||||
: [atan2(-R[0][1], -R[0][2]), -180, 0];
|
||||
: R[2][0] < 0 ? [atan2( R[0][1], R[0][2]), 90, 0]
|
||||
: [atan2(-R[0][1], -R[0][2]), -90, 0];
|
||||
|
||||
module position_children(list, t) //! Position children if they are on the Z = 0 plane when transformed by t
|
||||
for(p = list)
|
||||
|
@@ -25,6 +25,12 @@
|
||||
//!
|
||||
//! The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up.
|
||||
//! An additional twist around the path can be specified. If the path is closed this should be a multiple of 360.
|
||||
//!
|
||||
//! `rounded_path()` can be used to generate a path of lines connected by arcs, useful for wire runs, etc.
|
||||
//! The vertices specify where the the path would be without any rounding.
|
||||
//! Each vertex, apart from the first and the last, has an associated radius and the path shortcuts the vertex with an arc specified by the radius.
|
||||
//!
|
||||
//! `spiral_paths()` makes a list of new paths that spiral around a given path. It can be used to make twisted wires that follow a rounded_path, for example.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
|
||||
@@ -103,18 +109,19 @@ function helical_twist_per_segment(r, pitch, sides) = //! Calculate the twist ar
|
||||
) step_angle * sin(slope); // angle tangent should rotate around z projected onto axis rotate_from_to() uses
|
||||
|
||||
//
|
||||
// Generate all the surface points of the swept volume.
|
||||
// Generate all the transforms for the profile of the swept volume.
|
||||
//
|
||||
function skin_points(profile, path, loop, twist = 0) =
|
||||
function sweep_transforms(path, loop = false, twist = 0) =
|
||||
let(len = len(path),
|
||||
last = len - 1,
|
||||
|
||||
profile4 = [for(p = profile) [p.x, p.y, p.z, 1]],
|
||||
|
||||
tangents = [tangent(path, loop ? last : 0, 0, 1),
|
||||
for(i = [1 : last - 1]) tangent(path, i - 1, i, i + 1),
|
||||
tangent(path, last - 1, last, loop ? 0 : last)],
|
||||
|
||||
lengths = [for(i = 0, t = 0; i < len; t = t + norm(path[min(i + 1, last)] - path[i]), i = i + 1) t],
|
||||
length = lengths[last],
|
||||
|
||||
rotations = [for(i = 0, rot = fs_frame(tangents);
|
||||
i < len;
|
||||
i = i + 1,
|
||||
@@ -124,8 +131,20 @@ function skin_points(profile, path, loop, twist = 0) =
|
||||
rotation = missmatch + twist
|
||||
)
|
||||
[for(i = [0 : last])
|
||||
let(za = rotation * i / last)
|
||||
each profile4 * orientate(path[i], rotations[i] * rot3_z(za))
|
||||
let(za = rotation * lengths[i] / length)
|
||||
orientate(path[i], rotations[i] * rot3_z(za))
|
||||
];
|
||||
|
||||
//
|
||||
// Generate all the surface points of the swept volume.
|
||||
//
|
||||
function skin_points(profile, path, loop, twist = 0) =
|
||||
let(profile4 = [for(p = profile) [p.x, p.y, p.z, 1]],
|
||||
|
||||
transforms = sweep_transforms(path, loop, twist)
|
||||
)
|
||||
[for(t = transforms)
|
||||
each profile4 * t
|
||||
];
|
||||
|
||||
function cap(facets, segment = 0, end) = //! Create the mesh for an end cap
|
||||
@@ -179,3 +198,65 @@ function before(path1, path2) = //! Translate `path1` so its end meets the star
|
||||
function after(path1, path2) = //! Translate `path2` so its start meets the end of `path1` and then concatenate
|
||||
let(end1 = len(path1) - 1, end2 = len(path2) - 1, offset = path1[end1] - path2[0])
|
||||
concat(path1, [for(i = [1 : end2]) path2[i] + offset]);
|
||||
|
||||
function rounded_path(path) = //! Convert a rounded_path, consisting of a start coordinate, vertex / radius pairs and then an end coordinate, to a path of points for sweep.
|
||||
let(len = len(path)) assert(len > 3 && len % 2 == 0) [
|
||||
path[0], // First point has no radius
|
||||
for(i = [1 : 2 : len - 3]) let( // Step through the vertices with radii, i.e. not the first or last
|
||||
prev = max(i - 2, 0), // Index of previous point, might be the first point, which is a special case
|
||||
p0 = path[prev], // Point before the vertex
|
||||
p1 = path[i], // Vertex
|
||||
r = path[i + 1], // Radius of shortcut curve
|
||||
p2 = path[i + 2], // Point after the vertex
|
||||
v1 = assert(Len(p0) == 3, str("expected path[", prev, "] to be a vertex coordinate, got ", p0))
|
||||
assert(Len(p1) == 3, str("expected path[", i, "] to be a vertex coordinate, got ", p1))
|
||||
assert(Len(p2) == 3, str("expected path[", i + 2, "] to be a vertex coordinate, got ", p2))
|
||||
assert(is_num(r), str("expected path[", i + 1, "] to be a radius, got ", r))
|
||||
p0 - p1, // Calculate vectors between vertices
|
||||
v2 = p2 - p1,
|
||||
a = angle_between(v1, -v2), // Angle turned through
|
||||
arc_start = p1 + unit(v1) * r * tan(a / 2), // Calc the start position
|
||||
z_axis = unit(cross(v1, v2)), // z_axis is perpendicular to both vectors
|
||||
centre = arc_start + unit(cross(z_axis, v1)) * r, // Arc center is a radius away, and perpendicular to v1 and the z_axis.
|
||||
x_axis = arc_start - centre, // Make the x_axis along the radius to the start point, includes radius a scale factor
|
||||
y_axis = cross(x_axis, z_axis), // y_axis perpendicular to the other two
|
||||
sides = r2sides(ceil(r2sides(r) * a / 360)) // Sides needed to make the arc
|
||||
)
|
||||
for(j = [0 : sides], t = a * j / sides) // For each vertex in the arc
|
||||
cos(t) * x_axis + sin(t) * y_axis + centre, // Circular arc in the tiled xy plane.
|
||||
path[len - 1], // Last point has no radius
|
||||
];
|
||||
|
||||
function segmented_path(path, min_segment) = [ //! Add points to a path to enforce a minimum segment length
|
||||
for(i = [0 : len(path) - 2])
|
||||
let(delta =
|
||||
assert(path[i] != path[i + 1], str("Coincident points at path[", i, "] = ", path[i]))
|
||||
path[i+1] - path[i],
|
||||
segs = ceil(norm(delta) / min_segment)
|
||||
)
|
||||
for(j = [0 : segs - 1])
|
||||
path[i] + delta * j / segs, // Linear interpolation
|
||||
path[len(path) - 1]
|
||||
];
|
||||
|
||||
function spiral_paths(path, n, r, twists, start_angle) = let( //! Create a new paths which sprial around the given path. Use for making twisted cables
|
||||
segment = path_length(path) / twists / r2sides(2 * r),
|
||||
transforms = sweep_transforms(segmented_path(path, segment), twist = 360 * twists),
|
||||
initial = [r, 0, 0, 1] * rotate(start_angle)
|
||||
) [for(i = [0 : n - 1]) let(initial = [r, 0, 0, 1] * rotate(start_angle + i * 360 / n)) [for(t = transforms) initial * t]];
|
||||
|
||||
function rounded_path_vertices(path) = [path[0], for(i = [1 : 2 : len(path) - 1]) path[i]]; //! Show the unrounded version of a rounded_path for debug
|
||||
|
||||
module show_path(path) //! Show a path using a chain of hulls for debugging, duplicate points are highlighted.
|
||||
for(i = [0 : len(path) - 2]) {
|
||||
hull($fn = 16) {
|
||||
translate(path[i])
|
||||
sphere(0.1);
|
||||
|
||||
translate(path[i + 1])
|
||||
sphere(0.1);
|
||||
}
|
||||
if(path[i] == path[i + 1])
|
||||
translate(path[i])
|
||||
color("red") sphere(1);
|
||||
}
|
||||
|
@@ -23,27 +23,31 @@
|
||||
include <../utils/core/core.scad>
|
||||
include <../utils/round.scad>
|
||||
|
||||
module wire_link(d, l, h = 1, tail = 3) { //! Draw a wire jumper link.
|
||||
vitamin(str("wire_link(", d, ", ", l, arg(h, 1, "h"), arg(tail, 3, "tail"), "): Wire link ", d, "mm x ", l / inch(1), "\""));
|
||||
module wire_link(d, l, h = 1, tail = 3) { //! Draw a wire jumper link. If `l` is zero then a vertical wire is drawn.
|
||||
vitamin(str("wire_link(", d, ", ", l, arg(h, 1, "h"), arg(tail, 3, "tail"), "): Wire link ", d, "mm x ", l ? str(l / inch(1), "\"") : str(h + tail,"mm")));
|
||||
r = d;
|
||||
$fn = 32;
|
||||
|
||||
color("silver") {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * l / 2, 0, -tail])
|
||||
cylinder(d = d, h = tail + h - r);
|
||||
color("silver")
|
||||
if(l) {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * l / 2, 0, -tail])
|
||||
cylinder(d = d, h = tail + h - r);
|
||||
|
||||
translate([side * (l / 2 - r), 0, h - r])
|
||||
rotate([90, 0, side * 90 - 90])
|
||||
rotate_extrude(angle = 90)
|
||||
translate([r, 0])
|
||||
circle(d = d);
|
||||
translate([side * (l / 2 - r), 0, h - r])
|
||||
rotate([90, 0, side * 90 - 90])
|
||||
rotate_extrude(angle = 90)
|
||||
translate([r, 0])
|
||||
circle(d = d);
|
||||
}
|
||||
|
||||
translate_z(h)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = d, h = l - 2 * r, center = true);
|
||||
}
|
||||
|
||||
translate_z(h)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = d, h = l - 2 * r, center = true);
|
||||
}
|
||||
else
|
||||
translate_z(-tail)
|
||||
cylinder(d = d, h = tail + h);
|
||||
}
|
||||
|
||||
function ax_res_wattage(type) = type[1]; //! Power rating
|
||||
|
@@ -1032,7 +1032,7 @@ module block(size, colour, makes_cutout, cutouts) //! Draw a coloured cube to re
|
||||
|
||||
module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb component from description
|
||||
function show(comp, part) = (comp[3] == part || comp[3] == str("-",part)) && (!cutouts || angle == undef || angle == comp.z);
|
||||
function param(n, default = 0) = len(comp) > n ? comp[n] : default;
|
||||
function param(n, default = 0) = len(comp) > n && !is_undef(comp[n]) ? comp[n] : default;
|
||||
rotate(comp.z) {
|
||||
// Components that have a cutout parameter go in this section
|
||||
if(show(comp, "2p54header")) let($show_plugs = show_plugs && param(9, true))
|
||||
@@ -1087,7 +1087,8 @@ module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb compon
|
||||
if(show(comp, "potentiometer")) let(pot = param(4, BTT_encoder)) translate_z(pot_size(pot).z) vflip() potentiometer(pot, shaft_length = param(5, undef));
|
||||
if(show(comp, "buzzer")) buzzer(param(4, 9), param(5, 12), param(6, grey(20)));
|
||||
if(show(comp, "smd_res")) smd_resistor(comp[4], comp[5]);
|
||||
if(show(comp, "smd_cap")) smd_capacitor(comp[4], comp[5]);
|
||||
if(show(comp, "smd_cap")) smd_capacitor(comp[4], comp[5], param(6, undef));
|
||||
if(show(comp, "smd_sot")) smd_sot(comp[4], comp[5]);
|
||||
if(show(comp, "vero_pin")) vero_pin(param(4, false));
|
||||
if(show(comp, "terminal")) terminal_block(comp[5], comp[4]);
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
include <../utils/core/core.scad>
|
||||
|
||||
use <../utils/tube.scad>
|
||||
use <../utils/sweep.scad>
|
||||
|
||||
function smd_led_size(type) = type[1]; //! Body length, width and height
|
||||
function smd_led_lens(type) = type[2]; //! Lens length width and height
|
||||
@@ -104,7 +105,7 @@ module smd_resistor(type, value) { //! Draw an SMD resistor with specified value
|
||||
cube([cap, size.y - 2 * eps, size.z], center = true);
|
||||
|
||||
color("white")
|
||||
translate([0, 0, size.z])
|
||||
translate_z(size.z)
|
||||
linear_extrude(eps)
|
||||
resize([(size.x - 2 * cap) * 0.75, size.y / 2])
|
||||
text(value, halign = "center", valign = "center");
|
||||
@@ -113,9 +114,9 @@ module smd_resistor(type, value) { //! Draw an SMD resistor with specified value
|
||||
function smd_cap_size(type) = type[1]; //! Body length, width
|
||||
function smd_cap_end_cap(type) = type[2]; //! End cap width
|
||||
|
||||
module smd_capacitor(type, height) { //! Draw an SMD capacitor with specified height
|
||||
module smd_capacitor(type, height, value = undef) { //! Draw an SMD capacitor with specified height
|
||||
size = smd_cap_size(type);
|
||||
vitamin(str("smd_capacitor(", type[0], "): SMD capacitor ", smd_size(size)));
|
||||
vitamin(str("smd_capacitor(", type[0], "): SMD capacitor ", smd_size(size), !is_undef(value) ? str(" ", value) : ""));
|
||||
|
||||
cap = smd_cap_end_cap(type);
|
||||
|
||||
@@ -129,3 +130,51 @@ module smd_capacitor(type, height) { //! Draw an SMD capacitor with specified he
|
||||
translate([end * (size.x / 2 - cap / 2), 0, height / 2])
|
||||
cube([cap, size.y - 2 * eps, height], center = true);
|
||||
}
|
||||
|
||||
function smd_sot_size(type) = type[1]; //! Body length, width and height
|
||||
function smd_sot_z(type) = type[2]; //! Height above PCB surface
|
||||
function smd_sot_lead_z(type) = type[3]; //! Top of lead frame from top
|
||||
function smd_sot_lead_pitch(type) = type[4]; //! Lead pitch
|
||||
function smd_sot_lead_span(type) = type[5]; //! Total span of leads
|
||||
function smd_sot_lead_size(type) = type[6]; //! Lead width, foot depth, lead thickness
|
||||
function smd_sot_tab_width(type) = type[7]; //! The wide lead at the top
|
||||
|
||||
module smd_sot(type, value) { //! Draw an SMD transistor
|
||||
vitamin(str("smd_sot(", type[0], "): ", type[0], " package ", value));
|
||||
|
||||
size = smd_sot_size(type);
|
||||
z0 = smd_sot_z(type);
|
||||
z2 = z0 + size.z;
|
||||
z1 = z2 - smd_sot_lead_z(type);
|
||||
slant = 7; //! 7 degree body draft angle
|
||||
pitch = smd_sot_lead_pitch(type);
|
||||
span = smd_sot_lead_span(type);
|
||||
leads = floor(size.x / pitch) + 1;
|
||||
ls = smd_sot_lead_size(type);
|
||||
|
||||
r = ls.z;
|
||||
gullwing = rounded_path([[0, 0, ls.z / 2], [0, ls.y - ls.z, ls.z / 2], r, [0, ls.y -ls.z + z1 - ls.z, z1 - ls.z / 2], r, [0, span / 2, z1 - ls.z / 2]]);
|
||||
|
||||
color(grey(20))
|
||||
hull()
|
||||
for(z = [z0, z1, z2], inset = abs(z - z1) * tan(slant))
|
||||
translate_z(z)
|
||||
cube([size.x - 2 * inset, size.y - 2 * inset, eps], center = true);
|
||||
|
||||
color(silver) {
|
||||
for(i = [0 : leads - 1])
|
||||
translate([i * pitch - size.x / 2 + (size.x - (leads - 1) * pitch) / 2, -span / 2])
|
||||
sweep(gullwing, rectangle_points(ls.x, ls.z));
|
||||
|
||||
rotate(180)
|
||||
translate([0, -span / 2])
|
||||
sweep(gullwing, rectangle_points(smd_sot_tab_width(type), ls.z));
|
||||
}
|
||||
|
||||
color("white")
|
||||
translate_z(z0 + size.z)
|
||||
linear_extrude(eps)
|
||||
resize([size.x - 4 * (z2 - z1) * tan(slant), size.y / 2])
|
||||
text(value, halign = "center", valign = "center");
|
||||
|
||||
}
|
||||
|
@@ -38,4 +38,9 @@ CAP1206 = ["CAP1206", [3.1, 1.6], 0.5];
|
||||
|
||||
smd_capacitors = [CAP0603, CAP0805, CAP1206];
|
||||
|
||||
SOT23 = ["SOT23", [3, 1.4, 1.0], 0.05, 0.66, 1.9, 2.6, [0.4, 0.45, 0.15], 0.4];
|
||||
SOT223 = ["SOT223", [6.5, 3.5, 1.6], 0.05, 0.89, 2.3, 7.0, [0.7, 0.95, 0.25], 3];
|
||||
|
||||
smd_sots = [SOT23, SOT223];
|
||||
|
||||
use <smd.scad>
|
||||
|
@@ -205,12 +205,12 @@ module NEMA_screw_positions(type, n = 4) { //! Positions children at the screw h
|
||||
children();
|
||||
}
|
||||
|
||||
module NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef) //! Place screws and optional earth tag
|
||||
module NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef, earth_rot = undef) //! Place screws and optional earth tag
|
||||
NEMA_screw_positions(type, n)
|
||||
if($i != earth)
|
||||
screw_and_washer(screw, screw_length, true);
|
||||
else
|
||||
rotate($i > 1 ? 180 : 0)
|
||||
rotate(is_undef(earth_rot) ? $i > 1 ? 180 : 0 : earth_rot)
|
||||
ring_terminal(M3_ringterm)
|
||||
star_washer(screw_washer(screw))
|
||||
screw(screw, screw_length);
|
||||
|
@@ -41,19 +41,22 @@ function vero_track_width(type) = vero_pitch(type) * 0.8; //! The width of th
|
||||
function vero_length(type) = vero_holes(type) * vero_pitch(type); //! Length of the board
|
||||
function vero_width(type) = vero_strips(type) * vero_pitch(type); //! Width of the board
|
||||
|
||||
function vero(name, assembly, holes, strips, pitch = inch(0.1), fr4 = false, screw = M3_cap_screw, mounting_holes = [], breaks = [], no_tracks = [], components = [], joints = []) = //! Constructor
|
||||
[ name, assembly, holes, strips, pitch, fr4, screw, mounting_holes, breaks, no_tracks, components, joints ];
|
||||
|
||||
function vero_size(type) = [vero_length(type), vero_width(type), vero_thickness(type)]; //! Board size
|
||||
|
||||
module solder_meniscus(type) {
|
||||
h = 1;
|
||||
r = vero_track_width(type) / 2;
|
||||
module solder_meniscus(type, ir = 0.3, r = undef) { //! Draw a solder meniscus
|
||||
h = 0.7;
|
||||
r = is_undef(r) ? vero_track_width(type) / 2 : r;
|
||||
|
||||
translate_z(vero_track_thickness(type))
|
||||
color("silver") rotate_extrude()
|
||||
difference() {
|
||||
square([r, h]);
|
||||
|
||||
translate([r - eps, h + eps])
|
||||
ellipse(r , h);
|
||||
translate([r + eps, h + eps])
|
||||
ellipse(r - ir , h, $fn = 64);
|
||||
}
|
||||
}
|
||||
|
||||
|