1
0
Fork 0

Fixed offset issue when Cp lies on start/end

See https://github.com/Pomax/bezierjs/issues/37#issuecomment-410810976
This commit is contained in:
Joost De Cock 2018-08-06 20:43:19 +02:00
parent 4c81d41ab8
commit 8051a48880
2 changed files with 74 additions and 9 deletions

View file

@ -190,19 +190,29 @@ function pathOffset(path, distance) {
if (op.type === "line") {
offset.push(offsetLine(current, op.to, distance));
} else if (op.type === "curve") {
// We need to avoid a control point sitting on top of start or end
// because that will break the offset in bezier-js
let cp1, cp2;
if (current.sitsOn(op.cp1)) {
cp1 = new Path()
.move(current)
.curve(op.cp1, op.cp2, op.to)
.shiftAlong(1);
} else cp1 = op.cp1;
if (op.cp2.sitsOn(op.to)) {
cp2 = new Path()
.move(op.to)
.curve(op.cp2, op.cp1, current)
.shiftAlong(1);
} else cp2 = op.cp2;
let b = new Bezier(
{ x: current.x, y: current.y },
{ x: op.cp1.x, y: op.cp1.y },
{ x: op.cp2.x, y: op.cp2.y },
{ x: cp1.x, y: cp1.y },
{ x: cp2.x, y: cp2.y },
{ x: op.to.x, y: op.to.y }
);
for (let bezier of b.offset(distance)) {
offset.push(asPath(bezier));
}
} else if (op.type === "close") {
// offset.push(offsetLine(current, start, distance));
closed = true;
}
for (let bezier of b.offset(distance)) offset.push(asPath(bezier));
} else if (op.type === "close") closed = true;
if (op.to) current = op.to;
if (!start) start = current;
}
@ -252,4 +262,53 @@ function joinPaths(paths, closed = false) {
return joint;
}
/** Returns a point that lies at distance along this */
Path.prototype.shiftAlong = function(distance) {
let len = 0;
let current;
for (let i in this.ops) {
let op = this.ops[i];
if (op.type === "line") {
let thisLen = op.to.dist(current);
if (len + thisLen > distance)
return current.shiftTowards(op.to, distance - len);
else len += thisLen;
} else if (op.type === "curve") {
let bezier = new Bezier(
{ x: current.x, y: current.y },
{ x: op.cp1.x, y: op.cp1.y },
{ x: op.cp2.x, y: op.cp2.y },
{ x: op.to.x, y: op.to.y }
);
let thisLen = bezier.length();
if (len + thisLen > distance)
return shiftAlongBezier(distance - len, bezier);
else len += thisLen;
}
current = op.to;
}
console.log("distance is", distance, "len is", len);
throw "Ran out of curve to shift along";
};
/** Returns a point that lies at distance along bezier */
function shiftAlongBezier(distance, bezier) {
let steps = 100;
let maxLength = bezier.length();
if (distance > maxLength) throw "Cannot shift further than the bezier length";
let previous, next, t, thisLen;
let len = 0;
for (let i = 0; i <= steps; i++) {
t = i / steps;
next = bezier.get(t);
next = new Point(next.x, next.y);
if (i > 0) {
thisLen = next.dist(previous);
if (len + thisLen > distance) return next;
else len += thisLen;
}
previous = next;
}
}
export default Path;

View file

@ -99,6 +99,12 @@ Point.prototype.shiftTowards = function(that, distance) {
return this.shift(this.angle(that), distance);
};
/** Checks whether this has the same coordinates as that */
Point.prototype.sitsOn = function(that) {
if (this.x === that.x && this.y === that.y) return true;
else return false;
};
/** Shifts this point fraction of the distance towards that point */
Point.prototype.shiftFractionTowards = function(that, fraction) {
return this.shiftTowards(that, this.dist(that) * fraction);