sparkles: Auto-fitting of collar via brianFitCollar option
This commit is contained in:
parent
bb81f44678
commit
ebb29cd5c5
9 changed files with 982 additions and 923 deletions
|
@ -14,6 +14,7 @@ export default {
|
|||
options: {
|
||||
// Constants
|
||||
brianFitSleeve: true,
|
||||
brianFitCollar: true,
|
||||
collarFactor: 4.8,
|
||||
|
||||
// Percentages
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
focus: 'manSize34',
|
||||
models: freesewing.models.men
|
||||
}
|
||||
pattern.settings.onl='base';
|
||||
pattern.settings.nly= ['base'];
|
||||
//pattern.options.brianFitSleeve = false;
|
||||
//pattern.options.brianFitCollar = false;
|
||||
//pattern.sampleOption('shoulderSlopeReduction');
|
||||
//pattern.sampleMeasurement('shoulderSlope');
|
||||
//pattern.sampleModels(freesewing.models.men, 'manSize34');
|
||||
|
|
1798
packages/brian/package-lock.json
generated
1798
packages/brian/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -59,8 +59,8 @@
|
|||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"@freesewing/antman": "0.2.0",
|
||||
"@freesewing/models": "0.4.0",
|
||||
"@freesewing/plugin-debug": "0.1.0",
|
||||
"@freesewing/plugin-designer": "0.7.2",
|
||||
"@freesewing/plugin-debug": "0.3.0",
|
||||
"@freesewing/plugin-designer": "0.8.0",
|
||||
"@freesewing/plugin-theme": "0.13.2",
|
||||
"@freesewing/plugin-validate": "0.2.0",
|
||||
"@freesewing/plugin-i18n": "0.0.1",
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import freesewing from "freesewing";
|
||||
import * as shared from "./shared";
|
||||
|
||||
var base = {
|
||||
draft: function(part) {
|
||||
part.render = false;
|
||||
|
||||
// prettier-ignore
|
||||
let {measurements, options, store, points, snippets, Point, Snippet, utils, complete } = part.shorthand();
|
||||
let {units, debug, measurements, options, store, points, snippets, Point, Snippet, Path, paths, utils, complete } = part.shorthand();
|
||||
|
||||
store.set(
|
||||
"shoulderEase",
|
||||
|
@ -100,7 +99,7 @@ var base = {
|
|||
.shiftTowards(points.neck, points.shoulder.dy(points.armholePitch) / 5)
|
||||
.rotate(90, points.shoulder);
|
||||
|
||||
// Neck opening
|
||||
// Neck opening (back)
|
||||
points._tmp4 = points.neck
|
||||
.shiftTowards(points.shoulder, 10)
|
||||
.rotate(-90, points.neck);
|
||||
|
@ -110,9 +109,56 @@ var base = {
|
|||
points.cbNeck.y
|
||||
);
|
||||
|
||||
// Fit collar
|
||||
points.cfNeck = points.neck.rotate(-90, new Point(0, 0));
|
||||
let target = measurements.neckCircumference * (1 + options.collarEase);
|
||||
let delta = 0;
|
||||
let run = 0;
|
||||
do {
|
||||
run++;
|
||||
points.cfNeck = points.cfNeck.shift(90, delta / 3);
|
||||
points.frontNeckCpEdge = utils.beamsIntersect(
|
||||
points.neck,
|
||||
points.neckCp2,
|
||||
points.cfNeck,
|
||||
new Point(20, points.cfNeck.y)
|
||||
);
|
||||
points.cfNeckCp1 = points.cfNeck.shiftFractionTowards(
|
||||
points.frontNeckCpEdge,
|
||||
0.55
|
||||
);
|
||||
points.neckCp2Front = points.neck.shiftFractionTowards(
|
||||
points.frontNeckCpEdge,
|
||||
0.65
|
||||
);
|
||||
paths.neckOpening = new Path()
|
||||
.move(points.cfNeck)
|
||||
.curve(points.cfNeckCp1, points.neckCp2Front, points.neck)
|
||||
.curve(points.neckCp2, points.cbNeck, points.cbNeck)
|
||||
.attr("class", "dashed stroke-xl various");
|
||||
delta = paths.neckOpening.length() * 2 - target;
|
||||
} while (Math.abs(delta) > 1 && options.brianFitCollar && run < 10);
|
||||
delete paths.neckOpening;
|
||||
if (options.brianFitCollar) {
|
||||
debug(
|
||||
{ style: "success", label: "🏁 Collar fitted" },
|
||||
// prettier-ignore
|
||||
`Target was ${units(target)}, delta of ${units(delta)} reached in ${run} attempts.`
|
||||
);
|
||||
} else
|
||||
debug({ style: "warning", label: "🚫 Not fitting collar" }, "(in Brian)");
|
||||
|
||||
// Anchor point for sampling
|
||||
points.gridAnchor = points.cbHips;
|
||||
|
||||
// Seamline
|
||||
paths.saBase = shared.saBase("back", points, Path);
|
||||
paths.seam = new Path()
|
||||
.move(points.cbNeck)
|
||||
.line(points.cbHips)
|
||||
.join(paths.saBase)
|
||||
.attr("class", "fabric");
|
||||
|
||||
// Complete pattern?
|
||||
if (complete) {
|
||||
points.title = new Point(
|
||||
|
|
|
@ -14,17 +14,15 @@ var front = {
|
|||
points.armholePitchCp2.x -= deeper;
|
||||
|
||||
// Rename cb (center back) to cf (center front)
|
||||
for (let key of ["Neck", "Shoulder", "Armhole", "Waist", "Hips"]) {
|
||||
for (let key of ["Shoulder", "Armhole", "Waist", "Hips"]) {
|
||||
points[`cf${key}`] = new Point(
|
||||
points[`cb${key}`].x,
|
||||
points[`cb${key}`].y
|
||||
);
|
||||
delete points[`cb${key}`];
|
||||
}
|
||||
|
||||
// Adapt neck opening
|
||||
points.cfNeck = points.cfNeck.shift(-90, points.neck.x);
|
||||
points.neckCp2 = points.cfNeck.shift(0, points.neck.x * 0.7);
|
||||
// Front neckline points
|
||||
points.neckCp2 = new Point(points.neckCp2Front.x, points.neckCp2Front.y);
|
||||
|
||||
// Seamline
|
||||
paths.saBase = shared.saBase("front", points, Path);
|
||||
|
|
|
@ -12,7 +12,7 @@ export function saBase(side, points, Path) {
|
|||
if (side === "back") {
|
||||
path.curve(points.neckCp2, points.cbNeck, points.cbNeck);
|
||||
} else {
|
||||
path.curve(points.neckCp2, points.cfNeck, points.cfNeck);
|
||||
path.curve(points.neckCp2, points.cfNeckCp1, points.cfNeck);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
|
|
@ -7,8 +7,11 @@ var sleeve = {
|
|||
|
||||
// Wrist
|
||||
let top = paths.sleevecap.bbox().topLeft.y;
|
||||
debug("Sleevecap height is ", units(Math.abs(top)));
|
||||
debug("Sleeve width is ", units(points.bicepsRight.x * 2));
|
||||
debug({ style: "info", label: "🗸 Sleevecap height" }, units(Math.abs(top)));
|
||||
debug(
|
||||
{ style: "info", label: "🗸 Sleevecap width" },
|
||||
units(points.bicepsRight.x * 2)
|
||||
);
|
||||
points.centerWrist = new Point(
|
||||
0,
|
||||
top + measurements.shoulderToWrist * (1 + options.sleeveLengthBonus)
|
||||
|
|
|
@ -131,13 +131,13 @@ function draftSleevecap(part, run) {
|
|||
|
||||
// Store sleevecap length
|
||||
store.set("sleevecapLength", paths.sleevecap.length());
|
||||
if (run === 1) {
|
||||
if (run === 0) {
|
||||
let armholeLength =
|
||||
store.get("frontArmholeLength") + store.get("backArmholeLength");
|
||||
let sleevecapEase = armholeLength * options.sleevecapEase;
|
||||
store.set("sleevecapEase", sleevecapEase);
|
||||
store.set("sleevecapTarget", armholeLength + sleevecapEase);
|
||||
debug("Sleevecap ease is", units(sleevecapEase));
|
||||
debug({ style: "info", label: "🗸 Sleevecap ease" }, units(sleevecapEase));
|
||||
|
||||
// Uncomment this line to see all sleevecap iterations
|
||||
//paths[run] = paths.sleevecap;
|
||||
|
@ -150,21 +150,30 @@ var sleevecap = {
|
|||
let {debug, store, units, sa, measurements, options, Point, points, Path, paths } = part.shorthand();
|
||||
|
||||
store.set("sleeveFactor", 1);
|
||||
let run = 1;
|
||||
let run = 0;
|
||||
let delta = 0;
|
||||
do {
|
||||
draftSleevecap(part, run);
|
||||
debug(
|
||||
`Sleevecap draft ${run}, sleevecap delta is ${units(
|
||||
sleevecapDelta(store)
|
||||
)}`
|
||||
);
|
||||
delta = sleevecapDelta(store);
|
||||
sleevecapAdjust(store);
|
||||
run++;
|
||||
} while (
|
||||
options.brianFitSleeve === true &&
|
||||
run < 100 &&
|
||||
run < 30 &&
|
||||
Math.abs(sleevecapDelta(store)) > 2
|
||||
);
|
||||
if (options.brianFitSleeve) {
|
||||
debug(
|
||||
{ style: "success", label: "🏁 Sleevecap fitted" },
|
||||
`Target was ${units(store.get("sleevecapTarget"))}, delta of ${units(
|
||||
delta
|
||||
)} reached in ${run} attempts.`
|
||||
);
|
||||
} else
|
||||
debug(
|
||||
{ style: "warning", label: "🚫 Not fitting sleevecap" },
|
||||
"(in Brian)"
|
||||
);
|
||||
|
||||
// Paths
|
||||
paths.sleevecap.attr("class", "fabric");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue