diff --git a/packages/holmes/README.md b/packages/holmes/README.md new file mode 100644 index 00000000000..7a1323f72f4 --- /dev/null +++ b/packages/holmes/README.md @@ -0,0 +1,31 @@ +# holmes + +> Sherlock Holmes hat + +[![NPM](https://img.shields.io/npm/v/holmes.svg)](https://www.npmjs.com/package/holmes) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + +## Install + +```bash +npm install --save holmes +``` + +## Usage + +```jsx +import React, { Component } from 'react' + +import MyComponent from 'holmes' + +class Example extends Component { + render () { + return ( + + ) + } +} +``` + +## License + + © [AlfaLyr](https://github.com/AlfaLyr) diff --git a/packages/holmes/config/index.js b/packages/holmes/config/index.js new file mode 100644 index 00000000000..20a4b558082 --- /dev/null +++ b/packages/holmes/config/index.js @@ -0,0 +1,38 @@ +import { version } from "../package.json"; + +// ?? 🤔 ?? --> https://en.freesewing.dev/packages/core/config + +export default { + name: "holmes", + version, + design: "AlfaLyr", + code: "AlfaLyr", + department: "accessories", + type: "pattern", + difficulty: 3, + tags: [ + "freesewing", + "design", + "diy", + "fashion", + "made to measure", + "parametric design", + "pattern", + "sewing", + "sewing pattern" + ], + optionGroups: { + style: ["lengthRatio", "goreNumber", "brimAngle", "brimWidth"] + }, + measurements: ["headCircumference"], + dependencies: {}, + inject: {}, + hide: [], + parts: ["gore", "brim", "ear"], + options: { + lengthRatio: { pct: 55, min: 40, max: 60 }, + goreNumber: { count: 6, min: 4, max: 20 }, + brimAngle: { deg: 45, min: 10, max:90 }, + brimWidth: { mm: 30, min: 5, max: 100 } + } +}; diff --git a/packages/holmes/drawings/brimangle.svg b/packages/holmes/drawings/brimangle.svg new file mode 100644 index 00000000000..447a436a21d --- /dev/null +++ b/packages/holmes/drawings/brimangle.svg @@ -0,0 +1,130 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/packages/holmes/drawings/brimwidth.svg b/packages/holmes/drawings/brimwidth.svg new file mode 100644 index 00000000000..6d388c64b96 --- /dev/null +++ b/packages/holmes/drawings/brimwidth.svg @@ -0,0 +1,130 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/packages/holmes/drawings/gorenumber.svg b/packages/holmes/drawings/gorenumber.svg new file mode 100644 index 00000000000..011befa3fa8 --- /dev/null +++ b/packages/holmes/drawings/gorenumber.svg @@ -0,0 +1,142 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/holmes/drawings/lengthratio.svg b/packages/holmes/drawings/lengthratio.svg new file mode 100644 index 00000000000..8290280e175 --- /dev/null +++ b/packages/holmes/drawings/lengthratio.svg @@ -0,0 +1,130 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/packages/holmes/drawings/linedrawing.svg b/packages/holmes/drawings/linedrawing.svg new file mode 100644 index 00000000000..f7ec886cb80 --- /dev/null +++ b/packages/holmes/drawings/linedrawing.svg @@ -0,0 +1,94 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/packages/holmes/example/README.md b/packages/holmes/example/README.md new file mode 100644 index 00000000000..0fd98a71fff --- /dev/null +++ b/packages/holmes/example/README.md @@ -0,0 +1,96 @@ +

+Freesewing logo +
+FreeSewing v2 +

+

A JavaScript library for made-to-measure sewing patterns

+

Follow @freesewing_org on Twitter + Chat with us on Gitter + Become a FreeSewing Patron + Follow @freesewing_org on Twitter + +

+ +# holmes example + +This project was bootstrapped with [Create Freesewing Pattern](https://en.freesewing.dev/create-freesewing-pattern): + +```js +npm init freesewing-pattern +``` + +This example folder is part of the local development environment. +It is **not** part of the pattern's source code. + +To run this example, follow these steps: + + - In the folder above this one, run: `yarn start` (or `npm start`) + - Then, in new terminal, run the same command in this folder: `yarn start` (or `npm start`) + +This will spin up the development environment, similar to [our online demo](https://holmes.freesewing.dev/). + +## About FreeSewing 🤔 + +Where the world of makers and developers collide, that's where you'll find FreeSewing. + +Our [core library](https://freesewing.dev/en/freesewing) is a *batteries-included* toolbox +for parametric design of sewing patterns. It's a modular system (check our list +of [plugins](https://freesewing.dev/en/plugins) and getting started is as simple as: + +```bash +npm init freesewing-pattern +``` + +The [getting started] section on [freesewing.dev](https://freesewing.dev/) is a good +entrypoint to our documentation, but you'll find a lot more there, including +our [API documentation](https://freesewing.dev/en/freesewing/api), +as well as [examples](https://freesewing.dev/en/freesewing/examples), +and [best practices](https://freesewing.dev/en/do). + +If you're a maker, checkout [freesewing.org](https://freesewing/) where you can generate +our sewing patterns adapted to your measurements. + +## Support FreeSewing: Become a patron 🥰 + +FreeSewing is an open source project run by a community, +and financially supported by our patrons. + +If you feel what we do is worthwhile, you too +should [become a patron](https://freesewing.org/patrons/join). + +## Links 👩‍💻 + + - 💻 Makers website: [freesewing.org](https://freesewing.org) + - 💻 Developers website: [freesewing.dev](https://freesewing.org) + - 💬 Chat: [gitter.im/freesewing](https://gitter.im/freesewing/freesewing) + - 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org) + - 📷 Instagram: [@freesewing_org](https://instagram.com/freesewing_org) + +## License: MIT 🤓 + +© [Joost De Cock](https://github.com/joostdecock). +See [the license file](https://github.com/freesewing/freesewing/blob/develop/LICENSE) for details. + +## Where to get help 🤯 + +Our [chatroom on Gitter](https://gitter.im) is the best place to ask questions, +share your feedback, or just hang out. + +If you want to report a problem, please [create an issue](https://github.com/freesewing/freesewing/issues/new). + diff --git a/packages/holmes/example/package.json b/packages/holmes/example/package.json new file mode 100644 index 00000000000..64bc5b4a24c --- /dev/null +++ b/packages/holmes/example/package.json @@ -0,0 +1,48 @@ +{ + "name": "holmes-example", + "homepage": "https://AlfaLyr.github.io/holmes", + "version": "0.0.0", + "private": true, + "dependencies": { + "@freesewing/components": "latest", + "@freesewing/core": "latest", + "@freesewing/css-theme": "latest", + "@freesewing/i18n": "latest", + "@freesewing/models": "latest", + "@freesewing/mui-theme": "latest", + "@freesewing/pattern-info": "latest", + "@freesewing/plugin-bundle": "latest", + "@freesewing/plugin-theme": "latest", + "@freesewing/plugin-i18n": "latest", + "@freesewing/plugin-svgattr": "latest", + "@freesewing/utils": "latest", + "@material-ui/core": "^4.4.0", + "@material-ui/icons": "^4.2.1", + "@material-ui/lab": "^v4.0.0-alpha.25", + "pattern": "file:..", + "prismjs": "1.17.1", + "react": "^16.9", + "react-dom": "^16.9", + "react-scripts": "^3.1.1", + "file-saver": "^2.0.2", + "typeface-roboto-condensed": "latest" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ], + "devDependencies": { + "babel-plugin-prismjs": "1.1.1" + } +} diff --git a/packages/holmes/example/public/favicon.ico b/packages/holmes/example/public/favicon.ico new file mode 100644 index 00000000000..95061a260f1 Binary files /dev/null and b/packages/holmes/example/public/favicon.ico differ diff --git a/packages/holmes/example/public/index.html b/packages/holmes/example/public/index.html new file mode 100644 index 00000000000..48b507bf0c7 --- /dev/null +++ b/packages/holmes/example/public/index.html @@ -0,0 +1,40 @@ + + + + + + + + + + + holmes + + + +
+ + + diff --git a/packages/holmes/example/public/manifest.json b/packages/holmes/example/public/manifest.json new file mode 100644 index 00000000000..bae8e9ac3f8 --- /dev/null +++ b/packages/holmes/example/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "holmes", + "name": "holmes", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/packages/holmes/example/src/App.js b/packages/holmes/example/src/App.js new file mode 100644 index 00000000000..b336f6f6cd1 --- /dev/null +++ b/packages/holmes/example/src/App.js @@ -0,0 +1,22 @@ +import React from 'react' +import freesewing from '@freesewing/core' +import Workbench from '@freesewing/components/Workbench' +import 'typeface-roboto-condensed' +import '@freesewing/css-theme' + +import Pattern from 'pattern' + +const App = props => { + let instance = new Pattern() + let config = instance.config + return ( + + ) +} + +export default App diff --git a/packages/holmes/example/src/App.test.js b/packages/holmes/example/src/App.test.js new file mode 100644 index 00000000000..4bf19359ea4 --- /dev/null +++ b/packages/holmes/example/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' + +it('renders without crashing', () => { + const div = document.createElement('div') + ReactDOM.render(, div) + ReactDOM.unmountComponentAtNode(div) +}) diff --git a/packages/holmes/example/src/index.js b/packages/holmes/example/src/index.js new file mode 100644 index 00000000000..9dd7ba788d4 --- /dev/null +++ b/packages/holmes/example/src/index.js @@ -0,0 +1,11 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' +import * as serviceWorker from './serviceWorker' + +ReactDOM.render(, document.getElementById('root')) + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: http://bit.ly/CRA-PWA +serviceWorker.unregister() diff --git a/packages/holmes/example/src/serviceWorker.js b/packages/holmes/example/src/serviceWorker.js new file mode 100644 index 00000000000..44e1b1b2f8c --- /dev/null +++ b/packages/holmes/example/src/serviceWorker.js @@ -0,0 +1,123 @@ +// In production, we register a service worker to serve assets from local cache. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on the "N+1" visit to a page, since previously +// cached resources are updated in the background. + +// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. +// This link also includes instructions on opting out of this behavior. + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) +) + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location) + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config) + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://goo.gl/SC7cgQ' + ) + }) + } else { + // Is not local host. Just register service worker + registerValidSW(swUrl, config) + } + }) + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the old content will have been purged and + // the fresh content will have been added to the cache. + // It's the perfect time to display a "New content is + // available; please refresh." message in your web app. + console.log('New content is available; please refresh.') + + // Execute callback + if (config.onUpdate) { + config.onUpdate(registration) + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.') + + // Execute callback + if (config.onSuccess) { + config.onSuccess(registration) + } + } + } + } + } + }) + .catch(error => { + console.error('Error during service worker registration:', error) + }) +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + if ( + response.status === 404 || + response.headers.get('content-type').indexOf('javascript') === -1 + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload() + }) + }) + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config) + } + }) + .catch(() => { + console.log('No internet connection found. App is running in offline mode.') + }) +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister() + }) + } +} diff --git a/packages/holmes/package.json b/packages/holmes/package.json new file mode 100644 index 00000000000..a9e262b574a --- /dev/null +++ b/packages/holmes/package.json @@ -0,0 +1,66 @@ +{ + "name": "holmes", + "version": "0.0.1", + "description": "Sherlock Holmes hat", + "author": "AlfaLyr", + "license": "MIT", + "repository": "AlfaLyr/holmes", + "main": "dist/index.js", + "module": "dist/index.es.js", + "jsnext:main": "dist/index.es.js", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "scripts": { + "test": "cross-env CI=1 react-scripts test --env=jsdom", + "test:watch": "react-scripts test --env=jsdom", + "build": "rollup -c", + "start": "rollup -c -w", + "prepare": "npm run build", + "predeploy": "cd example && npm install && npm run build", + "deploy": "gh-pages -d example/build" + }, + "devDependencies": { + "react": "^16.8", + "react-dom": "^16.8", + "@babel/plugin-proposal-class-properties": "^7.0.0", + "babel-eslint": "10.0.1", + "eslint": "^5.16.0", + "babel-jest": "24.7.1", + "jest": "24.7.1", + "@freesewing/core": "latest", + "@freesewing/plugin-bundle": "latest", + "@freesewing/components": "latest", + "@freesewing/css-theme": "latest", + "@freesewing/i18n": "latest", + "@freesewing/mui-theme": "latest", + "@freesewing/patterns": "latest", + "@freesewing/plugin-bust": "latest", + "@freesewing/plugin-buttons": "latest", + "@freesewing/plugin-debug": "latest", + "@freesewing/plugin-designer": "latest", + "@freesewing/plugin-flip": "latest", + "@freesewing/utils": "latest", + "@svgr/rollup": "^2.4.1", + "cross-env": "^5.1.4", + "gh-pages": "^1.2.0", + "react-scripts": "^3.0.1", + "webpack": "4.29.6", + "rollup": "^0.64.1", + "rollup-plugin-babel": "^4.0.1", + "rollup-plugin-babel-minify": "^7.0.0", + "rollup-plugin-commonjs": "^9.1.3", + "rollup-plugin-json": "^3.1.0", + "rollup-plugin-node-resolve": "^3.3.0", + "rollup-plugin-peer-deps-external": "^2.2.0", + "rollup-plugin-postcss": "^1.6.2", + "rollup-plugin-url": "^1.4.0", + "@material-ui/core": "^4.0.1", + "@material-ui/icons": "^4.0.1", + "@material-ui/lab": "^v4.0.0-alpha.14", + "react-intl": "2.8.0", + "prop-types": "15.7.2", + "file-saver": "^2.0.2" + } +} diff --git a/packages/holmes/rollup.config.js b/packages/holmes/rollup.config.js new file mode 100644 index 00000000000..70c428bd463 --- /dev/null +++ b/packages/holmes/rollup.config.js @@ -0,0 +1,47 @@ +import babel from "rollup-plugin-babel"; +import commonjs from "rollup-plugin-commonjs"; +import external from "rollup-plugin-peer-deps-external"; +import postcss from "rollup-plugin-postcss"; +import json from "rollup-plugin-json"; +import resolve from "rollup-plugin-node-resolve"; +import url from "rollup-plugin-url"; +import svgr from "@svgr/rollup"; +import minify from "rollup-plugin-babel-minify"; +import { name, version, description, author, license } from "./package.json"; + +import pkg from "./package.json"; + +export default { + input: "src/index.js", + output: [ + { + file: pkg.main, + format: "cjs", + sourcemap: true + }, + { + file: pkg.module, + format: "es", + sourcemap: true + } + ], + plugins: [ + external(), + postcss({ + modules: true + }), + url({ exclude: ["**/*.svg"] }), + svgr(), + babel({ + exclude: "node_modules/**" + }), + resolve({ browser: true }), + json(), + commonjs(), + minify({ + comments: false, + sourceMap: true, + banner: `/**\n * ${name} | v${version}\n * ${description}\n * (c) ${new Date().getFullYear()} ${author}\n * @license ${license}\n */` + }) + ] +}; diff --git a/packages/holmes/src/brim.js b/packages/holmes/src/brim.js new file mode 100644 index 00000000000..9ff8b36c396 --- /dev/null +++ b/packages/holmes/src/brim.js @@ -0,0 +1,72 @@ +export default function(part) { + let { + Point, + points, + Path, + paths, + measurements, + options, + complete, + sa, + snippets, + Snippet, + paperless, + macro + } = part.shorthand(); + +// Design pattern here + +let headRadius = measurements.headCircumference/2/Math.PI +let brimRadius = headRadius/Math.sin(options.brimAngle*Math.PI/180) +let sectorAngle = Math.PI/3 +let brimSectorAngle = sectorAngle * headRadius / brimRadius +let cpDistance = 4/3*brimRadius*(1-Math.cos(brimSectorAngle/2))/Math.sin(brimSectorAngle/2) + +points.origin = new Point(0, 0) +points.in1 = new Point(0, 0) +points.in2 = points.in1.shift(90/Math.PI*brimSectorAngle, 2*brimRadius*Math.sin(brimSectorAngle/2)) +points.in1C = points.in1.shift(0, cpDistance) +points.in2C = points.in2.shift(180+180/Math.PI*brimSectorAngle, cpDistance) +points.in1CFlipped = points.in1C.flipX() +points.in2Flipped = points.in2.flipX() +points.in2CFlipped = points.in2C.flipX() + +points.ex1 = points.in1.shift(-90, options.brimWidth) +points.ex1C = points.ex1.shift(0, 0.5*points.in2.x) +points.ex2C = points.in2.shift(-90, (points.ex1.y-points.in2.y)*(2/(1+Math.exp(-options.brimWidth/15))-1)) +points.ex1CFlipped = points.ex1C.flipX() +points.ex2CFlipped = points.ex2C.flipX() + +paths.seam = new Path() + .move(points.in2Flipped) + .curve(points.in2CFlipped, points.in1CFlipped, points.in1) + .curve(points.in1C, points.in2C, points.in2) + .curve(points.ex2C, points.ex1C, points.ex1) + .curve(points.ex1CFlipped, points.ex2CFlipped, points.in2Flipped) + .close() + + // Complete? + if (complete) { + macro('grainline', {from: points.in1, to: points.ex1}) + macro('title', { at: points.ex1.shift(45, 20), nr: 2, title: 'brim', scale: 0.4}) + + if (sa) { + paths.sa = paths.seam.offset(sa * -1).attr('class', 'fabric sa') + } + + // Paperless? + if (paperless) { + macro('hd', { + from: points.in2Flipped, + to: points.in2, + y: points.ex1.y + 15 + sa + }) + macro('vd', { + from: points.ex1, + to: points.in2Flipped, + x: points.in2Flipped.x - 15 - sa + }) + } + } + return part; +} diff --git a/packages/holmes/src/ear.js b/packages/holmes/src/ear.js new file mode 100644 index 00000000000..f95e437e86a --- /dev/null +++ b/packages/holmes/src/ear.js @@ -0,0 +1,62 @@ +export default function(part) { + let { + Point, + points, + Path, + paths, + measurements, + options, + complete, + sa, + snippets, + Snippet, + paperless, + macro + } = part.shorthand(); + +// Design pattern here + +points.top = new Point(0, 0) +points.bottom = new Point(measurements.headCircumference/12, options.lengthRatio*measurements.headCircumference/2) +points.topC = points.top.shift(0, points.bottom.x) +points.bottomC = points.bottom.shift(90, points.bottom.y-points.bottom.x) +points.topCFlipped = points.topC.flipX() +points.bottomFlipped = points.bottom.flipX() +points.bottomCFlipped = points.bottomC.flipX() + +paths.seam = new Path() + .move(points.top) + .curve(points.topCFlipped, points.bottomCFlipped, points.bottomFlipped) + .line(points.bottom) + .curve(points.bottomC, points.topC, points.top) + .close() + + // Complete? + if (complete) { + macro('grainline', {from: points.top, to: new Point(0, points.bottom.y)}) + points.logo = new Point(-0.5*points.bottom.x, 0.75*points.bottom.y) + snippets.logo = new Snippet("logo", points.logo) + .attr("data-scale", 0.7); + points.title = new Point(0.3*points.bottom.x, 0.75*points.bottom.y) + macro('title', { at: points.title, nr: 3, title: 'ear', scale: 0.5}) + + if (sa) { + paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa') + } + + // Paperless? + if (paperless) { + macro('hd', { + from: points.bottomFlipped, + to: points.bottom, + y: points.bottom.y + 15 + sa + }) + macro('vd', { + from: points.bottomFlipped, + to: points.top, + x: points.bottomFlipped.x - 15 - sa + }) + } + } + return part; +} diff --git a/packages/holmes/src/gore.js b/packages/holmes/src/gore.js new file mode 100644 index 00000000000..8ef6ad09069 --- /dev/null +++ b/packages/holmes/src/gore.js @@ -0,0 +1,77 @@ +export default function(part) { + let { + Point, + points, + Path, + paths, + measurements, + options, + macro, + complete, + sa, + snippets, + Snippet, + paperless + } = part.shorthand(); + +// Design pattern here + +//Radius of the head +let headRadius = measurements.headCircumference/2/Math.PI + +points.p0 = new Point(0, 0); + +macro("gore", { + from: points.p0, + radius: headRadius, + goreNumber: options.goreNumber, + extraLength: (options.lengthRatio-0.5)*measurements.headCircumference/2, + prefix: "gore_", + render: true +}); + + // Complete? + if (complete) { + points.title = new Point(points.gore_p1.x/10, points.gore_p2.y/1.8) + macro('title', { at: points.title, nr: 1, title: 'gore', scale: 0.5}) + + macro('cutonfold', { + from: points.p0, + to: points.gore_p1.shift(180, 20), + offset: -points.gore_p2.y/6, + grainline: true + }) + + if (sa) { + paths.saBase = new Path() + .move(points.gore_p1) + .curve(points.gore_Cp1, points.gore_Cp2, points.gore_p2) + .line(points.gore_p3) + .line(points.p0) + .offset(sa) + .setRender(false) + paths.sa = new Path() + .move(points.gore_p1) + .line(points.gore_p1.shift(0, sa)) + .line(paths.saBase.start()) + .join(paths.saBase) + .line(points.p0) + .attr('class', 'fabric sa') + } + + // Paperless? + if (paperless) { + macro('hd', { + from: points.p0, + to: points.gore_p1, + y: -points.p0.x + 15 + }) + macro('vd', { + from: points.p0, + to: points.gore_p3, + x: points.p0.x - 15 - sa + }) + } + } + return part; +} diff --git a/packages/holmes/src/index.js b/packages/holmes/src/index.js new file mode 100644 index 00000000000..c1610596cd7 --- /dev/null +++ b/packages/holmes/src/index.js @@ -0,0 +1,17 @@ +import freesewing from '@freesewing/core' +import plugins from '@freesewing/plugin-bundle' +import gore from './plugin-gore' +import config from '../config' +import draftGore from './gore' +import draftBrim from './brim' +import draftEar from './ear' + +// Create new design +const Pattern = new freesewing.Design(config, [plugins,gore]) + +// Attach the draft methods to the prototype +Pattern.prototype.draftGore = draftGore +Pattern.prototype.draftBrim = draftBrim +Pattern.prototype.draftEar = draftEar + +export default Pattern diff --git a/packages/holmes/src/plugin-gore.js b/packages/holmes/src/plugin-gore.js new file mode 100644 index 00000000000..1b0396709d2 --- /dev/null +++ b/packages/holmes/src/plugin-gore.js @@ -0,0 +1,63 @@ +import { name, version } from '../package.json' + +export default { + name: name, + version: version, + hooks: { + preRender: function(svg) { + if (svg.attributes.get('freesewing:plugin-gore') === false) + svg.attributes.set('freesewing:plugin-gore', version) + } + }, + macros: { + gore: function(so) { + let from = so.from + let goreNumber = so.goreNumber //number of gores for the complete sphere + let radius = so.radius //radius of the sphere + let prefix = so.prefix + let extraLength = so.extraLength //the length of the straight section after a complete semisphere + + this.points[prefix + 'p1'] = from.shift(0, radius*Math.PI/2 + extraLength) + this.points[prefix + 'Cp1'] = this.points[prefix + 'p1'].shift(180-180/goreNumber, radius/2/Math.cos(Math.PI/goreNumber)) + this.points[prefix + 'p3'] = from.shift(90, radius*Math.PI/goreNumber) + this.points[prefix + 'p2'] = this.points[prefix + 'p3'].shift(0, extraLength) + this.points[prefix + 'Cp2'] = this.points[prefix + 'p2'].shift(0, radius*(Math.PI-2)/2) + + if (extraLength < 0){ + //top curve used to calculate the new points if extraLength < 0 + this.paths.auxiliaryPath = new this.Path() + .move(this.points[prefix + "p1"]) + .curve( + this.points[prefix + 'Cp1'], + this.points[prefix + 'Cp2'], + this.points[prefix + 'p2'] + ) + .setRender(false) + + this.points[prefix + 'p2'] = this.paths.auxiliaryPath.intersectsX(0)[0] //the new point p2 is the one in which the auxiliary curve intersects x=0 + this.paths.auxiliaryPath = this.paths.auxiliaryPath.split(this.points[prefix + 'p2'])[0] //the auxiliary curve is split + this.points[prefix + 'Cp1'] = this.paths.auxiliaryPath.ops[1].cp1 //the new control points are those of the new curve + this.points[prefix + 'Cp2'] = this.paths.auxiliaryPath.ops[1].cp2 + this.points[prefix + 'p3'] = this.points[prefix + 'p2'].clone() + } + + //the seam path is generated + this.paths[prefix + 'seam'] = new this.Path() + .move(from) + .line(this.points[prefix + 'p1']) + .curve( + this.points[prefix + 'Cp1'], + this.points[prefix + 'Cp2'], + this.points[prefix + 'p2'] + ) + .line(this.points[prefix + "p3"]) + .line(from) + .close() + .attr('class', so.class ? so.class : '') + + if (typeof so.render !== 'undefined' && so.render) + this.paths[prefix + 'seam'].render = true + else this.paths[prefix + 'seam'].render = false + } + } +}