more documentation and cleanup
This commit is contained in:
parent
3962c61162
commit
f39b947717
10 changed files with 165 additions and 57 deletions
|
@ -17,9 +17,6 @@ function draftCarltonCollar({
|
||||||
Path,
|
Path,
|
||||||
part,
|
part,
|
||||||
addCut,
|
addCut,
|
||||||
setGrain,
|
|
||||||
setCutOnFold,
|
|
||||||
store,
|
|
||||||
}) {
|
}) {
|
||||||
// We're going to slash and spread this collar. Slashing first:
|
// We're going to slash and spread this collar. Slashing first:
|
||||||
// Divide top in 5 parts
|
// Divide top in 5 parts
|
||||||
|
|
|
@ -11,6 +11,7 @@ It is provided by the [title plugin](/reference/plugins/title).
|
||||||
macro('title', {
|
macro('title', {
|
||||||
Boolean append,
|
Boolean append,
|
||||||
Point at,
|
Point at,
|
||||||
|
Boolean cutlist
|
||||||
String nr,
|
String nr,
|
||||||
String prefix,
|
String prefix,
|
||||||
Number rotation,
|
Number rotation,
|
||||||
|
@ -50,11 +51,12 @@ macro('title', {
|
||||||
|
|
||||||
| Property | Default | Type | Description |
|
| Property | Default | Type | Description |
|
||||||
| ----------:| :-----: | ------------------- | ----------- |
|
| ----------:| :-----: | ------------------- | ----------- |
|
||||||
|
| `append` | `false` | Boolean | Set this to `true` to append the `nr` to any text already set in Point `at`'s attributes, rather than overwrite it |
|
||||||
| `at` | | [Point](/reference/api/point) | The point at which to insert the title |
|
| `at` | | [Point](/reference/api/point) | The point at which to insert the title |
|
||||||
|
| `cutlist` | `true` | Boolean | Whether to include cutting instructions |
|
||||||
| `nr` | | String | The number of the pattern part |
|
| `nr` | | String | The number of the pattern part |
|
||||||
| `title` | | String | The name of the pattern part. If title is not set or is an empty string, this won't be rendered, and the version will go beneath the nr.|
|
| `title` | | String | The name of the pattern part. If title is not set or is an empty string, this won't be rendered, and the version will go beneath the nr.|
|
||||||
| `prefix` | | String | A prefix to add to the created points. This allow for more than 1 title per part, as long as you give them a different prefix.|
|
| `prefix` | | String | A prefix to add to the created points. This allow for more than 1 title per part, as long as you give them a different prefix.|
|
||||||
| `append` | `false` | Boolean | Set this to `true` to append the `nr` to any text already set in Point `at`'s attributes, rather than overwrite it |
|
|
||||||
| `rotation` | 0 | Number | An optional rotation in degrees |
|
| `rotation` | 0 | Number | An optional rotation in degrees |
|
||||||
| `scale` | 1 | Number | An optional scaling factor |
|
| `scale` | 1 | Number | An optional scaling factor |
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ macro('title', {
|
||||||
|-------------------|-------------|
|
|-------------------|-------------|
|
||||||
| `points._${prefix}_titleNr` | Point anchoring the part number text |
|
| `points._${prefix}_titleNr` | Point anchoring the part number text |
|
||||||
| `points._${prefix}_titleName` | Point anchoring the part name text |
|
| `points._${prefix}_titleName` | Point anchoring the part name text |
|
||||||
|
| `points._${prefix}_titleCut_${material}_${i} | Points anchoring the cutting instructions, by material key and instruction index |
|
||||||
| `points._${prefix}_titlePattern` | Point anchoring the pattern name text |
|
| `points._${prefix}_titlePattern` | Point anchoring the pattern name text |
|
||||||
| `points._${prefix}_titleFor` | Point anchoring the name of the person for whom the pattern was made, if that information exists |
|
| `points._${prefix}_titleFor` | Point anchoring the name of the person for whom the pattern was made, if that information exists |
|
||||||
| `points._${prefix}_exportDate` | Point anchoring the pattern export date |
|
| `points._${prefix}_exportDate` | Point anchoring the pattern export date |
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
lmhCanvas: Light to Medium Hair Canvas
|
canvas: Canvas
|
||||||
fabric: Main Fabric
|
|
||||||
lining: Lining
|
|
||||||
cut: Cut
|
cut: Cut
|
||||||
paired: paired
|
fabric: Main Fabric
|
||||||
|
heavyCanvas: Heavy Canvas
|
||||||
|
interfacing: Interfacing
|
||||||
|
lining: Lining
|
||||||
|
lmhCanvas: Light to Medium Hair Canvas
|
||||||
|
mirrored: mirrored
|
||||||
onFoldLower: on the fold
|
onFoldLower: on the fold
|
||||||
onFoldAndBias: folded on the bias
|
onFoldAndBias: folded on the bias
|
||||||
onBias: on the bias
|
onBias: on the bias
|
||||||
|
plastic: Plastic
|
||||||
|
ribbing: Ribbing
|
||||||
|
|
|
@ -38,15 +38,20 @@ describe('Cutlist Plugin Tests', () => {
|
||||||
const Test = new Design({ parts: [part] })
|
const Test = new Design({ parts: [part] })
|
||||||
const pattern = new Test()
|
const pattern = new Test()
|
||||||
pattern.draft()
|
pattern.draft()
|
||||||
expect(pattern.setStores[0].cutlist.example_part.materials.fabric.cut).to.equal(2)
|
expect(pattern.setStores[0].cutlist.example_part.materials.fabric).to.have.lengthOf(1)
|
||||||
expect(pattern.setStores[0].cutlist.example_part.materials.fabric.identical).to.equal(false)
|
expect(pattern.setStores[0].cutlist.example_part.materials.fabric[0]).to.deep.equal({
|
||||||
|
cut: 2,
|
||||||
|
identical: false,
|
||||||
|
bias: false,
|
||||||
|
ignoreOnFold: false,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should handle addCut() with non-defaults', () => {
|
it('Should handle addCut() with non-defaults', () => {
|
||||||
const part = {
|
const part = {
|
||||||
name: 'example_part',
|
name: 'example_part',
|
||||||
draft: ({ addCut, part }) => {
|
draft: ({ addCut, part }) => {
|
||||||
addCut(3, 'lining', true)
|
addCut({ cut: 3, material: 'lining', identical: true })
|
||||||
|
|
||||||
return part
|
return part
|
||||||
},
|
},
|
||||||
|
@ -55,8 +60,13 @@ describe('Cutlist Plugin Tests', () => {
|
||||||
const Test = new Design({ parts: [part] })
|
const Test = new Design({ parts: [part] })
|
||||||
const pattern = new Test()
|
const pattern = new Test()
|
||||||
pattern.draft()
|
pattern.draft()
|
||||||
expect(pattern.setStores[0].cutlist.example_part.materials.lining.cut).to.equal(3)
|
expect(pattern.setStores[0].cutlist.example_part.materials.lining).to.have.lengthOf(1)
|
||||||
expect(pattern.setStores[0].cutlist.example_part.materials.lining.identical).to.equal(true)
|
expect(pattern.setStores[0].cutlist.example_part.materials.lining[0]).to.deep.equal({
|
||||||
|
cut: 3,
|
||||||
|
identical: true,
|
||||||
|
bias: false,
|
||||||
|
ignoreOnFold: false,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should remove cut info via addCut(false)', () => {
|
it('Should remove cut info via addCut(false)', () => {
|
||||||
|
@ -93,7 +103,7 @@ describe('Cutlist Plugin Tests', () => {
|
||||||
const pattern = new Test()
|
const pattern = new Test()
|
||||||
pattern.draft()
|
pattern.draft()
|
||||||
expect(typeof pattern.setStores[0].cutlist.example_part.materials.lining).to.equal('undefined')
|
expect(typeof pattern.setStores[0].cutlist.example_part.materials.lining).to.equal('undefined')
|
||||||
expect(pattern.setStores[0].cutlist.example_part.materials.fabric.cut).to.equal(2)
|
expect(pattern.setStores[0].cutlist.example_part.materials.fabric[0].cut).to.equal(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should remove cut info for all materials via removeCut(true)', () => {
|
it('Should remove cut info for all materials via removeCut(true)', () => {
|
||||||
|
|
|
@ -24,7 +24,7 @@ export const plugin = {
|
||||||
delete points.cutonfoldTo
|
delete points.cutonfoldTo
|
||||||
delete points.cutonfoldVia1
|
delete points.cutonfoldVia1
|
||||||
delete points.cutonfoldVia2
|
delete points.cutonfoldVia2
|
||||||
delete paths.cutonfold
|
delete paths.cutonfoldCutonfold
|
||||||
// setCutOnFold relies on plugin-cutlist
|
// setCutOnFold relies on plugin-cutlist
|
||||||
if (typeof setCutOnFold === 'function') {
|
if (typeof setCutOnFold === 'function') {
|
||||||
setCutOnFold(false) // Restore default
|
setCutOnFold(false) // Restore default
|
||||||
|
|
|
@ -31,7 +31,7 @@ export const plugin = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
macros: {
|
macros: {
|
||||||
title: function (so, { points, scale, locale, store, part, getCutOnFold }) {
|
title: function (so, { points, scale, locale, store, part }) {
|
||||||
const prefix = so.prefix || ''
|
const prefix = so.prefix || ''
|
||||||
let overwrite = !so.append
|
let overwrite = !so.append
|
||||||
|
|
||||||
|
@ -52,8 +52,10 @@ export const plugin = {
|
||||||
}
|
}
|
||||||
let shift = 8
|
let shift = 8
|
||||||
const nextPoint = (text, textClass, shiftAmt = shift) => {
|
const nextPoint = (text, textClass, shiftAmt = shift) => {
|
||||||
const newPoint = so.at.shift(-90 - so.rotation, shiftAmt * so.scale)
|
const newPoint = so.at
|
||||||
newPoint.attr('data-text-transform', transform(newPoint)).addText(text, textClass)
|
.shift(-90 - so.rotation, shiftAmt * so.scale)
|
||||||
|
.addText(text, textClass)
|
||||||
|
newPoint.attr('data-text-transform', transform(newPoint))
|
||||||
return newPoint
|
return newPoint
|
||||||
}
|
}
|
||||||
const defaults = {
|
const defaults = {
|
||||||
|
@ -76,18 +78,32 @@ export const plugin = {
|
||||||
shift += 8
|
shift += 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cut List instructions
|
||||||
const partCutlist = store.get(['cutlist', part.name])
|
const partCutlist = store.get(['cutlist', part.name])
|
||||||
|
// if there's a cutlist and it should be included
|
||||||
if (so.cutlist && partCutlist?.materials) {
|
if (so.cutlist && partCutlist?.materials) {
|
||||||
|
// get the default cutonfold
|
||||||
const cutonfold = partCutlist.cutOnFold
|
const cutonfold = partCutlist.cutOnFold
|
||||||
|
// each material
|
||||||
for (const material in partCutlist.materials) {
|
for (const material in partCutlist.materials) {
|
||||||
|
// each set of instructions
|
||||||
partCutlist.materials[material].forEach(({ cut, identical, bias, ignoreOnFold }, c) => {
|
partCutlist.materials[material].forEach(({ cut, identical, bias, ignoreOnFold }, c) => {
|
||||||
const cutPoint = nextPoint('plugin:cut', 'text-md fill-current')
|
// make a new point for this set of instructions
|
||||||
cutPoint.addText(cut)
|
const cutPoint = nextPoint('plugin:cut', 'text-md fill-current').addText(cut)
|
||||||
if (!identical && cut > 1) cutPoint.addText('plugin:paired')
|
|
||||||
|
// if they're not identical, add that to the point's text
|
||||||
|
if (!identical && cut > 1) cutPoint.addText('plugin:mirrored')
|
||||||
|
|
||||||
|
// if they should be cut on the fold add that, with bias or without
|
||||||
if (cutonfold && !ignoreOnFold)
|
if (cutonfold && !ignoreOnFold)
|
||||||
cutPoint.addText(bias ? 'plugin:onFoldAndBias' : 'plugin:onFoldLower')
|
cutPoint.addText(bias ? 'plugin:onFoldAndBias' : 'plugin:onFoldLower')
|
||||||
|
// otherwise if they should be on the bias, say so
|
||||||
else if (bias) cutPoint.addText('plugin:onBias')
|
else if (bias) cutPoint.addText('plugin:onBias')
|
||||||
|
|
||||||
|
// add 'from' the material
|
||||||
cutPoint.addText('plugin:from').addText('plugin:' + material)
|
cutPoint.addText('plugin:from').addText('plugin:' + material)
|
||||||
|
|
||||||
|
// save and shift
|
||||||
points[`_${prefix}_titleCut_${material}_${c}`] = cutPoint
|
points[`_${prefix}_titleCut_${material}_${c}`] = cutPoint
|
||||||
shift += 8
|
shift += 8
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { MainSections, ActiveSection } from './primary.mjs'
|
||||||
export const AsideNavigation = ({ app, slug, mobileOnly = false, before = [], after = [] }) => (
|
export const AsideNavigation = ({ app, slug, mobileOnly = false, before = [], after = [] }) => (
|
||||||
<aside
|
<aside
|
||||||
className={`
|
className={`
|
||||||
fixed top-0 right-0 h-screen w-screen
|
fixed top-0 right-0 h-screen
|
||||||
overflow-y-auto z-20
|
overflow-y-auto z-20
|
||||||
bg-base-100 text-base-content
|
bg-base-100 text-base-content
|
||||||
${app.primaryMenu ? '' : 'translate-x-[-120%]'} transition-transform
|
${app.primaryMenu ? '' : 'translate-x-[-120%]'} transition-transform
|
||||||
|
@ -13,7 +13,6 @@ export const AsideNavigation = ({ app, slug, mobileOnly = false, before = [], af
|
||||||
lg:justify-center
|
lg:justify-center
|
||||||
lg:border-r-2 lg:border-base-200 lg:bg-base-200 lg:bg-opacity-50
|
lg:border-r-2 lg:border-base-200 lg:bg-base-200 lg:bg-opacity-50
|
||||||
${mobileOnly ? 'block lg:hidden' : ''}
|
${mobileOnly ? 'block lg:hidden' : ''}
|
||||||
w-full
|
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const ExportDraft = ({ gist, design, app }) => {
|
||||||
const [error, setError] = useState(false)
|
const [error, setError] = useState(false)
|
||||||
const [format, setFormat] = useState(false)
|
const [format, setFormat] = useState(false)
|
||||||
|
|
||||||
const { t } = useTranslation(['app', , 'plugin'])
|
const { t } = useTranslation(['app', 'plugin'])
|
||||||
const doExport = (format) => {
|
const doExport = (format) => {
|
||||||
setLink(false)
|
setLink(false)
|
||||||
setError(false)
|
setError(false)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { fabricPlugin } from '../plugin-layout-part.mjs'
|
||||||
import { cutLayoutPlugin } from './plugin-cut-layout.mjs'
|
import { cutLayoutPlugin } from './plugin-cut-layout.mjs'
|
||||||
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
||||||
import { pluginFlip } from '@freesewing/plugin-flip'
|
import { pluginFlip } from '@freesewing/plugin-flip'
|
||||||
import { pluginI18n } from '@freesewing/plugin-i18n'
|
|
||||||
import { measurementAsMm } from 'shared/utils.mjs'
|
import { measurementAsMm } from 'shared/utils.mjs'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import get from 'lodash.get'
|
import get from 'lodash.get'
|
||||||
|
@ -23,7 +22,7 @@ const useFabricSettings = (gist) => {
|
||||||
return { activeFabric, sheetWidth, grainDirection, sheetHeight }
|
return { activeFabric, sheetWidth, grainDirection, sheetHeight }
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFabricDraft = (gist, design, fabricSettings, t) => {
|
const useFabricDraft = (gist, design, fabricSettings) => {
|
||||||
// get the appropriate layout for the view
|
// get the appropriate layout for the view
|
||||||
const layout =
|
const layout =
|
||||||
get(gist, ['layouts', gist._state.view, fabricSettings.activeFabric]) || gist.layout || true
|
get(gist, ['layouts', gist._state.view, fabricSettings.activeFabric]) || gist.layout || true
|
||||||
|
@ -44,8 +43,6 @@ const useFabricDraft = (gist, design, fabricSettings, t) => {
|
||||||
// also, pluginCutlist and pluginFlip are needed
|
// also, pluginCutlist and pluginFlip are needed
|
||||||
draft.use(pluginCutlist)
|
draft.use(pluginCutlist)
|
||||||
draft.use(pluginFlip)
|
draft.use(pluginFlip)
|
||||||
// add translation
|
|
||||||
// draft.use(pluginI18n, { t })
|
|
||||||
|
|
||||||
// draft the pattern
|
// draft the pattern
|
||||||
draft.draft()
|
draft.draft()
|
||||||
|
@ -80,7 +77,7 @@ export const CutLayout = (props) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const fabricSettings = useFabricSettings(gist)
|
const fabricSettings = useFabricSettings(gist)
|
||||||
const { draft, patternProps } = useFabricDraft(gist, design, fabricSettings, t)
|
const { draft, patternProps } = useFabricDraft(gist, design, fabricSettings)
|
||||||
const fabricList = useFabricList(draft)
|
const fabricList = useFabricList(draft)
|
||||||
|
|
||||||
const setCutFabric = (newFabric) => {
|
const setCutFabric = (newFabric) => {
|
||||||
|
|
|
@ -1,52 +1,71 @@
|
||||||
const prefix = 'mirroredOnFold'
|
const prefix = 'mirroredOnFold'
|
||||||
|
|
||||||
|
// types of path operations
|
||||||
const opTypes = ['to', 'cp1', 'cp2']
|
const opTypes = ['to', 'cp1', 'cp2']
|
||||||
const getRotationAngle = (grainAngle, partGrain) => {
|
|
||||||
let toRotate = Math.abs(grainAngle - partGrain)
|
/**
|
||||||
if (toRotate >= 180) toRotate -= 180
|
* The plugin to handle all business related to mirroring, rotating, and duplicating parts for the cutting layout
|
||||||
return toRotate
|
* @param {string} material the material to generate a cutting layout for
|
||||||
}
|
* @param {number} grainAngle the angle of the material's grain
|
||||||
|
* @return {Object} the plugin
|
||||||
|
*/
|
||||||
export const cutLayoutPlugin = function (material, grainAngle) {
|
export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
return {
|
return {
|
||||||
hooks: {
|
hooks: {
|
||||||
|
// after each part
|
||||||
postPartDraft: (pattern) => {
|
postPartDraft: (pattern) => {
|
||||||
|
// get the part that's just been drafted
|
||||||
const part = pattern.parts[pattern.activeSet][pattern.activePart]
|
const part = pattern.parts[pattern.activeSet][pattern.activePart]
|
||||||
|
// if it's a duplicated cut part, the fabric part, or it's hidden, leave it alone
|
||||||
if (pattern.activePart.startsWith('cut.') || pattern.activePart === 'fabric' || part.hidden)
|
if (pattern.activePart.startsWith('cut.') || pattern.activePart === 'fabric' || part.hidden)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// get this part's cutlist configuration
|
||||||
let partCutlist = pattern.setStores[pattern.activeSet].get(['cutlist', pattern.activePart])
|
let partCutlist = pattern.setStores[pattern.activeSet].get(['cutlist', pattern.activePart])
|
||||||
|
// if there isn't one, we're done here
|
||||||
if (!partCutlist) return
|
if (!partCutlist) return
|
||||||
|
|
||||||
|
// if the cutlist has materials but this isn't one of them
|
||||||
|
// or it has no materials but this isn't the main fabric
|
||||||
if (partCutlist.materials ? !partCutlist.materials[material] : material !== 'fabric') {
|
if (partCutlist.materials ? !partCutlist.materials[material] : material !== 'fabric') {
|
||||||
|
// hide the part because it shouldn't be shown on this fabric
|
||||||
part.hide()
|
part.hide()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFoldAndGrain = (macro, grainSpec, ignoreOnFold) => {
|
// get the cutlist configuration for this material
|
||||||
if (!ignoreOnFold && partCutlist.cutOnFold)
|
|
||||||
macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
|
|
||||||
|
|
||||||
if (grainSpec !== undefined) macro('rotateToGrain', { grainAngle, partGrain: grainSpec })
|
|
||||||
}
|
|
||||||
|
|
||||||
const matCutConfig = partCutlist.materials?.[material]
|
const matCutConfig = partCutlist.materials?.[material]
|
||||||
|
// if there's specific instructions for this material
|
||||||
if (matCutConfig) {
|
if (matCutConfig) {
|
||||||
const activePart = pattern.config.parts[pattern.activePart]
|
// get the config of the active part to be inherited by all duplicates
|
||||||
|
const activePartConfig = pattern.config.parts[pattern.activePart]
|
||||||
|
|
||||||
// hide the part so that all others can inherit from it and be manipulated separately
|
// hide the active part so that all others can inherit from it and be manipulated separately
|
||||||
part.hide()
|
part.hide()
|
||||||
|
|
||||||
|
// for each set of cutting instructions for this material
|
||||||
matCutConfig.forEach(({ cut, identical, bias, ignoreOnFold }, i) => {
|
matCutConfig.forEach(({ cut, identical, bias, ignoreOnFold }, i) => {
|
||||||
|
// get the grain angle for the part for this set of instructions
|
||||||
const cGrain = partCutlist.grain ? partCutlist.grain + (bias ? 45 : 0) : undefined
|
const cGrain = partCutlist.grain ? partCutlist.grain + (bias ? 45 : 0) : undefined
|
||||||
|
|
||||||
|
// for each piece that should be cut
|
||||||
for (let c = 0; c < cut; c++) {
|
for (let c = 0; c < cut; c++) {
|
||||||
const dupPartName = `cut.${pattern.activePart}.${material}_${c + i + 1}`
|
const dupPartName = `cut.${pattern.activePart}.${material}_${c + i + 1}`
|
||||||
|
|
||||||
|
// make a new part that will follow these cutting instructions
|
||||||
pattern.addPart({
|
pattern.addPart({
|
||||||
name: dupPartName,
|
name: dupPartName,
|
||||||
from: activePart,
|
from: activePartConfig,
|
||||||
draft: ({ part, macro }) => {
|
draft: ({ part, macro }) => {
|
||||||
handleFoldAndGrain(macro, cGrain, ignoreOnFold)
|
// handle fold and grain for these cutting instructions
|
||||||
|
macro('handleFoldAndGrain', {
|
||||||
|
partCutlist,
|
||||||
|
grainSpec: cGrain,
|
||||||
|
ignoreOnFold,
|
||||||
|
bias,
|
||||||
|
})
|
||||||
|
|
||||||
|
// if they shouldn't be identical, flip every other piece
|
||||||
if (!identical && c % 2 === 1) macro('flip')
|
if (!identical && c % 2 === 1) macro('flip')
|
||||||
|
|
||||||
return part
|
return part
|
||||||
|
@ -54,39 +73,72 @@ export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
}
|
||||||
|
// if there wasn't a specific configuration, still make sure to handle fold and grain
|
||||||
|
else {
|
||||||
const { macro } = part.shorthand()
|
const { macro } = part.shorthand()
|
||||||
handleFoldAndGrain(partCutlist.grain)
|
macro('handleFoldAndGrain', { partCutlist, grainSpec: partCutlist.grain })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
macros: {
|
macros: {
|
||||||
mirrorOnFold: ({ fold }, { paths, snippets, utils, macro, points }) => {
|
// handle mirroring on the fold and rotating to sit along the grain or bias
|
||||||
const mirrorPaths = []
|
handleFoldAndGrain: ({ partCutlist, grainSpec, ignoreOnFold, bias }, { points, macro }) => {
|
||||||
for (const p in paths) {
|
// if the part has cutonfold instructions
|
||||||
if (!paths[p].hidden && !p.startsWith(prefix)) mirrorPaths.push(paths[p])
|
if (partCutlist.cutOnFold) {
|
||||||
|
// if we're not meant to igore those instructions, mirror on the fold
|
||||||
|
if (!ignoreOnFold) macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
|
||||||
|
// if we are meant to ignore those instructions, but there's a grainline
|
||||||
|
else if (grainSpec !== undefined) {
|
||||||
|
// replace the cutonfold with a grainline
|
||||||
|
macro('grainline', { from: points.cutonfoldVia1, to: points.cutonfoldVia2 })
|
||||||
|
macro('cutonfold', false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there's a grain angle, rotate the part to be along it
|
||||||
|
if (grainSpec !== undefined)
|
||||||
|
macro('rotateToGrain', { grainAngle, bias, partGrain: grainSpec })
|
||||||
|
},
|
||||||
|
// mirror the part across the line indicated by cutonfold
|
||||||
|
mirrorOnFold: ({ fold }, { paths, snippets, utils, macro, points }) => {
|
||||||
|
// get all the paths to mirror
|
||||||
|
const mirrorPaths = []
|
||||||
|
for (const p in paths) {
|
||||||
|
// skip ones that are hidden
|
||||||
|
if (!paths[p].hidden) mirrorPaths.push(paths[p])
|
||||||
|
}
|
||||||
|
|
||||||
|
// store all the points to mirror
|
||||||
const mirrorPoints = []
|
const mirrorPoints = []
|
||||||
|
// store snippets by type so we can re-sprinkle later
|
||||||
const snippetsByType = {}
|
const snippetsByType = {}
|
||||||
|
// for each snippet
|
||||||
for (var s in snippets) {
|
for (var s in snippets) {
|
||||||
const snip = snippets[s]
|
const snip = snippets[s]
|
||||||
|
// don't mirror these ones
|
||||||
if (['logo'].indexOf(snip.def) > -1) continue
|
if (['logo'].indexOf(snip.def) > -1) continue
|
||||||
|
|
||||||
|
// get or make an array for this type of snippet
|
||||||
snippetsByType[snip.def] = snippetsByType[snip.def] || []
|
snippetsByType[snip.def] = snippetsByType[snip.def] || []
|
||||||
|
|
||||||
|
// put the anchor on the list to mirror
|
||||||
mirrorPoints.push(snip.anchor)
|
mirrorPoints.push(snip.anchor)
|
||||||
|
|
||||||
|
// then we have to find the name of that point so we can apply the snippet to its mirror
|
||||||
for (var pName in points) {
|
for (var pName in points) {
|
||||||
if (points[pName] === snip.anchor) {
|
if (points[pName] === snip.anchor) {
|
||||||
|
// add the name-to-be of the mirrored anchor to the list for resprinkling
|
||||||
snippetsByType[snip.def].push(prefix + utils.capitalize(pName))
|
snippetsByType[snip.def].push(prefix + utils.capitalize(pName))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mirror
|
||||||
let unnamed = 0
|
let unnamed = 0
|
||||||
macro('mirror', {
|
macro('mirror', {
|
||||||
paths: Object.values(mirrorPaths),
|
paths: mirrorPaths,
|
||||||
points: mirrorPoints,
|
points: mirrorPoints,
|
||||||
mirror: fold,
|
mirror: fold,
|
||||||
prefix,
|
prefix,
|
||||||
|
@ -96,6 +148,7 @@ export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// sprinkle the snippets
|
||||||
for (var def in snippetsByType) {
|
for (var def in snippetsByType) {
|
||||||
macro('sprinkle', {
|
macro('sprinkle', {
|
||||||
snippet: def,
|
snippet: def,
|
||||||
|
@ -103,34 +156,63 @@ export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rotateToGrain: ({ partGrain, grainAngle }, { paths, snippets, Point, points }) => {
|
/**
|
||||||
|
* rotate the part so that it is oriented properly with regard to the fabric grain
|
||||||
|
* if the part should be on the bias, this rotates the part to lie on the bias
|
||||||
|
* while keeping the grainline annotation along the grain
|
||||||
|
*/
|
||||||
|
rotateToGrain: ({ partGrain, grainAngle, bias }, { paths, snippets, Point, points }) => {
|
||||||
|
// if this part doesn't have a grain recorded, bail
|
||||||
if (partGrain === undefined) return
|
if (partGrain === undefined) return
|
||||||
|
|
||||||
const toRotate = getRotationAngle(grainAngle, partGrain)
|
// the amount to rotate is the difference between this part's grain angle (as drafted) and the fabric's grain angle
|
||||||
|
let toRotate = Math.abs(grainAngle - partGrain)
|
||||||
|
// don't over rotate
|
||||||
|
if (toRotate >= 180) toRotate -= 180
|
||||||
|
// if there's no difference, don't rotate
|
||||||
if (toRotate === 0) return
|
if (toRotate === 0) return
|
||||||
|
|
||||||
const pivot = new Point(0, 0)
|
// we'll pivot rotations along the grainline to point, with a fallback
|
||||||
|
const pivot = points.grainlineTo || new Point(0, 0)
|
||||||
|
|
||||||
|
// go through all the paths
|
||||||
for (const pathName in paths) {
|
for (const pathName in paths) {
|
||||||
const path = paths[pathName]
|
const path = paths[pathName]
|
||||||
|
// don't rotate hidden paths
|
||||||
if (paths[pathName].hidden) continue
|
if (paths[pathName].hidden) continue
|
||||||
|
|
||||||
|
// we want the grainline indicator to always go in the fabric grain direction
|
||||||
|
// so if this part is on the bias and this path is the grainline indicator
|
||||||
|
// we'll rotate it 45 degrees less than necessary
|
||||||
|
let thisRotation = toRotate
|
||||||
|
if (pathName === 'grainline' && bias) thisRotation -= 45
|
||||||
|
|
||||||
|
// replace all the points in all the ops of this path with ones that have been rotated
|
||||||
path.ops.forEach((op) => {
|
path.ops.forEach((op) => {
|
||||||
opTypes.forEach((t) => {
|
opTypes.forEach((t) => {
|
||||||
if (op[t]) op[t] = op[t].rotate(toRotate, pivot)
|
if (op[t]) op[t] = op[t].rotate(thisRotation, pivot)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace all snippet anchors with ones that have been rotated
|
||||||
for (const snippetName in snippets) {
|
for (const snippetName in snippets) {
|
||||||
snippets[snippetName].anchor = snippets[snippetName].anchor.rotate(toRotate, pivot)
|
snippets[snippetName].anchor = snippets[snippetName].anchor.rotate(toRotate, pivot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// go through all the points
|
||||||
for (const pointName in points) {
|
for (const pointName in points) {
|
||||||
const point = points[pointName]
|
const point = points[pointName]
|
||||||
const pointAttrs = point.attributes
|
const pointAttrs = point.attributes
|
||||||
|
// if it has attributes, we want to rotate it
|
||||||
if (Object.keys(pointAttrs.list).length) {
|
if (Object.keys(pointAttrs.list).length) {
|
||||||
points[pointName] = point.rotate(toRotate, pivot)
|
points[pointName] = point.rotate(toRotate, pivot)
|
||||||
|
|
||||||
|
// title points need to be re-rotated around the top title point to avoid text collisions
|
||||||
|
if (pointName.match(/_(title|exportDate)(?!Nr)/))
|
||||||
|
points[pointName] = points[pointName].rotate(-toRotate, points.__titleNr)
|
||||||
|
|
||||||
|
// put the attributes back onto the new point
|
||||||
points[pointName].attributes = pointAttrs.clone()
|
points[pointName].attributes = pointAttrs.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue