Compare commits

..

37 Commits

Author SHA1 Message Date
Bane Stojkovic 2b37bd172e P-0+o (Proto) Board, Proto Board 780 Holes and Eurorack Stripboard now have an Underside Display like the other boards, with the P-0+o's top copper faded in the mirror; the P-0+o credits no longer run off the board and show the designer's name correctly 2026-11-12 23:13:35 +01:00
Bane Stojkovic fbbd468989 Update sign-windows.yml 2026-11-12 21:16:18 +01:00
Bane Stojkovic 86b54509bf A board can no longer be selected, dragged or stretched through its own Underside Display, where dragging it moved the mirror under the mouse and the board went the wrong way 2026-11-12 14:34:05 +01:00
Bane Stojkovic 6e3f72dfb6 Split trace layer 2026-11-12 13:42:04 +01:00
Bane Stojkovic 4aab04f751 Plan for splitting the Trace layer into Bottom Traces and Top Traces, with layer ids that keep old files and older DIYLC versions working 2026-11-12 13:20:52 +01:00
Bane Stojkovic 9d2624b59e Changelog: 6.11.0 entries consolidated - one Gerber export entry, PCB text and Underside Transparency folded into the entries they belong to, the Drill Hole drill file fix listed as a bug fix 2026-11-12 12:04:07 +01:00
Bane Stojkovic be87c08e7e New solder pads have a plated through hole by default, while pads saved without a hole type stay non-plated; Gerber marks pads with a hole as component pads and pads without one as SMD pads 2026-11-12 11:27:07 +01:00
Bane Stojkovic 2f888a0090 Gerber export writes drill files in Excellon format, picked by a constant in GerberExporter, through gerber-writer 1.2.0; a Drill Hole no longer adds its outline and crosshair to the drill file 2026-11-12 11:20:41 +01:00
Bane Stojkovic 34490b50b2 Gerber export no longer cuts the holes of solder pads and vias out of the copper layers; the drill files alone define the holes 2026-11-12 11:08:52 +01:00
Bane Stojkovic 2439510f35 Transistors in TO-92, TO-1, TO-126, TO-220 and TO-3 packages no longer draw circles around their pins in outline mode; only the body outline and the label are drawn 2026-11-12 10:57:46 +01:00
Bane Stojkovic 3049d4910c via and double-sided pad 2026-11-12 10:48:19 +01:00
Bane Stojkovic d166c58161 Copper keeps its 'Layer' property in the editor, the term PCB tools use for copper, while still counting as a Board Side component in code 2026-11-11 21:40:33 +01:00
Bane Stojkovic 144c19b44b Changelog entry for PCB text moving to the bottom page of the silkscreen print-out 2026-11-11 21:19:55 +01:00
Bane Stojkovic aef300d902 Traces, curved traces, ground fills, solder pads and PCB text call their layer 'Board Side', like every other part, and count as Board Side components in code; the saved field is still 'layer' 2026-11-11 21:15:26 +01:00
Bane Stojkovic 7ae773ab77 A part's Gerber silkscreen layer follows its Board Side in IGerberComponentSimple's default, so the exporter no longer swaps layers after the fact and GerberLayer.flip() is gone 2026-11-11 20:48:35 +01:00
Bane Stojkovic 698fba5630 Changelog: the Underside Display editing and the realistic board rendering get their own entries, and entries are ordered new features, improvements, bug fixes; CLAUDE.md records the ordering rule 2026-11-11 20:40:39 +01:00
Bane Stojkovic 34d475b18a Merge branch 'master' into copper-improvements
# Conflicts:
#	diylc/diylc-core/src/main/resources/update.xml
2026-11-11 18:39:47 +01:00
Bane Stojkovic 1fe823270e Hovering over a control point in a board's Underside Display shows its node name tooltip, as it does on the board itself 2026-11-11 18:39:29 +01:00
Bane Stojkovic 13b31e6dd5 Review fixes: a drag in the Underside Display picks the part a click would, the part being placed there is drawn like the parts already there, a bottom Dot no longer adds an empty silkscreen page; one helper decides a part's board side and copper layers share an interface 2026-11-11 17:32:46 +01:00
Bane Stojkovic 5ef6952ef4 The AI component catalog no longer offers the deprecated inner layers, and lists the new 'Board Side' property 2026-11-11 17:05:44 +01:00
Bane Stojkovic 19c78e5fa9 Parts dragged from the component tree or toolbox into a board's Underside Display go on the bottom of the board 2026-11-11 17:02:06 +01:00
Bane Stojkovic 7f8c790936 A 'Dot' used as a solder joint can be put on the bottom of the board with the 'Board Side' property 2026-11-11 16:57:35 +01:00
Bane Stojkovic 27b32b0b3c Changelog entries for the faded copper view, the true underside view and the hidden inner layers 2026-11-11 16:39:49 +01:00
Bane Stojkovic eeca9f112d New parts can be placed in a board's Underside Display; a part placed there goes on the bottom of the board 2026-11-11 15:46:29 +01:00
Bane Stojkovic 122a91a6f0 The silkscreen print-out has a separate page for parts placed on the bottom of the board 2026-11-11 15:37:27 +01:00
Bane Stojkovic 246763419c All PCB parts with a top silkscreen, including tube sockets, rotary switches, relays and transformers, have the 'Board Side' property 2026-11-11 15:34:40 +01:00
Bane Stojkovic 9721307586 Bottom-side plan: the board side is a plain property and parts are not mirrored for the user 2026-11-11 15:31:32 +01:00
Bane Stojkovic 9765f04e3c Parts placed on the bottom of the board are drawn faded on the canvas and solid in the Underside Display mirror 2026-11-11 15:20:06 +01:00
Bane Stojkovic df873df04a Resistors, capacitors, diodes, ICs, transistors and other PCB parts can be placed on the bottom of the board with the new 'Board Side' property; Gerber export puts their silkscreen on the bottom layer with the text mirrored 2026-11-11 15:15:19 +01:00
Bane Stojkovic 16f54fa479 'Solder Pad' on the top layer put its solder mask opening on the bottom layer in Gerber export 2026-11-11 15:15:10 +01:00
Bane Stojkovic b76d315f44 Components can be dragged and their points stretched through the Underside Display mirror of a board 2026-11-11 15:05:28 +01:00
Bane Stojkovic 90e10f4597 Components can be selected by clicking them in the Underside Display mirror of a board 2026-11-11 14:56:02 +01:00
Bane Stojkovic 3506c97403 A component can report which side of the board it is mounted on, and Gerber export puts the silkscreen of a part mounted underneath on the bottom layer 2026-11-11 14:48:57 +01:00
Bane Stojkovic 324cb20634 Gerber export decides each component's layer in one place, and Gerber layers can be mapped to the other side of the board 2026-11-11 14:46:02 +01:00
Bane Stojkovic 39c7743c30 Regenerated regression reference images for the far-side copper fade 2026-11-11 14:25:25 +01:00
Bane Stojkovic 0c26a71174 Merge branch 'master' into copper-improvements
# Conflicts:
#	diylc/diylc-core/src/test/java/org/diylc/presenter/DrawingManagerTest.java
2026-11-11 10:26:39 +01:00
Bane Stojkovic f73574641c phase 1 2026-11-10 22:50:16 +01:00
211 changed files with 5318 additions and 439 deletions
+3 -1
View File
@@ -27,7 +27,9 @@ env:
jobs:
windows:
runs-on: ubuntu-latest
# amake/innosetup's wine cannot start its wineserver on Ubuntu 26.04 ("socket: Function not
# implemented"); pinned until the image supports it
runs-on: ubuntu-24.04
steps:
- name: Checkout code
Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 KiB

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 KiB

After

Width:  |  Height:  |  Size: 463 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 KiB

After

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 805 KiB

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 KiB

After

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 730 KiB

After

Width:  |  Height:  |  Size: 732 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 MiB

After

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 KiB

After

Width:  |  Height:  |  Size: 862 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 KiB

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 155 KiB

+8
View File
@@ -210,6 +210,14 @@ logic, netlist and analyzer behaviour, datasheet parsing, core utilities. Compon
user interaction are covered by the regression suite instead, not by unit tests. Test classes are
named `*Test` or `*Tests` and carry the license header like any other file.
## Changelog
User-facing changes are listed in `diylc-core/src/main/resources/update.xml`, one `Version` block
per release. Within a block, all `NEW_FEATURE` entries come first, then `IMPROVEMENT`, then
`BUG_FIX`; keep the existing order inside each group and add a new entry at the end of its own
group, not at the end of the block. After a merge that brings entries in from both sides, sort the
unreleased block again. Released blocks stay exactly as they shipped.
## Git
**Do not commit or push.** Make the change in the working tree and stop; the maintainer reviews and
+319 -9
View File
@@ -1,5 +1,5 @@
{
"version" : "6.10.0",
"version" : "6.11.0",
"components" : [ {
"name" : "Blank Board",
"className" : "boards.BlankBoard",
@@ -99,6 +99,7 @@
"namePrefix" : "BB",
"description" : "David Haillant's eurorack format stripboard for prototyping and building simple modules",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "Set 'Underside Display' only if explicitly asked to. The values other than 'NONE' render the mirror image of the board in the provided direction with the offset controlled by 'Underside Offset'" ],
"properties" : [ {
"name" : "Board Color",
"type" : "Color",
@@ -127,6 +128,21 @@
"type" : "Color",
"format" : "hex",
"defaultValue" : "#FFC593"
}, {
"name" : "Underside Display",
"type" : "BoardUndersideDisplay",
"possibleValues" : [ "NONE", "ABOVE", "BELOW", "LEFT", "RIGHT" ],
"defaultValue" : "NONE"
}, {
"name" : "Underside Offset",
"type" : "Size",
"format" : "(value)(unit)",
"possibleUnits" : [ "px", "mm", "cm", "m", "in", "ft", "yd" ],
"defaultValue" : "0.1in"
}, {
"name" : "Underside Transparency",
"type" : "Boolean",
"defaultValue" : "true"
} ]
}, {
"name" : "Eyelet Board",
@@ -322,7 +338,7 @@
"namePrefix" : "BB",
"description" : "A prototyping board for modular synths, central bus with V+ GND and V-",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "The control point is the top-left corner of the 2in x 4in body and 'Orientation' rotates the board around it", "With 'Orientation' DEFAULT, pad row n (1-33) is (0.4 + n x 0.1)in below the control point. Each row is split into separately connected groups, labeled by column: 1-2, 3-5, 6-8, 9-11, 12-14 and 15-16, at 0.1-0.2, 0.4-0.6, 0.7-0.9, 1.2-1.4, 1.5-1.7 and 1.8-1.9in to the right of it" ],
"notes" : [ "Set 'Underside Display' only if explicitly asked to. The values other than 'NONE' render the mirror image of the board in the provided direction with the offset controlled by 'Underside Offset'", "The control point is the top-left corner of the 2in x 4in body and 'Orientation' rotates the board around it", "With 'Orientation' DEFAULT, pad row n (1-33) is (0.4 + n x 0.1)in below the control point. Each row is split into separately connected groups, labeled by column: 1-2, 3-5, 6-8, 9-11, 12-14 and 15-16, at 0.1-0.2, 0.4-0.6, 0.7-0.9, 1.2-1.4, 1.5-1.7 and 1.8-1.9in to the right of it" ],
"properties" : [ {
"name" : "Board Color",
"type" : "Color",
@@ -351,6 +367,17 @@
"type" : "Color",
"format" : "hex",
"defaultValue" : "#FFC593"
}, {
"name" : "Underside Display",
"type" : "BoardUndersideDisplay",
"possibleValues" : [ "NONE", "ABOVE", "BELOW", "LEFT", "RIGHT" ],
"defaultValue" : "NONE"
}, {
"name" : "Underside Offset",
"type" : "Size",
"format" : "(value)(unit)",
"possibleUnits" : [ "px", "mm", "cm", "m", "in", "ft", "yd" ],
"defaultValue" : "0.1in"
}, {
"name" : "Underside Pad Color",
"type" : "Color",
@@ -361,6 +388,10 @@
"type" : "Color",
"format" : "hex",
"defaultValue" : "#D7B2FF"
}, {
"name" : "Underside Transparency",
"type" : "Boolean",
"defaultValue" : "true"
} ]
}, {
"name" : "Perf Board w/ Pads",
@@ -465,6 +496,7 @@
"namePrefix" : "BB",
"description" : "Prototyping board similar to Radio Shack 276-168B or MPJA 33304",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "Set 'Underside Display' only if explicitly asked to. The values other than 'NONE' render the mirror image of the board in the provided direction with the offset controlled by 'Underside Offset'" ],
"properties" : [ {
"name" : "Board Color",
"type" : "Color",
@@ -498,6 +530,21 @@
"type" : "ProtoBoard780Type",
"possibleValues" : [ "RS", "MPJA" ],
"defaultValue" : "MPJA"
}, {
"name" : "Underside Display",
"type" : "BoardUndersideDisplay",
"possibleValues" : [ "NONE", "ABOVE", "BELOW", "LEFT", "RIGHT" ],
"defaultValue" : "NONE"
}, {
"name" : "Underside Offset",
"type" : "Size",
"format" : "(value)(unit)",
"possibleUnits" : [ "px", "mm", "cm", "m", "in", "ft", "yd" ],
"defaultValue" : "0.1in"
}, {
"name" : "Underside Transparency",
"type" : "Boolean",
"defaultValue" : "true"
} ]
}, {
"name" : "Tag Strip",
@@ -1035,7 +1082,7 @@
}, {
"name" : "Layer",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8" ],
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_1"
}, {
"name" : "Name",
@@ -1077,7 +1124,7 @@
}, {
"name" : "Layer",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8" ],
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_1"
}, {
"name" : "Name",
@@ -1196,6 +1243,11 @@
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "A junction marker for schematics and wiring diagrams; it is drawing only and connects nothing, since ends that meet at the same point are already connected. For a pad on a board use Solder Pad" ],
"properties" : [ {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Color",
"type" : "Color",
"format" : "hex",
@@ -1277,7 +1329,7 @@
}, {
"name" : "Layer",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8" ],
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_1"
}, {
"name" : "Name",
@@ -1459,6 +1511,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -1681,7 +1738,7 @@
"namePrefix" : "Pad",
"description" : "Copper solder pad, round or square",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "Use on Blank Board and PCB layouts; Perf Board, Vero Board, TriPad Board and the proto boards already have their own pads" ],
"notes" : [ "Use on Blank Board and PCB layouts; Perf Board, Vero Board, TriPad Board and the proto boards already have their own pads; a pad with Hole Type 'Plated Through Hole' is on both copper layers and joins them, so its Layer is ignored" ],
"properties" : [ {
"name" : "Alpha",
"type" : "Percentage",
@@ -1702,11 +1759,11 @@
"name" : "Hole Type",
"type" : "HoleType",
"possibleValues" : [ "NONE", "PTH", "NTPH" ],
"defaultValue" : "NTPH"
"defaultValue" : "PTH"
}, {
"name" : "Layer",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8" ],
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_1"
}, {
"name" : "Node Name",
@@ -1921,6 +1978,44 @@
} ]
} ]
}
}, {
"name" : "Via",
"className" : "connectivity.Via",
"category" : "Connectivity",
"namePrefix" : "Via",
"description" : "Plated hole joining the copper on the top and bottom of a PCB",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "Use on Blank Board and PCB layouts to take a trace from one copper layer to the other", "Place the control point where a Top trace and a Bottom trace meet; the via joins the copper of both layers there. It is not a component pad: leads go into a Solder Pad" ],
"properties" : [ {
"name" : "Alpha",
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Color",
"type" : "Color",
"format" : "hex",
"defaultValue" : "#000000"
}, {
"name" : "Hole",
"type" : "Size",
"format" : "(value)(unit)",
"possibleUnits" : [ "px", "mm", "cm", "m", "in", "ft", "yd" ],
"defaultValue" : "0.4mm"
}, {
"name" : "Name",
"type" : "String"
}, {
"name" : "Size",
"type" : "Size",
"format" : "(value)(unit)",
"possibleUnits" : [ "px", "mm", "cm", "m", "in", "ft", "yd" ],
"defaultValue" : "0.8mm"
} ],
"pinout" : {
"pinCount" : 1,
"labels" : "sequential"
}
}, {
"name" : "Arduino Mega 2560",
"className" : "micro.ArduinoMega",
@@ -7155,6 +7250,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Font Size Override",
"type" : "Integer"
@@ -7228,6 +7328,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Font Size Override",
"type" : "Integer"
@@ -7306,6 +7411,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Font Size Override",
"type" : "Integer"
@@ -7746,6 +7856,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Display",
"type" : "Display",
@@ -7851,6 +7966,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -8509,6 +8629,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Name",
"type" : "String"
@@ -8577,6 +8702,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Font Size Override",
"type" : "Integer"
@@ -8645,6 +8775,11 @@
}, {
"name" : "Angle Offset",
"type" : "Angle"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Color",
"type" : "Color",
@@ -9035,6 +9170,11 @@
}, {
"name" : "Angle",
"type" : "Angle"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Color",
"type" : "Color",
@@ -9372,6 +9512,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -9496,6 +9641,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -11842,6 +11992,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -11970,7 +12125,7 @@
}, {
"name" : "Layer",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8" ],
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_1"
}, {
"name" : "Orientation",
@@ -12082,6 +12237,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12170,6 +12330,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12252,6 +12417,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12367,6 +12537,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12492,6 +12667,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12589,6 +12769,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12693,6 +12878,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12804,6 +12994,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12913,6 +13108,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -12994,6 +13194,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -13083,6 +13288,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Coil",
"type" : "Color",
@@ -13222,6 +13432,11 @@
"type" : "Color",
"format" : "hex",
"defaultValue" : "#333333"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -13301,6 +13516,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -13459,6 +13679,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -13527,6 +13752,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -13621,6 +13851,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -13728,6 +13963,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -13786,6 +14026,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -13844,6 +14089,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -16501,6 +16751,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -16574,6 +16829,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -16837,6 +17097,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -16930,6 +17195,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Border",
"type" : "Color",
@@ -17017,6 +17287,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Color",
"type" : "Color",
@@ -17102,6 +17377,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -17263,6 +17543,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -17344,6 +17629,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -17779,6 +18069,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -18210,6 +18505,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -19072,6 +19372,11 @@
"type" : "Percentage",
"format" : "number without the % sign, e.g. 100",
"defaultValue" : "100"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Body",
"type" : "Color",
@@ -20011,6 +20316,11 @@
"type" : "Base",
"possibleValues" : [ "B9A", "OCTAL", "B7G", "B12C", "UX4" ],
"defaultValue" : "B9A"
}, {
"name" : "Board Side",
"type" : "PCBLayer",
"possibleValues" : [ "_1", "_2" ],
"defaultValue" : "_2"
}, {
"name" : "Color",
"type" : "Color",
+6 -2
View File
@@ -1,5 +1,5 @@
{
"version" : "6.10.0",
"version" : "6.11.0",
"categories" : {
"Boards" : [ {
"name" : "Blank Board",
@@ -85,7 +85,7 @@
}, {
"name" : "Solder Pad",
"className" : "connectivity.SolderPad",
"notes" : [ "Use on Blank Board and PCB layouts; Perf Board, Vero Board, TriPad Board and the proto boards already have their own pads" ]
"notes" : [ "Use on Blank Board and PCB layouts; Perf Board, Vero Board, TriPad Board and the proto boards already have their own pads; a pad with Hole Type 'Plated Through Hole' is on both copper layers and joins them, so its Layer is ignored" ]
}, {
"name" : "Trace Cut",
"className" : "connectivity.TraceCut"
@@ -96,6 +96,10 @@
"name" : "Twisted Leads",
"className" : "connectivity.TwistedWire",
"notes" : [ "Electrically a single conductor between its two ends, exactly like Hookup Wire, even though two twisted leads are drawn; use it only for the look of a twisted pair, and where the circuit must be electrically correct and analyzable, draw each conductor as its own Hookup Wire or Right Angle Wire instead" ]
}, {
"name" : "Via",
"className" : "connectivity.Via",
"notes" : [ "Use on Blank Board and PCB layouts to take a trace from one copper layer to the other" ]
} ],
"Controllers" : [ {
"name" : "Arduino Mega 2560",
+2 -2
View File
@@ -97,10 +97,10 @@
</dependency>
<dependency>
<groupId>org.diylc.local</groupId>
<artifactId>gerber-writer-api-1.1.0</artifactId>
<artifactId>gerber-writer-api-1.2.0</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.1.0.jar</systemPath>
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.2.0.jar</systemPath>
</dependency>
<dependency>
<groupId>org.diylc.local</groupId>
@@ -72,5 +72,9 @@ public enum DrawOption {
/**
* When applied, all colors will be converted to blackest black or whitest white
*/
MONOCHROMATIC;
MONOCHROMATIC,
/**
* Paint on the bottom side of a board is drawn at reduced opacity, as if seen through the board.
*/
FADE_FAR_SIDE;
}
@@ -110,6 +110,8 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
public static final String LOCKED_ALPHA = "lockedAlpha";
public static final String FADE_FAR_SIDE_KEY = "fadeFarSide";
public static final String LANGUAGE = "language";
public static final String LANGUAGE_DEFAULT = "English";
@@ -362,22 +364,24 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
void setNewComponentTypeSlot(ComponentType componentType, Template template, String[] model, boolean forceInstatiate);
/**
* Locks or unlocks the specified layer. All components within +- 0.5 range will be affected by
* the change as well.
* Locks or unlocks the specified layer: the components whose z-order rounds to it, or the
* components on one side of the board for a trace layer.
*
* @param layerZOrder
* @param layerId a z-order such as {@link org.diylc.core.IDIYComponent#BOARD}, or one of the
* trace layers in {@link org.diylc.core.LayerIds}
* @param locked
*/
void setLayerLocked(int layerZOrder, boolean locked);
void setLayerLocked(int layerId, boolean locked);
/**
* Shows or hides the specified layer. All components within +- 0.5 range will be affected by the
* change as well.
* Shows or hides the specified layer: the components whose z-order rounds to it, or the
* components on one side of the board for a trace layer.
*
* @param layerZOrder
* @param layerId a z-order such as {@link org.diylc.core.IDIYComponent#BOARD}, or one of the
* trace layers in {@link org.diylc.core.LayerIds}
* @param visible
*/
void setLayerVisibility(int layerZOrder, boolean visible);
void setLayerVisibility(int layerId, boolean visible);
/**
* @return selection size expressed in both inches or centimeters, respectively
@@ -77,7 +77,8 @@ public interface ISelectionProcessor extends IGroupProcessor {
/**
* Selects all components in the project.
*
* @param int layer if > 0, designates which layer to select. If <= 0 we should select all
* @param int layer if > 0, the id of the layer to select, as for
* {@link IPlugInPort#setLayerVisibility(int, boolean)}. If <= 0 we should select all
* regardless of layer
*/
void selectAll(int layer);
@@ -25,7 +25,11 @@ import org.diylc.core.gerber.GerberLayer;
public enum PCBLayer {
_1("Bottom"), _2("Top"), _3("Inner 1"), _4("Inner 2"), _5("Inner 3"), _6("Inner 4"), _7("Inner 5"), _8("Inner 6");
_1("Bottom"), _2("Top"),
// DIYLC models two-sided boards only. The inner layers are kept, in order, so that files using
// them still load with the same layer ids; the editor hides them and Gerber export rejects them.
@Deprecated _3("Inner 1"), @Deprecated _4("Inner 2"), @Deprecated _5("Inner 3"),
@Deprecated _6("Inner 4"), @Deprecated _7("Inner 5"), @Deprecated _8("Inner 6");
private String label;
@@ -1,10 +1,13 @@
package org.diylc.core;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import java.awt.geom.Rectangle2D;
public interface IBoard {
Size DEFAULT_UNDERSIDE_OFFSET = new Size(0.1, SizeUnit.in);
Rectangle2D getBoardRectangle();
@@ -0,0 +1,58 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import org.diylc.common.PCBLayer;
/**
* Interface for components on one side of a board, such as a resistor, an IC or a trace. The side
* says where the part sits physically; it is separate from {@link ILayeredComponent}, which drives
* continuity, because the leads of a through-hole part connect to copper on both sides whichever
* side the part is mounted on. Copper implements it through {@link IPCBLayerComponent}, whose layer
* is its side and also drives its continuity.
*
* @author Branislav Stojkovic
*/
public interface IBoardSideComponent {
/**
* @return {@link PCBLayer#_2} for the top of the board or {@link PCBLayer#_1} for the bottom,
* never an inner layer or null
*/
PCBLayer getBoardSide();
/**
* Sets the side of the board the component is mounted on. The component is not mirrored.
*
* @param boardSide {@link PCBLayer#_2} for the top or {@link PCBLayer#_1} for the bottom
*/
void setBoardSide(PCBLayer boardSide);
/**
* @return {@link PCBLayer#_1} for a component mounted on the bottom of the board, and
* {@link PCBLayer#_2} for any other, including components that have no side
*/
static PCBLayer sideOf(IDIYComponent<?> component) {
return component instanceof IBoardSideComponent sided && sided.getBoardSide() == PCBLayer._1
? PCBLayer._1 : PCBLayer._2;
}
}
@@ -21,6 +21,8 @@
*/
package org.diylc.core;
import org.diylc.common.PCBLayer;
/**
* Interface for tracking component drawing process. Components may use it to stop or restart
* tracking. Anything drawn while tracking is stopped will not be added to the mouse hot-spot area.
@@ -65,4 +67,26 @@ public interface IDrawingObserver {
* @param marker
*/
void setContinuityMarker(String marker);
/**
* Notifies the observer that what follows is painted on the given side of the board, until
* {@link #stopDrawingSide()}. Paint that is not bracketed is on the top (component) side. The
* observer may draw paint on the side facing away from the viewer at reduced opacity, as if seen
* through the board. Inner layers count as the bottom side.
*
* @param side the layer the paint lies on
*/
default void startDrawingSide(PCBLayer side) {}
/**
* Notifies the observer that what follows is visible from both sides of the board, such as a
* drilled hole or a cut through the copper, and is never drawn faded, until
* {@link #stopDrawingSide()}.
*/
default void startDrawingBothSides() {}
/**
* Notifies the observer that paint is back on the top (component) side.
*/
default void stopDrawingSide() {}
}
@@ -0,0 +1,52 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import org.diylc.common.PCBLayer;
/**
* Interface for copper drawn on a layer of a PCB, such as a trace, pad, ground fill or PCB text.
* The layer is the copper's board side, but unlike the side of a mounted part it also decides
* which other copper the copper connects to. It keeps the name 'Layer' in the editor, which is
* what PCB tools call it for copper.
*
* @author Branislav Stojkovic
*/
public interface IPCBLayerComponent extends IBoardSideComponent {
PCBLayer getLayer();
void setLayer(PCBLayer layer);
/**
* @return the layer, with the deprecated inner layers counted as the bottom
*/
@Override
default PCBLayer getBoardSide() {
return getLayer() == PCBLayer._2 ? PCBLayer._2 : PCBLayer._1;
}
@Override
default void setBoardSide(PCBLayer boardSide) {
setLayer(boardSide);
}
}
@@ -0,0 +1,72 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.util.Set;
/**
* Ids of the layers that can be hidden or locked in a project. A layer is a rounded z-order, such
* as {@link IDIYComponent#BOARD}, except that the traces are split into a bottom and a top layer.
* <p>
* The traces used to be one layer, {@link IDIYComponent#TRACE}, and older DIYLC versions still
* know only that one. Project files therefore keep {@link #LEGACY_TRACES} in a hidden or locked
* set exactly when both trace layers are in it, so that an older version hides or locks all
* traces when the new one has both sides hidden or locked.
*
* @author Branislav Stojkovic
*/
public final class LayerIds {
public static final int LEGACY_TRACES = IDIYComponent.TRACE;
public static final int BOTTOM_TRACES = IDIYComponent.TRACE * 10 + 1;
public static final int TOP_TRACES = IDIYComponent.TRACE * 10 + 2;
private LayerIds() {}
/**
* Brings a hidden or locked layer set read from a file up to date. The legacy trace layer, from
* an old file or written by an older version, stands for both trace layers. Both trace layers
* without it can only mean that an older version showed or unlocked its single trace layer, so
* neither side is hidden or locked any more.
*/
public static void migrateLoaded(Set<Integer> layers) {
if (layers.contains(LEGACY_TRACES)) {
layers.add(BOTTOM_TRACES);
layers.add(TOP_TRACES);
} else if (layers.contains(BOTTOM_TRACES) && layers.contains(TOP_TRACES)) {
layers.remove(BOTTOM_TRACES);
layers.remove(TOP_TRACES);
}
}
/**
* Keeps the legacy trace layer in a hidden or locked set after it has been changed: present
* exactly when both trace layers are.
*/
public static void syncLegacy(Set<Integer> layers) {
if (layers.contains(BOTTOM_TRACES) && layers.contains(TOP_TRACES)) {
layers.add(LEGACY_TRACES);
} else {
layers.remove(LEGACY_TRACES);
}
}
}
@@ -196,6 +196,17 @@ public class Project implements Serializable, Cloneable {
return hiddenLayers;
}
// called by XStream after loading, whichever way the project is opened; the trace layer was split
// in two, and files from older versions name only the single legacy one
private Object readResolve() {
if (lockedLayers == null) {
lockedLayers = new HashSet<Integer>();
}
LayerIds.migrateLoaded(lockedLayers);
LayerIds.migrateLoaded(getHiddenLayers());
return this;
}
public VersionNumber getFileVersion() {
return fileVersion;
}
@@ -15,9 +15,12 @@ import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.DrillFormat;
import org.diylc.common.PCBLayer;
import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IView;
import org.diylc.core.Project;
@@ -30,6 +33,9 @@ public class GerberExporter {
public static final double OUTLINE_THICKNESS = new Size(0.3d, SizeUnit.mm).convertToPixels();
private static final Logger LOG = Logger.getLogger(GerberExporter.class);
// Excellon is the drill format every fab accepts; Gerber drill files are not read by all of them
private static final DrillFormat DRILL_FORMAT = DrillFormat.EXCELLON;
public static void exportGerber(String fileNameBase, Project currentProject, IView view,
Graphics2D graphics2d, String diylcVersion) {
@@ -135,6 +141,23 @@ public class GerberExporter {
return;
}
});
g2d.getDrillLayerMap().forEach((layer, drillLayer) -> {
try {
String fileName = layer.formatFileName(fileNameBase, boardComponent.getName(),
DRILL_FORMAT == DrillFormat.EXCELLON ? "drl" : "gbr");
LOG.info("Exporting layer: " + layer + " for board " + boardComponent.getName()
+ " to file: " + fileName);
drillLayer.dumpToFile(fileName, DRILL_FORMAT);
generatedFiles.add(fileName);
} catch (IOException e) {
LOG.error("Error writing drill file: " + e.getMessage());
view.showMessage(
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
}
});
});
view.showMessage(
String.format(
@@ -145,8 +168,12 @@ public class GerberExporter {
LOG.info("Completed export to gerber");
}
private static void drawComponent(Project currentProject, GerberG2DWrapper g2d,
IDIYComponent<?> c, boolean outlineMode) {
/**
* Draws the specified component into the Gerber layers it belongs to. This is the only place that
* decides which layer a component's output goes to.
*/
static void drawComponent(Project currentProject, GerberG2DWrapper g2d,
IDIYComponent<?> c, boolean outlineMode) {
IGerberComponent gerberComponent = (IGerberComponent) c;
g2d.startedDrawingComponent();
if (gerberComponent instanceof IGerberComponentCustom) {
@@ -156,7 +183,10 @@ public class GerberExporter {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(),
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
// text on the bottom silkscreen is read from below, so it is written mirrored
g2d.setMirrorText(IBoardSideComponent.sideOf(c) == PCBLayer._1);
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.setMirrorText(false);
g2d.stopGerberOutput();
}
}
@@ -21,6 +21,7 @@ import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
@@ -32,6 +33,7 @@ import java.util.HashMap;
import java.util.Map;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.DrillLayer;
import com.bancika.gerberwriter.Point;
import com.bancika.gerberwriter.padmasters.Circle;
@@ -45,6 +47,7 @@ public class GerberG2DWrapper extends Graphics2D
private static final double CURVE_APPROXIMATION_TOLERANCE = 1d;
private Map<GerberLayer, DataLayer> layerMap;
private Map<GerberLayer, DrillLayer> drillLayerMap;
private boolean trackingGerber = false;
private Map<GerberLayer, GerberProperties> currentLayers =
new HashMap<GerberLayer, GerberProperties>();
@@ -58,12 +61,14 @@ public class GerberG2DWrapper extends Graphics2D
private double tolerance;
private Rectangle2D boardRect;
private boolean mirrorText = false;
public GerberG2DWrapper(Graphics2D graphics2d, String diylcVersion, Rectangle2D boardRect) {
super();
this.graphics2d = graphics2d;
this.boardRect = boardRect;
this.layerMap = new HashMap<GerberLayer, DataLayer>();
this.drillLayerMap = new HashMap<GerberLayer, DrillLayer>();
this.diylcVersion = diylcVersion;
}
@@ -114,7 +119,11 @@ public class GerberG2DWrapper extends Graphics2D
@Override
public void startGerberOutput(GerberLayer layer, String function, boolean negative) {
layerMap.computeIfAbsent(layer, k -> layer.buildLayer(diylcVersion));
if (layer.isDrill()) {
drillLayerMap.computeIfAbsent(layer, k -> layer.buildDrillLayer(diylcVersion));
} else {
layerMap.computeIfAbsent(layer, k -> layer.buildLayer(diylcVersion));
}
currentLayers.put(layer, new GerberProperties(function, negative));
trackingGerber = true;
}
@@ -154,10 +163,28 @@ public class GerberG2DWrapper extends Graphics2D
return layerMap;
}
public Map<GerberLayer, DrillLayer> getDrillLayerMap() {
return drillLayerMap;
}
/**
* Sets whether text is written mirrored, each string about its own centre. The output is in top
* view, so text on the bottom side has to be mirrored to read correctly once the board is turned
* over.
*/
public void setMirrorText(boolean mirrorText) {
this.mirrorText = mirrorText;
}
@Override
public void draw(Shape s) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
// only round fills are holes; outlines, such as a drill hole marker's border and
// crosshair, are not drilled
if (entry.getKey().isDrill()) {
return;
}
double width = 1;
if (stroke != null && stroke instanceof BasicStroke) {
width = ((BasicStroke) stroke).getLineWidth();
@@ -181,6 +208,10 @@ public class GerberG2DWrapper extends Graphics2D
GlyphVector gv = font.createGlyphVector(graphics2d.getFontRenderContext(), str);
AffineTransform translateInstance = AffineTransform.getTranslateInstance(x, y);
if (mirrorText) {
translateInstance.translate(gv.getLogicalBounds().getWidth(), 0);
translateInstance.scale(-1, 1);
}
for (int i = 0; i < gv.getNumGlyphs(); i++) {
Shape glyphShape = gv.getGlyphOutline(i);
@@ -208,6 +239,10 @@ public class GerberG2DWrapper extends Graphics2D
public void fillShape(Shape s) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
// only round fills are holes
if (entry.getKey().isDrill()) {
return;
}
DataLayer dataLayer = layerMap.get(entry.getKey());
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
GerberPathRenderer.outputPathArea(s.getPathIterator(finalTx), dataLayer,
@@ -220,6 +255,10 @@ public class GerberG2DWrapper extends Graphics2D
private void fillFlash(Ellipse2D c) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
if (entry.getKey().isDrill()) {
addHole(c, entry.getKey(), entry.getValue().function);
return;
}
DataLayer dataLayer = layerMap.get(entry.getKey());
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
if (Math.abs(c.getWidth() - c.getHeight()) < 0.1 && finalTx.getShearX() == 0
@@ -241,6 +280,17 @@ public class GerberG2DWrapper extends Graphics2D
}
}
private void addHole(Ellipse2D c, GerberLayer layer, String function) {
AffineTransform finalTx = getFinalTx(layer.isMirrored());
Point2D center = finalTx.transform(new Point2D.Double(c.getCenterX(), c.getCenterY()), null);
double factor = SizeUnit.px.getFactor();
// the drawing transform scales evenly, so the circle stays a circle, scaled by the square root
// of the determinant whether or not it is also rotated
double diameter = c.getWidth() * Math.sqrt(Math.abs(finalTx.getDeterminant())) * factor;
drillLayerMap.get(layer).addHole(new Point(center.getX() * factor, center.getY() * factor),
diameter, function);
}
private AffineTransform getFinalTx(boolean isMirrored) {
AffineTransform finalTx = new AffineTransform();
if (isMirrored) {
@@ -1,6 +1,7 @@
package org.diylc.core.gerber;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.DrillLayer;
import com.bancika.gerberwriter.GenerationSoftware;
public enum GerberLayer {
@@ -30,9 +31,18 @@ public enum GerberLayer {
}
public DataLayer buildLayer(String diylcVersion) {
GenerationSoftware genSoftware =
new GenerationSoftware("bancika", "DIY Layout Creator", diylcVersion);
return new DataLayer(function, negative, genSoftware);
return new DataLayer(function, negative, createGenerationSoftware(diylcVersion));
}
public DrillLayer buildDrillLayer(String diylcVersion) {
return new DrillLayer(this == DrillPlated, createGenerationSoftware(diylcVersion));
}
/**
* @return true for the drill layers, which hold holes rather than drawn copper or graphics
*/
public boolean isDrill() {
return this == DrillPlated || this == DrillNonPlated;
}
public String getExtension() {
@@ -54,9 +64,17 @@ public enum GerberLayer {
public boolean isMirrored() {
return mirrored;
}
public String formatFileName(String fileNameBase, String boardName) {
return formatFileName(fileNameBase, boardName, getExtension());
}
public String formatFileName(String fileNameBase, String boardName, String extension) {
return fileNameBase + (fileNameBase.endsWith(".") ? "" : ".")
+ boardName + "-" + getSuffix() + "." + getExtension();
+ boardName + "-" + getSuffix() + "." + extension;
}
private static GenerationSoftware createGenerationSoftware(String diylcVersion) {
return new GenerationSoftware("bancika", "DIY Layout Creator", diylcVersion);
}
}
@@ -25,29 +25,10 @@ import com.bancika.gerberwriter.Point;
import com.bancika.gerberwriter.path.MoveTo;
import com.bancika.gerberwriter.path.Path;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.measures.SizeUnit;
public class GerberPathRenderer {
public static void drawComponent(Project currentProject, GerberG2DWrapper g2d, IDIYComponent<?> c,
boolean outlineMode) {
IGerberComponent gerberComponent = (IGerberComponent) c;
g2d.startedDrawingComponent();
if (gerberComponent instanceof IGerberComponentCustom) {
IGerberComponentCustom gerberComponentCustom = (IGerberComponentCustom) gerberComponent;
gerberComponentCustom.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d, g2d);
} else if (gerberComponent instanceof IGerberComponentSimple) {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(),
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.stopGerberOutput();
}
}
public static void outputPathArea(PathIterator pathIterator, DataLayer dataLayer, double d,
boolean isNegative, String function) {
List<PathWithNegative> outputPath =

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