diff --git a/src/app/core/operations/bitfield/bitfield.ts b/src/app/core/operations/bitfield/bitfield.ts new file mode 100644 index 000000000..df9bb9d93 --- /dev/null +++ b/src/app/core/operations/bitfield/bitfield.ts @@ -0,0 +1,86 @@ +import { + NumParam, + StringParam, + OpParamVal, + OpInput, + Operation, +} from "../../model/datatypes"; +import { getOpParamValById } from "../../model/operations"; +import { Sequence } from "../../model/sequence"; +import { initDraftFromDrawdown } from "../../model/drafts"; +import { evaluate } from "mathjs"; + +const name = "bitfield"; +const old_names = []; + +//PARAMS +const warps: NumParam = { + name: "num warps", + type: "number", + min: 1, + max: 128, + value: 32, + dx: "Number of warps", +}; + +const wefts: NumParam = { + name: "num warps", + type: "number", + min: 1, + max: 128, + value: 32, + dx: "Number of wefts", +}; + +const f: StringParam = { + name: "bitfield function", + type: "string", + regex: /.*/, + error: "Invalid expression", + value: "(x ^ y) % 3", + dx: "Maths expression that uses x/y values to return a boolean value for each cell, to make 'bitfield' patterns", +}; + +const params = [warps, wefts, f]; + +const inlets = []; + +const perform = (param_vals: Array, op_inputs: Array) => { + const num_warps: number = getOpParamValById(0, param_vals); + const num_wefts: number = getOpParamValById(1, param_vals); + let script: string = getOpParamValById(2, param_vals); + + // Mathjs uses ^ for pow, and ^| for bitwise xor + // This replaces ^ with ^|, so folks don't have to type the | + script = script.replace(/\^(?!\|)/, "^|"); + + // Evaluate as an expression with mathjs. This could just be done with a javascript eval(), but this is more secure. + let func = evaluate("f(x, y) = ".concat(script)); + + let pattern = new Sequence.TwoD(); + for (let weft = 0; weft < num_wefts; ++weft) { + const row = new Sequence.OneD(); + for (let warp = 0; warp < num_warps; ++warp) { + row.push(!!func(warp, weft)); + } + pattern.pushWeftSequence(row.val()); + } + return Promise.resolve([initDraftFromDrawdown(pattern.export())]); +}; + +const generateName = ( + param_vals: Array, + op_inputs: Array +): string => { + const num_up: number = getOpParamValById(0, param_vals); + return num_up + "/bitfield"; +}; + +export const bitfield: Operation = { + name, + old_names, + params, + inlets, + perform, + generateName, +}; diff --git a/src/app/core/provider/operation.service.ts b/src/app/core/provider/operation.service.ts index a5ac59faf..1a752a367 100644 --- a/src/app/core/provider/operation.service.ts +++ b/src/app/core/provider/operation.service.ts @@ -73,6 +73,7 @@ import {flip} from '../operations/flip/flip' import { glitchsatin } from '../operations/glitchsatin/glitchsatin'; import { apply_warp_mats } from '../operations/applywarpmaterials/applywarpmaterials'; import { apply_weft_mats } from '../operations/applyweftmaterials/applyweftmaterials'; +import {bitfield} from '../operations/bitfield/bitfield'; @Injectable({ providedIn: 'root' @@ -172,6 +173,7 @@ export class OperationService { this.ops.push(sawtooth); this.ops.push(glitchsatin) // this.ops.push(hydra) + this.ops.push(bitfield); } diff --git a/src/assets/json/op_classifications.json b/src/assets/json/op_classifications.json index 8e879f753..a96ebd358 100644 --- a/src/assets/json/op_classifications.json +++ b/src/assets/json/op_classifications.json @@ -19,7 +19,8 @@ "sine", "sawtooth", "satinish", - "glitchsatin" + "glitchsatin", + "bitfield" ] }, diff --git a/src/assets/json/op_descriptions.json b/src/assets/json/op_descriptions.json index 1784060dd..43e5a1f16 100644 --- a/src/assets/json/op_descriptions.json +++ b/src/assets/json/op_descriptions.json @@ -525,10 +525,14 @@ "tags": ["advanced"], "description": "Create a drawdown from the input drafts (order 1. threading, 2. tieup, 3.lift plan)", "application": "To create drawdown from from a direct loom plan" - } - - - + }, + { + "name":"bitfield", + "tags": ["advanced"], + "displayname": "bitfield", + "description": "Takes a function from x and y values to boolean result, and applies it to each x/y position to generate a draft.", + "application": "For 'bitfield'-style generation of drafts that look like alien art, inspired by a post by Martin Kleppe on what used to be known as twitter." + } ], "param": [