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 = "C’est plus facile si tu prépares le motif sur une feuille : dessine une ligne droite et une seconde ligne à 45 degrés, de façon à ce que les lignes se croisent proche du coin de la feuille. Le point où les lignes se croisent est le centre des cercles. Mesure le rayon du tour de taille et le rayon total depuis le point où les lignes se croisent. Ajoute une marge pour les coutures sur les côtés du segment, et découpe ensuite. Utilise ce motif pour couper toutes les pièces de tissu comme décrit sur le diagramme." const halfSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius; }, hasBiasSeams: false, imagePath: "assets/half-fit.svg", instructions: "Place la marque du centre du cercle dans le coin du tissu replié, sur le pli mais avec une marge depuis le bord pour les coutures. Marque le rayon du tour de taille et le rayon total avec des quarts de cercle en prenant ce point comme centre.", } const threeqSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius + outerRadius * (Math.SQRT2/2); }, hasBiasSeams: true, imagePath: "assets/threeq-fit.svg", instructions: "Place la marque du centre du cercle sur le pli, à une distance du rayon total du bord. Marque le rayon du tour de taille et le rayon total à partir de ce point. Puis dessine une ligne à 45 degrés depuis la marque pour délimiter les bords de la jupe. Ajouter une marge pour les coutures sur ce bord.", } const fullSkirtFullFit = { calculateYardage: function (innerRadius, outerRadius, fabricWidth) { return outerRadius * 2; }, hasBiasSeams: false, imagePath: "assets/full-fit.svg", instructions: "Plie le tissu deux fois. Marque le centre du cercle dans le coin du tissu replié. Marque le rayon du tour de taille et le rayon total avec des quarts de cercle depuis ce 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 la marque du centre du cercle à la lisière du tissu déplié, avec une marge pour les coutures au bord de la lisière et à une distance du rayon total du bord. Marque le rayon du tour de taille et le rayon total.", } 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 le premier centre du cercle à la lisière du tissu déplié, avec la marge pour les coutures au bord de la lisière, et à une distance du rayon total depuis la lisière. Dessine le rayon du tour de taille et le rayon total. Ensuite, place une second marque pour le centre du cercle, diagonalement opposé, sur la lisière en face. Essaie d’avoir la seconde partie de la jupe aussi proche de la première que possible, pour économiser du tissu. N’oublie pas de garder une marge pour les coutures au bord de la lisière.", } 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 le premier centre du cercle à la lisière du tissu déplié, avec la marge pour les coutures au bord de la lisière, et à une distance du rayon total depuis la lisière. Dessine le rayon du tour de taille et le rayon total. Ensuite, place une second marque pour le centre du cercle, diagonalement opposé, sur la lisière en face. Essaie d’avoir la seconde partie de la jupe aussi proche de la première que possible, pour économiser du tissu. N’oublie pas de garder une marge pour les coutures au bord de la lisière.", } 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: "Ta jupe est trop grande pour qu’on puisse trouver des instructions de découpe adaptées. On ne peut pas trouver la longueur de tissu non plus. Mais tu peux utiliser les rayons de cercle. Bonne chance !", } 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"; }