Is there a simple way of keeping the shape of the existing arc while changing its length? In other words, I would like the ends of the arc to extend further while keeping the same shape (if that makes any sense). I have about 100 of these arcs to modify.
Here's a link to one since SVG files cannot be attached.
An automatic solution would be nice, but I would rather not have to manually manipulate the handlers to affect the change. The files are stored in a folder in Dropbox.
Answer
A Bézier segment of a path is a polynomial. Just because we only use the curve to a parameter of range [0-1] does not mean the function does not exist outside this range, it does. Since this new curve is also a Bézier, so it can be described with a different Bézier curve accurately.
Image 1: Two Bézier curves that have been extended by 0.1 t in both directions.
I have used the following, extremely beta version, script:
#target illustrator
// extendSelectedSegment.jsx v0.0
//
// Copyright (c) 2017 Janne Ojala
// License: MIT see https://opensource.org/licenses/MIT
var Bezier = function(p1, p2, p3, p4) {
if (p2 === undefined){
this.paramsFromPath(p1);
} else {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.p4 = p4;
}
};
Bezier.prototype.posAtParam = function(t){
var p = [undefined, undefined];
for (var i = 0; i < 2; i++){
p[i] = this.p1[i] * Math.pow(1 - t,3)
+ this.p2[i] * 3 * t * Math.pow(1 - t,2)
+ this.p3[i] * 3 * Math.pow(t,2) * (1 - t)
+ this.p4[i] * Math.pow(t,3);
}
return p;
}
Bezier.prototype.derivateAtParam = function(t){
var d = [undefined, undefined];
for (var i = 0; i < 2; i++){
d[i] = - 3 * this.p1[i] * Math.pow(1 - t,2)
+ 3 * this.p2[i] * Math.pow(1 - t,2)
- 6 * this.p2[i] * (1 - t) * t
+ 6 * this.p3[i] * (1 - t) * t
- 3 * this.p3[i] * Math.pow(t,2)
+ 3 * this.p4[i] * Math.pow(t,2);
}
return d;
}
Bezier.prototype.extendToParam = function(t, t2){
// Extend only to one direction at time.
if (t2 === undefined){
t2 = t;
t = 0;
}
var p4n = this.posAtParam(t2);
var p3n = this.derivateAtParam(t2);
for (var i = 0; i < 2; i++){
p3n[i] = p4n[i] - ((t2-t)*p3n[i])/3;
}
var p1n = this.posAtParam(t);
var p2n = this.derivateAtParam(t);
for (var i = 0; i < 2; i++){
p2n[i] = p1n[i] + ((t2-t)*p2n[i])/3;
}
return new Bezier(p1n, p2n, p3n, p4n);
}
Bezier.prototype.makePath = function(){
pth = app.activeDocument.pathItems.add();
var point1 = pth.pathPoints.add();
point1.anchor = this.p1;
point1.leftDirection = this.p1;
point1.rightDirection = this.p2;
var point2 = pth.pathPoints.add();
point2.anchor = this.p4;
point2.leftDirection = this.p3;
point2.rightDirection = this.p4;
}
Bezier.prototype.paramsFromPath = function(pth){
var point1 = pth.pathPoints[0];
this.p1 = point1.anchor;
this.p2 = point1.rightDirection;
var point2 = pth.pathPoints[1];
this.p3 = point2.leftDirection;
this.p4 = point2.anchor;
}
var sel = app.activeDocument.selection;
var bez = new Bezier(sel[0]);
bez = bez.extendToParam(0, 1.1);
bez = bez.extendToParam(-0.1, 1.0);
bez.makePath();
Now bear in mind that this works for a single selected path and has no checks. This script is posted as is and should be handled with care. But otherwise your free to do anything you like with it as long as you keep the attribution/license for my parts of the code.
Note: I am extending the Bézier function, this does not always yield a very "natural" extension as it uses the underlying function and that CAN turn on itself if you are near a situation that would make a cusp.
No comments:
Post a Comment