1
0
Fork 0

wip(markdown): Work on tutorial

This commit is contained in:
Joost De Cock 2022-10-10 04:50:43 +02:00
parent ed576747d8
commit 2d5cdf5806
6 changed files with 339 additions and 153 deletions

View file

@ -3,67 +3,129 @@ title: Completing the neck opening
order: 180 order: 180
--- ---
## Hiding our quarter neck
We've constructed the perfectly sized quarter neck, and we're going to use this We've constructed the perfectly sized quarter neck, and we're going to use this
to create our complete neck path by flipping and mirroring it. to create our complete neck path by flipping and mirroring it.
## Hiding our quarter neck opening
To make our code easier to understand, we're going to leave the `quarterNeck` path To make our code easier to understand, we're going to leave the `quarterNeck` path
as it is, and simply chose to not show it. as it is, and simply chose to not show it.
To accomplish this, update the code and add this one line: To accomplish this, we'll call the `hide()` method on our path:
<Example tutorial caption="A hidden path is not shown">
```js ```js
paths.quarterNeck = new Path() function draftBib({
.move(points.right) Path,
.curve(points.rightCp1, points.bottomCp2, points.bottom) Point,
.setRender(false) // <== Add this line paths,
``` points,
measurements,
options,
part,
}) {
We're saying: don't render this path. In other words, don't show it. // Construct the quarter neck opening
The path is now known, and we can still use it to calculate the length of the neck opening. let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let delta
do {
points.right = new Point(tweak * measurements.head / 10, 0)
points.bottom = new Point(0, tweak * measurements.head / 12)
points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right)/2)
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right)/2)
paths.quarterNeck = new Path()
.move(points.right)
.curve(points.rightCp1, points.bottomCp2, points.bottom)
.hide() // Add this line
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
return part
}
```
</Example>
We're saying: _hide this path_. In other words, don't show it.
The path is still known, and we can still use it to calculate the length of the neck opening.
But it won't show up on screen or on the page. But it won't show up on screen or on the page.
## Create the complete neck path ## Create the complete neck opening
Now that we've hidden our homework, let's create the complete neck path. Now that we've hidden our homework, let's create the complete neck path.
As the neck opening is symmetrical, there's no need to re-calculate the points As the neck opening is symmetrical, there's no need to re-calculate the points
on the other side. You can just flip them over, so to speak. And that's exactly what you'll do. on the other side. You can just flip them over, so to speak. And that's exactly
what you'll do.
Below your code (under the line with `while` on it), let's add some more points: Let's add some more points, and then construct the complete path for the neck
opening.
<Example tutorial caption="Our completed neck opening">
```js ```js
points.rightCp2 = points.rightCp1.flipY() function draftBib({
points.bottomCp1 = points.bottomCp2.flipX() Path,
Point,
paths,
points,
measurements,
options,
part,
}) {
points.left = points.right.flipX() // Construct the quarter neck opening
points.leftCp1 = points.rightCp2.flipX() let tweak = 1
points.leftCp2 = points.rightCp1.flipX() let target = (measurements.head * options.neckRatio) /4
let delta
do {
points.right = new Point(tweak * measurements.head / 10, 0)
points.bottom = new Point(0, tweak * measurements.head / 12)
points.top = points.bottom.flipY() points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right)/2)
points.topCp1 = points.bottomCp2.flipY() points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right)/2)
points.topCp2 = points.bottomCp1.flipY()
paths.quarterNeck = new Path()
.move(points.right)
.curve(points.rightCp1, points.bottomCp2, points.bottom)
.hide() // Add this line
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
// Construct the complete neck opening
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
points.leftCp1 = points.rightCp2.flipX()
points.leftCp2 = points.rightCp1.flipX()
points.top = points.bottom.flipY()
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
return part
}
``` ```
<Note>
We're using the `Point.flipX()` and `Point.flipY()` methods here.
Perhaps you can figure out what they do? If not, check [the API documentation](/reference/api/point/).
</Note>
Then, below those new points, and the following code to create your path for the neck opening:
```js
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
```
<Example pattern="tutorial" part="step4">
And now you have a complete neck opening
</Example> </Example>
To add the points, we're using the `Point.flipX()` and `Point.flipY()` methods
here. There's a few new Path methods to, like `close()` and `addClass()`.
Perhaps you can figure out what they do? If not, both [the Point
documentation](/reference/api/point/) and [the Path
documentation](/reference/api/path) have detailed info on all the methods
available, including these.

View file

@ -3,83 +3,119 @@ title: Constructing the neck opening
order: 160 order: 160
--- ---
Your goal is to construct a slightly oval neck opening that has a circumference that is Our goal is to construct an oval neck opening that has a circumference
the `head` measurements multiplied by the `neckRatio` option. that is the `head` measurements multiplied by the `neckRatio` option.
That might involve some trial and error. But since the neck opening will be symetric That might involve some trial and error. But since the neck opening will be symetric
both horizontal and vertical, you only need to construct one quadrant. both horizontal and vertical, we only need to construct one quadrant.
We'll be adding some points to our pattern to do just that. But we want to have access ## Desructuring measurements and options
to our measurements and options to do so. For this, you first update the shorthand call
to indicate you also want access to `measurements` and `options`:
```js We'll be adding some points to our pattern to do just that. But we want to have
const { access to our measurements and options to do so. For this, we first destructure
Point, `measurements` and `options` so we can access them:
points,
```design/src/bib.mjs
function draftBib({
Path, Path,
Point,
paths, paths,
complete, points,
sa, // Add the following two lines:
paperless,
measurements, measurements,
options options
} = part.shorthand() part,
}) {
return part
}
``` ```
Great. Now let's get to work: Great. Now let's get to work.
## Drawing our first path
Let's add some points, and use them to draw our first curve:
<Example tutorial caption="Our very first path forms a quarter of our neck opening">
```js ```js
// Design pattern here function draftBib({
points.right = new Point(measurements.head / 10, 0) Path,
points.bottom = new Point(0, measurements.head / 12) Point,
paths,
points,
measurements,
options,
part,
}) {
points.rightCp1 = points.right // Construct the quarter neck opening
.shift(90, points.bottom.dy(points.right)/2) points.right = new Point(measurements.head / 10, 0)
points.bottomCp2 = points.bottom points.bottom = new Point(0, measurements.head / 12)
.shift(0, points.bottom.dx(points.right)/2)
paths.quarterNeck = new Path() points.rightCp1 = points.right
.move(points.right) .shift(90, points.bottom.dy(points.right)/2)
.curve(points.rightCp1, points.bottomCp2, points.bottom) points.bottomCp2 = points.bottom
.shift(0, points.bottom.dx(points.right)/2)
paths.quarterNeck = new Path()
.move(points.right)
.curve(points.rightCp1, points.bottomCp2, points.bottom)
return part
}
``` ```
</Example>
You've added some points to your part, and drawn your first path. Let's look at each line in detail: You've added some points to your part, and drawn your first path.
Let's look at each line in detail.
## Adding points
```js ```js
points.right = new Point(measurements.head / 10, 0) points.right = new Point(measurements.head / 10, 0)
``` ```
- We're adding a point named `right` to `points` which holds our part's points - We're adding a point named `right` to the `points` object which holds our
- We're using the Point constructor, which takes two arguments: The point's X and Y values part's points
- We're using the Point constructor, which takes two arguments: The point's X
and Y values
- The X value is `measurements.head / 10` - The X value is `measurements.head / 10`
- The Y value is `0` - The Y value is `0`
The `bottom` part is very similar, so let's skip to the next line: The creation of `points.bottom` is very similar, so let's skip to the next line:
```js ```js
points.rightCp1 = points.right points.rightCp1 = points.right
.shift(90, points.bottom.dy(points.right)/2) .shift(90, points.bottom.dy(points.right)/2)
``` ```
- We're adding a point named `rightCp1`, which will become the _control point_ of the right part - We're adding a point named `rightCp1`, which will become the _control point_
- Instead of using the Point constructor, we're calling the `Point.shift()` method on an existing point of the right part
- Instead of using the Point constructor, we're calling the `Point.shift()`
method on an existing point
- It takes two arguments: The angle to shift towards, and the distance - It takes two arguments: The angle to shift towards, and the distance
- You can see that we're shifting 90 degrees (that means up) but the distance uses another method - You can see that we're shifting 90 degrees (that means up) but the distance
- The `Point.dy()` method returns the delta along the Y axis between the point you call it on and the point you pass it uses another method
- The `Point.dy()` method returns the delta along the Y axis between the point
you call it on and the point you pass it
- We shift half of the Y-delta - We shift half of the Y-delta
The next point is very similar again, except that this time we're shifting to the right (0 degrees) for half of The next point is very similar again, except that this time we're shifting to
the X-delta between points `bottom` and `right`. the right (0 degrees) for half of the X-delta between points `bottom` and
`right`.
<Tip> <Tip>
##### Further reading
The `Point.shift()` and `Point.dy()` are just the tip of the iceberg.
Points come with a bunch of these methods. Points come with a bunch of these methods.
You can find them all in [the Point API docs](/reference/api/point/). You can find them all in [the Point API docs](/reference/api/point/).
</Tip> </Tip>
The next line introduces you to something new: Paths: ## Adding paths
Adding points is typically merely a means to an end. And that end gets
introduced on the next line: Paths.
```js ```js
paths.quarterNeck = new Path() paths.quarterNeck = new Path()
@ -87,20 +123,20 @@ paths.quarterNeck = new Path()
.curve(points.rightCp1, points.bottomCp2, points.bottom) .curve(points.rightCp1, points.bottomCp2, points.bottom)
``` ```
- We're adding a path named `quarterNeck` to `paths` which holds our part's paths - We're adding a path named `quarterNeck` to the `paths` object which holds our
part's paths
- We're using the Path constructor, which takes no arguments - We're using the Path constructor, which takes no arguments
- We're following up with a `Path.move()` call that takes one Point as argument - We're following up with a `Path.move()` call that takes one Point as argument
- Then, there's a `Path.curve()` call that takes 3 points as arguments - Then, there's a `Path.curve()` call that takes 3 points as arguments
If you've read through the high-level [Pattern guide](/guides/patterns/) you will have learned that paths If you've read through the high-level [Pattern guide](/guides/patterns) you
always start with a `move()` operation. In this case, we moved to our `right` points. will have learned that paths always start with a `move()` operation. In this
case, we moved to our `right` points.
From there, we drew a Bezier curve to our `bottom` point by using `rightCp1` and `bottomCp2` as control points. From there, we drew a cubic Bezier curve to our `bottom` point by using
`rightCp1` and `bottomCp2` as control points.
When all is said and done, we now have a quarter of our neck opening:
<Example pattern="tutorial" part="step2">You have drawn your first path</Example>
When all is said and done, we now have a quarter of our neck opening.
The only problem is, we have no guarantee whatsoever that this opening is the correct size. The only problem is, we have no guarantee whatsoever that this opening is the correct size.
Rather than hope it is the correct size, you'll make sure it is next. Rather than hope it is the correct size, we'll make sure it is next.

View file

@ -28,6 +28,16 @@ need to draft your method. Destructuring is a way to *pull things out of the
object into their own variable*. It saves us a bunch of typing as these two are object into their own variable*. It saves us a bunch of typing as these two are
equivalent: equivalent:
<Tabs tabs="Without destructuring, With destructuring">
<Tab>
```design/src/bib.mjs
function draftBib({ part }) {
return part
}
```
</Tab>
<Tab>
```design/src/bib.mjs ```design/src/bib.mjs
function draftBib(props) { function draftBib(props) {
@ -35,13 +45,8 @@ function draftBib(props) {
} }
``` ```
</Tab>
```design/src/bib.mjs </Tabs>
function draftBib({ part }) {
return part
}
```
As we'll make our way through this tutorial, we'll need more and more stuff, so As we'll make our way through this tutorial, we'll need more and more stuff, so
we'll be pulling it out of the object passed to the draft method via we'll be pulling it out of the object passed to the draft method via

View file

@ -3,35 +3,92 @@ title: Drawing the bib outline
order: 190 order: 190
--- ---
With our neck opening in place, let's draw the basic outline of our bib: With our neck opening in place, let us draw the basic outline of our bib.
<Example tutorial caption="Note how the neck opening is the same distance from the left, right, and top edge">
```js ```js
let width = measurements.head * options.widthRatio function draftBib({
let length = measurements.head * options.lengthRatio Path,
Point,
paths,
points,
measurements,
options,
part,
}) {
points.topLeft = new Point( // Construct the quarter neck opening
width / -2, let tweak = 1
points.top.y - (width / 2 - points.right.x) let target = (measurements.head * options.neckRatio) /4
); let delta
points.topRight = points.topLeft.shift(0, width) do {
points.bottomLeft = points.topLeft.shift(-90, length) points.right = new Point(tweak * measurements.head / 10, 0)
points.bottomRight = points.topRight.shift(-90, length) points.bottom = new Point(0, tweak * measurements.head / 12)
paths.rect = new Path() points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right)/2)
.move(points.topLeft) points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right)/2)
.line(points.bottomLeft)
.line(points.bottomRight) paths.quarterNeck = new Path()
.line(points.topRight) .move(points.right)
.line(points.topLeft) .curve(points.rightCp1, points.bottomCp2, points.bottom)
.close() .hide() // Add this line
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
// Construct the complete neck opening
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
points.leftCp1 = points.rightCp2.flipX()
points.leftCp2 = points.rightCp1.flipX()
points.top = points.bottom.flipY()
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
// Drawing the bib outline
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
paths.rect = new Path()
.move(points.topLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.topRight)
.line(points.topLeft)
.close()
.addClass('fabric')
return part
}
``` ```
</Example>
First thing we did was create the `width` and `length` variables to First thing we did was create the `width` and `length` variables to
save ourselves some typing: save ourselves some typing:
```js ```js
let width = measurements.head * options.widthRatio const width = measurements.head * options.widthRatio
let length = measurements.head * options.lengthRatio const length = measurements.head * options.lengthRatio
``` ```
Both the length and width of your bib are a factor of the head circumference. Both the length and width of your bib are a factor of the head circumference.
@ -56,13 +113,11 @@ paths.rect = new Path()
.line(points.topRight) .line(points.topRight)
.line(points.topLeft) .line(points.topLeft)
.close() .close()
.addClass('fabric')
``` ```
We're calculating the `topLeft` point so that the top edge of our bib We're calculating the `topLeft` point so that the top edge of our bib
and the sides are equidistant from the neck neck opening. and the sides are equidistant from the neck neck opening.
You didn't have to do that. But it looks nicely balanced this way: We didn't have to do that. But it looks nicely balanced this way.
<Example pattern="tutorial" part="step5">
Note how the neck opening is the same distance from the left, right, and top edge
</Example>

View file

@ -5,6 +5,14 @@ title: Pattern design tutorial
Welcome to the FreeSewing pattern design tutorial, where you'll learn how to Welcome to the FreeSewing pattern design tutorial, where you'll learn how to
design a made-to-measure sewing pattern, start to finish. design a made-to-measure sewing pattern, start to finish.
<Tip>
##### Before you start
If you haven't done so yet, read the [Before you start
guide](/guides/prerequisites). It's very short, but covers some basic
terminology and concepts that we'll use throughout this guide.
</Tip>
You will be designing a pattern for a baby bib. It's a very simple pattern, but You will be designing a pattern for a baby bib. It's a very simple pattern, but
that's the point. Your focus today is on learning FreeSewing and how to that's the point. Your focus today is on learning FreeSewing and how to
translate your designs into code. translate your designs into code.

View file

@ -3,48 +3,68 @@ title: Fitting the neck opening
order: 170 order: 170
--- ---
Here's how we'll make sure the neck opening is _just right_: We are not going to create some opening that we _hope_ is the right size, we're
going to make sure it is. Here's how we'll make sure the neck opening is _just
right_:
<Example tutorial caption="It might look the same as before, but now it's just right">
```js ```js
let tweak = 1 function draftBib({
let target = (measurements.head * options.neckRatio) /4 Path,
let delta Point,
do { paths,
points.right = new Point(tweak * measurements.head / 10, 0) points,
points.bottom = new Point(0, tweak * measurements.head / 12) measurements,
options,
part,
}) {
points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right)/2) // Construct the quarter neck opening
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right)/2) let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let delta
do {
points.right = new Point(tweak * measurements.head / 10, 0)
points.bottom = new Point(0, tweak * measurements.head / 12)
paths.quarterNeck = new Path() points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right)/2)
.move(points.right) points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right)/2)
.curve(points.rightCp1, points.bottomCp2, points.bottom)
delta = paths.quarterNeck.length() - target paths.quarterNeck = new Path()
if (delta > 0) tweak = tweak * 0.99 .move(points.right)
else tweak = tweak * 1.02 .curve(points.rightCp1, points.bottomCp2, points.bottom)
} while (Math.abs(delta) > 1)
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
return part
}
``` ```
</Example>
We've added a few new variables: We've added a few new variables:
- `tweak`: A _tweak factor_ that we'll use to increase or decrease the neck opening by making it more or less than 1 - `tweak`: A _tweak factor_ that we'll use to increase or decrease the neck
opening by making it more or less than 1
- `target`: How long our (quarter) neck opening should be - `target`: How long our (quarter) neck opening should be
- `delta`: How far we're off. Positive numbers mean it's too long, negative means too short - `delta`: How far we're off. Positive numbers mean it's too long, negative
means too short
Now that we know what `target` is, we construct our path as we did before. Now that we know what `target` is, we construct our path as we did before. But
But this time around, we multiply our point coordinates with our `tweak` variable (1 at the start). this time around, we multiply our point coordinates with our `tweak` variable
(1 at the start).
Then, we compare our `target` to the result of `paths.neck.length()` which — you guessed it — returns the Then, we compare our `target` to the result of `paths.neck.length()` which —
length of our neck path. you guessed it — returns the length of our neck path.
If the delta is positive, our path is too long and we reduce the tweak factor. If the delta is positive, our path is too long and we reduce the tweak factor.
If the delta is negative, our path is too short and we increase the tweak factor. If the delta is negative, our path is too short and we increase the tweak
factor.
We keep on doing this until `Math.abs(delta)` is less than 1. Meaning that we are within 1mm of our target value. We keep on doing this until `Math.abs(delta)` is less than 1. Meaning that we
are within 1mm of our target value.
<Example pattern="tutorial" part="step2"> Now that we're happy with the length of our quarter neck opening, let's
It might look the same as before, but now it's just right construct the entire neck opening.
</Example>
Now that we're happy with the length of our quarter neck opening, let's construct the entire neck opening.