function getQuarterPanelsPatternWidth(innerRadius, outerRadius, fabricWidth, repetitions) { const twoR = outerRadius * 2; const trapezoidWidth = Math.sqrt(twoR * twoR - fabricWidth * fabricWidth); const arcToArcWidth = 2 * outerRadius - fabricWidth; const bellyOverlap = 2 * outerRadius - trapezoidWidth; const waistHoleWidth = innerRadius * (Math.SQRT2/2); const singlePanelWidth = outerRadius - waistHoleWidth; const overlap = arcToArcWidth - bellyOverlap >= singlePanelWidth ? bellyOverlap : arcToArcWidth - singlePanelWidth; return repetitions * arcToArcWidth - (repetitions - 1) * overlap; } const quarterPanelInstructions = "It is easiest if you prepare a pattern piece on paper: Draw a straight line and a second line at 45 degrees, such that the lines cross close to the corner of your paper. The crossing point is the center of your circles. Mark the waist radius and full radius from the crossing point, so you get a circle segment. Add seam allowance to the side edges of your segment, then cut it out. Use this pattern to cut all the pieces from your fabric as per the diagram." const halfSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius; }, hasBiasSeams: false, imagePath: "assets/half-fit.svg", instructions: "Place your circle center mark in the corner of your folded fabric, on the fold but one seam allowance width away from the raw edge. Mark your waist radius and full radius as quarter-circles from this point.", } const threeqSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius + outerRadius * (Math.SQRT2/2); }, hasBiasSeams: true, imagePath: "assets/threeq-fit.svg", instructions: "Place your circle center mark on the fold, one full radius away from the raw edge. Mark your waist radius and full radius from this point. Then draw a 45-degree line from the circle center mark to find the edge of your skirt piece. Add seam allowance to this edge.", } const fullSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius * 2; }, hasBiasSeams: false, imagePath: "assets/full-fit.svg", instructions: "Fold your fabric twice. Place your circle center mark in the corner of your folded fabric. Mark your waist radius and full radius as quarter-circles from this point.", } const fullSkirtFullFitThrifty = { // maybe I'll use this later, scoped out for now calculateYardage: function (innerRadius, outerRadius, fabricWidth) { const w = fabricWidth / 2; const twoR = outerRadius * 2; return Math.sqrt(twoR * twoR - w * w) }, hasBiasSeams: false, imagePath: "assets/full-fit.svg", } const halfSkirtHalfFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius * 2; }, hasBiasSeams: false, imagePath: "assets/half-half.svg", instructions: "Place your circle center mark on the selvage of your un-folded fabric, one seam allowance width away from the selvage edge and one full radius away from the raw edge. Mark your waist radius and full radius.", } const threeqSkirtHalfFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { const twoR = outerRadius * 2; const overlap = Math.sqrt(twoR * twoR - fabricWidth * fabricWidth) return outerRadius + overlap; }, hasBiasSeams: false, imagePath: "assets/threeq-half.svg", instructions: "Place your first circle center mark on the selvage of your un-folded fabric, one seam allowance width away from the selvage edge and one full radius away from the raw edge. Mark your waist radius and full radius. Then, place your second circle center mark diagonally-opposite on the other selvage, trying to get the second skirt panel as close to the first one as possible to save fabric. Make sure to place it one seam allowance width away from the selvage edge.", } const fullSkirtHalfFit = { calculateYardage:function (innerRadius, outerRadius, fabricWidth) { const twoR = outerRadius * 2; const overlap = Math.sqrt(twoR * twoR - fabricWidth * fabricWidth) return outerRadius * 2 + overlap; }, hasBiasSeams: false, imagePath: "assets/full-half.svg", instructions: "Place your first circle center mark on the selvage of your un-folded fabric, one seam allowance width away from the selvage edge and one full radius away from the raw edge. Mark your waist radius and full radius. Then, place your second circle center mark diagonally-opposite on the other selvage, trying to get the second skirt panel as close to the first one as possible to save fabric. Make sure to place it one seam allowance width away from the selvage edge.", } const halfSkirtNoFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return getQuarterPanelsPatternWidth(innerRadius, outerRadius, fabricWidth, 2); }, hasBiasSeams: true, imagePath: "assets/half-no.svg", instructions: quarterPanelInstructions, } const threeqSkirtNoFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return getQuarterPanelsPatternWidth(innerRadius, outerRadius, fabricWidth, 3); }, hasBiasSeams: true, imagePath: "assets/threeq-no.svg", instructions: quarterPanelInstructions, } const fullSkirtNoFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return getQuarterPanelsPatternWidth(innerRadius, outerRadius, fabricWidth, 4); }, hasBiasSeams: true, imagePath: "assets/full-no.svg", instructions: quarterPanelInstructions, } const errorState = { hasBiasSeams: false, imagePath: "assets/emptystate.svg", yardage: "error", instructions: "Your skirt is so big, we couldn't find ready-made cutting instructions for it. We can't calculate the yardage either. But you can still use the circle radii. Good luck!", } const finder = { full: { fit: fullSkirtFullFit, half: fullSkirtHalfFit, no: fullSkirtNoFit, }, threeq: { fit: threeqSkirtFullFit, half: threeqSkirtHalfFit, no: threeqSkirtNoFit, }, half: { fit: halfSkirtFullFit, half: halfSkirtHalfFit, no: halfSkirtNoFit, } } const centimeterDefaults = { seamAllowance: 1.5, hemAllowance: 3, fabricWidth: 140, } const inchDefaults = { seamAllowance: 0.625, hemAllowance: 2, fabricWidth: 54, } function calculatePatternSize(waist, length, seamAllowance, hemAllowance, skirtType) { const waistRadius = waist / (Math.PI * 2); console.log(skirtType); const normalizedWaistRadius = skirtType === "half" ? waistRadius*2 : skirtType === "threeq" ? waistRadius*4/3 : waistRadius; console.log(normalizedWaistRadius); const hemRadius = normalizedWaistRadius + length; const innerRadius = normalizedWaistRadius - seamAllowance; const outerRadius = hemRadius + hemAllowance; return { innerRadius: innerRadius, outerRadius: outerRadius, }; } function calculateYardage(innerRadius, outerRadius, skirtType, fabricWidth) { const variant = _getVariant(outerRadius, skirtType, fabricWidth); if (variant === "error") return errorState; return { hasBiasSeams: variant.hasBiasSeams, imagePath: variant.imagePath, yardage: variant.calculateYardage(innerRadius, outerRadius, fabricWidth) * 1.07, instructions: variant.instructions, }; } function _getVariant(outerRadius, skirtType, fabricWidth) { const fitVariant = _getFitVariant(outerRadius, fabricWidth); if (!(skirtType in finder)) return "error"; if (!(fitVariant in finder[skirtType])) return "error"; return finder[skirtType][fitVariant]; } function _getFitVariant(outerRadius, fabricWidth) { if (outerRadius * 2 < fabricWidth) return "fit"; if (outerRadius < fabricWidth) return "half"; if (outerRadius * (Math.SQRT2/2) < fabricWidth) return "no"; return "doesnotcompute"; }