1
0
Fork 0
freesewing/designs/shelly/src/base.mjs

212 lines
7.8 KiB
JavaScript

import { withCondition as bustPlugin } from '@freesewing/plugin-bust'
function draftBase({
utils,
Path,
Point,
paths,
points,
measurements,
options,
part,
store,
paperless,
complete,
sa,
macro,
snippets,
Snippet,
scale,
}) {
let hipsEase = options.hipsEase
if (options.straightSides) hipsEase = options.chestEase
const armholeYPosition = measurements.hpsToWaistBack - measurements.waistToArmhole
let chest = measurements.chest * (1 + options.chestEase)
if (options.straightSides) {
chest = Math.max(
measurements.chest * (1 + options.chestEase),
measurements.hips * (1 + hipsEase)
)
}
chest -= 4 * (options.raglanScoopMagnitude * armholeYPosition)
const bodyLength = options.bodyLength * (measurements.hpsToWaistBack + measurements.waistToHips)
const neckRadius = (measurements.neck * (1 + options.neckEase)) / (2 * Math.PI)
const hips = measurements.hips * (1 + hipsEase)
store.set('neckRadius', neckRadius)
points.raglanCenter = new Point(0, 0)
points.neckCenter = points.raglanCenter.shift(270, options.neckBalance * neckRadius)
points.armholeCorner = new Point(chest / 4, armholeYPosition)
points.neckShoulderCorner = utils.beamIntersectsCircle(
points.neckCenter,
neckRadius,
points.raglanCenter,
points.armholeCorner
)[1]
points.cfHem = new Point(0, bodyLength)
points.sideHem = new Point(hips / 4, bodyLength)
points.cfNeck = points.neckCenter.shift(270, neckRadius)
const raglanAngle = points.neckShoulderCorner.angle(points.armholeCorner)
store.set('raglanAngle', raglanAngle)
const raglanLength = points.raglanCenter.dist(points.armholeCorner)
store.set('raglanLength', raglanLength)
const necklineAngleAtRaglan = points.cfNeck.angle(points.neckShoulderCorner) * 2
const necklineArcLength = utils.deg2rad(necklineAngleAtRaglan) * neckRadius
points.neckCP1 = points.neckShoulderCorner.shift(
necklineAngleAtRaglan + 180,
necklineArcLength / 3
)
points.neckCP2 = points.cfNeck.shift(0, necklineArcLength / 3)
const frontNecklineToRaglanAngle = raglanAngle - (necklineAngleAtRaglan + 180)
store.set('frontNecklineToRaglanAngle', frontNecklineToRaglanAngle)
points.armholeCornerScooped = points.armholeCorner.shift(
raglanAngle + 90,
options.raglanScoopMagnitude * raglanLength
)
points.armholeScoopCp1 = points.armholeCorner.shift(
raglanAngle + 180,
(1 / 3) * options.raglanScoopLength * raglanLength
)
points.armholeScoopCp2 = points.armholeCorner.shift(
raglanAngle + 180,
(2 / 3) * options.raglanScoopLength * raglanLength
)
points.armholeScoopEnd = points.armholeCorner.shift(
raglanAngle + 180,
options.raglanScoopLength * raglanLength
)
// Make the side seams vertical if we're making a tubular shirt. Overrides any hips measurements or options.
if (options.straightSides)
points.sideHem.x = Math.max(points.armholeCornerScooped.x, points.sideHem.x)
// Make sure that the shirt at least reaches the armholes, to ensure that the full raglan seam can be formed. This code should only trigger is someone tries to make a really, _really_ short shirt.
if (points.sideHem.y < points.armholeCornerScooped.y) {
points.sideHem.y = points.armholeCornerScooped.y
points.cfHem.y = points.armholeCornerScooped.y
}
const sideAngle = points.sideHem.angle(points.armholeCornerScooped)
const sideLength = points.sideHem.dist(points.armholeCornerScooped)
points.sideCp1 = points.sideHem
.shift(sideAngle, (1 / 3) * sideLength)
.shift(sideAngle - 90, options.sideShape * sideLength)
points.sideCp2 = points.armholeCornerScooped
.shift(sideAngle + 180, (1 / 3) * sideLength)
.shift(sideAngle - 90, options.sideShape * sideLength)
const drawSide = () => {
if (options.straightSides)
return new Path().move(points.sideHem).line(points.armholeCornerScooped)
else
return new Path()
.move(points.sideHem)
.curve(points.sideCp1, points.sideCp2, points.armholeCornerScooped)
}
paths.saBase = new Path().move(points.sideHem)
if (options.straightSides) paths.saBase.line(points.armholeCornerScooped)
else paths.saBase.curve(points.sideCp1, points.sideCp2, points.armholeCornerScooped)
paths.saBase
.curve(points.armholeScoopCp1, points.armholeScoopCp2, points.armholeScoopEnd)
.line(points.neckShoulderCorner)
.curve(points.neckCP1, points.neckCP2, points.cfNeck)
.hide(true)
paths.foldBase = new Path().move(points.cfNeck).line(points.cfHem).hide(true)
paths.hemBase = new Path().move(points.cfHem).line(points.sideHem).hide(true)
paths.seam = paths.saBase.join(paths.foldBase).join(paths.hemBase).close().attr('class', 'fabric')
if (paperless) {
macro('hd', {
from: points.cfHem,
to: points.sideHem,
y: points.sideHem.y + (sa + 15),
})
macro('vd', {
from: points.sideHem,
to: points.armholeCornerScooped,
x: Math.max(points.sideHem.x, points.armholeCornerScooped.x) + (15 + sa),
})
macro('vd', {
from: points.armholeCornerScooped,
to: points.armholeScoopEnd,
x: points.armholeCornerScooped.x + (30 + sa),
})
macro('hd', {
from: points.armholeScoopEnd,
to: points.armholeCornerScooped,
y: 0 - (sa + 0),
})
}
points.cutonfoldFrom = points.cfNeck
points.cutonfoldTo = points.cfHem
macro('cutonfold', {
from: points.cutonfoldFrom,
to: points.cutonfoldTo,
grainline: true,
})
if (complete) {
points.title = new Point(
points.armholeCorner.x / 2,
(points.cfHem.y + points.armholeCornerScooped.y / 2) / 2
)
macro('title', { at: points.title, nr: 5, title: 'base' })
points.logo = points.title.shift(-90, 70 * scale)
snippets.logo = new Snippet('logo', points.logo)
if (sa) {
paths.sa = new Path()
.move(points.cfHem)
.join(paths.hemBase.offset(sa * options.hemWidth * 100))
.join(paths.saBase.offset(sa))
.line(points.cfNeck)
.attr('class', 'fabric sa')
}
}
return part
}
export const base = {
name: 'shelly.base',
plugins: [bustPlugin],
draft: draftBase,
hide: { self: true },
measurements: ['neck', 'chest', 'hips', 'waistToHips', 'hpsToWaistBack', 'waistToArmhole'],
options: {
// How much ease to give for the neck, as a percentage.
neckEase: { pct: 50, min: -30, max: 150, menu: 'fit' },
chestEase: { pct: 0, min: -40, max: 50, menu: 'fit' },
// If set to true, makes a tubular body based on the chest, ignoring the hips measurements and options.
straightSides: { bool: true, menu: 'advanced' },
hipsEase: { pct: 0, min: -30, max: 75, menu: 'advanced' },
bodyLength: { pct: 120, min: 20, max: 300, menu: 'style' },
// How far the neck hole is shifted towards the front. +100% means it's entirely on the front, -100% means it's entirely on the back, and 0 means the front and back are the same.
neckBalance: { pct: 40, min: 0, max: 80, menu: 'fit' },
// Note: The raglan length is the distance between the armhole and where the raglan seams would meet if there were no neckhole. It is used as a base for the following fit options.
// How long the scoop running down the raglan seam is, as a % of the raglan length.
raglanScoopLength: { pct: 20, min: 0, max: 50, menu: 'advanced' },
// How deep the scoop running down the raglan seam is, as a % of the raglan length.
raglanScoopMagnitude: { pct: 6, min: 0, max: 20, menu: 'advanced' },
// Length of the hem around the hips, as a multiple of the seam allowance.
hemWidth: { pct: 2, min: 0, max: 8, menu: 'construction' },
// How the body curves along the side from the armhole to the side of the hips, as a % of the length of the side seam. Negative values form a concave body and positive values form a convex body.
sideShape: { pct: 0, min: -20, max: 20, menu: 'advanced' },
},
optionalMeasurements: ['highBust'],
}