Basic KLE support
This commit is contained in:
parent
d09b3fdf38
commit
1cb9fdc3c2
5 changed files with 154 additions and 77 deletions
21
package-lock.json
generated
21
package-lock.json
generated
|
@ -12,7 +12,8 @@
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
"json5": "^2.2.0",
|
"json5": "^2.2.0",
|
||||||
"makerjs": "github:mrzealot/maker.js-dist#a0ca32948845efe8ad5c9ca454f1285926853138",
|
"kle-serial": "github:mrzealot/kle-serial",
|
||||||
|
"makerjs": "github:mrzealot/maker.js-dist",
|
||||||
"mathjs": "^8.1.1",
|
"mathjs": "^8.1.1",
|
||||||
"yargs": "^15.4.1"
|
"yargs": "^15.4.1"
|
||||||
},
|
},
|
||||||
|
@ -1805,6 +1806,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-2.0.1.tgz",
|
||||||
"integrity": "sha512-9KqSdmWCkBIisFIGclT0FRagKhI7IVbMyUjsxCFG0Ly1Dg6whlxJ7b9lrq8ifk3X/fGeJzok1R75LQfZTfA5zQ=="
|
"integrity": "sha512-9KqSdmWCkBIisFIGclT0FRagKhI7IVbMyUjsxCFG0Ly1Dg6whlxJ7b9lrq8ifk3X/fGeJzok1R75LQfZTfA5zQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/kle-serial": {
|
||||||
|
"name": "@ijprest/kle-serial",
|
||||||
|
"version": "0.15.1",
|
||||||
|
"resolved": "git+ssh://git@github.com/mrzealot/kle-serial.git#f6afaf61d32f7d4a82ec3da95b98f3f43997bd57",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"json5": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
@ -4703,6 +4713,13 @@
|
||||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-2.0.1.tgz",
|
||||||
"integrity": "sha512-9KqSdmWCkBIisFIGclT0FRagKhI7IVbMyUjsxCFG0Ly1Dg6whlxJ7b9lrq8ifk3X/fGeJzok1R75LQfZTfA5zQ=="
|
"integrity": "sha512-9KqSdmWCkBIisFIGclT0FRagKhI7IVbMyUjsxCFG0Ly1Dg6whlxJ7b9lrq8ifk3X/fGeJzok1R75LQfZTfA5zQ=="
|
||||||
},
|
},
|
||||||
|
"kle-serial": {
|
||||||
|
"version": "git+ssh://git@github.com/mrzealot/kle-serial.git#f6afaf61d32f7d4a82ec3da95b98f3f43997bd57",
|
||||||
|
"from": "kle-serial@github:mrzealot/kle-serial",
|
||||||
|
"requires": {
|
||||||
|
"json5": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
@ -4764,7 +4781,7 @@
|
||||||
"makerjs": {
|
"makerjs": {
|
||||||
"version": "git+ssh://git@github.com/mrzealot/maker.js-dist.git#a0ca32948845efe8ad5c9ca454f1285926853138",
|
"version": "git+ssh://git@github.com/mrzealot/maker.js-dist.git#a0ca32948845efe8ad5c9ca454f1285926853138",
|
||||||
"integrity": "sha512-MsYj7ch7Et7He/Nsd2BLvoPsJlyUoi7KkLyiqP0ap0ff+LcrdyKCqpr9vpudthaHjMmsWeVuPb0HnzfYbGw1wQ==",
|
"integrity": "sha512-MsYj7ch7Et7He/Nsd2BLvoPsJlyUoi7KkLyiqP0ap0ff+LcrdyKCqpr9vpudthaHjMmsWeVuPb0HnzfYbGw1wQ==",
|
||||||
"from": "makerjs@github:mrzealot/maker.js-dist#a0ca32948845efe8ad5c9ca454f1285926853138",
|
"from": "makerjs@github:mrzealot/maker.js-dist",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@danmarshall/jscad-typings": "^1.0.0",
|
"@danmarshall/jscad-typings": "^1.0.0",
|
||||||
"@types/bezier-js": "^0.0.6",
|
"@types/bezier-js": "^0.0.6",
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
"coverage": "nyc --reporter=html --reporter=text npm test"
|
"coverage": "nyc --reporter=html --reporter=text npm test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"kle-serial": "github:mrzealot/kle-serial",
|
||||||
"@jscad/openjscad": "^1.6.1",
|
"@jscad/openjscad": "^1.6.1",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
"json5": "^2.2.0",
|
"json5": "^2.2.0",
|
||||||
"makerjs": "github:mrzealot/maker.js-dist#a0ca32948845efe8ad5c9ca454f1285926853138",
|
"makerjs": "github:mrzealot/maker.js-dist",
|
||||||
"mathjs": "^8.1.1",
|
"mathjs": "^8.1.1",
|
||||||
"yargs": "^15.4.1"
|
"yargs": "^15.4.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
const yaml = require('js-yaml')
|
|
||||||
const json5 = require('json5')
|
|
||||||
const makerjs = require('makerjs')
|
|
||||||
const jscad = require('@jscad/openjscad')
|
|
||||||
|
|
||||||
const a = require('./assert')
|
|
||||||
const u = require('./utils')
|
const u = require('./utils')
|
||||||
|
const io = require('./io')
|
||||||
const prepare = require('./prepare')
|
const prepare = require('./prepare')
|
||||||
const units_lib = require('./units')
|
const units_lib = require('./units')
|
||||||
const points_lib = require('./points')
|
const points_lib = require('./points')
|
||||||
|
@ -13,79 +7,20 @@ const outlines_lib = require('./outlines')
|
||||||
const cases_lib = require('./cases')
|
const cases_lib = require('./cases')
|
||||||
const pcbs_lib = require('./pcbs')
|
const pcbs_lib = require('./pcbs')
|
||||||
|
|
||||||
const noop = () => {}
|
|
||||||
|
|
||||||
const twodee = (model, debug) => {
|
|
||||||
const assembly = makerjs.model.originate({
|
|
||||||
models: {
|
|
||||||
export: u.deepcopy(model)
|
|
||||||
},
|
|
||||||
units: 'mm'
|
|
||||||
})
|
|
||||||
|
|
||||||
const result = {
|
|
||||||
dxf: makerjs.exporter.toDXF(assembly),
|
|
||||||
}
|
|
||||||
if (debug) {
|
|
||||||
result.json = assembly
|
|
||||||
result.svg = makerjs.exporter.toSVG(assembly)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
const threedee = async (script, debug) => {
|
|
||||||
const compiled = await new Promise((resolve, reject) => {
|
|
||||||
jscad.compile(script, {}).then(compiled => {
|
|
||||||
resolve(compiled)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const result = {
|
|
||||||
stl: jscad.generateOutput('stla', compiled).asBuffer()
|
|
||||||
}
|
|
||||||
if (debug) {
|
|
||||||
result.jscad = script
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
version: '__ergogen_version',
|
version: '__ergogen_version',
|
||||||
process: async (raw, debug=false, logger=noop) => {
|
process: async (raw, debug=false, logger=()=>{}) => {
|
||||||
|
|
||||||
const prefix = 'Interpreting format... '
|
|
||||||
let config = raw
|
|
||||||
if (a.type(raw)() != 'object') {
|
|
||||||
try {
|
|
||||||
config = yaml.safeLoad(raw)
|
|
||||||
logger(prefix + 'YAML detected.')
|
|
||||||
} catch (yamlex) {
|
|
||||||
try {
|
|
||||||
config = json5.parse(raw)
|
|
||||||
logger(prefix + 'JSON detected.')
|
|
||||||
} catch (jsonex) {
|
|
||||||
try {
|
|
||||||
config = new Function(raw)()
|
|
||||||
logger(prefix + 'JS code detected.')
|
|
||||||
} catch (codeex) {
|
|
||||||
logger('YAML exception:', yamlex)
|
|
||||||
logger('JSON exception:', jsonex)
|
|
||||||
logger('Code exception:', codeex)
|
|
||||||
throw new Error('Input is not valid YAML, JSON, or JS code!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!config) {
|
|
||||||
throw new Error('Input appears to be empty!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let [config, format] = io.interpret(raw, logger)
|
||||||
|
logger('Interpreting format: ' + format)
|
||||||
|
|
||||||
logger('Preprocessing input...')
|
logger('Preprocessing input...')
|
||||||
config = prepare.unnest(config)
|
config = prepare.unnest(config)
|
||||||
config = prepare.inherit(config)
|
config = prepare.inherit(config)
|
||||||
const results = {}
|
const results = {}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
results.raw = raw
|
results.raw = raw
|
||||||
results.canonical = config
|
results.canonical = u.deepcopy(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('Calculating variables...')
|
logger('Calculating variables...')
|
||||||
|
@ -94,6 +29,7 @@ module.exports = {
|
||||||
results.units = units
|
results.units = units
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
logger('Parsing points...')
|
logger('Parsing points...')
|
||||||
if (!config.points) {
|
if (!config.points) {
|
||||||
throw new Error('Input does not contain any points!')
|
throw new Error('Input does not contain any points!')
|
||||||
|
@ -101,7 +37,7 @@ module.exports = {
|
||||||
const points = points_lib.parse(config.points, units)
|
const points = points_lib.parse(config.points, units)
|
||||||
if (debug) {
|
if (debug) {
|
||||||
results.points = points
|
results.points = points
|
||||||
results.demo = twodee(points_lib.visualize(points), debug)
|
results.demo = io.twodee(points_lib.visualize(points), debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('Generating outlines...')
|
logger('Generating outlines...')
|
||||||
|
@ -109,7 +45,7 @@ module.exports = {
|
||||||
results.outlines = {}
|
results.outlines = {}
|
||||||
for (const [name, outline] of Object.entries(outlines)) {
|
for (const [name, outline] of Object.entries(outlines)) {
|
||||||
if (!debug && name.startsWith('_')) continue
|
if (!debug && name.startsWith('_')) continue
|
||||||
results.outlines[name] = twodee(outline, debug)
|
results.outlines[name] = io.twodee(outline, debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('Extruding cases...')
|
logger('Extruding cases...')
|
||||||
|
@ -117,7 +53,7 @@ module.exports = {
|
||||||
results.cases = {}
|
results.cases = {}
|
||||||
for (const [case_name, case_script] of Object.entries(cases)) {
|
for (const [case_name, case_script] of Object.entries(cases)) {
|
||||||
if (!debug && case_name.startsWith('_')) continue
|
if (!debug && case_name.startsWith('_')) continue
|
||||||
results.cases[case_name] = await threedee(case_script, debug)
|
results.cases[case_name] = await io.threedee(case_script, debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('Scaffolding PCBs...')
|
logger('Scaffolding PCBs...')
|
||||||
|
|
78
src/io.js
Normal file
78
src/io.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
const json5 = require('json5')
|
||||||
|
const yaml = require('js-yaml')
|
||||||
|
const makerjs = require('makerjs')
|
||||||
|
const jscad = require('@jscad/openjscad')
|
||||||
|
|
||||||
|
const u = require('./utils')
|
||||||
|
const a = require('./assert')
|
||||||
|
const kle = require('./kle')
|
||||||
|
|
||||||
|
exports.interpret = (raw, logger) => {
|
||||||
|
let config
|
||||||
|
let format
|
||||||
|
if (a.type(raw)() != 'object') {
|
||||||
|
try {
|
||||||
|
config = yaml.safeLoad(raw)
|
||||||
|
format = 'YAML'
|
||||||
|
} catch (yamlex) {
|
||||||
|
try {
|
||||||
|
config = json5.parse(raw)
|
||||||
|
format = 'JSON'
|
||||||
|
} catch (jsonex) {
|
||||||
|
try {
|
||||||
|
config = new Function(raw)()
|
||||||
|
format = 'JS Code'
|
||||||
|
} catch (codeex) {
|
||||||
|
logger('YAML exception:', yamlex)
|
||||||
|
logger('JSON exception:', jsonex)
|
||||||
|
logger('Code exception:', codeex)
|
||||||
|
throw new Error('Input is not valid YAML, JSON, or JS Code!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!config) {
|
||||||
|
throw new Error('Input appears to be empty!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// assume it's KLE and try to convert it
|
||||||
|
// if it's not, it'll throw anyway
|
||||||
|
return kle.convert(config, logger)
|
||||||
|
} catch (kleex) {
|
||||||
|
return [config, format]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.twodee = (model, debug) => {
|
||||||
|
const assembly = makerjs.model.originate({
|
||||||
|
models: {
|
||||||
|
export: u.deepcopy(model)
|
||||||
|
},
|
||||||
|
units: 'mm'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
dxf: makerjs.exporter.toDXF(assembly),
|
||||||
|
}
|
||||||
|
if (debug) {
|
||||||
|
result.json = assembly
|
||||||
|
result.svg = makerjs.exporter.toSVG(assembly)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.threedee = async (script, debug) => {
|
||||||
|
const compiled = await new Promise((resolve, reject) => {
|
||||||
|
jscad.compile(script, {}).then(compiled => {
|
||||||
|
resolve(compiled)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const result = {
|
||||||
|
stl: jscad.generateOutput('stla', compiled).asBuffer()
|
||||||
|
}
|
||||||
|
if (debug) {
|
||||||
|
result.jscad = script
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
45
src/kle.js
Normal file
45
src/kle.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
const kle = require('kle-serial')
|
||||||
|
|
||||||
|
exports.convert = (config, logger) => {
|
||||||
|
const keyboard = kle.Serial.deserialize(config)
|
||||||
|
const result = {points: {zones: {}}}
|
||||||
|
|
||||||
|
let index = 1
|
||||||
|
for (const key of keyboard.keys) {
|
||||||
|
const id = `key${index++}`
|
||||||
|
const colid = `${id}col`
|
||||||
|
const rowid = `${id}row`
|
||||||
|
|
||||||
|
// need to account for keycap sizes, as KLE anchors
|
||||||
|
// at the corners, while we consider the centers
|
||||||
|
const x = key.x + (key.width - 1) / 2
|
||||||
|
const y = key.y + (key.height - 1) / 2
|
||||||
|
|
||||||
|
// KLE deals in absolute rotation origins so we calculate
|
||||||
|
// a relative difference as an origin for the column rotation
|
||||||
|
// again, considering corner vs. center with the extra half width/height
|
||||||
|
const diff_x = key.rotation_x - (key.x + key.width / 2)
|
||||||
|
const diff_y = key.rotation_y - (key.y + key.height / 2)
|
||||||
|
|
||||||
|
const converted = {
|
||||||
|
anchor: {
|
||||||
|
shift: [`${x} u`, `${-y} u`],
|
||||||
|
},
|
||||||
|
columns: {}
|
||||||
|
}
|
||||||
|
converted.columns[colid] = {
|
||||||
|
rotate: -key.rotation_angle,
|
||||||
|
origin: [`${diff_x} u`, `${-diff_y} u`],
|
||||||
|
rows: {}
|
||||||
|
}
|
||||||
|
converted.columns[colid].rows[rowid] = {
|
||||||
|
width: key.width,
|
||||||
|
height: key.height,
|
||||||
|
label: key.labels[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
result.points.zones[id] = converted
|
||||||
|
}
|
||||||
|
|
||||||
|
return [result, 'KLE']
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue