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",
|
||||
"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",
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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
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