From 8379361e476f56169b2741b507b8b1b10594f974 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Mon, 6 Aug 2018 16:19:12 +0200 Subject: [PATCH] construction: Sleeve head --- packages/brian/config/config.js | 22 +++- packages/brian/index.html | 16 ++- packages/brian/src/back.js | 79 +++++++------- packages/brian/src/base.js | 52 --------- packages/brian/src/front.js | 77 ++++++-------- packages/brian/src/index.js | 6 +- packages/brian/src/shared.js | 91 ++++++++++++++++ packages/brian/src/sleeve.js | 183 ++++++++++++++++++++++++++++++++ 8 files changed, 381 insertions(+), 145 deletions(-) create mode 100644 packages/brian/src/shared.js create mode 100644 packages/brian/src/sleeve.js diff --git a/packages/brian/config/config.js b/packages/brian/config/config.js index 8700c5df1f6..edb38953067 100644 --- a/packages/brian/config/config.js +++ b/packages/brian/config/config.js @@ -27,13 +27,31 @@ export default { { id: "sleeveLengthBonus", val: 0, min: -40, max: 80 }, // Percentages - { id: "frontArmholeDeeper", val: 0.5, type: "%" }, + { id: "frontArmholeDeeper", val: 0.5, type: "%", min: 0, max: 1.5 }, { id: "chestEase", val: 8, type: "%", min: -4, max: 20 }, { id: "collarEase", val: 3.5, type: "%", min: 0, max: 10 }, { id: "bicepsEase", val: 15, type: "%", min: 0, max: 100 }, { id: "backNeckCutout", val: 5, type: "%", min: 2, max: 8 }, { id: "acrossBackFactor", val: 97, type: "%", min: 93, max: 100 }, { id: "armholeDepthFactor", val: 50, type: "%", min: 35, max: 65 }, - { id: "sleevecapHeightFactor", val: 55, type: "%", min: 35, max: 75 } + { id: "sleevecapHeightFactor", val: 55, type: "%", min: 35, max: 75 }, + { id: "sleevecapBackFactorX", val: 50, type: "%", min: 35, max: 65 }, + { id: "sleevecapBackFactorY", val: 33, type: "%", min: 35, max: 65 }, + { id: "sleevecapFrontFactorX", val: 50, type: "%", min: 35, max: 65 }, + { id: "sleevecapFrontFactorY", val: 33, type: "%", min: 35, max: 65 }, + { id: "sleevecapQ1Offset", val: 5, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ2Offset", val: 5.5, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ3Offset", val: 4.5, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ4Offset", val: 2, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ1Spread1", val: 6, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ1Spread2", val: 15, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ2Spread1", val: 15, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ2Spread2", val: 5, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ3Spread1", val: 5, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ3Spread2", val: 8, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ4Spread1", val: 7, type: "%", min: 0, max: 7 }, + { id: "sleevecapQ4Spread2", val: 7, type: "%", min: 0, max: 7 }, + { id: "sleevecapTopSpread1", val: 5, type: "%", min: 0, max: 7 }, + { id: "sleevecapTopSpread2", val: 5, type: "%", min: 0, max: 7 }, ] }; diff --git a/packages/brian/index.html b/packages/brian/index.html index f9427be9589..3303b47a82e 100644 --- a/packages/brian/index.html +++ b/packages/brian/index.html @@ -31,9 +31,23 @@ shoulderToWrist: 700, wristCircumference: 190 }; + //pattern.options.sleevecapQ1Offset = 0.05; + //pattern.options.sleevecapQ2Offset = 0.055; + //pattern.options.sleevecapQ3Offset = 0.045; + //pattern.options.sleevecapQ4Offset = 0.02; + //pattern.options.sleevecapQ1Spread1 = 0.06; + //pattern.options.sleevecapQ1Spread2 = 0.15; + //pattern.options.sleevecapQ2Spread1 = 0.15; + //pattern.options.sleevecapQ2Spread2 = 0.05; + //pattern.options.sleevecapQ3Spread1 = 0.05; + //pattern.options.sleevecapQ3Spread2 = 0.08; + //pattern.options.sleevecapQ4Spread1 = 0.07; + //pattern.options.sleevecapQ4Spread2 = 0.07; + //pattern.options.sleevecapTopSpread1 = 0.05; + //pattern.options.sleevecapTopSpread2 = 0.05; pattern.settings.mode = 'draft'; pattern.settings.paperless = true; -pattern.settings.sa = 10; +//pattern.settings.sa = 10; pattern.settings.units = 'metric'; pattern.draft(); document.getElementById("svg").innerHTML = pattern.render(); diff --git a/packages/brian/src/back.js b/packages/brian/src/back.js index e88b4738c27..1e06d955f95 100644 --- a/packages/brian/src/back.js +++ b/packages/brian/src/back.js @@ -1,31 +1,31 @@ import freesewing from "freesewing"; +import * as shared from "./shared"; var back = { draft: function(pattern) { let part = new pattern.Part().copy(pattern.parts.base); // prettier-ignore - let {sa, Point, points, Path, paths, Snippet, snippets, final, paperless, macro} = freesewing.utils.shorthand(part); + let {store, sa, Point, points, Path, paths, Snippet, snippets, final, paperless, macro} = freesewing.utils.shorthand(part); - paths.seam = new Path() - .move(points.cbNeck) - .line(points.cbHips) - .line(points.hips) - .line(points.armhole) - .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) - .curve( - points.armholeHollowCp1, - points.armholeHollowCp2, - points.armholePitch - ) - .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder) - .line(points.neck) - .curve(points.neckCp1, points.cbNeck, points.cbNeck) - .close() - .attr("class", "fabric"); + // Seamline + paths.seam = shared.seamLine("back", points, Path); + + // Store lengths to fit sleeve + store.set("backArmholeLength", shared.armholeLength(points, Path)); + store.set( + "backShoulderToArmholePitch", + shared.shoulderToArmholePitch(points, Path) + ); // Final? if (final) { + macro("cutonfold", { + from: points.cbNeck, + to: points.cbHips, + grainline: true + }); + macro("title", { at: points.title, nr: 2, title: "back" }); snippets.armholePitchNotch = new Snippet("notch", points.armholePitch); if (sa) paths.sa = paths.seam.offset(sa).attr("class", "fabric sa"); @@ -33,33 +33,26 @@ var back = { // Paperless? if (paperless) { - macro("pd", { - id: "armholeLengthDimension", - path: new Path() - .move(points.armhole) - .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) - .curve( - points.armholeHollowCp1, - points.armholeHollowCp2, - points.armholePitch - ) - .curve( - points.armholePitchCp1, - points.armholePitchCp2, - points.shoulder - ), - d: sa + 15 + shared.dimensions(macro, points, Path, sa); + macro("hd", { + from: points.cbHips, + to: points.hips, + y: points.hips.y + sa + 15 }); - macro("pd", { - id: "armholePitchDimension", - path: new Path() - .move(points.armholePitch) - .curve( - points.armholePitchCp1, - points.armholePitchCp2, - points.shoulder - ), - d: -15 + macro("vd", { + from: points.cbHips, + to: points.cbNeck, + x: points.cbHips.x - sa - 15 + }); + macro("hd", { + from: points.cbNeck, + to: points.neck, + y: points.neck.y - sa - 15 + }); + macro("hd", { + from: points.cbNeck, + to: points.shoulder, + y: points.neck.y - sa - 30 }); } diff --git a/packages/brian/src/base.js b/packages/brian/src/base.js index 8405a880dbc..c1d053c6d40 100644 --- a/packages/brian/src/base.js +++ b/packages/brian/src/base.js @@ -105,12 +105,6 @@ var base = { // Final? if (final) { - macro("cutonfold", { - from: points.cbNeck, - to: points.cbHips, - grainline: true - }); - points.title = new Point( points.armholePitch.x / 2, points.armholePitch.y @@ -119,52 +113,6 @@ var base = { snippets.logo = new Snippet("logo", points.logo); } - // Paperless? - - if (paperless) { - macro("hd", { - from: points.cbHips, - to: points.hips, - y: points.hips.y + sa + 15 - }); - macro("vd", { - from: points.hips, - to: points.armhole, - x: points.hips.x + sa + 15 - }); - macro("vd", { - from: points.hips, - to: points.armholePitch, - x: points.hips.x + sa + 30 - }); - macro("vd", { - from: points.hips, - to: points.shoulder, - x: points.hips.x + sa + 45 - }); - macro("vd", { - from: points.hips, - to: points.neck, - x: points.hips.x + sa + 60 - }); - macro("vd", { - from: points.cbHips, - to: points.cbNeck, - x: points.cbHips.x - sa - 15 - }); - macro("hd", { - from: points.cbNeck, - to: points.neck, - y: points.neck.y - sa - 15 - }); - macro("hd", { - from: points.cbNeck, - to: points.shoulder, - y: points.neck.y - sa - 30 - }); - macro("ld", { from: points.neck, to: points.shoulder, d: sa + 15 }); - } - return part; } }; diff --git a/packages/brian/src/front.js b/packages/brian/src/front.js index 798fc39324c..b2e301d3ff0 100644 --- a/packages/brian/src/front.js +++ b/packages/brian/src/front.js @@ -1,12 +1,13 @@ import freesewing from "freesewing"; import base from "./base"; +import * as shared from "./shared"; var front = { draft: function(pattern) { let part = new pattern.Part().copy(pattern.parts.back); // prettier-ignore - let {sa, Point, points, Path, paths, Snippet, snippets, options, measurements, final, paperless, macro} = freesewing.utils.shorthand(part); + let {store, sa, Point, points, Path, paths, Snippet, snippets, options, measurements, final, paperless, macro} = freesewing.utils.shorthand(part); // Cut arm a bit deeper at the front let deeper = measurements.chestCircumference * options.frontArmholeDeeper; @@ -16,7 +17,6 @@ var front = { // Rename cb (center back) to cf (center front) for (let key of ["Neck", "Shoulder", "Armhole", "Waist", "Hips"]) { - console.log("key is", key); points[`cf${key}`] = new Point( points[`cb${key}`].x, points[`cb${key}`].y @@ -28,58 +28,49 @@ var front = { points.cfNeck = points.cfNeck.shift(-90, points.neck.x); points.neckCp2 = points.cfNeck.shift(0, points.neck.x * 0.7); - paths.seam = new Path() - .move(points.cfNeck) - .line(points.cfHips) - .line(points.hips) - .line(points.armhole) - .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) - .curve( - points.armholeHollowCp1, - points.armholeHollowCp2, - points.armholePitch - ) - .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder) - .line(points.neck) - .curve(points.neckCp1, points.neckCp2, points.cfNeck) - .close() - .attr("class", "fabric"); + paths.seam = shared.seamLine("front", points, Path); + + // Store lengths to fit sleeve + store.set("frontArmholeLength", shared.armholeLength(points, Path)); + store.set( + "frontShoulderToArmholePitch", + shared.shoulderToArmholePitch(points, Path) + ); // Final? if (final) { + macro("cutonfold", { + from: points.cfNeck, + to: points.cfHips, + grainline: true + }); macro("title", { at: points.title, nr: 1, title: "front" }); snippets.armholePitchNotch = new Snippet("notch", points.armholePitch); if (sa) paths.sa = paths.seam.offset(sa).attr("class", "fabric sa"); } // Paperless? - if (paperless) { - macro("pd", { - path: new Path() - .move(points.armhole) - .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) - .curve( - points.armholeHollowCp1, - points.armholeHollowCp2, - points.armholePitch - ) - .curve( - points.armholePitchCp1, - points.armholePitchCp2, - points.shoulder - ), - d: sa + 15 + shared.dimensions(macro, points, Path, sa); + macro("hd", { + from: points.cfHips, + to: points.hips, + y: points.hips.y + sa + 15 }); - macro("pd", { - path: new Path() - .move(points.armholePitch) - .curve( - points.armholePitchCp1, - points.armholePitchCp2, - points.shoulder - ), - d: -15 + macro("vd", { + from: points.cfHips, + to: points.cfNeck, + x: points.cfHips.x - sa - 15 + }); + macro("hd", { + from: points.cfNeck, + to: points.neck, + y: points.neck.y - sa - 15 + }); + macro("hd", { + from: points.cfNeck, + to: points.shoulder, + y: points.neck.y - sa - 30 }); } diff --git a/packages/brian/src/index.js b/packages/brian/src/index.js index adec16a7fb1..b089e8d7333 100644 --- a/packages/brian/src/index.js +++ b/packages/brian/src/index.js @@ -10,6 +10,7 @@ import { version } from "../package.json"; import base from "./base"; import back from "./back"; import front from "./front"; +import sleeve from "./sleeve"; var pattern = new freesewing.Pattern({ version: version, ...config }) .with(pluginCutonfold) @@ -21,10 +22,7 @@ pattern.draft = function() { pattern.parts.base = base.draft(pattern); pattern.parts.back = back.draft(pattern); pattern.parts.front = front.draft(pattern); - // Clone back - //pattern.parts.front = pattern.parts.back.clone(pattern.parts.front.id); - // Draft front - //front.draft(pattern.parts.front); + pattern.parts.sleeve = sleeve.draft(pattern); return pattern; }; diff --git a/packages/brian/src/shared.js b/packages/brian/src/shared.js new file mode 100644 index 00000000000..acfd26fab20 --- /dev/null +++ b/packages/brian/src/shared.js @@ -0,0 +1,91 @@ +export function seamLine(side, points, Path) { + let path = new Path(); + if (side === "back") { + path.move(points.cbNeck); + path.line(points.cbHips); + } else { + path.move(points.cfNeck); + path.line(points.cfHips); + } + path + .line(points.hips) + .line(points.armhole) + .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) + .curve( + points.armholeHollowCp1, + points.armholeHollowCp2, + points.armholePitch + ) + .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder) + .line(points.neck); + if (side === "back") { + path.curve(points.neckCp1, points.cbNeck, points.cbNeck); + } else { + path.curve(points.neckCp1, points.neckCp2, points.cfNeck); + } + path.close().attr("class", "fabric"); + + return path; +} + +export function armholeLength(points, Path) { + return new Path() + .move(points.armhole) + .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) + .curve( + points.armholeHollowCp1, + points.armholeHollowCp2, + points.armholePitch + ) + .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder) + .length(); +} + +export function shoulderToArmholePitch(points, Path) { + return new Path() + .move(points.armholePitch) + .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder) + .length(); +} + +export function dimensions(macro, points, Path, sa) { + macro("pd", { + path: new Path() + .move(points.armhole) + .curve(points.armholeCp1, points.armholeCp2, points.armholeHollow) + .curve( + points.armholeHollowCp1, + points.armholeHollowCp2, + points.armholePitch + ) + .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder), + d: sa + 15 + }); + macro("pd", { + path: new Path() + .move(points.armholePitch) + .curve(points.armholePitchCp1, points.armholePitchCp2, points.shoulder), + d: -15 + }); + macro("vd", { + from: points.hips, + to: points.armhole, + x: points.hips.x + sa + 15 + }); + macro("vd", { + from: points.hips, + to: points.armholePitch, + x: points.hips.x + sa + 30 + }); + macro("vd", { + from: points.hips, + to: points.shoulder, + x: points.hips.x + sa + 45 + }); + macro("vd", { + from: points.hips, + to: points.neck, + x: points.hips.x + sa + 60 + }); + macro("ld", { from: points.neck, to: points.shoulder, d: sa + 15 }); +} diff --git a/packages/brian/src/sleeve.js b/packages/brian/src/sleeve.js new file mode 100644 index 00000000000..caf55469ced --- /dev/null +++ b/packages/brian/src/sleeve.js @@ -0,0 +1,183 @@ +import freesewing from "freesewing"; + +var sleeve = { + draft: function(pattern) { + let part = new pattern.Part(); + + // prettier-ignore + let {store, sa, measurements, options, Point, points, Path, paths, Snippet, snippets, final, paperless, macro} = freesewing.utils.shorthand(part); + + store.set("sleeveFactor", 1); + + // Sleeve center axis + points.centerCap = new Point(0, 0); + points.centerWrist = new Point( + 0, + measurements.shoulderToWrist * (1 + options.sleeveLengthBonus) + ); + points.centerBiceps = new Point( + 0, + points.centerWrist.y - + measurements.bicepsCircumference * + (1 + options.sleevecapHeightFactor) * + store.get("sleeveFactor") + ); + + // Sleeve half width, limit impact of sleeveTweakFactor to 25% to avoid a too narrow sleeve + let halfWidth = + (measurements.bicepsCircumference * (1 + options.bicepsEase)) / 2; + points.leftBiceps = points.centerBiceps.shift( + 180, + halfWidth * 0.75 + halfWidth * 0.25 * store.get("sleeveFactor") + ); + points.rightBiceps = points.leftBiceps.flipX(points.centerBiceps); + + // Pitch points + points.backPitch = new Point( + points.leftBiceps.x * options.sleevecapBackFactorX, + points.leftBiceps.y * options.sleevecapBackFactorY + ); + points.frontPitch = new Point( + points.rightBiceps.x * options.sleevecapFrontFactorX, + points.rightBiceps.y * options.sleevecapFrontFactorY + ); + + // 4 sleevecap quadrants + // Base points + points.capQ1Base = points.frontPitch.shiftFractionTowards( + points.rightBiceps, + 0.5 + ); + points.capQ2Base = points.frontPitch.shiftFractionTowards( + points.centerCap, + 0.5 + ); + points.capQ3Base = points.backPitch.shiftFractionTowards( + points.centerCap, + 0.5 + ); + points.capQ4Base = points.backPitch.shiftFractionTowards( + points.leftBiceps, + 0.5 + ); + // Offset points + let baseOffset = + measurements.bicepsCircumference * (1 + options.bicepsEase); + points.capQ1 = points.capQ1Base.shift( + points.rightBiceps.angle(points.frontPitch) + 90, + baseOffset * options.sleevecapQ1Offset + ); + points.capQ2 = points.capQ2Base.shift( + points.centerCap.angle(points.frontPitch) + 90, + baseOffset * options.sleevecapQ2Offset + ); + points.capQ3 = points.capQ3Base.shift( + points.centerCap.angle(points.backPitch) - 90, + baseOffset * options.sleevecapQ3Offset + ); + points.capQ4 = points.capQ4Base.shift( + points.leftBiceps.angle(points.backPitch) - 90, + baseOffset * options.sleevecapQ4Offset + ); + // Control points + points.capQ1Cp1 = points.capQ1.shift( + points.frontPitch.angle(points.rightBiceps), + baseOffset * options.sleevecapQ1Spread1 + ); + points.capQ1Cp2 = points.capQ1.shift( + points.frontPitch.angle(points.rightBiceps), + baseOffset * options.sleevecapQ1Spread2 * -1 + ); + points.capQ2Cp1 = points.capQ2.shift( + points.centerCap.angle(points.frontPitch), + baseOffset * options.sleevecapQ2Spread1 + ); + points.capQ2Cp2 = points.capQ2.shift( + points.centerCap.angle(points.frontPitch), + baseOffset * options.sleevecapQ2Spread2 * -1 + ); + points.capQ3Cp1 = points.capQ3.shift( + points.backPitch.angle(points.centerCap), + baseOffset * options.sleevecapQ3Spread1 + ); + points.capQ3Cp2 = points.capQ3.shift( + points.backPitch.angle(points.centerCap), + baseOffset * options.sleevecapQ3Spread2 * -1 + ); + points.capQ4Cp1 = points.capQ4.shift( + points.leftBiceps.angle(points.backPitch), + baseOffset * options.sleevecapQ4Spread1 + ); + points.capQ4Cp2 = points.capQ4.shift( + points.leftBiceps.angle(points.backPitch), + baseOffset * options.sleevecapQ4Spread2 * -1 + ); + // Center cap control points + points.centerCapCp1 = points.centerCap.shift( + points.capQ3.angle(points.capQ2), + baseOffset * options.sleevecapTopSpread1 + ); + points.centerCapCp2 = points.centerCap.shift( + points.capQ3.angle(points.capQ2), + baseOffset * options.sleevecapTopSpread2 * -1 + ); + + paths.test = new Path() + .move(points.centerWrist) + .line(points.centerCap) + .move(points.leftBiceps) + .line(points.rightBiceps) + .curve(points.rightBiceps, points.capQ1Cp1, points.capQ1) + .curve(points.capQ1Cp2, points.capQ2Cp1, points.capQ2) + .curve(points.capQ2Cp2, points.centerCapCp1, points.centerCap) + .curve(points.centerCapCp2, points.capQ3Cp1, points.capQ3) + .curve(points.capQ3Cp2, points.capQ4Cp1, points.capQ4) + .curve(points.capQ4Cp2, points.leftBiceps, points.leftBiceps); + //// Wrist + //$wristWidth = $model->getMeasurement('wristCircumference') + $this->getOption('cuffEase'); + //$p->newPoint(31, $wristWidth / -2, $p->y(3), 'Wrist point back'); + //$p->newPoint(32, $wristWidth / 2, $p->y(3), 'Wrist point front'); + //// Elbow location + //$p->newPoint(33, 0, $p->y(2) + $p->distance(2, 3) / 2 - 25, 'Elbow point'); + //$p->addPoint('.help1', $p->shift(33, 0, 10)); + //$p->addPoint(34, $p->beamsCross(-5, 31, 33, '.help1'), 'Elbow point back side'); + //$p->addPoint(35, $p->beamsCross(5, 32, 33, 34), 'Elbow point front side'); + //$path = 'M 31 L -5 C -5 20 16 C 21 10 10 C 10 22 17 C 23 28 30 C 29 25 18 C 24 11 11 C 11 27 19 C 26 5 5 L 32 z'; + //$p->newPath('seamline', $path, ['class' => 'fabric']); + //// Mark path for sample service + //$p->paths['seamline']->setSample(true); + // + //// Store sleevehead length + //$this->setValue('sleeveheadLength', + // $p->curveLen(-5,-5,20,16) + + // $p->curveLen(16,21,10,10) + + // $p->curveLen(10,10,22,17) + + // $p->curveLen(17,23,28,30) + + // $p->curveLen(30,29,25,18) + + // $p->curveLen(18,24,11,11) + + // $p->curveLen(11,11,27,19) + + // $p->curveLen(19,26,5,5) + //); + + // Anchor point for sampling + points.gridAnchor = points.origin; + points.test = new Point(10, 10); + console.log(part); + + // Final? + if (final) { + //macro("title", { at: points.title, nr: 2, title: "back" }); + //snippets.armholePitchNotch = new Snippet("notch", points.armholePitch); + //if (sa) paths.sa = paths.seam.offset(sa).attr("class", "fabric sa"); + } + + // Paperless? + if (paperless) { + //shared.dimensions(macro, points, Path, sa); + } + + return part; + } +}; + +export default sleeve;