From 4c1c56898047c1b56a3bbf5cfef9c1dd783966d6 Mon Sep 17 00:00:00 2001 From: Jonathan Wilkes <jon.w.wilkes@gmail.com> Date: Mon, 24 Oct 2016 20:45:52 -0400 Subject: [PATCH] add feature to "normalize" svg path data and pass it along as a FUDI message (e.g., "M0-2l3 4" becomes "M 0 -2 l 3 4") This gets triggered when the user include the "d=" and double quotes as the object args to [draw path]. So [draw path d="M0-2l3 4"] triggers a conversion to [draw path M 0 -2 l 3 4], whereas [draw path M0-2l3 4] does not. This is necessary because Pd lets the user include scalar fields inside path data, and we can't normalize that. --- pd/nw/parse-svg-path.js | 59 +++++++++++++++++++++++++++++++++++++++++ pd/nw/pd_canvas.js | 21 +++++++++++++++ pd/nw/pdgui.js | 4 +++ 3 files changed, 84 insertions(+) create mode 100644 pd/nw/parse-svg-path.js diff --git a/pd/nw/parse-svg-path.js b/pd/nw/parse-svg-path.js new file mode 100644 index 000000000..8cfc53bb0 --- /dev/null +++ b/pd/nw/parse-svg-path.js @@ -0,0 +1,59 @@ +// Grabbed hastily from https://github.com/jkroso/parse-svg-path +// MIT licensed so it's a good fit for Pd :) + +module.exports = parse + +/** + * expected argument lengths + * @type {Object} + */ + +var length = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0} + +/** + * segment pattern + * @type {RegExp} + */ + +var segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig + +/** + * parse an svg path data string. Generates an Array + * of commands where each command is an Array of the + * form `[command, arg1, arg2, ...]` + * + * @param {String} path + * @return {Array} + */ + +function parse(path) { + var data = [] + path.replace(segment, function(_, command, args){ + var type = command.toLowerCase() + args = parseValues(args) + + // overloaded moveTo + if (type == 'm' && args.length > 2) { + data.push([command].concat(args.splice(0, 2))) + type = 'l' + command = command == 'm' ? 'l' : 'L' + } + + while (true) { + if (args.length == length[type]) { + args.unshift(command) + return data.push(args) + } + if (args.length < length[type]) throw new Error('malformed path data') + data.push([command].concat(args.splice(0, length[type]))) + } + }) + return data +} + +var number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig + +function parseValues(args) { + var numbers = args.match(number) + return numbers ? numbers.map(Number) : [] +} diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index 9d6980374..e0af0309d 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -32,8 +32,29 @@ function close_save_dialog() { document.getElementById("save_before_quit").close(); } +function text_to_normalized_svg_path(text) { + text = text.slice(4).trim() // draw + .slice(4).trim() // path + .slice(1).trim() // d + .slice(1).trim(); // = + if (text.slice(0, 1) === '"') { + text = text.slice(1); + } + if (text.slice(-1) === '"') { + text = text.slice(0, -1); + } + text = pdgui.parse_svg_path(text); + return "draw path " + text.reduce(function (prev, curr) { + return prev.concat(curr) + }).join(" "); +} + function text_to_fudi(text) { text = text.trim(); + // special case for draw path d="arbitrary path string" ... + if (text.search(/^draw\s+path\s+d\s*=\s*"/) !== -1) { + text = text_to_normalized_svg_path(text); + } text = text.replace(/(\$[0-9]+)/g, "\\$1"); // escape dollar signs text = text.replace(/(\$@)/g, "\\$@"); // escape special $@ sign text = text.replace(/(?!\\)(,|;)/g, " \\$1 "); // escape "," and ";" diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index c16affeca..727670b73 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -66,6 +66,10 @@ var fs = require("fs"); // for fs.existsSync var path = require("path"); // for path.dirname path.extname path.join var cp = require("child_process"); // for starting core Pd from GUI in OSX +var parse_svg_path = require("./parse-svg-path.js"); + +exports.parse_svg_path = parse_svg_path; + // local strings var lang = require("./pdlang.js"); -- GitLab