summaryrefslogtreecommitdiff
path: root/tools/parse-layout.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-03-17 02:34:42 +0100
committerTor Andersson <tor@ccxvii.net>2024-03-17 02:34:42 +0100
commit3859e04d3e8866bf6f6337031bd39647f52e6881 (patch)
treeb970dd3b8741f2556a588e3f6e7f7965fb40c9f8 /tools/parse-layout.js
parent8cd6fe0bba35ed37f0134d113dc2846df91894dc (diff)
downloadmaria-3859e04d3e8866bf6f6337031bd39647f52e6881.tar.gz
WIP layout 2
Diffstat (limited to 'tools/parse-layout.js')
-rw-r--r--tools/parse-layout.js224
1 files changed, 224 insertions, 0 deletions
diff --git a/tools/parse-layout.js b/tools/parse-layout.js
new file mode 100644
index 0000000..5219705
--- /dev/null
+++ b/tools/parse-layout.js
@@ -0,0 +1,224 @@
+const fs = require("fs")
+
+let points = {}
+let rects = {}
+let edges = []
+let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2
+
+function add_point(x, y) {
+ if (name in points)
+ points[name].push([x,y])
+ else
+ points[name] = [ [x,y] ]
+}
+
+function add_rect(x, y, w, h) {
+ if (name in rects)
+ rects[name].push([x,y,x+w,y+h])
+ else
+ rects[name] = [ [x,y,x+w,y+h] ]
+}
+
+function flush() {
+ if (mode === 'path') {
+ edges.push([ x, y, x2, y2 ])
+ }
+ if (mode === 'rect') {
+ if (name.startsWith("$"))
+ add_rect(x, y, w, h)
+ else
+ add_point( x + w/2, y + h/2 )
+ }
+ if (mode === 'circle') {
+ add_point( cx, cy )
+ }
+ x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0
+}
+
+function parse_path_data(path) {
+ let cx = 0
+ let cy = 0
+ let abs = 0
+ for (let i = 0; i < path.length;) {
+ switch (path[i]) {
+ case 'M':
+ x = cx = Number(path[i+1])
+ y = cy = Number(path[i+2])
+ i += 3
+ abs = true
+ break
+ case 'm':
+ x = cx = cx + Number(path[i+1])
+ y = cy = cy + Number(path[i+2])
+ i += 3
+ abs = false
+ break
+ case 'C':
+ x2 = cx = Number(path[i+5])
+ y2 = cy = Number(path[i+6])
+ i += 7
+ abs = true
+ break
+ case 'L':
+ i += 1
+ abs = true
+ break
+ case 'H':
+ x2 = cx = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'V':
+ y2 = cy = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'c':
+ x2 = cx = cx + Number(path[i+5])
+ y2 = cy = cy + Number(path[i+6])
+ i += 7
+ break
+ case 'l':
+ i += 1
+ abs = false
+ break
+ case 'h':
+ x2 = cx = cx + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ case 'v':
+ y2 = cy = cy + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ default:
+ if (abs) {
+ x2 = cx = Number(path[i+0])
+ y2 = cy = Number(path[i+1])
+ } else {
+ x2 = cx = cx + Number(path[i+0])
+ y2 = cy = cy + Number(path[i+1])
+ }
+ i += 2
+ break
+ }
+ }
+}
+
+for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) {
+ line = line.trim()
+ if (line.startsWith("<rect")) {
+ flush()
+ mode = "rect"
+ x = y = w = h = 0
+ }
+ else if (line.startsWith("<ellipse") || line.startsWith("<circle")) {
+ flush()
+ mode = "circle"
+ cx = cy = rx = ry = 0
+ }
+ else if (line.startsWith("<path")) {
+ flush()
+ mode = "path"
+ }
+ else if (line.startsWith("<g")) {
+ flush()
+ mode = "g"
+ }
+ else if (line.startsWith('x="'))
+ x = (Number(line.split('"')[1]))
+ else if (line.startsWith('y="'))
+ y = (Number(line.split('"')[1]))
+ else if (line.startsWith('width="'))
+ w = (Number(line.split('"')[1]))
+ else if (line.startsWith('height="'))
+ h = (Number(line.split('"')[1]))
+ else if (line.startsWith('cx="'))
+ cx = (Number(line.split('"')[1]))
+ else if (line.startsWith('cy="'))
+ cy = (Number(line.split('"')[1]))
+ else if (line.startsWith('r="'))
+ rx = ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('rx="'))
+ rx = (Number(line.split('"')[1]))
+ else if (line.startsWith('ry="'))
+ ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('inkscape:label="') && mode === "g")
+ name = line.split('"')[1]
+ else if (line.startsWith('d="'))
+ parse_path_data(line.split('"')[1].split(/[ ,]/))
+}
+
+flush()
+
+let labels = []
+
+// names.txt is layout.svg cleaned up by svgo and filtered to only include text nodes
+for (let line of fs.readFileSync("tools/names.txt", "utf-8").split("\n")) {
+ let m = line.match(/<tspan x="([\d.]*)" y="([\d.]*)">([^<]*)</)
+ if (m)
+ labels.push({x: Number(m[1]), y: Number(m[2]), name: m[3]})
+}
+
+function find_closest_node(list, x, y) {
+ let nd = Infinity, nn = null
+
+ for (let n of list) {
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = n
+ }
+ }
+
+ if (!nn) {
+ console.log("NOT FOUND", x, y)
+ return [ null, 0 ]
+ }
+
+ return [ nn, nd ]
+}
+
+function find_enclosing_rect(list, x, y) {
+ for (let [x1, y1, x2, y2] of list) {
+ if (x >= x1 && x <= x2)
+ if (y >= y1 && y <= y2)
+ return true
+ }
+ return false
+}
+
+// FIND and label all points!
+let all_labels = labels.slice()
+let out = {}
+for (let key in points) {
+ out = {}
+ for (let [x, y] of points[key]) {
+ let [ node, dist ] = find_closest_node(labels, x, y)
+ if (dist > 10) {
+ console.log(key,x,y, dist)
+ }
+ if (node) {
+ if (node.name in out)
+ console.log("DUPLICATE", node.name, x, y, out[node.name])
+ labels = labels.filter(x => x !== node)
+ let suit = "UNKNOWN"
+ if (find_enclosing_rect(rects.$CLUBS, x, y))
+ suit = "clubs"
+ else if (find_enclosing_rect(rects.$HEARTS, x, y))
+ suit = "hearts"
+ else if (find_enclosing_rect(rects.$DIAMONDS, x, y))
+ suit = "diamonds"
+ else if (find_enclosing_rect(rects.$SPADES, x, y))
+ suit = "spades"
+ else
+ console.log("NOT ASSIGNED SUIT", x, y)
+ out[node.name] = [x, y, dist, suit]
+ } else {
+ let [ dupname, dupdist ] = find_closest_node(all_labels, x, y)
+ console.log("ALREADY USED", dupname, dupdist, x, y, "OLD", out[dupname])
+ }
+ }
+}
+