1
0

Basic KLE support

This commit is contained in:
Bán Dénes 2021-07-15 21:36:44 +02:00
parent d09b3fdf38
commit 1cb9fdc3c2
5 changed files with 154 additions and 77 deletions

21
package-lock.json generated
View File

@ -12,7 +12,8 @@
"fs-extra": "^9.0.1",
"js-yaml": "^3.14.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",
"yargs": "^15.4.1"
},
@ -1805,6 +1806,15 @@
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-2.0.1.tgz",
"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": {
"version": "5.0.0",
"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",
"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": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@ -4764,7 +4781,7 @@
"makerjs": {
"version": "git+ssh://git@github.com/mrzealot/maker.js-dist.git#a0ca32948845efe8ad5c9ca454f1285926853138",
"integrity": "sha512-MsYj7ch7Et7He/Nsd2BLvoPsJlyUoi7KkLyiqP0ap0ff+LcrdyKCqpr9vpudthaHjMmsWeVuPb0HnzfYbGw1wQ==",
"from": "makerjs@github:mrzealot/maker.js-dist#a0ca32948845efe8ad5c9ca454f1285926853138",
"from": "makerjs@github:mrzealot/maker.js-dist",
"requires": {
"@danmarshall/jscad-typings": "^1.0.0",
"@types/bezier-js": "^0.0.6",

View File

@ -15,11 +15,12 @@
"coverage": "nyc --reporter=html --reporter=text npm test"
},
"dependencies": {
"kle-serial": "github:mrzealot/kle-serial",
"@jscad/openjscad": "^1.6.1",
"fs-extra": "^9.0.1",
"js-yaml": "^3.14.0",
"json5": "^2.2.0",
"makerjs": "github:mrzealot/maker.js-dist#a0ca32948845efe8ad5c9ca454f1285926853138",
"makerjs": "github:mrzealot/maker.js-dist",
"mathjs": "^8.1.1",
"yargs": "^15.4.1"
},

View File

@ -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 io = require('./io')
const prepare = require('./prepare')
const units_lib = require('./units')
const points_lib = require('./points')
@ -13,79 +7,20 @@ const outlines_lib = require('./outlines')
const cases_lib = require('./cases')
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 = {
version: '__ergogen_version',
process: async (raw, debug=false, logger=noop) => {
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!')
}
}
process: async (raw, debug=false, logger=()=>{}) => {
let [config, format] = io.interpret(raw, logger)
logger('Interpreting format: ' + format)
logger('Preprocessing input...')
config = prepare.unnest(config)
config = prepare.inherit(config)
const results = {}
if (debug) {
results.raw = raw
results.canonical = config
results.canonical = u.deepcopy(config)
}
logger('Calculating variables...')
@ -94,6 +29,7 @@ module.exports = {
results.units = units
}
logger('Parsing points...')
if (!config.points) {
throw new Error('Input does not contain any points!')
@ -101,7 +37,7 @@ module.exports = {
const points = points_lib.parse(config.points, units)
if (debug) {
results.points = points
results.demo = twodee(points_lib.visualize(points), debug)
results.demo = io.twodee(points_lib.visualize(points), debug)
}
logger('Generating outlines...')
@ -109,7 +45,7 @@ module.exports = {
results.outlines = {}
for (const [name, outline] of Object.entries(outlines)) {
if (!debug && name.startsWith('_')) continue
results.outlines[name] = twodee(outline, debug)
results.outlines[name] = io.twodee(outline, debug)
}
logger('Extruding cases...')
@ -117,7 +53,7 @@ module.exports = {
results.cases = {}
for (const [case_name, case_script] of Object.entries(cases)) {
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...')

78
src/io.js Normal file
View 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
View 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']
}