From 1896eba914d5712c0893dfe5a72977662cc180e8 Mon Sep 17 00:00:00 2001 From: Benjamin Fan Date: Sun, 18 May 2025 09:43:40 +0000 Subject: [PATCH] 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 Reviewed-on: https://codeberg.org/freesewing/freesewing/pulls/352 Reviewed-by: Joost De Cock Co-authored-by: Benjamin Fan Co-committed-by: Benjamin Fan --- designs/wahid/i18n/en.json | 12 ++++++ designs/wahid/src/back.mjs | 17 ++++++++- designs/wahid/src/front.mjs | 38 +++++++++++++++++-- designs/wahid/src/options.mjs | 1 + designs/wahid/src/shared.mjs | 16 ++++++++ .../wahid/options/legacywaisthips/readme.mdx | 21 ++++++++++ 6 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 sites/org/docs/docs/designs/wahid/options/legacywaisthips/readme.mdx diff --git a/designs/wahid/i18n/en.json b/designs/wahid/i18n/en.json index f5004a7674e..b15a033eea7 100644 --- a/designs/wahid/i18n/en.json +++ b/designs/wahid/i18n/en.json @@ -117,6 +117,18 @@ "centerBackDart": { "t": "Center back dart", "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" } } } diff --git a/designs/wahid/src/back.mjs b/designs/wahid/src/back.mjs index 105c5e7fa83..00cb52344b9 100644 --- a/designs/wahid/src/back.mjs +++ b/designs/wahid/src/back.mjs @@ -1,6 +1,13 @@ import { constructMainDart, shapeSideSeam, dartPath } from './shared.mjs' 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' function wahidBack({ @@ -20,6 +27,13 @@ function wahidBack({ for (let i of Object.keys(paths)) delete paths[i] 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 let shoulderLen = points.shoulder.dist(points.neck) let backInset = shoulderLen * options.backInset @@ -279,6 +293,7 @@ export const back = { neckInset, centerBackDart, backScyeDart, + legacyWaistHips, }, draft: wahidBack, } diff --git a/designs/wahid/src/front.mjs b/designs/wahid/src/front.mjs index 460564467d7..8adff217f51 100644 --- a/designs/wahid/src/front.mjs +++ b/designs/wahid/src/front.mjs @@ -30,6 +30,7 @@ import { s3Armhole, shoulderSlopeReduction, backNeckCutout, + legacyWaistHips, } from './options.mjs' function wahidFront({ @@ -51,6 +52,14 @@ function wahidFront({ // Cleanup from Brian for (let i of Object.keys(paths)) delete paths[i] 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 points.closureTop = new Point( measurements.chest * options.frontOverlap * -1, @@ -176,15 +185,31 @@ function wahidFront({ points.dartHipLeft, points.pocketTopMid.y + pwvh ) - points.pocketTopLeft = points.pocketTopMidLeft.shift(180 + options.pocketAngle, pw / 2) - points.pocketBottomLeft = points.pocketTopLeft.shift(options.pocketAngle - 90, pwh) + // The pocket can start out offset from the horizontal/vertical. + 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.pocketBottomMidRight = points.pocketBottomMidLeft.flipX(points.pocketTopMid) - points.pocketTopRight = points.pocketTopMidRight.shift(options.pocketAngle, pw / 2) - points.pocketBottomRight = points.pocketTopRight.shift(options.pocketAngle - 90, pwh) + points.pocketTopRight = points.pocketTopMidRight.shift( + options.pocketAngle - startingAngleOffset, + pw / 2 + ) + points.pocketBottomRight = points.pocketTopRight.shift( + options.pocketAngle - 90 - startingAngleOffset, + pwh + ) // Store pocket bag length store.set('pocketBagLength', points.pocketTopMid.dy(points.cfHem) * 0.75) 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 points._dartWidth = points.dartTop.shiftFractionTowards( points.armholeHollow.rotate(options.frontScyeDart, points.dartTop), @@ -230,6 +255,10 @@ function wahidFront({ if (typeof points[p] !== 'undefined') 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) } // Facing/Lining boundary (flb) @@ -561,6 +590,7 @@ export const front = { s3Armhole, shoulderSlopeReduction, backNeckCutout, + legacyWaistHips, }, draft: wahidFront, } diff --git a/designs/wahid/src/options.mjs b/designs/wahid/src/options.mjs index a2d0f4b8986..b95b0c6335b 100644 --- a/designs/wahid/src/options.mjs +++ b/designs/wahid/src/options.mjs @@ -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 pocketAngle = { deg: 5, min: 0, max: 5, menu: 'advanced' } export const shoulderSlopeReduction = { pct: 0, min: 0, max: 80, menu: 'advanced' } +export const legacyWaistHips = { bool: false, menu: 'advanced' } // Hide inherited options export const bicepsEase = 0.15 diff --git a/designs/wahid/src/shared.mjs b/designs/wahid/src/shared.mjs index f138af9c00f..a0b3e7098bd 100644 --- a/designs/wahid/src/shared.mjs +++ b/designs/wahid/src/shared.mjs @@ -16,6 +16,22 @@ export const constructMainDart = (part) => { store.set('wr12', wr12) 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.dartWaistRight = points.dartWaistCenter.shift(0, wr12) points.dartWaistLeft = points.dartWaistCenter.shift(180, wr12) diff --git a/sites/org/docs/docs/designs/wahid/options/legacywaisthips/readme.mdx b/sites/org/docs/docs/designs/wahid/options/legacywaisthips/readme.mdx new file mode 100644 index 00000000000..32c8b7aa4f5 --- /dev/null +++ b/sites/org/docs/docs/designs/wahid/options/legacywaisthips/readme.mdx @@ -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.