
The replaces the NextJS site powering FreeSewing.dev with a Docusaurus setup. It's part of my efforts to simplify FreeSewing's setup so we can focus on our core value proposition.
343 lines
12 KiB
Text
343 lines
12 KiB
Text
---
|
|
title: Sets
|
|
sidebar_position: 100
|
|
---
|
|
|
|
When we refer to a _set_ we mean a _set of settings_.
|
|
In the vast majority of cases, there is only one set of settings. So we just
|
|
refer to them as _the settings_. But FreeSewing supports instantiating a
|
|
pattern with multiple sets of settings. We refer to this as **multiset
|
|
support**.
|
|
|
|
## Multiset support
|
|
|
|
Multiset support underpins features such as
|
|
[sampling](/reference/api/pattern/sample) and in general can be used to
|
|
_combine_ multiple drafted variants into a single pattern container.
|
|
|
|
Here's a simple example:
|
|
|
|
<Example settings="sample: { type: measurement, measurement: head }" withHead caption="A simple example of sampling the `head` measurement">
|
|
```js
|
|
({
|
|
Point,
|
|
points,
|
|
Path,
|
|
paths,
|
|
Snippet,
|
|
snippets,
|
|
measurements,
|
|
part
|
|
}) => {
|
|
|
|
const size = measurements.head
|
|
paths.box = new Path()
|
|
.move(new Point(0,0))
|
|
.line(new Point(0, size/3))
|
|
.line(new Point(size, size/3))
|
|
.line(new Point(size, 0))
|
|
.addClass('fabric')
|
|
.close()
|
|
points.logo = new Point(size/2, size/5)
|
|
snippets.logo = new Snippet('logo', points.logo)
|
|
|
|
return part
|
|
}
|
|
```
|
|
</Example>
|
|
|
|
When drafting for multiple sets of settings, it's important to keep the different draft variants from cross-contaminating each other.
|
|
To ensure this, the core library will:
|
|
|
|
- Set up each pattern part per set
|
|
- Provide a per-set store that is shared between parts in the set
|
|
|
|
This is illustrated below:
|
|
|
|
|
|
|
|
<Example caption="A schematic overview of what goes on inside a FreeSewing pattern">
|
|
```mjs
|
|
({ Point, points, Path, paths, options, part }) => {
|
|
|
|
// Draws a w*h box, returns a Path object
|
|
const box = (name, origin, width, height, classes='fabric') => {
|
|
let base = height
|
|
if (width < height) base = width
|
|
let t = base
|
|
points[name + 'TopLeft'] = new Point(origin.x, origin.y)
|
|
points[name + 'BottomLeft'] = new Point(origin.x, origin.y + height)
|
|
points[name + 'BottomRight'] = new Point(
|
|
origin.x + width,
|
|
origin.y + height
|
|
)
|
|
points[name + 'TopRight'] = new Point(origin.x + width, origin.y)
|
|
points[name + 'Mid'] = points[name + 'TopLeft'].shiftFractionTowards(
|
|
points[name + 'BottomRight'],
|
|
0.5
|
|
)
|
|
points[name + 'Mid'].y += 3
|
|
|
|
return new Path()
|
|
.move(points[name + 'TopLeft'])
|
|
.line(points[name + 'BottomLeft'])
|
|
.line(points[name + 'BottomRight'])
|
|
.line(points[name + 'TopRight'])
|
|
.line(points[name + 'TopLeft'])
|
|
.close()
|
|
.addClass(classes)
|
|
}
|
|
|
|
// Draws and arrow from to and places text
|
|
const arrow = (name, text = '') => {
|
|
let from = points[name + 'From']
|
|
let to = points[name + 'To']
|
|
from = from.shiftTowards(to, 2)
|
|
to = to.shiftTowards(from, 2)
|
|
const base = from.dist(to)
|
|
const r = 3
|
|
points[name + 'Tip1'] = to.shiftTowards(from, 3.5).rotate(r, from)
|
|
points[name + 'Tip2'] = to.shiftTowards(from, 3.5).rotate(r * -1, from)
|
|
const path = new Path()
|
|
.move(from)
|
|
.line(to)
|
|
.move(points[name + 'Tip1'])
|
|
.line(to)
|
|
.line(points[name + 'Tip2'])
|
|
.addClass('lining stroke-lg')
|
|
if (options.focus === name) path.addClass('note')
|
|
|
|
return text
|
|
? path.addText(' ' + text, options.focus === name ? 'fill-note center' : 'center')
|
|
: path
|
|
}
|
|
|
|
// Draws a box and handled text placement
|
|
const drawBox = (name, x, y, width, height, text=true, classes, textClasses='') => {
|
|
points[name + 'Origin'] = new Point(x, y)
|
|
paths[name] = box(name, points[name + 'Origin'], width, height, classes)
|
|
if (text === 'b') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'BottomLeft'])
|
|
.line(points[name+'BottomRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dy', -1)
|
|
}
|
|
else if (text === 't') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'TopLeft'])
|
|
.line(points[name+'TopRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dy', 11)
|
|
}
|
|
else if (text === 'r') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'BottomRight'])
|
|
.line(points[name+'TopRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dx', -5)
|
|
}
|
|
else if (text) points[name + 'Mid'].addText(name, 'center')
|
|
}
|
|
|
|
// Stacks
|
|
drawBox('Stack 0', -30, -33, 50, 169, 'b', 'mark', 'fill-mark')
|
|
paths['Stack 0'].attr('fill-opacity', 0.2)
|
|
drawBox('Stack 1', 23, -33, 50, 169, 'b', 'mark', 'fill-mark')
|
|
paths['Stack 1'].attr('fill-opacity', 0.2)
|
|
drawBox('Stack 2', 76, -33, 50, 169, 'b', 'mark', 'fill-mark')
|
|
paths['Stack 2'].attr('fill-opacity', 0.2)
|
|
|
|
// Sets
|
|
drawBox('Set 0', -33, -30, 174, 76, 'r', 'contrast fill-contrast', 'bold text-lg fill-contrast')
|
|
paths['Set 0'].attr('fill-opacity', 0.2)
|
|
drawBox('Set 1', -33, 50, 174, 76, 'r', 'contrast fill-contrast', 'bold text-lg fill-contrast')
|
|
paths['Set 1'].attr('fill-opacity', 0.2)
|
|
|
|
// Parts set 0
|
|
drawBox('Part A (set 0)', -27, -27, 44, 70, 'b', 'note')
|
|
drawBox('points', -24, -24, 38, 12, true, 'note')
|
|
drawBox('paths', -24, -9, 38, 12, true, 'note')
|
|
drawBox('snippets', -24, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('Part B (set 0)', 26, -27, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 29, -24, 38, 12, true, 'note')
|
|
drawBox(' paths ', 29, -9, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 29, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('Part C (set 0)', 79, -27, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 82, -24, 38, 12, true, 'note')
|
|
drawBox(' paths ', 82, -9, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 82, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('setStore 0', -24, 21, 144, 12, true, 'lining', 'fill-various')
|
|
paths['setStore 0'].attr('fill-opacity', 0.2)
|
|
|
|
// Parts set 1
|
|
drawBox('Part A (set 1)', -27, 53, 44, 70, 'b', 'note')
|
|
drawBox(' points', -24, 56, 38, 12, true, 'note')
|
|
drawBox(' paths', -24, 71, 38, 12, true, 'note')
|
|
drawBox(' snippets', -24, 86, 38, 12, true, 'note')
|
|
|
|
drawBox('Part B (set 1)', 26, 53, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 29, 56, 38, 12, true, 'note')
|
|
drawBox(' paths ', 29, 71, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 29, 86, 38, 12, true, 'note')
|
|
|
|
drawBox('Part C (set 1)', 79, 53, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 82, 56, 38, 12, true, 'note')
|
|
drawBox(' paths ', 82, 71, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 82, 86, 38, 12, true, 'note')
|
|
|
|
drawBox('setStore 1', -24, 101, 147, 12, true, 'lining', 'fill-various')
|
|
paths['setStore 1'].attr('fill-opacity', 0.2)
|
|
|
|
// Pattern
|
|
drawBox('Pattern Store', -30, -52, 155, 15, true, 'lining', 'fill-lining')
|
|
paths['Pattern Store'].attr('fill-opacity', 0.2)
|
|
drawBox('Pattern', -43, -59, 195, 216, 'b', 'fabric stroke-lg', 'text-lg bold')
|
|
|
|
return part
|
|
}
|
|
```
|
|
</Example>
|
|
|
|
## One set is plenty
|
|
|
|
In the vast majority of cases, a pattern will only have one set of settings.
|
|
As such, multiset support is not something you need to be intimately familiar with.
|
|
But, it is good to know it exists and explains certain things that might seem
|
|
_odd_ if you were unaware of multiset support, such as the fact that there's a
|
|
pattern-wide store and a different store per set, the so-called _setStore(s)_.
|
|
|
|
Below is an illustration of a pattern with a single set of settings which, once again, is the vast majority of use cases:
|
|
|
|
<Example caption="A schematic overview of what goes on inside a FreeSewing pattern in a typical use-case: a single set of settings">
|
|
```mjs
|
|
({ Point, points, Path, paths, options, part }) => {
|
|
|
|
// Draws a w*h box, returns a Path object
|
|
const box = (name, origin, width, height, classes='fabric') => {
|
|
let base = height
|
|
if (width < height) base = width
|
|
let t = base
|
|
points[name + 'TopLeft'] = new Point(origin.x, origin.y)
|
|
points[name + 'BottomLeft'] = new Point(origin.x, origin.y + height)
|
|
points[name + 'BottomRight'] = new Point(
|
|
origin.x + width,
|
|
origin.y + height
|
|
)
|
|
points[name + 'TopRight'] = new Point(origin.x + width, origin.y)
|
|
points[name + 'Mid'] = points[name + 'TopLeft'].shiftFractionTowards(
|
|
points[name + 'BottomRight'],
|
|
0.5
|
|
)
|
|
points[name + 'Mid'].y += 3
|
|
|
|
return new Path()
|
|
.move(points[name + 'TopLeft'])
|
|
.line(points[name + 'BottomLeft'])
|
|
.line(points[name + 'BottomRight'])
|
|
.line(points[name + 'TopRight'])
|
|
.line(points[name + 'TopLeft'])
|
|
.close()
|
|
.addClass(classes)
|
|
}
|
|
|
|
// Draws and arrow from to and places text
|
|
const arrow = (name, text = '') => {
|
|
let from = points[name + 'From']
|
|
let to = points[name + 'To']
|
|
from = from.shiftTowards(to, 2)
|
|
to = to.shiftTowards(from, 2)
|
|
const base = from.dist(to)
|
|
const r = 3
|
|
points[name + 'Tip1'] = to.shiftTowards(from, 3.5).rotate(r, from)
|
|
points[name + 'Tip2'] = to.shiftTowards(from, 3.5).rotate(r * -1, from)
|
|
const path = new Path()
|
|
.move(from)
|
|
.line(to)
|
|
.move(points[name + 'Tip1'])
|
|
.line(to)
|
|
.line(points[name + 'Tip2'])
|
|
.addClass('lining stroke-lg')
|
|
if (options.focus === name) path.addClass('note')
|
|
|
|
return text
|
|
? path.addText(' ' + text, options.focus === name ? 'fill-note center' : 'center')
|
|
: path
|
|
}
|
|
|
|
// Draws a box and handled text placement
|
|
const drawBox = (name, x, y, width, height, text=true, classes, textClasses='') => {
|
|
points[name + 'Origin'] = new Point(x, y)
|
|
paths[name] = box(name, points[name + 'Origin'], width, height, classes)
|
|
if (text === 'b') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'BottomLeft'])
|
|
.line(points[name+'BottomRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dy', -1)
|
|
}
|
|
else if (text === 't') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'TopLeft'])
|
|
.line(points[name+'TopRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dy', 11)
|
|
}
|
|
else if (text === 'r') {
|
|
paths[name+'_label'] = new Path()
|
|
.move(points[name+'BottomRight'])
|
|
.line(points[name+'TopRight'])
|
|
.addClass('hidden')
|
|
.addText(name, 'center ' + textClasses)
|
|
.attr('data-text-dx', -5)
|
|
}
|
|
else if (text) points[name + 'Mid'].addText(name, 'center')
|
|
}
|
|
|
|
// Stacks
|
|
drawBox(' Stack 0', -30, -33, 50, 89, 'b', 'mark', 'fill-mark')
|
|
drawBox(' Stack 1', 23, -33, 50, 89, 'b', 'mark', 'fill-mark')
|
|
drawBox(' Stack 2', 76, -33, 50, 89, 'b', 'mark', 'fill-mark')
|
|
|
|
// Sets
|
|
drawBox('Set 0', -33, -30, 174, 76, 'r', 'contrast fill-contrast', 'bold text-lg fill-contrast')
|
|
paths['Set 0'].attr('fill-opacity', 0.2)
|
|
|
|
// Parts set 0
|
|
drawBox('Part A (set 0)', -27, -27, 44, 70, 'b', 'note')
|
|
drawBox('points', -24, -24, 38, 12, true, 'note')
|
|
drawBox('paths', -24, -9, 38, 12, true, 'note')
|
|
drawBox('snippets', -24, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('Part B (set 0)', 26, -27, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 29, -24, 38, 12, true, 'note')
|
|
drawBox(' paths ', 29, -9, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 29, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('Part C (set 0)', 79, -27, 44, 70, 'b', 'note')
|
|
drawBox(' points ', 82, -24, 38, 12, true, 'note')
|
|
drawBox(' paths ', 82, -9, 38, 12, true, 'note')
|
|
drawBox(' snippets ', 82, 6, 38, 12, true, 'note')
|
|
|
|
drawBox('setStore 0', -24, 21, 144, 12, true, 'lining', 'fill-various')
|
|
paths['setStore 0'].attr('fill-opacity', 0.2)
|
|
|
|
// Pattern
|
|
drawBox('Pattern Store', -30, -52, 155, 15, true, 'lining', 'fill-lining')
|
|
paths['Pattern Store'].attr('fill-opacity', 0.2)
|
|
drawBox(' Pattern', -43, -59, 195, 128, 'b', 'fabric stroke-lg', 'text-lg bold')
|
|
|
|
return part
|
|
}
|
|
```
|
|
</Example>
|
|
|
|
|