diff --git a/designs/hi/src/aboveMouth.js b/designs/hi/src/aboveMouth.js index c2f5637e9c2..de0bd2e50cd 100644 --- a/designs/hi/src/aboveMouth.js +++ b/designs/hi/src/aboveMouth.js @@ -1,5 +1,5 @@ export default function (part) { - let { + const { store, sa, Point, @@ -55,7 +55,7 @@ export default function (part) { aboveMouth01_02d = aboveMouth01_02d + diff aboveMouth01_04d = aboveMouth01_04d + diff iteration++ - } while ((diff < -1 || diff > 1) && iteration < 100) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) paths.seam = new Path() .move(points.aboveMouth01) diff --git a/designs/hi/src/belly.js b/designs/hi/src/belly.js index 2a2de84cffe..5ab1fa8d88a 100644 --- a/designs/hi/src/belly.js +++ b/designs/hi/src/belly.js @@ -102,7 +102,7 @@ export default function (part) { .move(points.belly01) .curve(points.belly01cp1, points.belly02cp2, points.belly02) .length() - } while ((diff < -1 || diff > 1) && iteration < 100) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) let bellyTailLength = store.get('bellyTailLength') @@ -122,7 +122,7 @@ export default function (part) { .move(points.belly03) .curve(points.belly03cp1, points.belly04cp2, points.belly04) .length() - } while ((diff < -1 || diff > 1) && iteration < 100) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) points.belly05cp1 = points.belly05cp2.flipY() points.belly06 = points.belly04.flipY() diff --git a/designs/hi/src/body.js b/designs/hi/src/body.js index be597f095d6..5b7206cf951 100644 --- a/designs/hi/src/body.js +++ b/designs/hi/src/body.js @@ -467,6 +467,9 @@ export default function (part) { new Path().move(points.body15).curve(points.body15cp1, points.body16cp2, points.body16).length() ) + // Reduce precision as size goes up coz performance + store.set('tolerance', (options.size < 1) ? 1 : options.size*100) + // Complete? if (complete) { points.bodyTailSnippet = new Path() diff --git a/designs/hi/src/bottomFin.js b/designs/hi/src/bottomFin.js index 15df6947468..3098c1cddef 100644 --- a/designs/hi/src/bottomFin.js +++ b/designs/hi/src/bottomFin.js @@ -58,8 +58,7 @@ export default function (part) { bottomFin01_03d = bottomFin01_03d + diff iteration++ - } while ((diff < -1 || diff > 1) && iteration < 100) - console.log({ iteration1: iteration }) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) diff = 0 iteration = 0 @@ -85,7 +84,7 @@ export default function (part) { bottomFin01_02d = bottomFin01_02d + diff iteration++ - } while ((diff < -1 || diff > 1) && iteration < 100) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) paths.seam = new Path() .move(points.bottomFin01) diff --git a/designs/hi/src/lowerTeeth.js b/designs/hi/src/lowerTeeth.js index d4155ba0292..1810fba3a69 100644 --- a/designs/hi/src/lowerTeeth.js +++ b/designs/hi/src/lowerTeeth.js @@ -1,7 +1,7 @@ import { createTeeth } from './teeth.js' export default function (part) { - let { + const { store, sa, Point, @@ -21,17 +21,23 @@ export default function (part) { let lowerTeeth01_02a = 25.414236606099728 + 180 let lowerTeeth02cp1d = 47.74891452755759 * options.size let lowerTeeth02cp1a = 42.59332849750379 - let lowerTeeth01cp2d = 17.774046078481962 * options.size + let lowerTeeth01cp2d = 27.774046078481962 * options.size let lowerTeeth01cp2a = 180 points.lowerTeeth01 = new Point(0, 0) points.lowerTeeth02 = points.lowerTeeth01.shift(lowerTeeth01_02a, lowerTeeth01_02d) points.lowerTeeth01cp2 = points.lowerTeeth01.shift(lowerTeeth01cp2a, lowerTeeth01cp2d) points.lowerTeeth02cp1 = points.lowerTeeth02.shift(lowerTeeth02cp1a, lowerTeeth02cp1d) + // Make seam symmetric to optimize generating teeth + points.lowerTeeth02cp1 = points.lowerTeeth02.shiftTowards( + points.lowerTeeth02cp1, + points.lowerTeeth01cp2.dist(points.lowerTeeth01) + ) points.lowerTeeth03 = points.lowerTeeth02.flipX() points.lowerTeeth01cp1 = points.lowerTeeth01cp2.flipX() points.lowerTeeth03cp2 = points.lowerTeeth02cp1.flipX() + paths.seam = new Path() .move(points.lowerTeeth02) .curve(points.lowerTeeth02cp1, points.lowerTeeth01cp2, points.lowerTeeth01) @@ -39,9 +45,17 @@ export default function (part) { store.set('lowerTeethLength', paths.seam.length()) - paths.teeth = new Path().move(paths.seam.start()) - - createTeeth(paths.seam, 16 * options.size, 8 * options.size, 10, options.aggressive, paths.teeth) + paths.teeth = createTeeth( + [ // Array holding the points for half a mouth (bezier, not path) + points.lowerTeeth02, // start + points.lowerTeeth02cp1, // cp1 + points.lowerTeeth01cp2, // cp2 + points.lowerTeeth01, // end + ], + 10, // number of teeth + 16, // size + part + ) // Complete? if (complete) { @@ -78,10 +92,8 @@ export default function (part) { noStartMarker: true, noEndMarker: true, }) - console.log({path:paths.teeth}) - console.log({point:paths.teeth.edge('top')}) macro('vd', { - from: points.lowerTeeth01, + from: points.lowerTeeth01, to: paths.teeth.edge('top'), x: points.lowerTeeth02.x - sa - 10, noStartMarker: true, diff --git a/designs/hi/src/teeth.js b/designs/hi/src/teeth.js index af50f6553f8..3da30a6ba7b 100644 --- a/designs/hi/src/teeth.js +++ b/designs/hi/src/teeth.js @@ -1,37 +1,93 @@ -export function createTeeth(path, largeTeeth, smallTeeth, numberOfTeeth, aggressive, newPath) { - let c = 0.55191502449351 +import { utils } from '@freesewing/core' +const { Bezier } = utils - let pLength = path.length() - let stepLength = pLength / numberOfTeeth +/* + * This method generates Hi's teeth. + * Growing teeth is not easy and it was making the pattern slow. + * So this method was optimized by @joostdeock to use the underlying + * Bezier object * rather than the higher-level path object + */ +export function createTeeth(pnts, toothCount, toothSize, part) { - let teethStep = (largeTeeth - smallTeeth) / (numberOfTeeth / 2 - 1) - let teethDirection = 1 + // Deconstruct what we need from the part via shorthand() + const { Path, points, Point, options } = part.shorthand() - let teethSize = smallTeeth - for (var i = 0; i < numberOfTeeth; i++) { - if (i == numberOfTeeth / 2) teethDirection = 0 - if (i > numberOfTeeth / 2) teethDirection = -1 + // These 4 points make up our cubic bezier curve which in turn is half of the mouth + const [ start, cp1, cp2, end ] = pnts - teethSize += teethStep * teethDirection - let startP = path.shiftAlong(stepLength * i) - let midP = path.shiftAlong(stepLength * (i + 0.5)) - let endP = path.shiftAlong(stepLength * (i + 1)) - let midPangle = midP.angle(path.shiftAlong(stepLength * (i + 0.5) + 0.1)) + 90 - midP = midP.shift(midPangle, teethSize) - let startPcp = startP.shift( - startP.angle(path.shiftAlong(stepLength * i + 0.1)) + 90, - teethSize * c - ) - let endPcp = endP.shift( - endP.angle(path.shiftAlong(stepLength * (i + 1) - 0.1)) - 90, - teethSize * c - ) - let midPcp1 = midP.shift(midPangle - 90, stepLength * c * (aggressive ? 0.05 : 0.7)) - let midPcp2 = midP.shift(midPangle + 90, stepLength * c * (aggressive ? 0.05 : 0.7)) + // Create the Bezier object from the 4 points + const halfMouth = new Bezier(...pnts) - newPath.curve(startPcp, midPcp2, midP) - newPath.curve(midPcp1, endPcp, endP) + // Center of the mouth + const center = pnts[3] + // Path that makes up the left half + const left = new Path().move(pnts[0]) + // Path that makes up the right half + const right = new Path().move(pnts[0].flipX(center)) + + // Get a lookup table (LUT) of points along the Bezier + const lut = halfMouth.getLUT(toothCount + 2) + + // Iterating over our LUT where p holds a number ID that we'll + // use to 'look back' to the other side of the tooth + for (const p in lut) { + + // Tooth size varies across the curve + const size = (toothSize*options.size) + (toothSize*options.size) * p/15 + + // Coordinates from the LUT + const { x, y } = lut[p] + // Create left half point at p + points[`leftTooth${p}`] = new Point(x, y) + // Mirror (flipX)to find right half point at p + points[`rightTooth${p}`] = points[`leftTooth${p}`].flipX(center) + + // This returns the normalized vector (nv) at p, + // in other words, the tangent + 90 degrees + const nv = halfMouth.normal(lut[p].t) + + // Create control points for left half at p + points[`leftTooth${p}Cp`] = new Point(x-size*nv.x, y-size*nv.y) + // Mirror (flipX) to find control points for right half at p + points[`rightTooth${p}Cp`] = points[`leftTooth${p}Cp`].flipX(center) + + // Skip the start point, the every 2 points, draw a teeth + // p = end of the tooth + // p - 2 = start of the tooth + if (p > 0 && p%2 === 0) { + if (options.aggressive) { + // For pointy tooth, find point between the two control points to form the tip + points[`leftTooth${p}Tip`] = points[`leftTooth${(p - 2)}Cp`].shiftFractionTowards(points[`leftTooth${(p)}Cp`], 0.5) + points[`rightTooth${p}Tip`] = points[`leftTooth${p}Tip`].flipX(center) + // Now draw tooth with shared control points for that pointy look + left.curve( + points[`leftTooth${(p)}Tip`], + points[`leftTooth${(p)}Tip`], + points[`leftTooth${p}`] + ) + // Do the same for the right half + right.curve( + points[`rightTooth${(p)}Tip`], + points[`rightTooth${(p)}Tip`], + points[`rightTooth${p}`] + ) + } else { + // Draw regular tooth in the left half + left.curve( + points[`leftTooth${(p - 2)}Cp`], + points[`leftTooth${p}Cp`], + points[`leftTooth${p}`] + ) + // Do the same for the right half + right.curve( + points[`rightTooth${(p - 2)}Cp`], + points[`rightTooth${p}Cp`], + points[`rightTooth${p}`] + ) + } + } } - return + // Return joined paths to get the full set of teeth + return left.join(right.reverse()) } diff --git a/designs/hi/src/topFin.js b/designs/hi/src/topFin.js index 560f3566423..b2b43068bf1 100644 --- a/designs/hi/src/topFin.js +++ b/designs/hi/src/topFin.js @@ -58,7 +58,7 @@ export default function (part) { topFinOpening = topFinOpening + diff iteration++ - } while ((diff < -1 || diff > 1) && iteration < 100) + } while (Math.abs(diff) > store.get('tolerance') && iteration < 100) paths.seam = new Path() .move(points.topFin01) @@ -140,7 +140,7 @@ export default function (part) { to: points.topFin01, x: points.topFinLeft.x -sa - 20, }) - } + } // if( options.size < 1.5 ) { // paths.smallTop.attr('data-text-class', 'text-xs') // paths.smallBottom.attr('data-text-class', 'text-xs') diff --git a/designs/hi/src/upperTeeth.js b/designs/hi/src/upperTeeth.js index 3de158b8919..2cde7a3cc11 100644 --- a/designs/hi/src/upperTeeth.js +++ b/designs/hi/src/upperTeeth.js @@ -19,15 +19,20 @@ export default function (part) { let upperTeeth01_02d = 131.305041182736 * options.size let upperTeeth01_02a = 34.147056946748805 + 180 - let upperTeeth02cp1d = 84.30113337316406 * options.size + let upperTeeth02cp1d = 64.30113337316406 * options.size let upperTeeth02cp1a = 55.1335930733262 - let upperTeeth01cp2d = 18.331000000000017 * options.size + let upperTeeth01cp2d = 48.331000000000017 * options.size let upperTeeth01cp2a = 180 points.upperTeeth01 = new Point(0, 0) points.upperTeeth02 = points.upperTeeth01.shift(upperTeeth01_02a, upperTeeth01_02d) points.upperTeeth01cp2 = points.upperTeeth01.shift(upperTeeth01cp2a, upperTeeth01cp2d) points.upperTeeth02cp1 = points.upperTeeth02.shift(upperTeeth02cp1a, upperTeeth02cp1d) + // Make seam symmetric to optimize generating teeth + points.upperTeeth02cp1 = points.upperTeeth02.shiftTowards( + points.upperTeeth02cp1, + points.upperTeeth01cp2.dist(points.upperTeeth01) + ) points.upperTeeth03 = points.upperTeeth02.flipX() points.upperTeeth01cp1 = points.upperTeeth01cp2.flipX() points.upperTeeth03cp2 = points.upperTeeth02cp1.flipX() @@ -39,9 +44,20 @@ export default function (part) { store.set('upperTeethLength', paths.seam.length()) - paths.teeth = new Path().move(paths.seam.start()) + //paths.teeth = new Path().move(paths.seam.start()) - createTeeth(paths.seam, 18 * options.size, 9 * options.size, 15, options.aggressive, paths.teeth) + paths.teeth = createTeeth( + [ // Array holding the points for half a mouth (bezier, not path) + points.upperTeeth02, // start + points.upperTeeth02cp1, // cp1 + points.upperTeeth01cp2, // cp2 + points.upperTeeth01, // end + ], + 14, // number of teeth + 14, // size + part + ) + //createTeeth(paths.seam, 18 * options.size, 9 * options.size, 15, options.aggressive, paths.teeth) // Complete? if (complete) { @@ -78,10 +94,8 @@ export default function (part) { noStartMarker: true, noEndMarker: true, }) - console.log({path:paths.teeth}) - console.log({point:paths.teeth.edge('top')}) macro('vd', { - from: points.upperTeeth01, + from: points.upperTeeth01, to: paths.teeth.edge('top'), x: points.upperTeeth02.x - sa - 10, noStartMarker: true,