Skip to content

Commit

Permalink
Add page on connectors, export plate to svg
Browse files Browse the repository at this point in the history
  • Loading branch information
rianadon committed Jun 22, 2023
1 parent 4d6458e commit ab675dd
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import ShapingSection from './lib/ShapingSection.svelte';
import Instructions from './lib/Instructions.svelte';
import FilamentChart from './lib/FilamentChart.svelte';
import InfoBox from './lib/presentation/Info.svelte';
import { serialize, deserialize } from './lib/serialize';
import { trackPageView, trackEvent } from './lib/telemetry';
Expand All @@ -43,6 +44,7 @@
let generatingCSG = false;
let generatingSCAD = false;
let generatingSTL = false;
let generatingSVG = false;
let generatingSCADSTL = false;
let stlDialogOpen = false;
let sponsorOpen = false;
Expand Down Expand Up @@ -100,6 +102,11 @@
myWorker.postMessage({type: "stl", data: state });
}
function downloadSVG() {
generatingSVG = true;
myWorker.postMessage({type: "svg", data: state });
}
function downloadSCADSTL() {
generatingSCADSTL = true;
logs = ['Loading OpenSCAD...']
Expand Down Expand Up @@ -135,6 +142,11 @@
trackEvent('dactyl-render', { time: window.performance.now() - renderBegin })
const blob = new Blob([e.data.data], { type: "application/octet-stream" })
download(blob, "model.stl")
} else if (e.data.type == 'svg') {
// SVG generation finished. Download it!
generatingSVG = false;
const blob = new Blob([e.data.data], { type: "image/svg+xml" })
download(blob, "plate.svg")
} else if (e.data.type == 'csg') {
// Preview finished. Show it!
generatingCSG = false;
Expand Down Expand Up @@ -194,6 +206,16 @@
{#each section.fields as key}
<Field defl={defaults.options[section.var][key.var]} schema={key} bind:value={state.options[section.var][key.var]} />
{/each}
{#if section.var == "connector" && state.options.connector.external}
<InfoBox>
<p>You'll also need to print one of the external holders listed <a class="underline text-purple-500" href="https://github.com/rianadon/dactyl-configurator/blob/main/src/connectors.md">here</a>.</p>
</InfoBox>
{:else if section.var == "misc" && state.options.misc.plate}
<InfoBox>
<p class="mb-1">If you plan to laser cut the base instead of 3D printing, you'll need a 2D drawing of the plate. <button class="underline text-purple-500" on:click={downloadSVG}>Download an SVG file{#if generatingSVG}...{/if}</button> that you can open in Inkscape or Illustrator and send to the cutter.</p>
<p>Please ensure the line labeled <span class="text-purple-500 font-semibold">1 cm</span> is really 1 cm long before sending the file. Afterwards you can safely delete it.</p>
</InfoBox>
{/if}
{/if}
</div>
{/each}
Expand Down
22 changes: 22 additions & 0 deletions src/connectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
List of External Holders for the Dactyl
====

While I personally don't use external holders, they are a popular way to securely fasten a microcontroller and connector to your keyboard, especially if you don't have access to a drill to widen the holes in the model.

If you're using one of these, make sure to set the connector type to *anything* but RJ9.

| Image | Board | Model Downloads | Author |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------------------------------------------------------------------|------------------------------|
| <img src=" https://github.com/yejianfengblue/dactyl-generator-demo/raw/main/images/external-holder-back.jpg" alt="Pro Micro Holder" height="100" /> | Pro Micro<br>(micro USB) | [[left (mesh fixed)][pm-leftf]] [[left][pm-left]] [[right][pm-right]] | [Blue Ye (@yejianfengblue )] |
| | Pro Micro<br>(USB-C) | [[left][pmc-left]] [[right][pmc-right]] | [Blue Ye (@yejianfengblue )] |
| | Elite-C | [[right][ec-right]] | Unknown |

[pm-leftf]: https://github.com/yejianfengblue/dactyl-generator-demo/blob/main/stl/promicro-holder-v3-left-mesh-fixed.stl
[pm-left]: https://github.com/yejianfengblue/dactyl-generator-demo/blob/main/stl/promicro-holder-v3-left.stl
[pm-right]: https://github.com/yejianfengblue/dactyl-generator-demo/blob/main/stl/promicro-holder-v3-right.stl
[pmc-left]: https://github.com/yejianfengblue/dactyl-generator-demo/blob/main/stl/promicro-holder-typec-untested-left.stl
[pmc-right]: https://github.com/yejianfengblue/dactyl-generator-demo/blob/main/stl/promicro-holder-typec-untested-right.stl
[Blue Ye (@yejianfengblue )]: https://github.com/yejianfengblue
[ec-right]: https://web.archive.org/web/20220607031927/https://dactyl.siskam.link/loligagger-external-holder-elite-c-v1.stl

If you found one that isn't listed here, please submit a pull request! I'd like to make this list as complete as possible.
2 changes: 1 addition & 1 deletion src/lib/SupportDialog.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import Dialog from './Dialog.svelte'
import Dialog from './presentation/Dialog.svelte'
import Heart from 'svelte-material-icons/HeartOutline.svelte'
let noGH = false
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions src/lib/presentation/Info.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
import Info from 'svelte-material-icons/AlertCircleOutline.svelte'
</script>
<div class="max-w-[32.3rem] text-sm mb-1 bg-purple-50 dark:bg-purple-400/10 dark:border-gray-900 mx-[-0.5rem] pl-2 pr-4 py-2 rounded flex gap-3 relative">
<div>
<Info size="20" class="text-purple-600" />
<div class="absolute top-9 left-[calc(7px+0.5rem)] bottom-2 w-[6px] bg-purple-300 rounded" />
</div>
<div class="opacity-80 dark:opacity-100">
<slot></slot>
</div>
</div>
85 changes: 85 additions & 0 deletions src/worker/SVGExporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Export a planar mesh to SVG.
*
* The formats are very different (a mesh is made of tesselated triangles, whereas SVG is a single face),
* so some preprocessing needs to be done.
* 1) The mesh is filtered so that only faces on the z plane are exported
* 2) The triangles of the mesh are combined into polygons
* 3) The polygons are written out to the SVG file.
*/

import type { Mesh } from 'manifold-3d';

interface Options {
margin?: number
color?: string
}

export default function svgExport(mesh: Mesh, options: Options) {
const margin = options?.margin ?? 10
const color = options?.color ?? "#8080F7"

const flatFaces: [number, number, number][] = []
for (let i = 0; i < mesh.triVerts.length; i+=3) {
// a, b, and c are the points on face
const [a, b, c] = mesh.triVerts.slice(i, i+3)
// If the z coordinates of all points are 0, add it.
if (mesh.vertProperties[a*3+2] == 0 &&
mesh.vertProperties[b*3+2] == 0 &&
mesh.vertProperties[c*3+2] == 0) {
flatFaces.push([a, b, c])
}
}

const boundary = new Set<string>()
for (const tri of flatFaces) {
for (const [e0, e1] of [[tri[0], tri[1]], [tri[1], tri[2]], [tri[2], tri[0]]]) {
if (boundary.has(e1 + ',' + e0)) {
boundary.delete(e1 + ',' + e0)
} else {
boundary.add(e0 + ',' + e1)
}
}
}

// To process the boundary, I create a queue of edges to their next edge (this map).
const next = new Map<number, number>()
for (const b of boundary) {
const [e0, e1] = b.split(',').map(v => Number(v))
next.set(e0, e1)
}

let minX = 0
let maxX = 0
let minY = 0
let maxY = 0

const paths: string[] = []
// Extract a vertex in the boundary, follow the next edges until there is no more vertex, then repeat.
while (next.size > 0) {
let vertex = next.keys().next().value
let path = ''
while (next.has(vertex)) {
// Flip the y to preserve how things look in the preview
const [x, y] = [mesh.vertProperties[vertex*3], -mesh.vertProperties[vertex*3+1]]
path += `${path.length==0 ? 'M' : 'L'}${x},${y}`
minX = Math.min(minX, x-margin)
maxX = Math.max(maxX, x+margin)
minY = Math.min(minY, y-margin)
maxY = Math.max(maxY, y+margin)
const newVertex = next.get(vertex)
next.delete(vertex)
vertex = newVertex
}
paths.push(path + 'Z')
}

return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="${minX} ${minY} ${maxX-minX} ${maxY-minY}" width="${maxX-minX}mm" height="${maxY-minY}mm"
>
<path fill="${color}" d="${paths.join(' ')}" />
<line x1="${minX+margin}" y1="${maxY-margin/2}" x2="${minX+margin+10}" y2="${maxY-margin/2}" stroke="#96D9D7" />
<text x="${minX+margin+12}" y="${maxY-margin/2+2}" style="font: bold 2mm sans-serif;fill:#96D9D7">= 1cm</text>
</svg>
`
}
12 changes: 12 additions & 0 deletions src/worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import createGC, { type GC } from './gc'
import scadWasmUrl from '../assets/openscad.wasm?url'
import stlExport from './STLExporter'
import { supportManifold } from './supports'
import svgExport from "./SVGExporter.js"

(Module as (a: any) => Promise<ManifoldStatic>)({
locateFile: () => manifoldWasmUrl,
Expand All @@ -29,6 +30,7 @@ function main(manifold: ManifoldStatic) {
switch (type) {
case 'csg': return generateCSG(data, modeling, cleanup)
case 'stl': return generateSTL(data, modeling, cleanup)
case 'svg': return generateSVG(data, modeling, cleanup)
case 'scad': return generateSCAD(data)
case 'scadstl': return generateSCAD_STL(data)
}
Expand Down Expand Up @@ -58,6 +60,16 @@ function generateSTL(config: any, modeling: Modeling, cleanup: GC) {
}
}

function generateSVG(config: any, modeling: Modeling, cleanup: GC) {
try {
const mesh: Mesh = Dactyl.generateManifold(config, modeling).getMesh()
message('svg', svgExport(mesh))
cleanup()
} catch (e) {
console.error(e)
}
}

function generateSCAD(config: any) {
message('scad', Dactyl.generateSCAD(config))
}
Expand Down

0 comments on commit ab675dd

Please sign in to comment.