@tscircuit/cli 0.1.1643 → 0.1.1644

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/main.js CHANGED
@@ -53619,6 +53619,1817 @@ var init_dist_3YR26ALR = __esm(() => {
53619
53619
  ];
53620
53620
  });
53621
53621
 
53622
+ // node_modules/splaytree/dist/splaytree.umd.cjs
53623
+ var require_splaytree_umd = __commonJS((exports2, module2) => {
53624
+ (function(h4, c3) {
53625
+ typeof exports2 == "object" && typeof module2 < "u" ? module2.exports = c3() : typeof define == "function" && define.amd ? define(c3) : (h4 = typeof globalThis < "u" ? globalThis : h4 || self, h4.SplayTree = c3());
53626
+ })(exports2, function() {
53627
+
53628
+ class h4 {
53629
+ constructor(t50, e4) {
53630
+ this.next = null, this.key = t50, this.data = e4, this.left = null, this.right = null;
53631
+ }
53632
+ }
53633
+ function c3(n3, t50) {
53634
+ return n3 > t50 ? 1 : n3 < t50 ? -1 : 0;
53635
+ }
53636
+ function u4(n3, t50, e4) {
53637
+ const r4 = new h4(null, null);
53638
+ let i3 = r4, l3 = r4;
53639
+ for (;; ) {
53640
+ const o3 = e4(n3, t50.key);
53641
+ if (o3 < 0) {
53642
+ if (t50.left === null)
53643
+ break;
53644
+ if (e4(n3, t50.left.key) < 0) {
53645
+ const s3 = t50.left;
53646
+ if (t50.left = s3.right, s3.right = t50, t50 = s3, t50.left === null)
53647
+ break;
53648
+ }
53649
+ l3.left = t50, l3 = t50, t50 = t50.left;
53650
+ } else if (o3 > 0) {
53651
+ if (t50.right === null)
53652
+ break;
53653
+ if (e4(n3, t50.right.key) > 0) {
53654
+ const s3 = t50.right;
53655
+ if (t50.right = s3.left, s3.left = t50, t50 = s3, t50.right === null)
53656
+ break;
53657
+ }
53658
+ i3.right = t50, i3 = t50, t50 = t50.right;
53659
+ } else
53660
+ break;
53661
+ }
53662
+ return i3.right = t50.left, l3.left = t50.right, t50.left = r4.right, t50.right = r4.left, t50;
53663
+ }
53664
+ function _4(n3, t50, e4, r4) {
53665
+ const i3 = new h4(n3, t50);
53666
+ if (e4 === null)
53667
+ return i3.left = i3.right = null, i3;
53668
+ e4 = u4(n3, e4, r4);
53669
+ const l3 = r4(n3, e4.key);
53670
+ return l3 < 0 ? (i3.left = e4.left, i3.right = e4, e4.left = null) : l3 >= 0 && (i3.right = e4.right, i3.left = e4, e4.right = null), i3;
53671
+ }
53672
+ function d3(n3, t50, e4) {
53673
+ let r4 = null, i3 = null;
53674
+ if (t50) {
53675
+ t50 = u4(n3, t50, e4);
53676
+ const l3 = e4(t50.key, n3);
53677
+ l3 === 0 ? (r4 = t50.left, i3 = t50.right) : l3 < 0 ? (i3 = t50.right, t50.right = null, r4 = t50) : (r4 = t50.left, t50.left = null, i3 = t50);
53678
+ }
53679
+ return { left: r4, right: i3 };
53680
+ }
53681
+ function w4(n3, t50, e4) {
53682
+ return t50 === null ? n3 : (n3 === null || (t50 = u4(n3.key, t50, e4), t50.left = n3), t50);
53683
+ }
53684
+ function a3(n3, t50, e4, r4, i3) {
53685
+ if (n3) {
53686
+ r4(`${t50}${e4 ? "└── " : "├── "}${i3(n3)}
53687
+ `);
53688
+ const l3 = t50 + (e4 ? " " : "│ ");
53689
+ n3.left && a3(n3.left, l3, false, r4, i3), n3.right && a3(n3.right, l3, true, r4, i3);
53690
+ }
53691
+ }
53692
+
53693
+ class x4 {
53694
+ constructor(t50 = c3) {
53695
+ this._root = null, this._size = 0, this._comparator = t50;
53696
+ }
53697
+ insert(t50, e4) {
53698
+ return this._size++, this._root = _4(t50, e4, this._root, this._comparator);
53699
+ }
53700
+ add(t50, e4) {
53701
+ const r4 = new h4(t50, e4);
53702
+ this._root === null && (r4.left = r4.right = null, this._size++, this._root = r4);
53703
+ const i3 = this._comparator, l3 = u4(t50, this._root, i3), o3 = i3(t50, l3.key);
53704
+ return o3 === 0 ? this._root = l3 : (o3 < 0 ? (r4.left = l3.left, r4.right = l3, l3.left = null) : o3 > 0 && (r4.right = l3.right, r4.left = l3, l3.right = null), this._size++, this._root = r4), this._root;
53705
+ }
53706
+ remove(t50) {
53707
+ this._root = this._remove(t50, this._root, this._comparator);
53708
+ }
53709
+ _remove(t50, e4, r4) {
53710
+ let i3;
53711
+ return e4 === null ? null : (e4 = u4(t50, e4, r4), r4(t50, e4.key) === 0 ? (e4.left === null ? i3 = e4.right : (i3 = u4(t50, e4.left, r4), i3.right = e4.right), this._size--, i3) : e4);
53712
+ }
53713
+ pop() {
53714
+ let t50 = this._root;
53715
+ if (t50) {
53716
+ for (;t50.left; )
53717
+ t50 = t50.left;
53718
+ return this._root = u4(t50.key, this._root, this._comparator), this._root = this._remove(t50.key, this._root, this._comparator), { key: t50.key, data: t50.data };
53719
+ }
53720
+ return null;
53721
+ }
53722
+ findStatic(t50) {
53723
+ let e4 = this._root;
53724
+ const r4 = this._comparator;
53725
+ for (;e4; ) {
53726
+ const i3 = r4(t50, e4.key);
53727
+ if (i3 === 0)
53728
+ return e4;
53729
+ i3 < 0 ? e4 = e4.left : e4 = e4.right;
53730
+ }
53731
+ return null;
53732
+ }
53733
+ find(t50) {
53734
+ return this._root && (this._root = u4(t50, this._root, this._comparator), this._comparator(t50, this._root.key) !== 0) ? null : this._root;
53735
+ }
53736
+ contains(t50) {
53737
+ let e4 = this._root;
53738
+ const r4 = this._comparator;
53739
+ for (;e4; ) {
53740
+ const i3 = r4(t50, e4.key);
53741
+ if (i3 === 0)
53742
+ return true;
53743
+ i3 < 0 ? e4 = e4.left : e4 = e4.right;
53744
+ }
53745
+ return false;
53746
+ }
53747
+ forEach(t50, e4) {
53748
+ let r4 = this._root;
53749
+ const i3 = [];
53750
+ let l3 = false;
53751
+ for (;!l3; )
53752
+ r4 !== null ? (i3.push(r4), r4 = r4.left) : i3.length !== 0 ? (r4 = i3.pop(), t50.call(e4, r4), r4 = r4.right) : l3 = true;
53753
+ return this;
53754
+ }
53755
+ range(t50, e4, r4, i3) {
53756
+ const l3 = [], o3 = this._comparator;
53757
+ let s3 = this._root, f3;
53758
+ for (;l3.length !== 0 || s3; )
53759
+ if (s3)
53760
+ l3.push(s3), s3 = s3.left;
53761
+ else {
53762
+ if (s3 = l3.pop(), f3 = o3(s3.key, e4), f3 > 0)
53763
+ break;
53764
+ if (o3(s3.key, t50) >= 0 && r4.call(i3, s3))
53765
+ return this;
53766
+ s3 = s3.right;
53767
+ }
53768
+ return this;
53769
+ }
53770
+ keys() {
53771
+ const t50 = [];
53772
+ return this.forEach(({ key: e4 }) => {
53773
+ t50.push(e4);
53774
+ }), t50;
53775
+ }
53776
+ values() {
53777
+ const t50 = [];
53778
+ return this.forEach(({ data: e4 }) => {
53779
+ t50.push(e4);
53780
+ }), t50;
53781
+ }
53782
+ min() {
53783
+ return this._root ? this.minNode(this._root).key : null;
53784
+ }
53785
+ max() {
53786
+ return this._root ? this.maxNode(this._root).key : null;
53787
+ }
53788
+ minNode(t50 = this._root) {
53789
+ if (t50)
53790
+ for (;t50.left; )
53791
+ t50 = t50.left;
53792
+ return t50;
53793
+ }
53794
+ maxNode(t50 = this._root) {
53795
+ if (t50)
53796
+ for (;t50.right; )
53797
+ t50 = t50.right;
53798
+ return t50;
53799
+ }
53800
+ at(t50) {
53801
+ let e4 = this._root, r4 = false, i3 = 0;
53802
+ const l3 = [];
53803
+ for (;!r4; )
53804
+ if (e4)
53805
+ l3.push(e4), e4 = e4.left;
53806
+ else if (l3.length > 0) {
53807
+ if (e4 = l3.pop(), i3 === t50)
53808
+ return e4;
53809
+ i3++, e4 = e4.right;
53810
+ } else
53811
+ r4 = true;
53812
+ return null;
53813
+ }
53814
+ next(t50) {
53815
+ let e4 = this._root, r4 = null;
53816
+ if (t50.right) {
53817
+ for (r4 = t50.right;r4.left; )
53818
+ r4 = r4.left;
53819
+ return r4;
53820
+ }
53821
+ const i3 = this._comparator;
53822
+ for (;e4; ) {
53823
+ const l3 = i3(t50.key, e4.key);
53824
+ if (l3 === 0)
53825
+ break;
53826
+ l3 < 0 ? (r4 = e4, e4 = e4.left) : e4 = e4.right;
53827
+ }
53828
+ return r4;
53829
+ }
53830
+ prev(t50) {
53831
+ let e4 = this._root, r4 = null;
53832
+ if (t50.left !== null) {
53833
+ for (r4 = t50.left;r4.right; )
53834
+ r4 = r4.right;
53835
+ return r4;
53836
+ }
53837
+ const i3 = this._comparator;
53838
+ for (;e4; ) {
53839
+ const l3 = i3(t50.key, e4.key);
53840
+ if (l3 === 0)
53841
+ break;
53842
+ l3 < 0 ? e4 = e4.left : (r4 = e4, e4 = e4.right);
53843
+ }
53844
+ return r4;
53845
+ }
53846
+ clear() {
53847
+ return this._root = null, this._size = 0, this;
53848
+ }
53849
+ toList() {
53850
+ return y4(this._root);
53851
+ }
53852
+ load(t50, e4 = [], r4 = false) {
53853
+ let i3 = t50.length;
53854
+ const l3 = this._comparator;
53855
+ if (r4 && m4(t50, e4, 0, i3 - 1, l3), this._root === null)
53856
+ this._root = p3(t50, e4, 0, i3), this._size = i3;
53857
+ else {
53858
+ const o3 = z4(this.toList(), k4(t50, e4), l3);
53859
+ i3 = this._size + i3, this._root = g6({ head: o3 }, 0, i3);
53860
+ }
53861
+ return this;
53862
+ }
53863
+ isEmpty() {
53864
+ return this._root === null;
53865
+ }
53866
+ get size() {
53867
+ return this._size;
53868
+ }
53869
+ get root() {
53870
+ return this._root;
53871
+ }
53872
+ toString(t50 = (e4) => String(e4.key)) {
53873
+ const e4 = [];
53874
+ return a3(this._root, "", true, (r4) => e4.push(r4), t50), e4.join("");
53875
+ }
53876
+ update(t50, e4, r4) {
53877
+ const i3 = this._comparator;
53878
+ let { left: l3, right: o3 } = d3(t50, this._root, i3);
53879
+ i3(t50, e4) < 0 ? o3 = _4(e4, r4, o3, i3) : l3 = _4(e4, r4, l3, i3), this._root = w4(l3, o3, i3);
53880
+ }
53881
+ split(t50) {
53882
+ return d3(t50, this._root, this._comparator);
53883
+ }
53884
+ *[Symbol.iterator]() {
53885
+ let t50 = this._root;
53886
+ const e4 = [];
53887
+ let r4 = false;
53888
+ for (;!r4; )
53889
+ t50 !== null ? (e4.push(t50), t50 = t50.left) : e4.length !== 0 ? (t50 = e4.pop(), yield t50, t50 = t50.right) : r4 = true;
53890
+ }
53891
+ }
53892
+ function p3(n3, t50, e4, r4) {
53893
+ const i3 = r4 - e4;
53894
+ if (i3 > 0) {
53895
+ const l3 = e4 + Math.floor(i3 / 2), o3 = n3[l3], s3 = t50[l3], f3 = new h4(o3, s3);
53896
+ return f3.left = p3(n3, t50, e4, l3), f3.right = p3(n3, t50, l3 + 1, r4), f3;
53897
+ }
53898
+ return null;
53899
+ }
53900
+ function k4(n3, t50) {
53901
+ const e4 = new h4(null, null);
53902
+ let r4 = e4;
53903
+ for (let i3 = 0;i3 < n3.length; i3++)
53904
+ r4 = r4.next = new h4(n3[i3], t50[i3]);
53905
+ return r4.next = null, e4.next;
53906
+ }
53907
+ function y4(n3) {
53908
+ let t50 = n3;
53909
+ const e4 = [];
53910
+ let r4 = false;
53911
+ const i3 = new h4(null, null);
53912
+ let l3 = i3;
53913
+ for (;!r4; )
53914
+ t50 ? (e4.push(t50), t50 = t50.left) : e4.length > 0 ? (t50 = l3 = l3.next = e4.pop(), t50 = t50.right) : r4 = true;
53915
+ return l3.next = null, i3.next;
53916
+ }
53917
+ function g6(n3, t50, e4) {
53918
+ const r4 = e4 - t50;
53919
+ if (r4 > 0) {
53920
+ const i3 = t50 + Math.floor(r4 / 2), l3 = g6(n3, t50, i3), o3 = n3.head;
53921
+ return o3.left = l3, n3.head = n3.head.next, o3.right = g6(n3, i3 + 1, e4), o3;
53922
+ }
53923
+ return null;
53924
+ }
53925
+ function z4(n3, t50, e4) {
53926
+ const r4 = new h4(null, null);
53927
+ let i3 = r4, l3 = n3, o3 = t50;
53928
+ for (;l3 !== null && o3 !== null; )
53929
+ e4(l3.key, o3.key) < 0 ? (i3.next = l3, l3 = l3.next) : (i3.next = o3, o3 = o3.next), i3 = i3.next;
53930
+ return l3 !== null ? i3.next = l3 : o3 !== null && (i3.next = o3), r4.next;
53931
+ }
53932
+ function m4(n3, t50, e4, r4, i3) {
53933
+ if (e4 >= r4)
53934
+ return;
53935
+ const l3 = n3[e4 + r4 >> 1];
53936
+ let o3 = e4 - 1, s3 = r4 + 1;
53937
+ for (;; ) {
53938
+ do
53939
+ o3++;
53940
+ while (i3(n3[o3], l3) < 0);
53941
+ do
53942
+ s3--;
53943
+ while (i3(n3[s3], l3) > 0);
53944
+ if (o3 >= s3)
53945
+ break;
53946
+ let f3 = n3[o3];
53947
+ n3[o3] = n3[s3], n3[s3] = f3, f3 = t50[o3], t50[o3] = t50[s3], t50[s3] = f3;
53948
+ }
53949
+ m4(n3, t50, e4, s3, i3), m4(n3, t50, s3 + 1, r4, i3);
53950
+ }
53951
+ return x4;
53952
+ });
53953
+ });
53954
+
53955
+ // node_modules/polygon-clipping/dist/polygon-clipping.cjs.js
53956
+ var require_polygon_clipping_cjs = __commonJS((exports2, module2) => {
53957
+ var SplayTree = require_splaytree_umd();
53958
+ function _interopDefaultLegacy(e4) {
53959
+ return e4 && typeof e4 === "object" && "default" in e4 ? e4 : { default: e4 };
53960
+ }
53961
+ var SplayTree__default = /* @__PURE__ */ _interopDefaultLegacy(SplayTree);
53962
+ var isInBbox = (bbox, point9) => {
53963
+ return bbox.ll.x <= point9.x && point9.x <= bbox.ur.x && bbox.ll.y <= point9.y && point9.y <= bbox.ur.y;
53964
+ };
53965
+ var getBboxOverlap = (b12, b22) => {
53966
+ if (b22.ur.x < b12.ll.x || b12.ur.x < b22.ll.x || b22.ur.y < b12.ll.y || b12.ur.y < b22.ll.y)
53967
+ return null;
53968
+ const lowerX = b12.ll.x < b22.ll.x ? b22.ll.x : b12.ll.x;
53969
+ const upperX = b12.ur.x < b22.ur.x ? b12.ur.x : b22.ur.x;
53970
+ const lowerY = b12.ll.y < b22.ll.y ? b22.ll.y : b12.ll.y;
53971
+ const upperY = b12.ur.y < b22.ur.y ? b12.ur.y : b22.ur.y;
53972
+ return {
53973
+ ll: {
53974
+ x: lowerX,
53975
+ y: lowerY
53976
+ },
53977
+ ur: {
53978
+ x: upperX,
53979
+ y: upperY
53980
+ }
53981
+ };
53982
+ };
53983
+ var epsilon$1 = Number.EPSILON;
53984
+ if (epsilon$1 === undefined)
53985
+ epsilon$1 = Math.pow(2, -52);
53986
+ var EPSILON_SQ = epsilon$1 * epsilon$1;
53987
+ var cmp = (a3, b3) => {
53988
+ if (-epsilon$1 < a3 && a3 < epsilon$1) {
53989
+ if (-epsilon$1 < b3 && b3 < epsilon$1) {
53990
+ return 0;
53991
+ }
53992
+ }
53993
+ const ab2 = a3 - b3;
53994
+ if (ab2 * ab2 < EPSILON_SQ * a3 * b3) {
53995
+ return 0;
53996
+ }
53997
+ return a3 < b3 ? -1 : 1;
53998
+ };
53999
+
54000
+ class PtRounder {
54001
+ constructor() {
54002
+ this.reset();
54003
+ }
54004
+ reset() {
54005
+ this.xRounder = new CoordRounder;
54006
+ this.yRounder = new CoordRounder;
54007
+ }
54008
+ round(x4, y4) {
54009
+ return {
54010
+ x: this.xRounder.round(x4),
54011
+ y: this.yRounder.round(y4)
54012
+ };
54013
+ }
54014
+ }
54015
+
54016
+ class CoordRounder {
54017
+ constructor() {
54018
+ this.tree = new SplayTree__default["default"];
54019
+ this.round(0);
54020
+ }
54021
+ round(coord) {
54022
+ const node = this.tree.add(coord);
54023
+ const prevNode = this.tree.prev(node);
54024
+ if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
54025
+ this.tree.remove(coord);
54026
+ return prevNode.key;
54027
+ }
54028
+ const nextNode = this.tree.next(node);
54029
+ if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
54030
+ this.tree.remove(coord);
54031
+ return nextNode.key;
54032
+ }
54033
+ return coord;
54034
+ }
54035
+ }
54036
+ var rounder = new PtRounder;
54037
+ var epsilon = 0.00000000000000011102230246251565;
54038
+ var splitter = 134217729;
54039
+ var resulterrbound = (3 + 8 * epsilon) * epsilon;
54040
+ function sum(elen, e4, flen, f3, h4) {
54041
+ let Q4, Qnew, hh3, bvirt;
54042
+ let enow = e4[0];
54043
+ let fnow = f3[0];
54044
+ let eindex = 0;
54045
+ let findex = 0;
54046
+ if (fnow > enow === fnow > -enow) {
54047
+ Q4 = enow;
54048
+ enow = e4[++eindex];
54049
+ } else {
54050
+ Q4 = fnow;
54051
+ fnow = f3[++findex];
54052
+ }
54053
+ let hindex = 0;
54054
+ if (eindex < elen && findex < flen) {
54055
+ if (fnow > enow === fnow > -enow) {
54056
+ Qnew = enow + Q4;
54057
+ hh3 = Q4 - (Qnew - enow);
54058
+ enow = e4[++eindex];
54059
+ } else {
54060
+ Qnew = fnow + Q4;
54061
+ hh3 = Q4 - (Qnew - fnow);
54062
+ fnow = f3[++findex];
54063
+ }
54064
+ Q4 = Qnew;
54065
+ if (hh3 !== 0) {
54066
+ h4[hindex++] = hh3;
54067
+ }
54068
+ while (eindex < elen && findex < flen) {
54069
+ if (fnow > enow === fnow > -enow) {
54070
+ Qnew = Q4 + enow;
54071
+ bvirt = Qnew - Q4;
54072
+ hh3 = Q4 - (Qnew - bvirt) + (enow - bvirt);
54073
+ enow = e4[++eindex];
54074
+ } else {
54075
+ Qnew = Q4 + fnow;
54076
+ bvirt = Qnew - Q4;
54077
+ hh3 = Q4 - (Qnew - bvirt) + (fnow - bvirt);
54078
+ fnow = f3[++findex];
54079
+ }
54080
+ Q4 = Qnew;
54081
+ if (hh3 !== 0) {
54082
+ h4[hindex++] = hh3;
54083
+ }
54084
+ }
54085
+ }
54086
+ while (eindex < elen) {
54087
+ Qnew = Q4 + enow;
54088
+ bvirt = Qnew - Q4;
54089
+ hh3 = Q4 - (Qnew - bvirt) + (enow - bvirt);
54090
+ enow = e4[++eindex];
54091
+ Q4 = Qnew;
54092
+ if (hh3 !== 0) {
54093
+ h4[hindex++] = hh3;
54094
+ }
54095
+ }
54096
+ while (findex < flen) {
54097
+ Qnew = Q4 + fnow;
54098
+ bvirt = Qnew - Q4;
54099
+ hh3 = Q4 - (Qnew - bvirt) + (fnow - bvirt);
54100
+ fnow = f3[++findex];
54101
+ Q4 = Qnew;
54102
+ if (hh3 !== 0) {
54103
+ h4[hindex++] = hh3;
54104
+ }
54105
+ }
54106
+ if (Q4 !== 0 || hindex === 0) {
54107
+ h4[hindex++] = Q4;
54108
+ }
54109
+ return hindex;
54110
+ }
54111
+ function estimate(elen, e4) {
54112
+ let Q4 = e4[0];
54113
+ for (let i3 = 1;i3 < elen; i3++)
54114
+ Q4 += e4[i3];
54115
+ return Q4;
54116
+ }
54117
+ function vec(n3) {
54118
+ return new Float64Array(n3);
54119
+ }
54120
+ var ccwerrboundA = (3 + 16 * epsilon) * epsilon;
54121
+ var ccwerrboundB = (2 + 12 * epsilon) * epsilon;
54122
+ var ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon;
54123
+ var B4 = vec(4);
54124
+ var C12 = vec(8);
54125
+ var C22 = vec(12);
54126
+ var D4 = vec(16);
54127
+ var u4 = vec(4);
54128
+ function orient2dadapt(ax3, ay3, bx3, by3, cx3, cy3, detsum) {
54129
+ let acxtail, acytail, bcxtail, bcytail;
54130
+ let bvirt, c3, ahi, alo, bhi, blo, _i3, _j, _02, s12, s02, t110, t02, u32;
54131
+ const acx = ax3 - cx3;
54132
+ const bcx = bx3 - cx3;
54133
+ const acy = ay3 - cy3;
54134
+ const bcy = by3 - cy3;
54135
+ s12 = acx * bcy;
54136
+ c3 = splitter * acx;
54137
+ ahi = c3 - (c3 - acx);
54138
+ alo = acx - ahi;
54139
+ c3 = splitter * bcy;
54140
+ bhi = c3 - (c3 - bcy);
54141
+ blo = bcy - bhi;
54142
+ s02 = alo * blo - (s12 - ahi * bhi - alo * bhi - ahi * blo);
54143
+ t110 = acy * bcx;
54144
+ c3 = splitter * acy;
54145
+ ahi = c3 - (c3 - acy);
54146
+ alo = acy - ahi;
54147
+ c3 = splitter * bcx;
54148
+ bhi = c3 - (c3 - bcx);
54149
+ blo = bcx - bhi;
54150
+ t02 = alo * blo - (t110 - ahi * bhi - alo * bhi - ahi * blo);
54151
+ _i3 = s02 - t02;
54152
+ bvirt = s02 - _i3;
54153
+ B4[0] = s02 - (_i3 + bvirt) + (bvirt - t02);
54154
+ _j = s12 + _i3;
54155
+ bvirt = _j - s12;
54156
+ _02 = s12 - (_j - bvirt) + (_i3 - bvirt);
54157
+ _i3 = _02 - t110;
54158
+ bvirt = _02 - _i3;
54159
+ B4[1] = _02 - (_i3 + bvirt) + (bvirt - t110);
54160
+ u32 = _j + _i3;
54161
+ bvirt = u32 - _j;
54162
+ B4[2] = _j - (u32 - bvirt) + (_i3 - bvirt);
54163
+ B4[3] = u32;
54164
+ let det = estimate(4, B4);
54165
+ let errbound = ccwerrboundB * detsum;
54166
+ if (det >= errbound || -det >= errbound) {
54167
+ return det;
54168
+ }
54169
+ bvirt = ax3 - acx;
54170
+ acxtail = ax3 - (acx + bvirt) + (bvirt - cx3);
54171
+ bvirt = bx3 - bcx;
54172
+ bcxtail = bx3 - (bcx + bvirt) + (bvirt - cx3);
54173
+ bvirt = ay3 - acy;
54174
+ acytail = ay3 - (acy + bvirt) + (bvirt - cy3);
54175
+ bvirt = by3 - bcy;
54176
+ bcytail = by3 - (bcy + bvirt) + (bvirt - cy3);
54177
+ if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
54178
+ return det;
54179
+ }
54180
+ errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
54181
+ det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
54182
+ if (det >= errbound || -det >= errbound)
54183
+ return det;
54184
+ s12 = acxtail * bcy;
54185
+ c3 = splitter * acxtail;
54186
+ ahi = c3 - (c3 - acxtail);
54187
+ alo = acxtail - ahi;
54188
+ c3 = splitter * bcy;
54189
+ bhi = c3 - (c3 - bcy);
54190
+ blo = bcy - bhi;
54191
+ s02 = alo * blo - (s12 - ahi * bhi - alo * bhi - ahi * blo);
54192
+ t110 = acytail * bcx;
54193
+ c3 = splitter * acytail;
54194
+ ahi = c3 - (c3 - acytail);
54195
+ alo = acytail - ahi;
54196
+ c3 = splitter * bcx;
54197
+ bhi = c3 - (c3 - bcx);
54198
+ blo = bcx - bhi;
54199
+ t02 = alo * blo - (t110 - ahi * bhi - alo * bhi - ahi * blo);
54200
+ _i3 = s02 - t02;
54201
+ bvirt = s02 - _i3;
54202
+ u4[0] = s02 - (_i3 + bvirt) + (bvirt - t02);
54203
+ _j = s12 + _i3;
54204
+ bvirt = _j - s12;
54205
+ _02 = s12 - (_j - bvirt) + (_i3 - bvirt);
54206
+ _i3 = _02 - t110;
54207
+ bvirt = _02 - _i3;
54208
+ u4[1] = _02 - (_i3 + bvirt) + (bvirt - t110);
54209
+ u32 = _j + _i3;
54210
+ bvirt = u32 - _j;
54211
+ u4[2] = _j - (u32 - bvirt) + (_i3 - bvirt);
54212
+ u4[3] = u32;
54213
+ const C1len = sum(4, B4, 4, u4, C12);
54214
+ s12 = acx * bcytail;
54215
+ c3 = splitter * acx;
54216
+ ahi = c3 - (c3 - acx);
54217
+ alo = acx - ahi;
54218
+ c3 = splitter * bcytail;
54219
+ bhi = c3 - (c3 - bcytail);
54220
+ blo = bcytail - bhi;
54221
+ s02 = alo * blo - (s12 - ahi * bhi - alo * bhi - ahi * blo);
54222
+ t110 = acy * bcxtail;
54223
+ c3 = splitter * acy;
54224
+ ahi = c3 - (c3 - acy);
54225
+ alo = acy - ahi;
54226
+ c3 = splitter * bcxtail;
54227
+ bhi = c3 - (c3 - bcxtail);
54228
+ blo = bcxtail - bhi;
54229
+ t02 = alo * blo - (t110 - ahi * bhi - alo * bhi - ahi * blo);
54230
+ _i3 = s02 - t02;
54231
+ bvirt = s02 - _i3;
54232
+ u4[0] = s02 - (_i3 + bvirt) + (bvirt - t02);
54233
+ _j = s12 + _i3;
54234
+ bvirt = _j - s12;
54235
+ _02 = s12 - (_j - bvirt) + (_i3 - bvirt);
54236
+ _i3 = _02 - t110;
54237
+ bvirt = _02 - _i3;
54238
+ u4[1] = _02 - (_i3 + bvirt) + (bvirt - t110);
54239
+ u32 = _j + _i3;
54240
+ bvirt = u32 - _j;
54241
+ u4[2] = _j - (u32 - bvirt) + (_i3 - bvirt);
54242
+ u4[3] = u32;
54243
+ const C2len = sum(C1len, C12, 4, u4, C22);
54244
+ s12 = acxtail * bcytail;
54245
+ c3 = splitter * acxtail;
54246
+ ahi = c3 - (c3 - acxtail);
54247
+ alo = acxtail - ahi;
54248
+ c3 = splitter * bcytail;
54249
+ bhi = c3 - (c3 - bcytail);
54250
+ blo = bcytail - bhi;
54251
+ s02 = alo * blo - (s12 - ahi * bhi - alo * bhi - ahi * blo);
54252
+ t110 = acytail * bcxtail;
54253
+ c3 = splitter * acytail;
54254
+ ahi = c3 - (c3 - acytail);
54255
+ alo = acytail - ahi;
54256
+ c3 = splitter * bcxtail;
54257
+ bhi = c3 - (c3 - bcxtail);
54258
+ blo = bcxtail - bhi;
54259
+ t02 = alo * blo - (t110 - ahi * bhi - alo * bhi - ahi * blo);
54260
+ _i3 = s02 - t02;
54261
+ bvirt = s02 - _i3;
54262
+ u4[0] = s02 - (_i3 + bvirt) + (bvirt - t02);
54263
+ _j = s12 + _i3;
54264
+ bvirt = _j - s12;
54265
+ _02 = s12 - (_j - bvirt) + (_i3 - bvirt);
54266
+ _i3 = _02 - t110;
54267
+ bvirt = _02 - _i3;
54268
+ u4[1] = _02 - (_i3 + bvirt) + (bvirt - t110);
54269
+ u32 = _j + _i3;
54270
+ bvirt = u32 - _j;
54271
+ u4[2] = _j - (u32 - bvirt) + (_i3 - bvirt);
54272
+ u4[3] = u32;
54273
+ const Dlen = sum(C2len, C22, 4, u4, D4);
54274
+ return D4[Dlen - 1];
54275
+ }
54276
+ function orient2d(ax3, ay3, bx3, by3, cx3, cy3) {
54277
+ const detleft = (ay3 - cy3) * (bx3 - cx3);
54278
+ const detright = (ax3 - cx3) * (by3 - cy3);
54279
+ const det = detleft - detright;
54280
+ const detsum = Math.abs(detleft + detright);
54281
+ if (Math.abs(det) >= ccwerrboundA * detsum)
54282
+ return det;
54283
+ return -orient2dadapt(ax3, ay3, bx3, by3, cx3, cy3, detsum);
54284
+ }
54285
+ var crossProduct = (a3, b3) => a3.x * b3.y - a3.y * b3.x;
54286
+ var dotProduct = (a3, b3) => a3.x * b3.x + a3.y * b3.y;
54287
+ var compareVectorAngles = (basePt, endPt1, endPt2) => {
54288
+ const res2 = orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y);
54289
+ if (res2 > 0)
54290
+ return -1;
54291
+ if (res2 < 0)
54292
+ return 1;
54293
+ return 0;
54294
+ };
54295
+ var length67 = (v4) => Math.sqrt(dotProduct(v4, v4));
54296
+ var sineOfAngle = (pShared, pBase, pAngle) => {
54297
+ const vBase = {
54298
+ x: pBase.x - pShared.x,
54299
+ y: pBase.y - pShared.y
54300
+ };
54301
+ const vAngle = {
54302
+ x: pAngle.x - pShared.x,
54303
+ y: pAngle.y - pShared.y
54304
+ };
54305
+ return crossProduct(vAngle, vBase) / length67(vAngle) / length67(vBase);
54306
+ };
54307
+ var cosineOfAngle = (pShared, pBase, pAngle) => {
54308
+ const vBase = {
54309
+ x: pBase.x - pShared.x,
54310
+ y: pBase.y - pShared.y
54311
+ };
54312
+ const vAngle = {
54313
+ x: pAngle.x - pShared.x,
54314
+ y: pAngle.y - pShared.y
54315
+ };
54316
+ return dotProduct(vAngle, vBase) / length67(vAngle) / length67(vBase);
54317
+ };
54318
+ var horizontalIntersection = (pt3, v4, y4) => {
54319
+ if (v4.y === 0)
54320
+ return null;
54321
+ return {
54322
+ x: pt3.x + v4.x / v4.y * (y4 - pt3.y),
54323
+ y: y4
54324
+ };
54325
+ };
54326
+ var verticalIntersection = (pt3, v4, x4) => {
54327
+ if (v4.x === 0)
54328
+ return null;
54329
+ return {
54330
+ x: x4,
54331
+ y: pt3.y + v4.y / v4.x * (x4 - pt3.x)
54332
+ };
54333
+ };
54334
+ var intersection$1 = (pt1, v12, pt22, v22) => {
54335
+ if (v12.x === 0)
54336
+ return verticalIntersection(pt22, v22, pt1.x);
54337
+ if (v22.x === 0)
54338
+ return verticalIntersection(pt1, v12, pt22.x);
54339
+ if (v12.y === 0)
54340
+ return horizontalIntersection(pt22, v22, pt1.y);
54341
+ if (v22.y === 0)
54342
+ return horizontalIntersection(pt1, v12, pt22.y);
54343
+ const kross = crossProduct(v12, v22);
54344
+ if (kross == 0)
54345
+ return null;
54346
+ const ve3 = {
54347
+ x: pt22.x - pt1.x,
54348
+ y: pt22.y - pt1.y
54349
+ };
54350
+ const d12 = crossProduct(ve3, v12) / kross;
54351
+ const d23 = crossProduct(ve3, v22) / kross;
54352
+ const x12 = pt1.x + d23 * v12.x, x22 = pt22.x + d12 * v22.x;
54353
+ const y12 = pt1.y + d23 * v12.y, y22 = pt22.y + d12 * v22.y;
54354
+ const x4 = (x12 + x22) / 2;
54355
+ const y4 = (y12 + y22) / 2;
54356
+ return {
54357
+ x: x4,
54358
+ y: y4
54359
+ };
54360
+ };
54361
+
54362
+ class SweepEvent {
54363
+ static compare(a3, b3) {
54364
+ const ptCmp = SweepEvent.comparePoints(a3.point, b3.point);
54365
+ if (ptCmp !== 0)
54366
+ return ptCmp;
54367
+ if (a3.point !== b3.point)
54368
+ a3.link(b3);
54369
+ if (a3.isLeft !== b3.isLeft)
54370
+ return a3.isLeft ? 1 : -1;
54371
+ return Segment3.compare(a3.segment, b3.segment);
54372
+ }
54373
+ static comparePoints(aPt, bPt) {
54374
+ if (aPt.x < bPt.x)
54375
+ return -1;
54376
+ if (aPt.x > bPt.x)
54377
+ return 1;
54378
+ if (aPt.y < bPt.y)
54379
+ return -1;
54380
+ if (aPt.y > bPt.y)
54381
+ return 1;
54382
+ return 0;
54383
+ }
54384
+ constructor(point9, isLeft) {
54385
+ if (point9.events === undefined)
54386
+ point9.events = [this];
54387
+ else
54388
+ point9.events.push(this);
54389
+ this.point = point9;
54390
+ this.isLeft = isLeft;
54391
+ }
54392
+ link(other) {
54393
+ if (other.point === this.point) {
54394
+ throw new Error("Tried to link already linked events");
54395
+ }
54396
+ const otherEvents = other.point.events;
54397
+ for (let i3 = 0, iMax = otherEvents.length;i3 < iMax; i3++) {
54398
+ const evt = otherEvents[i3];
54399
+ this.point.events.push(evt);
54400
+ evt.point = this.point;
54401
+ }
54402
+ this.checkForConsuming();
54403
+ }
54404
+ checkForConsuming() {
54405
+ const numEvents = this.point.events.length;
54406
+ for (let i3 = 0;i3 < numEvents; i3++) {
54407
+ const evt1 = this.point.events[i3];
54408
+ if (evt1.segment.consumedBy !== undefined)
54409
+ continue;
54410
+ for (let j4 = i3 + 1;j4 < numEvents; j4++) {
54411
+ const evt2 = this.point.events[j4];
54412
+ if (evt2.consumedBy !== undefined)
54413
+ continue;
54414
+ if (evt1.otherSE.point.events !== evt2.otherSE.point.events)
54415
+ continue;
54416
+ evt1.segment.consume(evt2.segment);
54417
+ }
54418
+ }
54419
+ }
54420
+ getAvailableLinkedEvents() {
54421
+ const events = [];
54422
+ for (let i3 = 0, iMax = this.point.events.length;i3 < iMax; i3++) {
54423
+ const evt = this.point.events[i3];
54424
+ if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
54425
+ events.push(evt);
54426
+ }
54427
+ }
54428
+ return events;
54429
+ }
54430
+ getLeftmostComparator(baseEvent) {
54431
+ const cache = new Map;
54432
+ const fillCache = (linkedEvent) => {
54433
+ const nextEvent = linkedEvent.otherSE;
54434
+ cache.set(linkedEvent, {
54435
+ sine: sineOfAngle(this.point, baseEvent.point, nextEvent.point),
54436
+ cosine: cosineOfAngle(this.point, baseEvent.point, nextEvent.point)
54437
+ });
54438
+ };
54439
+ return (a3, b3) => {
54440
+ if (!cache.has(a3))
54441
+ fillCache(a3);
54442
+ if (!cache.has(b3))
54443
+ fillCache(b3);
54444
+ const {
54445
+ sine: asine,
54446
+ cosine: acosine
54447
+ } = cache.get(a3);
54448
+ const {
54449
+ sine: bsine,
54450
+ cosine: bcosine
54451
+ } = cache.get(b3);
54452
+ if (asine >= 0 && bsine >= 0) {
54453
+ if (acosine < bcosine)
54454
+ return 1;
54455
+ if (acosine > bcosine)
54456
+ return -1;
54457
+ return 0;
54458
+ }
54459
+ if (asine < 0 && bsine < 0) {
54460
+ if (acosine < bcosine)
54461
+ return -1;
54462
+ if (acosine > bcosine)
54463
+ return 1;
54464
+ return 0;
54465
+ }
54466
+ if (bsine < asine)
54467
+ return -1;
54468
+ if (bsine > asine)
54469
+ return 1;
54470
+ return 0;
54471
+ };
54472
+ }
54473
+ }
54474
+ var segmentId = 0;
54475
+
54476
+ class Segment3 {
54477
+ static compare(a3, b3) {
54478
+ const alx = a3.leftSE.point.x;
54479
+ const blx = b3.leftSE.point.x;
54480
+ const arx = a3.rightSE.point.x;
54481
+ const brx = b3.rightSE.point.x;
54482
+ if (brx < alx)
54483
+ return 1;
54484
+ if (arx < blx)
54485
+ return -1;
54486
+ const aly = a3.leftSE.point.y;
54487
+ const bly = b3.leftSE.point.y;
54488
+ const ary = a3.rightSE.point.y;
54489
+ const bry = b3.rightSE.point.y;
54490
+ if (alx < blx) {
54491
+ if (bly < aly && bly < ary)
54492
+ return 1;
54493
+ if (bly > aly && bly > ary)
54494
+ return -1;
54495
+ const aCmpBLeft = a3.comparePoint(b3.leftSE.point);
54496
+ if (aCmpBLeft < 0)
54497
+ return 1;
54498
+ if (aCmpBLeft > 0)
54499
+ return -1;
54500
+ const bCmpARight = b3.comparePoint(a3.rightSE.point);
54501
+ if (bCmpARight !== 0)
54502
+ return bCmpARight;
54503
+ return -1;
54504
+ }
54505
+ if (alx > blx) {
54506
+ if (aly < bly && aly < bry)
54507
+ return -1;
54508
+ if (aly > bly && aly > bry)
54509
+ return 1;
54510
+ const bCmpALeft = b3.comparePoint(a3.leftSE.point);
54511
+ if (bCmpALeft !== 0)
54512
+ return bCmpALeft;
54513
+ const aCmpBRight = a3.comparePoint(b3.rightSE.point);
54514
+ if (aCmpBRight < 0)
54515
+ return 1;
54516
+ if (aCmpBRight > 0)
54517
+ return -1;
54518
+ return 1;
54519
+ }
54520
+ if (aly < bly)
54521
+ return -1;
54522
+ if (aly > bly)
54523
+ return 1;
54524
+ if (arx < brx) {
54525
+ const bCmpARight = b3.comparePoint(a3.rightSE.point);
54526
+ if (bCmpARight !== 0)
54527
+ return bCmpARight;
54528
+ }
54529
+ if (arx > brx) {
54530
+ const aCmpBRight = a3.comparePoint(b3.rightSE.point);
54531
+ if (aCmpBRight < 0)
54532
+ return 1;
54533
+ if (aCmpBRight > 0)
54534
+ return -1;
54535
+ }
54536
+ if (arx !== brx) {
54537
+ const ay3 = ary - aly;
54538
+ const ax3 = arx - alx;
54539
+ const by3 = bry - bly;
54540
+ const bx3 = brx - blx;
54541
+ if (ay3 > ax3 && by3 < bx3)
54542
+ return 1;
54543
+ if (ay3 < ax3 && by3 > bx3)
54544
+ return -1;
54545
+ }
54546
+ if (arx > brx)
54547
+ return 1;
54548
+ if (arx < brx)
54549
+ return -1;
54550
+ if (ary < bry)
54551
+ return -1;
54552
+ if (ary > bry)
54553
+ return 1;
54554
+ if (a3.id < b3.id)
54555
+ return -1;
54556
+ if (a3.id > b3.id)
54557
+ return 1;
54558
+ return 0;
54559
+ }
54560
+ constructor(leftSE, rightSE, rings, windings) {
54561
+ this.id = ++segmentId;
54562
+ this.leftSE = leftSE;
54563
+ leftSE.segment = this;
54564
+ leftSE.otherSE = rightSE;
54565
+ this.rightSE = rightSE;
54566
+ rightSE.segment = this;
54567
+ rightSE.otherSE = leftSE;
54568
+ this.rings = rings;
54569
+ this.windings = windings;
54570
+ }
54571
+ static fromRing(pt1, pt22, ring) {
54572
+ let leftPt, rightPt, winding;
54573
+ const cmpPts = SweepEvent.comparePoints(pt1, pt22);
54574
+ if (cmpPts < 0) {
54575
+ leftPt = pt1;
54576
+ rightPt = pt22;
54577
+ winding = 1;
54578
+ } else if (cmpPts > 0) {
54579
+ leftPt = pt22;
54580
+ rightPt = pt1;
54581
+ winding = -1;
54582
+ } else
54583
+ throw new Error(`Tried to create degenerate segment at [${pt1.x}, ${pt1.y}]`);
54584
+ const leftSE = new SweepEvent(leftPt, true);
54585
+ const rightSE = new SweepEvent(rightPt, false);
54586
+ return new Segment3(leftSE, rightSE, [ring], [winding]);
54587
+ }
54588
+ replaceRightSE(newRightSE) {
54589
+ this.rightSE = newRightSE;
54590
+ this.rightSE.segment = this;
54591
+ this.rightSE.otherSE = this.leftSE;
54592
+ this.leftSE.otherSE = this.rightSE;
54593
+ }
54594
+ bbox() {
54595
+ const y12 = this.leftSE.point.y;
54596
+ const y22 = this.rightSE.point.y;
54597
+ return {
54598
+ ll: {
54599
+ x: this.leftSE.point.x,
54600
+ y: y12 < y22 ? y12 : y22
54601
+ },
54602
+ ur: {
54603
+ x: this.rightSE.point.x,
54604
+ y: y12 > y22 ? y12 : y22
54605
+ }
54606
+ };
54607
+ }
54608
+ vector() {
54609
+ return {
54610
+ x: this.rightSE.point.x - this.leftSE.point.x,
54611
+ y: this.rightSE.point.y - this.leftSE.point.y
54612
+ };
54613
+ }
54614
+ isAnEndpoint(pt3) {
54615
+ return pt3.x === this.leftSE.point.x && pt3.y === this.leftSE.point.y || pt3.x === this.rightSE.point.x && pt3.y === this.rightSE.point.y;
54616
+ }
54617
+ comparePoint(point9) {
54618
+ if (this.isAnEndpoint(point9))
54619
+ return 0;
54620
+ const lPt = this.leftSE.point;
54621
+ const rPt = this.rightSE.point;
54622
+ const v4 = this.vector();
54623
+ if (lPt.x === rPt.x) {
54624
+ if (point9.x === lPt.x)
54625
+ return 0;
54626
+ return point9.x < lPt.x ? 1 : -1;
54627
+ }
54628
+ const yDist = (point9.y - lPt.y) / v4.y;
54629
+ const xFromYDist = lPt.x + yDist * v4.x;
54630
+ if (point9.x === xFromYDist)
54631
+ return 0;
54632
+ const xDist = (point9.x - lPt.x) / v4.x;
54633
+ const yFromXDist = lPt.y + xDist * v4.y;
54634
+ if (point9.y === yFromXDist)
54635
+ return 0;
54636
+ return point9.y < yFromXDist ? -1 : 1;
54637
+ }
54638
+ getIntersection(other) {
54639
+ const tBbox = this.bbox();
54640
+ const oBbox = other.bbox();
54641
+ const bboxOverlap = getBboxOverlap(tBbox, oBbox);
54642
+ if (bboxOverlap === null)
54643
+ return null;
54644
+ const tlp = this.leftSE.point;
54645
+ const trp = this.rightSE.point;
54646
+ const olp = other.leftSE.point;
54647
+ const orp = other.rightSE.point;
54648
+ const touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
54649
+ const touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
54650
+ const touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
54651
+ const touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0;
54652
+ if (touchesThisLSE && touchesOtherLSE) {
54653
+ if (touchesThisRSE && !touchesOtherRSE)
54654
+ return trp;
54655
+ if (!touchesThisRSE && touchesOtherRSE)
54656
+ return orp;
54657
+ return null;
54658
+ }
54659
+ if (touchesThisLSE) {
54660
+ if (touchesOtherRSE) {
54661
+ if (tlp.x === orp.x && tlp.y === orp.y)
54662
+ return null;
54663
+ }
54664
+ return tlp;
54665
+ }
54666
+ if (touchesOtherLSE) {
54667
+ if (touchesThisRSE) {
54668
+ if (trp.x === olp.x && trp.y === olp.y)
54669
+ return null;
54670
+ }
54671
+ return olp;
54672
+ }
54673
+ if (touchesThisRSE && touchesOtherRSE)
54674
+ return null;
54675
+ if (touchesThisRSE)
54676
+ return trp;
54677
+ if (touchesOtherRSE)
54678
+ return orp;
54679
+ const pt3 = intersection$1(tlp, this.vector(), olp, other.vector());
54680
+ if (pt3 === null)
54681
+ return null;
54682
+ if (!isInBbox(bboxOverlap, pt3))
54683
+ return null;
54684
+ return rounder.round(pt3.x, pt3.y);
54685
+ }
54686
+ split(point9) {
54687
+ const newEvents = [];
54688
+ const alreadyLinked = point9.events !== undefined;
54689
+ const newLeftSE = new SweepEvent(point9, true);
54690
+ const newRightSE = new SweepEvent(point9, false);
54691
+ const oldRightSE = this.rightSE;
54692
+ this.replaceRightSE(newRightSE);
54693
+ newEvents.push(newRightSE);
54694
+ newEvents.push(newLeftSE);
54695
+ const newSeg = new Segment3(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice());
54696
+ if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
54697
+ newSeg.swapEvents();
54698
+ }
54699
+ if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
54700
+ this.swapEvents();
54701
+ }
54702
+ if (alreadyLinked) {
54703
+ newLeftSE.checkForConsuming();
54704
+ newRightSE.checkForConsuming();
54705
+ }
54706
+ return newEvents;
54707
+ }
54708
+ swapEvents() {
54709
+ const tmpEvt = this.rightSE;
54710
+ this.rightSE = this.leftSE;
54711
+ this.leftSE = tmpEvt;
54712
+ this.leftSE.isLeft = true;
54713
+ this.rightSE.isLeft = false;
54714
+ for (let i3 = 0, iMax = this.windings.length;i3 < iMax; i3++) {
54715
+ this.windings[i3] *= -1;
54716
+ }
54717
+ }
54718
+ consume(other) {
54719
+ let consumer = this;
54720
+ let consumee = other;
54721
+ while (consumer.consumedBy)
54722
+ consumer = consumer.consumedBy;
54723
+ while (consumee.consumedBy)
54724
+ consumee = consumee.consumedBy;
54725
+ const cmp2 = Segment3.compare(consumer, consumee);
54726
+ if (cmp2 === 0)
54727
+ return;
54728
+ if (cmp2 > 0) {
54729
+ const tmp = consumer;
54730
+ consumer = consumee;
54731
+ consumee = tmp;
54732
+ }
54733
+ if (consumer.prev === consumee) {
54734
+ const tmp = consumer;
54735
+ consumer = consumee;
54736
+ consumee = tmp;
54737
+ }
54738
+ for (let i3 = 0, iMax = consumee.rings.length;i3 < iMax; i3++) {
54739
+ const ring = consumee.rings[i3];
54740
+ const winding = consumee.windings[i3];
54741
+ const index2 = consumer.rings.indexOf(ring);
54742
+ if (index2 === -1) {
54743
+ consumer.rings.push(ring);
54744
+ consumer.windings.push(winding);
54745
+ } else
54746
+ consumer.windings[index2] += winding;
54747
+ }
54748
+ consumee.rings = null;
54749
+ consumee.windings = null;
54750
+ consumee.consumedBy = consumer;
54751
+ consumee.leftSE.consumedBy = consumer.leftSE;
54752
+ consumee.rightSE.consumedBy = consumer.rightSE;
54753
+ }
54754
+ prevInResult() {
54755
+ if (this._prevInResult !== undefined)
54756
+ return this._prevInResult;
54757
+ if (!this.prev)
54758
+ this._prevInResult = null;
54759
+ else if (this.prev.isInResult())
54760
+ this._prevInResult = this.prev;
54761
+ else
54762
+ this._prevInResult = this.prev.prevInResult();
54763
+ return this._prevInResult;
54764
+ }
54765
+ beforeState() {
54766
+ if (this._beforeState !== undefined)
54767
+ return this._beforeState;
54768
+ if (!this.prev)
54769
+ this._beforeState = {
54770
+ rings: [],
54771
+ windings: [],
54772
+ multiPolys: []
54773
+ };
54774
+ else {
54775
+ const seg = this.prev.consumedBy || this.prev;
54776
+ this._beforeState = seg.afterState();
54777
+ }
54778
+ return this._beforeState;
54779
+ }
54780
+ afterState() {
54781
+ if (this._afterState !== undefined)
54782
+ return this._afterState;
54783
+ const beforeState = this.beforeState();
54784
+ this._afterState = {
54785
+ rings: beforeState.rings.slice(0),
54786
+ windings: beforeState.windings.slice(0),
54787
+ multiPolys: []
54788
+ };
54789
+ const ringsAfter = this._afterState.rings;
54790
+ const windingsAfter = this._afterState.windings;
54791
+ const mpsAfter = this._afterState.multiPolys;
54792
+ for (let i3 = 0, iMax = this.rings.length;i3 < iMax; i3++) {
54793
+ const ring = this.rings[i3];
54794
+ const winding = this.windings[i3];
54795
+ const index2 = ringsAfter.indexOf(ring);
54796
+ if (index2 === -1) {
54797
+ ringsAfter.push(ring);
54798
+ windingsAfter.push(winding);
54799
+ } else
54800
+ windingsAfter[index2] += winding;
54801
+ }
54802
+ const polysAfter = [];
54803
+ const polysExclude = [];
54804
+ for (let i3 = 0, iMax = ringsAfter.length;i3 < iMax; i3++) {
54805
+ if (windingsAfter[i3] === 0)
54806
+ continue;
54807
+ const ring = ringsAfter[i3];
54808
+ const poly = ring.poly;
54809
+ if (polysExclude.indexOf(poly) !== -1)
54810
+ continue;
54811
+ if (ring.isExterior)
54812
+ polysAfter.push(poly);
54813
+ else {
54814
+ if (polysExclude.indexOf(poly) === -1)
54815
+ polysExclude.push(poly);
54816
+ const index2 = polysAfter.indexOf(ring.poly);
54817
+ if (index2 !== -1)
54818
+ polysAfter.splice(index2, 1);
54819
+ }
54820
+ }
54821
+ for (let i3 = 0, iMax = polysAfter.length;i3 < iMax; i3++) {
54822
+ const mp3 = polysAfter[i3].multiPoly;
54823
+ if (mpsAfter.indexOf(mp3) === -1)
54824
+ mpsAfter.push(mp3);
54825
+ }
54826
+ return this._afterState;
54827
+ }
54828
+ isInResult() {
54829
+ if (this.consumedBy)
54830
+ return false;
54831
+ if (this._isInResult !== undefined)
54832
+ return this._isInResult;
54833
+ const mpsBefore = this.beforeState().multiPolys;
54834
+ const mpsAfter = this.afterState().multiPolys;
54835
+ switch (operation.type) {
54836
+ case "union": {
54837
+ const noBefores = mpsBefore.length === 0;
54838
+ const noAfters = mpsAfter.length === 0;
54839
+ this._isInResult = noBefores !== noAfters;
54840
+ break;
54841
+ }
54842
+ case "intersection": {
54843
+ let least;
54844
+ let most;
54845
+ if (mpsBefore.length < mpsAfter.length) {
54846
+ least = mpsBefore.length;
54847
+ most = mpsAfter.length;
54848
+ } else {
54849
+ least = mpsAfter.length;
54850
+ most = mpsBefore.length;
54851
+ }
54852
+ this._isInResult = most === operation.numMultiPolys && least < most;
54853
+ break;
54854
+ }
54855
+ case "xor": {
54856
+ const diff = Math.abs(mpsBefore.length - mpsAfter.length);
54857
+ this._isInResult = diff % 2 === 1;
54858
+ break;
54859
+ }
54860
+ case "difference": {
54861
+ const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
54862
+ this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
54863
+ break;
54864
+ }
54865
+ default:
54866
+ throw new Error(`Unrecognized operation type found ${operation.type}`);
54867
+ }
54868
+ return this._isInResult;
54869
+ }
54870
+ }
54871
+
54872
+ class RingIn {
54873
+ constructor(geomRing, poly, isExterior) {
54874
+ if (!Array.isArray(geomRing) || geomRing.length === 0) {
54875
+ throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
54876
+ }
54877
+ this.poly = poly;
54878
+ this.isExterior = isExterior;
54879
+ this.segments = [];
54880
+ if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
54881
+ throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
54882
+ }
54883
+ const firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
54884
+ this.bbox = {
54885
+ ll: {
54886
+ x: firstPoint.x,
54887
+ y: firstPoint.y
54888
+ },
54889
+ ur: {
54890
+ x: firstPoint.x,
54891
+ y: firstPoint.y
54892
+ }
54893
+ };
54894
+ let prevPoint = firstPoint;
54895
+ for (let i3 = 1, iMax = geomRing.length;i3 < iMax; i3++) {
54896
+ if (typeof geomRing[i3][0] !== "number" || typeof geomRing[i3][1] !== "number") {
54897
+ throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
54898
+ }
54899
+ let point9 = rounder.round(geomRing[i3][0], geomRing[i3][1]);
54900
+ if (point9.x === prevPoint.x && point9.y === prevPoint.y)
54901
+ continue;
54902
+ this.segments.push(Segment3.fromRing(prevPoint, point9, this));
54903
+ if (point9.x < this.bbox.ll.x)
54904
+ this.bbox.ll.x = point9.x;
54905
+ if (point9.y < this.bbox.ll.y)
54906
+ this.bbox.ll.y = point9.y;
54907
+ if (point9.x > this.bbox.ur.x)
54908
+ this.bbox.ur.x = point9.x;
54909
+ if (point9.y > this.bbox.ur.y)
54910
+ this.bbox.ur.y = point9.y;
54911
+ prevPoint = point9;
54912
+ }
54913
+ if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
54914
+ this.segments.push(Segment3.fromRing(prevPoint, firstPoint, this));
54915
+ }
54916
+ }
54917
+ getSweepEvents() {
54918
+ const sweepEvents = [];
54919
+ for (let i3 = 0, iMax = this.segments.length;i3 < iMax; i3++) {
54920
+ const segment2 = this.segments[i3];
54921
+ sweepEvents.push(segment2.leftSE);
54922
+ sweepEvents.push(segment2.rightSE);
54923
+ }
54924
+ return sweepEvents;
54925
+ }
54926
+ }
54927
+
54928
+ class PolyIn {
54929
+ constructor(geomPoly, multiPoly) {
54930
+ if (!Array.isArray(geomPoly)) {
54931
+ throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
54932
+ }
54933
+ this.exteriorRing = new RingIn(geomPoly[0], this, true);
54934
+ this.bbox = {
54935
+ ll: {
54936
+ x: this.exteriorRing.bbox.ll.x,
54937
+ y: this.exteriorRing.bbox.ll.y
54938
+ },
54939
+ ur: {
54940
+ x: this.exteriorRing.bbox.ur.x,
54941
+ y: this.exteriorRing.bbox.ur.y
54942
+ }
54943
+ };
54944
+ this.interiorRings = [];
54945
+ for (let i3 = 1, iMax = geomPoly.length;i3 < iMax; i3++) {
54946
+ const ring = new RingIn(geomPoly[i3], this, false);
54947
+ if (ring.bbox.ll.x < this.bbox.ll.x)
54948
+ this.bbox.ll.x = ring.bbox.ll.x;
54949
+ if (ring.bbox.ll.y < this.bbox.ll.y)
54950
+ this.bbox.ll.y = ring.bbox.ll.y;
54951
+ if (ring.bbox.ur.x > this.bbox.ur.x)
54952
+ this.bbox.ur.x = ring.bbox.ur.x;
54953
+ if (ring.bbox.ur.y > this.bbox.ur.y)
54954
+ this.bbox.ur.y = ring.bbox.ur.y;
54955
+ this.interiorRings.push(ring);
54956
+ }
54957
+ this.multiPoly = multiPoly;
54958
+ }
54959
+ getSweepEvents() {
54960
+ const sweepEvents = this.exteriorRing.getSweepEvents();
54961
+ for (let i3 = 0, iMax = this.interiorRings.length;i3 < iMax; i3++) {
54962
+ const ringSweepEvents = this.interiorRings[i3].getSweepEvents();
54963
+ for (let j4 = 0, jMax = ringSweepEvents.length;j4 < jMax; j4++) {
54964
+ sweepEvents.push(ringSweepEvents[j4]);
54965
+ }
54966
+ }
54967
+ return sweepEvents;
54968
+ }
54969
+ }
54970
+
54971
+ class MultiPolyIn {
54972
+ constructor(geom, isSubject) {
54973
+ if (!Array.isArray(geom)) {
54974
+ throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
54975
+ }
54976
+ try {
54977
+ if (typeof geom[0][0][0] === "number")
54978
+ geom = [geom];
54979
+ } catch (ex3) {}
54980
+ this.polys = [];
54981
+ this.bbox = {
54982
+ ll: {
54983
+ x: Number.POSITIVE_INFINITY,
54984
+ y: Number.POSITIVE_INFINITY
54985
+ },
54986
+ ur: {
54987
+ x: Number.NEGATIVE_INFINITY,
54988
+ y: Number.NEGATIVE_INFINITY
54989
+ }
54990
+ };
54991
+ for (let i3 = 0, iMax = geom.length;i3 < iMax; i3++) {
54992
+ const poly = new PolyIn(geom[i3], this);
54993
+ if (poly.bbox.ll.x < this.bbox.ll.x)
54994
+ this.bbox.ll.x = poly.bbox.ll.x;
54995
+ if (poly.bbox.ll.y < this.bbox.ll.y)
54996
+ this.bbox.ll.y = poly.bbox.ll.y;
54997
+ if (poly.bbox.ur.x > this.bbox.ur.x)
54998
+ this.bbox.ur.x = poly.bbox.ur.x;
54999
+ if (poly.bbox.ur.y > this.bbox.ur.y)
55000
+ this.bbox.ur.y = poly.bbox.ur.y;
55001
+ this.polys.push(poly);
55002
+ }
55003
+ this.isSubject = isSubject;
55004
+ }
55005
+ getSweepEvents() {
55006
+ const sweepEvents = [];
55007
+ for (let i3 = 0, iMax = this.polys.length;i3 < iMax; i3++) {
55008
+ const polySweepEvents = this.polys[i3].getSweepEvents();
55009
+ for (let j4 = 0, jMax = polySweepEvents.length;j4 < jMax; j4++) {
55010
+ sweepEvents.push(polySweepEvents[j4]);
55011
+ }
55012
+ }
55013
+ return sweepEvents;
55014
+ }
55015
+ }
55016
+
55017
+ class RingOut {
55018
+ static factory(allSegments) {
55019
+ const ringsOut = [];
55020
+ for (let i3 = 0, iMax = allSegments.length;i3 < iMax; i3++) {
55021
+ const segment2 = allSegments[i3];
55022
+ if (!segment2.isInResult() || segment2.ringOut)
55023
+ continue;
55024
+ let prevEvent = null;
55025
+ let event = segment2.leftSE;
55026
+ let nextEvent = segment2.rightSE;
55027
+ const events = [event];
55028
+ const startingPoint = event.point;
55029
+ const intersectionLEs = [];
55030
+ while (true) {
55031
+ prevEvent = event;
55032
+ event = nextEvent;
55033
+ events.push(event);
55034
+ if (event.point === startingPoint)
55035
+ break;
55036
+ while (true) {
55037
+ const availableLEs = event.getAvailableLinkedEvents();
55038
+ if (availableLEs.length === 0) {
55039
+ const firstPt = events[0].point;
55040
+ const lastPt = events[events.length - 1].point;
55041
+ throw new Error(`Unable to complete output ring starting at [${firstPt.x},` + ` ${firstPt.y}]. Last matching segment found ends at` + ` [${lastPt.x}, ${lastPt.y}].`);
55042
+ }
55043
+ if (availableLEs.length === 1) {
55044
+ nextEvent = availableLEs[0].otherSE;
55045
+ break;
55046
+ }
55047
+ let indexLE = null;
55048
+ for (let j4 = 0, jMax = intersectionLEs.length;j4 < jMax; j4++) {
55049
+ if (intersectionLEs[j4].point === event.point) {
55050
+ indexLE = j4;
55051
+ break;
55052
+ }
55053
+ }
55054
+ if (indexLE !== null) {
55055
+ const intersectionLE = intersectionLEs.splice(indexLE)[0];
55056
+ const ringEvents = events.splice(intersectionLE.index);
55057
+ ringEvents.unshift(ringEvents[0].otherSE);
55058
+ ringsOut.push(new RingOut(ringEvents.reverse()));
55059
+ continue;
55060
+ }
55061
+ intersectionLEs.push({
55062
+ index: events.length,
55063
+ point: event.point
55064
+ });
55065
+ const comparator = event.getLeftmostComparator(prevEvent);
55066
+ nextEvent = availableLEs.sort(comparator)[0].otherSE;
55067
+ break;
55068
+ }
55069
+ }
55070
+ ringsOut.push(new RingOut(events));
55071
+ }
55072
+ return ringsOut;
55073
+ }
55074
+ constructor(events) {
55075
+ this.events = events;
55076
+ for (let i3 = 0, iMax = events.length;i3 < iMax; i3++) {
55077
+ events[i3].segment.ringOut = this;
55078
+ }
55079
+ this.poly = null;
55080
+ }
55081
+ getGeom() {
55082
+ let prevPt = this.events[0].point;
55083
+ const points = [prevPt];
55084
+ for (let i3 = 1, iMax = this.events.length - 1;i3 < iMax; i3++) {
55085
+ const pt4 = this.events[i3].point;
55086
+ const nextPt2 = this.events[i3 + 1].point;
55087
+ if (compareVectorAngles(pt4, prevPt, nextPt2) === 0)
55088
+ continue;
55089
+ points.push(pt4);
55090
+ prevPt = pt4;
55091
+ }
55092
+ if (points.length === 1)
55093
+ return null;
55094
+ const pt3 = points[0];
55095
+ const nextPt = points[1];
55096
+ if (compareVectorAngles(pt3, prevPt, nextPt) === 0)
55097
+ points.shift();
55098
+ points.push(points[0]);
55099
+ const step = this.isExteriorRing() ? 1 : -1;
55100
+ const iStart = this.isExteriorRing() ? 0 : points.length - 1;
55101
+ const iEnd = this.isExteriorRing() ? points.length : -1;
55102
+ const orderedPoints = [];
55103
+ for (let i3 = iStart;i3 != iEnd; i3 += step)
55104
+ orderedPoints.push([points[i3].x, points[i3].y]);
55105
+ return orderedPoints;
55106
+ }
55107
+ isExteriorRing() {
55108
+ if (this._isExteriorRing === undefined) {
55109
+ const enclosing = this.enclosingRing();
55110
+ this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
55111
+ }
55112
+ return this._isExteriorRing;
55113
+ }
55114
+ enclosingRing() {
55115
+ if (this._enclosingRing === undefined) {
55116
+ this._enclosingRing = this._calcEnclosingRing();
55117
+ }
55118
+ return this._enclosingRing;
55119
+ }
55120
+ _calcEnclosingRing() {
55121
+ let leftMostEvt = this.events[0];
55122
+ for (let i3 = 1, iMax = this.events.length;i3 < iMax; i3++) {
55123
+ const evt = this.events[i3];
55124
+ if (SweepEvent.compare(leftMostEvt, evt) > 0)
55125
+ leftMostEvt = evt;
55126
+ }
55127
+ let prevSeg = leftMostEvt.segment.prevInResult();
55128
+ let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
55129
+ while (true) {
55130
+ if (!prevSeg)
55131
+ return null;
55132
+ if (!prevPrevSeg)
55133
+ return prevSeg.ringOut;
55134
+ if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
55135
+ if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
55136
+ return prevSeg.ringOut;
55137
+ } else
55138
+ return prevSeg.ringOut.enclosingRing();
55139
+ }
55140
+ prevSeg = prevPrevSeg.prevInResult();
55141
+ prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
55142
+ }
55143
+ }
55144
+ }
55145
+
55146
+ class PolyOut {
55147
+ constructor(exteriorRing) {
55148
+ this.exteriorRing = exteriorRing;
55149
+ exteriorRing.poly = this;
55150
+ this.interiorRings = [];
55151
+ }
55152
+ addInterior(ring) {
55153
+ this.interiorRings.push(ring);
55154
+ ring.poly = this;
55155
+ }
55156
+ getGeom() {
55157
+ const geom = [this.exteriorRing.getGeom()];
55158
+ if (geom[0] === null)
55159
+ return null;
55160
+ for (let i3 = 0, iMax = this.interiorRings.length;i3 < iMax; i3++) {
55161
+ const ringGeom = this.interiorRings[i3].getGeom();
55162
+ if (ringGeom === null)
55163
+ continue;
55164
+ geom.push(ringGeom);
55165
+ }
55166
+ return geom;
55167
+ }
55168
+ }
55169
+
55170
+ class MultiPolyOut {
55171
+ constructor(rings) {
55172
+ this.rings = rings;
55173
+ this.polys = this._composePolys(rings);
55174
+ }
55175
+ getGeom() {
55176
+ const geom = [];
55177
+ for (let i3 = 0, iMax = this.polys.length;i3 < iMax; i3++) {
55178
+ const polyGeom = this.polys[i3].getGeom();
55179
+ if (polyGeom === null)
55180
+ continue;
55181
+ geom.push(polyGeom);
55182
+ }
55183
+ return geom;
55184
+ }
55185
+ _composePolys(rings) {
55186
+ const polys = [];
55187
+ for (let i3 = 0, iMax = rings.length;i3 < iMax; i3++) {
55188
+ const ring = rings[i3];
55189
+ if (ring.poly)
55190
+ continue;
55191
+ if (ring.isExteriorRing())
55192
+ polys.push(new PolyOut(ring));
55193
+ else {
55194
+ const enclosingRing = ring.enclosingRing();
55195
+ if (!enclosingRing.poly)
55196
+ polys.push(new PolyOut(enclosingRing));
55197
+ enclosingRing.poly.addInterior(ring);
55198
+ }
55199
+ }
55200
+ return polys;
55201
+ }
55202
+ }
55203
+
55204
+ class SweepLine {
55205
+ constructor(queue) {
55206
+ let comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment3.compare;
55207
+ this.queue = queue;
55208
+ this.tree = new SplayTree__default["default"](comparator);
55209
+ this.segments = [];
55210
+ }
55211
+ process(event) {
55212
+ const segment2 = event.segment;
55213
+ const newEvents = [];
55214
+ if (event.consumedBy) {
55215
+ if (event.isLeft)
55216
+ this.queue.remove(event.otherSE);
55217
+ else
55218
+ this.tree.remove(segment2);
55219
+ return newEvents;
55220
+ }
55221
+ const node = event.isLeft ? this.tree.add(segment2) : this.tree.find(segment2);
55222
+ if (!node)
55223
+ throw new Error(`Unable to find segment #${segment2.id} ` + `[${segment2.leftSE.point.x}, ${segment2.leftSE.point.y}] -> ` + `[${segment2.rightSE.point.x}, ${segment2.rightSE.point.y}] ` + "in SweepLine tree.");
55224
+ let prevNode = node;
55225
+ let nextNode = node;
55226
+ let prevSeg = undefined;
55227
+ let nextSeg = undefined;
55228
+ while (prevSeg === undefined) {
55229
+ prevNode = this.tree.prev(prevNode);
55230
+ if (prevNode === null)
55231
+ prevSeg = null;
55232
+ else if (prevNode.key.consumedBy === undefined)
55233
+ prevSeg = prevNode.key;
55234
+ }
55235
+ while (nextSeg === undefined) {
55236
+ nextNode = this.tree.next(nextNode);
55237
+ if (nextNode === null)
55238
+ nextSeg = null;
55239
+ else if (nextNode.key.consumedBy === undefined)
55240
+ nextSeg = nextNode.key;
55241
+ }
55242
+ if (event.isLeft) {
55243
+ let prevMySplitter = null;
55244
+ if (prevSeg) {
55245
+ const prevInter = prevSeg.getIntersection(segment2);
55246
+ if (prevInter !== null) {
55247
+ if (!segment2.isAnEndpoint(prevInter))
55248
+ prevMySplitter = prevInter;
55249
+ if (!prevSeg.isAnEndpoint(prevInter)) {
55250
+ const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
55251
+ for (let i3 = 0, iMax = newEventsFromSplit.length;i3 < iMax; i3++) {
55252
+ newEvents.push(newEventsFromSplit[i3]);
55253
+ }
55254
+ }
55255
+ }
55256
+ }
55257
+ let nextMySplitter = null;
55258
+ if (nextSeg) {
55259
+ const nextInter = nextSeg.getIntersection(segment2);
55260
+ if (nextInter !== null) {
55261
+ if (!segment2.isAnEndpoint(nextInter))
55262
+ nextMySplitter = nextInter;
55263
+ if (!nextSeg.isAnEndpoint(nextInter)) {
55264
+ const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
55265
+ for (let i3 = 0, iMax = newEventsFromSplit.length;i3 < iMax; i3++) {
55266
+ newEvents.push(newEventsFromSplit[i3]);
55267
+ }
55268
+ }
55269
+ }
55270
+ }
55271
+ if (prevMySplitter !== null || nextMySplitter !== null) {
55272
+ let mySplitter = null;
55273
+ if (prevMySplitter === null)
55274
+ mySplitter = nextMySplitter;
55275
+ else if (nextMySplitter === null)
55276
+ mySplitter = prevMySplitter;
55277
+ else {
55278
+ const cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
55279
+ mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
55280
+ }
55281
+ this.queue.remove(segment2.rightSE);
55282
+ newEvents.push(segment2.rightSE);
55283
+ const newEventsFromSplit = segment2.split(mySplitter);
55284
+ for (let i3 = 0, iMax = newEventsFromSplit.length;i3 < iMax; i3++) {
55285
+ newEvents.push(newEventsFromSplit[i3]);
55286
+ }
55287
+ }
55288
+ if (newEvents.length > 0) {
55289
+ this.tree.remove(segment2);
55290
+ newEvents.push(event);
55291
+ } else {
55292
+ this.segments.push(segment2);
55293
+ segment2.prev = prevSeg;
55294
+ }
55295
+ } else {
55296
+ if (prevSeg && nextSeg) {
55297
+ const inter = prevSeg.getIntersection(nextSeg);
55298
+ if (inter !== null) {
55299
+ if (!prevSeg.isAnEndpoint(inter)) {
55300
+ const newEventsFromSplit = this._splitSafely(prevSeg, inter);
55301
+ for (let i3 = 0, iMax = newEventsFromSplit.length;i3 < iMax; i3++) {
55302
+ newEvents.push(newEventsFromSplit[i3]);
55303
+ }
55304
+ }
55305
+ if (!nextSeg.isAnEndpoint(inter)) {
55306
+ const newEventsFromSplit = this._splitSafely(nextSeg, inter);
55307
+ for (let i3 = 0, iMax = newEventsFromSplit.length;i3 < iMax; i3++) {
55308
+ newEvents.push(newEventsFromSplit[i3]);
55309
+ }
55310
+ }
55311
+ }
55312
+ }
55313
+ this.tree.remove(segment2);
55314
+ }
55315
+ return newEvents;
55316
+ }
55317
+ _splitSafely(seg, pt3) {
55318
+ this.tree.remove(seg);
55319
+ const rightSE = seg.rightSE;
55320
+ this.queue.remove(rightSE);
55321
+ const newEvents = seg.split(pt3);
55322
+ newEvents.push(rightSE);
55323
+ if (seg.consumedBy === undefined)
55324
+ this.tree.add(seg);
55325
+ return newEvents;
55326
+ }
55327
+ }
55328
+ var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1e6;
55329
+ var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1e6;
55330
+
55331
+ class Operation {
55332
+ run(type, geom, moreGeoms) {
55333
+ operation.type = type;
55334
+ rounder.reset();
55335
+ const multipolys = [new MultiPolyIn(geom, true)];
55336
+ for (let i3 = 0, iMax = moreGeoms.length;i3 < iMax; i3++) {
55337
+ multipolys.push(new MultiPolyIn(moreGeoms[i3], false));
55338
+ }
55339
+ operation.numMultiPolys = multipolys.length;
55340
+ if (operation.type === "difference") {
55341
+ const subject = multipolys[0];
55342
+ let i3 = 1;
55343
+ while (i3 < multipolys.length) {
55344
+ if (getBboxOverlap(multipolys[i3].bbox, subject.bbox) !== null)
55345
+ i3++;
55346
+ else
55347
+ multipolys.splice(i3, 1);
55348
+ }
55349
+ }
55350
+ if (operation.type === "intersection") {
55351
+ for (let i3 = 0, iMax = multipolys.length;i3 < iMax; i3++) {
55352
+ const mpA = multipolys[i3];
55353
+ for (let j4 = i3 + 1, jMax = multipolys.length;j4 < jMax; j4++) {
55354
+ if (getBboxOverlap(mpA.bbox, multipolys[j4].bbox) === null)
55355
+ return [];
55356
+ }
55357
+ }
55358
+ }
55359
+ const queue = new SplayTree__default["default"](SweepEvent.compare);
55360
+ for (let i3 = 0, iMax = multipolys.length;i3 < iMax; i3++) {
55361
+ const sweepEvents = multipolys[i3].getSweepEvents();
55362
+ for (let j4 = 0, jMax = sweepEvents.length;j4 < jMax; j4++) {
55363
+ queue.insert(sweepEvents[j4]);
55364
+ if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
55365
+ throw new Error("Infinite loop when putting segment endpoints in a priority queue " + "(queue size too big).");
55366
+ }
55367
+ }
55368
+ }
55369
+ const sweepLine = new SweepLine(queue);
55370
+ let prevQueueSize = queue.size;
55371
+ let node = queue.pop();
55372
+ while (node) {
55373
+ const evt = node.key;
55374
+ if (queue.size === prevQueueSize) {
55375
+ const seg = evt.segment;
55376
+ throw new Error(`Unable to pop() ${evt.isLeft ? "left" : "right"} SweepEvent ` + `[${evt.point.x}, ${evt.point.y}] from segment #${seg.id} ` + `[${seg.leftSE.point.x}, ${seg.leftSE.point.y}] -> ` + `[${seg.rightSE.point.x}, ${seg.rightSE.point.y}] from queue.`);
55377
+ }
55378
+ if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
55379
+ throw new Error("Infinite loop when passing sweep line over endpoints " + "(queue size too big).");
55380
+ }
55381
+ if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
55382
+ throw new Error("Infinite loop when passing sweep line over endpoints " + "(too many sweep line segments).");
55383
+ }
55384
+ const newEvents = sweepLine.process(evt);
55385
+ for (let i3 = 0, iMax = newEvents.length;i3 < iMax; i3++) {
55386
+ const evt2 = newEvents[i3];
55387
+ if (evt2.consumedBy === undefined)
55388
+ queue.insert(evt2);
55389
+ }
55390
+ prevQueueSize = queue.size;
55391
+ node = queue.pop();
55392
+ }
55393
+ rounder.reset();
55394
+ const ringsOut = RingOut.factory(sweepLine.segments);
55395
+ const result = new MultiPolyOut(ringsOut);
55396
+ return result.getGeom();
55397
+ }
55398
+ }
55399
+ var operation = new Operation;
55400
+ var union = function(geom) {
55401
+ for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1;_key < _len; _key++) {
55402
+ moreGeoms[_key - 1] = arguments[_key];
55403
+ }
55404
+ return operation.run("union", geom, moreGeoms);
55405
+ };
55406
+ var intersection = function(geom) {
55407
+ for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1;_key2 < _len2; _key2++) {
55408
+ moreGeoms[_key2 - 1] = arguments[_key2];
55409
+ }
55410
+ return operation.run("intersection", geom, moreGeoms);
55411
+ };
55412
+ var xor = function(geom) {
55413
+ for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1;_key3 < _len3; _key3++) {
55414
+ moreGeoms[_key3 - 1] = arguments[_key3];
55415
+ }
55416
+ return operation.run("xor", geom, moreGeoms);
55417
+ };
55418
+ var difference = function(subjectGeom) {
55419
+ for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1;_key4 < _len4; _key4++) {
55420
+ clippingGeoms[_key4 - 1] = arguments[_key4];
55421
+ }
55422
+ return operation.run("difference", subjectGeom, clippingGeoms);
55423
+ };
55424
+ var index = {
55425
+ union,
55426
+ intersection,
55427
+ xor,
55428
+ difference
55429
+ };
55430
+ module2.exports = index;
55431
+ });
55432
+
53622
55433
  // node_modules/fast-json-stable-stringify/index.js
53623
55434
  var require_fast_json_stable_stringify = __commonJS((exports2, module2) => {
53624
55435
  module2.exports = function(data, opts) {
@@ -53682,7 +55493,7 @@ var require_fast_json_stable_stringify = __commonJS((exports2, module2) => {
53682
55493
  };
53683
55494
  });
53684
55495
 
53685
- // node_modules/circuit-json-to-gerber/dist/chunk-FNNZTRYF.js
55496
+ // node_modules/circuit-json-to-gerber/dist/chunk-46NSLLUV.js
53686
55497
  import { z as z4 } from "zod";
53687
55498
  import { z as z23 } from "zod";
53688
55499
  import { z as z32 } from "zod";
@@ -53703,6 +55514,7 @@ import { z as z17 } from "zod";
53703
55514
  import { z as z18 } from "zod";
53704
55515
  import { z as z19 } from "zod";
53705
55516
  import { z as z20 } from "zod";
55517
+ import { getBoundFromCenteredRect } from "@tscircuit/math-utils";
53706
55518
  import { z as z21 } from "zod";
53707
55519
  import { z as z222 } from "zod";
53708
55520
  import { z as z232 } from "zod";
@@ -53733,7 +55545,6 @@ import { z as z47 } from "zod";
53733
55545
  import { z as z48 } from "zod";
53734
55546
  import { z as z49 } from "zod";
53735
55547
  import { z as z50 } from "zod";
53736
- import { lineAlphabet as lineAlphabet2 } from "@tscircuit/alphabet";
53737
55548
  import {
53738
55549
  applyToPoint as applyToPoint26,
53739
55550
  compose as compose9,
@@ -53741,6 +55552,25 @@ import {
53741
55552
  rotate as rotate12,
53742
55553
  translate as translate9
53743
55554
  } from "transformation-matrix";
55555
+ import { getBoundFromCenteredRect as getBoundFromCenteredRect2 } from "@tscircuit/math-utils";
55556
+ import { lineAlphabet as lineAlphabet2 } from "@tscircuit/alphabet";
55557
+ import {
55558
+ applyToPoint as applyToPoint42,
55559
+ compose as compose42,
55560
+ identity as identity32,
55561
+ rotate as rotate42,
55562
+ translate as translate42
55563
+ } from "transformation-matrix";
55564
+ import { getBoundFromCenteredRect as getBoundFromCenteredRect3 } from "@tscircuit/math-utils";
55565
+ import { applyToPoint as applyToPoint25, compose as compose22, rotate as rotate22, translate as translate22 } from "transformation-matrix";
55566
+ import { getBoundFromCenteredRect as getBoundFromCenteredRect4 } from "@tscircuit/math-utils";
55567
+ import {
55568
+ applyToPoint as applyToPoint32,
55569
+ compose as compose32,
55570
+ identity as identity22,
55571
+ rotate as rotate32,
55572
+ translate as translate32
55573
+ } from "transformation-matrix";
53744
55574
  function pairs3(arr) {
53745
55575
  const result = [];
53746
55576
  for (let i3 = 0;i3 < arr.length - 1; i3++) {
@@ -53756,17 +55586,30 @@ function getAllTraceWidths(soup) {
53756
55586
  if (segment2.route_type === "wire") {
53757
55587
  widths[segment2.layer] = widths[segment2.layer] || /* @__PURE__ */ new Set;
53758
55588
  widths[segment2.layer].add(segment2.width);
55589
+ } else if (segment2.route_type === "through_pad") {
55590
+ for (const layer of [segment2.start_layer, segment2.end_layer]) {
55591
+ if (typeof layer === "string" && typeof segment2.width === "number") {
55592
+ widths[layer] = widths[layer] || /* @__PURE__ */ new Set;
55593
+ widths[layer].add(segment2.width);
55594
+ }
55595
+ }
53759
55596
  }
53760
55597
  }
53761
55598
  }
53762
55599
  return {
53763
55600
  top: Array.from(widths.top || []),
55601
+ inner1: Array.from(widths.inner1 || []),
55602
+ inner2: Array.from(widths.inner2 || []),
55603
+ inner3: Array.from(widths.inner3 || []),
55604
+ inner4: Array.from(widths.inner4 || []),
55605
+ inner5: Array.from(widths.inner5 || []),
55606
+ inner6: Array.from(widths.inner6 || []),
53764
55607
  bottom: Array.from(widths.bottom || [])
53765
55608
  };
53766
55609
  }
53767
55610
  function defineAperturesForLayer({
53768
55611
  glayer,
53769
- soup,
55612
+ circuitJson,
53770
55613
  glayer_name
53771
55614
  }) {
53772
55615
  const getNextApertureNumber = () => {
@@ -53782,15 +55625,20 @@ function defineAperturesForLayer({
53782
55625
  return highest_aperture_number + 1;
53783
55626
  };
53784
55627
  glayer.push(...gerberBuilder().add("comment", { comment: "aperture START LIST" }).build());
53785
- const traceWidths = getAllTraceWidths(soup);
53786
- for (const width of traceWidths[glayer_name.startsWith("F_") ? "top" : "bottom"]) {
55628
+ const traceWidths = getAllTraceWidths(circuitJson);
55629
+ const layerRef = getLayerRefFromGerberLayerName(glayer_name);
55630
+ for (const width of traceWidths[layerRef]) {
53787
55631
  glayer.push(...gerberBuilder().add("define_aperture_template", {
53788
55632
  aperture_number: getNextApertureNumber(),
53789
55633
  standard_template_code: "C",
53790
55634
  diameter: width
53791
55635
  }).build());
53792
55636
  }
53793
- const apertureConfigs = getAllApertureTemplateConfigsForLayer(soup, glayer_name.startsWith("F_") ? "top" : "bottom");
55637
+ const apertureConfigs = getAllApertureTemplateConfigsForLayer({
55638
+ circuitJson,
55639
+ layer: layerRef,
55640
+ glayer_name
55641
+ });
53794
55642
  for (const apertureConfig of apertureConfigs) {
53795
55643
  glayer.push(...gerberBuilder().add("define_aperture_template", {
53796
55644
  aperture_number: getNextApertureNumber(),
@@ -53799,9 +55647,16 @@ function defineAperturesForLayer({
53799
55647
  }
53800
55648
  glayer.push(...gerberBuilder().add("delete_attribute", {}).add("comment", { comment: "aperture END LIST" }).build());
53801
55649
  }
53802
- function getAllApertureTemplateConfigsForLayer(soup, layer) {
55650
+ function getAllApertureTemplateConfigsForLayer({
55651
+ circuitJson,
55652
+ layer,
55653
+ glayer_name
55654
+ }) {
53803
55655
  const configs = [];
53804
55656
  const configHashMap = /* @__PURE__ */ new Set;
55657
+ const isSoldermaskLayer = glayer_name.endsWith("_Mask");
55658
+ const isCopperLayer = glayer_name.endsWith("_Cu");
55659
+ const isFabricationLayer = glayer_name.endsWith("_Fab");
53805
55660
  const addConfigIfNew = (config) => {
53806
55661
  const hash = import_fast_json_stable_stringify.default(config);
53807
55662
  if (!configHashMap.has(hash)) {
@@ -53809,38 +55664,145 @@ function getAllApertureTemplateConfigsForLayer(soup, layer) {
53809
55664
  configHashMap.add(hash);
53810
55665
  }
53811
55666
  };
53812
- for (const elm of soup) {
55667
+ for (const elm of circuitJson) {
53813
55668
  if (elm.type === "pcb_smtpad") {
55669
+ if (isFabricationLayer)
55670
+ continue;
53814
55671
  if (elm.layer === layer && elm.shape !== "polygon") {
53815
- addConfigIfNew(getApertureConfigFromPcbSmtpad(elm));
55672
+ if (isSoldermaskLayer) {
55673
+ addConfigIfNew(getApertureConfigFromPcbSmtpadSoldermask(elm));
55674
+ } else {
55675
+ addConfigIfNew(getApertureConfigFromPcbSmtpad(elm));
55676
+ }
53816
55677
  }
53817
55678
  } else if (elm.type === "pcb_solder_paste") {
55679
+ if (isFabricationLayer)
55680
+ continue;
53818
55681
  if (elm.layer === layer) {
53819
55682
  addConfigIfNew(getApertureConfigFromPcbSolderPaste(elm));
55683
+ if (elm.shape === "pill") {
55684
+ addConfigIfNew(getApertureConfigFromPcbSolderPaste({
55685
+ ...elm,
55686
+ width: elm.height,
55687
+ height: elm.width
55688
+ }));
55689
+ }
53820
55690
  }
53821
55691
  } else if (elm.type === "pcb_plated_hole") {
55692
+ if (isFabricationLayer)
55693
+ continue;
53822
55694
  if (elm.layers.includes(layer)) {
53823
- addConfigIfNew(getApertureConfigFromPcbPlatedHole(elm));
55695
+ if (elm.shape === "hole_with_polygon_pad") {
55696
+ continue;
55697
+ }
55698
+ if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
55699
+ continue;
55700
+ }
55701
+ if (isSoldermaskLayer) {
55702
+ addConfigIfNew(getApertureConfigFromPcbPlatedHoleSoldermask(elm));
55703
+ } else {
55704
+ addConfigIfNew(getApertureConfigFromPcbPlatedHole(elm));
55705
+ }
53824
55706
  }
53825
55707
  } else if (elm.type === "pcb_hole") {
53826
- if (elm.hole_shape === "circle")
53827
- addConfigIfNew(getApertureConfigFromCirclePcbHole(elm));
53828
- else
55708
+ if (!isSoldermaskLayer)
55709
+ continue;
55710
+ if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
55711
+ continue;
55712
+ }
55713
+ if (elm.hole_shape === "circle") {
55714
+ if (isSoldermaskLayer) {
55715
+ addConfigIfNew(getApertureConfigFromCirclePcbHoleSoldermask(elm));
55716
+ } else {
55717
+ addConfigIfNew(getApertureConfigFromCirclePcbHole(elm));
55718
+ }
55719
+ } else
53829
55720
  console.warn("NOT IMPLEMENTED: drawing gerber for non circle holes");
53830
55721
  } else if (elm.type === "pcb_via") {
53831
- addConfigIfNew(getApertureConfigFromPcbVia(elm));
53832
- } else if (elm.type === "pcb_silkscreen_path")
53833
- addConfigIfNew(getApertureConfigFromPcbSilkscreenPath(elm));
53834
- else if (elm.type === "pcb_silkscreen_text")
53835
- addConfigIfNew(getApertureConfigFromPcbSilkscreenText(elm));
53836
- else if (elm.type === "pcb_copper_text") {
55722
+ if (isFabricationLayer)
55723
+ continue;
55724
+ addConfigIfNew(getApertureConfigFromOuterDiameter(elm));
55725
+ } else if (elm.type === "pcb_trace") {
55726
+ if (isFabricationLayer)
55727
+ continue;
55728
+ for (const point9 of elm.route) {
55729
+ if (point9.route_type === "via" && typeof point9.outer_diameter === "number" && (point9.from_layer === layer || point9.to_layer === layer)) {
55730
+ addConfigIfNew(getApertureConfigFromOuterDiameter(point9));
55731
+ }
55732
+ }
55733
+ } else if (elm.type === "pcb_silkscreen_path") {
55734
+ if (!isFabricationLayer)
55735
+ addConfigIfNew(getApertureConfigFromPcbSilkscreenPath(elm));
55736
+ } else if (isSilkscreenShape(elm)) {
55737
+ if (!isFabricationLayer) {
55738
+ addConfigIfNew({
55739
+ standard_template_code: "C",
55740
+ diameter: elm.stroke_width ?? 0.1
55741
+ });
55742
+ if (elm.is_filled === true) {
55743
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55744
+ }
55745
+ }
55746
+ } else if (elm.type === "pcb_silkscreen_graphic") {
55747
+ if (glayer_name.endsWith("_SilkScreen")) {
55748
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55749
+ }
55750
+ } else if (elm.type === "pcb_silkscreen_text") {
55751
+ if (!isFabricationLayer)
55752
+ addConfigIfNew(getApertureConfigFromPcbSilkscreenText(elm));
55753
+ } else if (elm.type === "pcb_fabrication_note_text") {
55754
+ if (isFabricationLayer && elm.layer === layer)
55755
+ addConfigIfNew(getApertureConfigFromPcbFabricationNoteText(elm));
55756
+ } else if (elm.type === "pcb_fabrication_note_path") {
55757
+ if (isFabricationLayer && elm.layer === layer)
55758
+ addConfigIfNew(getApertureConfigFromPcbFabricationNotePath(elm));
55759
+ } else if (elm.type === "pcb_fabrication_note_rect") {
55760
+ if (isFabricationLayer && elm.layer === layer) {
55761
+ if (elm.has_stroke !== false)
55762
+ addConfigIfNew(getApertureConfigFromPcbFabricationNotePath(elm));
55763
+ if (elm.is_filled === true)
55764
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55765
+ }
55766
+ } else if (elm.type === "pcb_fabrication_note_dimension") {
55767
+ if (isFabricationLayer && elm.layer === layer) {
55768
+ addConfigIfNew(getApertureConfigFromPcbFabricationNoteDimension(elm));
55769
+ addConfigIfNew(getApertureConfigFromPcbFabricationNoteText(elm));
55770
+ }
55771
+ } else if (elm.type === "pcb_copper_text") {
53837
55772
  if (elm.layer === layer)
53838
55773
  addConfigIfNew(getApertureConfigFromPcbCopperText(elm));
53839
55774
  }
53840
55775
  }
55776
+ const needsRegionAperture = circuitJson.some((elm) => {
55777
+ if (elm.type === "pcb_copper_pour") {
55778
+ if (elm.layer !== layer)
55779
+ return false;
55780
+ if (isCopperLayer)
55781
+ return true;
55782
+ return isSoldermaskLayer && elm.covered_with_solder_mask === false;
55783
+ }
55784
+ if (elm.type === "pcb_smtpad" && elm.shape === "polygon") {
55785
+ if (elm.layer !== layer)
55786
+ return false;
55787
+ if (isCopperLayer)
55788
+ return true;
55789
+ return isSoldermaskLayer && elm.is_covered_with_solder_mask !== true;
55790
+ }
55791
+ if (elm.type === "pcb_plated_hole" && elm.shape === "hole_with_polygon_pad") {
55792
+ if (!elm.layers.includes(layer))
55793
+ return false;
55794
+ if (isCopperLayer)
55795
+ return true;
55796
+ return isSoldermaskLayer && elm.is_covered_with_solder_mask !== true;
55797
+ }
55798
+ return false;
55799
+ });
55800
+ if (needsRegionAperture) {
55801
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55802
+ }
53841
55803
  return configs;
53842
55804
  }
53843
- var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
55805
+ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_clipping2, import_polygon_clipping3, defineExcellonDrillCommand = ({
53844
55806
  command_code,
53845
55807
  schema,
53846
55808
  stringify: stringify3
@@ -53873,12 +55835,270 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
53873
55835
  build() {
53874
55836
  return this.commands;
53875
55837
  }
53876
- }, excellonDrill = () => new ExcellonDrillBuilder, convertSoupToExcellonDrillCommands = ({
55838
+ }, excellonDrill = () => new ExcellonDrillBuilder, getLayerCount = (circuitJson) => {
55839
+ const board = circuitJson.find((element) => element.type === "pcb_board");
55840
+ if (!board || typeof board.num_layers !== "number") {
55841
+ return 2;
55842
+ }
55843
+ return Math.max(2, board.num_layers);
55844
+ }, getLayerNumber = (layer, layerCount) => {
55845
+ if (layer === "top")
55846
+ return 1;
55847
+ if (layer === "bottom")
55848
+ return layerCount;
55849
+ const innerLayerMatch = layer.match(/^inner([1-6])$/);
55850
+ if (innerLayerMatch) {
55851
+ const innerLayerNumber = Number(innerLayerMatch[1]);
55852
+ if (innerLayerNumber >= 1 && innerLayerNumber <= layerCount - 2) {
55853
+ return innerLayerNumber + 1;
55854
+ }
55855
+ }
55856
+ throw new Error(`Invalid layer "${layer}" for ${layerCount}-layer board`);
55857
+ }, normalizeLayerSpan = (span, layerCount) => {
55858
+ const fromLayerNumber = getLayerNumber(span.from_layer, layerCount);
55859
+ const toLayerNumber = getLayerNumber(span.to_layer, layerCount);
55860
+ if (fromLayerNumber <= toLayerNumber) {
55861
+ return span;
55862
+ }
55863
+ return {
55864
+ from_layer: span.to_layer,
55865
+ to_layer: span.from_layer
55866
+ };
55867
+ }, getPlatedElementLayerSpan = (element, layerCount) => {
55868
+ if (element.type !== "pcb_plated_hole" && element.type !== "pcb_via") {
55869
+ return;
55870
+ }
55871
+ if ("from_layer" in element && typeof element.from_layer === "string" && "to_layer" in element && typeof element.to_layer === "string") {
55872
+ return normalizeLayerSpan({
55873
+ from_layer: element.from_layer,
55874
+ to_layer: element.to_layer
55875
+ }, layerCount);
55876
+ }
55877
+ let layers = [];
55878
+ if ("layers" in element && Array.isArray(element.layers)) {
55879
+ layers = element.layers;
55880
+ }
55881
+ if (layers.length > 0) {
55882
+ const sortedLayers = [...layers].sort((a3, b3) => getLayerNumber(a3, layerCount) - getLayerNumber(b3, layerCount));
55883
+ return {
55884
+ from_layer: sortedLayers[0],
55885
+ to_layer: sortedLayers[sortedLayers.length - 1]
55886
+ };
55887
+ }
55888
+ return {
55889
+ from_layer: "top",
55890
+ to_layer: "bottom"
55891
+ };
55892
+ }, getDefaultPlatedDrillLayerSpan = () => ({
55893
+ from_layer: "top",
55894
+ to_layer: "bottom"
55895
+ }), getRequestedLayerSpan = (layer_span) => {
55896
+ if (layer_span) {
55897
+ return layer_span;
55898
+ }
55899
+ return getDefaultPlatedDrillLayerSpan();
55900
+ }, isSameLayerSpan = (a3, b3, layerCount) => {
55901
+ const normalizedA = normalizeLayerSpan(a3, layerCount);
55902
+ const normalizedB = normalizeLayerSpan(b3, layerCount);
55903
+ return normalizedA.from_layer === normalizedB.from_layer && normalizedA.to_layer === normalizedB.to_layer;
55904
+ }, shouldIncludeElement = ({
55905
+ element,
55906
+ is_plated,
55907
+ layer_span,
55908
+ layerCount
55909
+ }) => {
55910
+ if (element.type !== "pcb_plated_hole" && element.type !== "pcb_hole" && element.type !== "pcb_via") {
55911
+ return false;
55912
+ }
55913
+ if (!is_plated)
55914
+ return element.type === "pcb_hole";
55915
+ if (element.type === "pcb_hole")
55916
+ return false;
55917
+ const elementLayerSpan = getPlatedElementLayerSpan(element, layerCount);
55918
+ if (!elementLayerSpan)
55919
+ return false;
55920
+ const requestedLayerSpan = getRequestedLayerSpan(layer_span);
55921
+ return isSameLayerSpan(elementLayerSpan, requestedLayerSpan, layerCount);
55922
+ }, getFileFunctionLayerSpan = ({
55923
+ circuitJson,
55924
+ is_plated,
55925
+ layer_span
55926
+ }) => {
55927
+ const layerCount = getLayerCount(circuitJson);
55928
+ if (!is_plated)
55929
+ return `NonPlated,1,${layerCount},NPTH`;
55930
+ const requestedLayerSpan = getRequestedLayerSpan(layer_span);
55931
+ const span = normalizeLayerSpan(requestedLayerSpan, layerCount);
55932
+ return `Plated,${getLayerNumber(span.from_layer, layerCount)},${getLayerNumber(span.to_layer, layerCount)},PTH`;
55933
+ }, getTraceRouteViaElements = (circuitJson) => {
55934
+ const routeVias = [];
55935
+ for (const element of circuitJson) {
55936
+ if (element.type !== "pcb_trace") {
55937
+ continue;
55938
+ }
55939
+ for (const [index, point9] of element.route.entries()) {
55940
+ if (point9.route_type !== "via" || typeof point9.hole_diameter !== "number" || typeof point9.outer_diameter !== "number" || typeof point9.from_layer !== "string" || typeof point9.to_layer !== "string") {
55941
+ continue;
55942
+ }
55943
+ const fromLayer = point9.from_layer;
55944
+ const toLayer = point9.to_layer;
55945
+ routeVias.push({
55946
+ type: "pcb_via",
55947
+ pcb_via_id: `${element.pcb_trace_id}_route_via_${index}`,
55948
+ x: point9.x,
55949
+ y: point9.y,
55950
+ hole_diameter: point9.hole_diameter,
55951
+ outer_diameter: point9.outer_diameter,
55952
+ from_layer: fromLayer,
55953
+ to_layer: toLayer,
55954
+ layers: [fromLayer, toLayer]
55955
+ });
55956
+ }
55957
+ }
55958
+ return routeVias;
55959
+ }, getDrillableElements = (circuitJson) => [
55960
+ ...circuitJson,
55961
+ ...getTraceRouteViaElements(circuitJson)
55962
+ ], circleCutoutPolygonSegmentCount = 64, getBoardOutlinePolygons = (circuitJson) => {
55963
+ return circuitJson.flatMap((element) => {
55964
+ if (element.type !== "pcb_board") {
55965
+ return [];
55966
+ }
55967
+ if (element.outline && element.outline.length > 2) {
55968
+ return [[element.outline.map((point9) => [point9.x, point9.y])]];
55969
+ }
55970
+ const bounds = getBoundFromCenteredRect({
55971
+ center: element.center,
55972
+ width: element.width,
55973
+ height: element.height
55974
+ });
55975
+ return [
55976
+ [
55977
+ [
55978
+ [bounds.minX, bounds.minY],
55979
+ [bounds.maxX, bounds.minY],
55980
+ [bounds.maxX, bounds.maxY],
55981
+ [bounds.minX, bounds.maxY]
55982
+ ]
55983
+ ]
55984
+ ];
55985
+ });
55986
+ }, getCircleCutoutPolygon = (cutout) => {
55987
+ const points = [];
55988
+ for (let i3 = 0;i3 < circleCutoutPolygonSegmentCount; i3++) {
55989
+ const angle = i3 / circleCutoutPolygonSegmentCount * Math.PI * 2;
55990
+ points.push([
55991
+ cutout.center.x + cutout.radius * Math.cos(angle),
55992
+ cutout.center.y + cutout.radius * Math.sin(angle)
55993
+ ]);
55994
+ }
55995
+ return [points];
55996
+ }, isInternalCircularCutout = ({
55997
+ cutout,
55998
+ boardOutlinePolygons
55999
+ }) => {
56000
+ const cutoutPolygon = getCircleCutoutPolygon(cutout);
56001
+ return boardOutlinePolygons.some((boardOutlinePolygon) => {
56002
+ const overlapsBoard = import_polygon_clipping.default.intersection(boardOutlinePolygon, cutoutPolygon).length > 0;
56003
+ const extendsOutsideBoard = import_polygon_clipping.default.difference(cutoutPolygon, boardOutlinePolygon).length > 0;
56004
+ return overlapsBoard && !extendsOutsideBoard;
56005
+ });
56006
+ }, getInternalCircularCutoutDrills = (circuitJson) => {
56007
+ const boardOutlinePolygons = getBoardOutlinePolygons(circuitJson);
56008
+ return circuitJson.filter((element) => {
56009
+ if (element.type !== "pcb_cutout") {
56010
+ return false;
56011
+ }
56012
+ if (element.shape !== "circle") {
56013
+ return false;
56014
+ }
56015
+ return isInternalCircularCutout({
56016
+ cutout: element,
56017
+ boardOutlinePolygons
56018
+ });
56019
+ });
56020
+ }, getDrillElements = ({
56021
+ circuitJson,
56022
+ is_plated
56023
+ }) => {
56024
+ const drillableElements = getDrillableElements(circuitJson).filter((element) => element.type !== "pcb_cutout");
56025
+ if (is_plated) {
56026
+ return drillableElements;
56027
+ }
56028
+ const internalCircularCutoutDrills = getInternalCircularCutoutDrills(circuitJson);
56029
+ return [...drillableElements, ...internalCircularCutoutDrills];
56030
+ }, getHoleDiameter = (element) => {
56031
+ if ("hole_diameter" in element && typeof element.hole_diameter === "number") {
56032
+ return element.hole_diameter;
56033
+ }
56034
+ if (element.type === "pcb_cutout") {
56035
+ return element.radius * 2;
56036
+ }
56037
+ if ("hole_width" in element && typeof element.hole_width === "number" && "hole_height" in element && typeof element.hole_height === "number") {
56038
+ return Math.min(element.hole_width, element.hole_height);
56039
+ }
56040
+ return;
56041
+ }, getDrillCenter = (element) => {
56042
+ if (element.type === "pcb_cutout") {
56043
+ return element.center;
56044
+ }
56045
+ let x4 = 0;
56046
+ let y4 = 0;
56047
+ let holeOffsetX = 0;
56048
+ let holeOffsetY = 0;
56049
+ if ("x" in element && typeof element.x === "number") {
56050
+ x4 = element.x;
56051
+ }
56052
+ if ("y" in element && typeof element.y === "number") {
56053
+ y4 = element.y;
56054
+ }
56055
+ if ("hole_offset_x" in element && typeof element.hole_offset_x === "number") {
56056
+ holeOffsetX = element.hole_offset_x;
56057
+ }
56058
+ if ("hole_offset_y" in element && typeof element.hole_offset_y === "number") {
56059
+ holeOffsetY = element.hole_offset_y;
56060
+ }
56061
+ return {
56062
+ x: x4 + holeOffsetX,
56063
+ y: y4 + holeOffsetY
56064
+ };
56065
+ }, getYMultiplier = (flip_y_axis) => {
56066
+ if (flip_y_axis) {
56067
+ return -1;
56068
+ }
56069
+ return 1;
56070
+ }, getSlotEndpoints = ({
56071
+ holeWidth,
56072
+ holeHeight,
56073
+ slotHalfLength
56074
+ }) => {
56075
+ let startRelative = { x: 0, y: -slotHalfLength };
56076
+ let endRelative = { x: 0, y: slotHalfLength };
56077
+ if (holeWidth >= holeHeight) {
56078
+ startRelative = { x: -slotHalfLength, y: 0 };
56079
+ endRelative = { x: slotHalfLength, y: 0 };
56080
+ }
56081
+ return { startRelative, endRelative };
56082
+ }, getHoleRotationDegrees = (element) => {
56083
+ if ("hole_ccw_rotation" in element && typeof element.hole_ccw_rotation === "number") {
56084
+ return element.hole_ccw_rotation;
56085
+ }
56086
+ if ("ccw_rotation" in element && typeof element.ccw_rotation === "number") {
56087
+ return element.ccw_rotation;
56088
+ }
56089
+ return 0;
56090
+ }, convertSoupToExcellonDrillCommands = ({
53877
56091
  circuitJson,
53878
56092
  is_plated,
53879
- flip_y_axis = false
56093
+ flip_y_axis = false,
56094
+ layer_span
53880
56095
  }) => {
53881
56096
  const builder = excellonDrill();
56097
+ const layerCount = getLayerCount(circuitJson);
56098
+ const drillElements = getDrillElements({
56099
+ circuitJson,
56100
+ is_plated
56101
+ });
53882
56102
  builder.add("M48", {});
53883
56103
  const date_str = (/* @__PURE__ */ new Date()).toISOString();
53884
56104
  builder.add("header_comment", {
@@ -53893,18 +56113,27 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
53893
56113
  attribute_value: "tscircuit"
53894
56114
  }).add("header_attribute", {
53895
56115
  attribute_name: "TF.FileFunction",
53896
- attribute_value: is_plated ? "Plated,1,2,PTH" : "NonPlated,1,2,NPTH"
56116
+ attribute_value: getFileFunctionLayerSpan({
56117
+ circuitJson,
56118
+ is_plated,
56119
+ layer_span
56120
+ })
53897
56121
  }).add("FMAT", { format: 2 }).add("unit_format", { unit: "METRIC", lz: null });
53898
56122
  let tool_counter = 10;
53899
56123
  const diameterToToolNumber = {};
53900
- for (const element of circuitJson) {
53901
- if (element.type !== "pcb_plated_hole" && element.type !== "pcb_hole" && element.type !== "pcb_via") {
56124
+ for (const element of drillElements) {
56125
+ if (element.type !== "pcb_cutout" && !shouldIncludeElement({
56126
+ element,
56127
+ is_plated,
56128
+ layer_span,
56129
+ layerCount
56130
+ })) {
53902
56131
  continue;
53903
56132
  }
53904
- if (!is_plated && (element.type === "pcb_plated_hole" || element.type === "pcb_via")) {
56133
+ if (is_plated && element.type === "pcb_hole") {
53905
56134
  continue;
53906
56135
  }
53907
- const holeDiameter = "hole_diameter" in element && typeof element.hole_diameter === "number" ? element.hole_diameter : ("hole_width" in element) && typeof element.hole_width === "number" && ("hole_height" in element) && typeof element.hole_height === "number" ? Math.min(element.hole_width, element.hole_height) : undefined;
56136
+ const holeDiameter = getHoleDiameter(element);
53908
56137
  if (!holeDiameter)
53909
56138
  continue;
53910
56139
  if (!diameterToToolNumber[holeDiameter]) {
@@ -53924,22 +56153,27 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
53924
56153
  builder.add("G05", {});
53925
56154
  for (let i3 = 10;i3 < tool_counter; i3++) {
53926
56155
  builder.add("use_tool", { tool_number: i3 });
53927
- for (const element of circuitJson) {
53928
- if (element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via") {
53929
- if (!is_plated && (element.type === "pcb_plated_hole" || element.type === "pcb_via")) {
56156
+ for (const element of drillElements) {
56157
+ if (element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via" || element.type === "pcb_cutout") {
56158
+ if (element.type !== "pcb_cutout" && !shouldIncludeElement({
56159
+ element,
56160
+ is_plated,
56161
+ layer_span,
56162
+ layerCount
56163
+ })) {
56164
+ continue;
56165
+ }
56166
+ if (is_plated && element.type === "pcb_hole") {
53930
56167
  continue;
53931
56168
  }
53932
- const holeDiameter = "hole_diameter" in element && typeof element.hole_diameter === "number" ? element.hole_diameter : ("hole_width" in element) && typeof element.hole_width === "number" && ("hole_height" in element) && typeof element.hole_height === "number" ? Math.min(element.hole_width, element.hole_height) : undefined;
56169
+ const holeDiameter = getHoleDiameter(element);
53933
56170
  if (!holeDiameter || diameterToToolNumber[holeDiameter] !== i3) {
53934
56171
  continue;
53935
56172
  }
53936
- const elementX = "x" in element && typeof element.x === "number" ? element.x : 0;
53937
- const elementY = "y" in element && typeof element.y === "number" ? element.y : 0;
53938
- const offsetX = "hole_offset_x" in element && typeof element.hole_offset_x === "number" ? element.hole_offset_x : 0;
53939
- const offsetY = "hole_offset_y" in element && typeof element.hole_offset_y === "number" ? element.hole_offset_y : 0;
53940
- const centerX = elementX + offsetX;
53941
- const centerY = elementY + offsetY;
53942
- const yMultiplier = flip_y_axis ? -1 : 1;
56173
+ const drillCenter = getDrillCenter(element);
56174
+ const centerX = drillCenter.x;
56175
+ const centerY = drillCenter.y;
56176
+ const yMultiplier = getYMultiplier(flip_y_axis);
53943
56177
  if ("hole_width" in element && typeof element.hole_width === "number" && "hole_height" in element && typeof element.hole_height === "number") {
53944
56178
  const holeWidth = element.hole_width;
53945
56179
  const holeHeight = element.hole_height;
@@ -53952,14 +56186,16 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
53952
56186
  });
53953
56187
  continue;
53954
56188
  }
53955
- const rotationDegrees = "hole_ccw_rotation" in element && typeof element.hole_ccw_rotation === "number" ? element.hole_ccw_rotation : ("ccw_rotation" in element) && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
56189
+ const rotationDegrees = getHoleRotationDegrees(element);
53956
56190
  const rotationRadians = rotationDegrees * Math.PI / 180;
53957
56191
  const cosTheta = Math.cos(rotationRadians);
53958
56192
  const sinTheta = Math.sin(rotationRadians);
53959
- const isWidthMajor = holeWidth >= holeHeight;
53960
56193
  const slotHalfLength = (maxDim - minDim) / 2;
53961
- const startRelative = isWidthMajor ? { x: -slotHalfLength, y: 0 } : { x: 0, y: -slotHalfLength };
53962
- const endRelative = isWidthMajor ? { x: slotHalfLength, y: 0 } : { x: 0, y: slotHalfLength };
56194
+ const { startRelative, endRelative } = getSlotEndpoints({
56195
+ holeWidth,
56196
+ holeHeight,
56197
+ slotHalfLength
56198
+ });
53963
56199
  const rotatePoint4 = ({ x: x4, y: y4 }) => ({
53964
56200
  x: x4 * cosTheta - y4 * sinTheta,
53965
56201
  y: x4 * sinTheta + y4 * cosTheta
@@ -54061,7 +56297,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54061
56297
  0 $4 = Circle center offset
54062
56298
  0 21 = Center Line(Exposure, Width, Height, Center X, Center Y, Rotation)*
54063
56299
  0 1 = Circle(Exposure, Diameter, Center X, Center Y, Rotation)*
54064
- 21,1,$1,$2,0.0,0.0,0.0*
56300
+ 21,1,$1-$3,$2,0.0,0.0,0.0*
54065
56301
  1,1,$3,0.0-$4,0.0*
54066
56302
  1,1,$3,$4,0.0*
54067
56303
  `.trim()
@@ -54075,12 +56311,12 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54075
56311
  0 $3 = Circle diameter (equal to width)*
54076
56312
  0 $4 = Circle center offset
54077
56313
  0 21 = Center Line(Exposure, Width, Height, Center X, Center Y, Rotation)*
54078
- 21,1,$1,$2,0.0,0.0,0.0*
56314
+ 21,1,$1,$2-$3,0.0,0.0,0.0*
54079
56315
  1,1,$3,0.0,0.0-$4*
54080
56316
  1,1,$3,0.0,$4*
54081
56317
  `.trim()
54082
56318
  }).add("define_macro_aperture_template", {
54083
- macro_name: "RoundRect",
56319
+ macro_name: "ROUNDRECT",
54084
56320
  template_code: `
54085
56321
  0 Rectangle with rounded corners*
54086
56322
  0 $1 Corner radius*
@@ -54099,7 +56335,117 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54099
56335
  20,1,$1+$1,$8,$9,$2,$3,0*
54100
56336
  `.trim()
54101
56337
  }).add("comment", { comment: "APERTURE MACROS END" }).build());
54102
- }, getApertureConfigFromPcbSmtpad = (elm) => {
56338
+ }, SILKSCREEN_SHAPE_TYPES, isSilkscreenShape = (element) => SILKSCREEN_SHAPE_TYPES.includes(element.type), DEFAULT_STROKE_WIDTH2 = 0.1, ELLIPSE_SEGMENTS = 48, CORNER_SEGMENTS = 12, rotationAboutCenter = (center2, ccwDegrees) => ccwDegrees ? compose9(translate9(center2.x, center2.y), rotate12(ccwDegrees * Math.PI / 180), translate9(-center2.x, -center2.y)) : identity8(), ellipseRoute = (center2, radiusX, radiusY, ccwDegrees = 0) => {
56339
+ const matrix2 = rotationAboutCenter(center2, ccwDegrees);
56340
+ return Array.from({ length: ELLIPSE_SEGMENTS + 1 }, (_4, i3) => {
56341
+ const angle = i3 / ELLIPSE_SEGMENTS * Math.PI * 2;
56342
+ return applyToPoint26(matrix2, {
56343
+ x: center2.x + radiusX * Math.cos(angle),
56344
+ y: center2.y + radiusY * Math.sin(angle)
56345
+ });
56346
+ });
56347
+ }, rectangleRoute = (center2, width, height, cornerRadius, ccwDegrees = 0) => {
56348
+ const halfW = width / 2;
56349
+ const halfH = height / 2;
56350
+ const route = [];
56351
+ if (cornerRadius <= 0) {
56352
+ const bounds = getBoundFromCenteredRect2({ center: center2, width, height });
56353
+ route.push({ x: bounds.minX, y: bounds.minY }, { x: bounds.maxX, y: bounds.minY }, { x: bounds.maxX, y: bounds.maxY }, { x: bounds.minX, y: bounds.maxY });
56354
+ } else {
56355
+ const insetW = halfW - cornerRadius;
56356
+ const insetH = halfH - cornerRadius;
56357
+ const corners = [
56358
+ { x: center2.x + insetW, y: center2.y + insetH, start: 0 },
56359
+ { x: center2.x - insetW, y: center2.y + insetH, start: Math.PI / 2 },
56360
+ { x: center2.x - insetW, y: center2.y - insetH, start: Math.PI },
56361
+ { x: center2.x + insetW, y: center2.y - insetH, start: 3 * Math.PI / 2 }
56362
+ ];
56363
+ for (const corner of corners) {
56364
+ for (let i3 = 0;i3 <= CORNER_SEGMENTS; i3++) {
56365
+ const angle = corner.start + i3 / CORNER_SEGMENTS * (Math.PI / 2);
56366
+ route.push({
56367
+ x: corner.x + cornerRadius * Math.cos(angle),
56368
+ y: corner.y + cornerRadius * Math.sin(angle)
56369
+ });
56370
+ }
56371
+ }
56372
+ }
56373
+ route.push(route[0]);
56374
+ const matrix2 = rotationAboutCenter(center2, ccwDegrees);
56375
+ return route.map((point9) => applyToPoint26(matrix2, point9));
56376
+ }, clampCornerRadius = (width, height, cornerRadius) => {
56377
+ if (typeof cornerRadius !== "number" || cornerRadius <= 0)
56378
+ return 0;
56379
+ return Math.min(cornerRadius, width / 2, height / 2);
56380
+ }, getSilkscreenShapeStroke = (element) => {
56381
+ const strokeWidth = element.stroke_width ?? DEFAULT_STROKE_WIDTH2;
56382
+ switch (element.type) {
56383
+ case "pcb_silkscreen_line":
56384
+ return {
56385
+ route: [
56386
+ { x: element.x1, y: element.y1 },
56387
+ { x: element.x2, y: element.y2 }
56388
+ ],
56389
+ strokeWidth
56390
+ };
56391
+ case "pcb_silkscreen_rect":
56392
+ return {
56393
+ route: rectangleRoute(element.center, element.width, element.height, clampCornerRadius(element.width, element.height, element.corner_radius), element.ccw_rotation ?? 0),
56394
+ strokeWidth
56395
+ };
56396
+ case "pcb_silkscreen_circle":
56397
+ return {
56398
+ route: ellipseRoute(element.center, element.radius, element.radius),
56399
+ strokeWidth
56400
+ };
56401
+ case "pcb_silkscreen_oval":
56402
+ return {
56403
+ route: ellipseRoute(element.center, element.radius_x, element.radius_y, element.ccw_rotation ?? 0),
56404
+ strokeWidth
56405
+ };
56406
+ case "pcb_silkscreen_pill":
56407
+ return {
56408
+ route: rectangleRoute(element.center, element.width, element.height, Math.min(element.width, element.height) / 2),
56409
+ strokeWidth
56410
+ };
56411
+ default:
56412
+ return null;
56413
+ }
56414
+ }, getLayerRefFromGerberLayerName = (glayer_name) => {
56415
+ if (glayer_name.startsWith("F_"))
56416
+ return "top";
56417
+ if (glayer_name.startsWith("B_"))
56418
+ return "bottom";
56419
+ const innerLayerMatch = glayer_name.match(/^In([1-6])_/);
56420
+ if (innerLayerMatch)
56421
+ return `inner${innerLayerMatch[1]}`;
56422
+ throw new Error(`Could not infer layer ref from ${glayer_name}`);
56423
+ }, getClampedRoundedRectCornerRadius = (width, height, cornerRadius) => {
56424
+ if (typeof cornerRadius !== "number")
56425
+ return 0;
56426
+ return Math.max(0, Math.min(cornerRadius, width / 2, height / 2));
56427
+ }, getRoundedRectApertureConfig = (width, height, cornerRadius) => {
56428
+ const halfWidth = width / 2;
56429
+ const halfHeight = height / 2;
56430
+ return {
56431
+ macro_name: "ROUNDRECT",
56432
+ corner_radius: cornerRadius,
56433
+ corner_1_x: -halfWidth + cornerRadius,
56434
+ corner_1_y: halfHeight - cornerRadius,
56435
+ corner_2_x: halfWidth - cornerRadius,
56436
+ corner_2_y: halfHeight - cornerRadius,
56437
+ corner_3_x: halfWidth - cornerRadius,
56438
+ corner_3_y: -halfHeight + cornerRadius,
56439
+ corner_4_x: -halfWidth + cornerRadius,
56440
+ corner_4_y: -halfHeight + cornerRadius
56441
+ };
56442
+ }, REGION_APERTURE_CONFIG, getApertureConfigFromPcbSmtpad = (elm) => {
56443
+ if (elm.shape === "rect" || elm.shape === "rotated_rect") {
56444
+ const cornerRadius = getClampedRoundedRectCornerRadius(elm.width, elm.height, "corner_radius" in elm ? elm.corner_radius : undefined);
56445
+ if (cornerRadius > 0) {
56446
+ return getRoundedRectApertureConfig(elm.width, elm.height, cornerRadius);
56447
+ }
56448
+ }
54103
56449
  if (elm.shape === "rect") {
54104
56450
  return {
54105
56451
  standard_template_code: "R",
@@ -54120,6 +56466,63 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54120
56466
  y_size: elm.height
54121
56467
  };
54122
56468
  }
56469
+ if (elm.shape === "pill" || elm.shape === "rotated_pill") {
56470
+ if (!(("width" in elm) && ("height" in elm))) {
56471
+ throw new Error("Invalid pill shape in getApertureConfigFromPcbSmtpad: missing dimensions");
56472
+ }
56473
+ return {
56474
+ standard_template_code: "C",
56475
+ diameter: Math.min(elm.width, elm.height)
56476
+ };
56477
+ }
56478
+ if (elm.shape === "polygon") {
56479
+ throw new Error("Polygon SMT pads are drawn as regions, not apertures");
56480
+ }
56481
+ throw new Error(`Unsupported shape ${elm.shape}`);
56482
+ }, getApertureConfigFromPcbSmtpadSoldermask = (elm) => {
56483
+ let soldermaskMargin = 0;
56484
+ if ("soldermask_margin" in elm && typeof elm.soldermask_margin === "number") {
56485
+ soldermaskMargin = elm.soldermask_margin;
56486
+ }
56487
+ if (elm.shape === "rect" || elm.shape === "rotated_rect") {
56488
+ const width = elm.width + soldermaskMargin * 2;
56489
+ const height = elm.height + soldermaskMargin * 2;
56490
+ const cornerRadius = getClampedRoundedRectCornerRadius(width, height, "corner_radius" in elm && typeof elm.corner_radius === "number" ? elm.corner_radius + soldermaskMargin : undefined);
56491
+ if (cornerRadius > 0) {
56492
+ return getRoundedRectApertureConfig(width, height, cornerRadius);
56493
+ }
56494
+ }
56495
+ if (elm.shape === "rect") {
56496
+ return {
56497
+ standard_template_code: "R",
56498
+ x_size: elm.width + soldermaskMargin * 2,
56499
+ y_size: elm.height + soldermaskMargin * 2
56500
+ };
56501
+ }
56502
+ if (elm.shape === "circle") {
56503
+ return {
56504
+ standard_template_code: "C",
56505
+ diameter: elm.radius * 2 + soldermaskMargin * 2
56506
+ };
56507
+ }
56508
+ if (elm.shape === "rotated_rect") {
56509
+ return {
56510
+ standard_template_code: "R",
56511
+ x_size: elm.width + soldermaskMargin * 2,
56512
+ y_size: elm.height + soldermaskMargin * 2
56513
+ };
56514
+ }
56515
+ if (elm.shape === "pill" || elm.shape === "rotated_pill") {
56516
+ if (!(("width" in elm) && ("height" in elm))) {
56517
+ throw new Error("Invalid pill shape in getApertureConfigFromPcbSmtpadSoldermask: missing dimensions");
56518
+ }
56519
+ const width = elm.width + soldermaskMargin * 2;
56520
+ const height = elm.height + soldermaskMargin * 2;
56521
+ return {
56522
+ standard_template_code: "C",
56523
+ diameter: Math.min(width, height)
56524
+ };
56525
+ }
54123
56526
  if (elm.shape === "polygon") {
54124
56527
  throw new Error("Polygon SMT pads are drawn as regions, not apertures");
54125
56528
  }
@@ -54148,6 +56551,30 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54148
56551
  };
54149
56552
  }
54150
56553
  throw new Error(`Provide font_size for: ${elm}`);
56554
+ }, getApertureConfigFromPcbFabricationNoteText = (elm) => {
56555
+ if ("font_size" in elm) {
56556
+ return {
56557
+ standard_template_code: "C",
56558
+ diameter: elm.font_size / 8
56559
+ };
56560
+ }
56561
+ throw new Error(`Provide font_size for: ${elm}`);
56562
+ }, getApertureConfigFromPcbFabricationNotePath = (elm) => {
56563
+ if (!("stroke_width" in elm) || typeof elm.stroke_width !== "number") {
56564
+ return {
56565
+ standard_template_code: "C",
56566
+ diameter: 0.1
56567
+ };
56568
+ }
56569
+ return {
56570
+ standard_template_code: "C",
56571
+ diameter: elm.stroke_width
56572
+ };
56573
+ }, getApertureConfigFromPcbFabricationNoteDimension = (elm) => {
56574
+ return {
56575
+ standard_template_code: "C",
56576
+ diameter: Math.max(0.05, elm.font_size / 10)
56577
+ };
54151
56578
  }, getApertureConfigFromPcbSolderPaste = (elm) => {
54152
56579
  if (elm.shape === "rect") {
54153
56580
  return {
@@ -54179,7 +56606,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54179
56606
  x_size: elm.width,
54180
56607
  y_size: elm.height,
54181
56608
  circle_diameter: Math.min(elm.width, elm.height),
54182
- circle_center_offset: elm.width / 2
56609
+ circle_center_offset: (elm.width - elm.height) / 2
54183
56610
  };
54184
56611
  }
54185
56612
  return {
@@ -54187,7 +56614,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54187
56614
  x_size: elm.width,
54188
56615
  y_size: elm.height,
54189
56616
  circle_diameter: Math.min(elm.width, elm.height),
54190
- circle_center_offset: elm.height / 2
56617
+ circle_center_offset: (elm.height - elm.width) / 2
54191
56618
  };
54192
56619
  }
54193
56620
  throw new Error(`Unsupported shape ${elm.shape}`);
@@ -54211,7 +56638,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54211
56638
  x_size: elm.outer_width,
54212
56639
  y_size: elm.outer_height,
54213
56640
  circle_diameter: Math.min(elm.outer_width, elm.outer_height),
54214
- circle_center_offset: elm.outer_width / 2
56641
+ circle_center_offset: (elm.outer_width - elm.outer_height) / 2
54215
56642
  };
54216
56643
  }
54217
56644
  return {
@@ -54219,7 +56646,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54219
56646
  x_size: elm.outer_width,
54220
56647
  y_size: elm.outer_height,
54221
56648
  circle_diameter: Math.min(elm.outer_width, elm.outer_height),
54222
- circle_center_offset: elm.outer_height / 2
56649
+ circle_center_offset: (elm.outer_height - elm.outer_width) / 2
54223
56650
  };
54224
56651
  }
54225
56652
  const shape = elm.shape;
@@ -54234,6 +56661,55 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54234
56661
  };
54235
56662
  }
54236
56663
  throw new Error(`Unsupported shape in getApertureConfigFromPcbPlatedHole: ${elm.shape}`);
56664
+ }, getApertureConfigFromPcbPlatedHoleSoldermask = (elm) => {
56665
+ let soldermaskMargin = 0;
56666
+ if ("soldermask_margin" in elm && typeof elm.soldermask_margin === "number") {
56667
+ soldermaskMargin = elm.soldermask_margin;
56668
+ }
56669
+ if (elm.shape === "circle") {
56670
+ if (!(("outer_diameter" in elm) && ("hole_diameter" in elm))) {
56671
+ throw new Error("Invalid circle shape in getApertureConfigFromPcbPlatedHoleSoldermask: missing diameters");
56672
+ }
56673
+ return {
56674
+ standard_template_code: "C",
56675
+ diameter: elm.outer_diameter + soldermaskMargin * 2
56676
+ };
56677
+ }
56678
+ if (elm.shape === "pill") {
56679
+ if (!(("outer_width" in elm) && ("outer_height" in elm))) {
56680
+ throw new Error("Invalid pill shape in getApertureConfigFromPcbPlatedHoleSoldermask: missing dimensions");
56681
+ }
56682
+ const outerWidth = elm.outer_width + soldermaskMargin * 2;
56683
+ const outerHeight = elm.outer_height + soldermaskMargin * 2;
56684
+ if (outerWidth > outerHeight) {
56685
+ return {
56686
+ macro_name: "HORZPILL",
56687
+ x_size: outerWidth,
56688
+ y_size: outerHeight,
56689
+ circle_diameter: Math.min(outerWidth, outerHeight),
56690
+ circle_center_offset: (outerWidth - outerHeight) / 2
56691
+ };
56692
+ }
56693
+ return {
56694
+ macro_name: "VERTPILL",
56695
+ x_size: outerWidth,
56696
+ y_size: outerHeight,
56697
+ circle_diameter: Math.min(outerWidth, outerHeight),
56698
+ circle_center_offset: (outerHeight - outerWidth) / 2
56699
+ };
56700
+ }
56701
+ const shape = elm.shape;
56702
+ if (shape === "circular_hole_with_rect_pad" || shape === "pill_hole_with_rect_pad" || shape === "rotated_pill_hole_with_rect_pad") {
56703
+ if (!(("rect_pad_width" in elm) && ("rect_pad_height" in elm))) {
56704
+ throw new Error(`Invalid ${shape} shape in getApertureConfigFromPcbPlatedHoleSoldermask: missing dimensions`);
56705
+ }
56706
+ return {
56707
+ standard_template_code: "R",
56708
+ x_size: elm.rect_pad_width + soldermaskMargin * 2,
56709
+ y_size: elm.rect_pad_height + soldermaskMargin * 2
56710
+ };
56711
+ }
56712
+ throw new Error(`Unsupported shape in getApertureConfigFromPcbPlatedHoleSoldermask: ${elm.shape}`);
54237
56713
  }, getApertureConfigFromCirclePcbHole = (elm) => {
54238
56714
  if (!("hole_diameter" in elm)) {
54239
56715
  throw new Error(`Invalid shape called in getApertureConfigFromCirclePcbHole: ${elm.hole_shape}`);
@@ -54242,9 +56718,21 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54242
56718
  standard_template_code: "C",
54243
56719
  diameter: elm.hole_diameter
54244
56720
  };
54245
- }, getApertureConfigFromPcbVia = (elm) => {
54246
- if (!("outer_diameter" in elm)) {
54247
- throw new Error("outer_diameter not specified in getApertureConfigFromPcbVia");
56721
+ }, getApertureConfigFromCirclePcbHoleSoldermask = (elm) => {
56722
+ if (!("hole_diameter" in elm)) {
56723
+ throw new Error(`Invalid shape called in getApertureConfigFromCirclePcbHoleSoldermask: ${elm.hole_shape}`);
56724
+ }
56725
+ let soldermaskMargin = 0;
56726
+ if ("soldermask_margin" in elm && typeof elm.soldermask_margin === "number") {
56727
+ soldermaskMargin = elm.soldermask_margin;
56728
+ }
56729
+ return {
56730
+ standard_template_code: "C",
56731
+ diameter: elm.hole_diameter + soldermaskMargin * 2
56732
+ };
56733
+ }, getApertureConfigFromOuterDiameter = (elm) => {
56734
+ if (typeof elm.outer_diameter !== "number") {
56735
+ throw new Error("outer_diameter not specified in getApertureConfigFromOuterDiameter");
54248
56736
  }
54249
56737
  return {
54250
56738
  standard_template_code: "C",
@@ -54262,8 +56750,22 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54262
56750
  throw new Error(`Aperture not found for search params ${JSON.stringify(search_params)}`);
54263
56751
  }
54264
56752
  return aperture.aperture_number;
54265
- }, package_default5, layerAndTypeToFileFunction, getCommandHeaders = (opts) => {
54266
- const file_function = layerAndTypeToFileFunction[opts.layer_type ? `${opts.layer}-${opts.layer_type}` : opts.layer];
56753
+ }, package_default5, layerAndTypeToFileFunction, getCopperLayerNumber = (layer, total_layer_count) => {
56754
+ if (layer === "top")
56755
+ return 1;
56756
+ if (layer === "bottom")
56757
+ return total_layer_count;
56758
+ return Number(layer.replace("inner", "")) + 1;
56759
+ }, getCommandHeaders = (opts) => {
56760
+ const total_layer_count = opts.total_layer_count ?? 2;
56761
+ let file_function;
56762
+ if (opts.layer_type === "copper" && opts.layer !== "edgecut") {
56763
+ const layerNumber = getCopperLayerNumber(opts.layer, total_layer_count);
56764
+ const layerPosition = opts.layer === "top" ? "Top" : opts.layer === "bottom" ? "Bot" : "Inr";
56765
+ file_function = `Copper,L${layerNumber},${layerPosition}`;
56766
+ } else {
56767
+ file_function = layerAndTypeToFileFunction[opts.layer_type ? `${opts.layer}-${opts.layer_type}` : opts.layer];
56768
+ }
54267
56769
  return gerberBuilder().add("add_attribute_on_file", {
54268
56770
  attribute_name: "GenerationSoftware",
54269
56771
  attribute_value: `tscircuit,circuit-json-to-gerber,${package_default5.version}`
@@ -54291,14 +56793,564 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54291
56793
  }, layerRefToGerberPrefix, layerTypeToGerberSuffix, getGerberLayerName = (layer_ref2, layer_type) => {
54292
56794
  if (layer_ref2 === "edgecut")
54293
56795
  return "Edge_Cuts";
56796
+ if (layer_ref2.startsWith("inner") && layer_type !== "copper") {
56797
+ throw new Error(`Inner layer ${layer_ref2} only supports copper gerbers`);
56798
+ }
54294
56799
  return `${layerRefToGerberPrefix[layer_ref2]}${layerTypeToGerberSuffix[layer_type]}`;
54295
- }, convertSoupToGerberCommands = (soup, opts = {}) => {
56800
+ }, getSignedPolygonArea = (points) => {
56801
+ let area2 = 0;
56802
+ for (let i3 = 0;i3 < points.length; i3++) {
56803
+ const current2 = points[i3];
56804
+ const next = points[(i3 + 1) % points.length];
56805
+ area2 += current2.x * next.y - next.x * current2.y;
56806
+ }
56807
+ return area2 / 2;
56808
+ }, getLineIntersection = (lineA, lineB) => {
56809
+ const ax3 = lineA.end.x - lineA.start.x;
56810
+ const ay3 = lineA.end.y - lineA.start.y;
56811
+ const bx3 = lineB.end.x - lineB.start.x;
56812
+ const by3 = lineB.end.y - lineB.start.y;
56813
+ const denominator = ax3 * by3 - ay3 * bx3;
56814
+ if (Math.abs(denominator) < 0.000000001) {
56815
+ return null;
56816
+ }
56817
+ const cx3 = lineB.start.x - lineA.start.x;
56818
+ const cy3 = lineB.start.y - lineA.start.y;
56819
+ const t50 = (cx3 * by3 - cy3 * bx3) / denominator;
56820
+ return {
56821
+ x: lineA.start.x + ax3 * t50,
56822
+ y: lineA.start.y + ay3 * t50
56823
+ };
56824
+ }, offsetPolygonOutline = (points, offset) => {
56825
+ if (points.length < 3 || offset === 0) {
56826
+ return points;
56827
+ }
56828
+ const isCounterClockwise = getSignedPolygonArea(points) > 0;
56829
+ const shiftedEdges = [];
56830
+ for (let i3 = 0;i3 < points.length; i3++) {
56831
+ const start = points[i3];
56832
+ const end = points[(i3 + 1) % points.length];
56833
+ const dx3 = end.x - start.x;
56834
+ const dy3 = end.y - start.y;
56835
+ const length67 = Math.sqrt(dx3 * dx3 + dy3 * dy3);
56836
+ if (length67 < 0.000000001) {
56837
+ continue;
56838
+ }
56839
+ let normalX = -dy3 / length67;
56840
+ let normalY = dx3 / length67;
56841
+ if (isCounterClockwise) {
56842
+ normalX = dy3 / length67;
56843
+ normalY = -dx3 / length67;
56844
+ }
56845
+ shiftedEdges.push({
56846
+ start: {
56847
+ x: start.x + normalX * offset,
56848
+ y: start.y + normalY * offset
56849
+ },
56850
+ end: {
56851
+ x: end.x + normalX * offset,
56852
+ y: end.y + normalY * offset
56853
+ }
56854
+ });
56855
+ }
56856
+ if (shiftedEdges.length < 3) {
56857
+ return points;
56858
+ }
56859
+ const offsetPoints = [];
56860
+ for (let i3 = 0;i3 < shiftedEdges.length; i3++) {
56861
+ const previousEdge = shiftedEdges[(i3 - 1 + shiftedEdges.length) % shiftedEdges.length];
56862
+ const currentEdge = shiftedEdges[i3];
56863
+ const intersection = getLineIntersection(previousEdge, currentEdge);
56864
+ if (intersection) {
56865
+ offsetPoints.push(intersection);
56866
+ } else {
56867
+ offsetPoints.push(currentEdge.start);
56868
+ }
56869
+ }
56870
+ return offsetPoints;
56871
+ }, outerLayerRefs, isOuterLayerRef = (layerRef) => layerRef === "top" || layerRef === "bottom", isFabricationElementOnLayer = (element, layerRef) => (element.type === "pcb_fabrication_note_text" || element.type === "pcb_fabrication_note_path" || element.type === "pcb_fabrication_note_rect" || element.type === "pcb_fabrication_note_dimension") && element.layer === layerRef, getFabricationLayerRefs = (circuitJson) => outerLayerRefs.filter((layerRef) => circuitJson.some((element) => isFabricationElementOnLayer(element, layerRef))), getFabRectPoints = (element) => {
56872
+ const bounds = getBoundFromCenteredRect3({
56873
+ center: element.center,
56874
+ width: element.width,
56875
+ height: element.height
56876
+ });
56877
+ return [
56878
+ { x: bounds.minX, y: bounds.minY },
56879
+ { x: bounds.maxX, y: bounds.minY },
56880
+ { x: bounds.maxX, y: bounds.maxY },
56881
+ { x: bounds.minX, y: bounds.maxY }
56882
+ ];
56883
+ }, renderOpenPath = ({
56884
+ element,
56885
+ glayer,
56886
+ apertureConfig,
56887
+ route,
56888
+ mapY
56889
+ }) => {
56890
+ if (route.length === 0)
56891
+ return;
56892
+ const gerber = gerberBuilder().add("select_aperture", {
56893
+ aperture_number: findApertureNumber(glayer, apertureConfig)
56894
+ });
56895
+ gerber.add("move_operation", {
56896
+ x: route[0].x,
56897
+ y: mapY(route[0].y)
56898
+ });
56899
+ const isDashed = element.is_stroke_dashed === true;
56900
+ if (!isDashed) {
56901
+ for (let i3 = 1;i3 < route.length; i3++) {
56902
+ gerber.add("plot_operation", {
56903
+ x: route[i3].x,
56904
+ y: mapY(route[i3].y)
56905
+ });
56906
+ }
56907
+ glayer.push(...gerber.build());
56908
+ return;
56909
+ }
56910
+ const dashLength = Math.max(0.2, (element.stroke_width ?? 0.1) * 4);
56911
+ const gapLength = dashLength;
56912
+ for (const [start, end] of pairs3(route)) {
56913
+ const dx3 = end.x - start.x;
56914
+ const dy3 = end.y - start.y;
56915
+ const length67 = Math.hypot(dx3, dy3);
56916
+ if (length67 <= 0.000000001)
56917
+ continue;
56918
+ const ux3 = dx3 / length67;
56919
+ const uy3 = dy3 / length67;
56920
+ let distance49 = 0;
56921
+ while (distance49 < length67) {
56922
+ const dashEndDistance = Math.min(distance49 + dashLength, length67);
56923
+ const dashStart = {
56924
+ x: start.x + ux3 * distance49,
56925
+ y: start.y + uy3 * distance49
56926
+ };
56927
+ const dashEnd = {
56928
+ x: start.x + ux3 * dashEndDistance,
56929
+ y: start.y + uy3 * dashEndDistance
56930
+ };
56931
+ gerber.add("move_operation", {
56932
+ x: dashStart.x,
56933
+ y: mapY(dashStart.y)
56934
+ });
56935
+ gerber.add("plot_operation", {
56936
+ x: dashEnd.x,
56937
+ y: mapY(dashEnd.y)
56938
+ });
56939
+ distance49 += dashLength + gapLength;
56940
+ }
56941
+ }
56942
+ glayer.push(...gerber.build());
56943
+ }, renderFabricationDimension = ({
56944
+ element,
56945
+ glayer,
56946
+ mapY,
56947
+ renderText: renderText2
56948
+ }) => {
56949
+ const from = element.from;
56950
+ const to3 = element.to;
56951
+ const dx3 = to3.x - from.x;
56952
+ const dy3 = to3.y - from.y;
56953
+ const length67 = Math.hypot(dx3, dy3);
56954
+ if (length67 <= 0.000000001)
56955
+ return;
56956
+ const offsetDistance = element.offset_distance ?? element.offset ?? 0;
56957
+ const defaultOffsetDirection = { x: -dy3 / length67, y: dx3 / length67 };
56958
+ const offsetDirection = element.offset_direction ?? defaultOffsetDirection;
56959
+ const offsetMagnitude = Math.hypot(offsetDirection.x, offsetDirection.y) || 1;
56960
+ const offsetVector = {
56961
+ x: offsetDirection.x / offsetMagnitude * offsetDistance,
56962
+ y: offsetDirection.y / offsetMagnitude * offsetDistance
56963
+ };
56964
+ const dimStart = { x: from.x + offsetVector.x, y: from.y + offsetVector.y };
56965
+ const dimEnd = { x: to3.x + offsetVector.x, y: to3.y + offsetVector.y };
56966
+ const arrowSize = element.arrow_size ?? 1;
56967
+ const ux3 = dx3 / length67;
56968
+ const uy3 = dy3 / length67;
56969
+ const px3 = -uy3;
56970
+ const py3 = ux3;
56971
+ const arrowHalfWidth = arrowSize * 0.35;
56972
+ const lineConfig = getApertureConfigFromPcbFabricationNoteDimension(element);
56973
+ renderOpenPath({
56974
+ element,
56975
+ glayer,
56976
+ apertureConfig: lineConfig,
56977
+ route: [from, dimStart, dimEnd, to3],
56978
+ mapY
56979
+ });
56980
+ renderOpenPath({
56981
+ element,
56982
+ glayer,
56983
+ apertureConfig: lineConfig,
56984
+ route: [
56985
+ {
56986
+ x: dimStart.x + ux3 * arrowSize + px3 * arrowHalfWidth,
56987
+ y: dimStart.y + uy3 * arrowSize + py3 * arrowHalfWidth
56988
+ },
56989
+ dimStart,
56990
+ {
56991
+ x: dimStart.x + ux3 * arrowSize - px3 * arrowHalfWidth,
56992
+ y: dimStart.y + uy3 * arrowSize - py3 * arrowHalfWidth
56993
+ }
56994
+ ],
56995
+ mapY
56996
+ });
56997
+ renderOpenPath({
56998
+ element,
56999
+ glayer,
57000
+ apertureConfig: lineConfig,
57001
+ route: [
57002
+ {
57003
+ x: dimEnd.x - ux3 * arrowSize + px3 * arrowHalfWidth,
57004
+ y: dimEnd.y - uy3 * arrowSize + py3 * arrowHalfWidth
57005
+ },
57006
+ dimEnd,
57007
+ {
57008
+ x: dimEnd.x - ux3 * arrowSize - px3 * arrowHalfWidth,
57009
+ y: dimEnd.y - uy3 * arrowSize - py3 * arrowHalfWidth
57010
+ }
57011
+ ],
57012
+ mapY
57013
+ });
57014
+ if (element.text) {
57015
+ renderText2({
57016
+ ...element,
57017
+ anchor_position: {
57018
+ x: (dimStart.x + dimEnd.x) / 2,
57019
+ y: (dimStart.y + dimEnd.y) / 2
57020
+ },
57021
+ anchor_alignment: "center",
57022
+ ccw_rotation: element.text_ccw_rotation ?? Math.atan2(dy3, dx3) * 180 / Math.PI
57023
+ });
57024
+ }
57025
+ }, roundedRectCornerArcSegmentCount = 8, circleCutoutPolygonSegmentCount2 = 64, getBoardOutlinePolygon = (board) => {
57026
+ if (board.outline && board.outline.length > 2) {
57027
+ return [board.outline.map((point9) => [point9.x, point9.y])];
57028
+ }
57029
+ const bounds = getBoundFromCenteredRect4({
57030
+ center: board.center,
57031
+ width: board.width,
57032
+ height: board.height
57033
+ });
57034
+ return [
57035
+ [
57036
+ [bounds.minX, bounds.minY],
57037
+ [bounds.maxX, bounds.minY],
57038
+ [bounds.maxX, bounds.maxY],
57039
+ [bounds.minX, bounds.maxY]
57040
+ ]
57041
+ ];
57042
+ }, getBoardOutlinePolygons2 = (circuitJson) => circuitJson.filter((element) => element.type === "pcb_board").map(getBoardOutlinePolygon), getRectCutoutOutlinePoints = (cutout) => {
57043
+ const { center: center2, width, height, rotation: rotation11, corner_radius } = cutout;
57044
+ const w4 = width / 2;
57045
+ const h4 = height / 2;
57046
+ const r4 = Math.max(0, Math.min(corner_radius ?? 0, Math.abs(w4), Math.abs(h4)));
57047
+ let transformMatrix = translate22(center2.x, center2.y);
57048
+ if (rotation11) {
57049
+ transformMatrix = compose22(transformMatrix, rotate22(rotation11 * Math.PI / 180));
57050
+ }
57051
+ if (r4 === 0) {
57052
+ return [
57053
+ { x: -w4, y: h4 },
57054
+ { x: w4, y: h4 },
57055
+ { x: w4, y: -h4 },
57056
+ { x: -w4, y: -h4 }
57057
+ ].map((point9) => applyToPoint25(transformMatrix, point9));
57058
+ }
57059
+ const points = [];
57060
+ const corners = [
57061
+ { center: { x: w4 - r4, y: h4 - r4 }, start: Math.PI / 2, end: 0 },
57062
+ { center: { x: w4 - r4, y: -h4 + r4 }, start: 0, end: -Math.PI / 2 },
57063
+ { center: { x: -w4 + r4, y: -h4 + r4 }, start: -Math.PI / 2, end: -Math.PI },
57064
+ { center: { x: -w4 + r4, y: h4 - r4 }, start: Math.PI, end: Math.PI / 2 }
57065
+ ];
57066
+ for (const corner of corners) {
57067
+ for (let i3 = 0;i3 <= roundedRectCornerArcSegmentCount; i3++) {
57068
+ const t50 = i3 / roundedRectCornerArcSegmentCount;
57069
+ const angle = corner.start + (corner.end - corner.start) * t50;
57070
+ points.push({
57071
+ x: corner.center.x + r4 * Math.cos(angle),
57072
+ y: corner.center.y + r4 * Math.sin(angle)
57073
+ });
57074
+ }
57075
+ }
57076
+ return points.map((point9) => applyToPoint25(transformMatrix, point9));
57077
+ }, getCircleCutoutOutlinePolygon = (cutout) => {
57078
+ const points = [];
57079
+ for (let i3 = 0;i3 < circleCutoutPolygonSegmentCount2; i3++) {
57080
+ const angle = i3 / circleCutoutPolygonSegmentCount2 * Math.PI * 2;
57081
+ points.push([
57082
+ cutout.center.x + cutout.radius * Math.cos(angle),
57083
+ cutout.center.y + cutout.radius * Math.sin(angle)
57084
+ ]);
57085
+ }
57086
+ return [points];
57087
+ }, getSolidCutoutOutlinePolygon = (cutout) => {
57088
+ if (cutout.shape === "rect") {
57089
+ return [
57090
+ getRectCutoutOutlinePoints(cutout).map((point9) => [point9.x, point9.y])
57091
+ ];
57092
+ }
57093
+ if (cutout.shape === "circle") {
57094
+ return getCircleCutoutOutlinePolygon(cutout);
57095
+ }
57096
+ if (cutout.shape === "polygon") {
57097
+ return [cutout.points.map((point9) => [point9.x, point9.y])];
57098
+ }
57099
+ return null;
57100
+ }, doesSolidCutoutOverlapBoardEdge = ({
57101
+ cutout,
57102
+ boardOutlinePolygons
57103
+ }) => {
57104
+ const cutoutOutlinePolygon = getSolidCutoutOutlinePolygon(cutout);
57105
+ if (!cutoutOutlinePolygon)
57106
+ return false;
57107
+ return boardOutlinePolygons.some((boardOutlinePolygon) => {
57108
+ const overlapsBoard = import_polygon_clipping3.default.intersection(boardOutlinePolygon, cutoutOutlinePolygon).length > 0;
57109
+ const extendsOutsideBoard = import_polygon_clipping3.default.difference(cutoutOutlinePolygon, boardOutlinePolygon).length > 0;
57110
+ return overlapsBoard && extendsOutsideBoard;
57111
+ });
57112
+ }, isCutoutFullyInternal = ({
57113
+ cutout,
57114
+ boardOutlinePolygons
57115
+ }) => {
57116
+ const cutoutOutlinePolygon = getSolidCutoutOutlinePolygon(cutout);
57117
+ if (!cutoutOutlinePolygon)
57118
+ return false;
57119
+ return boardOutlinePolygons.some((boardOutlinePolygon) => import_polygon_clipping3.default.intersection(boardOutlinePolygon, cutoutOutlinePolygon).length > 0 && import_polygon_clipping3.default.difference(cutoutOutlinePolygon, boardOutlinePolygon).length === 0);
57120
+ }, emitCutoutEdgeCuts = ({
57121
+ cutout,
57122
+ builder,
57123
+ mfy,
57124
+ drawCw
57125
+ }) => {
57126
+ if (cutout.shape === "circle") {
57127
+ emitCircle({ cutout, builder, mfy, drawCw });
57128
+ } else if (cutout.shape === "rect") {
57129
+ emitRect({ cutout, builder, mfy, drawCw });
57130
+ } else if (cutout.shape === "polygon") {
57131
+ emitPolygon({ cutout, builder, mfy, drawCw });
57132
+ }
57133
+ }, emitCircle = ({
57134
+ cutout,
57135
+ builder,
57136
+ mfy,
57137
+ drawCw
57138
+ }) => {
57139
+ const { center: center2, radius } = cutout;
57140
+ const p12 = { x: center2.x + radius, y: center2.y };
57141
+ const p23 = { x: center2.x - radius, y: center2.y };
57142
+ const isYFlipped = mfy(1) < 0;
57143
+ let isClockwise = drawCw;
57144
+ if (isYFlipped) {
57145
+ isClockwise = !isClockwise;
57146
+ }
57147
+ let arcMode = "set_movement_mode_to_counterclockwise_circular";
57148
+ if (isClockwise) {
57149
+ arcMode = "set_movement_mode_to_clockwise_circular";
57150
+ }
57151
+ builder.add("move_operation", { x: p12.x, y: mfy(p12.y) }).add(arcMode, {}).add("plot_operation", { x: p23.x, y: mfy(p23.y), i: -radius, j: 0 }).add("plot_operation", { x: p12.x, y: mfy(p12.y), i: radius, j: 0 }).add("set_movement_mode_to_linear", {});
57152
+ }, emitRect = ({
57153
+ cutout,
57154
+ builder,
57155
+ mfy,
57156
+ drawCw
57157
+ }) => {
57158
+ const { center: center2, width, height, rotation: rotation11, corner_radius } = cutout;
57159
+ const w4 = width / 2;
57160
+ const h4 = height / 2;
57161
+ let cr3 = 0;
57162
+ if (corner_radius !== undefined) {
57163
+ cr3 = corner_radius;
57164
+ }
57165
+ const r4 = Math.max(0, Math.min(cr3, Math.abs(w4), Math.abs(h4)));
57166
+ let rotationTransform = identity22();
57167
+ if (rotation11) {
57168
+ rotationTransform = rotate32(rotation11 * Math.PI / 180);
57169
+ }
57170
+ const transformMatrix = compose32(translate32(center2.x, center2.y), rotationTransform);
57171
+ if (r4 > 0) {
57172
+ emitRoundedRect({ w: w4, h: h4, r: r4, transformMatrix, builder, mfy, drawCw });
57173
+ } else {
57174
+ emitSharpRect({ w: w4, h: h4, transformMatrix, builder, mfy, drawCw });
57175
+ }
57176
+ }, emitSharpRect = ({
57177
+ w: w4,
57178
+ h: h4,
57179
+ transformMatrix,
57180
+ builder,
57181
+ mfy,
57182
+ drawCw
57183
+ }) => {
57184
+ const cwPoints = [
57185
+ { x: -w4, y: h4 },
57186
+ { x: w4, y: h4 },
57187
+ { x: w4, y: -h4 },
57188
+ { x: -w4, y: -h4 }
57189
+ ];
57190
+ const isYFlipped = mfy(1) < 0;
57191
+ let shouldReverse = !drawCw;
57192
+ if (isYFlipped) {
57193
+ shouldReverse = !shouldReverse;
57194
+ }
57195
+ let pts = cwPoints;
57196
+ if (shouldReverse) {
57197
+ pts = [...cwPoints].reverse();
57198
+ }
57199
+ const tpts = pts.map((p3) => applyToPoint32(transformMatrix, p3));
57200
+ builder.add("move_operation", { x: tpts[0].x, y: mfy(tpts[0].y) });
57201
+ for (let i3 = 1;i3 < tpts.length; i3++) {
57202
+ builder.add("plot_operation", { x: tpts[i3].x, y: mfy(tpts[i3].y) });
57203
+ }
57204
+ builder.add("plot_operation", { x: tpts[0].x, y: mfy(tpts[0].y) });
57205
+ }, emitRoundedRect = ({
57206
+ w: w4,
57207
+ h: h4,
57208
+ r: r4,
57209
+ transformMatrix,
57210
+ builder,
57211
+ mfy,
57212
+ drawCw
57213
+ }) => {
57214
+ const isYFlipped = mfy(1) < 0;
57215
+ let isClockwise = drawCw;
57216
+ if (isYFlipped) {
57217
+ isClockwise = !isClockwise;
57218
+ }
57219
+ let arcMode = "set_movement_mode_to_counterclockwise_circular";
57220
+ if (isClockwise) {
57221
+ arcMode = "set_movement_mode_to_clockwise_circular";
57222
+ }
57223
+ let currentPoint;
57224
+ const addLine = (pt3) => {
57225
+ const tpt = applyToPoint32(transformMatrix, pt3);
57226
+ builder.add("plot_operation", { x: tpt.x, y: mfy(tpt.y) });
57227
+ currentPoint = tpt;
57228
+ };
57229
+ const addArc = (endPt, centerPt) => {
57230
+ const tEnd = applyToPoint32(transformMatrix, endPt);
57231
+ const tCenter = applyToPoint32(transformMatrix, centerPt);
57232
+ builder.add(arcMode, {}).add("plot_operation", {
57233
+ x: tEnd.x,
57234
+ y: mfy(tEnd.y),
57235
+ i: tCenter.x - currentPoint.x,
57236
+ j: mfy(tCenter.y) - mfy(currentPoint.y)
57237
+ }).add("set_movement_mode_to_linear", {});
57238
+ currentPoint = tEnd;
57239
+ };
57240
+ if (isClockwise) {
57241
+ const cwSegments = [
57242
+ {
57243
+ lineTo: { x: w4 - r4, y: h4 },
57244
+ arcEnd: { x: w4, y: h4 - r4 },
57245
+ arcCenter: { x: w4 - r4, y: h4 - r4 }
57246
+ },
57247
+ {
57248
+ lineTo: { x: w4, y: -h4 + r4 },
57249
+ arcEnd: { x: w4 - r4, y: -h4 },
57250
+ arcCenter: { x: w4 - r4, y: -h4 + r4 }
57251
+ },
57252
+ {
57253
+ lineTo: { x: -w4 + r4, y: -h4 },
57254
+ arcEnd: { x: -w4, y: -h4 + r4 },
57255
+ arcCenter: { x: -w4 + r4, y: -h4 + r4 }
57256
+ },
57257
+ {
57258
+ lineTo: { x: -w4, y: h4 - r4 },
57259
+ arcEnd: { x: -w4 + r4, y: h4 },
57260
+ arcCenter: { x: -w4 + r4, y: h4 - r4 }
57261
+ }
57262
+ ];
57263
+ const startPt = { x: -w4 + r4, y: h4 };
57264
+ const tStart = applyToPoint32(transformMatrix, startPt);
57265
+ builder.add("move_operation", { x: tStart.x, y: mfy(tStart.y) });
57266
+ currentPoint = tStart;
57267
+ for (const seg of cwSegments) {
57268
+ addLine(seg.lineTo);
57269
+ addArc(seg.arcEnd, seg.arcCenter);
57270
+ }
57271
+ } else {
57272
+ const startPt = { x: w4 - r4, y: h4 };
57273
+ const tStart = applyToPoint32(transformMatrix, startPt);
57274
+ builder.add("move_operation", { x: tStart.x, y: mfy(tStart.y) });
57275
+ currentPoint = tStart;
57276
+ addLine({ x: -w4 + r4, y: h4 });
57277
+ addArc({ x: -w4, y: h4 - r4 }, { x: -w4 + r4, y: h4 - r4 });
57278
+ addLine({ x: -w4, y: -h4 + r4 });
57279
+ addArc({ x: -w4 + r4, y: -h4 }, { x: -w4 + r4, y: -h4 + r4 });
57280
+ addLine({ x: w4 - r4, y: -h4 });
57281
+ addArc({ x: w4, y: -h4 + r4 }, { x: w4 - r4, y: -h4 + r4 });
57282
+ addLine({ x: w4, y: h4 - r4 });
57283
+ addArc({ x: w4 - r4, y: h4 }, { x: w4 - r4, y: h4 - r4 });
57284
+ }
57285
+ }, emitPolygon = ({
57286
+ cutout,
57287
+ builder,
57288
+ mfy,
57289
+ drawCw
57290
+ }) => {
57291
+ const points = cutout.points;
57292
+ if (points.length === 0)
57293
+ return;
57294
+ const isYFlipped = mfy(1) < 0;
57295
+ let shouldReverse = !drawCw;
57296
+ if (isYFlipped) {
57297
+ shouldReverse = !shouldReverse;
57298
+ }
57299
+ let ordered = points;
57300
+ if (shouldReverse) {
57301
+ ordered = [...points].reverse();
57302
+ }
57303
+ builder.add("move_operation", { x: ordered[0].x, y: mfy(ordered[0].y) });
57304
+ for (let i3 = 1;i3 < ordered.length; i3++) {
57305
+ builder.add("plot_operation", { x: ordered[i3].x, y: mfy(ordered[i3].y) });
57306
+ }
57307
+ builder.add("plot_operation", { x: ordered[0].x, y: mfy(ordered[0].y) });
57308
+ }, closeRing = (ring) => {
57309
+ const first = ring[0];
57310
+ const last = ring[ring.length - 1];
57311
+ if (!first || !last)
57312
+ return ring;
57313
+ if (first[0] === last[0] && first[1] === last[1])
57314
+ return ring;
57315
+ return [...ring, first];
57316
+ }, emitEdgeCutRing = (gerberBuild, ring, mfy) => {
57317
+ const closedRing = closeRing(ring);
57318
+ const firstPoint = closedRing[0];
57319
+ if (!firstPoint || closedRing.length < 4)
57320
+ return;
57321
+ gerberBuild.add("move_operation", {
57322
+ x: firstPoint[0],
57323
+ y: mfy(firstPoint[1])
57324
+ });
57325
+ for (let i3 = 1;i3 < closedRing.length; i3++) {
57326
+ const point9 = closedRing[i3];
57327
+ gerberBuild.add("plot_operation", {
57328
+ x: point9[0],
57329
+ y: mfy(point9[1])
57330
+ });
57331
+ }
57332
+ }, getLayerCount2 = (circuitJson) => {
57333
+ const board = circuitJson.find((element) => element.type === "pcb_board");
57334
+ const numLayers = board?.num_layers ?? 2;
57335
+ return Math.max(2, Math.min(8, numLayers));
57336
+ }, getInnerLayerRefs = (layerCount) => Array.from({ length: layerCount - 2 }, (_4, i3) => `inner${i3 + 1}`), getGerberInnerLayerName = (layerRef) => {
57337
+ if (!layerRef.startsWith("inner")) {
57338
+ throw new Error(`Expected inner layer, got ${layerRef}`);
57339
+ }
57340
+ return `In${layerRef.replace("inner", "")}_Cu`;
57341
+ }, convertSoupToGerberCommands = (circuitJson, opts = {}) => {
54296
57342
  opts.flip_y_axis ??= false;
54297
- const hasPanel = soup.some((e4) => e4.type === "pcb_panel");
57343
+ const hasPanel = circuitJson.some((e4) => e4.type === "pcb_panel");
57344
+ const hasBoard = circuitJson.some((e4) => e4.type === "pcb_board");
57345
+ const layerCount = getLayerCount2(circuitJson);
57346
+ const innerLayerRefs = getInnerLayerRefs(layerCount);
57347
+ const copperLayerRefs = ["top", ...innerLayerRefs, "bottom"];
57348
+ const fabricationLayerRefs = getFabricationLayerRefs(circuitJson);
54298
57349
  const glayers = {
54299
57350
  F_Cu: getCommandHeaders({
54300
57351
  layer: "top",
54301
- layer_type: "copper"
57352
+ layer_type: "copper",
57353
+ total_layer_count: layerCount
54302
57354
  }),
54303
57355
  F_SilkScreen: getCommandHeaders({
54304
57356
  layer: "top",
@@ -54314,7 +57366,8 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54314
57366
  }),
54315
57367
  B_Cu: getCommandHeaders({
54316
57368
  layer: "bottom",
54317
- layer_type: "copper"
57369
+ layer_type: "copper",
57370
+ total_layer_count: layerCount
54318
57371
  }),
54319
57372
  B_SilkScreen: getCommandHeaders({
54320
57373
  layer: "bottom",
@@ -54332,20 +57385,36 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54332
57385
  layer: "edgecut"
54333
57386
  })
54334
57387
  };
57388
+ for (const innerLayerRef of innerLayerRefs) {
57389
+ glayers[getGerberInnerLayerName(innerLayerRef)] = getCommandHeaders({
57390
+ layer: innerLayerRef,
57391
+ layer_type: "copper",
57392
+ total_layer_count: layerCount
57393
+ });
57394
+ }
57395
+ for (const layerRef of fabricationLayerRefs) {
57396
+ glayers[getGerberLayerName(layerRef, "fabrication")] = getCommandHeaders({
57397
+ layer: layerRef,
57398
+ layer_type: "fabrication"
57399
+ });
57400
+ }
57401
+ const copperGerberLayerNames = copperLayerRefs.map((layerRef) => getGerberLayerName(layerRef, "copper"));
57402
+ const fabricationGerberLayerNames = fabricationLayerRefs.map((layerRef) => getGerberLayerName(layerRef, "fabrication"));
57403
+ const outerGerberLayerNames = outerLayerRefs.flatMap((layerRef) => [
57404
+ getGerberLayerName(layerRef, "soldermask"),
57405
+ getGerberLayerName(layerRef, "paste"),
57406
+ getGerberLayerName(layerRef, "silkscreen")
57407
+ ]);
54335
57408
  for (const glayer_name of [
54336
57409
  "F_Cu",
54337
- "B_Cu",
54338
- "F_Mask",
54339
- "B_Mask",
54340
- "F_Paste",
54341
- "B_Paste",
54342
- "F_SilkScreen",
54343
- "B_SilkScreen"
57410
+ ...copperGerberLayerNames.filter((name) => name !== "F_Cu"),
57411
+ ...fabricationGerberLayerNames,
57412
+ ...outerGerberLayerNames
54344
57413
  ]) {
54345
57414
  const glayer = glayers[glayer_name];
54346
57415
  defineCommonMacros(glayer);
54347
57416
  defineAperturesForLayer({
54348
- soup,
57417
+ circuitJson,
54349
57418
  glayer,
54350
57419
  glayer_name
54351
57420
  });
@@ -54355,14 +57424,92 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54355
57424
  standard_template_code: "C",
54356
57425
  diameter: 0.05
54357
57426
  }).build());
54358
- const mfy = (y4) => opts.flip_y_axis ? -y4 : y4;
54359
- const rotationLookup = /* @__PURE__ */ new Map;
54360
- for (const element of soup) {
54361
- if (element.type === "pcb_plated_hole" && "x" in element && typeof element.x === "number" && "y" in element && typeof element.y === "number") {
54362
- const rotation11 = "ccw_rotation" in element && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
54363
- rotationLookup.set(`${element.x}:${element.y}`, rotation11);
57427
+ const mfy = (y4) => {
57428
+ if (opts.flip_y_axis) {
57429
+ return -y4;
54364
57430
  }
54365
- }
57431
+ return y4;
57432
+ };
57433
+ const boardOutlinePolygons = getBoardOutlinePolygons2(circuitJson);
57434
+ const solidCutoutPolygons = circuitJson.filter((element) => element.type === "pcb_cutout").filter((cutout) => doesSolidCutoutOverlapBoardEdge({ cutout, boardOutlinePolygons })).map(getSolidCutoutOutlinePolygon).filter((polygon2) => polygon2 !== null);
57435
+ const renderPillFlash = ({
57436
+ glayer,
57437
+ x: x4,
57438
+ y: y4,
57439
+ width,
57440
+ height,
57441
+ rotationDegrees = 0
57442
+ }) => {
57443
+ const circleApertureConfig = {
57444
+ standard_template_code: "C",
57445
+ diameter: Math.min(width, height)
57446
+ };
57447
+ const apertureNumber = findApertureNumber(glayer, circleApertureConfig);
57448
+ const gb3 = gerberBuilder().add("select_aperture", {
57449
+ aperture_number: apertureNumber
57450
+ });
57451
+ const offset = Math.abs(width - height) / 2;
57452
+ const rotationRadians = rotationDegrees * Math.PI / 180;
57453
+ const cosTheta = Math.cos(rotationRadians);
57454
+ const sinTheta = Math.sin(rotationRadians);
57455
+ const rotateAndTranslate = (dx3, dy3) => ({
57456
+ x: x4 + dx3 * cosTheta - dy3 * sinTheta,
57457
+ y: y4 + dx3 * sinTheta + dy3 * cosTheta
57458
+ });
57459
+ if (offset <= 0.000000001) {
57460
+ gb3.add("flash_operation", { x: x4, y: mfy(y4) });
57461
+ glayer.push(...gb3.build());
57462
+ return;
57463
+ }
57464
+ const isHorizontal2 = width >= height;
57465
+ const startRelative = isHorizontal2 ? { x: -offset, y: 0 } : { x: 0, y: -offset };
57466
+ const endRelative = isHorizontal2 ? { x: offset, y: 0 } : { x: 0, y: offset };
57467
+ const startPoint = rotateAndTranslate(startRelative.x, startRelative.y);
57468
+ const endPoint = rotateAndTranslate(endRelative.x, endRelative.y);
57469
+ gb3.add("flash_operation", {
57470
+ x: startPoint.x,
57471
+ y: mfy(startPoint.y)
57472
+ }).add("move_operation", {
57473
+ x: startPoint.x,
57474
+ y: mfy(startPoint.y)
57475
+ }).add("plot_operation", {
57476
+ x: endPoint.x,
57477
+ y: mfy(endPoint.y)
57478
+ }).add("flash_operation", {
57479
+ x: endPoint.x,
57480
+ y: mfy(endPoint.y)
57481
+ });
57482
+ glayer.push(...gb3.build());
57483
+ };
57484
+ const getRegionApertureNumber = (glayer) => findApertureNumber(glayer, REGION_APERTURE_CONFIG);
57485
+ const addClosedRegionFromPoints = ({
57486
+ target,
57487
+ apertureSource,
57488
+ points
57489
+ }) => {
57490
+ if (points.length === 0)
57491
+ return;
57492
+ const regionApertureNumber = getRegionApertureNumber(apertureSource);
57493
+ const regionBuilder = gerberBuilder().add("select_aperture", {
57494
+ aperture_number: regionApertureNumber
57495
+ }).add("start_region_statement", {});
57496
+ regionBuilder.add("move_operation", {
57497
+ x: points[0].x,
57498
+ y: mfy(points[0].y)
57499
+ });
57500
+ for (let i3 = 1;i3 < points.length; i3++) {
57501
+ regionBuilder.add("plot_operation", {
57502
+ x: points[i3].x,
57503
+ y: mfy(points[i3].y)
57504
+ });
57505
+ }
57506
+ regionBuilder.add("plot_operation", {
57507
+ x: points[0].x,
57508
+ y: mfy(points[0].y)
57509
+ });
57510
+ regionBuilder.add("end_region_statement", {});
57511
+ target.push(...regionBuilder.build());
57512
+ };
54366
57513
  const renderVectorText = (element, layer, layerType, getApertureConfig) => {
54367
57514
  if (element.layer !== layer)
54368
57515
  return;
@@ -54439,16 +57586,16 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54439
57586
  const transforms = [];
54440
57587
  const shouldMirror = element.is_mirrored !== undefined ? element.is_mirrored : element.layer === "bottom";
54441
57588
  if (shouldMirror) {
54442
- transforms.push(translate9(cx3, cy3), { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 }, translate9(-cx3, -cy3));
57589
+ transforms.push(translate42(cx3, cy3), { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 }, translate42(-cx3, -cy3));
54443
57590
  rotation11 = -rotation11;
54444
57591
  }
54445
57592
  if (rotation11) {
54446
57593
  const rad = rotation11 * Math.PI / 180;
54447
- transforms.push(translate9(cx3, cy3), rotate12(rad), translate9(-cx3, -cy3));
57594
+ transforms.push(translate42(cx3, cy3), rotate42(rad), translate42(-cx3, -cy3));
54448
57595
  }
54449
- const transformMatrix = transforms.length > 0 ? compose9(...transforms) : undefined;
54450
- const applyTransform = (point9) => transformMatrix ? applyToPoint26(transformMatrix, point9) : point9;
54451
- if (layerType === "copper" && element.is_knockout) {
57596
+ const transformMatrix = transforms.length > 0 ? compose42(...transforms) : undefined;
57597
+ const applyTransform = (point9) => transformMatrix ? applyToPoint42(transformMatrix, point9) : point9;
57598
+ if (element.is_knockout) {
54452
57599
  const padding = element.knockout_padding ?? {
54453
57600
  left: 0.2,
54454
57601
  right: 0.2,
@@ -54490,7 +57637,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54490
57637
  }).add("end_region_statement", {}).build());
54491
57638
  glayer.push(...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build());
54492
57639
  }
54493
- for (const char of element.text.toUpperCase()) {
57640
+ for (const char of element.text) {
54494
57641
  if (char === " ") {
54495
57642
  anchoredX += spaceWidth + letterSpacing;
54496
57643
  continue;
@@ -54509,7 +57656,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54509
57656
  anchoredX += fontSize + letterSpacing;
54510
57657
  }
54511
57658
  glayer.push(...gerber.build());
54512
- if (layerType === "copper" && element.is_knockout) {
57659
+ if (element.is_knockout) {
54513
57660
  glayer.push(...gerberBuilder().add("set_layer_polarity", { polarity: "D" }).build());
54514
57661
  }
54515
57662
  };
@@ -54588,8 +57735,8 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54588
57735
  });
54589
57736
  return { vertices: new_vertices };
54590
57737
  };
54591
- for (const layer of ["top", "bottom"]) {
54592
- for (const element of soup) {
57738
+ for (const layer of copperLayerRefs) {
57739
+ for (const element of circuitJson) {
54593
57740
  if (element.type === "pcb_copper_pour" && layer === element.layer) {
54594
57741
  const copper_glayer = glayers[getGerberLayerName(layer, "copper")];
54595
57742
  const all_pour_commands = [];
@@ -54598,14 +57745,17 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54598
57745
  if (!brep_shape)
54599
57746
  continue;
54600
57747
  const { outer_ring, inner_rings } = brep_shape;
54601
- const outer_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
57748
+ const regionApertureNumber = getRegionApertureNumber(copper_glayer);
57749
+ const outer_builder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
54602
57750
  drawRingToBuilder(outer_builder, reverseRing(outer_ring));
54603
57751
  outer_builder.add("end_region_statement", {});
54604
57752
  all_pour_commands.push(...outer_builder.build());
54605
57753
  if (inner_rings && inner_rings.length > 0) {
54606
57754
  all_pour_commands.push(...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build());
54607
57755
  for (const inner_ring of inner_rings) {
54608
- const inner_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
57756
+ const inner_builder = gerberBuilder().add("select_aperture", {
57757
+ aperture_number: regionApertureNumber
57758
+ }).add("start_region_statement", {});
54609
57759
  drawRingToBuilder(inner_builder, inner_ring);
54610
57760
  inner_builder.add("end_region_statement", {});
54611
57761
  all_pour_commands.push(...inner_builder.build());
@@ -54622,14 +57772,15 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54622
57772
  { x: w4, y: -h4 },
54623
57773
  { x: -w4, y: -h4 }
54624
57774
  ];
54625
- let transformMatrix = identity8();
57775
+ let transformMatrix = identity32();
54626
57776
  if (rotation11) {
54627
57777
  const angle_rad = rotation11 * Math.PI / 180;
54628
- transformMatrix = rotate12(angle_rad);
57778
+ transformMatrix = rotate42(angle_rad);
54629
57779
  }
54630
- transformMatrix = compose9(translate9(center2.x, center2.y), transformMatrix);
54631
- const transformedPoints = points.map((p3) => applyToPoint26(transformMatrix, p3));
54632
- const rect_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
57780
+ transformMatrix = compose42(translate42(center2.x, center2.y), transformMatrix);
57781
+ const transformedPoints = points.map((p3) => applyToPoint42(transformMatrix, p3));
57782
+ const regionApertureNumber = getRegionApertureNumber(copper_glayer);
57783
+ const rect_builder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
54633
57784
  rect_builder.add("move_operation", {
54634
57785
  x: transformedPoints[0].x,
54635
57786
  y: mfy(transformedPoints[0].y)
@@ -54648,25 +57799,11 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54648
57799
  all_pour_commands.push(...rect_builder.build());
54649
57800
  } else if (element.shape === "polygon") {
54650
57801
  const { points } = element;
54651
- if (points.length > 0) {
54652
- const poly_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
54653
- poly_builder.add("move_operation", {
54654
- x: points[0].x,
54655
- y: mfy(points[0].y)
54656
- });
54657
- for (let i3 = 1;i3 < points.length; i3++) {
54658
- poly_builder.add("plot_operation", {
54659
- x: points[i3].x,
54660
- y: mfy(points[i3].y)
54661
- });
54662
- }
54663
- poly_builder.add("plot_operation", {
54664
- x: points[0].x,
54665
- y: mfy(points[0].y)
54666
- });
54667
- poly_builder.add("end_region_statement", {});
54668
- all_pour_commands.push(...poly_builder.build());
54669
- }
57802
+ addClosedRegionFromPoints({
57803
+ target: all_pour_commands,
57804
+ apertureSource: copper_glayer,
57805
+ points
57806
+ });
54670
57807
  }
54671
57808
  copper_glayer.push(...all_pour_commands);
54672
57809
  if (element.covered_with_solder_mask === false) {
@@ -54676,23 +57813,66 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54676
57813
  }
54677
57814
  }
54678
57815
  }
54679
- for (const layer of ["top", "bottom", "edgecut"]) {
54680
- for (const element of soup) {
57816
+ for (const layer of [...copperLayerRefs, "edgecut"]) {
57817
+ for (const element of circuitJson) {
54681
57818
  if (element.type === "pcb_trace") {
54682
- const { route } = element;
57819
+ if (layer === "edgecut")
57820
+ continue;
57821
+ const route = element.route;
54683
57822
  for (const [a3, b3] of pairs3(route)) {
54684
57823
  if (a3.route_type === "wire") {
54685
57824
  if (a3.layer === layer) {
57825
+ let bPoint = null;
57826
+ if (b3.route_type === "wire" || b3.route_type === "via") {
57827
+ bPoint = b3;
57828
+ } else if (b3.route_type === "through_pad") {
57829
+ if (b3.start_layer === layer) {
57830
+ bPoint = b3.start;
57831
+ } else if (b3.end_layer === layer) {
57832
+ bPoint = b3.end;
57833
+ }
57834
+ }
57835
+ if (!bPoint)
57836
+ continue;
54686
57837
  const glayer = glayers[getGerberLayerName(layer, "copper")];
54687
57838
  glayer.push(...gerberBuilder().add("select_aperture", {
54688
57839
  aperture_number: findApertureNumber(glayer, {
54689
57840
  trace_width: a3.width
54690
57841
  })
57842
+ }).add("move_operation", { x: a3.x, y: mfy(a3.y) }).add("plot_operation", { x: bPoint.x, y: mfy(bPoint.y) }).build());
57843
+ }
57844
+ } else if (a3.route_type === "via" && b3.route_type === "wire") {
57845
+ if (b3.layer === layer) {
57846
+ const glayer = glayers[getGerberLayerName(layer, "copper")];
57847
+ glayer.push(...gerberBuilder().add("select_aperture", {
57848
+ aperture_number: findApertureNumber(glayer, {
57849
+ trace_width: b3.width
57850
+ })
54691
57851
  }).add("move_operation", { x: a3.x, y: mfy(a3.y) }).add("plot_operation", { x: b3.x, y: mfy(b3.y) }).build());
54692
57852
  }
57853
+ } else if (a3.route_type === "through_pad" && b3.route_type === "wire") {
57854
+ if (b3.layer === layer) {
57855
+ const aPoint = a3.end_layer === layer ? a3.end : a3.start_layer === layer ? a3.start : null;
57856
+ if (!aPoint)
57857
+ continue;
57858
+ const glayer = glayers[getGerberLayerName(layer, "copper")];
57859
+ glayer.push(...gerberBuilder().add("select_aperture", {
57860
+ aperture_number: findApertureNumber(glayer, {
57861
+ trace_width: b3.width
57862
+ })
57863
+ }).add("move_operation", { x: aPoint.x, y: mfy(aPoint.y) }).add("plot_operation", { x: b3.x, y: mfy(b3.y) }).build());
57864
+ }
57865
+ }
57866
+ }
57867
+ for (const point9 of route) {
57868
+ if (point9.route_type === "via" && typeof point9.outer_diameter === "number" && (point9.from_layer === layer || point9.to_layer === layer)) {
57869
+ const glayer = glayers[getGerberLayerName(layer, "copper")];
57870
+ glayer.push(...gerberBuilder().add("select_aperture", {
57871
+ aperture_number: findApertureNumber(glayer, getApertureConfigFromOuterDiameter(point9))
57872
+ }).add("flash_operation", { x: point9.x, y: mfy(point9.y) }).build());
54693
57873
  }
54694
57874
  }
54695
- } else if (element.type === "pcb_silkscreen_path") {
57875
+ } else if (element.type === "pcb_silkscreen_path" && isOuterLayerRef(layer)) {
54696
57876
  if (element.layer === layer) {
54697
57877
  const glayer = glayers[getGerberLayerName(layer, "silkscreen")];
54698
57878
  const apertureConfig = getApertureConfigFromPcbSilkscreenPath(element);
@@ -54713,74 +57893,205 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54713
57893
  }
54714
57894
  glayer.push(...gerber.build());
54715
57895
  }
54716
- } else if (element.type === "pcb_silkscreen_text" && layer !== "edgecut") {
57896
+ } else if (isSilkscreenShape(element) && isOuterLayerRef(layer)) {
57897
+ if (element.layer === layer) {
57898
+ const stroke = getSilkscreenShapeStroke(element);
57899
+ if (stroke) {
57900
+ const glayer = glayers[getGerberLayerName(layer, "silkscreen")];
57901
+ const isFilled = element.is_filled === true;
57902
+ const isStroked = element.has_stroke !== false;
57903
+ if (isFilled) {
57904
+ addClosedRegionFromPoints({
57905
+ target: glayer,
57906
+ apertureSource: glayer,
57907
+ points: stroke.route
57908
+ });
57909
+ }
57910
+ if (isStroked) {
57911
+ renderOpenPath({
57912
+ element: {
57913
+ type: element.type,
57914
+ stroke_width: stroke.strokeWidth,
57915
+ is_stroke_dashed: element.is_stroke_dashed
57916
+ },
57917
+ glayer,
57918
+ apertureConfig: {
57919
+ standard_template_code: "C",
57920
+ diameter: stroke.strokeWidth
57921
+ },
57922
+ route: stroke.route,
57923
+ mapY: mfy
57924
+ });
57925
+ }
57926
+ }
57927
+ }
57928
+ } else if (element.type === "pcb_silkscreen_graphic" && isOuterLayerRef(layer)) {
57929
+ const graphic = element;
57930
+ if (graphic.layer === layer && graphic.brep_shape) {
57931
+ const glayer = glayers[getGerberLayerName(layer, "silkscreen")];
57932
+ const { outer_ring, inner_rings } = graphic.brep_shape;
57933
+ const regionApertureNumber = getRegionApertureNumber(glayer);
57934
+ const outerBuilder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
57935
+ drawRingToBuilder(outerBuilder, reverseRing(outer_ring));
57936
+ outerBuilder.add("end_region_statement", {});
57937
+ glayer.push(...outerBuilder.build());
57938
+ if (inner_rings && inner_rings.length > 0) {
57939
+ glayer.push(...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build());
57940
+ for (const inner_ring of inner_rings) {
57941
+ const innerBuilder = gerberBuilder().add("select_aperture", {
57942
+ aperture_number: regionApertureNumber
57943
+ }).add("start_region_statement", {});
57944
+ drawRingToBuilder(innerBuilder, inner_ring);
57945
+ innerBuilder.add("end_region_statement", {});
57946
+ glayer.push(...innerBuilder.build());
57947
+ }
57948
+ glayer.push(...gerberBuilder().add("set_layer_polarity", { polarity: "D" }).build());
57949
+ }
57950
+ }
57951
+ } else if (element.type === "pcb_silkscreen_text" && isOuterLayerRef(layer)) {
54717
57952
  renderVectorText(element, layer, "silkscreen", getApertureConfigFromPcbSilkscreenText);
57953
+ } else if (element.type === "pcb_fabrication_note_path" && isOuterLayerRef(layer)) {
57954
+ if (element.layer === layer) {
57955
+ renderOpenPath({
57956
+ element,
57957
+ glayer: glayers[getGerberLayerName(layer, "fabrication")],
57958
+ apertureConfig: getApertureConfigFromPcbFabricationNotePath(element),
57959
+ route: element.route,
57960
+ mapY: mfy
57961
+ });
57962
+ }
57963
+ } else if (element.type === "pcb_fabrication_note_rect" && isOuterLayerRef(layer)) {
57964
+ if (element.layer === layer) {
57965
+ const glayer = glayers[getGerberLayerName(layer, "fabrication")];
57966
+ const points = getFabRectPoints(element);
57967
+ if (element.is_filled === true) {
57968
+ addClosedRegionFromPoints({
57969
+ target: glayer,
57970
+ apertureSource: glayer,
57971
+ points
57972
+ });
57973
+ }
57974
+ if (element.has_stroke !== false) {
57975
+ renderOpenPath({
57976
+ element,
57977
+ glayer,
57978
+ apertureConfig: getApertureConfigFromPcbFabricationNotePath(element),
57979
+ route: [...points, points[0]],
57980
+ mapY: mfy
57981
+ });
57982
+ }
57983
+ }
57984
+ } else if (element.type === "pcb_fabrication_note_dimension" && isOuterLayerRef(layer)) {
57985
+ if (element.layer === layer) {
57986
+ renderFabricationDimension({
57987
+ element,
57988
+ glayer: glayers[getGerberLayerName(layer, "fabrication")],
57989
+ mapY: mfy,
57990
+ renderText: (textElement) => renderVectorText(textElement, layer, "fabrication", getApertureConfigFromPcbFabricationNoteText)
57991
+ });
57992
+ }
57993
+ } else if (element.type === "pcb_fabrication_note_text" && isOuterLayerRef(layer)) {
57994
+ renderVectorText(element, layer, "fabrication", getApertureConfigFromPcbFabricationNoteText);
54718
57995
  } else if (element.type === "pcb_copper_text" && layer !== "edgecut") {
54719
57996
  renderVectorText(element, layer, "copper", getApertureConfigFromPcbCopperText);
54720
57997
  } else if (element.type === "pcb_smtpad" && element.shape !== "polygon") {
54721
- if (element.layer === layer) {
54722
- for (const glayer of [
54723
- glayers[getGerberLayerName(layer, "copper")],
54724
- glayers[getGerberLayerName(layer, "soldermask")]
57998
+ if (element.layer === layer && isOuterLayerRef(layer)) {
57999
+ if (element.shape === "pill" || element.shape === "rotated_pill") {
58000
+ const soldermaskMargin = typeof element.soldermask_margin === "number" ? element.soldermask_margin : 0;
58001
+ const rotation23 = element.shape === "rotated_pill" && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
58002
+ renderPillFlash({
58003
+ glayer: glayers[getGerberLayerName(layer, "copper")],
58004
+ x: element.x,
58005
+ y: element.y,
58006
+ width: element.width,
58007
+ height: element.height,
58008
+ rotationDegrees: rotation23
58009
+ });
58010
+ renderPillFlash({
58011
+ glayer: glayers[getGerberLayerName(layer, "soldermask")],
58012
+ x: element.x,
58013
+ y: element.y,
58014
+ width: element.width + soldermaskMargin * 2,
58015
+ height: element.height + soldermaskMargin * 2,
58016
+ rotationDegrees: rotation23
58017
+ });
58018
+ continue;
58019
+ }
58020
+ const rotation11 = element.shape === "rotated_rect" && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
58021
+ for (const { glayer, apertureConfig } of [
58022
+ {
58023
+ glayer: glayers[getGerberLayerName(layer, "copper")],
58024
+ apertureConfig: getApertureConfigFromPcbSmtpad(element)
58025
+ },
58026
+ {
58027
+ glayer: glayers[getGerberLayerName(layer, "soldermask")],
58028
+ apertureConfig: getApertureConfigFromPcbSmtpadSoldermask(element)
58029
+ }
54725
58030
  ]) {
54726
- const apertureConfig = getApertureConfigFromPcbSmtpad(element);
54727
58031
  const apertureNumber = findApertureNumber(glayer, apertureConfig);
54728
58032
  const gb3 = gerberBuilder().add("select_aperture", {
54729
58033
  aperture_number: apertureNumber
54730
58034
  });
54731
- if (element.shape === "rotated_rect" && element.ccw_rotation) {
58035
+ if (rotation11) {
54732
58036
  gb3.add("load_rotation", {
54733
- rotation_degrees: element.ccw_rotation
58037
+ rotation_degrees: rotation11
54734
58038
  });
54735
58039
  }
54736
58040
  gb3.add("flash_operation", { x: element.x, y: mfy(element.y) });
54737
- if (element.shape === "rotated_rect" && element.ccw_rotation) {
58041
+ if (rotation11) {
54738
58042
  gb3.add("load_rotation", { rotation_degrees: 0 });
54739
58043
  }
54740
58044
  glayer.push(...gb3.build());
54741
58045
  }
54742
58046
  }
54743
58047
  } else if (element.type === "pcb_smtpad" && element.shape === "polygon") {
54744
- if (element.layer === layer) {
58048
+ if (element.layer === layer && isOuterLayerRef(layer)) {
54745
58049
  const layers_to_add_to = [
54746
58050
  glayers[getGerberLayerName(layer, "copper")]
54747
58051
  ];
54748
- if (!("is_covered_with_solder_mask" in element) || element.is_covered_with_solder_mask !== false) {
58052
+ if (element.is_covered_with_solder_mask !== true) {
54749
58053
  layers_to_add_to.push(glayers[getGerberLayerName(layer, "soldermask")]);
54750
58054
  }
54751
58055
  for (const glayer of layers_to_add_to) {
54752
- const pad_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
54753
58056
  const { points } = element;
54754
- if (points && points.length > 0) {
54755
- pad_builder.add("move_operation", {
54756
- x: points[0].x,
54757
- y: mfy(points[0].y)
54758
- });
54759
- for (let i3 = 1;i3 < points.length; i3++) {
54760
- pad_builder.add("plot_operation", {
54761
- x: points[i3].x,
54762
- y: mfy(points[i3].y)
54763
- });
54764
- }
54765
- pad_builder.add("plot_operation", {
54766
- x: points[0].x,
54767
- y: mfy(points[0].y)
54768
- });
54769
- }
54770
- pad_builder.add("end_region_statement", {});
54771
- glayer.push(...pad_builder.build());
58057
+ if (!points)
58058
+ continue;
58059
+ addClosedRegionFromPoints({
58060
+ target: glayer,
58061
+ apertureSource: glayer,
58062
+ points
58063
+ });
54772
58064
  }
54773
58065
  }
54774
58066
  } else if (element.type === "pcb_solder_paste") {
54775
- if (element.layer === layer) {
58067
+ if (element.layer === layer && isOuterLayerRef(layer)) {
54776
58068
  const glayer = glayers[getGerberLayerName(layer, "paste")];
54777
- const aperture_number = findApertureNumber(glayer, getApertureConfigFromPcbSolderPaste(element));
54778
- const rotation11 = "ccw_rotation" in element && typeof element.ccw_rotation === "number" ? element.ccw_rotation : rotationLookup.get(`${element.x}:${element.y}`) ?? 0;
58069
+ let rotation11 = 0;
58070
+ if ("ccw_rotation" in element && typeof element.ccw_rotation === "number") {
58071
+ rotation11 = element.ccw_rotation;
58072
+ } else {
58073
+ const platedHole = circuitJson.find((candidate) => candidate.type === "pcb_plated_hole" && candidate.x === element.x && candidate.y === element.y && ("ccw_rotation" in candidate) && typeof candidate.ccw_rotation === "number");
58074
+ if (platedHole) {
58075
+ rotation11 = platedHole.ccw_rotation;
58076
+ }
58077
+ }
58078
+ let apertureConfig = getApertureConfigFromPcbSolderPaste(element);
58079
+ if (element.shape === "pill" && (rotation11 === 90 || rotation11 === 270)) {
58080
+ apertureConfig = getApertureConfigFromPcbSolderPaste({
58081
+ ...element,
58082
+ width: element.height,
58083
+ height: element.width
58084
+ });
58085
+ rotation11 = 0;
58086
+ }
58087
+ const aperture_number = findApertureNumber(glayer, apertureConfig);
54779
58088
  const gb3 = gerberBuilder().add("select_aperture", {
54780
58089
  aperture_number
54781
58090
  });
54782
58091
  if (rotation11) {
54783
- gb3.add("load_rotation", { rotation_degrees: rotation11 });
58092
+ gb3.add("load_rotation", {
58093
+ rotation_degrees: rotation11
58094
+ });
54784
58095
  }
54785
58096
  gb3.add("flash_operation", { x: element.x, y: mfy(element.y) });
54786
58097
  if (rotation11) {
@@ -54790,10 +58101,33 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54790
58101
  }
54791
58102
  } else if (element.type === "pcb_plated_hole") {
54792
58103
  if (element.layers.includes(layer)) {
54793
- for (const glayer of [
54794
- glayers[getGerberLayerName(layer, "copper")],
54795
- glayers[getGerberLayerName(layer, "soldermask")]
54796
- ]) {
58104
+ const layersToAddTo = [
58105
+ glayers[getGerberLayerName(layer, "copper")]
58106
+ ];
58107
+ if (isOuterLayerRef(layer) && element.is_covered_with_solder_mask !== true) {
58108
+ layersToAddTo.push(glayers[getGerberLayerName(layer, "soldermask")]);
58109
+ }
58110
+ for (const glayer of layersToAddTo) {
58111
+ if (element.shape === "hole_with_polygon_pad") {
58112
+ const { pad_outline } = element;
58113
+ if (!pad_outline?.length)
58114
+ continue;
58115
+ const soldermaskGlayer2 = glayers[getGerberLayerName(layer, "soldermask")];
58116
+ let points = pad_outline;
58117
+ if (glayer === soldermaskGlayer2 && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58118
+ points = offsetPolygonOutline(pad_outline, element.soldermask_margin);
58119
+ }
58120
+ const translatedPoints = points.map((point9) => ({
58121
+ x: point9.x + element.x,
58122
+ y: point9.y + element.y
58123
+ }));
58124
+ addClosedRegionFromPoints({
58125
+ target: glayer,
58126
+ apertureSource: glayer,
58127
+ points: translatedPoints
58128
+ });
58129
+ continue;
58130
+ }
54797
58131
  const holeW = "hole_width" in element && typeof element.hole_width === "number" ? element.hole_width : 0;
54798
58132
  const holeH = "hole_height" in element && typeof element.hole_height === "number" ? element.hole_height : 0;
54799
58133
  const padWidthCandidates = [holeW];
@@ -54812,10 +58146,17 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54812
58146
  padHeightCandidates.push(element.rect_pad_height);
54813
58147
  }
54814
58148
  const padH = Math.max(...padHeightCandidates);
58149
+ const soldermaskGlayer = glayers[getGerberLayerName(layer, "soldermask")];
58150
+ let soldermaskMargin = 0;
58151
+ if (glayer === soldermaskGlayer && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58152
+ soldermaskMargin = element.soldermask_margin;
58153
+ }
58154
+ const aperturePadW = padW + soldermaskMargin * 2;
58155
+ const aperturePadH = padH + soldermaskMargin * 2;
54815
58156
  if (element.shape === "pill") {
54816
58157
  const circleApertureConfig = {
54817
58158
  standard_template_code: "C",
54818
- diameter: Math.min(padW, padH)
58159
+ diameter: Math.min(aperturePadW, aperturePadH)
54819
58160
  };
54820
58161
  let aperture_number;
54821
58162
  try {
@@ -54841,8 +58182,8 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54841
58182
  y: element.y + rotatedY
54842
58183
  };
54843
58184
  };
54844
- const isHorizontal2 = padW >= padH;
54845
- const offset = isHorizontal2 ? (padW - padH) / 2 : (padH - padW) / 2;
58185
+ const isHorizontal2 = aperturePadW >= aperturePadH;
58186
+ const offset = isHorizontal2 ? (aperturePadW - aperturePadH) / 2 : (aperturePadH - aperturePadW) / 2;
54846
58187
  if (offset <= 0) {
54847
58188
  const center2 = rotateAndTranslate(0, 0);
54848
58189
  gb3.add("flash_operation", { x: center2.x, y: mfy(center2.y) });
@@ -54867,10 +58208,16 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54867
58208
  }
54868
58209
  glayer.push(...gb3.build());
54869
58210
  } else {
54870
- const apertureConfig = getApertureConfigFromPcbPlatedHole({
58211
+ let apertureConfig = getApertureConfigFromPcbPlatedHole({
54871
58212
  ...element,
54872
58213
  ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
54873
58214
  });
58215
+ if (glayer === soldermaskGlayer) {
58216
+ apertureConfig = getApertureConfigFromPcbPlatedHoleSoldermask({
58217
+ ...element,
58218
+ ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
58219
+ });
58220
+ }
54874
58221
  const rotation11 = "rect_ccw_rotation" in element && typeof element.rect_ccw_rotation === "number" && Math.abs(padW - padH) > 0.000000001 ? element.rect_ccw_rotation : undefined;
54875
58222
  const gb3 = gerberBuilder().add("select_aperture", {
54876
58223
  aperture_number: findApertureNumber(glayer, apertureConfig)
@@ -54885,7 +58232,7 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54885
58232
  }
54886
58233
  }
54887
58234
  } else if (element.type === "pcb_hole") {
54888
- if (layer !== "edgecut") {
58235
+ if (isOuterLayerRef(layer) && element.is_covered_with_solder_mask !== true) {
54889
58236
  for (const glayer of [
54890
58237
  glayers[getGerberLayerName(layer, "soldermask")]
54891
58238
  ]) {
@@ -54894,15 +58241,21 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54894
58241
  continue;
54895
58242
  }
54896
58243
  glayer.push(...gerberBuilder().add("select_aperture", {
54897
- aperture_number: findApertureNumber(glayer, getApertureConfigFromCirclePcbHole(element))
58244
+ aperture_number: findApertureNumber(glayer, getApertureConfigFromCirclePcbHoleSoldermask(element))
54898
58245
  }).add("flash_operation", { x: element.x, y: mfy(element.y) }).build());
54899
58246
  }
54900
58247
  }
54901
58248
  } else if (element.type === "pcb_via") {
54902
58249
  if (element.layers.includes(layer)) {
54903
- for (const glayer of [glayers[getGerberLayerName(layer, "copper")]]) {
58250
+ const layersToAddTo = [
58251
+ glayers[getGerberLayerName(layer, "copper")]
58252
+ ];
58253
+ if (element.is_tented === false && isOuterLayerRef(layer)) {
58254
+ layersToAddTo.push(glayers[getGerberLayerName(layer, "soldermask")]);
58255
+ }
58256
+ for (const glayer of layersToAddTo) {
54904
58257
  glayer.push(...gerberBuilder().add("select_aperture", {
54905
- aperture_number: findApertureNumber(glayer, getApertureConfigFromPcbVia(element))
58258
+ aperture_number: findApertureNumber(glayer, getApertureConfigFromOuterDiameter(element))
54906
58259
  }).add("flash_operation", { x: element.x, y: mfy(element.y) }).build());
54907
58260
  }
54908
58261
  }
@@ -54915,36 +58268,36 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54915
58268
  aperture_number: 10
54916
58269
  });
54917
58270
  if (outline && outline.length > 2) {
54918
- const outlinePoints = outline.map((point9) => ({
54919
- x: point9.x,
54920
- y: mfy(point9.y)
54921
- }));
54922
- const firstPoint = outlinePoints[0];
54923
- gerberBuild.add("move_operation", firstPoint);
54924
- for (let i3 = 1;i3 < outlinePoints.length; i3++) {
54925
- gerberBuild.add("plot_operation", outlinePoints[i3]);
58271
+ const boardPolygon = [
58272
+ outline.map((point9) => [point9.x, point9.y])
58273
+ ];
58274
+ let boardGeometry = [boardPolygon];
58275
+ if (solidCutoutPolygons.length > 0) {
58276
+ boardGeometry = import_polygon_clipping2.default.difference(boardPolygon, ...solidCutoutPolygons);
54926
58277
  }
54927
- const lastPoint = outlinePoints[outlinePoints.length - 1];
54928
- if (lastPoint.x !== firstPoint.x || lastPoint.y !== firstPoint.y) {
54929
- gerberBuild.add("plot_operation", firstPoint);
58278
+ for (const polygon2 of boardGeometry) {
58279
+ for (const ring of polygon2) {
58280
+ emitEdgeCutRing(gerberBuild, ring, mfy);
58281
+ }
54930
58282
  }
54931
58283
  } else {
54932
- gerberBuild.add("move_operation", {
54933
- x: center2.x - width / 2,
54934
- y: mfy(center2.y - height / 2)
54935
- }).add("plot_operation", {
54936
- x: center2.x + width / 2,
54937
- y: mfy(center2.y - height / 2)
54938
- }).add("plot_operation", {
54939
- x: center2.x + width / 2,
54940
- y: mfy(center2.y + height / 2)
54941
- }).add("plot_operation", {
54942
- x: center2.x - width / 2,
54943
- y: mfy(center2.y + height / 2)
54944
- }).add("plot_operation", {
54945
- x: center2.x - width / 2,
54946
- y: mfy(center2.y - height / 2)
54947
- });
58284
+ const boardPolygon = [
58285
+ [
58286
+ [center2.x - width / 2, center2.y - height / 2],
58287
+ [center2.x + width / 2, center2.y - height / 2],
58288
+ [center2.x + width / 2, center2.y + height / 2],
58289
+ [center2.x - width / 2, center2.y + height / 2]
58290
+ ]
58291
+ ];
58292
+ let boardGeometry = [boardPolygon];
58293
+ if (solidCutoutPolygons.length > 0) {
58294
+ boardGeometry = import_polygon_clipping2.default.difference(boardPolygon, ...solidCutoutPolygons);
58295
+ }
58296
+ for (const polygon2 of boardGeometry) {
58297
+ for (const ring of polygon2) {
58298
+ emitEdgeCutRing(gerberBuild, ring, mfy);
58299
+ }
58300
+ }
54948
58301
  }
54949
58302
  glayer.push(...gerberBuild.build());
54950
58303
  } else if (element.type === "pcb_panel" && layer === "edgecut") {
@@ -54972,131 +58325,26 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
54972
58325
  glayer.push(...gerberBuild.build());
54973
58326
  } else if (element.type === "pcb_cutout") {
54974
58327
  if (layer === "edgecut") {
58328
+ if (hasBoard && !hasPanel && doesSolidCutoutOverlapBoardEdge({
58329
+ cutout: element,
58330
+ boardOutlinePolygons
58331
+ })) {
58332
+ continue;
58333
+ }
54975
58334
  const ec_layer = glayers.Edge_Cuts;
54976
58335
  const cutout_builder = gerberBuilder().add("select_aperture", {
54977
58336
  aperture_number: 10
54978
58337
  });
54979
- const el3 = element;
54980
- if (el3.shape === "rect") {
54981
- const { center: center2, width, height, rotation: rotation11, corner_radius } = el3;
54982
- const w4 = width / 2;
54983
- const h4 = height / 2;
54984
- const r4 = Math.max(0, Math.min(corner_radius ?? 0, Math.abs(w4), Math.abs(h4)));
54985
- const makeTransformMatrix = () => {
54986
- let transformMatrix2 = identity8();
54987
- if (rotation11) {
54988
- const angle_rad = rotation11 * Math.PI / 180;
54989
- transformMatrix2 = rotate12(angle_rad);
54990
- }
54991
- return compose9(translate9(center2.x, center2.y), transformMatrix2);
54992
- };
54993
- const transformMatrix = makeTransformMatrix();
54994
- if (r4 > 0) {
54995
- const startPoint = { x: -w4 + r4, y: h4 };
54996
- let currentPoint = applyToPoint26(transformMatrix, startPoint);
54997
- cutout_builder.add("move_operation", {
54998
- x: currentPoint.x,
54999
- y: mfy(currentPoint.y)
55000
- });
55001
- const addLine = (point9) => {
55002
- const transformedPoint = applyToPoint26(transformMatrix, point9);
55003
- cutout_builder.add("plot_operation", {
55004
- x: transformedPoint.x,
55005
- y: mfy(transformedPoint.y)
55006
- });
55007
- currentPoint = transformedPoint;
55008
- };
55009
- const addArc = (options) => {
55010
- const transformedPoint = applyToPoint26(transformMatrix, options.point);
55011
- const transformedCenter = applyToPoint26(transformMatrix, options.center);
55012
- cutout_builder.add("set_movement_mode_to_clockwise_circular", {}).add("plot_operation", {
55013
- x: transformedPoint.x,
55014
- y: mfy(transformedPoint.y),
55015
- i: transformedCenter.x - currentPoint.x,
55016
- j: mfy(transformedCenter.y) - mfy(currentPoint.y)
55017
- }).add("set_movement_mode_to_linear", {});
55018
- currentPoint = transformedPoint;
55019
- };
55020
- addLine({ x: w4 - r4, y: h4 });
55021
- addArc({
55022
- point: { x: w4, y: h4 - r4 },
55023
- center: { x: w4 - r4, y: h4 - r4 }
55024
- });
55025
- addLine({ x: w4, y: -h4 + r4 });
55026
- addArc({
55027
- point: { x: w4 - r4, y: -h4 },
55028
- center: { x: w4 - r4, y: -h4 + r4 }
55029
- });
55030
- addLine({ x: -w4 + r4, y: -h4 });
55031
- addArc({
55032
- point: { x: -w4, y: -h4 + r4 },
55033
- center: { x: -w4 + r4, y: -h4 + r4 }
55034
- });
55035
- addLine({ x: -w4, y: h4 - r4 });
55036
- addArc({
55037
- point: { x: -w4 + r4, y: h4 },
55038
- center: { x: -w4 + r4, y: h4 - r4 }
55039
- });
55040
- } else {
55041
- const points = [
55042
- { x: -w4, y: h4 },
55043
- { x: w4, y: h4 },
55044
- { x: w4, y: -h4 },
55045
- { x: -w4, y: -h4 }
55046
- ];
55047
- const transformedPoints = points.map((p3) => applyToPoint26(transformMatrix, p3));
55048
- cutout_builder.add("move_operation", {
55049
- x: transformedPoints[0].x,
55050
- y: mfy(transformedPoints[0].y)
55051
- });
55052
- for (let i3 = 1;i3 < transformedPoints.length; i3++) {
55053
- cutout_builder.add("plot_operation", {
55054
- x: transformedPoints[i3].x,
55055
- y: mfy(transformedPoints[i3].y)
55056
- });
55057
- }
55058
- cutout_builder.add("plot_operation", {
55059
- x: transformedPoints[0].x,
55060
- y: mfy(transformedPoints[0].y)
55061
- });
55062
- }
55063
- } else if (el3.shape === "circle") {
55064
- const { center: center2, radius } = el3;
55065
- const p12 = { x: center2.x + radius, y: center2.y };
55066
- const p23 = { x: center2.x - radius, y: center2.y };
55067
- cutout_builder.add("move_operation", {
55068
- x: p12.x,
55069
- y: mfy(p12.y)
55070
- }).add("set_movement_mode_to_counterclockwise_circular", {}).add("plot_operation", {
55071
- x: p23.x,
55072
- y: mfy(p23.y),
55073
- i: -radius,
55074
- j: 0
55075
- }).add("plot_operation", {
55076
- x: p12.x,
55077
- y: mfy(p12.y),
55078
- i: radius,
55079
- j: 0
55080
- }).add("set_movement_mode_to_linear", {});
55081
- } else if (el3.shape === "polygon") {
55082
- const { points } = el3;
55083
- if (points.length > 0) {
55084
- cutout_builder.add("move_operation", {
55085
- x: points[0].x,
55086
- y: mfy(points[0].y)
55087
- });
55088
- for (let i3 = 1;i3 < points.length; i3++) {
55089
- cutout_builder.add("plot_operation", {
55090
- x: points[i3].x,
55091
- y: mfy(points[i3].y)
55092
- });
55093
- }
55094
- cutout_builder.add("plot_operation", {
55095
- x: points[0].x,
55096
- y: mfy(points[0].y)
55097
- });
55098
- }
55099
- }
58338
+ const drawCw = hasBoard && !hasPanel && isCutoutFullyInternal({
58339
+ cutout: element,
58340
+ boardOutlinePolygons
58341
+ });
58342
+ emitCutoutEdgeCuts({
58343
+ cutout: element,
58344
+ builder: cutout_builder,
58345
+ mfy,
58346
+ drawCw
58347
+ });
55100
58348
  ec_layer.push(...cutout_builder.build());
55101
58349
  }
55102
58350
  }
@@ -55107,8 +58355,11 @@ var import_fast_json_stable_stringify, defineExcellonDrillCommand = ({
55107
58355
  }
55108
58356
  return glayers;
55109
58357
  };
55110
- var init_chunk_FNNZTRYF = __esm(() => {
58358
+ var init_chunk_46NSLLUV = __esm(() => {
58359
+ import_polygon_clipping = __toESM2(require_polygon_clipping_cjs(), 1);
55111
58360
  import_fast_json_stable_stringify = __toESM2(require_fast_json_stable_stringify(), 1);
58361
+ import_polygon_clipping2 = __toESM2(require_polygon_clipping_cjs(), 1);
58362
+ import_polygon_clipping3 = __toESM2(require_polygon_clipping_cjs(), 1);
55112
58363
  FMAT = defineExcellonDrillCommand({
55113
58364
  command_code: "FMAT",
55114
58365
  schema: z4.object({
@@ -55636,7 +58887,17 @@ ${template_code}%`;
55636
58887
  if (macro_name === "HORZPILL" || macro_name === "VERTPILL") {
55637
58888
  commandString += `${props.x_size.toFixed(6)}X${props.y_size.toFixed(6)}X${props.circle_diameter.toFixed(6)}X${props.circle_center_offset.toFixed(6)}`;
55638
58889
  } else if (macro_name === "ROUNDRECT") {
55639
- throw new Error("ROUNDRECT macro not implemented yet");
58890
+ commandString += [
58891
+ props.corner_radius,
58892
+ props.corner_1_x,
58893
+ props.corner_1_y,
58894
+ props.corner_2_x,
58895
+ props.corner_2_y,
58896
+ props.corner_3_x,
58897
+ props.corner_3_y,
58898
+ props.corner_4_x,
58899
+ props.corner_4_y
58900
+ ].map((value) => value.toFixed(6)).join("X");
55640
58901
  }
55641
58902
  commandString += "*%";
55642
58903
  return commandString;
@@ -55696,9 +58957,20 @@ ${template_code}%`;
55696
58957
  set_layer_polarity,
55697
58958
  start_region_statement
55698
58959
  };
58960
+ SILKSCREEN_SHAPE_TYPES = [
58961
+ "pcb_silkscreen_line",
58962
+ "pcb_silkscreen_rect",
58963
+ "pcb_silkscreen_circle",
58964
+ "pcb_silkscreen_oval",
58965
+ "pcb_silkscreen_pill"
58966
+ ];
58967
+ REGION_APERTURE_CONFIG = {
58968
+ standard_template_code: "C",
58969
+ diameter: 0.001
58970
+ };
55699
58971
  package_default5 = {
55700
58972
  name: "circuit-json-to-gerber",
55701
- version: "0.0.50",
58973
+ version: "0.0.82",
55702
58974
  main: "dist/index.js",
55703
58975
  type: "module",
55704
58976
  scripts: {
@@ -55723,15 +58995,16 @@ ${template_code}%`;
55723
58995
  "@types/react-dom": "^19.1.5",
55724
58996
  archiver: "^7.0.1",
55725
58997
  "bun-match-svg": "^0.0.13",
55726
- "circuit-json": "^0.0.421",
58998
+ "circuit-json": "^0.0.426",
55727
58999
  commander: "^12.1.0",
55728
59000
  "gerber-to-svg": "^4.2.8",
55729
59001
  gerberts: "^0.0.3",
55730
59002
  jszip: "^3.10.1",
55731
59003
  "pcb-stackup": "^4.2.8",
59004
+ "polygon-clipping": "^0.15.7",
55732
59005
  react: "^19.2.1",
55733
59006
  "react-dom": "^19.2.1",
55734
- tscircuit: "^0.0.1705",
59007
+ tscircuit: "^0.0.1776",
55735
59008
  tsup: "^8.2.4"
55736
59009
  },
55737
59010
  peerDependencies: {
@@ -55747,31 +59020,40 @@ ${template_code}%`;
55747
59020
  };
55748
59021
  layerAndTypeToFileFunction = {
55749
59022
  "top-copper": "Copper,L1,Top",
55750
- "bottom-copper": "Copper,L2,Bot",
55751
59023
  "top-soldermask": "Soldermask,Top",
55752
59024
  "bottom-soldermask": "Soldermask,Bot",
55753
59025
  "top-silkscreen": "Legend,Top",
55754
59026
  "bottom-silkscreen": "Legend,Bot",
59027
+ "top-fabrication": "Other,Fab,Top",
59028
+ "bottom-fabrication": "Other,Fab,Bot",
55755
59029
  "top-paste": "Paste,Top",
55756
59030
  "bottom-paste": "Paste,Bot",
55757
59031
  edgecut: "Profile,NP"
55758
59032
  };
55759
59033
  layerRefToGerberPrefix = {
55760
59034
  top: "F_",
55761
- bottom: "B_"
59035
+ bottom: "B_",
59036
+ inner1: "In1_",
59037
+ inner2: "In2_",
59038
+ inner3: "In3_",
59039
+ inner4: "In4_",
59040
+ inner5: "In5_",
59041
+ inner6: "In6_"
55762
59042
  };
55763
59043
  layerTypeToGerberSuffix = {
55764
59044
  copper: "Cu",
55765
59045
  silkscreen: "SilkScreen",
59046
+ fabrication: "Fab",
55766
59047
  soldermask: "Mask",
55767
59048
  mask: "Mask",
55768
59049
  paste: "Paste"
55769
59050
  };
59051
+ outerLayerRefs = ["top", "bottom"];
55770
59052
  });
55771
59053
 
55772
59054
  // node_modules/circuit-json-to-gerber/dist/index.js
55773
59055
  var init_dist = __esm(() => {
55774
- init_chunk_FNNZTRYF();
59056
+ init_chunk_46NSLLUV();
55775
59057
  });
55776
59058
 
55777
59059
  // node_modules/@tracespace/xml-id/index.js
@@ -68645,11 +71927,11 @@ var init_lib = __esm(() => {
68645
71927
  });
68646
71928
 
68647
71929
  // node_modules/circuit-to-canvas/dist/index.js
68648
- import { compose as compose32, identity as identity9, scale as scale7, translate as translate32 } from "transformation-matrix";
71930
+ import { compose as compose33, identity as identity9, scale as scale7, translate as translate33 } from "transformation-matrix";
68649
71931
  import { applyToPoint as applyToPoint27 } from "transformation-matrix";
68650
- import { applyToPoint as applyToPoint25 } from "transformation-matrix";
68651
- import { applyToPoint as applyToPoint42 } from "transformation-matrix";
68652
- import { applyToPoint as applyToPoint32 } from "transformation-matrix";
71932
+ import { applyToPoint as applyToPoint28 } from "transformation-matrix";
71933
+ import { applyToPoint as applyToPoint43 } from "transformation-matrix";
71934
+ import { applyToPoint as applyToPoint33 } from "transformation-matrix";
68653
71935
  import { glyphLineAlphabet } from "@tscircuit/alphabet";
68654
71936
  import { applyToPoint as applyToPoint52 } from "transformation-matrix";
68655
71937
  import {
@@ -68666,7 +71948,7 @@ import { applyToPoint as applyToPoint102 } from "transformation-matrix";
68666
71948
  import { applyToPoint as applyToPoint112 } from "transformation-matrix";
68667
71949
  import { applyToPoint as applyToPoint152 } from "transformation-matrix";
68668
71950
  import { applyToPoint as applyToPoint122, compose as compose10, rotate as rotate13, translate as translate10 } from "transformation-matrix";
68669
- import { applyToPoint as applyToPoint132, compose as compose22, rotate as rotate22, translate as translate22 } from "transformation-matrix";
71951
+ import { applyToPoint as applyToPoint132, compose as compose23, rotate as rotate23, translate as translate23 } from "transformation-matrix";
68670
71952
  import { applyToPoint as applyToPoint142 } from "transformation-matrix";
68671
71953
  import { applyToPoint as applyToPoint162 } from "transformation-matrix";
68672
71954
  import { applyToPoint as applyToPoint172 } from "transformation-matrix";
@@ -68738,7 +72020,7 @@ function drawRect(params2) {
68738
72020
  isStrokeDashed = false,
68739
72021
  lineJoin
68740
72022
  } = params2;
68741
- const [cx3, cy3] = applyToPoint25(realToCanvasMat, [center2.x, center2.y]);
72023
+ const [cx3, cy3] = applyToPoint28(realToCanvasMat, [center2.x, center2.y]);
68742
72024
  const scaledWidth = width * Math.abs(realToCanvasMat.a);
68743
72025
  const scaledHeight = height * Math.abs(realToCanvasMat.a);
68744
72026
  const scaledRadius = borderRadius * Math.abs(realToCanvasMat.a);
@@ -68850,7 +72132,7 @@ function drawPolygon(params2) {
68850
72132
  if (points.length < 3)
68851
72133
  return;
68852
72134
  ctx.beginPath();
68853
- const canvasPoints = points.map((p3) => applyToPoint32(realToCanvasMat, [p3.x, p3.y]));
72135
+ const canvasPoints = points.map((p3) => applyToPoint33(realToCanvasMat, [p3.x, p3.y]));
68854
72136
  const firstPoint = canvasPoints[0];
68855
72137
  if (!firstPoint)
68856
72138
  return;
@@ -68895,25 +72177,25 @@ function computeArcFromBulge(startX, startY, endX, endY, bulge) {
68895
72177
  }
68896
72178
  function drawArcFromBulge(ctx, realStartX, realStartY, realEndX, realEndY, bulge, realToCanvasMat) {
68897
72179
  if (Math.abs(bulge) < 0.0000000001) {
68898
- const [endX, endY] = applyToPoint42(realToCanvasMat, [realEndX, realEndY]);
72180
+ const [endX, endY] = applyToPoint43(realToCanvasMat, [realEndX, realEndY]);
68899
72181
  ctx.lineTo(endX, endY);
68900
72182
  return;
68901
72183
  }
68902
72184
  const arc2 = computeArcFromBulge(realStartX, realStartY, realEndX, realEndY, bulge);
68903
72185
  if (!arc2) {
68904
- const [endX, endY] = applyToPoint42(realToCanvasMat, [realEndX, realEndY]);
72186
+ const [endX, endY] = applyToPoint43(realToCanvasMat, [realEndX, realEndY]);
68905
72187
  ctx.lineTo(endX, endY);
68906
72188
  return;
68907
72189
  }
68908
- const [canvasStartX, canvasStartY] = applyToPoint42(realToCanvasMat, [
72190
+ const [canvasStartX, canvasStartY] = applyToPoint43(realToCanvasMat, [
68909
72191
  realStartX,
68910
72192
  realStartY
68911
72193
  ]);
68912
- const [canvasEndX, canvasEndY] = applyToPoint42(realToCanvasMat, [
72194
+ const [canvasEndX, canvasEndY] = applyToPoint43(realToCanvasMat, [
68913
72195
  realEndX,
68914
72196
  realEndY
68915
72197
  ]);
68916
- const [canvasCenterX, canvasCenterY] = applyToPoint42(realToCanvasMat, [
72198
+ const [canvasCenterX, canvasCenterY] = applyToPoint43(realToCanvasMat, [
68917
72199
  arc2.centerX,
68918
72200
  arc2.centerY
68919
72201
  ]);
@@ -68932,7 +72214,7 @@ function drawRing(ctx, ring, realToCanvasMat) {
68932
72214
  const v02 = ring.vertices[0];
68933
72215
  const v12 = ring.vertices[1];
68934
72216
  if (v02 && v12 && Math.abs((v02.bulge ?? 0) - 1) < 0.0000000001 && Math.abs((v12.bulge ?? 0) - 1) < 0.0000000001) {
68935
- const [x02, y02] = applyToPoint42(realToCanvasMat, [v02.x, v02.y]);
72217
+ const [x02, y02] = applyToPoint43(realToCanvasMat, [v02.x, v02.y]);
68936
72218
  ctx.moveTo(x02, y02);
68937
72219
  drawArcFromBulge(ctx, v02.x, v02.y, v12.x, v12.y, 1, realToCanvasMat);
68938
72220
  drawArcFromBulge(ctx, v12.x, v12.y, v02.x, v02.y, 1, realToCanvasMat);
@@ -68942,7 +72224,7 @@ function drawRing(ctx, ring, realToCanvasMat) {
68942
72224
  const firstVertex = ring.vertices[0];
68943
72225
  if (!firstVertex)
68944
72226
  return;
68945
- const [firstX, firstY] = applyToPoint42(realToCanvasMat, [
72227
+ const [firstX, firstY] = applyToPoint43(realToCanvasMat, [
68946
72228
  firstVertex.x,
68947
72229
  firstVertex.y
68948
72230
  ]);
@@ -68955,7 +72237,7 @@ function drawRing(ctx, ring, realToCanvasMat) {
68955
72237
  continue;
68956
72238
  const bulge = currentVertex.bulge ?? 0;
68957
72239
  if (Math.abs(bulge) < 0.0000000001) {
68958
- const [nextX, nextY] = applyToPoint42(realToCanvasMat, [
72240
+ const [nextX, nextY] = applyToPoint43(realToCanvasMat, [
68959
72241
  nextVertex.x,
68960
72242
  nextVertex.y
68961
72243
  ]);
@@ -68972,7 +72254,7 @@ function drawPcbCopperPour(params2) {
68972
72254
  ctx.save();
68973
72255
  ctx.globalAlpha = opacity;
68974
72256
  if (pour.shape === "rect") {
68975
- const [cx3, cy3] = applyToPoint42(realToCanvasMat, [
72257
+ const [cx3, cy3] = applyToPoint43(realToCanvasMat, [
68976
72258
  pour.center.x,
68977
72259
  pour.center.y
68978
72260
  ]);
@@ -68991,7 +72273,7 @@ function drawPcbCopperPour(params2) {
68991
72273
  }
68992
72274
  if (pour.shape === "polygon") {
68993
72275
  if (pour.points && pour.points.length >= 3) {
68994
- const canvasPoints = pour.points.map((p3) => applyToPoint42(realToCanvasMat, [p3.x, p3.y]));
72276
+ const canvasPoints = pour.points.map((p3) => applyToPoint43(realToCanvasMat, [p3.x, p3.y]));
68995
72277
  const firstPoint = canvasPoints[0];
68996
72278
  if (!firstPoint) {
68997
72279
  ctx.restore();
@@ -70016,7 +73298,7 @@ function drawRoundedRectPath(params2) {
70016
73298
  ccwRotationDegrees = 0
70017
73299
  } = params2;
70018
73300
  const ccwRotationRadians = ccwRotationDegrees * Math.PI / 180;
70019
- const realToPxTransform = compose22(translate22(centerX, centerY), rotate22(-ccwRotationRadians));
73301
+ const realToPxTransform = compose23(translate23(centerX, centerY), rotate23(-ccwRotationRadians));
70020
73302
  const rectHalfWidth = width / 2;
70021
73303
  const rectHalfHeight = height / 2;
70022
73304
  const rectCornerRadius = Math.min(radius, rectHalfWidth, rectHalfHeight);
@@ -73371,7 +76653,7 @@ var getAdvanceRatio = (char) => glyphAdvanceRatio[char] ?? (char === " " ? textM
73371
76653
  const uniformScale = Math.min(scaleX, scaleY);
73372
76654
  const offsetX = (canvasWidth - realWidth * uniformScale) / 2;
73373
76655
  const offsetY = (canvasHeight - realHeight * uniformScale) / 2;
73374
- this.realToCanvasMat = compose32(translate32(offsetX, offsetY), scale7(uniformScale, -uniformScale), translate32(-bounds.minX, -bounds.maxY));
76656
+ this.realToCanvasMat = compose33(translate33(offsetX, offsetY), scale7(uniformScale, -uniformScale), translate33(-bounds.minX, -bounds.maxY));
73375
76657
  }
73376
76658
  drawElements(elements, options = {}) {
73377
76659
  const layer = getCopperLayer(options.layers);
@@ -73830,7 +77112,7 @@ import {
73830
77112
  isPointInsidePolygon as isPointInsidePolygon2,
73831
77113
  pointToSegmentDistance as pointToSegmentDistance3
73832
77114
  } from "@tscircuit/math-utils";
73833
- import { applyToPoint as applyToPoint28, identity as identity10 } from "transformation-matrix";
77115
+ import { applyToPoint as applyToPoint29, identity as identity10 } from "transformation-matrix";
73834
77116
  import { convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg22 } from "circuit-to-svg";
73835
77117
  import { deflateSync } from "node:zlib";
73836
77118
 
@@ -74450,7 +77732,7 @@ var import_gerber_to_svg, renderTscircuitRepro = async (tsx, options = {}) => {
74450
77732
  const svg = await renderGerberToSvg(gerber);
74451
77733
  const boardSvg = forceSvgViewport({ svg, bounds, width, height });
74452
77734
  return getMaskFromPng(renderSvgToPng(boardSvg));
74453
- }, transformPoint = (matrix2, point9) => applyToPoint28(matrix2, point9), getBounds2 = (parts) => {
77735
+ }, transformPoint = (matrix2, point9) => applyToPoint29(matrix2, point9), getBounds2 = (parts) => {
74454
77736
  let minX = Number.POSITIVE_INFINITY;
74455
77737
  let minY = Number.POSITIVE_INFINITY;
74456
77738
  let maxX = Number.NEGATIVE_INFINITY;
@@ -115063,7 +118345,7 @@ var import_perfect_cli = __toESM2(require_dist2(), 1);
115063
118345
  // lib/getVersion.ts
115064
118346
  import { createRequire as createRequire2 } from "node:module";
115065
118347
  // package.json
115066
- var version = "0.1.1642";
118348
+ var version = "0.1.1643";
115067
118349
  var package_default = {
115068
118350
  name: "@tscircuit/cli",
115069
118351
  version,
@@ -115103,7 +118385,7 @@ var package_default = {
115103
118385
  "circuit-json-to-3d-png": "^0.0.6",
115104
118386
  "circuit-json-to-bom-csv": "^0.0.7",
115105
118387
  "circuit-json-to-connectivity-map": "^0.0.25",
115106
- "circuit-json-to-gerber": "^0.0.51",
118388
+ "circuit-json-to-gerber": "^0.0.83",
115107
118389
  "circuit-json-to-kicad": "0.0.157",
115108
118390
  "circuit-json-to-pnp-csv": "^0.0.7",
115109
118391
  "circuit-json-to-readable-netlist": "^0.0.15",
@@ -115136,6 +118418,7 @@ var package_default = {
115136
118418
  md5: "^2.3.0",
115137
118419
  "perfect-cli": "^1.0.21",
115138
118420
  playwright: "^1.57.0",
118421
+ "polygon-clipping": "^0.15.7",
115139
118422
  poppygl: "^0.0.24",
115140
118423
  prompts: "^2.4.2",
115141
118424
  redaxios: "^0.5.1",
@@ -287233,7 +290516,7 @@ import {
287233
290516
  // node_modules/dsn-converter/dist/index.js
287234
290517
  import { su as su14 } from "@tscircuit/soup-util";
287235
290518
  import { getBoundsFromPoints as getBoundsFromPoints4 } from "@tscircuit/math-utils";
287236
- import { applyToPoint as applyToPoint29, scale as scale8 } from "transformation-matrix";
290519
+ import { applyToPoint as applyToPoint31, scale as scale8 } from "transformation-matrix";
287237
290520
  import { su as su24 } from "@tscircuit/soup-util";
287238
290521
  import { su as su34 } from "@tscircuit/soup-util";
287239
290522
  import Debug4 from "debug";
@@ -287242,9 +290525,9 @@ import { applyToPoint as applyToPoint210, scale as scale22 } from "transformatio
287242
290525
  import Debug22 from "debug";
287243
290526
  import { applyToPoint as applyToPoint93, scale as scale32 } from "transformation-matrix";
287244
290527
  import { su as su52 } from "@tscircuit/soup-util";
287245
- import { applyToPoint as applyToPoint33 } from "transformation-matrix";
290528
+ import { applyToPoint as applyToPoint34 } from "transformation-matrix";
287246
290529
  import Debug32 from "debug";
287247
- import { applyToPoint as applyToPoint43 } from "transformation-matrix";
290530
+ import { applyToPoint as applyToPoint44 } from "transformation-matrix";
287248
290531
  import Debug6 from "debug";
287249
290532
  import"transformation-matrix";
287250
290533
  import { applyToPoint as applyToPoint53 } from "transformation-matrix";
@@ -287644,7 +290927,7 @@ function processComponentsAndPads(componentGroups, circuitElements, pcb) {
287644
290927
  const sourceComponent = su14(circuitElements).source_component.list().find((e4) => e4.source_component_id === pcbComponent?.source_component_id);
287645
290928
  const footprintName = getFootprintName(sourceComponent, pcbComponent);
287646
290929
  const componentName = sourceComponent?.name || "Unknown";
287647
- const circuitSpaceCoordinates = applyToPoint29(transformMmToUm, pcbComponent.center);
290930
+ const circuitSpaceCoordinates = applyToPoint31(transformMmToUm, pcbComponent.center);
287648
290931
  if (!componentsByFootprint.has(footprintName)) {
287649
290932
  componentsByFootprint.set(footprintName, []);
287650
290933
  }
@@ -296329,7 +299612,7 @@ var any_circuit_element = external_exports2.union([
296329
299612
  var any_soup_element4 = any_circuit_element;
296330
299613
  expectTypesMatch2(true);
296331
299614
  expectStringUnionsMatch(true);
296332
- function applyToPoint30(matrix2, point22) {
299615
+ function applyToPoint35(matrix2, point22) {
296333
299616
  return Array.isArray(point22) ? [
296334
299617
  matrix2.a * point22[0] + matrix2.c * point22[1] + matrix2.e,
296335
299618
  matrix2.b * point22[0] + matrix2.d * point22[1] + matrix2.f
@@ -297293,7 +300576,7 @@ var transformPCBElement2 = (elm, matrix2) => {
297293
300576
  const tsr = decomposeTSR2(matrix2);
297294
300577
  const flipPadWidthHeight = Math.round(tsr.rotation.angle / (Math.PI / 2)) % 2 === 1;
297295
300578
  if (elm.type === "pcb_plated_hole" || elm.type === "pcb_hole" || elm.type === "pcb_via" || elm.type === "pcb_smtpad" || elm.type === "pcb_port") {
297296
- const { x: x4, y: y4 } = applyToPoint30(matrix2, {
300579
+ const { x: x4, y: y4 } = applyToPoint35(matrix2, {
297297
300580
  x: Number(elm.x),
297298
300581
  y: Number(elm.y)
297299
300582
  });
@@ -297301,7 +300584,7 @@ var transformPCBElement2 = (elm, matrix2) => {
297301
300584
  elm.y = y4;
297302
300585
  if (elm.type === "pcb_smtpad" && elm.shape === "polygon" && Array.isArray(elm.points)) {
297303
300586
  elm.points = elm.points.map((point22) => {
297304
- const tp3 = applyToPoint30(matrix2, { x: point22.x, y: point22.y });
300587
+ const tp3 = applyToPoint35(matrix2, { x: point22.x, y: point22.y });
297305
300588
  return {
297306
300589
  x: tp3.x,
297307
300590
  y: tp3.y
@@ -297309,13 +300592,13 @@ var transformPCBElement2 = (elm, matrix2) => {
297309
300592
  });
297310
300593
  }
297311
300594
  } else if (elm.type === "pcb_keepout" || elm.type === "pcb_board") {
297312
- elm.center = applyToPoint30(matrix2, elm.center);
300595
+ elm.center = applyToPoint35(matrix2, elm.center);
297313
300596
  } else if (elm.type === "pcb_silkscreen_text" || elm.type === "pcb_fabrication_note_text" || elm.type === "pcb_note_text") {
297314
- elm.anchor_position = applyToPoint30(matrix2, elm.anchor_position);
300597
+ elm.anchor_position = applyToPoint35(matrix2, elm.anchor_position);
297315
300598
  } else if (elm.type === "pcb_silkscreen_circle" || elm.type === "pcb_silkscreen_rect" || elm.type === "pcb_note_rect" || elm.type === "pcb_courtyard_rect" || elm.type === "pcb_courtyard_circle") {
297316
- elm.center = applyToPoint30(matrix2, elm.center);
300599
+ elm.center = applyToPoint35(matrix2, elm.center);
297317
300600
  } else if (elm.type === "pcb_component") {
297318
- elm.center = applyToPoint30(matrix2, elm.center);
300601
+ elm.center = applyToPoint35(matrix2, elm.center);
297319
300602
  elm.rotation = elm.rotation + tsr.rotation.angle / Math.PI * 180;
297320
300603
  elm.rotation = elm.rotation % 360;
297321
300604
  if (flipPadWidthHeight) {
@@ -297323,21 +300606,21 @@ var transformPCBElement2 = (elm, matrix2) => {
297323
300606
  }
297324
300607
  } else if (elm.type === "pcb_courtyard_outline") {
297325
300608
  elm.outline = elm.outline.map((p3) => {
297326
- const tp3 = applyToPoint30(matrix2, p3);
300609
+ const tp3 = applyToPoint35(matrix2, p3);
297327
300610
  p3.x = tp3.x;
297328
300611
  p3.y = tp3.y;
297329
300612
  return p3;
297330
300613
  });
297331
300614
  } else if (elm.type === "pcb_courtyard_polygon") {
297332
300615
  elm.points = elm.points.map((p3) => {
297333
- const tp3 = applyToPoint30(matrix2, p3);
300616
+ const tp3 = applyToPoint35(matrix2, p3);
297334
300617
  p3.x = tp3.x;
297335
300618
  p3.y = tp3.y;
297336
300619
  return p3;
297337
300620
  });
297338
300621
  } else if (elm.type === "pcb_silkscreen_path" || elm.type === "pcb_trace" || elm.type === "pcb_fabrication_note_path" || elm.type === "pcb_note_path") {
297339
300622
  elm.route = elm.route.map((rp3) => {
297340
- const tp3 = applyToPoint30(matrix2, rp3);
300623
+ const tp3 = applyToPoint35(matrix2, rp3);
297341
300624
  rp3.x = tp3.x;
297342
300625
  rp3.y = tp3.y;
297343
300626
  return rp3;
@@ -297345,14 +300628,14 @@ var transformPCBElement2 = (elm, matrix2) => {
297345
300628
  } else if (elm.type === "pcb_silkscreen_line" || elm.type === "pcb_note_line") {
297346
300629
  const p12 = { x: elm.x1, y: elm.y1 };
297347
300630
  const p23 = { x: elm.x2, y: elm.y2 };
297348
- const p1t = applyToPoint30(matrix2, p12);
297349
- const p2t = applyToPoint30(matrix2, p23);
300631
+ const p1t = applyToPoint35(matrix2, p12);
300632
+ const p2t = applyToPoint35(matrix2, p23);
297350
300633
  elm.x1 = p1t.x;
297351
300634
  elm.y1 = p1t.y;
297352
300635
  elm.x2 = p2t.x;
297353
300636
  elm.y2 = p2t.y;
297354
300637
  } else if (elm.type === "cad_component") {
297355
- const newPos = applyToPoint30(matrix2, {
300638
+ const newPos = applyToPoint35(matrix2, {
297356
300639
  x: elm.position.x,
297357
300640
  y: elm.position.y
297358
300641
  });
@@ -298315,15 +301598,15 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
298315
301598
  for (const e4 of circuitElements) {
298316
301599
  if (e4.type === "pcb_cutout") {
298317
301600
  if (e4.shape === "polygon") {
298318
- e4.points = e4.points.map((p3) => applyToPoint30(matrix2, p3));
301601
+ e4.points = e4.points.map((p3) => applyToPoint35(matrix2, p3));
298319
301602
  } else if (e4.shape === "circle" || e4.shape === "rect") {
298320
- e4.center = applyToPoint30(matrix2, e4.center);
301603
+ e4.center = applyToPoint35(matrix2, e4.center);
298321
301604
  } else if ("route" in e4) {
298322
301605
  const cutoutPath = e4;
298323
- cutoutPath.route = cutoutPath.route.map((p3) => applyToPoint30(matrix2, p3));
301606
+ cutoutPath.route = cutoutPath.route.map((p3) => applyToPoint35(matrix2, p3));
298324
301607
  }
298325
301608
  } else if (e4.type === "pcb_smtpad" && e4.shape === "polygon") {
298326
- e4.points = e4.points.map((p3) => applyToPoint30(matrix2, p3));
301609
+ e4.points = e4.points.map((p3) => applyToPoint35(matrix2, p3));
298327
301610
  }
298328
301611
  }
298329
301612
  const cad = circuitElements.find((e4) => e4.type === "cad_component");
@@ -303116,7 +306399,7 @@ var any_circuit_element2 = z160.union([
303116
306399
  var any_soup_element5 = any_circuit_element2;
303117
306400
  expectTypesMatch3(true);
303118
306401
  expectStringUnionsMatch2(true);
303119
- function applyToPoint31(matrix2, point22) {
306402
+ function applyToPoint37(matrix2, point22) {
303120
306403
  return Array.isArray(point22) ? [
303121
306404
  matrix2.a * point22[0] + matrix2.c * point22[1] + matrix2.e,
303122
306405
  matrix2.b * point22[0] + matrix2.d * point22[1] + matrix2.f
@@ -304079,7 +307362,7 @@ var transformPCBElement3 = (elm, matrix2) => {
304079
307362
  const tsr = decomposeTSR3(matrix2);
304080
307363
  const flipPadWidthHeight = Math.round(tsr.rotation.angle / (Math.PI / 2)) % 2 === 1;
304081
307364
  if (elm.type === "pcb_plated_hole" || elm.type === "pcb_hole" || elm.type === "pcb_via" || elm.type === "pcb_smtpad" || elm.type === "pcb_port") {
304082
- const { x: x4, y: y4 } = applyToPoint31(matrix2, {
307365
+ const { x: x4, y: y4 } = applyToPoint37(matrix2, {
304083
307366
  x: Number(elm.x),
304084
307367
  y: Number(elm.y)
304085
307368
  });
@@ -304087,7 +307370,7 @@ var transformPCBElement3 = (elm, matrix2) => {
304087
307370
  elm.y = y4;
304088
307371
  if (elm.type === "pcb_smtpad" && elm.shape === "polygon" && Array.isArray(elm.points)) {
304089
307372
  elm.points = elm.points.map((point22) => {
304090
- const tp3 = applyToPoint31(matrix2, { x: point22.x, y: point22.y });
307373
+ const tp3 = applyToPoint37(matrix2, { x: point22.x, y: point22.y });
304091
307374
  return {
304092
307375
  x: tp3.x,
304093
307376
  y: tp3.y
@@ -304095,13 +307378,13 @@ var transformPCBElement3 = (elm, matrix2) => {
304095
307378
  });
304096
307379
  }
304097
307380
  } else if (elm.type === "pcb_keepout" || elm.type === "pcb_board") {
304098
- elm.center = applyToPoint31(matrix2, elm.center);
307381
+ elm.center = applyToPoint37(matrix2, elm.center);
304099
307382
  } else if (elm.type === "pcb_silkscreen_text" || elm.type === "pcb_fabrication_note_text" || elm.type === "pcb_note_text") {
304100
- elm.anchor_position = applyToPoint31(matrix2, elm.anchor_position);
307383
+ elm.anchor_position = applyToPoint37(matrix2, elm.anchor_position);
304101
307384
  } else if (elm.type === "pcb_silkscreen_circle" || elm.type === "pcb_silkscreen_rect" || elm.type === "pcb_note_rect" || elm.type === "pcb_courtyard_rect" || elm.type === "pcb_courtyard_circle") {
304102
- elm.center = applyToPoint31(matrix2, elm.center);
307385
+ elm.center = applyToPoint37(matrix2, elm.center);
304103
307386
  } else if (elm.type === "pcb_component") {
304104
- elm.center = applyToPoint31(matrix2, elm.center);
307387
+ elm.center = applyToPoint37(matrix2, elm.center);
304105
307388
  elm.rotation = elm.rotation + tsr.rotation.angle / Math.PI * 180;
304106
307389
  elm.rotation = elm.rotation % 360;
304107
307390
  if (flipPadWidthHeight) {
@@ -304109,21 +307392,21 @@ var transformPCBElement3 = (elm, matrix2) => {
304109
307392
  }
304110
307393
  } else if (elm.type === "pcb_courtyard_outline") {
304111
307394
  elm.outline = elm.outline.map((p3) => {
304112
- const tp3 = applyToPoint31(matrix2, p3);
307395
+ const tp3 = applyToPoint37(matrix2, p3);
304113
307396
  p3.x = tp3.x;
304114
307397
  p3.y = tp3.y;
304115
307398
  return p3;
304116
307399
  });
304117
307400
  } else if (elm.type === "pcb_courtyard_polygon") {
304118
307401
  elm.points = elm.points.map((p3) => {
304119
- const tp3 = applyToPoint31(matrix2, p3);
307402
+ const tp3 = applyToPoint37(matrix2, p3);
304120
307403
  p3.x = tp3.x;
304121
307404
  p3.y = tp3.y;
304122
307405
  return p3;
304123
307406
  });
304124
307407
  } else if (elm.type === "pcb_silkscreen_path" || elm.type === "pcb_trace" || elm.type === "pcb_fabrication_note_path" || elm.type === "pcb_note_path") {
304125
307408
  elm.route = elm.route.map((rp3) => {
304126
- const tp3 = applyToPoint31(matrix2, rp3);
307409
+ const tp3 = applyToPoint37(matrix2, rp3);
304127
307410
  rp3.x = tp3.x;
304128
307411
  rp3.y = tp3.y;
304129
307412
  return rp3;
@@ -304131,14 +307414,14 @@ var transformPCBElement3 = (elm, matrix2) => {
304131
307414
  } else if (elm.type === "pcb_silkscreen_line" || elm.type === "pcb_note_line") {
304132
307415
  const p12 = { x: elm.x1, y: elm.y1 };
304133
307416
  const p23 = { x: elm.x2, y: elm.y2 };
304134
- const p1t = applyToPoint31(matrix2, p12);
304135
- const p2t = applyToPoint31(matrix2, p23);
307417
+ const p1t = applyToPoint37(matrix2, p12);
307418
+ const p2t = applyToPoint37(matrix2, p23);
304136
307419
  elm.x1 = p1t.x;
304137
307420
  elm.y1 = p1t.y;
304138
307421
  elm.x2 = p2t.x;
304139
307422
  elm.y2 = p2t.y;
304140
307423
  } else if (elm.type === "cad_component") {
304141
- const newPos = applyToPoint31(matrix2, {
307424
+ const newPos = applyToPoint37(matrix2, {
304142
307425
  x: elm.position.x,
304143
307426
  y: elm.position.y
304144
307427
  });
@@ -305084,15 +308367,15 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
305084
308367
  for (const e4 of circuitElements) {
305085
308368
  if (e4.type === "pcb_cutout") {
305086
308369
  if (e4.shape === "polygon") {
305087
- e4.points = e4.points.map((p3) => applyToPoint31(matrix2, p3));
308370
+ e4.points = e4.points.map((p3) => applyToPoint37(matrix2, p3));
305088
308371
  } else if (e4.shape === "circle" || e4.shape === "rect") {
305089
- e4.center = applyToPoint31(matrix2, e4.center);
308372
+ e4.center = applyToPoint37(matrix2, e4.center);
305090
308373
  } else if ("route" in e4) {
305091
308374
  const cutoutPath = e4;
305092
- cutoutPath.route = cutoutPath.route.map((p3) => applyToPoint31(matrix2, p3));
308375
+ cutoutPath.route = cutoutPath.route.map((p3) => applyToPoint37(matrix2, p3));
305093
308376
  }
305094
308377
  } else if (e4.type === "pcb_smtpad" && e4.shape === "polygon") {
305095
- e4.points = e4.points.map((p3) => applyToPoint31(matrix2, p3));
308378
+ e4.points = e4.points.map((p3) => applyToPoint37(matrix2, p3));
305096
308379
  }
305097
308380
  }
305098
308381
  const cad = circuitElements.find((e4) => e4.type === "cad_component");