Outlines rewrite actually done

This commit is contained in:
Bán Dénes 2022-01-16 20:36:19 +01:00
parent 4844a044df
commit d6f83232a8
23 changed files with 288 additions and 1034 deletions

View file

@ -1,9 +1,11 @@
const u = require('./utils')
const a = require('./assert')
const anchor_lib = require('./anchor')
const Point = require('./point')
const anchor = anchor_lib.parse
const _true = () => true
const _false = () => false
const _and = arr => p => arr.map(e => e(p)).reduce((a, b) => a && b)
const _or = arr => p => arr.map(e => e(p)).reduce((a, b) => a || b)
@ -78,20 +80,19 @@ const simple = (exp, name, units) => {
const complex = (config, name, units, aggregator=_or) => {
// default is all points
if (config === undefined) {
return _true
}
// otherwise we branch by type
const type = a.type(config)()
// we branch by type
const type = a.type(config)(units)
switch(type) {
// boolean --> either all or nothing
case 'boolean':
return config ? _true : _false
// base case is a string, meaning a simple/single filter
// string --> base case, meaning a simple/single filter
case 'string':
return simple(config, name, units)
// arrays are aggregated with alternating and/or conditions
// array --> aggregated simple filters with alternating and/or conditions
case 'array':
const alternate = aggregator == _and ? _or : _and
return aggregator(config.map(elem => complex(elem, name, units, alternate)))
@ -101,12 +102,22 @@ const complex = (config, name, units, aggregator=_or) => {
}
}
const contains_object = (val) => {
if (a.type(val)() == 'object') return true
if (a.type(val)() == 'array') return val.some(el => contains_object(el))
return false
}
exports.parse = (config, name, points={}, units={}, include_mirrors=false) => {
let result = []
// if a filter decl is an object, it is an anchor
if (a.type(config)() == 'object') {
// if a filter decl is undefined, it's just the default point at [0, 0]
if (config === undefined) {
result.push(new Point())
// if a filter decl is an object, or an array that contains an object at any depth, it is an anchor
} else if (contains_object(config)) {
result.push(anchor(config, name, points)(units))
if (include_mirrors) {
// this is strict: if the ref of the anchor doesn't have a mirror pair, it will error out

View file

@ -32,16 +32,16 @@ const rectangle = (config, name, points, outlines, units) => {
// prepare params
a.unexpected(config, `${name}`, ['size', 'corner', 'bevel'])
const size = a.wh(params.size, `${export_name}.size`)(units)
const size = a.wh(config.size, `${name}.size`)(units)
const rec_units = prep.extend({
sx: size[0],
sy: size[1]
}, units)
const corner = a.sane(params.corner || 0, `${export_name}.corner`, 'number')(rec_units)
const bevel = a.sane(params.bevel || 0, `${export_name}.bevel`, 'number')(rec_units)
const corner = a.sane(config.corner || 0, `${name}.corner`, 'number')(rec_units)
const bevel = a.sane(config.bevel || 0, `${name}.bevel`, 'number')(rec_units)
// return shape function
return (point, bound) => {
// return shape function and its units
return [(point, bound) => {
const error = (dim, val) => `Rectangle for "${name}" isn't ${dim} enough for its corner and bevel (${val} - 2 * ${corner} - 2 * ${bevel} <= 0)!`
const [w, h] = size
@ -65,7 +65,7 @@ const rectangle = (config, name, points, outlines, units) => {
])
}
if (corner > 0) rect = m.model.outline(rect, corner, 0)
rect = m.model.moveRelative(res, [-cw/2, -ch/2])
rect = m.model.moveRelative(rect, [-cw/2, -ch/2])
if (bound) {
const bbox = {high: [w/2, h/2], low: [-w/2, -h/2]}
rect = binding(rect, bbox, point, rec_units)
@ -73,7 +73,7 @@ const rectangle = (config, name, points, outlines, units) => {
rect = point.position(rect)
return rect
}
}, rec_units]
}
const circle = (config, name, points, outlines, units) => {
@ -85,8 +85,8 @@ const circle = (config, name, points, outlines, units) => {
r: radius
}, units)
// return shape function
return (point, bound) => {
// return shape function and its units
return [(point, bound) => {
let circle = u.circle([0, 0], radius)
if (bound) {
const bbox = {high: [radius, radius], low: [-radius, -radius]}
@ -94,7 +94,7 @@ const circle = (config, name, points, outlines, units) => {
}
circle = point.position(circle)
return circle
}
}, circ_units]
}
const polygon = (config, name, points, outlines, units) => {
@ -103,10 +103,12 @@ const polygon = (config, name, points, outlines, units) => {
a.unexpected(config, `${name}`, ['points'])
const poly_points = a.sane(config.points, `${name}.points`, 'array')()
// return shape function
return (point, bound) => {
// return shape function and its units
return [(point, bound) => {
const parsed_points = []
let last_anchor = new Point()
// the point starts at [0, 0] as it will be positioned later
// but we keep the metadata for potential mirroring purposes
let last_anchor = new Point(0, 0, 0, point.meta)
let poly_index = -1
for (const poly_point of poly_points) {
const poly_name = `${name}.points[${++poly_index}]`
@ -120,7 +122,7 @@ const polygon = (config, name, points, outlines, units) => {
}
poly = point.position(poly)
return poly
}
}, units]
}
const outline = (config, name, points, outlines, units) => {
@ -131,10 +133,10 @@ const outline = (config, name, points, outlines, units) => {
const fillet = a.sane(config.fillet || 0, `${name}.fillet`, 'number')(units)
const expand = a.sane(config.expand || 0, `${name}.expand`, 'number')(units)
const joints = a.in(a.sane(config.joints || 0, `${name}.joints`, 'number')(units), `${name}.joints`, [0, 1, 2])
const origin = anchor(config.origin, `${name}.origin`, points)(units)
const origin = anchor(config.origin || {}, `${name}.origin`, points)(units)
// return shape function
return (point, bound) => {
// return shape function and its units
return [(point, bound) => {
let o = u.deepcopy(outlines[config.name])
o = origin.unposition(o)
@ -155,7 +157,7 @@ const outline = (config, name, points, outlines, units) => {
o = point.position(o)
return o
}
}, units]
}
const whats = {
@ -182,11 +184,11 @@ exports.parse = (config = {}, points = {}, units = {}) => {
if (a.type(parts)() == 'array') {
parts = {...parts}
}
parts = a.sane(parts, `outlines.${key}`, 'object')()
parts = a.sane(parts, `outlines.${outline_name}`, 'object')()
for (let [part_name, part] of Object.entries(parts)) {
const name = `outlines.${key}.${part_name}`
const name = `outlines.${outline_name}.${part_name}`
// string part-shortcuts are expanded first
if (a.type(part)() == 'string') {
@ -200,8 +202,9 @@ exports.parse = (config = {}, points = {}, units = {}) => {
const bound = part.bound === undefined ? bound_by_default.includes(what) : !!part.bound
const mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')()
// `where` is delayed until we have all, potentially what-dependent units
// default where is the single default anchor (at [0,0])
const where = units => filter(part.where || {}, `${name}.where`, points, units, mirror)
// default where is [0, 0], as per filter parsing
const original_where = part.where // need to save, so the delete's don't get rid of it below
const where = units => filter(original_where, `${name}.where`, points, units, mirror)
// these keys are then removed, so ops can check their own unexpected keys without interference
delete part.operation