export default (part) => { /* * Helper method to draw the inseam path */ const drawInseam = () => options.fitKnee ? new Path().move(points.floorIn).line(points.kneeIn).curve_(points.kneeInCp2, points.fork) : new Path().move(points.floorIn).curve_(points.kneeInCp2, points.fork) /* * Helper method to draw the outseam path */ const drawOutseam = () => { let waistOut = points.styleWaistOut || points.waistOut if (options.fitKnee) { if (points.waistOut.x < points.seatOut.x) return new Path() .move(waistOut) .curve(points.seatOut, points.kneeOutCp1, points.kneeOut) .line(points.floorOut) else return new Path() .move(waistOut) ._curve(points.seatOutCp1, points.seatOut) .curve(points.seatOutCp2, points.kneeOutCp1, points.kneeOut) .line(points.floorOut) } else { if (points.waistOut.x < points.seatOut.x) return new Path().move(waistOut).curve(points.seatOut, points.kneeOutCp1, points.floorOut) else return new Path() .move(waistOut) ._curve(points.seatOutCp1, points.seatOut) .curve(points.seatOutCp2, points.kneeOutCp1, points.floorOut) } } /* * Helper method to draw the outline path */ const drawPath = () => { let waistIn = points.styleWaistIn || points.waistIn let waistOut = points.styleWaistOut || points.waistOut return drawOutseam() .line(points.floorIn) .join(drawInseam()) .curve(points.crotchSeamCurveCp1, points.crotchSeamCurveCp2, points.crotchSeamCurveStart) .line(waistIn) .line(waistOut) .close() } /* * Helper method to calculate the length of the crotch seam */ const crotchSeamDelta = () => new Path() .move(points.waistIn) .line(points.crotchSeamCurveStart) .curve(points.crotchSeamCurveCp2, points.crotchSeamCurveCp1, points.fork) .length() - measurements.frontCrossSeam /* * Helper method to (re)draw the crotch seam */ const drawCrotchSeam = () => { points.crotchSeamCurveStart = points.waistIn.shiftFractionTowards( points.cfSeat, options.crotchSeamCurveStart ) points.crotchSeamCurveMax = utils.beamsIntersect( points.waistIn, points.cfSeat, points.fork, points.fork.shift(0, 666) ) points.crotchSeamCurveCp1 = points.fork.shiftFractionTowards( points.crotchSeamCurveMax, options.crotchSeamCurveBend ) points.crotchSeamCurveCp2 = points.crotchSeamCurveStart.shiftFractionTowards( points.crotchSeamCurveMax, options.crotchSeamCurveBend ) } /* * Helper method to calculate the inseam delta */ const inseamDelta = () => drawInseam().length() - store.get('inseamBack') /* * Helper method to calculate the outseam delta */ const outseamDelta = () => drawOutseam().length() - store.get('outseamBack') /* * Helper method to lengthen/shorten both inseam and outseam */ const adaptInseamAndOutseam = () => { let shift = [ 'kneeInCp2', 'kneeOutCp1', 'kneeIn', 'kneeOut', 'knee', 'floorIn', 'floorOut', 'floor', 'grainlineBottom' ] let delta = seamDelta() let run = 0 do { run++ for (const i of shift) points[i] = points[i].shift(90, delta) delta = seamDelta() } while (Math.abs(delta) > 1 && run < 10) } /* * Helper method to determine the delta common when both inseam and outseam * are either too long or too short */ const seamDelta = () => { let inseam = inseamDelta() let outseam = outseamDelta() return Math.abs(inseam) > Math.abs(outseam) ? outseam : inseam } /* * Helper method that can fit either inseam or outseam */ const adaptSeam = (side) => { const out = side === 'out' ? true : false let rotate = [ 'cfSeat', 'crotchSeamCurveCp1', 'crotchSeamCurveCp2', 'crotchSeamCurveStart', 'waistIn', 'cfWaist', 'waistOut' ] rotate.push(out ? 'seatOut' : 'fork') const deltaMethod = out ? outseamDelta : inseamDelta let run = 0 let delta = deltaMethod() do { for (const i of rotate) points[i] = points[i].rotate( (delta / 10) * (out ? 1 : -1), points[out ? 'fork' : 'seatOut'] ) run++ delta = deltaMethod() } while (Math.abs(delta) > 1 && run < 20) } const adaptOutseam = (delta) => adaptSeam('out') const adaptInseam = (delta) => adaptSeam('in') let { points, Point, paths, Path, measurements, options, complete, paperless, store, macro, utils, snippets, Snippet } = part.shorthand() // Fuck this noise, I'm starting over points.waistX = new Point(measurements.frontWaistArc * (1 + options.waistEase), 0) points.upperLegY = new Point(0, measurements.waistToUpperLeg) points.seatX = new Point(measurements.frontSeatArc * (1 + options.seatEase), 0) points.seatY = new Point(0, measurements.waistToSeat) points.seatOut = points.seatY points.cfSeat = new Point(points.seatX.x, points.seatY.y) // Determine fork width points.fork = new Point( measurements.frontSeatArc * (1 + options.seatEase) * 1.25, points.upperLegY.y * (1 + options.crotchDrop) ) // Grainline location, map out center of knee and floor points.grainlineTop = points.upperLegY.shiftFractionTowards( points.fork, options.grainlinePosition ) points.knee = new Point(points.grainlineTop.x, measurements.waistToKnee) points.floor = new Point( points.grainlineTop.x, measurements.waistToFloor * (1 + options.lengthBonus) ) points.grainlineBottom = points.floor // Figure out width at the knee let halfKnee = store.get('kneeFront') / 2 points.kneeOut = points.knee.shift(180, halfKnee) points.kneeIn = points.kneeOut.flipX(points.knee) /* * Not shaping the ankle as that's a style choice. * As this is a block, just go straight down from the knee. */ points.floorOut = points.floor.shift(180, halfKnee) points.floorIn = points.floorOut.flipX(points.floor) // Control points to shape the legs towards the seat points.kneeInCp2 = points.kneeIn.shift(90, points.fork.dy(points.knee) / 3) points.kneeOutCp1 = points.kneeOut.shift(90, points.fork.dy(points.knee) / 3) points.seatOutCp1 = points.seatOut.shift(90, points.seatOut.y / 2) points.seatOutCp2 = points.seatOut.shift(-90, points.seatOut.dy(points.knee) / 3) // Balance the waist if (points.cfSeat.x > points.waistX.x) { let delta = points.waistX.dx(points.cfSeat) let width = points.waistX.x points.waistOut = new Point(delta * options.waistBalance, 0) points.waistIn = points.waistOut.shift(0, width) points.cfWaist = points.waistIn } // Draw initial crotch seam drawCrotchSeam() // Uncomment this to see the outline prior to fitting the crotch seam // paths.seam1 = drawPath().attr('class', 'dashed lining') if (options.fitCrossSeam && options.fitFrontCrossSeam) { let delta = crotchSeamDelta() let rotate = ['waistIn', 'waistOut', 'cfWaist'] let run = 0 do { run++ // Remedy A: Slash and spread for (const i of rotate) points[i] = points[i].rotate(delta / -15, points.seatOut) // Remedy B: Nudge the fork inwards/outwards points.fork = points.fork.shift(180, delta / 5) drawCrotchSeam() delta = crotchSeamDelta() // Uncomment the line below this to see all iterations // paths[`try${run}`] = drawPath().attr('class', 'dotted') } while (Math.abs(delta) > 1 && run < 15) } // Uncomment this to see the outline prior to fitting the inseam & outseam // paths.seam2 = drawPath().attr('class', 'dotted interfacing') /* * With the cross seams matched back and front, * all that's left is to match the inseam and outseam */ // When both are too short/long, adapt the leg length if ((inseamDelta() < 0 && outseamDelta() < 0) || (inseamDelta() > 0 && outseamDelta() > 0)) adaptInseamAndOutseam() // Now one is ok, the other will be adapted adaptOutseam(outseamDelta()) adaptInseam(inseamDelta()) // Changing one will ever so slightly impact the other, so let's run both again to be sure adaptOutseam(outseamDelta()) adaptInseam(inseamDelta()) // Only now style the waist lower if requested if (options.waistHeight < 1) { points.styleWaistOut = drawOutseam().shiftAlong( measurements.waistToHips * (1 - options.waistHeight) ) points.styleWaistIn = utils.beamsIntersect( points.styleWaistOut, points.styleWaistOut.shift(points.waistOut.angle(points.waistIn), 10), points.waistIn, points.crotchSeamCurveStart ) } else { points.styleWaistIn = points.waistIn.clone() points.styleWaistOut = points.waistOut.clone() } // Seamline paths.seam = drawPath().attr('class', 'fabric') if (complete) { points.grainlineTop.y = points.styleWaistIn.y macro('grainline', { from: points.grainlineTop, to: points.grainlineBottom }) if (paperless) { } } return part }