1
0
Fork 0

🚧 Progress on Sandy

This commit is contained in:
Joost De Cock 2019-07-12 13:13:09 +02:00
parent 859c5f14fb
commit dd38a36906
5 changed files with 193 additions and 113 deletions

View file

@ -10,17 +10,15 @@ export default {
difficulty: 3, difficulty: 3,
tags: ["skirt", "top", "basics"], tags: ["skirt", "top", "basics"],
optionGroups: { optionGroups: {
fit: ["waistbandPosition"], fit: ["waistbandPosition", "waistbandShape"],
style: [ style: [
"lengthBonus", "lengthBonus",
"circleRatio", "circleRatio",
"waistbandWidth", "waistbandWidth",
"waistbandShape",
"waistbandOverlap", "waistbandOverlap",
"gathering", "gathering"
"seamlessFullCircle", ],
"hemWidth" construction: ["seamlessFullCircle", "hemWidth"]
]
}, },
measurements: [ measurements: [
"naturalWaist", "naturalWaist",
@ -32,6 +30,9 @@ export default {
waistband: "skirt" waistband: "skirt"
}, },
options: { options: {
// Constants
minimumOverlap: 15, // Lower than this and we don't draw a button
// Bool // Bool
seamlessFullCircle: { bool: false }, seamlessFullCircle: { bool: false },
@ -44,7 +45,7 @@ export default {
circleRatio: { pct: 50, min: 20, max: 100 }, circleRatio: { pct: 50, min: 20, max: 100 },
waistbandOverlap: { pct: 3, min: 0, max: 15 }, waistbandOverlap: { pct: 3, min: 0, max: 15 },
gathering: { pct: 0, min: 0, max: 200 }, gathering: { pct: 0, min: 0, max: 200 },
hemWidth: { pct: 1, min: 0, max: 5 }, hemWidth: { pct: 2, min: 1, max: 10 },
// Lists // Lists
waistbandShape: { waistbandShape: {

View file

@ -52,8 +52,61 @@ export default function(part) {
// Complete pattern? // Complete pattern?
if (complete) { if (complete) {
if (sa) { points.title = points.in1Rotated
.shiftFractionTowards(points.ex1Rotated, 0.5)
.shift(0, 25);
macro("title", {
at: points.title,
nr: 2,
title: "curvedWaistband",
scale: 0.5
});
points.grainlineFrom = utils.curveIntersectsY(
points.ex2FlippedRotated,
points.ex2CFlippedRotated,
points.ex1CFlippedRotated,
points.ex1Rotated,
points.title.y
);
points.grainlineTo = points.grainlineFrom.flipX();
macro("grainline", {
from: points.grainlineFrom,
to: points.grainlineTo
});
if (store.get("waistbandOverlap") >= options.minimumOverlap) {
points.pivot = points.in2Rotated.shiftFractionTowards(
points.ex2Rotated,
0.5
);
points.button = points.pivot
.shiftTowards(points.ex2Rotated, store.get("waistbandOverlap") / 2)
.rotate(-90, points.pivot);
points.buttonhole = points.button.flipX();
snippets.button = new Snippet("button", points.button);
snippets.buttonhole = new Snippet("buttonhole", points.buttonhole).attr(
"data-rotate",
-1 * points.ex2FlippedRotated.angle(points.in2FlippedRotated)
);
points.centerNotch = new Path()
.move(points.ex1Rotated)
.curve(
points.ex1CFlippedRotated,
points.ex2CFlippedRotated,
points.ex2FlippedRotated
)
.shiftAlong(store.get("waistbandOverlap") / 2);
points.buttonNotch = new Path()
.move(points.ex2Rotated)
.curve(points.ex2CRotated, points.ex1CRotated, points.ex1Rotated)
.shiftAlong(store.get("waistbandOverlap"));
macro("sprinkle", {
snippet: "notch",
on: ["centerNotch", "buttonNotch", "ex2FlippedRotated"]
});
} }
if (sa) paths.sa = paths.seam.offset(sa * -1).attr("class", "fabric sa");
} }
// Paperless? // Paperless?

View file

@ -1,4 +1,4 @@
const draftRingSector = (part, rot, an, radIn, radEx) => { const draftRingSector = (part, rot, an, radIn, radEx, rotate = false) => {
let { let {
utils, utils,
store, store,
@ -101,6 +101,13 @@ const draftRingSector = (part, rot, an, radIn, radEx) => {
]) ])
points[id + "Rotated"] = points[id].rotate(rot, points.center); points[id + "Rotated"] = points[id].rotate(rot, points.center);
if (rotate) {
// Rotate all points so the line from in1Rotated to ex1Rotated is vertical
let deg = 270 - points.in1Rotated.angle(points.ex1Rotated);
for (let id in points) {
points[id] = points[id].rotate(deg, points.in1Rotated);
}
}
// Return the path of the full ring sector // Return the path of the full ring sector
return new Path() return new Path()
.move(points.in2Flipped) .move(points.in2Flipped)

View file

@ -18,103 +18,6 @@ export default function(part) {
macro macro
} = part.shorthand(); } = part.shorthand();
const oundExtended = (radius, angle = 90) => {
let arg = utils.deg2rad(angle / 2);
return (radius * 4 * (1 - Math.cos(arg))) / Math.sin(arg) / 3;
};
const raftRingSector = (rot, an, radIn, radEx) => {
/**
* Calculates the distance of the control point for the internal
* and external arcs using bezierCircleExtended
*/
let distIn = roundExtended(radIn, an / 2);
let distEx = roundExtended(radEx, an / 2);
// The centre of the circles
points.center = new Point(0, 0);
/**
* This function is expected to draft ring sectors for
* angles up to 180%. Since roundExtended works
* best for angles until 90º, we generate the ring
* sector using the half angle and then duplicate it
*/
/**
* The first point of the internal arc, situated at
* a radIn distance below the centre
*/
points.in1 = points.center.shift(-90, radIn);
/**
* The control point for 'in1'. It's situated at a
* distance $distIn calculated with bezierCircleExtended
* and the line between it and 'in1' is perpendicular to
* the line between 'in1' and the centre, so it's
* shifted in the direction 0º
*/
points.in1C = points.in1.shift(0, distIn);
/**
* The second point of the internal arc, situated at
* a $radIn distance of the centre in the direction
* $an/2 - 90º
*/
points.in2 = points.center.shift(an / 2 - 90, radIn);
/**
* The control point for 'in2'. It's situated at a
* distance $distIn calculated with bezierCircleExtended
* and the line between it and 'in2' is perpendicular to
* the line between 'in2' and the centre, so it's
* shifted in the direction $an/2 + 180º
*/
points.in2C = points.in2.shift(an / 2 + 180, distIn);
/**
* The points for the external arc are generated in the
* same way, using $radEx and $distEx instead
*/
points.ex1 = points.center.shift(-90, radEx);
points.ex1C = points.ex1.shift(0, distEx);
points.ex2 = points.center.shift(an / 2 - 90, radEx);
points.ex2C = points.ex2.shift(an / 2 + 180, distEx);
// Flip all the points to generate the full ring sector
for (let id of ["in2", "in2C", "in1C", "ex1C", "ex2C", "ex2"])
points[id + "Flipped"] = points[id].flipX();
// Rotate all the points an angle rot
for (let id of [
"in1",
"in1C",
"in2",
"in2C",
"ex1",
"ex1C",
"ex2",
"ex2C",
"in2Flipped",
"in2CFlipped",
"in1CFlipped",
"ex1CFlipped",
"ex2CFlipped",
"ex2Flipped"
])
points[id + "Rotated"] = points[id].rotate(rot, points.center);
// Return the path of the full ring sector
return new Path()
.move(points.in2Flipped)
.curve(points.in2CFlipped, points.in1CFlipped, points.in1)
.curve(points.in1C, points.in2C, points.in2)
.line(points.ex2)
.curve(points.ex2C, points.ex1C, points.ex1)
.curve(points.ex1CFlipped, points.ex2CFlipped, points.ex2Flipped)
.close();
};
// Circumference of the top of the waistband, calculated from the waistbandPosition option // Circumference of the top of the waistband, calculated from the waistbandPosition option
store.set( store.set(
"topCircumference", "topCircumference",
@ -155,7 +58,6 @@ export default function(part) {
measurements.naturalWaistToHip * options.waistbandPosition measurements.naturalWaistToHip * options.waistbandPosition
); );
console.log("STORE", store.data);
let radiusWaist, an; let radiusWaist, an;
if (options.seamlessFullCircle) { if (options.seamlessFullCircle) {
/** /**
@ -201,17 +103,103 @@ export default function(part) {
let rot = an / 2; let rot = an / 2;
// Call draftRingSector to draft the part // Call draftRingSector to draft the part
paths.seam = draftRingSector(part, rot, an, radiusWaist, radiusHem).attr( paths.seam = draftRingSector(
"class", part,
"fabric" rot,
); an,
radiusWaist,
radiusHem,
true
).attr("class", "fabric");
// Anchor samples to the centre of the waist // Anchor samples to the centre of the waist
points.gridAnchor = points.in2Flipped.clone(); points.gridAnchor = points.in2Flipped.clone();
// Complete pattern? // Complete pattern?
if (complete) { if (complete) {
macro("cutonfold", {
from: points.in2Flipped,
to: points.ex2Flipped,
grainline: true
});
if (options.seamlessFullCircle) {
macro("cutonfold", {
from: points.ex1Rotated,
to: points.in1Rotated,
prefix: "double"
});
}
points.logo = points.in2FlippedRotated.shiftFractionTowards(
points.ex2FlippedRotated,
0.3
);
snippets.logo = new Snippet("logo", points.logo);
points.title = points.in2FlippedRotated.shiftFractionTowards(
points.ex2FlippedRotated,
0.5
);
macro("title", { at: points.title, nr: 1, title: "skirt" });
points.scalebox = points.in2FlippedRotated.shiftFractionTowards(
points.ex2FlippedRotated,
0.7
);
macro("scalebox", { at: points.scalebox });
macro("sprinkle", {
snippet: "notch",
on: ["in1Rotated", "gridAnchor"]
});
if (sa) { if (sa) {
paths.hemBase = new Path()
.move(points.ex1Rotated)
.curve(
points.ex1CFlippedRotated,
points.ex2CFlippedRotated,
points.ex2FlippedRotated
)
.curve(points.ex1CFlipped, points.ex2CFlipped, points.ex2Flipped)
.offset(
store.get("fullLength") * options.lengthBonus * options.hemWidth * -1
);
paths.saBase = new Path()
.move(points.in2Flipped)
.curve(points.in2CFlipped, points.in1CFlipped, points.in2FlippedRotated)
.curve(
points.in2CFlippedRotated,
points.in1CFlippedRotated,
points.in1Rotated
);
if (!options.seamlessFullCircle)
paths.saBase = paths.saBase.line(points.ex1Rotated);
paths.saBase = paths.saBase.offset(sa * -1);
paths.hemBase.render = false;
paths.saBase.render = false;
if (options.seamlessFullCircle) {
paths.sa = new Path()
.move(points.in2Flipped)
.line(paths.saBase.start())
.join(paths.saBase)
.line(points.in1Rotated)
.move(points.ex1Rotated)
.line(paths.hemBase.start())
.join(paths.hemBase)
.line(points.ex2Flipped)
.attr("class", "fabric sa");
} else {
paths.sa = new Path()
.move(points.in2Flipped)
.line(paths.saBase.start())
.join(paths.saBase)
.line(paths.hemBase.start())
.join(paths.hemBase)
.line(points.ex2Flipped)
.attr("class", "fabric sa");
}
} }
} }

View file

@ -50,8 +50,39 @@ export default function(part) {
// Complete pattern? // Complete pattern?
if (complete) { if (complete) {
if (sa) { points.title = points.center.shiftFractionTowards(points.centerRight, 0.5);
} macro("title", { at: points.title, nr: 2, title: "straightWaistband" });
points.grainlineFrom = points.centerLeft.shiftFractionTowards(
points.topLeft,
0.5
);
points.grainlineTo = points.grainlineFrom.flipX();
macro("grainline", {
from: points.grainlineFrom,
to: points.grainlineTo
});
points.button = points.centerRight
.shiftFractionTowards(points.bottomRight, 0.5)
.shift(180, store.get("waistbandOverlap") / 2);
points.buttonhole = points.centerLeft
.shiftFractionTowards(points.bottomLeft, 0.5)
.shift(0, store.get("waistbandOverlap") / 2);
snippets.button = new Snippet("button", points.button);
snippets.buttonhole = new Snippet("buttonhole", points.buttonhole);
points.centerNotch = new Point(
(-1 * store.get("waistbandOverlap")) / 2,
points.bottomLeft.y
);
points.buttonNotch = points.bottomRight.shift(
180,
store.get("waistbandOverlap")
);
macro("sprinkle", {
snippet: "notch",
on: ["centerNotch", "buttonNotch", "bottomLeft"]
});
if (sa) paths.sa = paths.seam.offset(sa).attr("class", "fabric sa");
} }
// Paperless? // Paperless?