better default script

This commit is contained in:
Davor Hrg
2021-08-23 11:49:38 +02:00
parent b4cdd3e1ef
commit 9aa686b4a4
2 changed files with 222 additions and 45 deletions

View File

@@ -235,7 +235,148 @@ const cmdHandler = (handlers)=>(cmd)=>{
function parseParams(script){
let lines = script.split('\n').map(l=>l.trim())
lines = lines.map((l,i)=>{
return {code:l, line:i+1, group: l[0] == '/' && !lines[i+1]}
}).filter(l=>l.code)
let i = 0, line, next, lineNum
while(i<lines.length){
line = lines[i].code.trim()
i++
if(line.length>12 && line.substring(line.length-13) == '//jscadparams') break;
if(line.length>12 && line.indexOf('@jscad-params') != -1) break;
}
let groupIndex = 1
const defs = []
while(i<lines.length){
line = lines[i].code
lineNum = lines[i].line
next = lines[i+1] ? lines[i+1].code : ''
if(line[0] === '}') break
if(line[0] === '/'){
// group
const def = parseComment(line, lineNum)
let name = '_group_' +(groupIndex++)
let caption = def.caption
const idx = caption.lastIndexOf(':')
if(idx !== -1){
name = caption.substring(idx+1).trim()
caption = caption.substring(0,idx).trim()
}
defs.push({name, type: 'group', caption, ...def.options})
}else{
const idx = line.indexOf('/')
if(idx === -1){
const def = parseDef(line, lineNum)
def.caption = def.name
defs.push(def)
}else{
defs.push(parseOne(
line.substring(idx).trim(),
line.substring(0,idx).trim(),
lineNum,lineNum
))
}
}
i++
}
return defs
}
function parseOne(comment, code, line1, line2){
const {caption, options} = parseComment(comment, line1)
let def = {caption, ...parseDef(code, line2)}
def.caption = def.caption || def.name
if(options){
def = {...def, ...options}
if(def.type === 'checkbox' && def.hasOwnProperty('initial')) def.checked = true
if(def.type === 'slider'){
if(def.min === undefined){
def.min=0
}
if(def.max === undefined){
def.max = def.initial * 2 ||100
}
}
}
return def;
}
function parseComment(comment, line){
const prefix = comment.substring(0,2)
if(prefix === '//') comment = comment.substring(2)
if(prefix === '/*') comment = comment.substring(2, comment.length-2)
comment = comment.trim()
const ret = {}
const idx = comment.indexOf('{')
if(idx !== -1){
try{
ret.options = eval('('+comment.substring(idx)+')')
}catch(e){
console.log('Error in line '+line);
console.log(comment);
throw e
}
comment = comment.substring(0,idx).trim()
}
ret.caption = comment
return ret
}
function parseDef(code, line){
if(code[code.length-1] == ',') code = code.substring(0,code.length-1).trim()
let idx = code.indexOf('=')
if(idx == -1) idx = code.indexOf(':')
if(idx == -1){
return {name:code, type:'text'}
}else{
let initial = code.substring(idx+1).trim()
const ret = {type:'text', name:code.substring(0,idx).trim()}
if(initial === 'true' || initial === 'false'){
ret.type = 'checkbox'
ret.checked = initial === 'true'
}else if(/^[0-9]+$/.test(initial)){
ret.type = 'int'
ret.initial = parseFloat(initial)
}else if(/^[0-9]+\.[0-9]+$/.test(initial)){
ret.type = 'number'
ret.initial = parseFloat(initial)
}else{
try {
ret.initial = eval(initial)
} catch (e) {
console.log('Error in line '+line);
console.log(code);
console.log('problem evaluating inital value:', initial)
e = new EvalError(e.message, 'code', line);
e.lineNumber = line
throw e
}
}
return ret
}
}
@@ -243,12 +384,24 @@ const cmdHandler = (handlers)=>(cmd)=>{
const makeScriptWorker = ({callback, convertToSolids})=>{ const makeScriptWorker = ({callback, convertToSolids})=>{
let workerBaseURI, onInit let workerBaseURI, onInit
function runMain(params={}){ function runMain(params={}){
let time = Date.now() let time = Date.now()
let solids let solids
let transfer = [] let transfer = []
try{ try{
solids = main(params) let tmp = main(params)
solids = []
function flatten(arr){
if(arr){
if(arr instanceof Array)
arr.forEach(flatten)
else
solids.push(arr)
}
}
flatten(tmp)
}catch(e){ }catch(e){
callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}, transfer) callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}, transfer)
return return
@@ -258,7 +411,7 @@ const makeScriptWorker = ({callback, convertToSolids})=>{
if(convertToSolids === 'buffers'){ if(convertToSolids === 'buffers'){
CSGToBuffers.clearCache() CSGToBuffers.clearCache()
entities = solids.map((csg)=>{ entities = solids.filter(s=>s).map((csg)=>{
let obj = CSGToBuffers(csg, transfer) let obj = CSGToBuffers(csg, transfer)
obj.color = csg.color obj.color = csg.color
obj.transforms = csg.transforms obj.transforms = csg.transforms
@@ -290,9 +443,20 @@ const makeScriptWorker = ({callback, convertToSolids})=>{
} }
main = script_module.exports.main main = script_module.exports.main
let gp = script_module.exports.getParameterDefinitions let gp = script_module.exports.getParameterDefinitions
let paramsDef = parseParams(script) || []
if(gp){ if(gp){
callback({action:'parameterDefinitions', worker:'main', data:gp()}) gp().forEach(p=>{
let idx = paramsDef.findIndex(old=>old.name == p.name)
if(idx === -1){
paramsDef.push(p)
}else{
paramsDef.splice(idx,1,p)
} }
})
}
console.log('paramsDef', paramsDef)
if(paramsDef.length) callback({action:'parameterDefinitions', worker:'main', data:paramsDef})
runMain(params) runMain(params)
}, },
updateParams: ({params={}})=>{ updateParams: ({params={}})=>{

View File

@@ -48,56 +48,69 @@ result = (cq.Workplane().circle(diam).extrude(20.0)
show_object(result) show_object(result)
`, `,
jscad: ` jscad: `
const jscad = require('@jscad/modeling')
// https://openjscad.xyz/docs/module-modeling_primitives.html
const { circle, rectangle, cube, cuboid, sphere, cylinder } = jscad.primitives
const { booleans, colors, primitives } = require('@jscad/modeling') // modeling comes from the included MODELING library const { rotate, scale } = jscad.transforms
const { degToRad } = jscad.utils // because jscad uses radians for rotations
const { colorize } = jscad.colors
// https://openjscad.xyz/docs/module-modeling_booleans.html
const { union, intersect } = jscad.booleans
const { intersect, subtract } = booleans // guessing where are those holes if miscalculated can ba a pain
const { colorize } = colors // use this to preview the subtract.
const { cube, cuboid, line, sphere, star } = primitives // it is also massively faster than the actual subtract (so it may help while testing)
let previewSubtract = false
const main = ({length=200}) => { function main({//@jscad-params
const logo = [ // Box example
colorize([1.0, 0.4, 1.0], subtract( width=40, // Width
cube({ size: 75 }), length=20, // Length
sphere({ radius: 50 }) height=10, // Height
)), hole=3,// Hole for cables diameter (0=no hole)
colorize([1.0, 1.0, 0], intersect( wall=1, // wall {min:0.5, step:0.5}
sphere({ radius: 32 }), }){
cube({ size: 50 })
))
]
const transpCube = colorize([1, 0, 0, 0.75], cuboid({ size: [30, 30, length] })) let wallOffset = wall * 2
const star2D = star({ vertices: 8, innerRadius: 38, outerRadius: 60 }) let model = subtract(
const line2D = colorize([1.0, 0, 0], line([[70, 70], [-70, 70], [-70, -70], [70, -70], [70, 70]])) cuboid({size:[width, length, height]}),
translate([0,0,wall], cuboid({size:[width-wallOffset, length-wallOffset, height+wall]})),
return [transpCube, star2D, line2D, ...logo] )
if(hole){
model = subtract( model,
translate([width/2-wall/2], rotate([0, degToRad(90), 0 ], cylinder({radius:hole/2, height:wall})))
)
}
return model
} }
const getParameterDefinitions = () => {
// subtract with preview ability
function subtract(model, ...rest){
if(previewSubtract){
return [ return [
{type:'slider', name:'length', initial:200, caption:'Length', min:100, max:500}, ...rest,
{ name: 'group1', type: 'group', caption: 'Group 1: Text Entry' }, colorize([1,1,1,0.5],model),
{ name: 'text', type: 'text', initial: '', size: 20, maxLength: 20, caption: 'Hooks “thickness” = object\s width = prints height', placeholder: '20 characters' },
{ name: 'int', type: 'int', initial: 20, min: 1, max: 100, step: 1, caption: 'Integer:' },
{ name: 'number', type: 'number', initial: 2.0, min: 1.0, max: 10.0, step: 0.1, caption: 'Number:' },
{ name: 'date', type: 'date', initial: '2020-01-01', min: '2020-01-01', max: '2030-12-31', caption: 'Choose between classic hook with screw holes (0) or “bracket” system (1)', placeholder: 'YYYY-MM-DD' },
{ name: 'email', type: 'email', initial: 'me@example.com', caption: 'Email:' },
{ name: 'url', type: 'url', initial: 'www.example.com', size: 40, maxLength: 40, caption: 'Url:', placeholder: '40 characters' },
{ name: 'password', type: 'password', initial: '', caption: 'Password:' },
{ name: 'group2', type: 'group', caption: 'Group 2: Interactive Controls' },
{ name: 'checkbox', type: 'checkbox', checked: true, initial: '20', caption: 'Checkbox:' },
{ name: 'color', type: 'color', initial: '#FFB431', caption: 'Color:' },
{ name: 'slider', type: 'slider', initial: 3, min: 1, max: 10, step: 1, caption: 'Slider:' },
{ name: 'choice1', type: 'choice', caption: 'Dropdown Menu:', values: [0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 2 },
{ name: 'choice3', type: 'choice', caption: 'Dropdown Menu:', values: ['No', 'Yes', 'Maybe', 'So so'], initial: 'No' },
{ name: 'choice2', type: 'radio', caption: 'Radio Buttons:', values:[0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 2 },
{ name: 'group3', type: 'group', initial: 'closed', caption: 'Group 3: Initially Closed Group' },
{ name: 'checkbox2', type: 'checkbox', checked: true, initial: '20', caption: 'Optional Checkbox:' },
] ]
}
return jscad.booleans.subtract(model, ...rest)
} }
module.exports = {main, getParameterDefinitions}
// FIX for color retention for translate until jscad improves transforms
function translate(xyz, ...models){
return jscad.utils.flatten(models).map(m=>{
let color = m.color
let out = jscad.transforms.translate(xyz,m)
out.color = color
return out
})
}
module.exports = {main}
`, `,
} }