mirror of
https://github.com/skishore/makemeahanzi.git
synced 2025-11-03 22:18:19 +08:00
Get basic matching algorithm working
This commit is contained in:
@ -194,8 +194,21 @@ Template.glyph.helpers({
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
bridges: function() {
|
bridges: function() {
|
||||||
return [];
|
|
||||||
var glyph = Session.get('glyph.data');
|
var glyph = Session.get('glyph.data');
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < glyph.render.segments[0].length; i++) {
|
||||||
|
var j = glyph.render.matching[i];
|
||||||
|
var point1 = glyph.render.segments[0][i].point;
|
||||||
|
var point2 = glyph.render.segments[1][j].point;
|
||||||
|
if (point1[0] === point2[0] && point1[1] === point2[1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var line = to_line([point1, point2]);
|
||||||
|
line.color = 'red'
|
||||||
|
result.push(line);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
var removed = {};
|
var removed = {};
|
||||||
for (var i = 0; i < glyph.manual.bridges_removed.length; i++) {
|
for (var i = 0; i < glyph.manual.bridges_removed.length; i++) {
|
||||||
removed[to_line(glyph.manual.bridges_removed[i]).coordinates] = true;
|
removed[to_line(glyph.manual.bridges_removed[i]).coordinates] = true;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
var MAX_BRIDGE_DISTANCE = 64;
|
||||||
var MIN_CORNER_ANGLE = 0.1*Math.PI;
|
var MIN_CORNER_ANGLE = 0.1*Math.PI;
|
||||||
var MIN_CORNER_TANGENT_DISTANCE = 4;
|
var MIN_CORNER_TANGENT_DISTANCE = 4;
|
||||||
|
|
||||||
@ -21,6 +22,9 @@ var Angle = {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
penalty: function(diff) {
|
||||||
|
return diff*diff*(diff < 0 ? 4 : 1);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper methods for use with "points", which are just pairs of integers.
|
// Helper methods for use with "points", which are just pairs of integers.
|
||||||
@ -138,19 +142,45 @@ function get_2x_area(path) {
|
|||||||
// Returns a list of critical segments that are arrayed around the corner.
|
// Returns a list of critical segments that are arrayed around the corner.
|
||||||
// Each of these segments will include a d value, an "in" bit, and an "out" bit.
|
// Each of these segments will include a d value, an "in" bit, and an "out" bit.
|
||||||
function get_segments(corners) {
|
function get_segments(corners) {
|
||||||
var map = {};
|
var result = [[], []];
|
||||||
for (var i = 0; i < corners.length; i++) {
|
for (var i = 0; i < corners.length; i++) {
|
||||||
var corner = corners[i];
|
|
||||||
for (var j = 0; j < 2; j++) {
|
for (var j = 0; j < 2; j++) {
|
||||||
var key = Point.key(corner.indices[j]);
|
result[j].push({
|
||||||
if (!map.hasOwnProperty(key)) {
|
angle: corners[i].angles[j],
|
||||||
map[key] = {segment: corner.segments[j]};
|
point: corners[i].point,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map[Point.key(corner.indices[0])].in = true;
|
return result;
|
||||||
map[Point.key(corner.indices[1])].out = true;
|
}
|
||||||
|
|
||||||
|
// Takes a list of segments and returns a bipartite match array between them.
|
||||||
|
// If array[i] === j, then segments[0][i] is matched with segments[1][j].
|
||||||
|
function match_segments(segments) {
|
||||||
|
var matrix = [];
|
||||||
|
for (var i = 0; i < segments[0].length; i++) {
|
||||||
|
matrix.push([]);
|
||||||
|
for (var j = 0; j < segments[0].length; j++) {
|
||||||
|
matrix[i].push(score_segments(segments[0][i], segments[1][j]));
|
||||||
}
|
}
|
||||||
return _.values(map);
|
}
|
||||||
|
return (new Hungarian(matrix)).x_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes two segments and returns the score that should be assigned to matching
|
||||||
|
// the in segment to the out segment. The score will generally be negative.
|
||||||
|
function score_segments(ins, out) {
|
||||||
|
var diff = Point.subtract(out.point, ins.point);
|
||||||
|
if (Point.equal(diff, [0, 0])) {
|
||||||
|
return -Angle.penalty(Angle.subtract(out.angle, ins.angle));
|
||||||
|
}
|
||||||
|
var angle = Math.atan2(diff[1], diff[0]);
|
||||||
|
var threshold = Math.pow(MAX_BRIDGE_DISTANCE, 2);
|
||||||
|
var score = 0;
|
||||||
|
score -= Angle.penalty(Angle.subtract(angle, ins.angle));
|
||||||
|
score -= Angle.penalty(Angle.subtract(out.angle, angle));
|
||||||
|
score -= Point.distance2(out.point, ins.point)/threshold;
|
||||||
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Endpoint(paths, index) {
|
function Endpoint(paths, index) {
|
||||||
@ -192,9 +222,12 @@ this.get_glyph_render_data = function(glyph) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var corners = endpoints.filter(function(x) { return x.corner; });
|
var corners = endpoints.filter(function(x) { return x.corner; });
|
||||||
|
var segments = get_segments(corners);
|
||||||
|
var matching = match_segments(segments);
|
||||||
return {
|
return {
|
||||||
d: Glyphs.get_svg_path(glyph),
|
d: Glyphs.get_svg_path(glyph),
|
||||||
endpoints: endpoints,
|
endpoints: endpoints,
|
||||||
segments: get_segments(corners),
|
segments: segments,
|
||||||
|
matching: matching,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user