mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-26 13:49:01 -05:00
added Matter.Svg.pathToPoints
This commit is contained in:
parent
2d1ef0d6d4
commit
7822ead3bf
3 changed files with 234 additions and 2 deletions
233
src/geometry/Svg.js
Normal file
233
src/geometry/Svg.js
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/**
|
||||||
|
* The `Matter.Svg` module contains methods for converting SVG images into sets of `Matter.Vertices`.
|
||||||
|
*
|
||||||
|
* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js)
|
||||||
|
* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples.
|
||||||
|
*
|
||||||
|
* @class Svg
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Svg = {};
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an SVG path into a `Matter.Vertices` object for the given `Matter.Body`.
|
||||||
|
* @method pathToPoints
|
||||||
|
* @param {string} path
|
||||||
|
* @return {Vector} points
|
||||||
|
*/
|
||||||
|
Svg.pathToPoints = function(path) {
|
||||||
|
var i, il, total, point, distance, segment, segments,
|
||||||
|
segmentsQueue, lastSegment,
|
||||||
|
lastPoint, segmentIndex, points = [],
|
||||||
|
length = 0, x = 0, y = 0;
|
||||||
|
|
||||||
|
// prepare helpers functions
|
||||||
|
var addPoint = function(px, py, pathSegType) {
|
||||||
|
// all odd-numbered path types are relative, except PATHSEG_CLOSEPATH (1)
|
||||||
|
var isRelative = pathSegType % 2 === 1 && pathSegType > 1;
|
||||||
|
|
||||||
|
// when the last point doesn't equal the current point add the current point
|
||||||
|
if (!lastPoint || px != lastPoint.x || py != lastPoint.y) {
|
||||||
|
if (lastPoint && isRelative) {
|
||||||
|
lx = lastPoint.x;
|
||||||
|
ly = lastPoint.y;
|
||||||
|
} else {
|
||||||
|
lx = 0;
|
||||||
|
ly = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var point = {
|
||||||
|
x: lx + px,
|
||||||
|
y: ly + py
|
||||||
|
};
|
||||||
|
|
||||||
|
// set last point
|
||||||
|
if (isRelative || !lastPoint) {
|
||||||
|
lastPoint = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
points.push(point);
|
||||||
|
|
||||||
|
x = lx + px;
|
||||||
|
y = ly + py;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var addSegmentPoint = function(segment) {
|
||||||
|
var segType = segment.pathSegTypeAsLetter.toUpperCase();
|
||||||
|
|
||||||
|
// don't bother processing path ends
|
||||||
|
if (segType === 'Z')
|
||||||
|
return;
|
||||||
|
|
||||||
|
// map segment to x and y
|
||||||
|
switch (segType) {
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
case 'L':
|
||||||
|
case 'T':
|
||||||
|
x = segment.x;
|
||||||
|
y = segment.y;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
x = segment.x;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
y = segment.y;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
x = segment.x;
|
||||||
|
y = segment.y;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
case 'Q':
|
||||||
|
x = segment.x;
|
||||||
|
y = segment.y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// add point
|
||||||
|
addPoint(x, y, segment.pathSegType);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ensure path is absolute
|
||||||
|
_svgPathToAbsolute(path);
|
||||||
|
|
||||||
|
// parse sample value
|
||||||
|
sample = '1%';
|
||||||
|
|
||||||
|
// get total length
|
||||||
|
total = path.getTotalLength();
|
||||||
|
|
||||||
|
// calculate sample distance
|
||||||
|
if (typeof sample === 'string') {
|
||||||
|
if (sample.indexOf('%') > -1) {
|
||||||
|
// sample distance in %
|
||||||
|
distance = total * (parseFloat(sample) / 100);
|
||||||
|
} else if (sample.indexOf('px') > -1) {
|
||||||
|
// fixed sample distance in px
|
||||||
|
distance = parseFloat(sample);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// specific number of samples
|
||||||
|
distance = total / sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put all path segments in a queue
|
||||||
|
segments = [];
|
||||||
|
for (i = 0; i < path.pathSegList.numberOfItems; i += 1)
|
||||||
|
segments.push(path.pathSegList.getItem(i));
|
||||||
|
|
||||||
|
segmentsQueue = segments.concat();
|
||||||
|
|
||||||
|
// sample through path
|
||||||
|
while (length < total) {
|
||||||
|
// get segment index
|
||||||
|
segmentIndex = path.getPathSegAtLength(length);
|
||||||
|
|
||||||
|
// get segment
|
||||||
|
segment = segments[segmentIndex];
|
||||||
|
|
||||||
|
// new segment?
|
||||||
|
if (segment != lastSegment) {
|
||||||
|
while (segmentsQueue.length && segmentsQueue[0] != segment)
|
||||||
|
addSegmentPoint(segmentsQueue.shift());
|
||||||
|
|
||||||
|
lastSegment = segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add points in between when curving
|
||||||
|
switch (segment.pathSegTypeAsLetter.toUpperCase()) {
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
case 'T':
|
||||||
|
case 'S':
|
||||||
|
case 'Q':
|
||||||
|
case 'A':
|
||||||
|
point = path.getPointAtLength(length);
|
||||||
|
addPoint(point.x, point.y, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment by sample value
|
||||||
|
length += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add remaining segments we didn't pass while sampling
|
||||||
|
for (i = 0, il = segmentsQueue.length; i < il; ++i)
|
||||||
|
addSegmentPoint(segmentsQueue[i]);
|
||||||
|
|
||||||
|
return points;
|
||||||
|
};
|
||||||
|
|
||||||
|
var _svgPathToAbsolute = function(path) {
|
||||||
|
// http://phrogz.net/convert-svg-path-to-all-absolute-commands
|
||||||
|
|
||||||
|
var x0, y0, x1, y1, x2, y2, segs = path.pathSegList,
|
||||||
|
x = 0, y = 0, len = segs.numberOfItems;
|
||||||
|
|
||||||
|
for (var i = 0; i < len; ++i) {
|
||||||
|
var seg = segs.getItem(i),
|
||||||
|
c = seg.pathSegTypeAsLetter;
|
||||||
|
|
||||||
|
if (/[MLHVCSQTA]/.test(c)) {
|
||||||
|
if ('x' in seg) x = seg.x;
|
||||||
|
if ('y' in seg) y = seg.y;
|
||||||
|
} else {
|
||||||
|
if ('x1' in seg) x1 = x + seg.x1;
|
||||||
|
if ('x2' in seg) x2 = x + seg.x2;
|
||||||
|
if ('y1' in seg) y1 = y + seg.y1;
|
||||||
|
if ('y2' in seg) y2 = y + seg.y2;
|
||||||
|
if ('x' in seg) x += seg.x;
|
||||||
|
if ('y' in seg) y += seg.y;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
segs.replaceItem(path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i);
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
case 'Z':
|
||||||
|
x = x0;
|
||||||
|
y = y0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'M' || c == 'm') {
|
||||||
|
x0 = x;
|
||||||
|
y0 = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -9,8 +9,6 @@
|
||||||
* @class Vertices
|
* @class Vertices
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: convex decomposition - http://mnbayazit.com/406/bayazit
|
|
||||||
|
|
||||||
var Vertices = {};
|
var Vertices = {};
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
|
@ -38,6 +38,7 @@ Matter.RenderPixi = RenderPixi;
|
||||||
Matter.Events = Events;
|
Matter.Events = Events;
|
||||||
Matter.Query = Query;
|
Matter.Query = Query;
|
||||||
Matter.Runner = Runner;
|
Matter.Runner = Runner;
|
||||||
|
Matter.Svg = Svg;
|
||||||
|
|
||||||
// @if DEBUG
|
// @if DEBUG
|
||||||
Matter.Metrics = Metrics;
|
Matter.Metrics = Metrics;
|
||||||
|
|
Loading…
Reference in a new issue