feat(ursula): Initial release of Ursula
Ursula is a basic, highly-customizable underwear pattern
This commit is contained in:
parent
a3b37b060b
commit
cc00ec65ff
7 changed files with 727 additions and 0 deletions
51
packages/ursula/config/index.js
Normal file
51
packages/ursula/config/index.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { version } from '../package.json'
|
||||||
|
|
||||||
|
// ?? 🤔 ?? --> https://en.freesewing.dev/packages/core/config
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ursula',
|
||||||
|
version,
|
||||||
|
design: 'natalia',
|
||||||
|
code: 'natalia',
|
||||||
|
department: 'womenswear',
|
||||||
|
type: 'pattern',
|
||||||
|
difficulty: 1,
|
||||||
|
tags: [
|
||||||
|
'freesewing',
|
||||||
|
'design',
|
||||||
|
'diy',
|
||||||
|
'fashion',
|
||||||
|
'made to measure',
|
||||||
|
'parametric design',
|
||||||
|
'pattern',
|
||||||
|
'sewing',
|
||||||
|
'sewing pattern',
|
||||||
|
],
|
||||||
|
optionGroups: {
|
||||||
|
fit: ['fabricStretch','gussetWidth','gussetLength','elasticStretch'],
|
||||||
|
style: ['rise','legOpening','frontDip','backDip','taperToGusset','backExposure'],
|
||||||
|
},
|
||||||
|
measurements: ['waist','seat','waistToSeat','waistToUpperLeg'], // Potentially useful: 'hips', 'waistToHips'
|
||||||
|
dependencies: {},
|
||||||
|
inject: {},
|
||||||
|
hide: [],
|
||||||
|
parts: ['front','back','gusset','elastic'],
|
||||||
|
//Constants
|
||||||
|
options: {
|
||||||
|
backToFrontLength: 1.15, // Maybe include this in advanced options?
|
||||||
|
backToFrontWidth: 1.1, // Maybe include this in advanced options?
|
||||||
|
gussetRatio: 0.7, // Relationship between front and back gusset widths
|
||||||
|
|
||||||
|
// Percentages
|
||||||
|
gussetWidth: { pct : 7.7, min: 4, max: 12 }, // Gusset width in relation to seat
|
||||||
|
gussetLength: { pct: 12.7, min: 10, max: 16 }, // Gusset length in relation to seat
|
||||||
|
fabricStretch: { pct: 15, min: 5, max: 25 },
|
||||||
|
rise: { pct: 60, min: 30, max: 100 },
|
||||||
|
legOpening: { pct: 58, min: 5, max: 85 },
|
||||||
|
frontDip: { pct: 5.0, min: -5, max: 15 },
|
||||||
|
backDip: { pct: 2.5, min: -5, max: 15 },
|
||||||
|
taperToGusset: { pct: 70, min: 5, max: 100},
|
||||||
|
backExposure: { pct: 20, min: -30, max: 90},
|
||||||
|
elasticStretch: { pct: 8, min: 5, max: 15 }
|
||||||
|
},
|
||||||
|
}
|
93
packages/ursula/package.json
Normal file
93
packages/ursula/package.json
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"name": "@freesewing/ursula",
|
||||||
|
"version": "2.16.2",
|
||||||
|
"description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
|
||||||
|
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
||||||
|
"homepage": "https://freesewing.org/",
|
||||||
|
"repository": "github:freesewing/freesewing",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/freesewing/freesewing/issues"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"freesewing",
|
||||||
|
"design",
|
||||||
|
"diy",
|
||||||
|
"fashion",
|
||||||
|
"made to measure",
|
||||||
|
"parametric design",
|
||||||
|
"pattern",
|
||||||
|
"sewing",
|
||||||
|
"sewing pattern"
|
||||||
|
],
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"build": "rollup -c",
|
||||||
|
"test": "BABEL_ENV=production ../../node_modules/.bin/_mocha tests/*.test.js --require @babel/register",
|
||||||
|
"pubtest": "npm publish --registry http://localhost:6662",
|
||||||
|
"pubforce": "npm publish",
|
||||||
|
"symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
|
||||||
|
"start": "rollup -c -w",
|
||||||
|
"netlify": "echo \"Not configured yet\"",
|
||||||
|
"testci": "BABEL_ENV=production ./node_modules/.bin/_mocha tests/*.test.js --require @babel/register"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@freesewing/core": "^2.16.2",
|
||||||
|
"@freesewing/plugin-bundle": "^2.16.2"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"eslint": "^7.27.0",
|
||||||
|
"eslint-config-standard": "^16.0.3",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^1.1.0",
|
||||||
|
"@freesewing/components": "^2.16.2",
|
||||||
|
"@freesewing/css-theme": "^2.16.2",
|
||||||
|
"@freesewing/i18n": "^2.16.2",
|
||||||
|
"@freesewing/mui-theme": "^2.16.2",
|
||||||
|
"@freesewing/plugin-bust": "^2.16.2",
|
||||||
|
"@freesewing/plugin-buttons": "^2.16.2",
|
||||||
|
"@freesewing/plugin-flip": "^2.16.2",
|
||||||
|
"@freesewing/utils": "^2.16.2",
|
||||||
|
"react-scripts": "^4.0.3",
|
||||||
|
"webpack": "^5.37.0",
|
||||||
|
"rollup": "^2.50.6",
|
||||||
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
|
"@rollup/plugin-commonjs": "^19.0.0",
|
||||||
|
"@rollup/plugin-json": "^4.1.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||||
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||||
|
"@material-ui/core": "^4.11.4",
|
||||||
|
"@material-ui/icons": "^4.11.2",
|
||||||
|
"@material-ui/lab": "^v4.0.0-alpha.57",
|
||||||
|
"axios": "0.21.1",
|
||||||
|
"react-intl": "^5.17.6",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"mocha": "^8.1.0",
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"chai-string": "^1.5.0",
|
||||||
|
"@babel/register": "^7.10.5"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/*",
|
||||||
|
"README.md",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"tag": "latest"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0",
|
||||||
|
"npm": ">=6"
|
||||||
|
},
|
||||||
|
"rollup": {
|
||||||
|
"exports": "default"
|
||||||
|
}
|
||||||
|
}
|
240
packages/ursula/src/back.js
Normal file
240
packages/ursula/src/back.js
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
export default function (part) {
|
||||||
|
let {
|
||||||
|
options,
|
||||||
|
Point,
|
||||||
|
Path,
|
||||||
|
points,
|
||||||
|
paths,
|
||||||
|
measurements,
|
||||||
|
// Snippet,
|
||||||
|
// snippets,
|
||||||
|
store,
|
||||||
|
utils,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
paperless,
|
||||||
|
macro,
|
||||||
|
} = part.shorthand()
|
||||||
|
|
||||||
|
// Design pattern here
|
||||||
|
|
||||||
|
// Create points
|
||||||
|
|
||||||
|
points.backWaistMid = new Point(measurements.seat / 4, 0)
|
||||||
|
points.backWaistBandLeft = new Point(store.get('sideSeamWaist').x / options.backToFrontWidth, store.get('sideSeamWaist').y)
|
||||||
|
points.backLegOpeningLeft = new Point(store.get('sideSeamHip').x / options.backToFrontWidth, store.get('sideSeamHip').y)
|
||||||
|
points.backGussetLeft = new Point(
|
||||||
|
(measurements.seat / 4) - (measurements.waist * options.gussetWidth) * store.get('xScale') / options.gussetRatio * options.backToFrontWidth,
|
||||||
|
measurements.waistToUpperLeg * options.backToFrontLength
|
||||||
|
)
|
||||||
|
points.backGussetMid = new Point(measurements.seat / 4, measurements.waistToUpperLeg * options.backToFrontLength)
|
||||||
|
|
||||||
|
points.backGussetRight = points.backGussetLeft.flipX(points.backWaistMid)
|
||||||
|
points.backLegOpeningRight = points.backLegOpeningLeft.flipX(points.backWaistMid)
|
||||||
|
points.backWaistBandRight = points.backWaistBandLeft.flipX(points.backWaistMid)
|
||||||
|
|
||||||
|
points.backWaistBandMid = points.backWaistBandLeft.shiftFractionTowards(points.backWaistBandRight, 0.5)
|
||||||
|
.shift(270,measurements.waistToUpperLeg * options.backDip)
|
||||||
|
|
||||||
|
/* Middle point for label */
|
||||||
|
points.backMidMid = points.backLegOpeningLeft.shiftFractionTowards(points.backLegOpeningRight, 0.5)
|
||||||
|
|
||||||
|
|
||||||
|
// Create control points
|
||||||
|
|
||||||
|
/* Control point for waistband dip */
|
||||||
|
points.backWaistBandLeftCp1 = new Point(points.backWaistBandRight.x / 3, points.backWaistBandMid.y)
|
||||||
|
|
||||||
|
/* Flip points to right side */
|
||||||
|
points.backWaistBandRightCp1 = points.backWaistBandLeftCp1.flipX(points.backWaistMid)
|
||||||
|
|
||||||
|
// Shape back coverage
|
||||||
|
|
||||||
|
/* Only have to do this on one side */
|
||||||
|
points.backLegOpeningCorner = utils.beamsIntersect(
|
||||||
|
points.backLegOpeningLeft,
|
||||||
|
points.backLegOpeningLeft.shift(180, points.backGussetLeft.dy(points.backLegOpeningLeft)),
|
||||||
|
points.backGussetLeft,
|
||||||
|
points.backGussetLeft.shift(270, points.backGussetLeft.dy(points.backLegOpeningLeft))
|
||||||
|
)
|
||||||
|
|
||||||
|
if (options.backExposure >= 0) {
|
||||||
|
/* If back exposure is high, like a thong style */
|
||||||
|
/* This controls the hip bit */
|
||||||
|
points.backLegOpeningLeftCp1 = points.backLegOpeningLeft.shiftFractionTowards(
|
||||||
|
points.backLegOpeningCorner,
|
||||||
|
options.backExposure
|
||||||
|
)
|
||||||
|
/* This controls the center bit */
|
||||||
|
points.backGussetLeftCp1 = points.backGussetLeft.shiftFractionTowards(
|
||||||
|
points.backWaistBandMid,
|
||||||
|
options.backExposure
|
||||||
|
)
|
||||||
|
points.backGussetLeft = points.backGussetLeft.shiftFractionTowards(points.backGussetMid, options.backExposure) // This narrows the back of the gusset
|
||||||
|
points.backGussetRight = points.backGussetLeft.flipX(points.backWaistMid)
|
||||||
|
} else {
|
||||||
|
/* If back exposure is low and flares out to cover more */
|
||||||
|
/* This controls the hip bit */
|
||||||
|
points.backLegOpeningLeftCp1 = points.backLegOpeningLeft.shift(
|
||||||
|
-45,
|
||||||
|
points.backWaistBandMid.x / 8
|
||||||
|
)
|
||||||
|
/* This controls the taper to gusset */
|
||||||
|
points.backGussetLeftCp1 = points.backGussetLeft.shift(
|
||||||
|
115,
|
||||||
|
points.backWaistBandMid.x / 8
|
||||||
|
)
|
||||||
|
/* This adds a new point in the middle of the back coverage */
|
||||||
|
points.backFlare = points.backGussetLeft.shiftFractionTowards(
|
||||||
|
points.backLegOpeningLeft,
|
||||||
|
0.5
|
||||||
|
)
|
||||||
|
points.backFlareLeft = points.backFlare.shift(
|
||||||
|
215,
|
||||||
|
-points.backWaistBandMid.x / 2 * options.backExposure
|
||||||
|
)
|
||||||
|
points.backFlareRight = points.backFlareLeft.flipX(points.backWaistBandMid)
|
||||||
|
/* This controls the flare */
|
||||||
|
points.backFlareLeftCp1 = points.backFlareLeft.shift(
|
||||||
|
115,
|
||||||
|
points.backWaistBandMid.x / 5//-150*options.backExposure
|
||||||
|
)
|
||||||
|
points.backFlareLeftCp2 = points.backFlareLeft.shift(
|
||||||
|
295,
|
||||||
|
points.backWaistBandMid.x / 5//-150*options.backExposure
|
||||||
|
)
|
||||||
|
points.backFlareRightCp1 = points.backFlareLeftCp1.flipX(points.backWaistMid)
|
||||||
|
points.backFlareRightCp2 = points.backFlareLeftCp2.flipX(points.backWaistMid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flip points to the right */
|
||||||
|
|
||||||
|
points.backLegOpeningRightCp1 = points.backLegOpeningLeftCp1.flipX(points.backWaistMid)
|
||||||
|
points.backGussetRightCp1 = points.backGussetLeftCp1.flipX(points.backWaistMid)
|
||||||
|
|
||||||
|
// Draw paths
|
||||||
|
|
||||||
|
if (options.backExposure >= 0) {
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.backWaistBandMid)
|
||||||
|
.curve(points.backWaistBandLeftCp1, points.backWaistBandLeft, points.backWaistBandLeft) // Waist band dip
|
||||||
|
.line(points.backLegOpeningLeft)
|
||||||
|
.curve(points.backLegOpeningLeftCp1, points.backGussetLeftCp1, points.backGussetLeft)
|
||||||
|
.line(points.backGussetMid)
|
||||||
|
.line(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight)
|
||||||
|
.line(points.backWaistBandRight)
|
||||||
|
.curve(points.backWaistBandRight, points.backWaistBandRightCp1, points.backWaistBandMid) // Waist band dip
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric')
|
||||||
|
} else {
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.backWaistBandMid)
|
||||||
|
.curve(points.backWaistBandLeftCp1, points.backWaistBandLeft, points.backWaistBandLeft) // Waist band dip
|
||||||
|
.line(points.backLegOpeningLeft)
|
||||||
|
.curve(points.backLegOpeningLeftCp1, points.backFlareLeftCp1, points.backFlareLeft)
|
||||||
|
.curve(points.backFlareLeftCp2, points.backGussetLeftCp1, points.backGussetLeft)
|
||||||
|
.line(points.backGussetMid)
|
||||||
|
.line(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backFlareRightCp2, points.backFlareRight)
|
||||||
|
.curve(points.backFlareRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight)
|
||||||
|
.line(points.backWaistBandRight)
|
||||||
|
.curve(points.backWaistBandRight, points.backWaistBandRightCp1, points.backWaistBandMid) // Waist band dip
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store points for use in other parts
|
||||||
|
|
||||||
|
/* Store gusset points for use in gusset */
|
||||||
|
|
||||||
|
store.set('backGussetLeft', points.backGussetLeft)
|
||||||
|
store.set('backGussetRight', points.backGussetRight)
|
||||||
|
|
||||||
|
/* Store lengths for use in elastic */
|
||||||
|
|
||||||
|
if (options.backExposure >= 0 ) {
|
||||||
|
store.set(
|
||||||
|
'backLegOpeningLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight)
|
||||||
|
.length()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
store.set(
|
||||||
|
'backLegOpeningLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backFlareRightCp2, points.backFlareRight)
|
||||||
|
.curve(points.backFlareRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set(
|
||||||
|
'backWaistBandLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.backWaistBandRight)
|
||||||
|
.curve(points.backWaistBandRightCp1, points.backWaistBandLeftCp1, points.backWaistBandLeft)
|
||||||
|
.length()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Complete?
|
||||||
|
if (complete) {
|
||||||
|
|
||||||
|
if (sa) {
|
||||||
|
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro('title', {
|
||||||
|
at: points.backMidMid,
|
||||||
|
nr: 2,
|
||||||
|
title: 'back',
|
||||||
|
})
|
||||||
|
|
||||||
|
points.scaleboxAnchor = points.scalebox = points.backMidMid.shift(90, -50)
|
||||||
|
macro('miniscale', { at: points.scalebox })
|
||||||
|
|
||||||
|
// Paperless?
|
||||||
|
if (paperless) {
|
||||||
|
macro('hd', {
|
||||||
|
from: points.backWaistBandRight,
|
||||||
|
to: points.backWaistBandLeft,
|
||||||
|
y: points.backWaistBandRight.y + sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
from: points.backLegOpeningRight,
|
||||||
|
to: points.backLegOpeningLeft,
|
||||||
|
y: points.backLegOpeningRight.y + sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
from: points.backGussetLeft,
|
||||||
|
to: points.backGussetRight,
|
||||||
|
y: points.backGussetLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
from: points.backWaistBandMid,
|
||||||
|
to: points.backGussetMid,
|
||||||
|
x: points.backWaistBandMid.x + sa + 15,
|
||||||
|
})
|
||||||
|
if (options.backExposure >= 0 ) {
|
||||||
|
macro('pd', {
|
||||||
|
path: new Path()
|
||||||
|
.move(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight),
|
||||||
|
d: 15
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
macro('pd', {
|
||||||
|
path: new Path()
|
||||||
|
.move(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRightCp1, points.backFlareRightCp2, points.backFlareRight)
|
||||||
|
.curve(points.backFlareRightCp1, points.backLegOpeningRightCp1, points.backLegOpeningRight),
|
||||||
|
d: 15
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
56
packages/ursula/src/elastic.js
Normal file
56
packages/ursula/src/elastic.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
export default function (part) {
|
||||||
|
let {
|
||||||
|
options,
|
||||||
|
Point,
|
||||||
|
Path,
|
||||||
|
points,
|
||||||
|
paths,
|
||||||
|
measurements,
|
||||||
|
// Snippet,
|
||||||
|
// snippets,
|
||||||
|
store,
|
||||||
|
utils,
|
||||||
|
units,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
paperless,
|
||||||
|
macro,
|
||||||
|
} = part.shorthand()
|
||||||
|
|
||||||
|
// Stretch utility method
|
||||||
|
|
||||||
|
store.set('elasticScale', utils.stretchToScale(options.elasticStretch))
|
||||||
|
|
||||||
|
// Design pattern here
|
||||||
|
|
||||||
|
let legOpeningLength = store.get('frontLegOpeningLength') + store.get('backLegOpeningLength') + store.get('gussetSideLength')
|
||||||
|
let waistBandLength = store.get('frontWaistBandLength') + store.get('backWaistBandLength')
|
||||||
|
|
||||||
|
points.elasticInfo = new Point(0,0)
|
||||||
|
.attr('data-text', 'cutTwoPiecesOfElasticToFinishTheLegOpenings')
|
||||||
|
.attr('data-text', ':')
|
||||||
|
.attr('data-text', units(legOpeningLength * store.get('elasticScale') + 2 * sa))
|
||||||
|
.attr('data-text', '\n')
|
||||||
|
.attr('data-text', 'cutOnePieceOfElasticToFinishTheWaistBand')
|
||||||
|
.attr('data-text', ':')
|
||||||
|
.attr('data-text', units(waistBandLength * store.get('elasticScale') + 2 * sa))
|
||||||
|
|
||||||
|
// Complete?
|
||||||
|
if (complete) {
|
||||||
|
|
||||||
|
// if (sa) {
|
||||||
|
// paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paperless?
|
||||||
|
if (paperless) {
|
||||||
|
macro('hd', {
|
||||||
|
from: points.elasticInfo,
|
||||||
|
to: points.elasticInfo,
|
||||||
|
y: points.elasticInfo.y + sa + 15,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
174
packages/ursula/src/front.js
Normal file
174
packages/ursula/src/front.js
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
export default function (part) {
|
||||||
|
let {
|
||||||
|
options,
|
||||||
|
Point,
|
||||||
|
Path,
|
||||||
|
points,
|
||||||
|
paths,
|
||||||
|
measurements,
|
||||||
|
// Snippet,
|
||||||
|
// snippets,
|
||||||
|
store,
|
||||||
|
utils,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
paperless,
|
||||||
|
macro,
|
||||||
|
} = part.shorthand()
|
||||||
|
|
||||||
|
// Stretch utility method
|
||||||
|
|
||||||
|
store.set('xScale', utils.stretchToScale(options.fabricStretch))
|
||||||
|
|
||||||
|
// Design pattern here
|
||||||
|
|
||||||
|
// Create points
|
||||||
|
|
||||||
|
points.frontWaistMid = new Point(measurements.seat / 4, 0)
|
||||||
|
points.frontWaistLeft = new Point(measurements.seat / 4 - measurements.waist / 4 * store.get('xScale'), 0)
|
||||||
|
points.frontHipLeft = new Point(measurements.seat / 4 - measurements.seat / 4 * store.get('xScale'), measurements.waistToSeat) // Consider renaming from "hip" to "seat"
|
||||||
|
points.frontGussetLeft = new Point((measurements.seat / 4) - (measurements.waist * options.gussetWidth) * store.get('xScale') / 1.2, measurements.waistToUpperLeg)
|
||||||
|
points.frontGussetMid = new Point(measurements.seat / 4, measurements.waistToUpperLeg)
|
||||||
|
|
||||||
|
/* Flip points to right side */
|
||||||
|
points.frontGussetRight = points.frontGussetLeft.flipX(points.frontWaistMid)
|
||||||
|
points.frontHipRight = points.frontHipLeft.flipX(points.frontWaistMid)
|
||||||
|
points.frontWaistRight = points.frontWaistLeft.flipX(points.frontWaistMid)
|
||||||
|
|
||||||
|
/* Waist band is based on waist at top, hip at bottom */
|
||||||
|
points.frontWaistBandLeft = points.frontHipLeft.shiftFractionTowards(points.frontWaistLeft, options.rise)
|
||||||
|
points.frontWaistBandRight = points.frontWaistBandLeft.flipX(points.frontWaistMid)
|
||||||
|
points.frontWaistBandMid = points.frontWaistBandLeft.shiftFractionTowards(points.frontWaistBandRight, 0.5)
|
||||||
|
.shift(270,measurements.waistToUpperLeg * options.frontDip) /* Waist band dip */
|
||||||
|
|
||||||
|
/* Leg opening is based on waist band and hip */
|
||||||
|
// points.frontLegOpeningLeft = points.frontHipLeft.shiftFractionTowards(points.frontWaistBandLeft, options.legOpening) // Waist band side point
|
||||||
|
// points.frontLegOpeningRight = points.frontLegOpeningLeft.flipX(points.frontWaistMid) // Waist band side point
|
||||||
|
|
||||||
|
///////////// Replace the point it's shifting towards with a beamsIntersect() of the
|
||||||
|
///////////// side (frontWaistLeft and frontHipLeft) and the lowest point of the waistband (backWaistBandMid
|
||||||
|
///////////// and backWaistBandLeftCp1 should work)
|
||||||
|
///////////// or maybe beamIntersectsY() of backWaistBandMid.y ??
|
||||||
|
|
||||||
|
points.frontLegOpeningLeft = points.frontHipLeft.shiftFractionTowards(points.frontWaistBandLeft, options.legOpening) // Waist band low point
|
||||||
|
points.frontLegOpeningRight = points.frontLegOpeningLeft.flipX(points.frontWaistMid) // Waist band low point
|
||||||
|
|
||||||
|
/* Middle point for label */
|
||||||
|
points.frontMidMid = points.frontLegOpeningLeft.shiftFractionTowards(points.frontLegOpeningRight, 0.5)
|
||||||
|
|
||||||
|
// Create control points
|
||||||
|
|
||||||
|
/* Control points for leg opening curves */
|
||||||
|
points.frontLegOpeningLeftCp1 = points.frontLegOpeningLeft
|
||||||
|
.shift(180, points.frontGussetLeft.dy(points.frontLegOpeningLeft)/3);
|
||||||
|
points.frontGussetLeftCp1 = points.frontGussetLeft
|
||||||
|
// .shift(270, points.frontGussetLeft.dy(points.frontHipLeft) * 4 * options.taperToGusset); // Consider changing this so it's relative
|
||||||
|
.shift(270, points.frontGussetLeft.dy(points.frontWaistBandMid) * options.taperToGusset);
|
||||||
|
|
||||||
|
/* Control point for waistband dip */
|
||||||
|
points.frontWaistBandLeftCp1 = new Point(points.frontWaistBandRight.x / 3, points.frontWaistBandMid.y)
|
||||||
|
|
||||||
|
/* Flip control points to right side */
|
||||||
|
points.frontGussetRightCp1 = points.frontGussetLeftCp1.flipX(points.frontWaistMid)
|
||||||
|
points.frontLegOpeningRightCp1 = points.frontLegOpeningLeftCp1.flipX(points.frontWaistMid)
|
||||||
|
points.frontWaistBandRightCp1 = points.frontWaistBandLeftCp1.flipX(points.frontWaistMid)
|
||||||
|
|
||||||
|
// Draw paths
|
||||||
|
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.frontWaistBandMid)
|
||||||
|
.curve(points.frontWaistBandLeftCp1, points.frontWaistBandLeft, points.frontWaistBandLeft) // Waist band dip
|
||||||
|
.line(points.frontLegOpeningLeft)
|
||||||
|
.curve(points.frontLegOpeningLeftCp1, points.frontGussetLeftCp1, points.frontGussetLeft)
|
||||||
|
.line(points.frontGussetMid)
|
||||||
|
.line(points.frontGussetRight)
|
||||||
|
.curve(points.frontGussetRightCp1, points.frontLegOpeningRightCp1, points.frontLegOpeningRight)
|
||||||
|
.line(points.frontWaistBandRight)
|
||||||
|
.curve(points.frontWaistBandRight, points.frontWaistBandRightCp1, points.frontWaistBandMid) // Waist band dip
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric')
|
||||||
|
|
||||||
|
// Store points for use in other parts
|
||||||
|
|
||||||
|
/* Store side seam points for use in back */
|
||||||
|
|
||||||
|
store.set('sideSeamWaist', points.frontWaistBandLeft)
|
||||||
|
store.set('sideSeamHip', points.frontLegOpeningLeft)
|
||||||
|
|
||||||
|
/* Store gusset points for use in gusset */
|
||||||
|
|
||||||
|
store.set('frontGussetLeft', points.frontGussetLeft)
|
||||||
|
store.set('frontGussetRight', points.frontGussetRight)
|
||||||
|
store.set('frontGussetMid', points.frontGussetMid)
|
||||||
|
|
||||||
|
/* Store lengths for use in elastic */
|
||||||
|
|
||||||
|
store.set(
|
||||||
|
'frontLegOpeningLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.frontGussetRight)
|
||||||
|
.curve(points.frontGussetRightCp1, points.frontLegOpeningRightCp1, points.frontLegOpeningRight)
|
||||||
|
.length()
|
||||||
|
)
|
||||||
|
store.set(
|
||||||
|
'frontWaistBandLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.frontWaistBandRight)
|
||||||
|
.curve(points.frontWaistBandRightCp1, points.frontWaistBandLeftCp1, points.frontWaistBandLeft)
|
||||||
|
.length()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Complete?
|
||||||
|
if (complete) {
|
||||||
|
|
||||||
|
if (sa) {
|
||||||
|
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro('title', {
|
||||||
|
at: points.frontMidMid,
|
||||||
|
nr: 1,
|
||||||
|
title: 'front',
|
||||||
|
})
|
||||||
|
// Paperless?
|
||||||
|
if (paperless) {
|
||||||
|
macro('hd', {
|
||||||
|
from: points.frontWaistBandRight,
|
||||||
|
to: points.frontWaistBandLeft,
|
||||||
|
y: points.frontWaistBandRight.y + sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
from: points.frontLegOpeningRight,
|
||||||
|
to: points.frontLegOpeningLeft,
|
||||||
|
y: points.frontLegOpeningRight.y + sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
from: points.frontGussetLeft,
|
||||||
|
to: points.frontGussetRight,
|
||||||
|
y: points.frontGussetLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
from: points.frontWaistBandMid,
|
||||||
|
to: points.frontGussetMid,
|
||||||
|
x: points.frontWaistBandMid.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('ld', {
|
||||||
|
from: points.frontWaistBandLeft,
|
||||||
|
to: points.frontLegOpeningLeft,
|
||||||
|
d: points.frontWaistBandLeft.y + sa - 15
|
||||||
|
})
|
||||||
|
macro('pd', {
|
||||||
|
path: new Path()
|
||||||
|
.move(points.frontGussetRight)
|
||||||
|
.curve(points.frontGussetRightCp1, points.frontLegOpeningRightCp1, points.frontLegOpeningRight),
|
||||||
|
d: 15
|
||||||
|
})
|
||||||
|
/* macro('vd', {
|
||||||
|
from: points.frontWaistBandLeft,
|
||||||
|
to: points.frontWaistBandMid,
|
||||||
|
x: points.frontWaistBandMid.x + sa + 15,
|
||||||
|
}) */
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
95
packages/ursula/src/gusset.js
Normal file
95
packages/ursula/src/gusset.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
export default function (part) {
|
||||||
|
let {
|
||||||
|
options,
|
||||||
|
Point,
|
||||||
|
Path,
|
||||||
|
points,
|
||||||
|
paths,
|
||||||
|
measurements,
|
||||||
|
// Snippet,
|
||||||
|
// snippets,
|
||||||
|
store,
|
||||||
|
utils,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
paperless,
|
||||||
|
macro,
|
||||||
|
} = part.shorthand()
|
||||||
|
|
||||||
|
// Design pattern here
|
||||||
|
|
||||||
|
// Create points
|
||||||
|
|
||||||
|
points.frontGussetLeft = new Point(store.get('frontGussetLeft').x, 0)
|
||||||
|
points.backGussetLeft = new Point(store.get('backGussetLeft').x, measurements.seat * options.gussetLength)
|
||||||
|
points.frontGussetRight = new Point(store.get('frontGussetRight').x, 0)
|
||||||
|
points.backGussetRight = new Point(store.get('backGussetRight').x, measurements.seat * options.gussetLength)
|
||||||
|
|
||||||
|
// Create control points
|
||||||
|
|
||||||
|
points.gussetCp1 = points.frontGussetLeft.shiftFractionTowards(points.backGussetLeft, 0.5)
|
||||||
|
.shift(180,points.frontGussetRight.x / -15)
|
||||||
|
|
||||||
|
// Flip points to right side
|
||||||
|
|
||||||
|
points.gussetCp2 = points.gussetCp1.flipX(store.get('frontGussetMid'))
|
||||||
|
|
||||||
|
// Create point for title
|
||||||
|
|
||||||
|
points.frontMidMid = points.gussetCp1.shiftFractionTowards(points.gussetCp2, 0.5)
|
||||||
|
|
||||||
|
/* Store lengths for use in elastic */
|
||||||
|
|
||||||
|
store.set(
|
||||||
|
'gussetSideLength',
|
||||||
|
new Path()
|
||||||
|
.move(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRight, points.gussetCp2, points.frontGussetRight)
|
||||||
|
.length()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Draw paths
|
||||||
|
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.frontGussetLeft)
|
||||||
|
.curve(points.gussetCp1, points.backGussetLeft, points.backGussetLeft)
|
||||||
|
.line(points.backGussetRight)
|
||||||
|
.curve(points.backGussetRight, points.gussetCp2, points.frontGussetRight)
|
||||||
|
.line(points.frontGussetLeft) // Without this, doesn't generate seam allowance
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric')
|
||||||
|
|
||||||
|
// Complete?
|
||||||
|
if (complete) {
|
||||||
|
|
||||||
|
if (sa) {
|
||||||
|
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro('title', {
|
||||||
|
at: points.frontMidMid,
|
||||||
|
nr: 3,
|
||||||
|
title: 'gusset',
|
||||||
|
})
|
||||||
|
|
||||||
|
// Paperless?
|
||||||
|
if (paperless) {
|
||||||
|
macro('hd', {
|
||||||
|
from: points.frontGussetLeft,
|
||||||
|
to: points.frontGussetRight,
|
||||||
|
y: points.frontGussetLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
from: points.backGussetLeft,
|
||||||
|
to: points.backGussetRight,
|
||||||
|
y: points.backGussetLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
from: points.frontGussetRight,
|
||||||
|
to: points.backGussetRight,
|
||||||
|
x: points.frontGussetRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
18
packages/ursula/src/index.js
Normal file
18
packages/ursula/src/index.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import freesewing from '@freesewing/core'
|
||||||
|
import plugins from '@freesewing/plugin-bundle'
|
||||||
|
import config from '../config'
|
||||||
|
import draftFront from './front'
|
||||||
|
import draftBack from './back'
|
||||||
|
import draftGusset from './gusset'
|
||||||
|
import draftElastic from './elastic'
|
||||||
|
|
||||||
|
// Create new design
|
||||||
|
const Pattern = new freesewing.Design(config, plugins)
|
||||||
|
|
||||||
|
// Attach the draft methods to the prototype
|
||||||
|
Pattern.prototype.draftFront = draftFront
|
||||||
|
Pattern.prototype.draftBack = draftBack
|
||||||
|
Pattern.prototype.draftGusset = draftGusset
|
||||||
|
Pattern.prototype.draftElastic = draftElastic
|
||||||
|
|
||||||
|
export default Pattern
|
Loading…
Add table
Add a link
Reference in a new issue