From c10079bba4a995a15e34d262fe8e76183494463c Mon Sep 17 00:00:00 2001 From: Shaunak Kishore Date: Wed, 30 Sep 2015 01:31:12 -0400 Subject: [PATCH] Get bridges working --- client/editor.js | 2 +- client/lib/bridges.js | 95 +++++++++++++++++++++++++++++++++++++++++ client/style.less | 2 +- lib/stroke_extractor.js | 3 +- 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 client/lib/bridges.js diff --git a/client/editor.js b/client/editor.js index 10ea312f..3552ff05 100644 --- a/client/editor.js +++ b/client/editor.js @@ -53,7 +53,7 @@ Tracker.autorun(() => { const glyph = Session.get('editor.glyph'); if (!glyph) return; if (!last_glyph || glyph.character !== last_glyph.character) { - stage = new stages.strokes(glyph); + stage = new stages.bridges(glyph); } stage.refresh(glyph); last_glyph = glyph; diff --git a/client/lib/bridges.js b/client/lib/bridges.js new file mode 100644 index 00000000..afdbbf30 --- /dev/null +++ b/client/lib/bridges.js @@ -0,0 +1,95 @@ +"use strict"; + +const bridgeKey = (bridge) => bridge.map(Point.key).join('-'); + +const removeBridge = (bridges, bridge) => { + const keys = {}; + keys[bridgeKey(bridge)] = true; + keys[bridgeKey(bridge.reverse())] = true; + return bridges.filter((bridge) => !keys[bridgeKey(bridge)]); +} + +stages.bridges = class BridgesStage extends stages.AbstractStage { + constructor(glyph) { + super(); + Session.set('stage.type', 'bridges'); + Session.set('stage.instructions', + 'Connect each pair of points on the glyph outline such that ' + + 'the segment connecting those points is part of some stroke ' + + 'outline. Click on a bridge to drop it.'); + const bridges = stroke_extractor.getBridges(glyph); + this.bridges = bridges.bridges; + this.endpoints = []; + bridges.endpoints.map( + (path) => this.endpoints = this.endpoints.concat(path)); + this.selected_point = undefined; + glyph.stages.strokes = glyph.stages.strokes || this.bridges; + } + handleClickOnBridge(glyph, bridge) { + glyph.stages.bridges = removeBridge(glyph.stages.bridges, bridge); + Session.set('editor.glyph', glyph); + } + handleClickOnPoint(glyph, point) { + if (this.selected_point === undefined) { + this.selected_point = point; + this.refresh(glyph); + return; + } else if (Point.equal(point, this.selected_point)) { + this.selected_point = undefined; + this.refresh(glyph); + return; + } + const bridge = [point, this.selected_point]; + this.selected_point = undefined; + const without = removeBridge(glyph.stages.bridges, bridge); + if (without.length < glyph.stages.bridges.length) { + this.refresh(glyph); + return; + } + glyph.stages.bridges.push(bridge); + Session.set('editor.glyph', glyph); + } + handleEvent(glyph, event, template) { + if (template.x1 !== undefined) { + this.handleClickOnBridge( + glyph, [[template.x1, template.y1], [template.x2, template.y2]]); + } else if (template.cx !== undefined) { + this.handleClickOnPoint(glyph, [template.cx, template.cy]); + } + } + refresh(glyph) { + Session.set('stage.paths', + [{d: glyph.stages.path, fill: 'gray', stroke: 'gray'}]); + const keys = {}; + this.bridges.map((bridge) => { + keys[bridgeKey(bridge)] = true; + keys[bridgeKey(bridge.reverse())] = true; + }); + Session.set('stage.lines', glyph.stages.bridges.map((bridge) => ({ + cls: 'selectable', + stroke: keys[bridgeKey(bridge)] ? 'red' : 'purple', + x1: bridge[0][0], + y1: bridge[0][1], + x2: bridge[1][0], + y2: bridge[1][1], + }))); + Session.set('stage.points', this.endpoints.map((endpoint) => { + let color = endpoint.corner ? 'red' : 'black'; + if (this.selected_point && + Point.equal(endpoint.point, this.selected_point)) { + color = 'purple'; + } + return { + cls: 'selectable', + cx: endpoint.point[0], + cy: endpoint.point[1], + fill: color, + stroke: color, + } + })); + const strokes = stroke_extractor.getStrokes(glyph); + const n = strokes.strokes.length; + const message = `Extracted ${n} stroke${n == 1 ? '' : 's'}.`; + Session.set('stage.status', strokes.log.concat([{message: message}])); + } +} diff --git a/client/style.less b/client/style.less index e8d53078..4fb31b5b 100644 --- a/client/style.less +++ b/client/style.less @@ -86,7 +86,7 @@ height: 100%; margin: 0 auto; - path.selectable:hover { + path.selectable:hover, line.selectable:hover { cursor: pointer; stroke: blue; stroke-width: 8; diff --git a/lib/stroke_extractor.js b/lib/stroke_extractor.js index ff19a031..5dee927c 100644 --- a/lib/stroke_extractor.js +++ b/lib/stroke_extractor.js @@ -363,7 +363,8 @@ this.stroke_extractor.getBridges = (glyph, classifier) => { endpoints.push(new Endpoint(paths, [i, j])); } } - return getBridges(endpoints, classifier || handTunedClassifier); + const bridges = getBridges(endpoints, classifier || handTunedClassifier); + return {endpoints: endpoints, bridges: bridges}; } this.stroke_extractor.getStrokes = (glyph) => {