2019-02-26 17:46:07 +01:00
|
|
|
export default function(part) {
|
2019-07-06 13:59:33 +02:00
|
|
|
let { Path, paths, points, store, options } = part.shorthand();
|
2019-02-26 17:46:07 +01:00
|
|
|
|
|
|
|
function draftSleeve(part, tweak) {
|
2019-05-10 13:14:31 +02:00
|
|
|
let {
|
|
|
|
Point,
|
|
|
|
Path,
|
|
|
|
points,
|
2019-07-02 19:27:40 +02:00
|
|
|
paths,
|
2019-05-10 13:14:31 +02:00
|
|
|
store,
|
|
|
|
options,
|
|
|
|
measurements,
|
|
|
|
utils
|
|
|
|
} = part.shorthand();
|
2019-02-26 17:46:07 +01:00
|
|
|
// Sleeve frame
|
|
|
|
points.top = new Point(0, 0);
|
2019-05-10 13:14:31 +02:00
|
|
|
points.boxTopRight = points.top.shift(
|
|
|
|
0,
|
|
|
|
(store.get("sleevecapTarget") / 5.8) * tweak
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
points.boxTopLeft = points.boxTopRight.flipX();
|
2019-05-10 13:14:31 +02:00
|
|
|
points.boxBottom = points.top.shift(
|
|
|
|
-90,
|
|
|
|
measurements.shoulderToWrist * (1 + options.sleeveLengthBonus)
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
points.boxBottomRight = points.boxBottom.shift(0, points.boxTopRight.x);
|
|
|
|
points.boxBottomLeft = points.boxBottomRight.flipX();
|
|
|
|
points.armCenter = points.top.shift(
|
|
|
|
-90,
|
|
|
|
measurements.bicepsCircumference *
|
2019-05-10 13:14:31 +02:00
|
|
|
(1 + options.bicepsEase) *
|
|
|
|
options.sleevecapHeight *
|
|
|
|
tweak
|
2019-02-26 17:46:07 +01:00
|
|
|
);
|
|
|
|
points.armRight = points.armCenter.shift(0, points.boxTopRight.x);
|
|
|
|
points.armLeft = points.armRight.flipX();
|
|
|
|
points.elbowCenter = points.top.shift(-90, measurements.shoulderToElbow);
|
|
|
|
points.elbowRight = points.elbowCenter.shift(0, points.boxTopRight.x);
|
|
|
|
points.elbowLeft = points.elbowRight.flipX();
|
|
|
|
|
|
|
|
// Using sleeve width to adapt other values
|
|
|
|
let factor = points.boxTopRight.x;
|
|
|
|
|
|
|
|
// Note: us = undersleeve, ts = topsleeve
|
|
|
|
points.backPitchPoint = new Point(factor, points.armCenter.y / 3);
|
|
|
|
points.usTip = points.backPitchPoint.shift(180, factor / 4);
|
|
|
|
points.tsLeftEdge = points.armLeft.shift(180, factor / 4);
|
|
|
|
points.usLeftEdge = points.armLeft.shift(0, factor / 4);
|
|
|
|
points.tsRightEdge = points.armRight.shift(0, factor / 9);
|
|
|
|
points.usRightEdge = points.armRight.shift(180, factor / 9);
|
2019-05-10 13:14:31 +02:00
|
|
|
points.frontPitchPoint = new Point(
|
|
|
|
points.boxTopLeft.x,
|
|
|
|
points.armCenter.y * 0.6
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
points.tsElbowLeft = points.elbowLeft.shift(180, factor / 9);
|
|
|
|
points.usElbowLeft = points.elbowLeft.shift(0, factor / 2.4);
|
|
|
|
|
|
|
|
// Different approach to sleeve bend, wrist right first
|
|
|
|
points.tsWristRight = utils.beamsIntersect(
|
|
|
|
points.elbowRight,
|
|
|
|
points.boxBottomRight.rotate(options.sleeveBend * -1, points.elbowRight),
|
|
|
|
points.boxBottomLeft,
|
|
|
|
points.boxBottomRight
|
|
|
|
);
|
|
|
|
points.usWristRight = points.tsWristRight.clone();
|
|
|
|
|
|
|
|
// Shift wrist left to the exact wrist width
|
|
|
|
let wristWidth = measurements.wristCircumference * (1 + options.cuffEase);
|
2019-05-10 13:14:31 +02:00
|
|
|
let topWrist = wristWidth / 2 + factor / 5;
|
|
|
|
let underWrist = wristWidth / 2 - factor / 5;
|
|
|
|
points.tsWristLeftHelperBottom = points.tsWristRight.shift(
|
|
|
|
180,
|
|
|
|
topWrist / 2
|
|
|
|
);
|
|
|
|
points.usWristLeftHelperBottom = points.usWristRight.shift(
|
|
|
|
180,
|
|
|
|
underWrist / 2
|
|
|
|
);
|
|
|
|
points.tsWristLeftHelperTop = points.tsElbowLeft.shiftFractionTowards(
|
|
|
|
points.elbowRight,
|
|
|
|
0.5
|
|
|
|
);
|
|
|
|
points.usWristLeftHelperTop = points.usElbowLeft.shiftFractionTowards(
|
|
|
|
points.elbowRight,
|
|
|
|
0.5
|
|
|
|
);
|
|
|
|
let tsWristAngle = points.tsWristLeftHelperBottom.angle(
|
|
|
|
points.tsWristLeftHelperTop
|
|
|
|
);
|
|
|
|
let usWristAngle = points.usWristLeftHelperBottom.angle(
|
|
|
|
points.usWristLeftHelperTop
|
|
|
|
);
|
|
|
|
points.tsWristLeft = points.tsWristRight.shift(
|
|
|
|
tsWristAngle - 90,
|
|
|
|
topWrist * -1
|
|
|
|
);
|
|
|
|
points.usWristLeft = points.usWristRight.shift(
|
|
|
|
usWristAngle - 90,
|
|
|
|
underWrist * -1
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
|
|
|
|
// Control points ts
|
2019-05-10 13:14:31 +02:00
|
|
|
points.tsRightEdgeCpTop = points.tsRightEdge.shift(
|
|
|
|
90,
|
|
|
|
points.backPitchPoint.dy(points.tsRightEdge) / 2
|
|
|
|
);
|
|
|
|
points.tsRightEdgeCpBottom = points.tsRightEdgeCpTop.flipY(
|
|
|
|
points.tsRightEdge
|
|
|
|
);
|
|
|
|
points.elbowRightCpTop = points.tsWristRight.shiftFractionTowards(
|
|
|
|
points.elbowRight,
|
|
|
|
1.15
|
|
|
|
);
|
|
|
|
points.topCpRight = points.top.shift(0, factor / 1.6);
|
2019-02-26 17:46:07 +01:00
|
|
|
points.topCpLeft = points.topCpRight.flipX();
|
2019-05-10 13:14:31 +02:00
|
|
|
points.tsLeftEdgeCpRight = points.tsLeftEdge.shift(
|
|
|
|
0,
|
|
|
|
points.tsLeftEdge.dist(points.armLeft) / 2
|
|
|
|
);
|
|
|
|
points.frontPitchPointCpBottom = points.frontPitchPoint.shiftFractionTowards(
|
|
|
|
points.tsLeftEdgeCpRight,
|
|
|
|
0.666
|
|
|
|
);
|
|
|
|
points.frontPitchPointCpTop = points.frontPitchPointCpBottom.rotate(
|
|
|
|
180,
|
|
|
|
points.frontPitchPoint
|
|
|
|
);
|
|
|
|
points.tsElbowLeftCpTop = points.tsWristLeft.shiftFractionTowards(
|
|
|
|
points.tsElbowLeft,
|
|
|
|
1.2
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
|
|
|
|
// Control points us
|
2019-05-10 13:14:31 +02:00
|
|
|
points.usRightEdgeCpBottom = points.usRightEdge.shift(
|
|
|
|
points.usTip.angle(points.elbowRight),
|
|
|
|
points.usTip.dy(points.usRightEdge) / 2
|
|
|
|
);
|
|
|
|
points.usRightEdgeCpTop = points.usRightEdgeCpBottom.rotate(
|
|
|
|
180,
|
|
|
|
points.usRightEdge
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
points._helper1 = new Path()
|
|
|
|
.move(points.backPitchPoint)
|
|
|
|
._curve(points.topCpRight, points.top)
|
|
|
|
.shiftAlong(5);
|
|
|
|
points._helper2 = new Path()
|
|
|
|
.move(points.backPitchPoint)
|
|
|
|
._curve(points.tsRightEdgeCpTop, points.tsRightEdge)
|
|
|
|
.shiftAlong(5);
|
2019-05-10 13:14:31 +02:00
|
|
|
points.usLeftEdgeRight = points.usLeftEdge.shift(
|
|
|
|
0,
|
|
|
|
points.usLeftEdge.dist(points.armCenter) / 3
|
|
|
|
);
|
|
|
|
points.usLeftEdgeCpRight = points.usLeftEdge.shift(
|
|
|
|
0,
|
|
|
|
points.usLeftEdge.dist(points.armCenter) / 1.2
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
|
|
|
|
// Angle of the usTip
|
2019-05-10 13:14:31 +02:00
|
|
|
let angle =
|
|
|
|
points._helper1.angle(points.backPitchPoint) -
|
|
|
|
points.backPitchPoint.angle(points._helper2);
|
|
|
|
points.usTipCpBottom = points.usRightEdgeCpTop.rotate(
|
|
|
|
angle * -1,
|
|
|
|
points.usTip
|
|
|
|
);
|
|
|
|
points.usElbowLeftCpTop = points.usWristLeft.shiftFractionTowards(
|
|
|
|
points.usElbowLeft,
|
|
|
|
1.2
|
|
|
|
);
|
2019-02-26 17:46:07 +01:00
|
|
|
|
|
|
|
// Calculate length of the sleevecap seam
|
|
|
|
let lenTop = new Path()
|
|
|
|
.move(points.backPitchPoint)
|
|
|
|
.curve(points.backPitchPoint, points.topCpRight, points.top)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.topCpLeft,
|
|
|
|
points.frontPitchPointCpTop,
|
|
|
|
points.frontPitchPoint
|
|
|
|
)
|
|
|
|
.curve(
|
|
|
|
points.frontPitchPointCpBottom,
|
|
|
|
points.tsLeftEdgeCpRight,
|
|
|
|
points.tsLeftEdge
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.length();
|
|
|
|
let lenUnder = new Path()
|
|
|
|
.move(points.usTip)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.usTipCpBottom,
|
|
|
|
points.usLeftEdgeCpRight,
|
|
|
|
points.usLeftEdgeRight
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.line(points.usLeftEdge)
|
|
|
|
.length();
|
|
|
|
store.set("sleevecapLength", lenTop + lenUnder);
|
|
|
|
}
|
|
|
|
|
|
|
|
let armholeLength =
|
|
|
|
store.get("frontArmholeLength") + store.get("backArmholeLength");
|
|
|
|
let sleevecapEase = armholeLength * options.sleevecapEase;
|
|
|
|
store.set("sleevecapEase", sleevecapEase);
|
|
|
|
store.set("sleevecapTarget", armholeLength + sleevecapEase);
|
|
|
|
|
|
|
|
let delta = 0;
|
|
|
|
let runs = 0;
|
|
|
|
let tweak = 1;
|
|
|
|
let target = store.get("sleevecapTarget");
|
|
|
|
do {
|
|
|
|
draftSleeve(part, tweak);
|
|
|
|
runs++;
|
|
|
|
delta = store.get("sleevecapLength") - target;
|
|
|
|
if (delta > 0) tweak = tweak * 0.99;
|
|
|
|
else tweak = tweak * 1.02;
|
|
|
|
} while (Math.abs(delta) > 2 && runs < 25);
|
|
|
|
|
|
|
|
// Paths
|
|
|
|
paths.ts = new Path()
|
|
|
|
.move(points.tsWristRight)
|
|
|
|
.line(points.elbowRight)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.elbowRightCpTop,
|
|
|
|
points.tsRightEdgeCpBottom,
|
|
|
|
points.tsRightEdge
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.curve_(points.tsRightEdgeCpTop, points.backPitchPoint)
|
|
|
|
.curve(points.backPitchPoint, points.topCpRight, points.top)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.topCpLeft,
|
|
|
|
points.frontPitchPointCpTop,
|
|
|
|
points.frontPitchPoint
|
|
|
|
)
|
|
|
|
.curve(
|
|
|
|
points.frontPitchPointCpBottom,
|
|
|
|
points.tsLeftEdgeCpRight,
|
|
|
|
points.tsLeftEdge
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.curve(points.tsLeftEdge, points.tsElbowLeftCpTop, points.tsElbowLeft)
|
|
|
|
.line(points.tsWristLeft)
|
|
|
|
.line(points.tsWristRight)
|
|
|
|
.close()
|
|
|
|
.attr("class", "lining");
|
|
|
|
|
|
|
|
paths.us = new Path()
|
|
|
|
.move(points.usWristRight)
|
|
|
|
.line(points.elbowRight)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.elbowRightCpTop,
|
|
|
|
points.usRightEdgeCpBottom,
|
|
|
|
points.usRightEdge
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.curve_(points.usRightEdgeCpTop, points.usTip)
|
2019-05-10 13:14:31 +02:00
|
|
|
.curve(
|
|
|
|
points.usTipCpBottom,
|
|
|
|
points.usLeftEdgeCpRight,
|
|
|
|
points.usLeftEdgeRight
|
|
|
|
)
|
2019-02-26 17:46:07 +01:00
|
|
|
.line(points.usLeftEdge)
|
|
|
|
.curve(points.usLeftEdge, points.usElbowLeftCpTop, points.usElbowLeft)
|
|
|
|
.line(points.usWristLeft)
|
|
|
|
.line(points.usWristRight)
|
|
|
|
.close()
|
|
|
|
.attr("class", "stroke-xl interfacing");
|
|
|
|
|
|
|
|
return part;
|
|
|
|
}
|