Merge pull request #2822 from mbasaglia/offset-path-open
Properly handle offset path for open shapes
diff --git a/player/js/utils/PolynomialBezier.js b/player/js/utils/PolynomialBezier.js
index 20bc5fe..07e9786 100644
--- a/player/js/utils/PolynomialBezier.js
+++ b/player/js/utils/PolynomialBezier.js
@@ -199,6 +199,11 @@
return new PolynomialBezier(shapePath.v[index], shapePath.o[index], shapePath.i[nextIndex], shapePath.v[nextIndex], true);
};
+PolynomialBezier.shapeSegmentInverted = function (shapePath, index) {
+ var nextIndex = (index + 1) % shapePath.length();
+ return new PolynomialBezier(shapePath.v[nextIndex], shapePath.i[nextIndex], shapePath.o[index], shapePath.v[index], true);
+};
+
function crossProduct(a, b) {
return [
a[1] * b[2] - a[2] * b[1],
diff --git a/player/js/utils/shapes/OffsetPathModifier.js b/player/js/utils/shapes/OffsetPathModifier.js
index a8bfab0..ef08e05 100644
--- a/player/js/utils/shapes/OffsetPathModifier.js
+++ b/player/js/utils/shapes/OffsetPathModifier.js
@@ -145,6 +145,49 @@
return segments;
}
+function offsetSegmentSplit(segment, amount) {
+ /*
+ We split each bezier segment into smaller pieces based
+ on inflection points, this ensures the control point
+ polygon is convex.
+
+ (A cubic bezier can have none, one, or two inflection points)
+ */
+ var flex = segment.inflectionPoints();
+ var left;
+ var right;
+ var split;
+ var mid;
+
+ if (flex.length === 0) {
+ return [offsetSegment(segment, amount)];
+ }
+
+ if (flex.length === 1 || floatEqual(flex[1], 1)) {
+ split = segment.split(flex[0]);
+ left = split[0];
+ right = split[1];
+
+ return [
+ offsetSegment(left, amount),
+ offsetSegment(right, amount),
+ ];
+ }
+
+ split = segment.split(flex[0]);
+ left = split[0];
+ var t = (flex[1] - flex[0]) / (1 - flex[0]);
+ split = split[1].split(t);
+ mid = split[0];
+ right = split[1];
+
+ return [
+ offsetSegment(left, amount),
+ offsetSegment(mid, amount),
+ offsetSegment(right, amount),
+ ];
+}
+
function OffsetPathModifier() {}
extendPrototype([ShapeModifier], OffsetPathModifier);
@@ -163,45 +206,18 @@
if (!inputBezier.c) {
count -= 1;
}
- var left; var right; var mid; var split;
var i; var j; var segment;
var multiSegments = [];
for (i = 0; i < count; i += 1) {
segment = PolynomialBezier.shapeSegment(inputBezier, i);
- /*
- We split each bezier segment into smaller pieces based
- on inflection points, this ensures the control point
- polygon is convex.
+ multiSegments.push(offsetSegmentSplit(segment, amount));
+ }
- (A cubic bezier can have none, one, or two inflection points)
- */
- var flex = segment.inflectionPoints();
-
- if (flex.length === 0) {
- multiSegments.push([offsetSegment(segment, amount)]);
- } else if (flex.length === 1 || floatEqual(flex[1], 1)) {
- split = segment.split(flex[0]);
- left = split[0];
- right = split[1];
-
- multiSegments.push([
- offsetSegment(left, amount),
- offsetSegment(right, amount),
- ]);
- } else {
- split = segment.split(flex[0]);
- left = split[0];
- var t = (flex[1] - flex[0]) / (1 - flex[0]);
- split = split[1].split(t);
- mid = split[0];
- right = split[1];
-
- multiSegments.push([
- offsetSegment(left, amount),
- offsetSegment(mid, amount),
- offsetSegment(right, amount),
- ]);
+ if (!inputBezier.c) {
+ for (i = count - 1; i >= 0; i -= 1) {
+ segment = PolynomialBezier.shapeSegmentInverted(inputBezier, i);
+ multiSegments.push(offsetSegmentSplit(segment, amount));
}
}
@@ -249,7 +265,7 @@
}
}
- if (inputBezier.c && multiSegments.length) joinLines(outputBezier, lastSeg, multiSegments[0][0], lineJoin, miterLimit);
+ if (multiSegments.length) joinLines(outputBezier, lastSeg, multiSegments[0][0], lineJoin, miterLimit);
return outputBezier;
};