1
0
Fork 0

fix(wahid): Add new waist, hips, and pocket calculations (#352)

This PR changes how the Wahid pattern is generated to improve widths at the waist and hips. It does so by using the actual waist and hips measurements to generate the waist and hips points, as opposed to the old method which used the chest circumference as the base to approximate the waist and hips points. The new method results in a pattern where the chest/waist/hips widths of the garment are exactly the values of chest/waist/hips measurements plus ease.

The changes are controlled by a new Legacy Waist and Hips option. The option is disabled by default, but when it is enabled the Wahid pattern is generated the old way. So, users will be able to generate the same Wahid patterns as before, if desired.

The PR also contains a fix for the front pocket angle.

The waist and hips changes were tested by someone who reported that it fixed their sway back issue:
https://discord.com/channels/698854858052075530/757631205804998759/1367899207553388556
discord://discord.com/channels/698854858052075530/757631205804998759/1367899207553388556

Fixes #302
Fixes #328

Co-authored-by: Benjamin Fan <ben-git@swinglonga.com>
Reviewed-on: https://codeberg.org/freesewing/freesewing/pulls/352
Reviewed-by: Joost De Cock <joostdecock@noreply.codeberg.org>
Co-authored-by: Benjamin Fan <benjamesben@noreply.codeberg.org>
Co-committed-by: Benjamin Fan <benjamesben@noreply.codeberg.org>
This commit is contained in:
Benjamin Fan 2025-05-18 09:43:40 +00:00 committed by Joost De Cock
parent 3390def67c
commit 1896eba914
6 changed files with 100 additions and 5 deletions

View file

@ -117,6 +117,18 @@
"centerBackDart": { "centerBackDart": {
"t": "Center back dart", "t": "Center back dart",
"d": "Whether or not to include a center back dart to fit a rounded back." "d": "Whether or not to include a center back dart to fit a rounded back."
},
"legacyWaistHips": {
"t": "Legacy waist and hips widths",
"d": "Enable this option to use the legacy (v3) way to calculate the waist and hips widths (using chest circumference) rather than the new way (using the waist and hips measurements)."
},
"legacyWaistHipsNo": {
"t": "Calculate waist and hips widths the new way",
"d": "Uses the waist and hips measurements to calculate the waist and hips widths"
},
"legacyWaistHipsYes": {
"t": "Calculate waist and hips widths the legacy (v3) way",
"d": "Uses the chest measurement to approximate the waist and hips widths"
} }
} }
} }

View file

@ -1,6 +1,13 @@
import { constructMainDart, shapeSideSeam, dartPath } from './shared.mjs' import { constructMainDart, shapeSideSeam, dartPath } from './shared.mjs'
import { back as brianBack } from '@freesewing/brian' import { back as brianBack } from '@freesewing/brian'
import { backInset, shoulderInset, neckInset, centerBackDart, backScyeDart } from './options.mjs' import {
backInset,
shoulderInset,
neckInset,
centerBackDart,
backScyeDart,
legacyWaistHips,
} from './options.mjs'
import { hidePresets } from '@freesewing/core' import { hidePresets } from '@freesewing/core'
function wahidBack({ function wahidBack({
@ -20,6 +27,13 @@ function wahidBack({
for (let i of Object.keys(paths)) delete paths[i] for (let i of Object.keys(paths)) delete paths[i]
delete snippets.armholePitchNotch delete snippets.armholePitchNotch
if (!options.legacyWaistHips) {
// Use actual measurements to set waist and hips points
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cbWaist.y)
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cbHips.y)
points.hem = new Point(points.hips.x, points.cbHem.y)
}
// Back inset // Back inset
let shoulderLen = points.shoulder.dist(points.neck) let shoulderLen = points.shoulder.dist(points.neck)
let backInset = shoulderLen * options.backInset let backInset = shoulderLen * options.backInset
@ -279,6 +293,7 @@ export const back = {
neckInset, neckInset,
centerBackDart, centerBackDart,
backScyeDart, backScyeDart,
legacyWaistHips,
}, },
draft: wahidBack, draft: wahidBack,
} }

View file

@ -30,6 +30,7 @@ import {
s3Armhole, s3Armhole,
shoulderSlopeReduction, shoulderSlopeReduction,
backNeckCutout, backNeckCutout,
legacyWaistHips,
} from './options.mjs' } from './options.mjs'
function wahidFront({ function wahidFront({
@ -51,6 +52,14 @@ function wahidFront({
// Cleanup from Brian // Cleanup from Brian
for (let i of Object.keys(paths)) delete paths[i] for (let i of Object.keys(paths)) delete paths[i]
delete snippets.armholePitchNotch delete snippets.armholePitchNotch
if (!options.legacyWaistHips) {
// Use actual measurements to set waist and hips points
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cfWaist.y)
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cfHips.y)
points.hem = new Point(points.hips.x, points.cfHem.y)
}
// Neck cutout // Neck cutout
points.closureTop = new Point( points.closureTop = new Point(
measurements.chest * options.frontOverlap * -1, measurements.chest * options.frontOverlap * -1,
@ -176,15 +185,31 @@ function wahidFront({
points.dartHipLeft, points.dartHipLeft,
points.pocketTopMid.y + pwvh points.pocketTopMid.y + pwvh
) )
points.pocketTopLeft = points.pocketTopMidLeft.shift(180 + options.pocketAngle, pw / 2) // The pocket can start out offset from the horizontal/vertical.
points.pocketBottomLeft = points.pocketTopLeft.shift(options.pocketAngle - 90, pwh) const startingAngleOffset = points.pocketBottomMidLeft.angle(points.pocketTopMidLeft) - 90
points.pocketTopLeft = points.pocketTopMidLeft.shift(
180 + options.pocketAngle + startingAngleOffset,
pw / 2
)
points.pocketBottomLeft = points.pocketTopLeft.shift(
options.pocketAngle - 90 + startingAngleOffset,
pwh
)
points.pocketTopMidRight = points.pocketTopMidLeft.flipX(points.pocketTopMid) points.pocketTopMidRight = points.pocketTopMidLeft.flipX(points.pocketTopMid)
points.pocketBottomMidRight = points.pocketBottomMidLeft.flipX(points.pocketTopMid) points.pocketBottomMidRight = points.pocketBottomMidLeft.flipX(points.pocketTopMid)
points.pocketTopRight = points.pocketTopMidRight.shift(options.pocketAngle, pw / 2) points.pocketTopRight = points.pocketTopMidRight.shift(
points.pocketBottomRight = points.pocketTopRight.shift(options.pocketAngle - 90, pwh) options.pocketAngle - startingAngleOffset,
pw / 2
)
points.pocketBottomRight = points.pocketTopRight.shift(
options.pocketAngle - 90 - startingAngleOffset,
pwh
)
// Store pocket bag length // Store pocket bag length
store.set('pocketBagLength', points.pocketTopMid.dy(points.cfHem) * 0.75) store.set('pocketBagLength', points.pocketTopMid.dy(points.cfHem) * 0.75)
if (options.frontScyeDart) { if (options.frontScyeDart) {
// Save original armhole width so we can restore it later
const original_chest_width = points.cfArmhole.dist(points.armhole)
// Front scye dart // Front scye dart
points._dartWidth = points.dartTop.shiftFractionTowards( points._dartWidth = points.dartTop.shiftFractionTowards(
points.armholeHollow.rotate(options.frontScyeDart, points.dartTop), points.armholeHollow.rotate(options.frontScyeDart, points.dartTop),
@ -230,6 +255,10 @@ function wahidFront({
if (typeof points[p] !== 'undefined') if (typeof points[p] !== 'undefined')
points[p] = points[p].rotate(options.frontScyeDart, points.dartTop) points[p] = points[p].rotate(options.frontScyeDart, points.dartTop)
} }
if (!options.legacyWaistHips) {
// Set armhole back to original width
points.armhole = points.cfArmhole.shiftTowards(points.armhole, original_chest_width)
}
points.armholeHollowCp1 = points.armholeHollowCp2.rotate(180, points.armholeHollow) points.armholeHollowCp1 = points.armholeHollowCp2.rotate(180, points.armholeHollow)
} }
// Facing/Lining boundary (flb) // Facing/Lining boundary (flb)
@ -561,6 +590,7 @@ export const front = {
s3Armhole, s3Armhole,
shoulderSlopeReduction, shoulderSlopeReduction,
backNeckCutout, backNeckCutout,
legacyWaistHips,
}, },
draft: wahidFront, draft: wahidFront,
} }

View file

@ -28,6 +28,7 @@ export const shoulderInset = { pct: 10, min: 0, max: 20, menu: 'advanced' }
export const neckInset = { pct: 5, min: 0, max: 10, menu: 'advanced' } export const neckInset = { pct: 5, min: 0, max: 10, menu: 'advanced' }
export const pocketAngle = { deg: 5, min: 0, max: 5, menu: 'advanced' } export const pocketAngle = { deg: 5, min: 0, max: 5, menu: 'advanced' }
export const shoulderSlopeReduction = { pct: 0, min: 0, max: 80, menu: 'advanced' } export const shoulderSlopeReduction = { pct: 0, min: 0, max: 80, menu: 'advanced' }
export const legacyWaistHips = { bool: false, menu: 'advanced' }
// Hide inherited options // Hide inherited options
export const bicepsEase = 0.15 export const bicepsEase = 0.15

View file

@ -16,6 +16,22 @@ export const constructMainDart = (part) => {
store.set('wr12', wr12) store.set('wr12', wr12)
store.set('hr12', hr12) store.set('hr12', hr12)
if (!options.legacyWaistHips) {
// Use largest chest-or-hips measurement to determine reduction
const largest_measurement = chest >= hips ? chest : hips
reduce.waist = largest_measurement - waist
reduce.hips = largest_measurement - hips
if (reduce.hips < 0) reduce.hips = 0
if (reduce.waist < 0) reduce.waist = 0
// Use a different reduction factor
const reduction_factor = 15
wr12 = reduce.waist / reduction_factor
hr12 = reduce.hips / reduction_factor
// Shift side seam to other direction by total amount added to dart
store.set('wr12', wr12 * -2)
store.set('hr12', hr12 * -2)
}
points.dartWaistCenter = new Point(points.armhole.x / 2, points.waist.y) points.dartWaistCenter = new Point(points.armhole.x / 2, points.waist.y)
points.dartWaistRight = points.dartWaistCenter.shift(0, wr12) points.dartWaistRight = points.dartWaistCenter.shift(0, wr12)
points.dartWaistLeft = points.dartWaistCenter.shift(180, wr12) points.dartWaistLeft = points.dartWaistCenter.shift(180, wr12)

View file

@ -0,0 +1,21 @@
---
title: 'Legacy waist and hips calculations'
---
This option allows you to use the legacy way of calculating the waist
and hips.
The legacy (v3) way used the chest circumference to set the intial waist
and hips points.
It then used waist and hips measurements to attempt to move the waist
and hips points towards the actual measurement values.
The new, v4 way instead uses the actual waist and hips measurements to
set the waist and hips points.
It also contains corrections to the front waist dart and side seam
adjustments to maintain the correct width and ease at the waist and hips.
It also adjusts the armhole point after the dart rotation to maintain
the correct width and ease at the armhole.
If you enable this option, Wahid will revert to the v3 way of calculating
waist and hips points.