better default script
This commit is contained in:
@@ -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={}})=>{
|
||||||
|
|||||||
@@ -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})))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
const getParameterDefinitions = () => {
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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: 'Hook’s “thickness” = object\’s width = print’s 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:' },
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
module.exports = {main, getParameterDefinitions}
|
return jscad.booleans.subtract(model, ...rest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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}
|
||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user