You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.4 KiB
129 lines
3.4 KiB
'use strict'; |
|
|
|
var _ = require('lodash'); |
|
var math = require('../math'); |
|
|
|
// Remove points, that looks like straight line |
|
function simplify(contours, accuracy) { |
|
return _.map(contours, function (contour) { |
|
var i, curr, prev, next; |
|
var p, pPrev, pNext; |
|
|
|
// run from the end, to simplify array elements removal |
|
for (i = contour.length - 2; i > 1; i--) { |
|
prev = contour[i - 1]; |
|
next = contour[i + 1]; |
|
curr = contour[i]; |
|
|
|
// skip point (both oncurve & offcurve), |
|
// if [prev,next] is straight line |
|
if (prev.onCurve && next.onCurve) { |
|
p = new math.Point(curr.x, curr.y); |
|
pPrev = new math.Point(prev.x, prev.y); |
|
pNext = new math.Point(next.x, next.y); |
|
if (math.isInLine(pPrev, p, pNext, accuracy)) { |
|
contour.splice(i, 1); |
|
} |
|
} |
|
} |
|
return contour; |
|
}); |
|
} |
|
|
|
// Remove interpolateable oncurve points |
|
// Those should be in the middle of nebor offcurve points |
|
function interpolate(contours, accuracy) { |
|
return _.map(contours, function (contour) { |
|
var resContour = []; |
|
|
|
_.forEach(contour, function (point, idx) { |
|
// Never skip first and last points |
|
if (idx === 0 || idx === (contour.length - 1)) { |
|
resContour.push(point); |
|
return; |
|
} |
|
|
|
var prev = contour[idx - 1]; |
|
var next = contour[idx + 1]; |
|
|
|
var p, pPrev, pNext; |
|
|
|
// skip interpolateable oncurve points (if exactly between previous and next offcurves) |
|
if (!prev.onCurve && point.onCurve && !next.onCurve) { |
|
p = new math.Point(point.x, point.y); |
|
pPrev = new math.Point(prev.x, prev.y); |
|
pNext = new math.Point(next.x, next.y); |
|
if (pPrev.add(pNext).div(2).sub(p).dist() < accuracy) { |
|
return; |
|
} |
|
} |
|
// keep the rest |
|
resContour.push(point); |
|
}); |
|
return resContour; |
|
}); |
|
} |
|
|
|
function roundPoints(contours) { |
|
return _.map(contours, function (contour) { |
|
return _.map(contour, function (point) { |
|
return { x: Math.round(point.x), y: Math.round(point.y), onCurve: point.onCurve }; |
|
}); |
|
}); |
|
} |
|
|
|
// Remove closing point if it is the same as first point of contour. |
|
// TTF doesn't need this point when drawing contours. |
|
function removeClosingReturnPoints(contours) { |
|
return _.map(contours, function (contour) { |
|
var length = contour.length; |
|
|
|
if (length > 1 && |
|
contour[0].x === contour[length - 1].x && |
|
contour[0].y === contour[length - 1].y) { |
|
contour.splice(length - 1); |
|
} |
|
return contour; |
|
}); |
|
} |
|
|
|
function toRelative(contours) { |
|
var prevPoint = { x: 0, y: 0 }; |
|
var resContours = []; |
|
var resContour; |
|
|
|
_.forEach(contours, function (contour) { |
|
resContour = []; |
|
resContours.push(resContour); |
|
_.forEach(contour, function (point) { |
|
resContour.push({ |
|
x: point.x - prevPoint.x, |
|
y: point.y - prevPoint.y, |
|
onCurve: point.onCurve |
|
}); |
|
prevPoint = point; |
|
}); |
|
}); |
|
return resContours; |
|
} |
|
|
|
function identifier(string, littleEndian) { |
|
var result = 0; |
|
|
|
for (var i = 0; i < string.length; i++) { |
|
result = result << 8; |
|
var index = littleEndian ? string.length - i - 1 : i; |
|
|
|
result += string.charCodeAt(index); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
module.exports.interpolate = interpolate; |
|
module.exports.simplify = simplify; |
|
module.exports.roundPoints = roundPoints; |
|
module.exports.removeClosingReturnPoints = removeClosingReturnPoints; |
|
module.exports.toRelative = toRelative; |
|
module.exports.identifier = identifier; |
|
|
|
|