Compare commits

..

53 commits

Author SHA1 Message Date
73775d6999 pre update 2024-02-23 17:55:10 +01:00
5060864b08 fix 4.0 2024-02-23 17:55:10 +01:00
efc7329646 add choc version 2024-02-23 17:55:10 +01:00
85bd46a4d8 version 003 2024-02-23 17:55:10 +01:00
c57440a231 fix matrix :< 2024-02-23 17:55:10 +01:00
a48fb3c064 allow keeping of gerber files 2024-02-23 17:55:10 +01:00
56a81c20b8 add v002 2024-02-23 17:55:10 +01:00
9370da75b7 add v2 with support for powerswitch and reset 2024-02-23 17:55:10 +01:00
fd3fd6b5c0 rename board 2024-02-23 17:55:10 +01:00
Stefan Schwarz
73483e290b add groundplane 2024-02-23 17:55:10 +01:00
Stefan Schwarz
35f2684348 add a switchplate 2024-02-23 17:55:10 +01:00
Stefan Schwarz
ce65a9ef5d cleanup 2024-02-23 17:55:10 +01:00
Stefan Schwarz
3032e6b3d1 rearrange via and connect grounds 2024-02-23 17:55:10 +01:00
Stefan Schwarz
57e8173848 remove bak files from github 2024-02-23 17:55:10 +01:00
Stefan Schwarz
85a13fa4e7 add first routed version 2024-02-23 17:55:10 +01:00
6afbf0385a rotate the diode for cleaner wireing 2024-02-23 17:55:10 +01:00
bec14b1705 remove reverse option 2024-02-23 17:55:10 +01:00
99acabbd12 fix pin assignments 2024-02-23 17:55:10 +01:00
1190f35c66 add makefile and kicad project 2024-02-23 17:55:10 +01:00
52af7f0a20 fix case 2024-02-23 17:55:10 +01:00
Stefan Schwarz
96d043126a wip 2024-02-23 17:55:10 +01:00
Bán Dénes
21e50cb11d 4.0.5 2024-01-22 17:34:20 +01:00
Bán Dénes
353e07654d Package audit 2024-01-22 17:33:56 +01:00
Bán Dénes
e1697e367f Autobind vs. mirroring bugfix (#119) 2024-01-22 15:56:45 +01:00
Bán Dénes
1f57ec4e19 Footprint param streamlining 2023-08-14 19:00:37 +02:00
Kim
6e520e745a
Add intersect aggregator (#102)
* Added intersect aggregator

* Addressed stylistic PR feedback

* Set the rotation of the intersected point to the second point’s rotation

* Revert "Set the rotation of the intersected point to the second point’s rotation"

This reverts commit d210a98f79a8866519fc9695487a9ea235167b8b.

* Adjusted aggregate function to not need axis1 and axis2 parameters

* Add assert to check for exactly 2 parts

* Add unit tests for the aggregate intersect method

* Change the assert string to use ${name.length}

* Change test group name to align with style guide

* Update intersect logic to consider negative Y axis

---------

Co-authored-by: Marco Massarelli <60667061+ceoloide@users.noreply.github.com>
2023-07-19 23:00:44 +02:00
Bán Dénes
e924352763 Allow outline adjusts to use shape-specific units 2023-05-31 11:01:43 +02:00
Bán Dénes
14cd499182 4.0.4 2023-05-20 22:07:22 +02:00
Bán Dénes
7baa6a3b3a 4.0.3 2023-05-20 22:03:21 +02:00
Bán Dénes
9f644c2e2b Independent per-point adjustment 2023-05-20 22:03:21 +02:00
Bán Dénes
9832489d41
Sponsor fixes 2023-05-08 18:46:26 +02:00
Bán Dénes
89981199d9
Initial list of distinguished sponsors 2023-05-08 17:42:43 +02:00
Bán Dénes
63684e33d7
Add donate button to readme 2023-05-01 13:37:48 +02:00
Bán Dénes
d74f657f24
Add sponsorship button 2023-05-01 13:25:16 +02:00
Bán Dénes
daaef0af79 4.0.2 2023-03-18 16:24:47 +01:00
Bán Dénes
4d65eb19a6 Filter negation bugfix 2023-03-18 16:23:05 +01:00
Bán Dénes
3eac7f8e6d Rollup CJS changes 2023-03-18 00:04:38 +01:00
Bán Dénes
5761266260 4.0.1 2023-03-17 23:44:22 +01:00
Luke Kershaw
244fc53eae Handle backslashes in windows tests (#82) 2023-03-17 10:45:04 +01:00
Bán Dénes
9ad080d24c Templating bugfix (#86) 2023-03-17 10:29:55 +01:00
Bán Dénes
f0d22328cd Filter/mirror bugfix 2023-02-09 23:50:18 +01:00
Bán Dénes
480c362c1e Preprocessing bugfix 2023-01-30 15:01:52 +01:00
Bán Dénes
c45523f38a Getting coverage to 100% 2023-01-23 23:34:06 +01:00
Anarion
b27e10374e
Add array to footprint param types (#76) 2023-01-23 21:21:49 +01:00
Luke Kershaw
75f907917b
Extra test coverage for expand_shorthand (#80) 2023-01-23 14:46:57 +01:00
Luke Kershaw
86a74945ca
Fix typo in error message if using incorrect type for stagger (#75) 2023-01-23 12:22:59 +01:00
Bán Dénes
c480a33fa3 Readme postprocessing 2023-01-23 12:19:45 +01:00
Bán Dénes
841addb9ad Roadmap update 2023-01-23 11:17:27 +01:00
Bán Dénes
d2c3999d41 Fix multiple extrusions of the same outline in cases 2023-01-23 11:17:27 +01:00
Bán Dénes
77778249d2 Dependency update 2023-01-23 11:17:27 +01:00
トトも
357e01d639
Improve readme formatting (#62)
* Fixed LICENSE File Name
* Adjusted README Name
* Formatted Contribution Section
* Added License Badge
* Formatted Getting Started
* Moved Getting Started Into Dedicated File
* Added Quicklinks
* Fixed File Name
* Formatted Description + Added Showcase
* Adjusted Image Padding
* Adjusted Spacing
2023-01-23 11:17:01 +01:00
Luke Kershaw
e0eb43566f
Expand test coverage (#77)
* ignore line endings in cli tests
* ignore line endings in integration tests
* expand code coverage for `choc` footprint
* expand code coverage for `chocmini` footprint
* expand code coverage for `mx` footprint
* expand code coverage for `pad` footprint
* expand code coverage for rest of footprints
* expand code coverage for `anchor.js`
* expand code coverage for `units.js`
* expand code coverage for `points.js`
* expand code coverage for `filter.js`
* expand code coverage for `outlines.js`
* expand code coverage for `pcbs.js`
* expand code coverage for `ergogen.js`
* expand code coverage for `kle.js`
* more code coverage for `outlines.js`
* expand code coverage for `cases.js`
2023-01-23 10:02:08 +01:00
Luke Kershaw
3746900490
Bugfix for expand_shorthand (#79) 2023-01-23 09:32:22 +01:00
107 changed files with 15704 additions and 2797 deletions

13
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: [mrzealot] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -1,3 +1,4 @@
# yaml-language-server: $schema=./meta/schema.json
units:
kx: cx
ky: cy
@ -67,6 +68,78 @@ points:
outlines:
# outer border
farouter:
- what: polygon
points:
- ref: matrix_inner_num
shift: [13, 13]
- ref: matrix_middle_num
shift: [13, 13]
- ref: matrix_middle_num
shift: [-13, 13]
- ref: matrix_pinky_num
shift: [-13, 13]
- ref: matrix_pinky_bottom
shift: [-13, -13]
- ref: matrix_pinky_bottom
shift: [13, -13]
- ref: matrix_inner_bottom
shift: [-13, -13]
- ref: matrix_inner_bottom
shift: [13, -13]
- ref: mirror_matrix_inner_bottom
shift: [13, -13]
- ref: mirror_matrix_inner_bottom
shift: [-13, -13]
- ref: mirror_matrix_pinky_bottom
shift: [13, -13]
- ref: mirror_matrix_pinky_bottom
shift: [-13, -13]
- ref: mirror_matrix_pinky_num
shift: [-13, 13]
- ref: mirror_matrix_middle_num
shift: [-13, 13]
- ref: mirror_matrix_middle_num
shift: [13, 13]
- ref: mirror_matrix_inner_num
shift: [13, 13]
compatouter:
- what: polygon
points:
- ref: matrix_inner_num
shift: [11, 11]
- ref: matrix_middle_num
shift: [11, 11]
- ref: matrix_middle_num
shift: [-11, 11]
- ref: matrix_pinky_num
shift: [-11, 11]
- ref: matrix_pinky_bottom
shift: [-11, -11]
- ref: matrix_pinky_bottom
shift: [11, -11]
- ref: matrix_inner_bottom
shift: [-11, -11]
- ref: matrix_inner_bottom
shift: [11, -11]
- ref: mirror_matrix_inner_bottom
shift: [11, -11]
- ref: mirror_matrix_inner_bottom
shift: [-11, -11]
- ref: mirror_matrix_pinky_bottom
shift: [11, -11]
- ref: mirror_matrix_pinky_bottom
shift: [-11, -11]
- ref: mirror_matrix_pinky_num
shift: [-11, 11]
- ref: mirror_matrix_middle_num
shift: [-11, 11]
- ref: mirror_matrix_middle_num
shift: [11, 11]
- ref: mirror_matrix_inner_num
shift: [11, 11]
outer:
- what: polygon
points:
@ -112,14 +185,14 @@ outlines:
aggregate.parts:
- matrix_inner_bottom
- mirror_matrix_inner_bottom
shift: [0, 0]
shift: [0, 40]
# 14mm holes for cherry switches
keyholes:
- what: rectangle
where: true
asym: source
size: 13.5
size: 13.8
# keycaps
keycaps:
@ -134,6 +207,21 @@ outlines:
- -keyholes
- -chip
# far outer switchplate
farouterswitchplate:
- farouter
- -keyholes
- -chip
cases:
laser:
- name: farouterswitchplate
extrude: 6.5
- name: compatouter
extrude: 5.2
shift: [0, 0, 1.3]
operation: subtract
pcbs:
main:
outlines:
@ -149,14 +237,7 @@ pcbs:
to: "{{column_net}}"
keycaps: true
hotswap: true
#led:
# what: rgb
# where: true
# adjust:
# shift: [0, -5]
# params:
# din: "{{label}}"
# dout: P02
diode:
what: diode
where: true
@ -164,8 +245,9 @@ pcbs:
from: "{{colrow}}"
to: "{{row_net}}"
adjust:
shift: [-8, -0]
rotate: 90
shift: [0, -5]
rotate: 180
reset:
what: button
params:
@ -177,6 +259,7 @@ pcbs:
- matrix_inner_bottom
- mirror_matrix_inner_bottom
rotate: 90
mcu:
what: promicro
where:

View file

@ -145,6 +145,8 @@ outlines:
- -keyholes
- -chip
cases:
pcbs:
main:
outlines:

View file

View file

@ -1,6 +1,6 @@
all: node_modules
node src/cli.js 23creus.yaml -o output
cp output/pcbs/main.kicad_pcb kicad/45treus/
node src/cli.js 23creus.yaml -d -o output
cp output/pcbs/main.kicad_pcb kicad/23creus/
node_modules:
npm ci

111
README.md Normal file
View file

@ -0,0 +1,111 @@
# Ergogen
***Ergonomic Keyboard Generator***
<br>
<img
src = 'showcase.png'
width = 400
align = right
/>
The project aims to provide a common configuration format to describe ***ergonomic*** 2D layouts and generate automatic plates, cases, as well as un-routed PCBs for them. The project grew out of (and is an integral part of) the [Absolem keyboard], and shares its [Discord] server as well.
<div align = center>
<br>
<br>
<br>
---
[![Button WebUI]][WebUI]
[![Button Documentation]][Documentation]
[![Button Discord]][Discord]
[![Button Donate]][Donate]
---
</div>
<br>
<br>
## Getting Started
Until there's a proper "Getting started" guide, try getting acquainted with **Ergogen** by following these steps in order:
<br>
1. Read the **[Documentation]**.
D'uuh.
They're not complete by any measure, but should give you a fairly good idea what you're dealing with here.
<br>
2. Try one of the web-based deployments.
[![Button Official]][WebUI]
[![Button Unofficial]][Unofficial]
The unofficial deployment is probably better, tbh, and will soon be replacing the official one.
Choose either one, then click things, look at outputs and see if things start to make sense.
There is no need for you to download the **CLI** unless you want to do one of the following:
- Preview in-development features
- Use custom modifications
- Contribute code
<br>
3. Search the [`ergogen`][Topic] topic on GitHub.
There, you can look at (and reverse engineer) a variety of real life configs using **Ergogen**.
Pop them into the web UI to see what they do, tinker with them and things should start to make more sense.
<br>
4. If a question persists after all of the above, feel free to ask it over on **[Discord]** and we'll do our best to help you out.
<br>
## Contributions
Feature ideas, documentation improvements, examples, tests, or pull requests welcome!
Get in touch on our **[Discord]**, and we can definitely find something you can help with, if you'd like to.
<br>
## Sponsors
Huge thanks go to everyone who chooses to support my work!
But even huger thanks are due to the following, *distinguished* sponsors:
- [perce](https://madebyperce.com/)
- [Cache](https://github.com/MvEerd)
- [Neil Gilmour](https://github.com/neilgilmour)
- [ochief](https://github.com/ochief)
- [Alyx Brett](https://github.com/alyx-brett)
<!----------------------------------------------------------------------------->
[Absolem keyboard]: https://zealot.hu/absolem
[Documentation]: https://docs.ergogen.xyz
[Discord]: http://discord.ergogen.xyz
[WebUI]: https://ergogen.xyz
[Unofficial]: https://ergogen.cache.works/
[Topic]: https://github.com/topics/ergogen
[Donate]: https://github.com/sponsors/mrzealot
<!--------------------------------{ Buttons }---------------------------------->
[Button WebUI]: https://img.shields.io/badge/Deployment-37a779?style=for-the-badge&logoColor=white&logo=AppleArcade
[Button Unofficial]: https://img.shields.io/badge/Unofficial-yellow?style=for-the-badge
[Button Official]: https://img.shields.io/badge/Official-37a779?style=for-the-badge
[Button Documentation]: https://img.shields.io/badge/Documentation-1793D1?style=for-the-badge&logoColor=white&logo=GitBook
[Button Discord]: https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logoColor=white&logo=Discord
[Button Donate]: https://img.shields.io/badge/Donate-EA4AAA?style=for-the-badge&logoColor=white&logo=githubsponsors

View file

@ -1,12 +1,14 @@
{
"board": {
"active_layer": 0,
"active_layer": 37,
"active_layer_preset": "All Layers",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,

View file

@ -1,5 +1,6 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
@ -44,7 +45,6 @@
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.508
}
},
@ -57,32 +57,43 @@
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"footprint": "error",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
@ -91,32 +102,75 @@
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.075,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996,
"min_via_annular_width": 0.09999999999999999,
"min_via_diameter": 0.39999999999999997,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 5,
"td_on_pad_in_zone": false,
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [],
"via_dimensions": [],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
@ -338,7 +392,7 @@
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
@ -352,13 +406,276 @@
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
"wire_width": 6
}
],
"meta": {
"version": 2
"version": 3
},
"net_colors": null
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": [
{
"netclass": "Default",
"pattern": ""
},
{
"netclass": "Default",
"pattern": "pinky_bottom"
},
{
"netclass": "Default",
"pattern": "P21"
},
{
"netclass": "Default",
"pattern": "pinky_home"
},
{
"netclass": "Default",
"pattern": "pinky_top"
},
{
"netclass": "Default",
"pattern": "pinky_num"
},
{
"netclass": "Default",
"pattern": "ring_bottom"
},
{
"netclass": "Default",
"pattern": "P20"
},
{
"netclass": "Default",
"pattern": "ring_home"
},
{
"netclass": "Default",
"pattern": "ring_top"
},
{
"netclass": "Default",
"pattern": "ring_num"
},
{
"netclass": "Default",
"pattern": "middle_bottom"
},
{
"netclass": "Default",
"pattern": "P19"
},
{
"netclass": "Default",
"pattern": "middle_home"
},
{
"netclass": "Default",
"pattern": "middle_top"
},
{
"netclass": "Default",
"pattern": "middle_num"
},
{
"netclass": "Default",
"pattern": "index_bottom"
},
{
"netclass": "Default",
"pattern": "P18"
},
{
"netclass": "Default",
"pattern": "index_home"
},
{
"netclass": "Default",
"pattern": "index_top"
},
{
"netclass": "Default",
"pattern": "index_num"
},
{
"netclass": "Default",
"pattern": "inner_bottom"
},
{
"netclass": "Default",
"pattern": "P15"
},
{
"netclass": "Default",
"pattern": "inner_home"
},
{
"netclass": "Default",
"pattern": "inner_top"
},
{
"netclass": "Default",
"pattern": "inner_num"
},
{
"netclass": "Default",
"pattern": "thumb_bottom"
},
{
"netclass": "Default",
"pattern": "P14"
},
{
"netclass": "Default",
"pattern": "mirror_pinky_bottom"
},
{
"netclass": "Default",
"pattern": "P2"
},
{
"netclass": "Default",
"pattern": "mirror_pinky_home"
},
{
"netclass": "Default",
"pattern": "mirror_pinky_top"
},
{
"netclass": "Default",
"pattern": "mirror_pinky_num"
},
{
"netclass": "Default",
"pattern": "mirror_ring_bottom"
},
{
"netclass": "Default",
"pattern": "P3"
},
{
"netclass": "Default",
"pattern": "mirror_ring_home"
},
{
"netclass": "Default",
"pattern": "mirror_ring_top"
},
{
"netclass": "Default",
"pattern": "mirror_ring_num"
},
{
"netclass": "Default",
"pattern": "mirror_middle_bottom"
},
{
"netclass": "Default",
"pattern": "P4"
},
{
"netclass": "Default",
"pattern": "mirror_middle_home"
},
{
"netclass": "Default",
"pattern": "mirror_middle_top"
},
{
"netclass": "Default",
"pattern": "mirror_middle_num"
},
{
"netclass": "Default",
"pattern": "mirror_index_bottom"
},
{
"netclass": "Default",
"pattern": "P5"
},
{
"netclass": "Default",
"pattern": "mirror_index_home"
},
{
"netclass": "Default",
"pattern": "mirror_index_top"
},
{
"netclass": "Default",
"pattern": "mirror_index_num"
},
{
"netclass": "Default",
"pattern": "mirror_inner_bottom"
},
{
"netclass": "Default",
"pattern": "P6"
},
{
"netclass": "Default",
"pattern": "mirror_inner_home"
},
{
"netclass": "Default",
"pattern": "mirror_inner_top"
},
{
"netclass": "Default",
"pattern": "mirror_inner_num"
},
{
"netclass": "Default",
"pattern": "mirror_thumb_bottom"
},
{
"netclass": "Default",
"pattern": "P7"
},
{
"netclass": "Default",
"pattern": "P16"
},
{
"netclass": "Default",
"pattern": "P10"
},
{
"netclass": "Default",
"pattern": "P9"
},
{
"netclass": "Default",
"pattern": "P8"
},
{
"netclass": "Default",
"pattern": "RST"
},
{
"netclass": "Default",
"pattern": "GND"
},
{
"netclass": "Default",
"pattern": "RAW"
},
{
"netclass": "Default",
"pattern": "VCC"
},
{
"netclass": "Default",
"pattern": "P1"
},
{
"netclass": "Default",
"pattern": "P0"
}
]
},
"pcbnew": {
"last_paths": {

7254
kicad/23creus/main.kicad_pcb Normal file

File diff suppressed because it is too large Load diff

3418
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "ergogen",
"version": "4.0.0",
"version": "4.0.5",
"description": "Ergonomic keyboard layout generator",
"author": "Bán Dénes <mr@zealot.hu>",
"license": "MIT",
@ -15,24 +15,25 @@
"coverage": "nyc --reporter=html --reporter=text npm test"
},
"dependencies": {
"fs-extra": "^10.0.1",
"fs-extra": "^11.1.0",
"js-yaml": "^3.14.1",
"jszip": "^3.10.1",
"kle-serial": "github:ergogen/kle-serial#ergogen",
"makerjs": "github:ergogen/maker.js#ergogen",
"mathjs": "^10.1.1",
"yargs": "^17.3.1"
"mathjs": "^11.5.0",
"yargs": "^17.6.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^21.0.2",
"@rollup/plugin-json": "^4.1.0",
"chai": "^4.3.6",
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-json": "^6.0.0",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"dir-compare": "^4.0.0",
"glob": "^7.2.0",
"mocha": "^9.2.1",
"glob": "^8.1.0",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"rollup": "^2.68.0"
"rollup": "^3.10.1",
"sinon": "^15.0.1"
},
"nyc": {
"all": true,

View file

@ -1,22 +0,0 @@
# Ergogen
Ergogen is a keyboard generator that aims to provide a common configuration format to describe **ergonomic** 2D layouts, and generate automatic plates, cases, and (un-routed) PCBs for them.
The project grew out of (and is an integral part of) the [Absolem keyboard](https://zealot.hu/absolem), and shares its [Discord server](https://discord.gg/nbKcAZB) as well.
## Getting started
Until there's a proper "Getting started" guide, try getting acquainted with ergogen by following these steps in order:
1. Read the [docs](https://docs.ergogen.xyz). D'uuh. They're not complete by any measure, but should give you a fairly good idea what you're dealing with here.
1. Try one of the web-based deployments ([official](https://ergogen.xyz); [unofficial](https://ergogen.cache.works/) but probably better and soon to be official) - no need to download the CLI unless you want to A) preview in-development features, B) use custom modifications, or C) contribute code. Click things, look at outputs; see if things start to make sense.
1. Search the [`#ergogen`](https://github.com/topics/ergogen) topic on GitHub to look at (and reverse engineer) a variety of real life configs using ergogen. Pop them into the web UI, see what they do, tinker with them; things should start to make more and more sense.
1. If a question persists after all of the above, feel free to ask it over on [Discord](https://discord.gg/nbKcAZB) and we'll do our best to help you out.
## Contributions
Feature ideas, documentation improvements, examples, tests, or pull requests welcome!
Get in touch [on Discord](https://discord.gg/nbKcAZB), and we can definitely find something you can help with, if you'd like to.

View file

@ -14,6 +14,10 @@
### Minor
- Support "direct" anchors, as in, recognize num arrays and parse them as x/y/r
- Add `origin` to zone-wide and global rotation in points
- Handle unnecessary (but seemingly consistent, so easy to confuse) `key` subfield of row-level overrides
- Allow footprints to access raw array/object fields from points with templating
- Include raw kicad footprint integrations
- pull torik's script to be able to convert raw kicad footprints into positionable ergogen ones
- have a `dummy` footprint which can just be updated from schematic

View file

@ -1,4 +1,4 @@
import pkg from './package.json'
import pkg from './package.json' assert { type: 'json' }
import json from '@rollup/plugin-json'
import commonjs from '@rollup/plugin-commonjs'

BIN
showcase.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View file

@ -1,6 +1,7 @@
const u = require('./utils')
const a = require('./assert')
const Point = require('./point')
const m = require('makerjs')
const mirror_ref = exports.mirror = (ref, mirror=true) => {
if (mirror) {
@ -17,15 +18,52 @@ const aggregator_common = ['parts', 'method']
const aggregators = {
average: (config, name, parts) => {
a.unexpected(config, name, aggregator_common)
let x = 0, y = 0, r = 0
const len = parts.length
if (len == 0) {
return new Point()
}
let x = 0, y = 0, r = 0
for (const part of parts) {
x += part.x
y += part.y
r += part.r
}
return new Point(x / len, y / len, r / len)
}
},
intersect: (config, name, parts) => {
// a line is generated from a point by taking their
// (rotated) Y axis. The line is not extended to
// +/- Infinity as that doesn't work with makerjs.
// An arbitrary offset of 1 meter is considered
// sufficient for practical purposes, and the point
// coordinates are used as pivot point for the rotation.
const get_line_from_point = (point, offset=1000) => {
const origin = [point.x, point.y]
const p1 = [point.x, point.y - offset]
const p2 = [point.x, point.y + offset]
let line = new m.paths.Line(p1, p2)
line = m.path.rotate(line, point.r, origin)
return line
}
a.unexpected(config, name, aggregator_common)
a.assert(parts.length==2, `Intersect expects exactly two parts, but it got ${parts.length}!`)
const line1 = get_line_from_point(parts[0])
const line2 = get_line_from_point(parts[1])
const intersection = m.path.intersection(line1, line2)
a.assert(intersection, `The points under "${name}.parts" do not intersect!`)
const intersection_point_arr = intersection.intersectionPoints[0]
const intersection_point = new Point(
intersection_point_arr[0], intersection_point_arr[1], 0
)
return intersection_point
},
}
const anchor = exports.parse = (raw, name, points={}, start=new Point(), mirror=false) => units => {
@ -53,7 +91,7 @@ const anchor = exports.parse = (raw, name, points={}, start=new Point(), mirror=
//
// Reference or aggregate handling
//
let point = start.clone()
if (raw.ref !== undefined && raw.aggregate !== undefined) {
throw new Error(`Fields "ref" and "aggregate" cannot appear together in anchor "${name}"!`)

View file

@ -69,15 +69,19 @@ exports.parse = (config, outlines, units) => {
const extrude = a.sane(part.extrude || 1, `${part_qname}.extrude`, 'number')(units)
const outline = outlines[name]
a.assert(outline, `Field "${part_qname}.name" does not name a valid outline!`)
if (!scripts[name]) {
scripts[name] = m.exporter.toJscadScript(outline, {
functionName: `${name}_outline_fn`,
// This is a hack to separate multiple calls to the same outline with different extrude values
// I know it needlessly duplicates a lot of code, but it's the quickest fix in the short term
// And on the long run, we'll probably be moving to CADQuery anyway...
const extruded_name = `${name}_extrude_` + ('' + extrude).replace(/\D/g, '_')
if (!scripts[extruded_name]) {
scripts[extruded_name] = m.exporter.toJscadScript(outline, {
functionName: `${extruded_name}_outline_fn`,
extrude: extrude,
indent: 4
})
}
outline_dependencies.push(name)
base = `${name}_outline_fn()`
outline_dependencies.push(extruded_name)
base = `${extruded_name}_outline_fn()`
} else {
a.assert(part.extrude === undefined, `Field "${part_qname}.extrude" should not be used when what=case!`)
a.in(name, `${part_qname}.name`, Object.keys(cases))

View file

@ -132,12 +132,14 @@ try {
// output helpers
const yamldump = data => yaml.dump(data, {indent: 4, noRefs: true})
const single = (data, rel) => {
if (!data) return
const abs = path.join(args.o, rel)
fs.mkdirpSync(path.dirname(abs))
if (abs.endsWith('.yaml')) {
fs.writeFileSync(abs, yaml.dump(data, {indent: 4}))
fs.writeFileSync(abs, yamldump(data))
} else {
fs.writeFileSync(abs, data)
}
@ -148,7 +150,7 @@ const composite = (data, rel) => {
const abs = path.join(args.o, rel)
if (data.yaml) {
fs.mkdirpSync(path.dirname(abs))
fs.writeFileSync(abs + '.yaml', yaml.dump(data.yaml, {indent: 4}))
fs.writeFileSync(abs + '.yaml', yamldump(data.yaml))
}
for (const format of ['svg', 'dxf', 'jscad']) {
if (data[format]) {

View file

@ -9,9 +9,8 @@ const _false = () => false
const _and = arr => p => arr.map(e => e(p)).reduce((a, b) => a && b)
const _or = arr => p => arr.map(e => e(p)).reduce((a, b) => a || b)
const similar = (key, reference, name, units) => {
const similar = (keys, reference, name, units) => {
let neg = false
if (reference.startsWith('-')) {
neg = true
reference = reference.slice(1)
@ -20,15 +19,19 @@ const similar = (key, reference, name, units) => {
// support both string or regex as reference
let internal_tester = val => (''+val) == reference
if (reference.startsWith('/')) {
const regex_parts = reference.split('/')
regex_parts.shift() // remove starting slash
const flags = regex_parts.pop()
const regex = new RegExp(regex_parts.join('/'), flags)
internal_tester = val => regex.test(''+val)
try {
const regex_parts = reference.split('/')
regex_parts.shift() // remove starting slash
const flags = regex_parts.pop()
const regex = new RegExp(regex_parts.join('/'), flags)
internal_tester = val => regex.test(''+val)
} catch (ex) {
throw new Error(`Invalid regex "${reference}" found at filter "${name}"!`)
}
}
// support strings, arrays, or objects as key
const external_tester = point => {
const external_tester = (point, key) => {
const value = u.deep(point, key)
if (a.type(value)() == 'array') {
return value.some(subkey => internal_tester(subkey))
@ -39,11 +42,12 @@ const similar = (key, reference, name, units) => {
}
}
// negation happens at the end
// consider negation
if (neg) {
return point => !external_tester(point)
return point => keys.every(key => !external_tester(point, key))
} else {
return point => keys.some(key => external_tester(point, key))
}
return external_tester
}
const comparators = {
@ -75,7 +79,7 @@ const simple = (exp, name, units) => {
value = exp
}
return point => keys.some(key => comparators[op](key, value, name, units)(point))
return point => comparators[op](keys, value, name, units)(point)
}
const complex = (config, name, units, aggregator=_or) => {
@ -109,7 +113,7 @@ const contains_object = (val) => {
}
exports.parse = (config, name, points={}, units={}, asym='source') => {
let result = []
// if a filter decl is undefined, it's just the default point at [0, 0]
@ -123,7 +127,11 @@ exports.parse = (config, name, points={}, units={}, asym='source') => {
}
if (['clone', 'both'].includes(asym)) {
// this is strict: if the ref of the anchor doesn't have a mirror pair, it will error out
result.push(anchor(config, name, points, undefined, true)(units))
// also, we check for duplicates as ref-less anchors mirror to themselves
const clone = anchor(config, name, points, undefined, true)(units)
if (result.every(p => !p.equals(clone))) {
result.push(clone)
}
}
// otherwise, it is treated as a condition to filter all available points
@ -132,9 +140,15 @@ exports.parse = (config, name, points={}, units={}, asym='source') => {
if (['source', 'both'].includes(asym)) {
result = result.concat(source)
}
if (['source', 'both'].includes(asym)) {
if (['clone', 'both'].includes(asym)) {
// this is permissive: we only include mirrored versions if they exist, and don't fuss if they don't
result = result.concat(source.map(p => points[anchor_lib.mirror(p.meta.name)]).filter(p => !!p))
// also, we check for duplicates as clones can potentially refer back to their sources, too
const pool = result.map(p => p.meta.name)
result = result.concat(
source.map(p => points[anchor_lib.mirror(p.meta.name)])
.filter(p => !!p)
.filter(p => !pool.includes(p.meta.name))
)
}
}

View file

@ -25,8 +25,8 @@ module.exports = {
(fp_line (start 7 -7) (end 7 -6) (layer Dwgs.User) (width 0.15))
${''/* pins */}
(pad 1 thru_hole circle (at 2.5 -4.5) (size 2.25 2.25) (drill 1.47) (layers *.Cu *.Mask) ${p.from.str})
(pad 2 thru_hole circle (at -2.5 -4) (size 2.25 2.25) (drill 1.47) (layers *.Cu *.Mask) ${p.to.str})
(pad 1 thru_hole circle (at 2.5 -4.5) (size 2.25 2.25) (drill 1.47) (layers *.Cu *.Mask) ${p.from})
(pad 2 thru_hole circle (at -2.5 -4) (size 2.25 2.25) (drill 1.47) (layers *.Cu *.Mask) ${p.to})
)
`

View file

@ -28,10 +28,10 @@ module.exports = {
(fp_line (start -2.75 -1.25) (end -2.75 1.25) (layer ${p.side}.SilkS) (width 0.15))
${'' /* pins */}
(pad 1 smd rect (at -3.1 -1.85 ${p.rot}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from.str})
(pad 1 smd rect (at 3.1 -1.85 ${p.rot}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from.str})
(pad 2 smd rect (at -3.1 1.85 ${p.rot}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to.str})
(pad 2 smd rect (at 3.1 1.85 ${p.rot}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to.str})
(pad 1 smd rect (at -3.1 -1.85 ${p.r}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from})
(pad 1 smd rect (at 3.1 -1.85 ${p.r}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from})
(pad 2 smd rect (at -3.1 1.85 ${p.r}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to})
(pad 2 smd rect (at 3.1 1.85 ${p.r}) (size 1.8 1.1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to})
)
`

View file

@ -62,14 +62,14 @@ module.exports = {
(pad "" np_thru_hole circle (at 0 -5.95) (size 3 3) (drill 3) (layers *.Cu *.Mask))
${'' /* net pads */}
(pad 1 smd rect (at ${def_neg}3.275 -5.95 ${p.rot}) (size 2.6 2.6) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.from.str})
(pad 2 smd rect (at ${def_pos}8.275 -3.75 ${p.rot}) (size 2.6 2.6) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.to.str})
(pad 1 smd rect (at ${def_neg}3.275 -5.95 ${p.r}) (size 2.6 2.6) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.from})
(pad 2 smd rect (at ${def_pos}8.275 -3.75 ${p.r}) (size 2.6 2.6) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.to})
`
} else {
return `
${''/* pins */}
(pad 1 thru_hole circle (at ${def_pos}5 -3.8) (size 2.032 2.032) (drill 1.27) (layers *.Cu *.Mask) ${p.from.str})
(pad 2 thru_hole circle (at ${def_pos}0 -5.9) (size 2.032 2.032) (drill 1.27) (layers *.Cu *.Mask) ${p.to.str})
(pad 1 thru_hole circle (at ${def_pos}5 -3.8) (size 2.032 2.032) (drill 1.27) (layers *.Cu *.Mask) ${p.from})
(pad 2 thru_hole circle (at ${def_pos}0 -5.9) (size 2.032 2.032) (drill 1.27) (layers *.Cu *.Mask) ${p.to})
`
}
}

View file

@ -69,8 +69,8 @@ module.exports = {
function pins(def_neg, def_pos) {
return `
${''/* pins */}
(pad 1 thru_hole circle (at ${def_neg}4.58 5.1) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) ${p.from.str} (clearance 0.2))
(pad 2 thru_hole circle (at ${def_pos}2 5.4) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) ${p.to.str} (clearance 0.2))
(pad 1 thru_hole circle (at ${def_neg}4.58 5.1) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) ${p.from} (clearance 0.2))
(pad 2 thru_hole circle (at ${def_pos}2 5.4) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) ${p.to} (clearance 0.2))
`
}
if(p.reverse){

View file

@ -32,14 +32,14 @@ module.exports = {
(fp_line (start -0.75 0) (end -0.35 0) (layer B.SilkS) (width 0.1))
${''/* SMD pads on both sides */}
(pad 1 smd rect (at -1.65 0 ${p.rot}) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) ${p.to.str})
(pad 2 smd rect (at 1.65 0 ${p.rot}) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) ${p.from.str})
(pad 1 smd rect (at -1.65 0 ${p.rot}) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) ${p.to.str})
(pad 2 smd rect (at 1.65 0 ${p.rot}) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) ${p.from.str})
(pad 1 smd rect (at -1.65 0 ${p.r}) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) ${p.to})
(pad 2 smd rect (at 1.65 0 ${p.r}) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) ${p.from})
(pad 1 smd rect (at -1.65 0 ${p.r}) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) ${p.to})
(pad 2 smd rect (at 1.65 0 ${p.r}) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) ${p.from})
${''/* THT terminals */}
(pad 1 thru_hole rect (at -3.81 0 ${p.rot}) (size 1.778 1.778) (drill 0.9906) (layers *.Cu *.Mask) ${p.to.str})
(pad 2 thru_hole circle (at 3.81 0 ${p.rot}) (size 1.905 1.905) (drill 0.9906) (layers *.Cu *.Mask) ${p.from.str})
(pad 1 thru_hole rect (at -3.81 0 ${p.r}) (size 1.778 1.778) (drill 0.9906) (layers *.Cu *.Mask) ${p.to})
(pad 2 thru_hole circle (at 3.81 0 ${p.r}) (size 1.905 1.905) (drill 0.9906) (layers *.Cu *.Mask) ${p.from})
)
`

View file

@ -30,8 +30,8 @@ module.exports = {
(fp_line (start -1 1.5) (end -1 2.0) (layer ${p.side}.SilkS) (width 0.15))
(fp_line (start -1.25 1.75) (end -0.75 1.75) (layer ${p.side}.SilkS) (width 0.15))
(pad 1 thru_hole rect (at -1 0 ${p.rot}) (size 1.2 1.7) (drill 0.75) (layers *.Cu *.Mask) ${p.pos.str})
(pad 2 thru_hole oval (at 1 0 ${p.rot}) (size 1.2 1.7) (drill 0.75) (layers *.Cu *.Mask) ${p.neg.str})
(pad 1 thru_hole rect (at -1 0 ${p.r}) (size 1.2 1.7) (drill 0.75) (layers *.Cu *.Mask) ${p.pos})
(pad 2 thru_hole oval (at 1 0 ${p.r}) (size 1.2 1.7) (drill 0.75) (layers *.Cu *.Mask) ${p.neg})
)

View file

@ -14,9 +14,9 @@ module.exports = {
(fp_text value Jumper (at 0 -7.3) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
${'' /* pins */}
(pad 1 smd rect (at -0.50038 0 ${p.rot}) (size 0.635 1.143) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
(clearance 0.1905) ${p.from.str})
(pad 2 smd rect (at 0.50038 0 ${p.rot}) (size 0.635 1.143) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
(clearance 0.1905) ${p.to.str}))
(pad 1 smd rect (at -0.50038 0 ${p.r}) (size 0.635 1.143) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
(clearance 0.1905) ${p.from})
(pad 2 smd rect (at 0.50038 0 ${p.r}) (size 0.635 1.143) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
(clearance 0.1905) ${p.to}))
`
}

View file

@ -62,14 +62,14 @@ module.exports = {
(pad "" np_thru_hole circle (at ${def_neg}3.81 -2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
${'' /* net pads */}
(pad 1 smd rect (at ${def_neg}7.085 -2.54 ${p.rot}) (size 2.55 2.5) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.from.str})
(pad 2 smd rect (at ${def_pos}5.842 -5.08 ${p.rot}) (size 2.55 2.5) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.to.str})
(pad 1 smd rect (at ${def_neg}7.085 -2.54 ${p.r}) (size 2.55 2.5) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.from})
(pad 2 smd rect (at ${def_pos}5.842 -5.08 ${p.r}) (size 2.55 2.5) (layers ${def_side}.Cu ${def_side}.Paste ${def_side}.Mask) ${p.to})
`
} else {
return `
${''/* pins */}
(pad 1 thru_hole circle (at ${def_pos}2.54 -5.08) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) ${p.from.str})
(pad 2 thru_hole circle (at ${def_neg}3.81 -2.54) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) ${p.to.str})
(pad 1 thru_hole circle (at ${def_pos}2.54 -5.08) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) ${p.from})
(pad 2 thru_hole circle (at ${def_neg}3.81 -2.54) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) ${p.to})
`
}
}

View file

@ -16,14 +16,14 @@ module.exports = {
(fp_text value OLED (at 0 -7.3) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
${'' /* pins */}
(pad 4 thru_hole oval (at 1.6 2.18 ${p.rot+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.SDA.str})
(pad 3 thru_hole oval (at 1.6 4.72 ${p.rot+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.SCL.str})
(pad 2 thru_hole oval (at 1.6 7.26 ${p.rot+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.VCC.str})
(pad 1 thru_hole rect (at 1.6 9.8 ${p.rot+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.GND.str})
(pad 4 thru_hole oval (at 1.6 2.18 ${p.r+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.SDA})
(pad 3 thru_hole oval (at 1.6 4.72 ${p.r+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.SCL})
(pad 2 thru_hole oval (at 1.6 7.26 ${p.r+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.VCC})
(pad 1 thru_hole rect (at 1.6 9.8 ${p.r+270}) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask)
${p.GND})
)
`
}

View file

@ -24,10 +24,10 @@ module.exports = {
(fp_line (start -6 6) (end -6 -6) (layer Dwgs.User) (width 0.15))
${'' /* pins */}
(pad 1 np_thru_hole circle (at 6.25 -2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.from.str})
(pad 2 np_thru_hole circle (at -6.25 -2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.from.str})
(pad 3 np_thru_hole circle (at 6.25 2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.to.str})
(pad 4 np_thru_hole circle (at -6.25 2.5 ) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.to.str})
(pad 1 np_thru_hole circle (at 6.25 -2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.from})
(pad 2 np_thru_hole circle (at -6.25 -2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.from})
(pad 3 np_thru_hole circle (at 6.25 2.5) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.to})
(pad 4 np_thru_hole circle (at -6.25 2.5 ) (size 1.2 1.2) (drill 1.2) (layers *.Cu *.Mask) ${p.to})
)
`

View file

@ -28,9 +28,9 @@ module.exports = {
if (align == 'down') y -= p.height / 2 + plus
let text = ''
if (p.text.length) {
text = `(fp_text user ${p.text} (at ${x} ${y} ${p.rot}) (layer ${side}.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15)) ${mirror}))`
text = `(fp_text user ${p.text} (at ${x} ${y} ${p.r}) (layer ${side}.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15)) ${mirror}))`
}
return `(pad 1 smd rect (at 0 0 ${p.rot}) (size ${p.width} ${p.height}) (layers ${side}.Cu ${side}.Paste ${side}.Mask) ${p.net.str})\n${text}`
return `(pad 1 smd rect (at 0 0 ${p.r}) (size ${p.width} ${p.height}) (layers ${side}.Cu ${side}.Paste ${side}.Mask) ${p.net})\n${text}`
}
return `

View file

@ -60,58 +60,58 @@ module.exports = {
(fp_line (start -12.7 ${def_pos}6.35) (end -12.7 ${def_pos}8.89) (layer F.SilkS) (width 0.15))
${''/* pin names */}
(fp_text user RAW (at -13.97 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -11.43 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user RST (at -8.89 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user VCC (at -6.35 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P21 (at -3.81 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P20 (at -1.27 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P19 (at 1.27 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P18 (at 3.81 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P15 (at 6.35 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P14 (at 8.89 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P16 (at 11.43 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P10 (at 13.97 ${def_pos}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user RAW (at -13.97 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -11.43 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user RST (at -8.89 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user VCC (at -6.35 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P21 (at -3.81 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P20 (at -1.27 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P19 (at 1.27 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P18 (at 3.81 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P15 (at 6.35 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P14 (at 8.89 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P16 (at 11.43 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P10 (at 13.97 ${def_pos}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P01 (at -13.97 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P00 (at -11.43 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -8.89 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -6.35 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P02 (at -3.81 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P03 (at -1.27 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P04 (at 1.27 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P05 (at 3.81 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P06 (at 6.35 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P07 (at 8.89 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P08 (at 11.43 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P09 (at 13.97 ${def_neg}4.8 ${p.rot + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P01 (at -13.97 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P00 (at -11.43 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -8.89 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user GND (at -6.35 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P02 (at -3.81 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P03 (at -1.27 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P04 (at 1.27 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P05 (at 3.81 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P06 (at 6.35 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P07 (at 8.89 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P08 (at 11.43 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
(fp_text user P09 (at 13.97 ${def_neg}4.8 ${p.r + 90}) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
${''/* and now the actual pins */}
(pad 1 thru_hole rect (at -13.97 ${def_pos}7.62 ${p.rot}) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.RAW.str})
(pad 2 thru_hole circle (at -11.43 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND.str})
(pad 3 thru_hole circle (at -8.89 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.RST.str})
(pad 4 thru_hole circle (at -6.35 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.VCC.str})
(pad 5 thru_hole circle (at -3.81 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P21.str})
(pad 6 thru_hole circle (at -1.27 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P20.str})
(pad 7 thru_hole circle (at 1.27 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P19.str})
(pad 8 thru_hole circle (at 3.81 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P18.str})
(pad 9 thru_hole circle (at 6.35 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P15.str})
(pad 10 thru_hole circle (at 8.89 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P14.str})
(pad 11 thru_hole circle (at 11.43 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P16.str})
(pad 12 thru_hole circle (at 13.97 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P10.str})
(pad 1 thru_hole rect (at -13.97 ${def_pos}7.62 ${p.r}) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.RAW})
(pad 2 thru_hole circle (at -11.43 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND})
(pad 3 thru_hole circle (at -8.89 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.RST})
(pad 4 thru_hole circle (at -6.35 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.VCC})
(pad 5 thru_hole circle (at -3.81 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P21})
(pad 6 thru_hole circle (at -1.27 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P20})
(pad 7 thru_hole circle (at 1.27 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P19})
(pad 8 thru_hole circle (at 3.81 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P18})
(pad 9 thru_hole circle (at 6.35 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P15})
(pad 10 thru_hole circle (at 8.89 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P14})
(pad 11 thru_hole circle (at 11.43 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P16})
(pad 12 thru_hole circle (at 13.97 ${def_pos}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P10})
(pad 13 thru_hole circle (at -13.97 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P1.str})
(pad 14 thru_hole circle (at -11.43 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P0.str})
(pad 15 thru_hole circle (at -8.89 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND.str})
(pad 16 thru_hole circle (at -6.35 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND.str})
(pad 17 thru_hole circle (at -3.81 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P2.str})
(pad 18 thru_hole circle (at -1.27 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P3.str})
(pad 19 thru_hole circle (at 1.27 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P4.str})
(pad 20 thru_hole circle (at 3.81 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P5.str})
(pad 21 thru_hole circle (at 6.35 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P6.str})
(pad 22 thru_hole circle (at 8.89 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P7.str})
(pad 23 thru_hole circle (at 11.43 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P8.str})
(pad 24 thru_hole circle (at 13.97 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P9.str})
(pad 13 thru_hole circle (at -13.97 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P1})
(pad 14 thru_hole circle (at -11.43 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P0})
(pad 15 thru_hole circle (at -8.89 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND})
(pad 16 thru_hole circle (at -6.35 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.GND})
(pad 17 thru_hole circle (at -3.81 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P2})
(pad 18 thru_hole circle (at -1.27 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P3})
(pad 19 thru_hole circle (at 1.27 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P4})
(pad 20 thru_hole circle (at 3.81 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P5})
(pad 21 thru_hole circle (at 6.35 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P6})
(pad 22 thru_hole circle (at 8.89 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P7})
(pad 23 thru_hole circle (at 11.43 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P8})
(pad 24 thru_hole circle (at 13.97 ${def_neg}7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) ${p.P9})
`
}
if(p.orientation == 'down') {

View file

@ -29,15 +29,15 @@ module.exports = {
(fp_poly (pts (xy 4 2.2) (xy 4 0.375) (xy 5 1.2875)) (layer ${p.side}.SilkS) (width 0.1))
(pad 1 smd rect (at -2.2 -0.875 ${p.rot}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.VCC.str})
(pad 2 smd rect (at -2.2 0.875 ${p.rot}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.dout.str})
(pad 3 smd rect (at 2.2 0.875 ${p.rot}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.GND.str})
(pad 4 smd rect (at 2.2 -0.875 ${p.rot}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.din.str})
(pad 1 smd rect (at -2.2 -0.875 ${p.r}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.VCC})
(pad 2 smd rect (at -2.2 0.875 ${p.r}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.dout})
(pad 3 smd rect (at 2.2 0.875 ${p.r}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.GND})
(pad 4 smd rect (at 2.2 -0.875 ${p.r}) (size 2.6 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.din})
(pad 11 smd rect (at -2.5 -1.6 ${p.rot}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.VCC.str})
(pad 22 smd rect (at -2.5 1.6 ${p.rot}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.dout.str})
(pad 33 smd rect (at 2.5 1.6 ${p.rot}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.GND.str})
(pad 44 smd rect (at 2.5 -1.6 ${p.rot}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.din.str})
(pad 11 smd rect (at -2.5 -1.6 ${p.r}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.VCC})
(pad 22 smd rect (at -2.5 1.6 ${p.r}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.dout})
(pad 33 smd rect (at 2.5 1.6 ${p.r}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.GND})
(pad 44 smd rect (at 2.5 -1.6 ${p.r}) (size 2 1.2) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.din})
)

View file

@ -56,15 +56,15 @@ module.exports = {
(fp_circle (center -0.12 -0.04) (end 2.88 -0.04) (layer F.Fab) (width 0.12))
${''/* pin names */}
(pad A thru_hole rect (at -7.62 -2.54 ${p.rot}) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.A.str})
(pad C thru_hole circle (at -7.62 -0.04) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.C.str})
(pad B thru_hole circle (at -7.62 2.46) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.B.str})
(pad 1 thru_hole circle (at 6.88 -2.54) (size 1.5 1.5) (drill 1) (layers *.Cu *.Mask) ${p.from.str})
(pad 2 thru_hole circle (at 6.88 2.46) (size 1.5 1.5) (drill 1) (layers *.Cu *.Mask) ${p.to.str})
(pad A thru_hole rect (at -7.62 -2.54 ${p.r}) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.A})
(pad C thru_hole circle (at -7.62 -0.04) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.C})
(pad B thru_hole circle (at -7.62 2.46) (size 2 2) (drill 1) (layers *.Cu *.Mask) ${p.B})
(pad 1 thru_hole circle (at 6.88 -2.54) (size 1.5 1.5) (drill 1) (layers *.Cu *.Mask) ${p.from})
(pad 2 thru_hole circle (at 6.88 2.46) (size 1.5 1.5) (drill 1) (layers *.Cu *.Mask) ${p.to})
${''/* Legs */}
(pad "" thru_hole rect (at -0.12 -5.64 ${p.rot}) (size 3.2 2) (drill oval 2.8 1.5) (layers *.Cu *.Mask))
(pad "" thru_hole rect (at -0.12 5.56 ${p.rot}) (size 3.2 2) (drill oval 2.8 1.5) (layers *.Cu *.Mask))
(pad "" thru_hole rect (at -0.12 -5.64 ${p.r}) (size 3.2 2) (drill oval 2.8 1.5) (layers *.Cu *.Mask))
(pad "" thru_hole rect (at -0.12 5.56 ${p.r}) (size 3.2 2) (drill oval 2.8 1.5) (layers *.Cu *.Mask))
)
`
}

View file

@ -35,8 +35,8 @@ module.exports = {
const standard = `
(module RollerEncoder_Panasonic_EVQWGD001 (layer F.Cu) (tedit 6040A10C)
${p.at /* parametric position */}
(fp_text reference REF** (at 0 0 ${p.rot}) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_text value RollerEncoder_Panasonic_EVQWGD001 (at -0.1 9 ${p.rot}) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_text reference REF** (at 0 0 ${p.r}) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_text value RollerEncoder_Panasonic_EVQWGD001 (at -0.1 9 ${p.r}) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
${'' /* corner marks */}
(fp_line (start -8.4 -6.4) (end 8.4 -6.4) (layer Dwgs.User) (width 0.12))
@ -57,15 +57,15 @@ module.exports = {
(fp_arc (start ${def_pos}9.5 -6.3) (end ${def_pos}9.8 -6.3) (angle ${def_neg}90) (layer Edge.Cuts) (width 0.15))
${'' /* pins */}
(pad S1 thru_hole circle (at ${def_neg}6.85 -6.2 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.from.str})
(pad S2 thru_hole circle (at ${def_neg}5 -6.2 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.to.str})
(pad A thru_hole circle (at ${def_neg}5.625 -3.81 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.A.str})
(pad B thru_hole circle (at ${def_neg}5.625 -1.27 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.B.str})
(pad C thru_hole circle (at ${def_neg}5.625 1.27 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.C.str})
(pad D thru_hole circle (at ${def_neg}5.625 3.81 ${p.rot}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.D.str})
(pad S1 thru_hole circle (at ${def_neg}6.85 -6.2 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.from})
(pad S2 thru_hole circle (at ${def_neg}5 -6.2 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.to})
(pad A thru_hole circle (at ${def_neg}5.625 -3.81 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.A})
(pad B thru_hole circle (at ${def_neg}5.625 -1.27 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.B})
(pad C thru_hole circle (at ${def_neg}5.625 1.27 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.C})
(pad D thru_hole circle (at ${def_neg}5.625 3.81 ${p.r}) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) ${p.D})
${'' /* stabilizer */}
(pad "" np_thru_hole circle (at ${def_neg}5.625 6.3 ${p.rot}) (size 1.5 1.5) (drill 1.5) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at ${def_neg}5.625 6.3 ${p.r}) (size 1.5 1.5) (drill 1.5) (layers *.Cu *.Mask))
`
}
if(p.reverse) {

View file

@ -38,15 +38,15 @@ module.exports = {
(pad "" np_thru_hole circle (at -1.5 0) (size 1 1) (drill 0.9) (layers *.Cu *.Mask))
${'' /* pins */}
(pad 1 smd rect (at ${right}2.25 2.075 ${p.rot}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from.str})
(pad 2 smd rect (at ${left}0.75 2.075 ${p.rot}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to.str})
(pad 3 smd rect (at ${left}2.25 2.075 ${p.rot}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad 1 smd rect (at ${right}2.25 2.075 ${p.r}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.from})
(pad 2 smd rect (at ${left}0.75 2.075 ${p.r}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask) ${p.to})
(pad 3 smd rect (at ${left}2.25 2.075 ${p.r}) (size 0.9 1.25) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
${'' /* side mounts */}
(pad "" smd rect (at 3.7 -1.1 ${p.rot}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at 3.7 1.1 ${p.rot}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at -3.7 1.1 ${p.rot}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at -3.7 -1.1 ${p.rot}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at 3.7 -1.1 ${p.r}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at 3.7 1.1 ${p.r}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at -3.7 1.1 ${p.r}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
(pad "" smd rect (at -3.7 -1.1 ${p.r}) (size 0.9 0.9) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask))
)
`

View file

@ -71,10 +71,10 @@ module.exports = {
}
function pins(def_neg, def_pos) {
return `
(pad 1 thru_hole oval (at ${def_neg} 11.3 ${p.rot}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.A.str})
(pad 2 thru_hole oval (at ${def_pos} 10.2 ${p.rot}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.B.str})
(pad 3 thru_hole oval (at ${def_pos} 6.2 ${p.rot}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.C.str})
(pad 4 thru_hole oval (at ${def_pos} 3.2 ${p.rot}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.D.str})
(pad 1 thru_hole oval (at ${def_neg} 11.3 ${p.r}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.A})
(pad 2 thru_hole oval (at ${def_pos} 10.2 ${p.r}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.B})
(pad 3 thru_hole oval (at ${def_pos} 6.2 ${p.r}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.C})
(pad 4 thru_hole oval (at ${def_pos} 3.2 ${p.r}) (size 1.6 2.2) (drill oval 0.9 1.5) (layers *.Cu *.Mask) ${p.D})
`
}
if(p.reverse & p.symmetric) {

View file

@ -14,7 +14,7 @@ module.exports = {
(fp_text value VIA-0.6mm (at 0 -1.4) (layer F.Fab) hide (effects (font (size 1 1) (thickness 0.15))))
${'' /* via */}
(pad 1 thru_hole circle (at 0 0) (size 0.6 0.6) (drill 0.3) (layers *.Cu) (zone_connect 2) ${p.net.str})
(pad 1 thru_hole circle (at 0 0) (size 0.6 0.6) (drill 0.3) (layers *.Cu) (zone_connect 2) ${p.net})
)
`
}

View file

@ -136,20 +136,15 @@ const whats = {
outline
}
const expand_shorthand = (config, units) => {
const expand_shorthand = (config, name, units) => {
if (a.type(config.expand)(units) == 'string') {
const prefix = config.expand.slice(0, -1)
const suffix = config.expand.slice(-1)
let expand = suffix
let joints = 0
if (suffix == ')') ; // noop
else if (suffix == '>') joints = 1
else if (suffix == ']') joints = 2
else expand = config.expand
config.expand = parseFloat(expand)
config.joints = config.joints || joints
const valid_suffixes = [')', '>', ']']
a.assert(valid_suffixes.includes(suffix), `If field "${name}" is a string, ` +
`it should end with one of [${valid_suffixes.map(s => `'${s}'`).join(', ')}]!`)
config.expand = prefix
config.joints = config.joints || valid_suffixes.indexOf(suffix)
}
if (a.type(config.joints)(units) == 'string') {
@ -159,7 +154,7 @@ const expand_shorthand = (config, units) => {
}
}
exports.parse = (config = {}, points = {}, units = {}) => {
exports.parse = (config, points, units) => {
// output outlines will be collected here
const outlines = {}
@ -199,9 +194,8 @@ exports.parse = (config = {}, points = {}, units = {}) => {
const where = units => filter(original_where, `${name}.where`, points, units, asym)
const original_adjust = part.adjust // same as above
const adjust = start => anchor(original_adjust || {}, `${name}.adjust`, points, start)(units)
const fillet = a.sane(part.fillet || 0, `${name}.fillet`, 'number')(units)
expand_shorthand(part, units)
expand_shorthand(part, `${name}.expand`, units)
const expand = a.sane(part.expand || 0, `${name}.expand`, 'number')(units)
const joints = a.in(a.sane(part.joints || 0, `${name}.joints`, 'number')(units), `${name}.joints`, [0, 1, 2])
const scale = a.sane(part.scale || 1, `${name}.scale`, 'number')(units)
@ -220,6 +214,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
// a prototype "shape" maker (and its units) are computed
const [shape_maker, shape_units] = whats[what](part, name, points, outlines, units)
const adjust = start => anchor(original_adjust || {}, `${name}.adjust`, points, start)(shape_units)
// and then the shape is repeated for all where positions
for (const w of where(shape_units)) {

View file

@ -1,4 +1,6 @@
const m = require('makerjs')
const yaml = require('js-yaml')
const u = require('./utils')
const a = require('./assert')
const prep = require('./prepare')
@ -115,7 +117,7 @@ const kicad_netclass = `
)
`
const makerjs2kicad = exports._makerjs2kicad = (model, layer='Edge.Cuts') => {
const makerjs2kicad = exports._makerjs2kicad = (model, layer) => {
const grs = []
const xy = val => `${val[0]} ${-val[1]}`
m.model.walk(model, {
@ -151,6 +153,24 @@ exports.inject_footprint = (name, fp) => {
footprint_types[name] = fp
}
const xy_obj = (x, y) => {
return {
x,
y,
str: `${x} ${y}`,
toString: function() { return this.str }
}
}
const net_obj = (name, index) => {
return {
name,
index,
str: `(net ${index} "${name}")`,
toString: function() { return this.str }
}
}
const footprint = exports._footprint = (points, net_indexer, component_indexer, units, extra) => (config, name, point) => {
// config sanitization
@ -169,7 +189,7 @@ const footprint = exports._footprint = (points, net_indexer, component_indexer,
params = prep.extend(params, mirror_overrides)
}
a.unexpected(params, `${name}.params`, Object.keys(fp.params))
// parsing parameters
const parsed_params = {}
for (const [param_name, param_def] of Object.entries(fp.params)) {
@ -183,40 +203,51 @@ const footprint = exports._footprint = (points, net_indexer, component_indexer,
parsed_def = {type: 'number', value: a.mathnum(param_def)(units)}
} else if (def_type == 'boolean') {
parsed_def = {type: 'boolean', value: param_def}
} else if (def_type == 'undefined') {
} else if (def_type == 'array') {
parsed_def = {type: 'array', value: param_def}
} else if (def_type == 'object') {
// parsed param definitions also expand to an object
// so to detect whether this is an arbitrary object,
// we first have to make sure it's not an expanded param def
// (this has to be a heuristic, but should be pretty reliable)
const defarr = Object.keys(param_def)
const already_expanded = defarr.length == 2 && defarr.includes('type') && defarr.includes('value')
if (!already_expanded) {
parsed_def = {type: 'object', value: param_def}
}
} else {
parsed_def = {type: 'net', value: undefined}
}
// combine default value with potential user override
let value = prep.extend(parsed_def.value, params[param_name])
let type = parsed_def.type
let value = params[param_name] !== undefined ? params[param_name] : parsed_def.value
const type = parsed_def.type
// templating support, with conversion back to raw datatypes
const converters = {
string: v => v,
number: v => a.sane(v, `${name}.params.${param_name}`, 'number')(units),
boolean: v => v === 'true',
array: v => yaml.load(v),
object: v => yaml.load(v),
net: v => v,
anchor: v => v
anchor: v => yaml.load(v)
}
a.in(type, `${name}.params.${param_name}.type`, Object.keys(converters))
if (a.type(value)() == 'string') {
value = u.template(value, point.meta)
value = converters[type](value)
}
// type-specific processing
if (['string', 'number', 'boolean'].includes(type)) {
// type-specific postprocessing
if (['string', 'number', 'boolean', 'array', 'object'].includes(type)) {
parsed_params[param_name] = value
} else if (type == 'net') {
const net = a.sane(value, `${name}.params.${param_name}`, 'string')(units)
const index = net_indexer(net)
parsed_params[param_name] = {
name: net,
index: index,
str: `(net ${index} "${net}")`
}
} else if (type == 'anchor') {
let parsed_anchor = anchor(value || {}, `${name}.params.${param_name}`, points, point)(units)
parsed_params[param_name] = net_obj(net, index)
} else { // anchor
let parsed_anchor = anchor(value, `${name}.params.${param_name}`, points, point)(units)
parsed_anchor.y = -parsed_anchor.y // kicad mirror, as per usual
parsed_params[param_name] = parsed_anchor
}
@ -227,31 +258,35 @@ const footprint = exports._footprint = (points, net_indexer, component_indexer,
parsed_params.ref_hide = extra.references ? '' : 'hide'
// footprint positioning
parsed_params.x = point.x
parsed_params.y = -point.y
parsed_params.r = point.r
parsed_params.rot = point.r // to be deprecated
parsed_params.xy = `${point.x} ${-point.y}`
parsed_params.at = `(at ${point.x} ${-point.y} ${point.r})`
parsed_params.rot = point.r
parsed_params.ixy = (x, y) => {
const sign = point.meta.mirrored ? -1 : 1
return `${sign * x} ${y}`
const internal_xyfunc = (x, y, resist) => {
const sign = resist ? 1 : (point.meta.mirrored ? -1 : 1)
return xy_obj(sign * x, y)
}
const xyfunc = (x, y, resist=true) => {
parsed_params.isxy = (x, y) => internal_xyfunc(x, y, false)
parsed_params.iaxy = (x, y) => internal_xyfunc(x, y, true)
const external_xyfunc = (x, y, resist) => {
const new_anchor = anchor({
shift: [x, -y],
resist: resist
}, '_internal_footprint_xy', points, point)(units)
return `${new_anchor.x} ${-new_anchor.y}`
return xy_obj(new_anchor.x, -new_anchor.y)
}
parsed_params.xy = (x, y) => xyfunc(x, y, true)
parsed_params.sxy = (x, y) => xyfunc(x, y, false)
parsed_params.esxy = (x, y) => external_xyfunc(x, y, false)
parsed_params.eaxy = (x, y) => external_xyfunc(x, y, true)
// allowing footprints to add dynamic nets
parsed_params.local_net = suffix => {
const net = `${component_ref}_${suffix}`
const index = net_indexer(net)
return {
name: net,
index: index,
str: `(net ${index} "${net}")`
}
return net_obj(net, index)
}
return fp.body(parsed_params)

View file

@ -76,4 +76,11 @@ module.exports = class Point {
const dy = other.y - this.y
return -Math.atan2(dx, dy) * (180 / Math.PI)
}
equals(other) {
return this.x === other.x
&& this.y === other.y
&& this.r === other.r
&& JSON.stringify(this.meta) === JSON.stringify(other.meta)
}
}

View file

@ -21,7 +21,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
a.unexpected(zone, `points.zones.${zone_name}`, ['columns', 'rows', 'key'])
// the anchor comes from "above", because it needs other zones too (for references)
const cols = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')()
const cols = zone.columns = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')()
const zone_wide_rows = a.sane(zone.rows || {}, `points.zones.${zone_name}.rows`, 'object')()
for (const [key, val] of Object.entries(zone_wide_rows)) {
zone_wide_rows[key] = val || {} // no check yet, as it will be extended later
@ -43,7 +43,6 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// column layout
const col_minmax = {}
if (!Object.keys(cols).length) {
cols.default = {}
}
@ -53,7 +52,6 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// column-level sanitization
col = col || {}
col_minmax[col_name] = {min: Infinity, max: -Infinity}
a.unexpected(
col,
@ -92,6 +90,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
orient: 0,
shift: [0, 0],
rotate: 0,
adjust: {},
width: units.$default_width,
height: units.$default_height,
padding: units.$default_padding,
@ -117,7 +116,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
key.col.name = col_name
key.row = row
key.stagger = a.sane(key.stagger, `${key.name}.shift`, 'number')(units)
key.stagger = a.sane(key.stagger, `${key.name}.stagger`, 'number')(units)
key.spread = a.sane(key.spread, `${key.name}.spread`, 'number')(units)
key.splay = a.sane(key.splay, `${key.name}.splay`, 'number')(units)
key.origin = a.xy(key.origin, `${key.name}.origin`)(units)
@ -168,83 +167,34 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// copy the current column anchor
let point = running_anchor.clone()
// apply per-key adjustments
// apply cumulative per-key adjustments
point.r += key.orient
point.shift(key.shift)
point.r += key.rotate
// commit running anchor
running_anchor = point.clone()
// apply independent adjustments
point = anchor_lib.parse(key.adjust, `${key.name}.adjust`, {}, point)(units)
// save new key
point.meta = key
points[key.name] = point
// collect minmax stats for autobind
col_minmax[col_name].min = Math.min(col_minmax[col_name].min, point.y)
col_minmax[col_name].max = Math.max(col_minmax[col_name].max, point.y)
// advance the running anchor to the next position
running_anchor = point.clone()
running_anchor.shift([0, key.padding])
}
first_col = false
}
// autobind
let col_names = Object.keys(col_minmax)
let col_index = 0
for (const [col_name, bounds] of Object.entries(col_minmax)) {
for (const point of Object.values(points)) {
if (point.meta.col.name != col_name) continue
if (!point.meta.autobind) continue
const autobind = a.sane(point.meta.autobind, `${point.meta.name}.autobind`, 'number')(units)
// specify default as -1, so we can recognize where it was left undefined even after number-ification
const bind = point.meta.bind = a.trbl(point.meta.bind, `${point.meta.name}.bind`, -1)(units)
// up
if (bind[0] == -1) {
if (point.y < bounds.max) bind[0] = autobind
else bind[0] = 0
}
// right
if (bind[1] == -1) {
bind[1] = 0
if (col_index < col_names.length - 1) {
const right = col_minmax[col_names[col_index + 1]]
if (point.y >= right.min && point.y <= right.max) {
bind[1] = autobind
}
}
}
// down
if (bind[2] == -1) {
if (point.y > bounds.min) bind[2] = autobind
else bind[2] = 0
}
// left
if (bind[3] == -1) {
bind[3] = 0
if (col_index > 0) {
const left = col_minmax[col_names[col_index - 1]]
if (point.y >= left.min && point.y <= left.max) {
bind[3] = autobind
}
}
}
}
col_index++
}
return points
}
const parse_axis = exports._parse_axis = (config, name, points, units) => {
if (!['number', 'undefined'].includes(a.type(config)(units))) {
const mirror_obj = a.sane(config || {}, name, 'object')()
const mirror_obj = a.sane(config, name, 'object')()
const distance = a.sane(mirror_obj.distance || 0, `${name}.distance`, 'number')(units)
delete mirror_obj.distance
let axis = anchor_lib.parse(mirror_obj, name, points)(units).x
@ -254,21 +204,91 @@ const parse_axis = exports._parse_axis = (config, name, points, units) => {
}
const perform_mirror = exports._perform_mirror = (point, axis) => {
if (axis !== undefined) {
point.meta.mirrored = false
if (point.meta.asym == 'source') return ['', null]
const mp = point.clone().mirror(axis)
const mirrored_name = `mirror_${point.meta.name}`
mp.meta = prep.extend(mp.meta, mp.meta.mirror || {})
mp.meta.name = mirrored_name
mp.meta.colrow = `mirror_${mp.meta.colrow}`
mp.meta.mirrored = true
if (point.meta.asym == 'clone') {
point.meta.skip = true
}
return [mirrored_name, mp]
point.meta.mirrored = false
if (point.meta.asym == 'source') return ['', null]
const mp = point.clone().mirror(axis)
const mirrored_name = `mirror_${point.meta.name}`
mp.meta = prep.extend(mp.meta, mp.meta.mirror || {})
mp.meta.name = mirrored_name
mp.meta.colrow = `mirror_${mp.meta.colrow}`
mp.meta.mirrored = true
if (point.meta.asym == 'clone') {
point.meta.skip = true
}
return [mirrored_name, mp]
}
const perform_autobind = exports._perform_autobind = (points, units) => {
const bounds = {}
const col_lists = {}
const mirrorzone = p => (p.meta.mirrored ? 'mirror_' : '') + p.meta.zone.name
// round one: get column upper/lower bounds and per-zone column lists
for (const p of Object.values(points)) {
const zone = mirrorzone(p)
const col = p.meta.col.name
if (!bounds[zone]) bounds[zone] = {}
if (!bounds[zone][col]) bounds[zone][col] = {min: Infinity, max: -Infinity}
if (!col_lists[zone]) col_lists[zone] = Object.keys(p.meta.zone.columns)
bounds[zone][col].min = Math.min(bounds[zone][col].min, p.y)
bounds[zone][col].max = Math.max(bounds[zone][col].max, p.y)
}
// round two: apply autobind as appropriate
for (const p of Object.values(points)) {
const autobind = a.sane(p.meta.autobind, `${p.meta.name}.autobind`, 'number')(units)
if (!autobind) continue
const zone = mirrorzone(p)
const col = p.meta.col.name
const col_list = col_lists[zone]
const col_bounds = bounds[zone][col]
// specify default as -1, so we can recognize where it was left undefined even after number-ification
const bind = p.meta.bind = a.trbl(p.meta.bind, `${p.meta.name}.bind`, -1)(units)
// up
if (bind[0] == -1) {
if (p.y < col_bounds.max) bind[0] = autobind
else bind[0] = 0
}
// down
if (bind[2] == -1) {
if (p.y > col_bounds.min) bind[2] = autobind
else bind[2] = 0
}
// left
if (bind[3] == -1) {
bind[3] = 0
const col_index = col_list.indexOf(col)
if (col_index > 0) {
const left = bounds[zone][col_list[col_index - 1]]
if (left && p.y >= left.min && p.y <= left.max) {
bind[3] = autobind
}
}
}
// right
if (bind[1] == -1) {
bind[1] = 0
const col_index = col_list.indexOf(col)
if (col_index < col_list.length - 1) {
const right = bounds[zone][col_list[col_index + 1]]
if (right && p.y >= right.min && p.y <= right.max) {
bind[1] = autobind
}
}
}
}
return ['', null]
}
exports.parse = (config, units) => {
@ -300,13 +320,11 @@ exports.parse = (config, units) => {
// simplifying the names in individual point "zones" and single-key columns
while (Object.keys(new_points).some(k => k.endsWith('_default'))) {
for (const key of Object.keys(new_points)) {
if (key.endsWith('_default')) {
const new_key = key.slice(0, -8)
new_points[new_key] = new_points[key]
new_points[new_key].meta.name = new_key
delete new_points[key]
}
for (const key of Object.keys(new_points).filter(k => k.endsWith('_default'))) {
const new_key = key.slice(0, -8)
new_points[new_key] = new_points[key]
new_points[new_key].meta.name = new_key
delete new_points[key]
}
}
@ -352,7 +370,7 @@ exports.parse = (config, units) => {
const global_axis = parse_axis(global_mirror, `points.mirror`, points, units)
const global_mirrored_points = {}
for (const point of Object.values(points)) {
if (global_axis !== undefined && point.mirrored === undefined) {
if (global_axis !== undefined && point.meta.mirrored === undefined) {
const [mname, mp] = perform_mirror(point, global_axis)
if (mp) {
global_mirrored_points[mname] = mp
@ -368,6 +386,9 @@ exports.parse = (config, units) => {
filtered[k] = p
}
// apply autobind
perform_autobind(filtered, units)
// done
return filtered
}

View file

@ -42,11 +42,14 @@ const traverse = exports.traverse = (config, root, breadcrumbs, op) => {
}
return result
} else if (a.type(config)() == 'array') {
// needed so that arrays can set output the same way as objects within ops
const dummy = {}
const result = []
let index = 0
for (const val of config) {
breadcrumbs.push(`[${index}]`)
result[index] = traverse(val, root, breadcrumbs, op)
op(dummy, 'dummykey', traverse(val, root, breadcrumbs, op), root, breadcrumbs)
result[index] = dummy.dummykey
breadcrumbs.pop()
index++
}

View file

@ -23,7 +23,7 @@ exports.template = (str, vals={}) => {
let res = str
let shift = 0
for (const match of str.matchAll(regex)) {
const replacement = deep(vals, match[1]) || ''
const replacement = (deep(vals, match[1]) || '') + ''
res = res.substring(0, match.index + shift)
+ replacement
+ res.substring(match.index + shift + match[0].length)

View file

@ -1,4 +1,4 @@
function square_outline_fn(){
function square_extrude_5_outline_fn(){
return new CSG.Path2D([[-2.5,-2.5],[2.5,-2.5]]).appendPoint([2.5,2.5]).appendPoint([-2.5,2.5]).appendPoint([-2.5,-2.5]).close().innerToCAG()
.extrude({ offset: [0, 0, 5] });
}
@ -10,7 +10,7 @@ function square_outline_fn(){
// creating part 0 of case cube
let cube__part_0 = square_outline_fn();
let cube__part_0 = square_extrude_5_outline_fn();
// make sure that rotations are relative
let cube__part_0_bounds = cube__part_0.getBounds();

View file

@ -0,0 +1,36 @@
points.zones.matrix: {}
outlines:
_square:
- what: rectangle
where: true
size: [8, 8]
_circle:
- what: circle
where: true
radius: 3
cases:
_cube:
- name: _square
extrude: 8
_cylinder_one:
- name: _circle
extrude: 8
_subtract:
target:
name: _cube
what: case
tool:
name: _cylinder_one
what: case
operation: subtract
_cylinder_two:
- name: _circle
extrude: 8
shift: [0,4,4]
rotate: [90,0,0]
_flat_square:
- "_square"
combination:
- "_subtract"
- "~_cylinder_two"
- "+_flat_square"

View file

@ -0,0 +1,211 @@
function _square_extrude_8_outline_fn(){
return new CSG.Path2D([[-4,-4],[4,-4]]).appendPoint([4,4]).appendPoint([-4,4]).appendPoint([-4,-4]).close().innerToCAG()
.extrude({ offset: [0, 0, 8] });
}
function _circle_extrude_8_outline_fn(){
return CAG.circle({"center":[0,0],"radius":3})
.extrude({ offset: [0, 0, 8] });
}
function _square_extrude_1_outline_fn(){
return new CSG.Path2D([[-4,-4],[4,-4]]).appendPoint([4,4]).appendPoint([-4,4]).appendPoint([-4,-4]).close().innerToCAG()
.extrude({ offset: [0, 0, 1] });
}
function _subtract_case_fn() {
// creating part target of case _subtract
let _subtract__part_target = _cube_case_fn();
// make sure that rotations are relative
let _subtract__part_target_bounds = _subtract__part_target.getBounds();
let _subtract__part_target_x = _subtract__part_target_bounds[0].x + (_subtract__part_target_bounds[1].x - _subtract__part_target_bounds[0].x) / 2
let _subtract__part_target_y = _subtract__part_target_bounds[0].y + (_subtract__part_target_bounds[1].y - _subtract__part_target_bounds[0].y) / 2
_subtract__part_target = translate([-_subtract__part_target_x, -_subtract__part_target_y, 0], _subtract__part_target);
_subtract__part_target = rotate([0,0,0], _subtract__part_target);
_subtract__part_target = translate([_subtract__part_target_x, _subtract__part_target_y, 0], _subtract__part_target);
_subtract__part_target = translate([0,0,0], _subtract__part_target);
let result = _subtract__part_target;
// creating part tool of case _subtract
let _subtract__part_tool = _cylinder_one_case_fn();
// make sure that rotations are relative
let _subtract__part_tool_bounds = _subtract__part_tool.getBounds();
let _subtract__part_tool_x = _subtract__part_tool_bounds[0].x + (_subtract__part_tool_bounds[1].x - _subtract__part_tool_bounds[0].x) / 2
let _subtract__part_tool_y = _subtract__part_tool_bounds[0].y + (_subtract__part_tool_bounds[1].y - _subtract__part_tool_bounds[0].y) / 2
_subtract__part_tool = translate([-_subtract__part_tool_x, -_subtract__part_tool_y, 0], _subtract__part_tool);
_subtract__part_tool = rotate([0,0,0], _subtract__part_tool);
_subtract__part_tool = translate([_subtract__part_tool_x, _subtract__part_tool_y, 0], _subtract__part_tool);
_subtract__part_tool = translate([0,0,0], _subtract__part_tool);
result = result.subtract(_subtract__part_tool);
return result;
}
function _cube_case_fn() {
// creating part 0 of case _cube
let _cube__part_0 = _square_extrude_8_outline_fn();
// make sure that rotations are relative
let _cube__part_0_bounds = _cube__part_0.getBounds();
let _cube__part_0_x = _cube__part_0_bounds[0].x + (_cube__part_0_bounds[1].x - _cube__part_0_bounds[0].x) / 2
let _cube__part_0_y = _cube__part_0_bounds[0].y + (_cube__part_0_bounds[1].y - _cube__part_0_bounds[0].y) / 2
_cube__part_0 = translate([-_cube__part_0_x, -_cube__part_0_y, 0], _cube__part_0);
_cube__part_0 = rotate([0,0,0], _cube__part_0);
_cube__part_0 = translate([_cube__part_0_x, _cube__part_0_y, 0], _cube__part_0);
_cube__part_0 = translate([0,0,0], _cube__part_0);
let result = _cube__part_0;
return result;
}
function _cylinder_one_case_fn() {
// creating part 0 of case _cylinder_one
let _cylinder_one__part_0 = _circle_extrude_8_outline_fn();
// make sure that rotations are relative
let _cylinder_one__part_0_bounds = _cylinder_one__part_0.getBounds();
let _cylinder_one__part_0_x = _cylinder_one__part_0_bounds[0].x + (_cylinder_one__part_0_bounds[1].x - _cylinder_one__part_0_bounds[0].x) / 2
let _cylinder_one__part_0_y = _cylinder_one__part_0_bounds[0].y + (_cylinder_one__part_0_bounds[1].y - _cylinder_one__part_0_bounds[0].y) / 2
_cylinder_one__part_0 = translate([-_cylinder_one__part_0_x, -_cylinder_one__part_0_y, 0], _cylinder_one__part_0);
_cylinder_one__part_0 = rotate([0,0,0], _cylinder_one__part_0);
_cylinder_one__part_0 = translate([_cylinder_one__part_0_x, _cylinder_one__part_0_y, 0], _cylinder_one__part_0);
_cylinder_one__part_0 = translate([0,0,0], _cylinder_one__part_0);
let result = _cylinder_one__part_0;
return result;
}
function _cylinder_two_case_fn() {
// creating part 0 of case _cylinder_two
let _cylinder_two__part_0 = _circle_extrude_8_outline_fn();
// make sure that rotations are relative
let _cylinder_two__part_0_bounds = _cylinder_two__part_0.getBounds();
let _cylinder_two__part_0_x = _cylinder_two__part_0_bounds[0].x + (_cylinder_two__part_0_bounds[1].x - _cylinder_two__part_0_bounds[0].x) / 2
let _cylinder_two__part_0_y = _cylinder_two__part_0_bounds[0].y + (_cylinder_two__part_0_bounds[1].y - _cylinder_two__part_0_bounds[0].y) / 2
_cylinder_two__part_0 = translate([-_cylinder_two__part_0_x, -_cylinder_two__part_0_y, 0], _cylinder_two__part_0);
_cylinder_two__part_0 = rotate([90,0,0], _cylinder_two__part_0);
_cylinder_two__part_0 = translate([_cylinder_two__part_0_x, _cylinder_two__part_0_y, 0], _cylinder_two__part_0);
_cylinder_two__part_0 = translate([0,4,4], _cylinder_two__part_0);
let result = _cylinder_two__part_0;
return result;
}
function _flat_square_case_fn() {
// creating part 0 of case _flat_square
let _flat_square__part_0 = _square_extrude_1_outline_fn();
// make sure that rotations are relative
let _flat_square__part_0_bounds = _flat_square__part_0.getBounds();
let _flat_square__part_0_x = _flat_square__part_0_bounds[0].x + (_flat_square__part_0_bounds[1].x - _flat_square__part_0_bounds[0].x) / 2
let _flat_square__part_0_y = _flat_square__part_0_bounds[0].y + (_flat_square__part_0_bounds[1].y - _flat_square__part_0_bounds[0].y) / 2
_flat_square__part_0 = translate([-_flat_square__part_0_x, -_flat_square__part_0_y, 0], _flat_square__part_0);
_flat_square__part_0 = rotate([0,0,0], _flat_square__part_0);
_flat_square__part_0 = translate([_flat_square__part_0_x, _flat_square__part_0_y, 0], _flat_square__part_0);
_flat_square__part_0 = translate([0,0,0], _flat_square__part_0);
let result = _flat_square__part_0;
return result;
}
function combination_case_fn() {
// creating part 0 of case combination
let combination__part_0 = _subtract_case_fn();
// make sure that rotations are relative
let combination__part_0_bounds = combination__part_0.getBounds();
let combination__part_0_x = combination__part_0_bounds[0].x + (combination__part_0_bounds[1].x - combination__part_0_bounds[0].x) / 2
let combination__part_0_y = combination__part_0_bounds[0].y + (combination__part_0_bounds[1].y - combination__part_0_bounds[0].y) / 2
combination__part_0 = translate([-combination__part_0_x, -combination__part_0_y, 0], combination__part_0);
combination__part_0 = rotate([0,0,0], combination__part_0);
combination__part_0 = translate([combination__part_0_x, combination__part_0_y, 0], combination__part_0);
combination__part_0 = translate([0,0,0], combination__part_0);
let result = combination__part_0;
// creating part 1 of case combination
let combination__part_1 = _cylinder_two_case_fn();
// make sure that rotations are relative
let combination__part_1_bounds = combination__part_1.getBounds();
let combination__part_1_x = combination__part_1_bounds[0].x + (combination__part_1_bounds[1].x - combination__part_1_bounds[0].x) / 2
let combination__part_1_y = combination__part_1_bounds[0].y + (combination__part_1_bounds[1].y - combination__part_1_bounds[0].y) / 2
combination__part_1 = translate([-combination__part_1_x, -combination__part_1_y, 0], combination__part_1);
combination__part_1 = rotate([0,0,0], combination__part_1);
combination__part_1 = translate([combination__part_1_x, combination__part_1_y, 0], combination__part_1);
combination__part_1 = translate([0,0,0], combination__part_1);
result = result.intersect(combination__part_1);
// creating part 2 of case combination
let combination__part_2 = _flat_square_case_fn();
// make sure that rotations are relative
let combination__part_2_bounds = combination__part_2.getBounds();
let combination__part_2_x = combination__part_2_bounds[0].x + (combination__part_2_bounds[1].x - combination__part_2_bounds[0].x) / 2
let combination__part_2_y = combination__part_2_bounds[0].y + (combination__part_2_bounds[1].y - combination__part_2_bounds[0].y) / 2
combination__part_2 = translate([-combination__part_2_x, -combination__part_2_y, 0], combination__part_2);
combination__part_2 = rotate([0,0,0], combination__part_2);
combination__part_2 = translate([combination__part_2_x, combination__part_2_y, 0], combination__part_2);
combination__part_2 = translate([0,0,0], combination__part_2);
result = result.union(combination__part_2);
return result;
}
function main() {
return combination_case_fn();
}

View file

@ -1,4 +1,4 @@
function export_outline_fn(){
function export_extrude_1_outline_fn(){
return new CSG.Path2D([[-9,-9],[9,-9]]).appendPoint([9,9]).appendPoint([-9,9]).appendPoint([-9,-9]).close().innerToCAG()
.extrude({ offset: [0, 0, 1] });
}
@ -10,7 +10,7 @@ function export_outline_fn(){
// creating part 0 of case _export
let _export__part_0 = export_outline_fn();
let _export__part_0 = export_extrude_1_outline_fn();
// make sure that rotations are relative
let _export__part_0_bounds = _export__part_0.getBounds();

View file

@ -1,4 +1,4 @@
function export_outline_fn(){
function export_extrude_1_outline_fn(){
return new CSG.Path2D([[-9,-9],[9,-9]]).appendPoint([9,9]).appendPoint([-9,9]).appendPoint([-9,-9]).close().innerToCAG()
.extrude({ offset: [0, 0, 1] });
}
@ -10,7 +10,7 @@ function export_outline_fn(){
// creating part 0 of case export
let export__part_0 = export_outline_fn();
let export__part_0 = export_extrude_1_outline_fn();
// make sure that rotations are relative
let export__part_0_bounds = export__part_0.getBounds();

View file

@ -5,8 +5,8 @@
(page A3)
(title_block
(title _export)
(rev v1.0.0)
(company Unknown)
(rev v3.14)
(company MrZealot)
)
(general

View file

@ -5,8 +5,8 @@
(page A3)
(title_block
(title export)
(rev v1.0.0)
(company Unknown)
(rev v3.14)
(company MrZealot)
)
(general

View file

@ -14,6 +14,7 @@ matrix:
- 0
- 0
rotate: 0
adjust: {}
width: 18
height: 18
padding: 19
@ -23,6 +24,11 @@ matrix:
colrow: default_default
name: matrix
zone:
columns:
default:
rows: {}
key: {}
name: default
name: matrix
col:
rows: {}

View file

@ -1,3 +1,6 @@
meta:
author: MrZealot
version: v3.14
units:
a: 28 + u
points:

View file

@ -1,3 +1,6 @@
meta:
author: MrZealot
version: v3.14
units:
a: 28 + u
points.zones.matrix:

View file

@ -14,6 +14,7 @@ matrix_col_row:
- 0
- 0
rotate: 0
adjust: {}
width: 18
height: 18
padding: 19
@ -24,14 +25,17 @@ matrix_col_row:
name: matrix_col_row
zone:
columns:
col: &ref_0
col:
rows: {}
key: {}
name: col
rows:
row: {}
name: matrix
col: *ref_0
col:
rows: {}
key: {}
name: col
row: row
bind:
- 0

View file

@ -1,3 +1,6 @@
meta:
author: MrZealot
version: v3.14
units:
a: 28 + u
points.zones.matrix:

15
test/fixtures/minimal_kle.json vendored Normal file
View file

@ -0,0 +1,15 @@
[
[
"0_0",
"0_1"
],
[
"1_0",
"1_1"
],
[
"",
""
]
]

View file

@ -38,4 +38,14 @@ pcbs.pcb.footprints:
to: to
reverse: true
hotswap: true
adjust.shift: [200, 0]
adjust.shift: [200, 0]
# all of keycaps, reverse and hotswap
- what: choc
params:
from: from
to: to
keycaps: true
reverse: true
hotswap: true
adjust.shift: [250, 0]

View file

@ -284,6 +284,58 @@
(pad "" np_thru_hole circle (at 5 -3.75) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 0 -5.95) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad 1 smd rect (at -3.275 -5.95 0) (size 2.6 2.6) (layers B.Cu B.Paste B.Mask) (net 1 "from"))
(pad 2 smd rect (at 8.275 -3.75 0) (size 2.6 2.6) (layers B.Cu B.Paste B.Mask) (net 2 "to"))
(pad "" np_thru_hole circle (at -5 -3.75) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 0 -5.95) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad 1 smd rect (at 3.275 -5.95 0) (size 2.6 2.6) (layers F.Cu F.Paste F.Mask) (net 1 "from"))
(pad 2 smd rect (at -8.275 -3.75 0) (size 2.6 2.6) (layers F.Cu F.Paste F.Mask) (net 2 "to"))
)
(module PG1350 (layer F.Cu) (tedit 5DD50112)
(at 250 0 0)
(fp_text reference "S6" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value "" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_line (start -7 -6) (end -7 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start -7 7) (end -6 7) (layer Dwgs.User) (width 0.15))
(fp_line (start -6 -7) (end -7 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start -7 7) (end -7 6) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 6) (end 7 7) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 -7) (end 6 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start 6 7) (end 7 7) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 -7) (end 7 -6) (layer Dwgs.User) (width 0.15))
(pad "" np_thru_hole circle (at 0 0) (size 3.429 3.429) (drill 3.429) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 5.5 0) (size 1.7018 1.7018) (drill 1.7018) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at -5.5 0) (size 1.7018 1.7018) (drill 1.7018) (layers *.Cu *.Mask))
(fp_line (start -9 -8.5) (end 9 -8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9 -8.5) (end 9 8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9 8.5) (end -9 8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start -9 8.5) (end -9 -8.5) (layer Dwgs.User) (width 0.15))
(pad "" np_thru_hole circle (at 5 -3.75) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 0 -5.95) (size 3 3) (drill 3) (layers *.Cu *.Mask))

View file

@ -22,3 +22,12 @@ pcbs.pcb.footprints:
to: to
reverse: true
adjust.shift: [100, 0]
# reverse with keycap visualization
- what: chocmini
params:
from: from
to: to
keycaps: true
reverse: true
adjust.shift: [150, 0]

View file

@ -267,6 +267,67 @@
)
(module lib:Kailh_PG1232 (layer F.Cu) (tedit 5E1ADAC2)
(at 150 0 0)
(fp_text reference "S4" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value Kailh_PG1232 (at 0 -7.3) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_line (start -7.25 -6.75) (end -6.25 -6.75) (layer Dwgs.User) (width 0.15))
(fp_line (start -7.25 -6.75) (end -7.25 -5.75) (layer Dwgs.User) (width 0.15))
(fp_line (start -7.25 6.75) (end -6.25 6.75) (layer Dwgs.User) (width 0.15))
(fp_line (start -7.25 6.75) (end -7.25 5.75) (layer Dwgs.User) (width 0.15))
(fp_line (start 7.25 -6.75) (end 6.25 -6.75) (layer Dwgs.User) (width 0.15))
(fp_line (start 7.25 -6.75) (end 7.25 -5.75) (layer Dwgs.User) (width 0.15))
(fp_line (start 7.25 6.75) (end 6.25 6.75) (layer Dwgs.User) (width 0.15))
(fp_line (start 7.25 6.75) (end 7.25 5.75) (layer Dwgs.User) (width 0.15))
(fp_line (start 2.8 -5.35) (end -2.8 -5.35) (layer Dwgs.User) (width 0.15))
(fp_line (start -2.8 -3.2) (end 2.8 -3.2) (layer Dwgs.User) (width 0.15))
(fp_line (start 2.8 -3.2) (end 2.8 -5.35) (layer Dwgs.User) (width 0.15))
(fp_line (start -2.8 -3.2) (end -2.8 -5.35) (layer Dwgs.User) (width 0.15))
(fp_line (start 2.25 2.6) (end 5.8 2.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start -2.25 2.6) (end -5.8 2.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start 2.25 3.6) (end 2.25 2.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start -2.25 3.6) (end 2.25 3.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start -2.25 2.6) (end -2.25 3.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start -5.8 2.6) (end -5.8 -2.95) (layer Edge.Cuts) (width 0.12))
(fp_line (start 5.8 -2.95) (end 5.8 2.6) (layer Edge.Cuts) (width 0.12))
(fp_line (start -5.8 -2.95) (end 5.8 -2.95) (layer Edge.Cuts) (width 0.12))
(pad 3 thru_hole circle (at 5.3 -4.75) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (clearance 0.2))
(pad 4 thru_hole circle (at -5.3 -4.75) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (clearance 0.2))
(fp_line (start -9 -8.5) (end 9 -8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9 -8.5) (end 9 8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9 8.5) (end -9 8.5) (layer Dwgs.User) (width 0.15))
(fp_line (start -9 8.5) (end -9 -8.5) (layer Dwgs.User) (width 0.15))
(pad 1 thru_hole circle (at -4.58 5.1) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (net 1 "from") (clearance 0.2))
(pad 2 thru_hole circle (at 2 5.4) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (net 2 "to") (clearance 0.2))
(pad 1 thru_hole circle (at 4.58 5.1) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (net 1 "from") (clearance 0.2))
(pad 2 thru_hole circle (at -2 5.4) (size 1.6 1.6) (drill 1.1) (layers *.Cu *.Mask) (net 2 "to") (clearance 0.2))
)
)

View file

@ -38,4 +38,14 @@ pcbs.pcb.footprints:
to: to
reverse: true
hotswap: true
adjust.shift: [200, 0]
adjust.shift: [200, 0]
# all of keycaps, reverse and hotswap
- what: mx
params:
from: from
to: to
keycaps: true
reverse: true
hotswap: true
adjust.shift: [250, 0]

View file

@ -284,6 +284,58 @@
(pad "" np_thru_hole circle (at 2.54 -5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at -3.81 -2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad 1 smd rect (at -7.085 -2.54 0) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask) (net 1 "from"))
(pad 2 smd rect (at 5.842 -5.08 0) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask) (net 2 "to"))
(pad "" np_thru_hole circle (at -2.54 -5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 3.81 -2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad 1 smd rect (at 7.085 -2.54 0) (size 2.55 2.5) (layers F.Cu F.Paste F.Mask) (net 1 "from"))
(pad 2 smd rect (at -5.842 -5.08 0) (size 2.55 2.5) (layers F.Cu F.Paste F.Mask) (net 2 "to"))
)
(module MX (layer F.Cu) (tedit 5DD4F656)
(at 250 0 0)
(fp_text reference "S6" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value "" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_line (start -7 -6) (end -7 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start -7 7) (end -6 7) (layer Dwgs.User) (width 0.15))
(fp_line (start -6 -7) (end -7 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start -7 7) (end -7 6) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 6) (end 7 7) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 -7) (end 6 -7) (layer Dwgs.User) (width 0.15))
(fp_line (start 6 7) (end 7 7) (layer Dwgs.User) (width 0.15))
(fp_line (start 7 -7) (end 7 -6) (layer Dwgs.User) (width 0.15))
(pad "" np_thru_hole circle (at 0 0) (size 3.9878 3.9878) (drill 3.9878) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at 5.08 0) (size 1.7018 1.7018) (drill 1.7018) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at -5.08 0) (size 1.7018 1.7018) (drill 1.7018) (layers *.Cu *.Mask))
(fp_line (start -9.5 -9.5) (end 9.5 -9.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9.5 -9.5) (end 9.5 9.5) (layer Dwgs.User) (width 0.15))
(fp_line (start 9.5 9.5) (end -9.5 9.5) (layer Dwgs.User) (width 0.15))
(fp_line (start -9.5 9.5) (end -9.5 -9.5) (layer Dwgs.User) (width 0.15))
(pad "" np_thru_hole circle (at 2.54 -5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at -3.81 -2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))

View file

@ -25,3 +25,17 @@ pcbs.pcb.footprints:
align: down
mirrored: true
adjust.shift: [50, 50]
- what: pad
params:
net: net
align: right
mirrored: true
adjust.shift: [100, 0]
- what: pad
params:
net: net
align: left
mirrored: true
adjust.shift: [100, 50]

View file

@ -181,6 +181,44 @@
)
(module SMDPad (layer F.Cu) (tedit 5B24D78E)
(at 100 0 0)
(fp_text reference "PAD5" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value "" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask) (net 1 "net"))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers B.Cu B.Paste B.Mask) (net 1 "net"))
)
(module SMDPad (layer F.Cu) (tedit 5B24D78E)
(at 100 -50 0)
(fp_text reference "PAD6" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value "" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask) (net 1 "net"))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers B.Cu B.Paste B.Mask) (net 1 "net"))
)
)

View file

@ -64,4 +64,22 @@ pcbs.pcb.footprints:
- what: via
params:
net: net
adjust.shift: [0, 150]
adjust.shift: [0, 150]
- what: scrollwheel
params:
from: from
to: to
A: A
B: B
C: C
D: D
reverse: true
adjust.shift: [50, 150]
- what: slider
params:
from: from
to: to
side: B
adjust.shift: [100, 150]

View file

@ -424,6 +424,104 @@
(pad 1 thru_hole circle (at 0 0) (size 0.6 0.6) (drill 0.3) (layers *.Cu) (zone_connect 2) (net 15 "net"))
)
(module RollerEncoder_Panasonic_EVQWGD001 (layer F.Cu) (tedit 6040A10C)
(at 50 -150 0)
(fp_text reference REF** (at 0 0 0) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_text value RollerEncoder_Panasonic_EVQWGD001 (at -0.1 9 0) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))))
(fp_line (start -8.4 -6.4) (end 8.4 -6.4) (layer Dwgs.User) (width 0.12))
(fp_line (start 8.4 -6.4) (end 8.4 7.4) (layer Dwgs.User) (width 0.12))
(fp_line (start 8.4 7.4) (end -8.4 7.4) (layer Dwgs.User) (width 0.12))
(fp_line (start -8.4 7.4) (end -8.4 -6.4) (layer Dwgs.User) (width 0.12))
(fp_line (start 9.8 7.3) (end 9.8 -6.3) (layer Edge.Cuts) (width 0.15))
(fp_line (start 7.4 -6.3) (end 7.4 7.3) (layer Edge.Cuts) (width 0.15))
(fp_line (start 9.5 -6.6) (end 7.7 -6.6) (layer Edge.Cuts) (width 0.15))
(fp_line (start 7.7 7.6) (end 9.5 7.6) (layer Edge.Cuts) (width 0.15))
(fp_arc (start 7.7 7.3) (end 7.4 7.3) (angle -90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start 9.5 7.3) (end 9.5 7.6) (angle -90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start 7.7 -6.3) (end 7.7 -6.6) (angle -90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start 9.5 -6.3) (end 9.8 -6.3) (angle -90) (layer Edge.Cuts) (width 0.15))
(pad S1 thru_hole circle (at -6.85 -6.2 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 1 "from"))
(pad S2 thru_hole circle (at -5 -6.2 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 2 "to"))
(pad A thru_hole circle (at -5.625 -3.81 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 11 "A"))
(pad B thru_hole circle (at -5.625 -1.27 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 12 "B"))
(pad C thru_hole circle (at -5.625 1.27 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 13 "C"))
(pad D thru_hole circle (at -5.625 3.81 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 14 "D"))
(pad "" np_thru_hole circle (at -5.625 6.3 0) (size 1.5 1.5) (drill 1.5) (layers *.Cu *.Mask))
(fp_line (start -9.8 7.3) (end -9.8 -6.3) (layer Edge.Cuts) (width 0.15))
(fp_line (start -7.4 -6.3) (end -7.4 7.3) (layer Edge.Cuts) (width 0.15))
(fp_line (start -9.5 -6.6) (end -7.7 -6.6) (layer Edge.Cuts) (width 0.15))
(fp_line (start -7.7 7.6) (end -9.5 7.6) (layer Edge.Cuts) (width 0.15))
(fp_arc (start -7.7 7.3) (end -7.4 7.3) (angle 90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start -9.5 7.3) (end -9.5 7.6) (angle 90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start -7.7 -6.3) (end -7.7 -6.6) (angle 90) (layer Edge.Cuts) (width 0.15))
(fp_arc (start -9.5 -6.3) (end -9.8 -6.3) (angle 90) (layer Edge.Cuts) (width 0.15))
(pad S1 thru_hole circle (at 6.85 -6.2 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 1 "from"))
(pad S2 thru_hole circle (at 5 -6.2 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 2 "to"))
(pad A thru_hole circle (at 5.625 -3.81 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 11 "A"))
(pad B thru_hole circle (at 5.625 -1.27 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 12 "B"))
(pad C thru_hole circle (at 5.625 1.27 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 13 "C"))
(pad D thru_hole circle (at 5.625 3.81 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (net 14 "D"))
(pad "" np_thru_hole circle (at 5.625 6.3 0) (size 1.5 1.5) (drill 1.5) (layers *.Cu *.Mask))
)
(module E73:SPDT_C128955 (layer F.Cu) (tstamp 5BF2CC3C)
(at 100 -150 0)
(fp_text reference "T2" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_text value "" (at 0 0) (layer F.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))
(fp_line (start 1.95 -1.35) (end -1.95 -1.35) (layer B.SilkS) (width 0.15))
(fp_line (start 0 -1.35) (end -3.3 -1.35) (layer B.SilkS) (width 0.15))
(fp_line (start -3.3 -1.35) (end -3.3 1.5) (layer B.SilkS) (width 0.15))
(fp_line (start -3.3 1.5) (end 3.3 1.5) (layer B.SilkS) (width 0.15))
(fp_line (start 3.3 1.5) (end 3.3 -1.35) (layer B.SilkS) (width 0.15))
(fp_line (start 0 -1.35) (end 3.3 -1.35) (layer B.SilkS) (width 0.15))
(fp_line (start -1.95 -3.85) (end 1.95 -3.85) (layer Dwgs.User) (width 0.15))
(fp_line (start 1.95 -3.85) (end 1.95 -1.35) (layer Dwgs.User) (width 0.15))
(fp_line (start -1.95 -1.35) (end -1.95 -3.85) (layer Dwgs.User) (width 0.15))
(pad "" np_thru_hole circle (at 1.5 0) (size 1 1) (drill 0.9) (layers *.Cu *.Mask))
(pad "" np_thru_hole circle (at -1.5 0) (size 1 1) (drill 0.9) (layers *.Cu *.Mask))
(pad 1 smd rect (at -2.25 2.075 0) (size 0.9 1.25) (layers B.Cu B.Paste B.Mask) (net 1 "from"))
(pad 2 smd rect (at 0.75 2.075 0) (size 0.9 1.25) (layers B.Cu B.Paste B.Mask) (net 2 "to"))
(pad 3 smd rect (at 2.25 2.075 0) (size 0.9 1.25) (layers B.Cu B.Paste B.Mask))
(pad "" smd rect (at 3.7 -1.1 0) (size 0.9 0.9) (layers B.Cu B.Paste B.Mask))
(pad "" smd rect (at 3.7 1.1 0) (size 0.9 0.9) (layers B.Cu B.Paste B.Mask))
(pad "" smd rect (at -3.7 1.1 0) (size 0.9 0.9) (layers B.Cu B.Paste B.Mask))
(pad "" smd rect (at -3.7 -1.1 0) (size 0.9 0.9) (layers B.Cu B.Paste B.Mask))
)
)

View file

@ -3,6 +3,7 @@ exports.inject = (ergogen) => {
params: {
designator: 'T',
side: 'F',
width: 0.25,
P1: {type: 'net', value: 'P1'}
},
body: p => {
@ -12,15 +13,15 @@ exports.inject = (ergogen) => {
${p.at /* parametric position */}
(pad 1 smd rect (at ${p.ixy(0, 0)} ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1.str} (solder_mask_margin 0.2))
(pad 1 smd rect (at ${p.isxy(0, 0)} ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1} (solder_mask_margin 0.2))
(pad 2 smd rect (at ${p.ixy(5, 5)} ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1.str} (solder_mask_margin 0.2))
(pad 2 smd rect (at ${p.isxy(5, 5)} ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1} (solder_mask_margin 0.2))
)
(segment (start ${p.sxy(0, 0)}) (end ${p.sxy(5, 5)}) (width 0.25) (layer ${p.side}.Cu) (net ${p.P1.index}))
(segment (start ${p.esxy(0, 0)}) (end ${p.esxy(5, 5)}) (width ${p.width}) (layer ${p.side}.Cu) (net ${p.P1.index}))
`
}
@ -39,11 +40,11 @@ exports.inject = (ergogen) => {
${p.at /* parametric position */}
(pad 1 smd rect (at 0 0 ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1.str} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1} (solder_mask_margin 0.2))
(pad 2 smd rect (at 5 5 ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1.str} (solder_mask_margin 0.2))
(pad 2 smd rect (at ${p.iaxy(5, 5)} ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.P1} (solder_mask_margin 0.2))
)
@ -51,7 +52,7 @@ exports.inject = (ergogen) => {
(connect_pads (clearance 0.508))
(min_thickness 0.254)
(fill yes (arc_segments 32) (thermal_gap 0.508) (thermal_bridge_width 0.508))
(polygon (pts (xy ${p.xy(5, 5)}) (xy ${p.xy(5, -5)}) (xy ${p.xy(-5, -5)}) (xy ${p.xy(-5, 5)})))
(polygon (pts (xy ${p.eaxy(5, 5)}) (xy ${p.eaxy(5, -5)}) (xy ${p.eaxy(-5, -5)}) (xy ${p.eaxy(-5, 5)})))
)
`
@ -70,14 +71,14 @@ exports.inject = (ergogen) => {
${p.at /* parametric position */}
(pad 1 smd rect (at 0 0 ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('1').str} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('1')} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('2').str} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('2')} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.rot}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('3').str} (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 ${p.r}) (size 1 1) (layers ${p.side}.Cu ${p.side}.Paste ${p.side}.Mask)
${p.local_net('3')} (solder_mask_margin 0.2))
)
@ -106,7 +107,33 @@ exports.inject = (ergogen) => {
}
})
ergogen.inject('footprint', 'references_test', {
ergogen.inject('footprint', 'arrobj_test', {
params: {
designator: 'T',
side: 'F',
start: {x: 0, y: 0},
end: [[1, 0], [0, 1]]
},
body: p => {
lines = ''
for (const item of p.end) {
lines += `(fp_line (start ${p.start.x} ${p.start.y}) (end ${item[0]} ${item[1]}) (layer Dwgs.User) (width 0.05))\n`
}
return `
(module arrobj_test (layer ${p.side}.Cu) (tedit 5CF31DEF)
${p.at /* parametric position */}
${lines}
)
`
}
})
ergogen.inject('references_test', {
params: {},
body: p => {
return `references ${p.ref_hide ? 'hidden' : 'shown'}`

View file

@ -1,4 +1,12 @@
global.chai = require('chai')
global.chai.use(require('chai-as-promised'))
global.expect = global.chai.expect
global.should = global.chai.should()
global.should = global.chai.should()
global.sinon = require('sinon')
// Restore the default sandbox after every test
exports.mochaHooks = {
afterEach() {
sinon.restore()
}
}

View file

@ -9,7 +9,15 @@ require('./helpers/mock_footprints').inject(ergogen)
let what = process.env.npm_config_what
const dump = process.env.npm_config_dump
const lineends = /(?:\r\n|\r|\n)/g
const handle_slash = (() => {
if (path.sep == '\\') {
return str => str.replace(/\\/g,'/')
} else {
return str => str
}
})()
// Unit tests
@ -17,7 +25,7 @@ const dump = process.env.npm_config_dump
// the --dump switch does nothing here
what = what ? what.split(',') : false
for (const unit of glob.sync(path.join(__dirname, 'unit', '*.js'))) {
for (const unit of glob.sync(handle_slash(path.join(__dirname, 'unit', '*.js')))) {
const base = path.basename(unit, '.js')
if (what && !what.includes(base)) continue
require(`./unit/${base}.js`)
@ -30,6 +38,19 @@ for (const unit of glob.sync(path.join(__dirname, 'unit', '*.js'))) {
// as well as individual tests using slash-notation (like `points/default`)
// the --dump switch can output the new results, overriding the old reference
const dump_structure = (obj, depth=-1, prefix='', breadcrumbs=[]) => {
if (a.type(obj)() != 'object') {
console.log(prefix + breadcrumbs.join('_'))
return
}
if (depth == 0) return
for (const [key, val] of Object.entries(obj)) {
breadcrumbs.push(key)
dump_structure(val, depth-1, prefix, breadcrumbs)
breadcrumbs.pop()
}
}
const cap = s => s.charAt(0).toUpperCase() + s.slice(1)
const test = function(input_path) {
@ -37,27 +58,52 @@ const test = function(input_path) {
this.slow(120000)
title = path.basename(input_path, '.yaml').split('_').join(' ')
it(title, async function() {
const input = yaml.load(fs.readFileSync(input_path).toString())
const base = path.join(path.dirname(input_path), path.basename(input_path, '.yaml'))
const references = glob.sync(handle_slash(base) + '___*')
// handle deliberately wrong inputs
const exception = base + '___EXCEPTION.txt'
if (fs.existsSync(exception)) {
const exception_snippet = fs.readFileSync(exception).toString()
return await ergogen.process(input, true).should.be.rejectedWith(exception_snippet)
}
const output = await ergogen.process(input, true)
// compare output vs. reference
const base = path.join(path.dirname(input_path), path.basename(input_path, '.yaml'))
for (const expected_path of glob.sync(base + '___*')) {
let expected = fs.readFileSync(expected_path).toString()
if (expected_path.endsWith('.json')) {
expected = JSON.parse(expected)
}
const comp_path = expected_path.split('___')[1].split('.')[0].split('_').join('.')
const output_part = u.deep(output, comp_path)
if (dump) {
if (a.type(output_part)() == 'string') {
fs.writeFileSync(expected_path, output_part)
} else {
fs.writeJSONSync(expected_path, output_part, {spaces: 4})
if (references.length) {
for (const expected_path of references) {
let expected = fs.readFileSync(expected_path).toString()
if (expected_path.endsWith('.json')) {
expected = JSON.parse(expected)
}
const comp_path = expected_path.split('___')[1].split('.')[0].split('_').join('.')
const output_part = u.deep(output, comp_path)
if (dump) {
if (a.type(output_part)() == 'string') {
fs.writeFileSync(expected_path, output_part)
} else {
fs.writeJSONSync(expected_path, output_part, {spaces: 4})
}
} else {
if (a.type(output_part)() == 'string') {
const parse_out = output_part.replace(lineends, '\n')
const parse_exp = expected.replace(lineends, '\n')
parse_out.should.deep.equal(parse_exp)
} else {
// JSON can hide negative zeroes, for example, so we canonical-ize first
const canonical_part = JSON.parse(JSON.stringify(output_part))
canonical_part.should.deep.equal(expected)
}
}
} else {
output_part.should.deep.equal(expected)
}
// explicit dump-ing above only works, if there are already files with the right name
// if there aren't, dump now outputs a list of candidates that could be referenced
} else if (dump) {
dump_structure(output, 3, base + '___')
}
})
}
@ -74,7 +120,7 @@ if (what) {
regex = path.join(__dirname, w, '*.yaml')
}
describe(title, function() {
for (const i of glob.sync(regex)) {
for (const i of glob.sync(handle_slash(regex))) {
test.call(this, i)
}
})
@ -82,7 +128,7 @@ if (what) {
} else {
for (const part of ['points', 'outlines', 'cases', 'pcbs', 'footprints']) {
describe(cap(part), function() {
for (const i of glob.sync(path.join(__dirname, part, '*.yaml'))) {
for (const i of glob.sync(handle_slash(path.join(__dirname, part, '*.yaml')))) {
test.call(this, i)
}
})
@ -109,7 +155,7 @@ for (let w of cli_what) {
describe('CLI', function() {
this.timeout(120000)
this.slow(120000)
for (const t of glob.sync(path.join(__dirname, w))) {
for (const t of glob.sync(handle_slash(path.join(__dirname, w)))) {
it(path.basename(t).split('_').join(' '), function() {
const command = read(t, 'command')
const output_path = exists(t, 'path') ? read(t, 'path') : 'output'
@ -133,14 +179,19 @@ for (let w of cli_what) {
ref_path = path.resolve(path.join(t, read(ref_path).trim()))
}
const comp_res = dircompare.compareSync(output_path, ref_path, {
compareContent: true
compareContent: true,
ignoreLineEnding: true,
compareFileSync: dircompare.fileCompareHandlers.lineBasedFileCompare.compareSync,
compareFileAsync: dircompare.fileCompareHandlers.lineBasedFileCompare.compareAsync
})
if (dump) {
fs.moveSync(output_path, ref_path, {overwrite: true})
} else {
fs.removeSync(output_path)
}
actual_log.should.equal(ref_log)
const parse_act_log = actual_log.replace(lineends, '\n')
const parse_ref_log = ref_log.replace(lineends, '\n')
parse_act_log.should.equal(parse_ref_log)
comp_res.same.should.be.true
// deliberately incorrect execution
} else {
@ -162,4 +213,4 @@ for (let w of cli_what) {
})
}
})
}
}

View file

@ -0,0 +1,18 @@
points:
zones:
matrix:
mirror:
ref: matrix_only_first
distance: 30
columns:
only.rows:
first.bind: 0
second.bind: [0,10,0,10]
third.bind: [10,0,10,0]
fourth.bind: [u, u/2, u/3, u/4]
outlines:
bound:
- what: rectangle
where: true
size: 20
bound: true

View file

@ -0,0 +1,338 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-10
20
-10
11
10
21
-10
0
LINE
8
0
10
10
20
-10
11
10
21
9
0
LINE
8
0
10
-10
20
9
11
-10
21
-10
0
LINE
8
0
10
10
20
29
11
20
21
29
0
LINE
8
0
10
20
20
9
11
10
21
9
0
LINE
8
0
10
-10
20
9
11
-20
21
9
0
LINE
8
0
10
-20
20
9
11
-20
21
29
0
LINE
8
0
10
-20
20
29
11
-10
21
29
0
LINE
8
0
10
10
20
29
11
10
21
40.6666667
0
LINE
8
0
10
-10
20
29
11
-10
21
40.6666667
0
LINE
8
0
10
-14.75
20
86
11
44.75
21
86
0
LINE
8
0
10
10
20
40.6666667
11
20
21
40.6666667
0
LINE
8
0
10
-10
20
40.6666667
11
-14.75
21
40.6666667
0
LINE
8
0
10
-14.75
20
40.6666667
11
-14.75
21
86
0
LINE
8
0
10
20
20
-10
11
40
21
-10
0
LINE
8
0
10
40
20
-10
11
40
21
9
0
LINE
8
0
10
20
20
9
11
20
21
-10
0
LINE
8
0
10
40
20
29
11
50
21
29
0
LINE
8
0
10
50
20
9
11
50
21
29
0
LINE
8
0
10
50
20
9
11
40
21
9
0
LINE
8
0
10
40
20
29
11
40
21
40.6666667
0
LINE
8
0
10
20
20
29
11
20
21
40.6666667
0
LINE
8
0
10
44.75
20
40.6666667
11
44.75
21
86
0
LINE
8
0
10
44.75
20
40.6666667
11
40
21
40.6666667
0
ENDSEC
0
EOF

46
test/outlines/expand.yaml Normal file
View file

@ -0,0 +1,46 @@
points:
zones:
matrix: {}
outlines:
base:
- what: rectangle
where: true
size: 20
bound: false
sh_beveled:
- what: outline
name: base
expand: "5]"
sh_round:
- what: outline
name: base
expand: "6)"
sh_pointy:
- what: outline
name: base
expand: "7>"
shorthand-combo:
- "sh_pointy"
- "-sh_round"
- "+sh_beveled"
- "-base"
jnt_beveled:
- what: outline
name: base
expand: 8
joints: beveled
jnt_round:
- what: outline
name: base
expand: 9
joints: round
jnt_pointy:
- what: outline
name: base
expand: 10
joints: pointy
joint-name-combo:
- "jnt_pointy"
- "-jnt_round"
- "+jnt_beveled"
- "-base"

View file

@ -0,0 +1,346 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-20
20
-20
11
20
21
-20
0
LINE
8
0
10
20
20
-20
11
20
21
20
0
LINE
8
0
10
-20
20
20
11
20
21
20
0
LINE
8
0
10
-20
20
-20
11
-20
21
20
0
LINE
8
0
10
-10
20
-19
11
10
21
-19
0
ARC
8
0
10
10
20
-10
40
9
50
270
51
360
0
LINE
8
0
10
19
20
-10
11
19
21
10
0
ARC
8
0
10
10
20
10
40
9
50
0
51
90
0
LINE
8
0
10
10
20
19
11
-10
21
19
0
ARC
8
0
10
-10
20
10
40
9
50
90
51
180
0
LINE
8
0
10
-19
20
10
11
-19
21
-10
0
ARC
8
0
10
-10
20
-10
40
9
50
180
51
270
0
LINE
8
0
10
-13.3137085
20
-18
11
13.3137085
21
-18
0
LINE
8
0
10
13.3137085
20
-18
11
18
21
-13.3137085
0
LINE
8
0
10
18
20
-13.3137085
11
18
21
13.3137085
0
LINE
8
0
10
13.3137085
20
18
11
18
21
13.3137085
0
LINE
8
0
10
-13.3137085
20
18
11
13.3137085
21
18
0
LINE
8
0
10
-18
20
13.3137085
11
-13.3137085
21
18
0
LINE
8
0
10
-18
20
-13.3137085
11
-18
21
13.3137085
0
LINE
8
0
10
-18
20
-13.3137085
11
-13.3137085
21
-18
0
LINE
8
0
10
-10
20
-10
11
10
21
-10
0
LINE
8
0
10
10
20
-10
11
10
21
10
0
LINE
8
0
10
10
20
10
11
-10
21
10
0
LINE
8
0
10
-10
20
10
11
-10
21
-10
0
ENDSEC
0
EOF

View file

@ -0,0 +1,346 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-17
20
-17
11
17
21
-17
0
LINE
8
0
10
17
20
-17
11
17
21
17
0
LINE
8
0
10
-17
20
17
11
17
21
17
0
LINE
8
0
10
-17
20
-17
11
-17
21
17
0
LINE
8
0
10
-10
20
-16
11
10
21
-16
0
ARC
8
0
10
10
20
-10
40
6
50
270
51
360
0
LINE
8
0
10
16
20
-10
11
16
21
10
0
ARC
8
0
10
10
20
10
40
6
50
0
51
90
0
LINE
8
0
10
10
20
16
11
-10
21
16
0
ARC
8
0
10
-10
20
10
40
6
50
90
51
180
0
LINE
8
0
10
-16
20
10
11
-16
21
-10
0
ARC
8
0
10
-10
20
-10
40
6
50
180
51
270
0
LINE
8
0
10
-12.0710678
20
-15
11
12.0710678
21
-15
0
LINE
8
0
10
12.0710678
20
-15
11
15
21
-12.0710678
0
LINE
8
0
10
15
20
-12.0710678
11
15
21
12.0710678
0
LINE
8
0
10
12.0710678
20
15
11
15
21
12.0710678
0
LINE
8
0
10
-12.0710678
20
15
11
12.0710678
21
15
0
LINE
8
0
10
-15
20
12.0710678
11
-12.0710678
21
15
0
LINE
8
0
10
-15
20
-12.0710678
11
-15
21
12.0710678
0
LINE
8
0
10
-15
20
-12.0710678
11
-12.0710678
21
-15
0
LINE
8
0
10
-10
20
-10
11
10
21
-10
0
LINE
8
0
10
10
20
-10
11
10
21
10
0
LINE
8
0
10
10
20
10
11
-10
21
10
0
LINE
8
0
10
-10
20
10
11
-10
21
-10
0
ENDSEC
0
EOF

View file

@ -16,11 +16,22 @@ outlines:
where: true
size: cy
bound: true
adjust:
- what: circle
where: true
radius: 2
# adjust works, and it can use shape-specific units
adjust.shift: [0, r]
fillet:
- what: outline
name: base
- name: base
fillet: 2
scale:
- what: outline
name: fillet
scale: 0.5
- name: fillet
scale: 0.5
combination:
- "base"
- "-scale"
- "~fillet"
expand:
- name: combination
expand: 1

View file

@ -0,0 +1,90 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
CIRCLE
8
0
10
0
20
2
40
2
0
CIRCLE
8
0
10
0
20
19
40
2
0
CIRCLE
8
0
10
19
20
2
40
2
0
CIRCLE
8
0
10
19
20
19
40
2
0
ENDSEC
0
EOF

View file

@ -0,0 +1,514 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
8.6
20
-6.6
11
8.6
21
-4.3
0
LINE
8
0
10
8.6
20
12.8
11
8.6
21
23.6
0
LINE
8
0
10
-6.6
20
-8.6
11
6.6
21
-8.6
0
LINE
8
0
10
-8.6
20
-6.6
11
-8.6
21
23.6
0
LINE
8
0
10
-6.6
20
25.6
11
6.6
21
25.6
0
LINE
8
0
10
27.6
20
-6.6
11
27.6
21
23.6
0
LINE
8
0
10
12.4
20
-8.6
11
25.6
21
-8.6
0
LINE
8
0
10
10.4
20
-6.6
11
10.4
21
-4.3
0
LINE
8
0
10
10.4
20
12.8
11
10.4
21
23.6
0
LINE
8
0
10
12.4
20
25.6
11
25.6
21
25.6
0
LINE
8
0
10
4.3
20
-3.3
11
4.3
21
11.8
0
LINE
8
0
10
-3.3
20
-4.3
11
3.3
21
-4.3
0
LINE
8
0
10
-4.3
20
-3.3
11
-4.3
21
11.8
0
LINE
8
0
10
-3.3
20
12.8
11
3.3
21
12.8
0
LINE
8
0
10
13.8
20
-3.3
11
13.8
21
11.8
0
LINE
8
0
10
6.2
20
-4.3
11
8.6
21
-4.3
0
LINE
8
0
10
10.4
20
-4.3
11
12.8
21
-4.3
0
LINE
8
0
10
5.2
20
-3.3
11
5.2
21
11.8
0
LINE
8
0
10
6.2
20
12.8
11
8.6
21
12.8
0
LINE
8
0
10
10.4
20
12.8
11
12.8
21
12.8
0
ARC
8
0
10
3.3
20
11.8
40
1
50
0
51
90
0
ARC
8
0
10
-3.3
20
11.8
40
1
50
90
51
180
0
ARC
8
0
10
-3.3
20
-3.3
40
1
50
180
51
270
0
ARC
8
0
10
3.3
20
-3.3
40
1
50
270
51
0
0
ARC
8
0
10
12.8
20
11.8
40
1
50
0
51
90
0
ARC
8
0
10
6.2
20
11.8
40
1
50
90
51
180
0
ARC
8
0
10
6.2
20
-3.3
40
1
50
180
51
270
0
ARC
8
0
10
12.8
20
-3.3
40
1
50
270
51
0
0
ARC
8
0
10
6.6
20
23.6
40
2
50
0
51
90
0
ARC
8
0
10
-6.6
20
23.6
40
2
50
90
51
180
0
ARC
8
0
10
-6.6
20
-6.6
40
2
50
180
51
270
0
ARC
8
0
10
6.6
20
-6.6
40
2
50
270
51
0
0
ARC
8
0
10
25.6
20
23.6
40
2
50
0
51
90
0
ARC
8
0
10
12.4
20
23.6
40
2
50
90
51
180
0
ARC
8
0
10
12.4
20
-6.6
40
2
50
180
51
270
0
ARC
8
0
10
25.6
20
-6.6
40
2
50
270
51
0
0
ENDSEC
0
EOF

View file

@ -0,0 +1,410 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-6.6
20
-9.6
11
6.6
21
-9.6
0
ARC
8
0
10
6.6
20
-6.6
40
3
50
270
51
345.164888
0
ARC
8
0
10
12.4
20
-6.6
40
3
50
194.835112
51
270
0
LINE
8
0
10
12.4
20
-9.6
11
25.6
21
-9.6
0
ARC
8
0
10
25.6
20
-6.6
40
3
50
270
51
360
0
LINE
8
0
10
28.6
20
-6.6
11
28.6
21
23.6
0
ARC
8
0
10
25.6
20
23.6
40
3
50
0
51
90
0
LINE
8
0
10
12.4
20
26.6
11
25.6
21
26.6
0
ARC
8
0
10
12.4
20
23.6
40
3
50
90
51
165.164888
0
ARC
8
0
10
6.6
20
23.6
40
3
50
14.835112
51
90
0
LINE
8
0
10
-6.6
20
26.6
11
6.6
21
26.6
0
ARC
8
0
10
-6.6
20
23.6
40
3
50
90
51
180
0
LINE
8
0
10
-9.6
20
-6.6
11
-9.6
21
23.6
0
ARC
8
0
10
-6.6
20
-6.6
40
3
50
180
51
270
0
LINE
8
0
10
12.8
20
-3.3
11
12.8
21
11.8
0
LINE
8
0
10
10.4
20
11.8
11
12.8
21
11.8
0
ARC
8
0
10
10.4
20
12.8
40
1
50
205.8419331
51
270
0
ARC
8
0
10
8.6
20
12.8
40
1
50
270
51
334.1580669
0
LINE
8
0
10
6.2
20
11.8
11
8.6
21
11.8
0
LINE
8
0
10
6.2
20
-3.3
11
6.2
21
11.8
0
LINE
8
0
10
6.2
20
-3.3
11
8.6
21
-3.3
0
ARC
8
0
10
8.6
20
-4.3
40
1
50
25.8419331
51
90
0
ARC
8
0
10
10.4
20
-4.3
40
1
50
90
51
154.1580669
0
LINE
8
0
10
10.4
20
-3.3
11
12.8
21
-3.3
0
LINE
8
0
10
3.3
20
-3.3
11
3.3
21
11.8
0
LINE
8
0
10
-3.3
20
11.8
11
3.3
21
11.8
0
LINE
8
0
10
-3.3
20
-3.3
11
-3.3
21
11.8
0
LINE
8
0
10
-3.3
20
-3.3
11
3.3
21
-3.3
0
ENDSEC
0
EOF

View file

@ -17,6 +17,7 @@ outlines:
- mirror_matrix
shift: [0, sy/2]
size: [20, 40]
corner: 5
outside_rects:
what: rectangle
where:

View file

@ -67,7 +67,7 @@ LINE
11
10
21
0
5
0
LINE
8
@ -135,7 +135,7 @@ LINE
10
30
20
0
5
11
30
21
@ -145,14 +145,28 @@ LINE
8
0
10
10
15
20
0
11
30
25
21
0
0
ARC
8
0
10
25
20
5
40
5
50
270
51
360
0
LINE
8
0
@ -163,32 +177,74 @@ LINE
11
30
21
35
0
ARC
8
0
10
25
20
35
40
5
50
0
51
90
0
LINE
8
0
10
30
25
20
40
11
10
15
21
40
0
ARC
8
0
10
15
20
35
40
5
50
90
51
180
0
LINE
8
0
10
10
20
40
35
11
10
21
10
0
ARC
8
0
10
15
20
5
40
5
50
180
51
270
0
LINE
8
0

View file

@ -1,5 +1,7 @@
points.zones.matrix:
mirror: 10
key:
magic_value: 5
outlines:
edge:
- what: rectangle
@ -18,6 +20,7 @@ pcbs:
shift: [1, 1]
rotate: 30
params:
width: u/40
side: F
mirror:
side: B
@ -28,9 +31,25 @@ pcbs:
rotate: 30
dyn:
what: dynamic_net_test
anc:
anc1:
what: anchor_test
params:
end:
ref: matrix
shift: [10, 10]
shift: [10, 10]
anc2:
what: anchor_test
params:
end: matrix
arrobj:
what: arrobj_test
params:
start: {x: 5, y: 5}
end: [[6, 6], [7, 7]]
arrobj_templated:
what: arrobj_test
where:
ref: matrix
params:
start: '{x: {{magic_value}}, y: {{magic_value}}}'
end: '[[6, 6], [7, {{magic_value}}]]'

View file

@ -94,9 +94,9 @@
(net 0 "")
(net 1 "P1")
(net 2 "T6_1")
(net 3 "T6_2")
(net 4 "T6_3")
(net 2 "T4_1")
(net 3 "T4_2")
(net 4 "T4_3")
(net_class Default "This is the default net class."
(clearance 0.2)
@ -107,9 +107,9 @@
(uvia_drill 0.1)
(add_net "")
(add_net "P1")
(add_net "T6_1")
(add_net "T6_2")
(add_net "T6_3")
(add_net "T4_1")
(add_net "T4_2")
(add_net "T4_3")
)
@ -126,7 +126,7 @@
)
(segment (start 1 -1) (end 7.830127 0.8301270000000001) (width 0.25) (layer F.Cu) (net 1))
(segment (start 1 -1) (end 7.830127 0.8301270000000001) (width 0.475) (layer F.Cu) (net 1))
@ -143,41 +143,7 @@
)
(segment (start 19 -1) (end 12.169872999999999 0.8301270000000001) (width 0.25) (layer B.Cu) (net 1))
(module trace_test (layer B.Cu) (tedit 5CF31DEF)
(at 19 -1 -30)
(pad 1 smd rect (at 0 0 -30) (size 1 1) (layers B.Cu B.Paste B.Mask)
(net 1 "P1") (solder_mask_margin 0.2))
(pad 2 smd rect (at -5 5 -30) (size 1 1) (layers B.Cu B.Paste B.Mask)
(net 1 "P1") (solder_mask_margin 0.2))
)
(segment (start 19 -1) (end 12.169872999999999 0.8301270000000001) (width 0.25) (layer B.Cu) (net 1))
(module trace_test (layer F.Cu) (tedit 5CF31DEF)
(at 1 -1 30)
(pad 1 smd rect (at 0 0 30) (size 1 1) (layers F.Cu F.Paste F.Mask)
(net 1 "P1") (solder_mask_margin 0.2))
(pad 2 smd rect (at 5 5 30) (size 1 1) (layers F.Cu F.Paste F.Mask)
(net 1 "P1") (solder_mask_margin 0.2))
)
(segment (start 1 -1) (end 7.830127 0.8301270000000001) (width 0.25) (layer F.Cu) (net 1))
(segment (start 19 -1) (end 12.169872999999999 0.8301270000000001) (width 0.475) (layer B.Cu) (net 1))
@ -209,13 +175,13 @@
(at 0 0 0)
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask)
(net 2 "T6_1") (solder_mask_margin 0.2))
(net 2 "T4_1") (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask)
(net 3 "T6_2") (solder_mask_margin 0.2))
(net 3 "T4_2") (solder_mask_margin 0.2))
(pad 1 smd rect (at 0 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask)
(net 4 "T6_3") (solder_mask_margin 0.2))
(net 4 "T4_3") (solder_mask_margin 0.2))
)
@ -231,6 +197,43 @@
)
(module anchor_test (layer F.Cu) (tedit 5CF31DEF)
(at 0 0 0)
(fp_line (start 0 0) (end 0 0) (layer Dwgs.User) (width 0.05))
)
(module arrobj_test (layer F.Cu) (tedit 5CF31DEF)
(at 0 0 0)
(fp_line (start 5 5) (end 6 6) (layer Dwgs.User) (width 0.05))
(fp_line (start 5 5) (end 7 7) (layer Dwgs.User) (width 0.05))
)
(module arrobj_test (layer F.Cu) (tedit 5CF31DEF)
(at 0 0 0)
(fp_line (start 5 5) (end 6 6) (layer Dwgs.User) (width 0.05))
(fp_line (start 5 5) (end 7 5) (layer Dwgs.User) (width 0.05))
)
(gr_line (start -9.5 9.5) (end 9.5 9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 9.5 9.5) (end 9.5 -9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 9.5 -9.5) (end -9.5 -9.5) (angle 90) (layer Edge.Cuts) (width 0.15))

34
test/pcbs/outlines.yaml Normal file
View file

@ -0,0 +1,34 @@
points.zones.matrix:
columns:
left:
right:
rows.only:
outlines:
left:
out:
what: rectangle
where: matrix_left_only
size: u
fillet: u/5
in:
what: circle
where: matrix_left_only
radius: u/4
operation: subtract
right:
out:
what: rectangle
where: matrix_right_only
size: u
bevel: u/5
in:
what: rectangle
where: matrix_right_only
size: u/2
bevel: u/4
operation: subtract
pcbs:
main:
outlines:
- outline: 'left'
- outline: 'right'

View file

@ -0,0 +1,132 @@
(kicad_pcb (version 20171130) (host pcbnew 5.1.6)
(page A3)
(title_block
(title main)
(rev v1.0.0)
(company Unknown)
)
(general
(thickness 1.6)
)
(layers
(0 F.Cu signal)
(31 B.Cu signal)
(32 B.Adhes user)
(33 F.Adhes user)
(34 B.Paste user)
(35 F.Paste user)
(36 B.SilkS user)
(37 F.SilkS user)
(38 B.Mask user)
(39 F.Mask user)
(40 Dwgs.User user)
(41 Cmts.User user)
(42 Eco1.User user)
(43 Eco2.User user)
(44 Edge.Cuts user)
(45 Margin user)
(46 B.CrtYd user)
(47 F.CrtYd user)
(48 B.Fab user)
(49 F.Fab user)
)
(setup
(last_trace_width 0.25)
(trace_clearance 0.2)
(zone_clearance 0.508)
(zone_45_only no)
(trace_min 0.2)
(via_size 0.8)
(via_drill 0.4)
(via_min_size 0.4)
(via_min_drill 0.3)
(uvia_size 0.3)
(uvia_drill 0.1)
(uvias_allowed no)
(uvia_min_size 0.2)
(uvia_min_drill 0.1)
(edge_width 0.05)
(segment_width 0.2)
(pcb_text_width 0.3)
(pcb_text_size 1.5 1.5)
(mod_edge_width 0.12)
(mod_text_size 1 1)
(mod_text_width 0.15)
(pad_size 1.524 1.524)
(pad_drill 0.762)
(pad_to_mask_clearance 0.05)
(aux_axis_origin 0 0)
(visible_elements FFFFFF7F)
(pcbplotparams
(layerselection 0x010fc_ffffffff)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(excludeedgelayer true)
(linewidth 0.100000)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(padsonsilk false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory ""))
)
(net 0 "")
(net_class Default "This is the default net class."
(clearance 0.2)
(trace_width 0.25)
(via_dia 0.8)
(via_drill 0.4)
(uvia_dia 0.3)
(uvia_drill 0.1)
(add_net "")
)
(gr_line (start -5.7 9.5) (end 5.699999999999999 9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 9.5 5.7) (end 9.5 -5.699999999999999) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 5.699999999999999 -9.5) (end -5.7 -9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start -9.5 -5.699999999999999) (end -9.5 5.7) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_arc (start 5.7 5.7) (end 5.7 9.5) (angle -90) (layer Edge.Cuts) (width 0.15))
(gr_arc (start 5.7 -5.7) (end 9.5 -5.7) (angle -90) (layer Edge.Cuts) (width 0.15))
(gr_arc (start -5.7 -5.7) (end -5.7 -9.5) (angle -90) (layer Edge.Cuts) (width 0.15))
(gr_arc (start -5.7 5.7) (end -9.5 5.7) (angle -90) (layer Edge.Cuts) (width 0.15))
(gr_circle (center 0 0) (end 4.75 0) (layer Edge.Cuts) (width 0.15))
(gr_line (start 13.3 9.5) (end 9.5 5.7) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 9.5 5.7) (end 9.5 -5.7) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 9.5 -5.7) (end 13.3 -9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 13.3 -9.5) (end 24.700000000000003 -9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 24.700000000000003 -9.5) (end 28.5 -5.7) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 28.5 -5.7) (end 28.5 5.7) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 28.5 5.7) (end 24.700000000000003 9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 24.700000000000003 9.5) (end 13.3 9.5) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 19 4.75) (end 14.25 0) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 14.25 0) (end 19 -4.75) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 19 -4.75) (end 23.75 0) (angle 90) (layer Edge.Cuts) (width 0.15))
(gr_line (start 23.75 0) (end 19 4.75) (angle 90) (layer Edge.Cuts) (width 0.15))
)

View file

@ -3,17 +3,21 @@ points:
matrix:
columns:
left:
middle.rows.home.adjust:
shift: [-2u, 0]
rotate: 45
right:
key:
stagger: 5
spread: 25
splay: 5
splay: -5
origin: [-9, -9]
rows:
top:
home:
orient: -90
shift: [0, 10]
rotate: 90
rows:
bottom:
home:
top:

View file

@ -145,35 +145,227 @@ LINE
8
0
10
14.4311966
-9
20
47
11
9
21
47
0
LINE
8
0
10
9
20
47
11
9
21
29
0
LINE
8
0
10
9
20
29
11
-9
21
29
0
LINE
8
0
10
-9
20
29
11
-9
21
47
0
LINE
8
0
10
10
20
9
11
28
21
9
0
LINE
8
0
10
28
20
9
11
28
21
-9
0
LINE
8
0
10
28
20
-9
11
10
21
-9
0
LINE
8
0
10
10
20
-9
11
10
21
9
0
LINE
8
0
10
-31.7279221
20
19
11
-19
21
31.7279221
0
LINE
8
0
10
-19
20
31.7279221
11
-6.2720779
21
19
0
LINE
8
0
10
-6.2720779
20
19
11
-19
21
6.2720779
0
LINE
8
0
10
-19
20
6.2720779
11
-31.7279221
21
19
0
LINE
8
0
10
10
20
47
11
28
21
47
0
LINE
8
0
10
28
20
47
11
28
21
29
0
LINE
8
0
10
28
20
29
11
10
21
29
0
LINE
8
0
10
10
20
29
11
10
21
47
0
LINE
8
0
10
36.5688034
20
13.9315046
11
32.3627012
54.500308
21
15.500308
12.3627012
0
LINE
8
0
10
32.3627012
54.500308
20
15.500308
12.3627012
11
33.9315046
52.9315046
21
-2.4311966
-5.5688034
0
LINE
8
0
10
33.9315046
52.9315046
20
-2.4311966
-5.5688034
11
16
35
21
-4
0
@ -181,11 +373,11 @@ LINE
8
0
10
16
35
20
-4
11
14.4311966
36.5688034
21
13.9315046
0
@ -193,49 +385,97 @@ LINE
8
0
10
22.7371845
48.1867095
20
33.7307613
31.9876465
11
40.6686891
66.1182141
21
35.2995647
30.4188431
0
LINE
8
0
10
40.6686891
66.1182141
20
35.2995647
30.4188431
11
42.2374925
64.5494107
21
17.3680601
12.4873385
0
LINE
8
0
10
42.2374925
64.5494107
20
17.3680601
12.4873385
11
24.3059879
46.6179061
21
15.7992567
14.0561419
0
LINE
8
0
10
24.3059879
46.6179061
20
15.7992567
14.0561419
11
22.7371845
48.1867095
21
33.7307613
31.9876465
0
LINE
8
0
10
49.8426686
20
50.9153458
11
67.7741732
21
49.3465424
0
LINE
8
0
10
67.7741732
20
49.3465424
11
66.2053698
21
31.4150378
0
LINE
8
0
10
66.2053698
20
31.4150378
11
48.2738652
21
32.9838412
0
LINE
8
0
10
48.2738652
20
32.9838412
11
49.8426686
21
50.9153458
0
ENDSEC
0

View file

@ -17,6 +17,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -28,18 +29,33 @@
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
@ -53,6 +69,7 @@
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
@ -65,13 +82,13 @@
"row": "bottom",
"bind": [
10,
0,
10,
0,
0
]
}
},
"matrix_left_top": {
"matrix_left_home": {
"x": 0,
"y": 19,
"r": 0,
@ -89,29 +106,45 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "left_top",
"name": "matrix_left_top",
"colrow": "left_home",
"name": "matrix_left_home",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
@ -125,6 +158,96 @@
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {},
"key": {},
"name": "left"
},
"row": "home",
"bind": [
10,
10,
10,
0
]
}
},
"matrix_left_top": {
"x": 0,
"y": 38,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "left_top",
"name": "matrix_left_top",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
}
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
@ -143,17 +266,17 @@
]
}
},
"matrix_right_bottom": {
"x": 24.181350600000002,
"y": 5.750154,
"r": 5,
"matrix_middle_bottom": {
"x": 19,
"y": 0,
"r": 0,
"meta": {
"stagger": 5,
"spread": 25,
"splay": 5,
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
-9,
-9
0,
0
],
"orient": 0,
"shift": [
@ -161,29 +284,45 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_bottom",
"name": "matrix_right_bottom",
"colrow": "middle_bottom",
"name": "matrix_middle_bottom",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
@ -197,6 +336,310 @@
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"row": "bottom",
"bind": [
10,
0,
0,
10
]
}
},
"matrix_middle_home": {
"x": -19,
"y": 19,
"r": 45,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "middle_home",
"name": "matrix_middle_home",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
}
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"row": "home",
"bind": [
10,
10,
10,
10
]
}
},
"matrix_middle_top": {
"x": 19,
"y": 38,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "middle_top",
"name": "matrix_middle_top",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
}
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"row": "top",
"bind": [
0,
10,
10,
10
]
}
},
"matrix_right_bottom": {
"x": 44.750154,
"y": 4.1813506,
"r": -5,
"meta": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_bottom",
"name": "matrix_right_bottom",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
}
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
@ -205,14 +648,14 @@
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
@ -232,14 +675,14 @@
]
}
},
"matrix_right_top": {
"x": 32.4873385,
"y": 25.549410700000003,
"r": 5,
"matrix_right_home": {
"x": 56.3680601,
"y": 22.237492500000002,
"r": -5,
"meta": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
@ -250,29 +693,45 @@
10
],
"rotate": 90,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_top",
"name": "matrix_right_top",
"colrow": "right_home",
"name": "matrix_right_home",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
@ -286,6 +745,7 @@
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
@ -294,14 +754,120 @@
"key": {
"stagger": 5,
"spread": 25,
"splay": 5,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"top": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
},
"row": "home",
"bind": [
10,
0,
10,
10
]
}
},
"matrix_right_top": {
"x": 58.0240192,
"y": 41.1651918,
"r": -5,
"meta": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_top",
"name": "matrix_right_top",
"zone": {
"columns": {
"left": null,
"middle": {
"rows": {
"home": {
"adjust": {
"shift": [
"-2u",
0
],
"rotate": 45
}
}
},
"key": {},
"name": "middle"
},
"right": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,
10
],
"rotate": 90
}
},
"name": "right"
}
},
"rows": {
"bottom": {},
"home": {},
"top": {}
},
"name": "matrix"
},
"col": {
"key": {
"stagger": 5,
"spread": 25,
"splay": -5,
"origin": [
-9,
-9
]
},
"rows": {
"home": {
"orient": -90,
"shift": [
0,

24
test/points/autobind.yaml Normal file
View file

@ -0,0 +1,24 @@
points.zones:
none:
key:
autobind: 0
columns:
a:
b:
some:
key:
autobind: 1
columns:
a:
b:
outlines:
none:
- what: rectangle
where: /none_.*/
size: 5
bound: true
some:
- what: rectangle
where: /some_.*/
size: 5
bound: true

View file

@ -0,0 +1,146 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-2.5
20
-2.5
11
2.5
21
-2.5
0
LINE
8
0
10
2.5
20
-2.5
11
2.5
21
2.5
0
LINE
8
0
10
2.5
20
2.5
11
-2.5
21
2.5
0
LINE
8
0
10
-2.5
20
2.5
11
-2.5
21
-2.5
0
LINE
8
0
10
16.5
20
-2.5
11
21.5
21
-2.5
0
LINE
8
0
10
21.5
20
-2.5
11
21.5
21
2.5
0
LINE
8
0
10
21.5
20
2.5
11
16.5
21
2.5
0
LINE
8
0
10
16.5
20
2.5
11
16.5
21
-2.5
0
ENDSEC
0
EOF

View file

@ -0,0 +1,146 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-2.5
20
-2.5
11
3.5
21
-2.5
0
LINE
8
0
10
-2.5
20
2.5
11
3.5
21
2.5
0
LINE
8
0
10
-2.5
20
2.5
11
-2.5
21
-2.5
0
LINE
8
0
10
3.5
20
-2.5
11
3.5
21
2.5
0
LINE
8
0
10
15.5
20
-2.5
11
21.5
21
-2.5
0
LINE
8
0
10
21.5
20
-2.5
11
21.5
21
2.5
0
LINE
8
0
10
15.5
20
2.5
11
21.5
21
2.5
0
LINE
8
0
10
15.5
20
-2.5
11
15.5
21
2.5
0
ENDSEC
0
EOF

View file

@ -17,6 +17,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -68,6 +69,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -119,6 +121,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -170,6 +173,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,

View file

@ -17,6 +17,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -26,6 +27,13 @@
"colrow": "default_default",
"name": "matrix",
"zone": {
"columns": {
"default": {
"rows": {},
"key": {},
"name": "default"
}
},
"name": "matrix"
},
"col": {
@ -60,6 +68,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,

30
test/points/mirrors.yaml Normal file
View file

@ -0,0 +1,30 @@
points:
mirror:
ref: matrix_right_top
distance: U
zones:
matrix:
columns:
left:
rows:
bottom.asym: source
top.asym: clone
right:
rows:
bottom:
top:
other:
anchor:
ref: matrix_right_top
shift: [100, 100]
# default mirror object, ref = [0, 0], distance = 0
mirror: {}
columns:
left:
rows:
bottom.asym: source
top.asym: clone
right:
rows:
bottom:
top:

View file

@ -0,0 +1,626 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-9
20
9
11
9
21
9
0
LINE
8
0
10
9
20
9
11
9
21
-9
0
LINE
8
0
10
9
20
-9
11
-9
21
-9
0
LINE
8
0
10
-9
20
-9
11
-9
21
9
0
LINE
8
0
10
10
20
9
11
28
21
9
0
LINE
8
0
10
28
20
9
11
28
21
-9
0
LINE
8
0
10
28
20
-9
11
10
21
-9
0
LINE
8
0
10
10
20
-9
11
10
21
9
0
LINE
8
0
10
10
20
28
11
28
21
28
0
LINE
8
0
10
28
20
28
11
28
21
10
0
LINE
8
0
10
28
20
10
11
10
21
10
0
LINE
8
0
10
10
20
10
11
10
21
28
0
LINE
8
0
10
110
20
128
11
128
21
128
0
LINE
8
0
10
128
20
128
11
128
21
110
0
LINE
8
0
10
128
20
110
11
110
21
110
0
LINE
8
0
10
110
20
110
11
110
21
128
0
LINE
8
0
10
129
20
128
11
147
21
128
0
LINE
8
0
10
147
20
128
11
147
21
110
0
LINE
8
0
10
147
20
110
11
129
21
110
0
LINE
8
0
10
129
20
110
11
129
21
128
0
LINE
8
0
10
129
20
147
11
147
21
147
0
LINE
8
0
10
147
20
147
11
147
21
129
0
LINE
8
0
10
147
20
129
11
129
21
129
0
LINE
8
0
10
129
20
129
11
129
21
147
0
LINE
8
0
10
-128
20
147
11
-110
21
147
0
LINE
8
0
10
-110
20
147
11
-110
21
129
0
LINE
8
0
10
-110
20
129
11
-128
21
129
0
LINE
8
0
10
-128
20
129
11
-128
21
147
0
LINE
8
0
10
-147
20
128
11
-129
21
128
0
LINE
8
0
10
-129
20
128
11
-129
21
110
0
LINE
8
0
10
-129
20
110
11
-147
21
110
0
LINE
8
0
10
-147
20
110
11
-147
21
128
0
LINE
8
0
10
-147
20
147
11
-129
21
147
0
LINE
8
0
10
-129
20
147
11
-129
21
129
0
LINE
8
0
10
-129
20
129
11
-147
21
129
0
LINE
8
0
10
-147
20
129
11
-147
21
147
0
LINE
8
0
10
48.05
20
28
11
66.05
21
28
0
LINE
8
0
10
66.05
20
28
11
66.05
21
10
0
LINE
8
0
10
66.05
20
10
11
48.05
21
10
0
LINE
8
0
10
48.05
20
10
11
48.05
21
28
0
LINE
8
0
10
29.05
20
9
11
47.05
21
9
0
LINE
8
0
10
47.05
20
9
11
47.05
21
-9
0
LINE
8
0
10
47.05
20
-9
11
29.05
21
-9
0
LINE
8
0
10
29.05
20
-9
11
29.05
21
9
0
LINE
8
0
10
29.05
20
28
11
47.05
21
28
0
LINE
8
0
10
47.05
20
28
11
47.05
21
10
0
LINE
8
0
10
47.05
20
10
11
29.05
21
10
0
LINE
8
0
10
29.05
20
10
11
29.05
21
28
0
ENDSEC
0
EOF

View file

@ -0,0 +1,798 @@
{
"matrix_left_bottom": {
"x": 0,
"y": 0,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "source",
"colrow": "left_bottom",
"name": "matrix_left_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"row": "bottom",
"mirrored": false,
"bind": [
0,
10,
0,
0
]
}
},
"matrix_right_bottom": {
"x": 19,
"y": 0,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_bottom",
"name": "matrix_right_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "bottom",
"mirrored": false,
"bind": [
10,
0,
0,
10
]
}
},
"matrix_right_top": {
"x": 19,
"y": 19,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_top",
"name": "matrix_right_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "top",
"mirrored": false,
"bind": [
0,
0,
10,
0
]
}
},
"other_left_bottom": {
"x": 119,
"y": 119,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "source",
"colrow": "left_bottom",
"name": "other_left_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"row": "bottom",
"mirrored": false,
"bind": [
0,
10,
0,
0
]
}
},
"other_right_bottom": {
"x": 138,
"y": 119,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_bottom",
"name": "other_right_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "bottom",
"mirrored": false,
"bind": [
10,
0,
0,
10
]
}
},
"other_right_top": {
"x": 138,
"y": 138,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "right_top",
"name": "other_right_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "top",
"mirrored": false,
"bind": [
0,
0,
10,
0
]
}
},
"mirror_other_left_top": {
"x": -119,
"y": 138,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "clone",
"colrow": "mirror_left_top",
"name": "mirror_other_left_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"row": "top",
"mirrored": true,
"bind": [
0,
10,
0,
0
]
}
},
"mirror_other_right_bottom": {
"x": -138,
"y": 119,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "mirror_right_bottom",
"name": "mirror_other_right_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "bottom",
"mirrored": true,
"bind": [
10,
0,
0,
0
]
}
},
"mirror_other_right_top": {
"x": -138,
"y": 138,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "mirror_right_top",
"name": "mirror_other_right_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "other"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "top",
"mirrored": true,
"bind": [
0,
0,
10,
10
]
}
},
"mirror_matrix_left_top": {
"x": 57.05,
"y": 19,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "clone",
"colrow": "mirror_left_top",
"name": "mirror_matrix_left_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"row": "top",
"mirrored": true,
"bind": [
0,
10,
0,
0
]
}
},
"mirror_matrix_right_bottom": {
"x": 38.05,
"y": 0,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "mirror_right_bottom",
"name": "mirror_matrix_right_bottom",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "bottom",
"mirrored": true,
"bind": [
10,
0,
0,
0
]
}
},
"mirror_matrix_right_top": {
"x": 38.05,
"y": 19,
"r": 0,
"meta": {
"stagger": 0,
"spread": 19,
"splay": 0,
"origin": [
0,
0
],
"orient": 0,
"shift": [
0,
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
"autobind": 10,
"skip": false,
"asym": "both",
"colrow": "mirror_right_top",
"name": "mirror_matrix_right_top",
"zone": {
"columns": {
"left": {
"rows": {
"bottom": {
"asym": "source"
},
"top": {
"asym": "clone"
}
},
"key": {},
"name": "left"
},
"right": null
},
"rows": {
"bottom": {},
"top": {}
},
"name": "matrix"
},
"col": {
"rows": {},
"key": {},
"name": "right"
},
"row": "top",
"mirrored": true,
"bind": [
0,
0,
10,
10
]
}
}
}

View file

@ -17,6 +17,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -85,6 +86,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -153,6 +155,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -223,6 +226,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -293,6 +297,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -363,6 +368,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,
@ -437,6 +443,7 @@
0
],
"rotate": 0,
"adjust": {},
"width": 18,
"height": 18,
"padding": 19,

View file

@ -0,0 +1,16 @@
points:
rotate: 22.5
zones:
matrix:
rotate: 22.5
key:
origin: [-u/2, -u/2]
columns:
left:
right.key:
rotate: -45
padding: (1+sqrt(2))/2 * u
spread: (1+sqrt(2))/2 * u
rows:
bottom:
top:

View file

@ -0,0 +1,242 @@
0
SECTION
2
HEADER
9
$INSUNITS
70
4
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
0
LTYPE
72
65
70
64
2
CONTINUOUS
3
______
73
0
40
0
0
ENDTAB
0
TABLE
2
LAYER
0
ENDTAB
0
ENDSEC
0
SECTION
2
ENTITIES
0
LINE
8
0
10
-12.7279221
20
0
11
0
21
12.7279221
0
LINE
8
0
10
0
20
12.7279221
11
12.7279221
21
0
0
LINE
8
0
10
12.7279221
20
0
11
0
21
-12.7279221
0
LINE
8
0
10
0
20
-12.7279221
11
-12.7279221
21
0
0
LINE
8
0
10
-26.1629509
20
13.4350288
11
-13.4350288
21
26.1629509
0
LINE
8
0
10
-13.4350288
20
26.1629509
11
-0.7071067
21
13.4350288
0
LINE
8
0
10
-0.7071067
20
13.4350288
11
-13.4350288
21
0.7071067
0
LINE
8
0
10
-13.4350288
20
0.7071067
11
-26.1629509
21
13.4350288
0
LINE
8
0
10
7.2175144
20
25.2175144
11
25.2175144
21
25.2175144
0
LINE
8
0
10
25.2175144
20
25.2175144
11
25.2175144
21
7.2175144
0
LINE
8
0
10
25.2175144
20
7.2175144
11
7.2175144
21
7.2175144
0
LINE
8
0
10
7.2175144
20
7.2175144
11
7.2175144
21
25.2175144
0
LINE
8
0
10
16.2175144
20
51.8804653
11
28.9454365
21
39.1525432
0
LINE
8
0
10
28.9454365
20
39.1525432
11
16.2175144
21
26.4246211
0
LINE
8
0
10
16.2175144
20
26.4246211
11
3.4895923
21
39.1525432
0
LINE
8
0
10
3.4895923
20
39.1525432
11
16.2175144
21
51.8804653
0
ENDSEC
0
EOF

View file

@ -0,0 +1,2 @@
points.zones.matrix.key.name: samename
points.zones.other.key.name: samename

View file

@ -0,0 +1 @@
defined more than once

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