From 294e1560cafebdc087160cfab4cb80040f61bebd Mon Sep 17 00:00:00 2001 From: Tom Brewe Date: Tue, 3 Jul 2018 11:53:26 +0200 Subject: [PATCH] bump version and prepare for new release. --- dist/lindenmayer.browser.js | 37 ++++++++++++++++----------------- dist/lindenmayer.browser.min.js | 2 +- dist/lindenmayer.es.js | 37 ++++++++++++++++----------------- dist/lindenmayer.es.min.js | 2 +- dist/lindenmayer.js | 37 ++++++++++++++++----------------- dist/lindenmayer.min.js | 2 +- docs/examples/lindenmayer.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 9 files changed, 60 insertions(+), 63 deletions(-) diff --git a/dist/lindenmayer.browser.js b/dist/lindenmayer.browser.js index aec76fa..4220cc8 100644 --- a/dist/lindenmayer.browser.js +++ b/dist/lindenmayer.browser.js @@ -180,7 +180,10 @@ class LSystem { setProduction(from, to, allowAppendingMultiSuccessors = false) { let newProduction = [from, to]; - if (newProduction === undefined) throw new Error('no production specified.'); + + if (newProduction === undefined) { + throw new Error('no production specified.'); + } if (to.successor && to.successors) { throw new Error('You can not have both a "successor" and a "successors" field in your production!'); @@ -224,7 +227,6 @@ class LSystem { } // set multiple productions from name:value Object - // TODO: ALLOW TUPLE/ARRAY setProductions(newProductions) { if (newProductions === undefined) throw new Error('no production specified.'); this.clearProductions(); @@ -279,6 +281,12 @@ class LSystem { index: index, branchSymbols: this.branchSymbols, ignoredSymbols: this.ignoredSymbols + }).result && this.match({ + direction: 'right', + match: p.rightCtx, + index: index, + branchSymbols: this.branchSymbols, + ignoredSymbols: this.ignoredSymbols }).result; } else if (p.leftCtx !== undefined) { precheck = this.match({ @@ -307,7 +315,7 @@ class LSystem { // If p has multiple successors else if (p.successors) { // This could be stochastic successors or multiple functions - // Tread every element in the list as an individual production object + // Treat every element in the list as an individual production object // For stochastic productions (if all prods in the list have a 'weight' property) // Get a random number then pick a production from the list according to their weight @@ -331,11 +339,8 @@ class LSystem { // and evaluated recursively because it , kax also have rightCtx, leftCtx and condition to further inhibit production. This is not standard L-System behaviour though! // last true is for recursiv call - // TODO: refactor getProductionResult to use an object + // TODO: refactor getProductionResult to use an object if not a hit on perf let _result = this.getProductionResult(_p, index, part, params, true); - // console.log(part, p.successors); - // console.log(result); - // console.log("\n"); if (_result !== undefined && _result !== false) { result = _result; break; @@ -344,7 +349,6 @@ class LSystem { } // if successor is a function, execute function and append return value else if (typeof p.successor === 'function') { - result = p.successor({ index, currentAxiom: this.axiom, part, params }); } else { result = p.successor; @@ -382,7 +386,7 @@ class LSystem { newAxiom += result; } else if (result instanceof Array) { // If result is an array, merge result into new axiom instead of pushing. - Array.prototype.push.apply(newAxiom, result); + newAxiom.push(...result); } else { newAxiom.push(result); } @@ -436,22 +440,17 @@ class LSystem { If you use the classic syntax, it will by default be automatically transformed to proper JS-Syntax. Howerver, you can use the match helper function in your on productions: - - index is the index of a production using `match` + index is the index of a production using `match` eg. in a classic L-System - - LSYS = ABCDE + LSYS = ABCDE BDE -> 'Z' - - the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the + the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the production would perform match(). so (if not using the ClassicLSystem class) you'd construction your context-sensitive production from C to Z like so: - - LSYS.setProduction('C', (index, axiom) => { + LSYS.setProduction('C', (index, axiom) => { (LSYS.match({index, match: 'B', direction: 'left'}) && LSYS.match({index, match: 'DE', direction: 'right'}) ? 'Z' : 'C') }) - - You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 + You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 */ match({ axiom_, match, ignoredSymbols, branchSymbols, index, direction }) { diff --git a/dist/lindenmayer.browser.min.js b/dist/lindenmayer.browser.min.js index f4f0e3e..3ce9c83 100644 --- a/dist/lindenmayer.browser.min.js +++ b/dist/lindenmayer.browser.min.js @@ -1 +1 @@ -var LSystem=function(){"use strict";function t(t){let s,i=t[0].match(/(.+)<(.)/),o=t[0].match(/(.)>(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function s(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function i(t,i){return t[1]=function t(i,o){if(i.hasOwnProperty("successors"))for(var e=0;e{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(s,o,e=!1){let r=[s,o];if(void 0===r)throw new Error("no production specified.");if(o.successor&&o.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(r=t(r)),(r=i(r,this.forceObjects))[1].isStochastic=void 0!==r[1].successors&&r[1].successors.every(t=>void 0!==t.weight),r[1].isStochastic){r[1].weightSum=0;for(let t of r[1].successors)r[1].weightSum+=t.weight}let n=r[0];if(!0===e&&this.productions.has(n)){let t=this.productions.get(n),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(r[1]),this.productions.set(n,t)}else this.productions.set(n,r[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var b=o;l=b[0],a=b[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(y.push(h),f+=m)),f===d)return{result:!0,matchIndices:y}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:y}}return{result:!1,matchIndices:y}}}return LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=function(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function s(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function i(t,i){return t[1]=function t(i,o){if(i.hasOwnProperty("successors"))for(var e=0;e{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(s,o,e=!1){let r=[s,o];if(void 0===r)throw new Error("no production specified.");if(o.successor&&o.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(r=t(r)),(r=i(r,this.forceObjects))[1].isStochastic=void 0!==r[1].successors&&r[1].successors.every(t=>void 0!==t.weight),r[1].isStochastic){r[1].weightSum=0;for(let t of r[1].successors)r[1].weightSum+=t.weight}let n=r[0];if(!0===e&&this.productions.has(n)){let t=this.productions.get(n),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(r[1]),this.productions.set(n,t)}else this.productions.set(n,r[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result&&this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var y=o;l=y[0],a=y[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(b.push(h),f+=m)),f===d)return{result:!0,matchIndices:b}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:b}}return{result:!1,matchIndices:b}}}return LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=function(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;tDE -> 'Z' - - the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the + the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the production would perform match(). so (if not using the ClassicLSystem class) you'd construction your context-sensitive production from C to Z like so: - - LSYS.setProduction('C', (index, axiom) => { + LSYS.setProduction('C', (index, axiom) => { (LSYS.match({index, match: 'B', direction: 'left'}) && LSYS.match({index, match: 'DE', direction: 'right'}) ? 'Z' : 'C') }) - - You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 + You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 */ match({ axiom_, match, ignoredSymbols, branchSymbols, index, direction }) { diff --git a/dist/lindenmayer.es.min.js b/dist/lindenmayer.es.min.js index ff252e9..521f161 100644 --- a/dist/lindenmayer.es.min.js +++ b/dist/lindenmayer.es.min.js @@ -1 +1 @@ -function t(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function e(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function r(t,s){if(t.hasOwnProperty("successors"))for(var i=0;i{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(t,s,i=!1){let e=[t,s];if(void 0===e)throw new Error("no production specified.");if(s.successor&&s.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(e=o(e)),(e=n(e,this.forceObjects))[1].isStochastic=void 0!==e[1].successors&&e[1].successors.every(t=>void 0!==t.weight),e[1].isStochastic){e[1].weightSum=0;for(let t of e[1].successors)e[1].weightSum+=t.weight}let r=e[0];if(!0===i&&this.productions.has(r)){let t=this.productions.get(r),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(e[1]),this.productions.set(r,t)}else this.productions.set(r,e[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var b=o;l=b[0],a=b[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(y.push(h),f+=m)),f===d)return{result:!0,matchIndices:y}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:y}}return{result:!1,matchIndices:y}}}LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=t,LSystem.transformClassicCSProduction=o,LSystem.transformClassicParametricAxiom=i,LSystem.testClassicParametricSyntax=s;export default LSystem; +function t(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function e(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function r(t,s){if(t.hasOwnProperty("successors"))for(var i=0;i{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(t,s,i=!1){let e=[t,s];if(void 0===e)throw new Error("no production specified.");if(s.successor&&s.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(e=o(e)),(e=n(e,this.forceObjects))[1].isStochastic=void 0!==e[1].successors&&e[1].successors.every(t=>void 0!==t.weight),e[1].isStochastic){e[1].weightSum=0;for(let t of e[1].successors)e[1].weightSum+=t.weight}let r=e[0];if(!0===i&&this.productions.has(r)){let t=this.productions.get(r),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(e[1]),this.productions.set(r,t)}else this.productions.set(r,e[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result&&this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var y=o;l=y[0],a=y[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(b.push(h),f+=m)),f===d)return{result:!0,matchIndices:b}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:b}}return{result:!1,matchIndices:b}}}LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=t,LSystem.transformClassicCSProduction=o,LSystem.transformClassicParametricAxiom=i,LSystem.testClassicParametricSyntax=s;export default LSystem; diff --git a/dist/lindenmayer.js b/dist/lindenmayer.js index 0fa8b1b..6cc4185 100644 --- a/dist/lindenmayer.js +++ b/dist/lindenmayer.js @@ -179,7 +179,10 @@ class LSystem { setProduction(from, to, allowAppendingMultiSuccessors = false) { let newProduction = [from, to]; - if (newProduction === undefined) throw new Error('no production specified.'); + + if (newProduction === undefined) { + throw new Error('no production specified.'); + } if (to.successor && to.successors) { throw new Error('You can not have both a "successor" and a "successors" field in your production!'); @@ -223,7 +226,6 @@ class LSystem { } // set multiple productions from name:value Object - // TODO: ALLOW TUPLE/ARRAY setProductions(newProductions) { if (newProductions === undefined) throw new Error('no production specified.'); this.clearProductions(); @@ -278,6 +280,12 @@ class LSystem { index: index, branchSymbols: this.branchSymbols, ignoredSymbols: this.ignoredSymbols + }).result && this.match({ + direction: 'right', + match: p.rightCtx, + index: index, + branchSymbols: this.branchSymbols, + ignoredSymbols: this.ignoredSymbols }).result; } else if (p.leftCtx !== undefined) { precheck = this.match({ @@ -306,7 +314,7 @@ class LSystem { // If p has multiple successors else if (p.successors) { // This could be stochastic successors or multiple functions - // Tread every element in the list as an individual production object + // Treat every element in the list as an individual production object // For stochastic productions (if all prods in the list have a 'weight' property) // Get a random number then pick a production from the list according to their weight @@ -330,11 +338,8 @@ class LSystem { // and evaluated recursively because it , kax also have rightCtx, leftCtx and condition to further inhibit production. This is not standard L-System behaviour though! // last true is for recursiv call - // TODO: refactor getProductionResult to use an object + // TODO: refactor getProductionResult to use an object if not a hit on perf let _result = this.getProductionResult(_p, index, part, params, true); - // console.log(part, p.successors); - // console.log(result); - // console.log("\n"); if (_result !== undefined && _result !== false) { result = _result; break; @@ -343,7 +348,6 @@ class LSystem { } // if successor is a function, execute function and append return value else if (typeof p.successor === 'function') { - result = p.successor({ index, currentAxiom: this.axiom, part, params }); } else { result = p.successor; @@ -381,7 +385,7 @@ class LSystem { newAxiom += result; } else if (result instanceof Array) { // If result is an array, merge result into new axiom instead of pushing. - Array.prototype.push.apply(newAxiom, result); + newAxiom.push(...result); } else { newAxiom.push(result); } @@ -435,22 +439,17 @@ class LSystem { If you use the classic syntax, it will by default be automatically transformed to proper JS-Syntax. Howerver, you can use the match helper function in your on productions: - - index is the index of a production using `match` + index is the index of a production using `match` eg. in a classic L-System - - LSYS = ABCDE + LSYS = ABCDE BDE -> 'Z' - - the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the + the index of the `BD -> 'Z'` production would be the index of C (which is 2) when the production would perform match(). so (if not using the ClassicLSystem class) you'd construction your context-sensitive production from C to Z like so: - - LSYS.setProduction('C', (index, axiom) => { + LSYS.setProduction('C', (index, axiom) => { (LSYS.match({index, match: 'B', direction: 'left'}) && LSYS.match({index, match: 'DE', direction: 'right'}) ? 'Z' : 'C') }) - - You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 + You can just write match({index, ...} instead of match({index: index, ..}) because of new ES6 Object initialization, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_6 */ match({ axiom_, match, ignoredSymbols, branchSymbols, index, direction }) { diff --git a/dist/lindenmayer.min.js b/dist/lindenmayer.min.js index 07fcc8b..d009a68 100644 --- a/dist/lindenmayer.min.js +++ b/dist/lindenmayer.min.js @@ -1 +1 @@ -"use strict";function t(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function e(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function r(t,s){if(t.hasOwnProperty("successors"))for(var i=0;i{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(t,s,i=!1){let e=[t,s];if(void 0===e)throw new Error("no production specified.");if(s.successor&&s.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(e=o(e)),(e=n(e,this.forceObjects))[1].isStochastic=void 0!==e[1].successors&&e[1].successors.every(t=>void 0!==t.weight),e[1].isStochastic){e[1].weightSum=0;for(let t of e[1].successors)e[1].weightSum+=t.weight}let r=e[0];if(!0===i&&this.productions.has(r)){let t=this.productions.get(r),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(e[1]),this.productions.set(r,t)}else this.productions.set(r,e[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var b=o;l=b[0],a=b[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(y.push(h),f+=m)),f===d)return{result:!0,matchIndices:y}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:y}}return{result:!1,matchIndices:y}}}LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=t,LSystem.transformClassicCSProduction=o,LSystem.transformClassicParametricAxiom=i,LSystem.testClassicParametricSyntax=s,module.exports=LSystem; +"use strict";function t(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function e(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function r(t,s){if(t.hasOwnProperty("successors"))for(var i=0;i{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(t,s,i=!1){let e=[t,s];if(void 0===e)throw new Error("no production specified.");if(s.successor&&s.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(e=o(e)),(e=n(e,this.forceObjects))[1].isStochastic=void 0!==e[1].successors&&e[1].successors.every(t=>void 0!==t.weight),e[1].isStochastic){e[1].weightSum=0;for(let t of e[1].successors)e[1].weightSum+=t.weight}let r=e[0];if(!0===i&&this.productions.has(r)){let t=this.productions.get(r),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(e[1]),this.productions.set(r,t)}else this.productions.set(r,e[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result&&this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var y=o;l=y[0],a=y[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(b.push(h),f+=m)),f===d)return{result:!0,matchIndices:b}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:b}}return{result:!1,matchIndices:b}}}LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=t,LSystem.transformClassicCSProduction=o,LSystem.transformClassicParametricAxiom=i,LSystem.testClassicParametricSyntax=s,module.exports=LSystem; diff --git a/docs/examples/lindenmayer.js b/docs/examples/lindenmayer.js index f4f0e3e..3ce9c83 100644 --- a/docs/examples/lindenmayer.js +++ b/docs/examples/lindenmayer.js @@ -1 +1 @@ -var LSystem=function(){"use strict";function t(t){let s,i=t[0].match(/(.+)<(.)/),o=t[0].match(/(.)>(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function s(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function i(t,i){return t[1]=function t(i,o){if(i.hasOwnProperty("successors"))for(var e=0;e{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(s,o,e=!1){let r=[s,o];if(void 0===r)throw new Error("no production specified.");if(o.successor&&o.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(r=t(r)),(r=i(r,this.forceObjects))[1].isStochastic=void 0!==r[1].successors&&r[1].successors.every(t=>void 0!==t.weight),r[1].isStochastic){r[1].weightSum=0;for(let t of r[1].successors)r[1].weightSum+=t.weight}let n=r[0];if(!0===e&&this.productions.has(n)){let t=this.productions.get(n),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(r[1]),this.productions.set(n,t)}else this.productions.set(n,r[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var b=o;l=b[0],a=b[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(y.push(h),f+=m)),f===d)return{result:!0,matchIndices:y}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:y}}return{result:!1,matchIndices:y}}}return LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=function(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t(.+)/);if(null===i&&null===o)return t;let e=t[1].successor||t[1].successors?t[1]:{successor:t[1]};return null!==i&&(s=i[2],e.leftCtx=i[1]),null!==o&&(s=o[1],e.rightCtx=o[2]),[s,e]}function s(t){if("string"!=typeof t&&t instanceof String==!1)return t;let s=[];for(let i of t)s.push({symbol:i});return s}function i(t,i){return t[1]=function t(i,o){if(i.hasOwnProperty("successors"))for(var e=0;e{if(void 0===s.symbol)throw console.log("found:",s),new Error("L-Systems that use only objects as symbols (eg: {symbol: 'F', params: []}), cant use string symbols (eg. 'F')! Check if you always return objects in your productions and no strings.");return t+s.symbol},""):JSON.stringify(this.axiom)}setProduction(s,o,e=!1){let r=[s,o];if(void 0===r)throw new Error("no production specified.");if(o.successor&&o.successors)throw new Error('You can not have both a "successor" and a "successors" field in your production!');if(!0===this.allowClassicSyntax&&(r=t(r)),(r=i(r,this.forceObjects))[1].isStochastic=void 0!==r[1].successors&&r[1].successors.every(t=>void 0!==t.weight),r[1].isStochastic){r[1].weightSum=0;for(let t of r[1].successors)r[1].weightSum+=t.weight}let n=r[0];if(!0===e&&this.productions.has(n)){let t=this.productions.get(n),s=t.successor,i=t.successors;s&&!i&&(t={successors:[t]}),t.successors.push(r[1]),this.productions.set(n,t)}else this.productions.set(n,r[1])}setProductions(t){if(void 0===t)throw new Error("no production specified.");this.clearProductions();for(let s of Object.entries(t)){let t=s[0],i=s[1];this.setProduction(t,i,!0)}}clearProductions(){this.productions=new Map}setFinal(t,s){let i=[t,s];if(void 0===i)throw new Error("no final specified.");this.finals.set(i[0],i[1])}setFinals(t){if(void 0===t)throw new Error("no finals specified.");this.finals=new Map;for(let s in t)t.hasOwnProperty(s)&&this.setFinal(s,t[s])}getProductionResult(t,s,i,o,e=!1){let r=void 0!==t.leftCtx||void 0!==t.rightCtx,n=!1,c=!0;if(void 0!==t.condition&&!1===t.condition({index:s,currentAxiom:this.axiom,part:i,params:o})?c=!1:r&&(void 0!==t.leftCtx&&void 0!==t.rightCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result&&this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.leftCtx?c=this.match({direction:"left",match:t.leftCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result:void 0!==t.rightCtx&&(c=this.match({direction:"right",match:t.rightCtx,index:s,branchSymbols:this.branchSymbols,ignoredSymbols:this.ignoredSymbols}).result)),!1===c)n=!1;else if(t.successors){let e,r;t.isStochastic&&(r=Math.random()*t.weightSum,e=0);for(let c of t.successors){if(t.isStochastic&&(e+=c.weight)0){var g=o;a=g[0],l=g[1]}}else{if("left"!==r)throw Error(r,"is not a valid direction for matching.");if(u=m=-1,h=e-1,f=s.length-1,d=-1,o.length>0){var y=o;l=y[0],a=y[1]}}for(;h=0;h+=u){let o=t[h].symbol||t[h],e=s[f];if(o===e){if((0===n||c>0)&&(o===a?(c++,n++,f+=m):o===l?(c=Math.max(0,c-1),n=Math.max(0,n-1),0===c&&(f+=m)):(b.push(h),f+=m)),f===d)return{result:!0,matchIndices:b}}else if(o===a)n++,c>0&&c++;else if(o===l)n=Math.max(0,n-1),c>0&&(c=Math.max(0,c-1));else if((0===n||c>0&&e!==l)&&!1===i.includes(o))return{result:!1,matchIndices:b}}return{result:!1,matchIndices:b}}}return LSystem.getStringResult=LSystem.getString,LSystem.transformClassicStochasticProductions=function(t){return function(){let s=t,i=s.length,o=Math.random();for(let t=0;t", "license": "MIT", "keywords": [