diff --git a/js/events/download.js b/js/events/download.js
index a60688f..e66c62c 100644
--- a/js/events/download.js
+++ b/js/events/download.js
@@ -1,4 +1,8 @@
import { changeDpiDataUrl } from "./changeDPI.js";
+import { offset2 } from "../../geogram/index.js";
+import JSZip from "jszip";
+import { saveAs } from "file-saver";
+
export function downloadSVG(state) {
const svgUrl = makeSVG(state);
@@ -59,26 +63,121 @@ function format(x) {
export function downloadGerber(state) {
const layers = state.storedPCB.layers;
- // console.log(layers);
- let str = ''
- str += "%MOIN*%\n" // inch units
- str += "%LPD*%\n" // layer dark
- str += "%FSLAX66Y66*%\n" // format absolute 6.6
- str += "G01*\n" // linear interpolation
+ const expandWire = w => offset2(
+ w.shape,
+ w.thickness/2,
+ {
+ endType: "etOpenRound",
+ jointType:"jtRound",
+ }
+ );
+
+ // this is a list of polylines
+ const frontCopper = layers["F.Cu"].map( x => {
+ if (x.type === "wire") return expandWire(x);
+ else return x;
+ }).flat();
+
+ const drill = layers["drill"].flat().map( x => {
+
+ const getCenter = (pts) => {
+ let totalX = 0;
+ let totalY = 0;
+ pts.forEach(pt => {
+ totalX += pt.x;
+ totalY += pt.y;
+ })
+ return { x: totalX/pts.length, y: totalY/pts.length };
+ }
- const front_copper = layers["F.Cu"];
- const strs = front_copper.polylines().map( (x) => {
- const { pts } = x;
- let ptsString = pts.reduce((acc, cur, i) => `${acc}X${format(cur.x)}Y${format(cur.y)}D0${i === 0 ? 2 : 1}*\n`, "G36*\n")
- ptsString += "G37*\n";
+ const getDistance = (pt0, pt1) => Math.sqrt((pt1.x - pt0.x)**2+(pt1.y - pt0.y)**2);
- return ptsString;
+ const center = getCenter(x);
+ const dist = Math.round(1000*x.reduce((acc, cur) => acc + getDistance(center, cur), 0)/x.length)/1000;
+
+ return {
+ center,
+ dist
+ };
});
- str += strs.join("") + "M02*";
+ const interior = layers["interior"].map( x => {
+ return x;
+ }).flat();;
+
+ console.log({
+ drill,
+ frontCopper,
+ interior
+ })
+
+ const makeFile = (layer) => {
+ let str = ''
+ str += "%MOIN*%\n" // inch units
+ str += "%LPD*%\n" // layer dark
+ str += "%FSLAX66Y66*%\n" // format absolute 6.6
+ str += "G01*\n" // linear interpolation
+
+ const strs = layer.map( pts => {
+ let ptsString = pts.reduce((acc, cur, i) => `${acc}X${format(cur.x)}Y${format(cur.y)}D0${i === 0 ? 2 : 1}*\n`, "G36*\n")
+ ptsString += "G37*\n";
+
+ return ptsString;
+ });
+
+ str += strs.join("") + "M02*";
+
+ return str;
+ }
+
+ const makeFileDrill = (drills) => {
+ const tools = {};
+ drills.forEach( ({ dist, center }) => {
+ if (dist in tools) {
+ tools[dist].push(center);
+ } else {
+ tools[dist] = [ center ];
+ }
+ })
+
+ let str = "";
+ str += "M48\n" // start of header
+ str += "INCH,LZ\n" // inch units with leading zeros
+ str += "VER,1\n" // version 1
+ str += "FMAT,2\n" // format 2
+ for (const tool in tools) {
+ str += 'T'+ tool + 'C'+ tool + "\n"; // +'C'+tool+"\n" // define tools
+ }
+ str += "M95\n" // end of header
+ str += "G05\n" // drill mode
+ for (const tool in tools) {
+ str += 'T'+tool+'\n' // tool selection
+ for (var i = 0; i < tools[tool].length; i++) {
+ const hole = tools[tool][i];
+ str += 'X'+format(hole.x)+'Y'+format(hole.y)+'\n'
+ }
+ }
+
+ str += "M30\n" // end of program
+
+ return str;
+ }
+
+
+ var zip = new JSZip();
+ zip.file(`${state.name === "" ? "anon" : state.name}-F_Cu.gbr`, makeFile(frontCopper));
+ zip.file(`${state.name === "" ? "anon" : state.name}-Edge_Cuts.gbr`, makeFile(interior));
+ zip.file(`${state.name === "" ? "anon" : state.name}-Drill.xln`, makeFileDrill(drill));
+
+ zip
+ .generateAsync({ type:"blob" })
+ .then((content) => {
+ // see FileSaver.js
+ saveAs(content, `${state.name === "" ? "anon" : state.name}-gerber.zip`);
+ });
- downloadText(`${state.name === "" ? "anon" : state.name}.gerber`, str);
+ // downloadText(`${state.name === "" ? "anon" : state.name}-F_Cu.gbr`, str);
}
export function downloadText(filename, text) {
diff --git a/js/view.js b/js/view.js
index b5e7442..ac3f8c4 100644
--- a/js/view.js
+++ b/js/view.js
@@ -62,6 +62,10 @@ const menu = state => html`
@click=${() => downloadText(`${state.name === "" ? "anon" : state.name}.js`, state.codemirror.view.state.doc.toString())}>
js
+
{
// parts overlap then i want to render on top (first way)
// interior shapes I want to render outside (second way)
- d.split(/(?=M)/g).forEach(dstring => {
- toRender.push(renderDataString(dstring));
- });
+ // d.split(/(?=M)/g).forEach(dstring => {
+ // toRender.push(renderDataString(dstring));
+ // });
- // const toAdd = svg`
- //
- // `
+ const toAdd = svg`
+
+ `
- // toRender.push(toAdd);
+ toRender.push(toAdd);
} else if (d.type === "text") {
toRender.push(renderText(d));
diff --git a/package.json b/package.json
index 65a90bb..3a00fa7 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,8 @@
"astring": "^1.7.5",
"codemirror": "^6.0.0",
"esprima": "^4.0.1",
+ "file-saver": "^2.0.5",
+ "jszip": "^3.10.1",
"lit-html": "^2.0.1"
}
}
diff --git a/yarn.lock b/yarn.lock
index dc30bd7..cce4ea0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -562,6 +562,11 @@ cookies@~0.8.0:
depd "~2.0.0"
keygrip "~1.1.0"
+core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
crelt@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
@@ -794,6 +799,11 @@ etag@^1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+file-saver@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
+ integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
+
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@@ -888,12 +898,17 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
+immediate@~3.0.5:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
+ integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
+
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
-inherits@2.0.4:
+inherits@2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -970,6 +985,11 @@ is-wsl@^2.2.0:
dependencies:
is-docker "^2.0.0"
+isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
isbinaryfile@^4.0.6:
version "4.0.10"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3"
@@ -980,6 +1000,16 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+jszip@^3.10.1:
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2"
+ integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
+ dependencies:
+ lie "~3.3.0"
+ pako "~1.0.2"
+ readable-stream "~2.3.6"
+ setimmediate "^1.0.5"
+
keygrip@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
@@ -1053,6 +1083,13 @@ koa@^2.13.0:
type-is "^1.6.16"
vary "^1.1.2"
+lie@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
+ integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
+ dependencies:
+ immediate "~3.0.5"
+
lit-html@^2.0.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.4.0.tgz#b510430f39a56ec959167ed1187241a4e3ab1574"
@@ -1157,6 +1194,11 @@ open@^8.0.2:
is-docker "^2.1.1"
is-wsl "^2.2.0"
+pako@~1.0.2:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
+ integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+
parse5@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
@@ -1205,11 +1247,29 @@ postcss@^8.4.16:
picocolors "^1.0.0"
source-map-js "^1.0.2"
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+readable-stream@~2.3.6:
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+ integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -1258,6 +1318,11 @@ safe-buffer@5.2.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
semver@^7.3.4:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
@@ -1265,6 +1330,11 @@ semver@^7.3.4:
dependencies:
lru-cache "^6.0.0"
+setimmediate@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+ integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
+
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@@ -1285,6 +1355,13 @@ source-map-js@^1.0.2:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
style-mod@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.0.tgz#97e7c2d68b592975f2ca7a63d0dd6fcacfe35a01"
@@ -1354,6 +1431,11 @@ typical@^5.2.0:
resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"
integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
vary@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"