Skip to content

Commit

Permalink
Improved brush line and smooth interpolator (#292)
Browse files Browse the repository at this point in the history
* Use approximate way to interpolate brush segments tangent curves.
* Fixed smooth cases when dX is close to 0.
* Use mild transition between control cut and rotation for curve limit.
  • Loading branch information
alexanderby committed Dec 9, 2016
1 parent 0a41047 commit 1d774b7
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 203 deletions.
2 changes: 1 addition & 1 deletion src/utils/d3-decorators.js
Expand Up @@ -593,7 +593,7 @@ var d3_createPathTween = (
}

var points = utils.unique(data, idGetter).map(pointConvertor);
var interpolateLine = getLineInterpolator(interpolationType);
var interpolateLine = getLineInterpolator(interpolationType) || getLineInterpolator('linear');
var pointsTo = interpolateLine(points);
var pointsFrom = this[pointStore];

Expand Down
13 changes: 11 additions & 2 deletions src/utils/path/bezier.js
Expand Up @@ -23,7 +23,16 @@ export function getBezierPoint(t, ...p) {
x.unshift(t);
y.unshift(t);
return {
x: bezier.apply(null, x),
y: bezier.apply(null, y)
x: bezier(...x),
y: bezier(...y)
};
}

export function splitCubicSegment(t, p0, c0, c1, p1) {
var c2 = getBezierPoint(t, p0, c0);
var c3 = getBezierPoint(t, p0, c0, c1);
var c4 = getBezierPoint(t, c0, c1, p1);
var c5 = getBezierPoint(t, c1, p1);
var m = getBezierPoint(t, c3, c4);
return [p0, c2, c3, m, c4, c5, p1];
}
27 changes: 10 additions & 17 deletions src/utils/path/interpolators/path-points.js
@@ -1,5 +1,5 @@
import {utils} from '../../utils';
import {bezier, getBezierPoint} from '../bezier';
import {getBezierPoint, splitCubicSegment as split} from '../bezier';

/**
* Returns intermediate line or curve between two sources.
Expand Down Expand Up @@ -694,22 +694,15 @@ function getDistance(x0, y0, x, y) {
}

function splitCubicSegment(t, [p0, c0, c1, p1]) {
var r = Object.keys(p1)
.reduce((memo, k) => {
if (k === 'x' || k === 'y') {
memo[k] = bezier(t, p0[k], c0[k], c1[k], p1[k]);
} else if (k !== 'id') {
memo[k] = interpolateValue(p0[k], p1[k], t);
}
return memo;
}, {});
var c2 = getBezierPoint(t, p0, c0);
var c3 = getBezierPoint(t, p0, c0, c1);
var c4 = getBezierPoint(t, c0, c1, p1);
var c5 = getBezierPoint(t, c1, p1);
[c2, c3, c4, c5].forEach(c => c.isCubicControl = true);

return [p0, c2, c3, r, c4, c5, p1];
var seg = split(t, p0, c0, c1, p1);
[seg[1], seg[2], seg[4], seg[5]].forEach(c => c.isCubicControl = true);
Object.keys(p1).forEach((k) => {
if (k !== 'x' && k !== 'y' && k !== 'id') {
seg[3][k] = interpolateValue(p0[k], p1[k], t);
}
});

return seg;
}

function multipleSplitCubicSegment(ts, seg) {
Expand Down
30 changes: 17 additions & 13 deletions src/utils/path/interpolators/smooth.js
@@ -1,4 +1,4 @@
import {bezier, getBezierPoint} from '../bezier';
import {getBezierPoint} from '../bezier';

/**
* Returns smooth cubic spline.
Expand Down Expand Up @@ -37,7 +37,7 @@ function getCubicSpline(points, limited) {
}

var curve = new Array((points.length - 1) * 3 + 1);
var c0, p1, c3, c1x, c1y, c2x, c2y, qx, qy, qt, tan, dx1, dx2;
var c0, p1, c3, c1x, c1y, c2x, c2y, qx, qy, qt, tan, dx1, dx2, kl;
for (var i = 0; i < points.length; i++) {
curve[i * 3] = points[i];
if (i > 0) {
Expand All @@ -51,19 +51,19 @@ function getCubicSpline(points, limited) {
c0 = result[i - 5];
p1 = result[i - 3];
c3 = result[i - 1];
if ((p1.x - c0.x) * (c3.x - p1.x) === 0) {
c1x = bezier(0.5, c0.x, p1.x);
c2x = bezier(0.5, p1.x, c3.x);
c1y = bezier(0.5, c0.y, p1.y);
c2y = bezier(0.5, p1.y, c3.y);
if ((p1.x - c0.x) * (c3.x - p1.x) * 1e12 < 1) {
c1x = interpolate(c0.x, p1.x, 0.5);
c2x = interpolate(p1.x, c3.x, 0.5);
c1y = interpolate(c0.y, p1.y, 0.5);
c2y = interpolate(p1.y, c3.y, 0.5);
} else {
qt = (p1.x - c0.x) / (c3.x - c0.x);
qx = (p1.x - c0.x * (1 - qt) * (1 - qt) - c3.x * qt * qt) / (2 * (1 - qt) * qt);
qy = (p1.y - c0.y * (1 - qt) * (1 - qt) - c3.y * qt * qt) / (2 * (1 - qt) * qt);
c1x = bezier(qt, c0.x, qx);
c2x = bezier(qt, qx, c3.x);
c1y = bezier(qt, c0.y, qy);
c2y = bezier(qt, qy, c3.y);
c1x = interpolate(c0.x, qx, qt);
c2x = interpolate(qx, c3.x, qt);
c1y = interpolate(c0.y, qy, qt);
c2y = interpolate(qy, c3.y, qt);

if (limited) {
dx1 = (p1.x - c1x);
Expand All @@ -73,10 +73,14 @@ function getCubicSpline(points, limited) {
tan = 0;
} else {
if (p1.y > c0.y === c2y > c3.y) {
dx2 = dx2 * (c3.y - p1.y) / (c2y - p1.y);
kl = ((c3.y - p1.y) / (c2y - p1.y));
dx2 = interpolate(dx2 * kl, dx2, 1 / (1 + Math.abs(kl)));
tan = (c3.y - p1.y) / dx2;
}
if (p1.y > c0.y === c1y < c0.y) {
dx1 = dx1 * (p1.y - c0.y) / (p1.y - c1y);
kl = ((p1.y - c0.y) / (p1.y - c1y));
dx1 = interpolate(dx1 * kl, dx1, 1 / (1 + Math.abs(kl)));
tan = (p1.y - c0.y) / dx1;
}
}
c1x = p1.x - dx1;
Expand Down

0 comments on commit 1d774b7

Please sign in to comment.