1
0
Fork 0
freesewing/designs/bibi/src/shared.mjs

485 lines
16 KiB
JavaScript

function createLowerPoints(points, measurements, options, prefix) {
// These lengths are typically not critical, so use a rough estimate if not given
// We don't want the user to need these measurements, as this design can also be used for shorter tops
if (typeof measurements.waistToKnee !== 'undefined') {
points[prefix + 'Knee'] = points[prefix + 'Waist'].translate(0, measurements.waistToKnee)
} else {
points[prefix + 'Knee'] = points[prefix + 'Waist'].translate(
0,
measurements.hpsToWaistBack * 1.5
)
}
if (typeof measurements.waistToFloor !== 'undefined') {
points[prefix + 'Floor'] = points[prefix + 'Waist'].translate(0, measurements.waistToFloor)
} else {
points[prefix + 'Floor'] = points[prefix + 'Waist'].translate(
0,
measurements.hpsToWaistBack * 2.5
)
}
points.sideTarget = points[prefix + 'Knee'].translate(points.seatBase.x * (1 + options.flare), 0)
}
export function constructFrontPoints(points, Point, measurements, options) {
points.cfBust = new Point(0, measurements.hpsToBust)
if (measurements.bustSpan) {
points.bust = new Point(measurements.bustSpan / 2, measurements.hpsToBust)
} else {
// Very rough estimate, but only used for potential dart construction
points.bust = new Point(measurements.chest / 8, measurements.hpsToBust)
}
points.chest = new Point(
(measurements.chest * (1 + options.chestEase)) / 4,
measurements.hpsToBust
)
points.cbWaist = new Point(0, measurements.hpsToWaistBack)
points.cfWaist = new Point(0, Math.max(measurements.hpsToWaistBack, measurements.hpsToWaistFront))
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cfWaist.y)
points.cfArmhole = new Point(
0,
points.cbWaist.y -
measurements.waistToArmpit * (1 - options.armholeDepth - options.bicepsEase / 2)
)
points.armhole = new Point(points.armhole.x, points.cfArmhole.y)
points.armholeCp2 = points.armhole.shift(180, points._tmp1.dx(points.armhole) / 4)
points.cfUnderbust = new Point(
0,
points.cfWaist.y - (measurements.waistToUnderbust ?? measurements.hpsToWaistBack / 6)
)
points.underbust = new Point(
(measurements.chest * (1 + options.chestEase)) / 4,
points.cfUnderbust.y
)
points.cfHips = new Point(0, points.cfWaist.y + measurements.waistToHips)
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cfHips.y)
const seatFront = measurements.seat - measurements.seatBack
const seatExtra = (measurements.seatBack - seatFront) / 4
points.cfSeat = new Point(0, points.cfWaist.y + measurements.waistToSeat)
points.seatBase = new Point((measurements.seat * (1 + options.seatEase)) / 4, points.cfSeat.y)
points.seat = seatAdjustment(points.seatBase, points.hips, -seatExtra)
// points.cfSeat = points.cfSeat.shift(-90, -seatExtra * 2)
createLowerPoints(points, measurements, options, 'cf')
}
export function constructBackPoints(points, Point, measurements, options) {
points.chest = new Point(
(measurements.chest * (1 + options.chestEase)) / 4,
measurements.hpsToBust
)
points.cbWaist = new Point(0, measurements.hpsToWaistBack)
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cbWaist.y)
points.cbUnderbust = new Point(
0,
points.cbWaist.y - (measurements.waistToUnderbust ?? measurements.hpsToWaistBack / 6)
)
points.underbust = new Point(
(measurements.chest * (1 + options.chestEase)) / 4,
points.cbUnderbust.y
)
points.cbHips = new Point(0, points.cbWaist.y + measurements.waistToHips)
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cbHips.y)
points.cbSeat = new Point(0, points.cbWaist.y + measurements.waistToSeat)
const seatFront = measurements.seat - measurements.seatBack
const seatExtra = (measurements.seatBack - seatFront) / 4
points.seatBase = new Point((measurements.seat * (1 + options.seatEase)) / 4, points.cbSeat.y)
points.seat = seatAdjustment(points.seatBase, points.hips, seatExtra)
// points.cbSeat = points.cbSeat.shift(-90, seatExtra * 2)
createLowerPoints(points, measurements, options, 'cb')
}
function seatAdjustment(seatBase, anchor, seatExtra) {
const r = anchor.dist(seatBase)
return seatBase.rotate((seatExtra / r) * 90, anchor)
}
export function calculateFba(anchor, bust, side, dx, Point) {
const r = anchor.dist(bust)
const a0 = Math.asin((bust.x - anchor.x) / r)
let a1 = Math.asin((bust.x - anchor.x + dx) / r)
if (isNaN(a1)) {
a1 = Math.PI / 2
}
const bustOffset = new Point(anchor.x + r * Math.sin(a1), anchor.y + r * Math.cos(a1))
const dy = bustOffset.y - bust.y
const b = a1 - a0
const rotateUpper = (point) => point.rotate((b / Math.PI) * 180, anchor)
const sideOffset0 = rotateUpper(side)
const sideOffset1 = side.translate(dx, dy)
const c = sideOffset1.angle(bust) - sideOffset0.angle(bust)
const rotateLower = (point) => point.translate(dx, dy).rotate(-c, bust)
return {
dx: dx,
dy: dy,
rotateUpper: rotateUpper,
rotateLower: rotateLower,
bustOffset: bustOffset,
sideOffset0: sideOffset0,
sideOffset1: sideOffset1,
}
}
export function correctArmHole(points, paths, Path, options, utils) {
points.armholeCp1 = points.chest
if (!options.sleeves && points.armhole.y > points.chest.y) {
points.armhole = utils.beamIntersectsY(points.chest, points.waist, points.armhole.y)
points.armholeCp2 = points.armhole.shift(180, points._tmp1.dx(points.armhole) / 4)
}
if (points.armhole.y > points.armholeCp1.y * 0.8) {
const frac = Math.min(
1,
(points.armhole.y - points.armholeCp1.y * 0.8) / (0.2 * points.armholeCp1.y)
)
points.armholeCp1 = points.chest.shiftFractionTowards(
points.armholeCp2.rotate(90, points.armhole),
frac
)
}
}
function extendSideLine(points, intersectionY) {
const fraction = (intersectionY - points.seat.y) / points.seat.dy(points.sideTarget)
return points.seat.shiftFractionTowards(points.sideTarget, fraction)
}
export function constructSideSeam(Path, Point, points, height, bottomSmoothness) {
const base = new Path()
.move(points.armhole)
.curve(points.armholeCp1, points.waistCp2, points.waist)
.smurve(points.hipsCp2, points.hips)
.smurve(points.seatCp2, points.seat)
const intersectionY = Math.min(height, points.seat.y) - bottomSmoothness
let bottom = base.intersectsY(height)[0]
if (!bottom) {
// below seat
bottom = extendSideLine(points, height)
}
points.hem = bottom
let intersection = base.intersectsY(intersectionY)[0]
if (!intersection) {
if (intersectionY >= points.seat.y) {
// below seat
intersection = extendSideLine(points, intersectionY)
} else {
//above armhole
intersection = points.armhole
}
}
bottom.x = (bottom.x + intersection.x) / 2 // creates a smoother bottom as the bottom is vertical
points.intersection = intersection
const angle = base.angleAt(intersection)
if (!angle) {
return base
}
const intersectionCp1 = intersection.shift(angle, bottomSmoothness * 0.3)
const intersectionCp2 = new Point(bottom.x, bottom.y - bottomSmoothness * 0.3)
points.intersectionCp1 = intersectionCp1
points.intersectionCp2 = intersectionCp2
let result = base.split(intersection)[0]
if (!result.curve) {
result = new Path().move(points.armhole)
}
return result.curve(intersectionCp1, intersectionCp2, bottom).reverse()
}
export function adjustSidePoints(points, options) {
// Remove waist fitting if option is disabled
if (!options.fitWaist || points.waist.x > points.armhole.x) {
if (points.waist.x < points.armhole.x) {
points.waist.x = points.armhole.x
}
points.waistCp2 = points.waist.shiftFractionTowards(points.armhole, 0.2)
if (points.hips.x < points.waist.x) {
points.hips.x = points.waist.x
}
}
// prevent barrel shape
if (points.hips.x < points.waist.x) {
points.hips.x = points.waist.x
}
// prevent excessive hips narrowing
if (points.hips.x < (points.waist.x + points.seat.x) / 2) {
points.hips.x = (points.waist.x + points.seat.x) / 2
}
// prevent smaller seat than hips
if (points.seat.x < points.hips.x) {
points.seat.x = points.hips.x
}
// prevent excessive waist narrowing
if (points.waist.x < 2 * points.hips.x - points.seat.x) {
points.waist.x = 2 * points.hips.x - points.seat.x
}
// curve points
points.waistCp2 = points.waist.shift(90, points.armhole.dy(points.waist) * 0.2)
points.seatCp2 = points.seat.shift(90, points.hips.dy(points.seat) * 0.3)
points.hipsCp2 = points.waist.shiftFractionTowards(points.hips, 0.6)
}
function getBottomSmoothness(bottom, points) {
return (Math.min(bottom, points.seat.y) - points.armhole.y) * 0.3
}
export function constructBackHem(points, measurements, options, Point, paths, Path) {
let centerPoint
// Extra length for butt
let extraBackLength = 0
let bonusLengthMeasurement = measurements.hpsToWaistBack
switch (options.length) {
case 'underbust':
centerPoint = points.cbUnderbust
bonusLengthMeasurement = measurements.waistToUnderbust
break
case 'waist':
centerPoint = points.cbWaist
break
case 'hips':
centerPoint = points.cbHips
break
case 'seat':
centerPoint = points.cbSeat
extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2
bonusLengthMeasurement *= 2
break
case 'knee':
centerPoint = points.cbKnee
extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2
bonusLengthMeasurement *= 3
break
case 'floor':
centerPoint = points.cbFloor
extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2
bonusLengthMeasurement *= 3
}
if (!centerPoint) {
centerPoint = points.cbSeat
}
const hemBottom = centerPoint.y + bonusLengthMeasurement * options.lengthBonus
points.cbHem = new Point(
0,
centerPoint.y + bonusLengthMeasurement * options.lengthBonus + extraBackLength
)
points.midHem = new Point(points.hem.x * 0.66, points.cbHem.y)
paths.sideSeam = constructSideSeam(
Path,
Point,
points,
hemBottom,
getBottomSmoothness(hemBottom, points)
).addClass('fabric')
paths.hem = new Path()
.move(points.cbHem)
.curve(points.midHem, points.midHem, points.hem)
.addClass('fabric')
}
export function constructFrontHem(points, measurements, options, Point, paths, Path) {
let centerPoint
let bonusLengthMeasurement = measurements.hpsToWaistBack
switch (options.length) {
case 'underbust':
centerPoint = points.cfUnderbust
bonusLengthMeasurement = measurements.waistToUnderbust
break
case 'waist':
centerPoint = points.cfWaist
break
case 'hips':
centerPoint = points.cfHips
break
case 'seat':
centerPoint = points.cfSeat
bonusLengthMeasurement *= 2
break
case 'knee':
centerPoint = points.cfKnee
bonusLengthMeasurement *= 3
break
case 'floor':
centerPoint = points.cfFloor
bonusLengthMeasurement *= 3
}
if (!centerPoint) {
centerPoint = points.cfSeat
}
const hemBottom = centerPoint.y + bonusLengthMeasurement * options.lengthBonus
points.cfHem = new Point(0, centerPoint.y + bonusLengthMeasurement * options.lengthBonus)
points.midHem = new Point(points.hem.x * 0.66, points.cfHem.y)
paths.sideSeam = constructSideSeam(
Path,
Point,
points,
hemBottom,
getBottomSmoothness(hemBottom, points)
).addClass('fabric')
paths.hem = new Path()
.move(points.cfHem)
.curve(points.midHem, points.midHem, points.hem)
.addClass('fabric')
}
export function createArmHoles(
options,
store,
points,
paths,
Path,
snippets,
Snippet,
strapWidth,
armholeCurve,
armholeDrop,
utils,
notchType = 'notch'
) {
if (options.sleeves) {
if (store.get('capSleeves')) {
const sleeveCapFactor = (options.sleeveLength + 0.2) * 4
const capLength = sleeveCapFactor * store.get('sleeveCapHeight')
points.sleeveCap = points.shoulder.shift(
points.neck.angle(points.shoulder) - 15 + options.cuffEase * 15,
capLength
)
points.sleeveCapStart = points.shoulder.shift(
points.neck.angle(points.shoulder),
capLength * -0.2
)
points.sleeveCapCp = points.sleeveCap
.shiftTowards(points.armholePitchCp1, capLength * 0.2)
.rotate(-90, points.sleeveCap)
paths.shoulder = new Path()
.move(points.sleeveCap)
.curve(points.sleeveCapCp, points.shoulder, points.sleeveCapStart)
.line(points.neck)
.addClass('fabric')
paths.armhole = new Path()
.move(points.armhole)
.curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow)
.curve(points.armholeHollowCp2, points.armholePitchCp1, points.sleeveCap)
.addClass('fabric')
} else {
paths.shoulder = new Path().move(points.shoulder).line(points.neck).addClass('fabric')
paths.armhole = new Path()
.move(points.armhole)
.curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow)
.curve(points.armholeHollowCp2, points.armholePitchCp1, points.armholePitch)
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
.addClass('fabric')
snippets.armholePitchNotch = new Snippet(notchType, points.armholePitch)
}
} else {
points.strapTop = points.neck.shift(
points.shoulder.angle(points.hps),
-strapWidth * points.shoulder.dist(points.hps)
)
points.strapTopCp1 = points.strapTop
.shiftTowards(points.hps, 0.2 * points.strapTop.dy(points.armhole))
.rotate(90, points.strapTop)
// Increase weight of armhole control points because we don't use armholeHollow here anymore
points.armholeCp2 = points.armhole.shiftFractionTowards(points.armholeCp2, 3)
points.armholeIntersection = utils.beamsIntersect(
points.strapTop,
points.strapTopCp1,
points.armhole,
points.armholeCp2
)
points.armholeIntersectionDrop = points.armholeIntersection.shiftFractionTowards(
points.strapTop,
-armholeDrop
)
points.armholeCp2 = points.armholeCp2.shiftFractionTowards(
points.armholeIntersection,
armholeCurve
)
points.strapTopCp1 = points.strapTopCp1.shiftFractionTowards(
points.armholeIntersectionDrop,
armholeCurve
)
paths.armhole = new Path()
.move(points.armhole)
.curve(points.armholeCp2, points.strapTopCp1, points.strapTop)
.addClass('fabric')
paths.shoulder = new Path().move(points.strapTop).line(points.neck).addClass('fabric')
}
}
export function plotSideLineMeasurements(points, sideSeam, utils, macro) {
const offsets = {
seat: points.seat.y,
hips: points.hips.y,
waist: points.waist.y,
underbust: points.underbust.y,
dart: points.dartTip?.y,
armhole: points.armhole.y + 0.01,
}
let prevY = (points.cfHem ?? points.cbHem).y
const strings = Object.keys(offsets)
for (let i = 0; i < strings.length; i++) {
const key = strings[i]
let y = offsets[key]
if (!y || y > points.hem.y) {
continue
}
let intersects = sideSeam.intersectsY(y)
if (intersects.length === 0) {
// Intersecting the path exactly on the corner points sometimes doesn't work
// See issue #3367
y += 0.001
intersects = sideSeam.intersectsY(y)
}
if (intersects.length > 0) {
const sidePoint = intersects[0]
const centerPoint = sidePoint.clone()
centerPoint.x = 0
const prevPoint = centerPoint.clone()
prevPoint.y = prevY
prevY = y
macro('hd', {
id: 'wAt' + utils.capitalize(key),
from: centerPoint,
to: sidePoint,
y: y,
})
macro('vd', {
id: 'hBelow' + utils.capitalize(key),
from: centerPoint,
to: prevPoint,
x: 30,
})
}
}
}