This is a box with an irregular shape that I have generated:
And this is the end effect I'd like to achieve (note the smooth edges):
Here's the code for my sharp version:
var path1 = new Path({
segments: [[123, 6], [290, 6], [304, 142], [112, 142]],
strokeColor: 'white',
closed: true,
strokeWidth: 3,
strokeJoin: 'round'
});
Thing is, I'm already using the strokeJoin: 'round' option and the difference is hardly noticeable with a stroke width of 3px. It's a small thing but could turn into a game breaker as there are going to be multiple objects like this and the difference is huge.
Is there any way to achieve that with paper.js without overdoing it?
This is a box with an irregular shape that I have generated:
And this is the end effect I'd like to achieve (note the smooth edges):
Here's the code for my sharp version:
var path1 = new Path({
segments: [[123, 6], [290, 6], [304, 142], [112, 142]],
strokeColor: 'white',
closed: true,
strokeWidth: 3,
strokeJoin: 'round'
});
Thing is, I'm already using the strokeJoin: 'round' option and the difference is hardly noticeable with a stroke width of 3px. It's a small thing but could turn into a game breaker as there are going to be multiple objects like this and the difference is huge.
Is there any way to achieve that with paper.js without overdoing it?
Share Improve this question asked Sep 19, 2014 at 14:43 Paweł DudaPaweł Duda 1,7834 gold badges18 silver badges36 bronze badges 1-
1
strokeJoin
only determines how the intersection point of 2 lines will be displayed. Since it's a point it won't result in a curve. So you will need to use both lines & curves (or arcs) to round your trapezoid. – markE Commented Sep 19, 2014 at 16:11
2 Answers
Reset to default 8As markE mentioned, strokeJoin
only changes the canvas style of a path's stroke. Paper.js does not e with a corner-rounding function, you'll have to make your own.
Here's a quick function that you can use a starting point. It will negatively offset the points of a polygon by a given distance and add the appropriate handles.
function roundPath(path,radius) {
var segments = path.segments.slice(0);
path.segments = [];
for(var i = 0, l = segments.length; i < l; i++) {
var curPoint = segments[i].point;
var nextPoint = segments[i + 1 == l ? 0 : i + 1].point;
var prevPoint = segments[i - 1 < 0 ? segments.length - 1 : i - 1].point;
var nextDelta = curPoint - nextPoint;
var prevDelta = curPoint - prevPoint;
nextDelta.length = radius;
prevDelta.length = radius;
path.add({
point:curPoint - prevDelta,
handleOut: prevDelta/2
});
path.add({
point:curPoint - nextDelta,
handleIn: nextDelta/2
});
}
path.closed = true;
return path;
}
Here it is in action.
I was looking for an exact implementation, as described here: http://shanfanhuang./everything/2015/10/27/rounding-corners
My implementation works as follows:
- curPoint is the corner, prevPoint and nextPoint as above
- nextNorm and prevNorm are the normalized versions of the points
- angle is the angle of the corner, derived from the dot product
- delta is the distance from the corner points to where the control points need to be inserted, this is derived from a right triangle formed by the control point, curPoint and the center of the corner arc. The corner is a half angle, and the side opposing that corner is the radius
- prevDelta and nextDelta are the new endpoints of the sides, between those an arc is inserted
through is a point halfway on the arc, found by getting the hypotenuse of the above triangle and subtracting the radius.
var segments = path.segments.slice(0); path.segments = []; for(var i = 0, l = segments.length; i < l; i++) { var curPoint = segments[i].point; var nextPoint = segments[i + 1 == l ? 0 : i + 1].point; var prevPoint = segments[i - 1 < 0 ? segments.length - 1 : i - 1].point; var nextNorm = (curPoint - nextPoint).normalize(); var prevNorm = (curPoint - prevPoint).normalize(); var angle = Math.acos(nextNorm.dot(prevNorm)); var delta = radius/Math.tan(angle/2); var prevDelta = prevNorm.normalize(delta); var nextDelta = nextNorm.normalize(delta); var through = curPoint - (prevNorm + nextNorm).normalize(Math.sqrt(delta*delta + radius*radius) - radius); path.add(curPoint - prevDelta); path.arcTo(through, curPoint - nextDelta); }