├── .gitignore ├── docs ├── code │ ├── README.md │ ├── config.js │ ├── metric.md │ ├── hardware.md │ └── imperial.md ├── .vuepress │ ├── dist │ │ ├── assets │ │ │ ├── js │ │ │ │ ├── 9.e4b84b16.js │ │ │ │ ├── 5.13c5e1fd.js │ │ │ │ ├── 3.fe9e1b4e.js │ │ │ │ ├── 4.7d932259.js │ │ │ │ ├── 8.362e9d24.js │ │ │ │ ├── 7.02f8640a.js │ │ │ │ └── 6.4b3ce8a0.js │ │ │ ├── img │ │ │ │ └── search.83621669.svg │ │ │ └── css │ │ │ │ └── 0.styles.617c345f.css │ │ ├── 404.html │ │ └── code │ │ │ ├── index.html │ │ │ ├── metric.html │ │ │ ├── imperial.html │ │ │ └── hardware.html │ └── config.js └── README.md ├── githubdocs ├── _config.yml ├── bolt.png ├── imgs │ └── busy.gif ├── jscad-hardware.png ├── themes │ └── architect │ │ ├── images │ │ ├── body-bg.jpg │ │ ├── header-bg.jpg │ │ ├── sidebar-bg.jpg │ │ ├── github-button.png │ │ ├── download-button.png │ │ └── hr.png │ │ └── css │ │ └── style.css ├── themes.sh ├── layout.css ├── index.tmpl ├── jscad-function.js ├── index.html ├── jscad-worker.js └── formats.js ├── jscad.json ├── .vscode └── settings.json ├── test ├── snapshots │ ├── hardware.js.snap │ └── hardware.js.md ├── hardware.js └── helpers │ └── compat-env.js ├── examples ├── nut.jscad ├── washer.jscad ├── bolt.jscad └── example.jscad ├── .gitlab-ci.yml ├── src ├── index.js ├── v1compat.js ├── hardware.js ├── metric.js └── imperial.js ├── .eslintrc.json ├── v1 ├── metric.jscad ├── imperial.jscad └── jscad-hardware.jscad ├── README.md ├── jsdoc2md └── README.hbs ├── package.json └── gulpfile.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | public -------------------------------------------------------------------------------- /docs/code/README.md: -------------------------------------------------------------------------------- 1 | ### Welcome to API -------------------------------------------------------------------------------- /githubdocs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /jscad.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": ["dist/index.js"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "standard.enable": false 3 | } -------------------------------------------------------------------------------- /githubdocs/bolt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/bolt.png -------------------------------------------------------------------------------- /githubdocs/imgs/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/imgs/busy.gif -------------------------------------------------------------------------------- /githubdocs/jscad-hardware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/jscad-hardware.png -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/9.e4b84b16.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[9],{225:function(n,w,o){}}]); -------------------------------------------------------------------------------- /test/snapshots/hardware.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/test/snapshots/hardware.js.snap -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/themes/architect/images/body-bg.jpg -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/themes/architect/images/header-bg.jpg -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/themes/architect/images/sidebar-bg.jpg -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/themes/architect/images/github-button.png -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwebbcole/jscad-hardware/HEAD/githubdocs/themes/architect/images/download-button.png -------------------------------------------------------------------------------- /examples/nut.jscad: -------------------------------------------------------------------------------- 1 | function main() { 2 | util.init(CSG); 3 | var nut = Hardware.Nut(ImperialNuts['1/4 hex'], 'close').color('gray'); 4 | 5 | return nut; 6 | } 7 | 8 | // include:js 9 | // endinject 10 | -------------------------------------------------------------------------------- /examples/washer.jscad: -------------------------------------------------------------------------------- 1 | function main() { 2 | util.init(CSG); 3 | var washer = Hardware.Washer(ImperialWashers['1/4']); 4 | 5 | return washer.combine('washer'); 6 | } 7 | 8 | // include:js 9 | // endinject 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: node:lts-alpine 2 | 3 | pages: 4 | script: 5 | - npm ci 6 | - npm run docs 7 | - ls -al -R public 8 | artifacts: 9 | paths: 10 | - public 11 | only: 12 | - master 13 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/img/search.83621669.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JsCad Hardware es6 3 | */ 4 | import * as hardware from './hardware'; 5 | import * as imperial from './imperial'; 6 | import * as metric from './metric'; 7 | 8 | export { hardware, imperial, metric }; 9 | 10 | // export const Hardware = { 11 | // ...hardware, 12 | // ...imperial, 13 | // ...metric 14 | // }; 15 | -------------------------------------------------------------------------------- /docs/code/config.js: -------------------------------------------------------------------------------- 1 | exports.fileTree=[{"name":"hardware","path":"/hardware","fullPath":"./docs/code/hardware"},{"name":"imperial","path":"/imperial","fullPath":"./docs/code/imperial"},{"name":"metric","path":"/metric","fullPath":"./docs/code/metric"}];exports.sidebarTree = (title = 'Mainpage') => ({"/code/":[{"title":"API","collapsable":false,"children":[["",""+title+""],"hardware","imperial","metric"]}]}); -------------------------------------------------------------------------------- /examples/bolt.jscad: -------------------------------------------------------------------------------- 1 | function main() { 2 | util.init(CSG, { debug: '*' }); 3 | var bolt = Hardware.Bolt(util.inch(1), ImperialBolts['1/4 hex'], 'close'); 4 | var bolt2 = Hardware.Bolt( 5 | util.inch(1), 6 | MetricBolts['m8 socket'], 7 | 'close' 8 | ).snap('head', bolt.parts.head, 'x', 'outside+', -10); 9 | 10 | return [bolt.combine('head,thread'), bolt2.combine('head,thread')]; 11 | } 12 | 13 | // include:js 14 | // endinject 15 | -------------------------------------------------------------------------------- /test/snapshots/hardware.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/hardware.js` 2 | 3 | The actual snapshot is saved in `hardware.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## import util 8 | 9 | > Snapshot 1 10 | 11 | [ 12 | 'Bolt', 13 | 'Clearances', 14 | 'CreateScrew', 15 | 'FlatHeadScrew', 16 | 'HexHeadScrew', 17 | 'Nut', 18 | 'Orientation', 19 | 'PanHeadScrew', 20 | 'Screw', 21 | 'Washer', 22 | ] 23 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/5.13c5e1fd.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[5],{266:function(t,e,s){"use strict";s.r(e);var a=s(38),o=Object(a.a)({},function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("h3",{attrs:{id:"welcome-to-api"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#welcome-to-api","aria-hidden":"true"}},[this._v("#")]),this._v(" Welcome to API")])])},[],!1,null,null,null);e.default=o.exports}}]); -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/3.fe9e1b4e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[3],{239:function(t,e,n){},263:function(t,e,n){"use strict";var i=n(239);n.n(i).a},270:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(263),n(38)),a=Object(r.a)(i,void 0,void 0,!1,null,"c13ee5b0",null);e.default=a.exports}}]); -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/4.7d932259.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[4],{265:function(t,e,s){"use strict";s.r(e);var o=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],n={methods:{getMsg:function(){return o[Math.floor(Math.random()*o.length)]}}},i=s(38),h=Object(i.a)(n,function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("router-link",{attrs:{to:"/"}},[this._v("Take me home.")])],1)])},[],!1,null,null,null);e.default=h.exports}}]); -------------------------------------------------------------------------------- /test/hardware.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | // import { nearlyEqual } from './helpers/nearlyEqual'; 3 | import * as Hardware from '../src/hardware'; 4 | import { ImperialBolts } from '../src/imperial'; 5 | 6 | // import { util, init as utilInit } from '@jwc/jscad-utils'; 7 | // console.warn('utilInit', utilInit.default); 8 | 9 | test('import util', t => { 10 | // console.log( 11 | // Object.keys(util) 12 | // .map(k => `test.todo('${k}');`) 13 | // .join('\n') 14 | // ); 15 | 16 | t.snapshot(Object.keys(Hardware).sort()); 17 | }); 18 | 19 | // test('imperial bolt', t => { 20 | // // utilInit.default(CSG); 21 | // var bolt = Hardware.Bolt(util.inch(1), ImperialBolts['1/4 hex'], 'close'); 22 | // }); 23 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "globals": { 6 | "CSG": true, 7 | "CAG": true, 8 | "echo": true, 9 | "util": true, 10 | "include": true, 11 | "union": true, 12 | "Colors": true, 13 | "RaspberryPi": true, 14 | "Boxes": true, 15 | "Parts": true, 16 | "_": true, 17 | "vector_text": true, 18 | "rectangular_extrude": true, 19 | "_boardutils": true 20 | }, 21 | "extends": "eslint:recommended", 22 | "rules": { 23 | "no-console": [2, {"allow": ["warn", "error"]}], 24 | "linebreak-style": [ 25 | 2, 26 | "unix" 27 | ], 28 | "quotes": [ 29 | 2, 30 | "single" 31 | ], 32 | "semi": [ 33 | 2, 34 | "always" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/helpers/compat-env.js: -------------------------------------------------------------------------------- 1 | import jsCadCSG from '@jscad/csg'; 2 | import scadApi from '@jscad/scad-api'; 3 | const { CSG, CAG } = jsCadCSG; 4 | // console.warn('scadApi', scadApi); 5 | // import { init as utilInit } from '@jwc/jscad-utils'; 6 | import '@jwc/jscad-utils/dist/compat.js'; 7 | 8 | global.CSG = CSG; 9 | global.CAG = CAG; 10 | global.jsCadCSG = jsCadCSG; 11 | global.scadApi = scadApi; 12 | global.vector_text = scadApi.text.vector_text; 13 | global.vector_char = scadApi.text.vector_char; 14 | global.rectangular_extrude = scadApi.extrusions.rectangular_extrude; 15 | global.cube = scadApi.primitives3d.cube; 16 | global.sphere = scadApi.primitives3d.sphere; 17 | global.cylinder = scadApi.primitives3d.cylinder; 18 | 19 | global.union = scadApi.booleanOps.union; 20 | global.jscadUtilsDebug = { enabled: [], disabled: [] }; 21 | 22 | util.init(CSG); 23 | 24 | // console.warn('CSG', CSG); 25 | // console.warn('jscadUtils', util, util.init); 26 | -------------------------------------------------------------------------------- /githubdocs/themes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | rm -rf themes 5 | mkdir -p themes 6 | 7 | dl() { 8 | URL=https://pages-themes.github.io/$1/assets/css/style.css 9 | FILE=themes/$1/css/style.css 10 | 11 | mkdir -p themes/$1/css 12 | 13 | curl -Ss $URL -o $FILE && { 14 | echo "$1 ok" 15 | pushd themes/$1/css 16 | for url in `sed -n -e 's/.*url(\([^)]*\).*/\1/p' style.css`; do 17 | # echo "$(dirname $url)" 18 | ASSET=${url//\"} 19 | DIRNAME=$(dirname $ASSET) 20 | echo "downloading $ASSET into $DIRNAME" 21 | mkdir -p $DIRNAME 22 | curl -Ss https://pages-themes.github.io/$1/assets/css/$ASSET -o $ASSET 23 | done 24 | popd 25 | } || { 26 | echo "$1 error$?" 27 | } 28 | } 29 | 30 | dl architect 31 | # dl caymen 32 | # dl dinky 33 | # dl hacker 34 | # dl leap-day 35 | # dl merlot 36 | # dl midnight 37 | # dl minima 38 | # dl minimal 39 | # dl modernist 40 | # dl slate 41 | # dl tactile 42 | # dl time-machine 43 | -------------------------------------------------------------------------------- /src/v1compat.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var Hardware, 3 | ImperialBolts, 4 | ImperialNuts, 5 | ImperialWashers, 6 | ImperialWoodScrews, 7 | MetricBolts, 8 | MetricNuts, 9 | MetricWashers, 10 | MetricWoodScrews; 11 | function initJscadHardware() { 12 | var Debug = util.Debug; 13 | var debug = Debug('jscadHardware:initJscadHardware'); 14 | var jscadUtils = { util, Debug, parts: Parts, Group }; 15 | var jsCadCSG = { CSG, CAG }; 16 | debug('initJscadHardware:jscadUtils', jscadUtils); 17 | 18 | // include:compat 19 | // end:compat 20 | 21 | debug('jscadHardware', jscadHardware); 22 | Hardware = jscadHardware.hardware; 23 | 24 | ImperialBolts = jscadHardware.imperial.ImperialBolts; 25 | ImperialNuts = jscadHardware.imperial.ImperialNuts; 26 | ImperialWashers = jscadHardware.imperial.ImperialWashers; 27 | ImperialWoodScrews = jscadHardware.imperial.ImperialWoodScrews; 28 | 29 | MetricBolts = jscadHardware.metric.MetricBolts; 30 | MetricNuts = jscadHardware.metric.MetricNuts; 31 | MetricWashers = jscadHardware.metric.MetricWashers; 32 | MetricWoodScrews = jscadHardware.metric.MetricWoodScrews; 33 | } 34 | 35 | /** 36 | * Add `initJscadHardware` to the init queue for `util.init`. 37 | */ 38 | jscadUtilsPluginInit.push(initJscadHardware); 39 | /* eslint-enable */ 40 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | // auto generated sidebar 2 | const { fileTree } = require('../code/config'); 3 | console.log('foo', fileTree); 4 | module.exports = { 5 | base: process.env.CI ? '/jscad-hardware/' : '/', 6 | dest: 'public', 7 | locales: { 8 | '/': { 9 | title: 'JsCad Hardware', 10 | description: 'jscad parts library for screws, washers and nuts' 11 | } 12 | }, 13 | 14 | // plugins: [ 15 | // [ 16 | // '@vuepress/google-analytics', 17 | // { 18 | // ga: 'UA-135958052-3' 19 | // } 20 | // ] 21 | // ], 22 | 23 | themeConfig: { 24 | nav: [ 25 | { text: 'Home', link: '/' }, 26 | { text: 'API', link: '/code/' }, 27 | { text: 'GitLab', link: 'https://gitlab.com/johnwebbcole/jscad-hardware' } 28 | ], 29 | displayAllHeaders: true, 30 | editLinks: true, 31 | sidebarDepth: 3, 32 | docsDir: 'code', 33 | sidebar: [ 34 | ['/', 'Readme'], 35 | // { 36 | // title: 'Home', 37 | // path: '/', 38 | // collapsable: false, 39 | // children: [['/', 'Readme']] 40 | // }, 41 | { 42 | title: 'Code', 43 | path: '/code/', 44 | collapsable: false, 45 | children: fileTree.map(api => `/code${api.path}`) 46 | } 47 | ] 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | VuePress 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

404

That's a Four-Oh-Four.
Take me home.
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /v1/metric.jscad: -------------------------------------------------------------------------------- 1 | /* exported MetricBolts, MetricScrews, MetricNuts */ 2 | /** 3 | * http://www.atlrod.com/metric-hex-bolt-dimensions/ 4 | * E - Body Diameter (D) 5 | * F - Width Across Flats 6 | * G - Width Across Corners (C) 7 | * H - Head Height 8 | * D - Head Diameter 9 | * 10 | * tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 11 | * @type {Object} 12 | */ 13 | var MetricBolts = { 14 | 'm10 hex': { 15 | E: 10, // 10-9.78 16 | tap: 8.5, 17 | close: 10.5, 18 | loose: 11, 19 | H: 6.5, // 6.63-6.17 20 | G: 18, // 18.48-17.77 21 | F: 17, // 17-15.73 22 | type: 'HexHeadScrew' 23 | }, 24 | 'm12 hex': { 25 | E: 12, // 12-11.73 26 | tap: 10.3, 27 | close: 12.6, 28 | loose: 13.2, 29 | H: 7.5, // 7.76-4.24 30 | G: 20, // 20.78-20.03 31 | F: 19, // 19-17.73 32 | type: 'HexHeadScrew' 33 | } 34 | }; 35 | 36 | // headDiameter, headLength, diameter, tap, countersink 37 | var MetricScrews = { 38 | 'm4': [8, 3.1, 4] 39 | }; 40 | 41 | /** 42 | * Dimensions of nuts for imperial bolts. 43 | * F is the width across the faces, C is the width 44 | * across the points, and H is the height. D is the 45 | * basic diameter. 46 | * 47 | * [F, C, H, D] 48 | * 49 | * @see https://en.wikipedia.org/wiki/Nut_(hardware) 50 | * @type {Object} 51 | */ 52 | var MetricNuts = { 53 | 'm4': [7, 8.1, 3.2, 4] 54 | }; -------------------------------------------------------------------------------- /githubdocs/layout.css: -------------------------------------------------------------------------------- 1 | /* 2 | * layout.css for OpenJSCAD.org viewer 3 | */ 4 | 5 | body { 6 | display: flex; 7 | } 8 | 9 | .jscad-container { 10 | } 11 | 12 | #header { 13 | } 14 | 15 | #viewerContext { 16 | background: white; 17 | width: 480px; 18 | height: 340px; 19 | } 20 | 21 | #README { 22 | padding-left: 10px; 23 | flex: 1 1 auto; 24 | } 25 | 26 | canvas { 27 | margin: 0px; 28 | padding: 0px; 29 | 30 | width: 100%; 31 | height: 100%; 32 | 33 | cursor: move; 34 | } 35 | 36 | #parametersdiv { 37 | margin: 5px; /* not inherited */ 38 | border: thin solid rgb(200,200,200); 39 | border-radius: 1em; 40 | padding: 10px; 41 | 42 | background: white; 43 | opacity: 0.8; 44 | } 45 | 46 | #parametersdiv table { 47 | margin-bottom: 5px; 48 | 49 | text-align: left; 50 | font-size: 0.8em; 51 | font-weight: normal; 52 | } 53 | 54 | #parametersdiv th { 55 | margin: 0px; /* not inherited */ 56 | border: 0px none gray; /* not inherited */ 57 | padding: 5px; /* not inherited */ 58 | 59 | font-weight: bold; 60 | } 61 | 62 | #parametersdiv th.caption { 63 | text-decoration: underline; 64 | } 65 | 66 | #parametersdiv td.caption { 67 | text-align: right; 68 | font-weight: bold; 69 | } 70 | 71 | #parametersdiv td { 72 | margin: 0px; /* not inherited */ 73 | border: 0px none gray; /* not inherited */ 74 | padding: 0px; /* not inherited */ 75 | } 76 | 77 | #parametersdiv input, #parametersdiv textarea, #parametersdiv select { 78 | font-size: 0.9em; 79 | background: #fea; 80 | border: none; 81 | } 82 | 83 | #updateButton { 84 | margin: 5px; /* not inherited */ 85 | border: thin solid Black; /* not inherited */ 86 | padding: 2px; /* not inherited */ 87 | border-radius: 4px; 88 | background: white; 89 | 90 | margin-left: 1em; 91 | } 92 | 93 | #tail { 94 | margin: 5px; /* not inherited */ 95 | } 96 | 97 | #busy { 98 | vertical-align: middle; 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![view on npm](http://img.shields.io/npm/v/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) [![npm module downloads](http://img.shields.io/npm/dt/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) 2 | 3 | # jscad-hardware 4 | 5 | > https://johnwebbcole.github.io/jscad-hardware/ 6 | 7 | ![bplus example](docs/jscad-hardware.png) 8 | 9 | This is a collection of jscad parts that model a common Imperial and Metric bolts and washers. These models use the [jscad-utils](https://github.com/johnwebbcole/jscad-utils) library and return jscad-utils [`group` objects](https://github.com/johnwebbcole/jscad-utils#utilgroupnames-objects--object). 10 | 11 | 12 | ## Installation 13 | Install `jscad-hardware` using NPM: 14 | 15 | ```bash 16 | npm install --save jscad-hardware 17 | ``` 18 | 19 | ## Basic usage 20 | To use the utilities, you need to include the `jscad-hardware.jscad`. 21 | 22 | ```javascript 23 | include('node_modules/jscad-utils/jscad-utils.jscad'); 24 | include('node_modules/jscad-hardware/jscad-hardware.jscad'); 25 | 26 | main() { 27 | util.init(CSG); 28 | 29 | var bolt = Hardware.Bolt( 30 | util.inch(1), 31 | ImperialBolts['5/16 hex'], 32 | 'close' 33 | ) 34 | 35 | return bolt.combine('head,thread'); 36 | } 37 | ``` 38 | 39 | ## Yeoman Generator 40 | You can use the [yeoman jscad generator](https://www.npmjs.com/package/generator-jscad) which will create a project that uses this library. 41 | 42 | Once you create your project, install `jscad-hardware`, and run `gulp`. Dragging the `dist` directory into [http://openjscad.org/](http://openjscad.org/) will include this library. 43 | 44 | Modify your `main.jscad` file to return a bolt object. 45 | 46 | ```javascript 47 | function main() { 48 | util.init(CSG); 49 | 50 | var bolt = Hardware.Bolt( 51 | util.inch(1), 52 | ImperialBolts['5/16 hex'], 53 | 'close' 54 | ) 55 | 56 | return bolt.combine('head,thread'); 57 | } 58 | 59 | // include:js 60 | // endinject 61 | ``` 62 | 63 | ![bplus example](docs/bolt.png) 64 | -------------------------------------------------------------------------------- /jsdoc2md/README.hbs: -------------------------------------------------------------------------------- 1 | [![view on npm](http://img.shields.io/npm/v/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) [![npm module downloads](http://img.shields.io/npm/dt/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) 2 | 3 | # jscad-hardware 4 | 5 | > https://johnwebbcole.github.io/jscad-hardware/ 6 | 7 | ![bplus example](docs/jscad-hardware.png) 8 | 9 | This is a collection of jscad parts that model a common Imperial and Metric bolts and washers. These models use the [jscad-utils](https://github.com/johnwebbcole/jscad-utils) library and return jscad-utils [`group` objects](https://github.com/johnwebbcole/jscad-utils#utilgroupnames-objects--object). 10 | 11 | 12 | ## Installation 13 | Install `jscad-hardware` using NPM: 14 | 15 | ```bash 16 | npm install --save jscad-hardware 17 | ``` 18 | 19 | ## Basic usage 20 | To use the utilities, you need to include the `jscad-hardware.jscad`. 21 | 22 | ```javascript 23 | include('node_modules/jscad-utils/jscad-utils.jscad'); 24 | include('node_modules/jscad-hardware/jscad-hardware.jscad'); 25 | 26 | main() { 27 | util.init(CSG); 28 | 29 | var bolt = Hardware.Bolt( 30 | util.inch(1), 31 | ImperialBolts['5/16 hex'], 32 | 'close' 33 | ) 34 | 35 | return bolt.combine('head,thread'); 36 | } 37 | ``` 38 | 39 | ## Yeoman Generator 40 | You can use the [yeoman jscad generator](https://www.npmjs.com/package/generator-jscad) which will create a project that uses this library. 41 | 42 | Once you create your project, install `jscad-hardware`, and run `gulp`. Dragging the `dist` directory into [http://openjscad.org/](http://openjscad.org/) will include this library. 43 | 44 | Modify your `main.jscad` file to return a bolt object. 45 | 46 | ```javascript 47 | function main() { 48 | util.init(CSG); 49 | 50 | var bolt = Hardware.Bolt( 51 | util.inch(1), 52 | ImperialBolts['5/16 hex'], 53 | 'close' 54 | ) 55 | 56 | return bolt.combine('head,thread'); 57 | } 58 | 59 | // include:js 60 | // endinject 61 | ``` 62 | 63 | ![bplus example](docs/bolt.png) 64 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [![view on npm](http://img.shields.io/npm/v/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) [![npm module downloads](http://img.shields.io/npm/dt/jscad-hardware.svg)](https://www.npmjs.org/package/jscad-hardware) 2 | 3 | # jscad-hardware 4 | 5 | > https://johnwebbcole.github.io/jscad-hardware/ 6 | 7 | ![bplus example](docs/jscad-hardware.png) 8 | 9 | This is a collection of jscad parts that model a common Imperial and Metric bolts and washers. These models use the [jscad-utils](https://github.com/johnwebbcole/jscad-utils) library and return jscad-utils [`group` objects](https://github.com/johnwebbcole/jscad-utils#utilgroupnames-objects--object). 10 | 11 | ## Installation 12 | 13 | Install `jscad-hardware` using NPM: 14 | 15 | ```bash 16 | npm install --save @jwc/jscad-hardware 17 | ``` 18 | 19 | ## Basic usage 20 | 21 | > Note: these instrucitons are for version 1. 22 | 23 | To use the utilities, you need to include the `jscad-hardware.jscad`. 24 | 25 | ```javascript 26 | include('node_modules/jscad-utils/jscad-utils.jscad'); 27 | include('node_modules/jscad-hardware/jscad-hardware.jscad'); 28 | 29 | main() { 30 | util.init(CSG); 31 | 32 | var bolt = Hardware.Bolt( 33 | util.inch(1), 34 | ImperialBolts['5/16 hex'], 35 | 'close' 36 | ) 37 | 38 | return bolt.combine('head,thread'); 39 | } 40 | ``` 41 | 42 | ## Yeoman Generator 43 | 44 | You can use the [yeoman jscad generator](https://www.npmjs.com/package/generator-jscad) which will create a project that uses this library. 45 | 46 | Once you create your project, install `jscad-hardware`, and run `gulp`. Dragging the `dist` directory into [http://openjscad.org/](http://openjscad.org/) will include this library. 47 | 48 | Modify your `main.jscad` file to return a bolt object. 49 | 50 | ```javascript 51 | function main() { 52 | util.init(CSG); 53 | 54 | var bolt = Hardware.Bolt(util.inch(1), ImperialBolts["5/16 hex"], "close"); 55 | 56 | return bolt.combine("head,thread"); 57 | } 58 | 59 | // include:js 60 | // endinject 61 | ``` 62 | 63 | ![bplus example](docs/bolt.png) 64 | -------------------------------------------------------------------------------- /examples/example.jscad: -------------------------------------------------------------------------------- 1 | function main() { 2 | util.init(CSG); 3 | 4 | var ibolts = makeSet(makeBolt, ImperialBolts); 5 | var iwood = makeSet(makeWoodScrew, ImperialWoodScrews); 6 | var mbolts = makeSet(makeBolt, MetricBolts); 7 | var iwasher = makeSet(makeWasher, ImperialWashers); 8 | 9 | return [ 10 | union(ibolts) 11 | .center('x') 12 | .translate([0, -50, 0]), 13 | union(iwood) 14 | .center('x') 15 | .translate([0, -25, 0]), 16 | union(mbolts) 17 | .center('x') 18 | .translate([0, 0, 0]), 19 | union(iwasher) 20 | .center('x') 21 | .translate([0, 50, 0]) 22 | ]; 23 | } 24 | 25 | function makeWasher(washer) { 26 | return Hardware.Washer(washer).combine('washer'); 27 | } 28 | 29 | function makeBolt(bolt) { 30 | return Hardware.Bolt(util.inch(1), bolt).combine('head,thread'); 31 | } 32 | 33 | function makeWoodScrew(args) { 34 | [h, l, d] = args; 35 | return Hardware.FlatHeadScrew(h, l, d, util.inch(1)).combine(); 36 | } 37 | 38 | function makeSet(maker, set, offset, width) { 39 | var g = util.group(); 40 | Object.keys(set) 41 | .sort(function(a, b) { 42 | return (set[a].E || set[a].od) > (set[b].E || set[b].od) ? 1 : -1; 43 | }) 44 | .slice(0, 10) 45 | .forEach(function(key, idx) { 46 | var item = maker(set[key]); 47 | if (idx == 0) { 48 | g.add(item.translate([0, 0, 0]), key); 49 | } else { 50 | var gsize = util.size(g.combine()); 51 | var isize = util.size(item); 52 | g.add(item.translate([gsize.x + isize.x / 2, 0, 0]), key); 53 | } 54 | // var gsize = util.size(g.combine()); 55 | // g.translate([gsize.x, 0, 0]); 56 | 57 | // var label = util 58 | // .label(key) 59 | // .fit([width - 5, 10, 10], true) 60 | // .rotateX(90) 61 | // .rotateZ(180) 62 | // .snap(item, 'z', 'outside-') 63 | // .align(item, 'xy') 64 | // .translate([0,0,5]); 65 | 66 | // return item.translate([width * idx, offset, 0]); 67 | }); 68 | 69 | return g.combine(); 70 | } 71 | 72 | // include:js 73 | // endinject 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jwc/jscad-hardware", 3 | "version": "2.0.2", 4 | "description": "jscad parts library for screws, washers and nuts", 5 | "main": "jscad-hardware.jscad", 6 | "scripts": { 7 | "test": "ava", 8 | "build": "gulp all", 9 | "start": "gulp", 10 | "docs": "vuepress-jsdoc --source ./src --dist ./docs && npx vuepress build ./docs" 11 | }, 12 | "keywords": [ 13 | "jscad", 14 | "hardware" 15 | ], 16 | "author": { 17 | "name": "John Cole", 18 | "email": "johnwebbcole@gmail.com", 19 | "url": "http://github.com/johnwebbcole@gmail.com" 20 | }, 21 | "homepage": "https://github.com/johnwebbcole/jscad-hardware", 22 | "bugs": "https://github.com/johnwebbcole/jscad-hardware/issues", 23 | "repository": { 24 | "type": "git", 25 | "url": "git://github.com/johnwebbcole/jscad-hardware.git" 26 | }, 27 | "license": "ISC", 28 | "devDependencies": { 29 | "@babel/core": "^7.5.5", 30 | "@babel/preset-env": "^7.5.5", 31 | "@babel/register": "^7.5.5", 32 | "@vuepress/plugin-active-header-links": "^1.0.3", 33 | "@vuepress/plugin-google-analytics": "^1.0.3", 34 | "ava": "^2.3.0", 35 | "del": "^5.0.0", 36 | "esm": "^3.2.25", 37 | "gulp": "^4.0.2", 38 | "gulp-concat": "^2.6.0", 39 | "gulp-debug": "^4.0.0", 40 | "gulp-eslint": "^6.0.0", 41 | "gulp-inject": "^5.0.4", 42 | "gulp-jscad-files": "^3.0.1", 43 | "gulp-jsdoc-to-markdown": "^1.2.1", 44 | "gulp-merge": "^0.1.1", 45 | "gulp-plumber": "^1.2.1", 46 | "gulp-terser": "^1.2.0", 47 | "gulp-util": "^3.0.7", 48 | "gulp-watch": "^5.0.1", 49 | "rollup": "^1.19.4", 50 | "rollup-plugin-babel": "^4.3.3", 51 | "rollup-plugin-node-resolve": "^5.2.0", 52 | "vuepress-jsdoc": "^1.8.1" 53 | }, 54 | "dependencies": { 55 | "@jscad/csg": "^0.7.0", 56 | "@jscad/scad-api": "^0.5.1", 57 | "@jwc/jscad-utils": "^4.2.1" 58 | }, 59 | "ava": { 60 | "files": [ 61 | "test/**/*.js", 62 | "!test/helpers/**/*.js" 63 | ], 64 | "sources": [ 65 | "src/**/*.js" 66 | ], 67 | "require": [ 68 | "esm", 69 | "@babel/register", 70 | "babel-polyfill", 71 | "./test/helpers/compat-env.js" 72 | ] 73 | }, 74 | "babel": { 75 | "presets": [ 76 | "@babel/preset-env" 77 | ] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /githubdocs/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= title %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <%= theme %> 21 | 22 | 23 | 24 | 25 |
26 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 | <%= readme %> 46 |
47 | 48 | 49 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/code/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Welcome to API 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

Welcome to API

15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /githubdocs/jscad-function.js: -------------------------------------------------------------------------------- 1 | // jscad-function.js 2 | // 3 | // == OpenJSCAD.org, Copyright (c) 2013-2016, Licensed under MIT License 4 | // 5 | // History: 6 | // 2016/02/02: 0.4.0: GUI refactored, functionality split up into more files, mostly done by Z3 Dev 7 | 8 | // Create an function for processing the JSCAD script into CSG/CAG objects 9 | // 10 | // fullurl - URL to original script 11 | // script - FULL script with all possible support routines, etc 12 | // callback - function to call, returning results or errors 13 | // 14 | // This function creates an anonymous Function, which is invoked to execute the thread. 15 | // The function executes in the GLOBAL context, so all necessary parameters are provided. 16 | // 17 | OpenJsCad.createJscadFunction = function(fullurl, script, callback) { 18 | //console.log("createJscadFunction()"); 19 | 20 | // determine the relative base path for include() 21 | var relpath = fullurl; 22 | if (relpath.lastIndexOf('/') >= 0) { 23 | relpath = relpath.substring(0,relpath.lastIndexOf('/')+1); 24 | } 25 | 26 | var source = "// SYNC WORKER\n"; 27 | source += ' var relpath = "'+relpath+'";\n' 28 | source += ' var include = includeJscadSync;\n'; 29 | source += '\n'; 30 | source += includeJscadSync.toString()+'\n'; 31 | source += '\n'; 32 | source += script+'\n'; 33 | source += '\n'; 34 | source += "return main(params);\n"; 35 | 36 | //console.log("SOURCE: "+source); 37 | 38 | var f = new Function("params", source); 39 | return f; 40 | }; 41 | 42 | // 43 | // THESE FUNCTIONS ARE SERIALIZED FOR INCLUSION IN THE FULL SCRIPT 44 | // 45 | // TODO It might be possible to cache the serialized versions 46 | // 47 | 48 | // Include the requested script via MemFs (if available) or HTTP Request 49 | // 50 | // (Note: This function is appended together with the JSCAD script) 51 | // 52 | function includeJscadSync(fn) { 53 | // include the requested script via MemFs if possible 54 | if (typeof(gMemFs) == 'object') { 55 | for(var fs in gMemFs) { 56 | if (gMemFs[fs].name == fn) { 57 | eval(gMemFs[fs].source); 58 | return; 59 | } 60 | } 61 | } 62 | // include the requested script via webserver access 63 | var xhr = new XMLHttpRequest(); 64 | var url = relpath+fn; 65 | if (fn.match(/^(https:|http:)/i)) { 66 | url = fn; 67 | } 68 | xhr.open('GET',url,false); 69 | xhr.onload = function() { 70 | var src = this.responseText; 71 | eval(src); 72 | }; 73 | xhr.onerror = function() { 74 | }; 75 | xhr.send(); 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /v1/imperial.jscad: -------------------------------------------------------------------------------- 1 | /* exported ImperialBolts, ImperialWashers */ 2 | /** 3 | * http://www.americanfastener.com/cap-screws/ 4 | * E - Body Diameter 5 | * F - Width Across Flats 6 | * G - Width Across Corners 7 | * H - Head Height 8 | * D - Head Diameter 9 | * 10 | * tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 11 | * @type {Object} 12 | */ 13 | ImperialBolts = { 14 | '1/4 hex': { 15 | name: '1/4 hex', 16 | E: util.inch(0.25), 17 | tap: util.inch(0.201), 18 | close: util.inch(0.257), 19 | loose: util.inch(0.266), 20 | H: util.inch(5 / 32), 21 | G: util.inch(0.505), 22 | F: util.inch(7 / 16), 23 | type: 'HexHeadScrew' 24 | }, 25 | '1/4 socket': { 26 | name: '1/4 socket', 27 | E: util.inch(0.25), 28 | tap: util.inch(0.201), 29 | close: util.inch(0.257), 30 | loose: util.inch(0.266), 31 | H: util.inch(0.25), 32 | D: util.inch(0.375), 33 | type: 'PanHeadScrew' 34 | }, 35 | '5/16 hex': { 36 | name: '5/16 hex', 37 | E: util.inch(0.3125), 38 | tap: util.inch(0.257), 39 | close: util.inch(0.323), 40 | loose: util.inch(0.332), 41 | H: util.inch(0.203125), 42 | G: util.inch(0.577), // 0.577-0.557 43 | F: util.inch(0.5), 44 | type: 'HexHeadScrew' 45 | } 46 | }; 47 | 48 | /** 49 | * Imperial washer sizes 50 | * 51 | * @see http://almabolt.com/pages/catalog/washers/fender.htm 52 | * @type {Object} 53 | */ 54 | var ImperialWashers = { 55 | '1/4': { 56 | od: util.inch(0.734), 57 | id: util.inch(0.312), 58 | thickness: util.inch(0.08) // .051/.080 59 | }, 60 | '1/4 fender': { 61 | od: util.inch(1.25), 62 | id: util.inch(0.28125), 63 | thickness: util.inch(0.08) // .051/.080 64 | }, 65 | '5/16': { 66 | od: util.inch(1.25), 67 | id: util.inch(0.34375), 68 | thickness: util.inch(0.08) // .051/.080 69 | } 70 | }; 71 | 72 | // headDiameter, headLength, diameter, tap, countersink 73 | var ImperialWoodScrews = { 74 | '#4': [util.inch(0.225), util.inch(0.067), util.inch(0.112)], 75 | '#6': [util.inch(0.279), util.inch(0.083), util.inch(0.138)], 76 | '#8': [util.inch(0.332), util.inch(0.1), util.inch(0.164)], 77 | '#10': [util.inch(0.385), util.inch(0.116), util.inch(0.19)], 78 | '#12': [util.inch(0.438), util.inch(0.132), util.inch(0.216)] 79 | }; 80 | 81 | /** 82 | * Dimensions of nuts for imperial bolts. 83 | * F is the width across teh faces, C is the width 84 | * across the points, and H is the height. D is the 85 | * basic diameter. 86 | * 87 | * [F, C, H, D] 88 | * 89 | * @see https://en.wikipedia.org/wiki/Nut_(hardware) 90 | * @type {Object} 91 | */ 92 | var ImperialNuts = { 93 | '1/4 hex': [11.113, 12.8, 5.56, 6.35] 94 | }; 95 | -------------------------------------------------------------------------------- /docs/code/metric.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: metric 3 | --- 4 | 5 | # metric 6 | 7 | ## Constants 8 | 9 |
10 |
MetricHexBoltDimensions
11 |
12 |
SocketCapScrewDimensions
13 |
14 |
MetricBolts : Object
15 |

http://www.atlrod.com/metric-hex-bolt-dimensions/ 16 | E - Body Diameter (D) 17 | F - Width Across Flats 18 | G - Width Across Corners (C) 19 | H - Head Height 20 | D - Head Diameter

21 |

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

22 |
23 |
MetricNuts : Object
24 |

Dimensions of nuts for imperial bolts. 25 | F is the width across the faces, C is the width 26 | across the points, and H is the height. D is the 27 | basic diameter.

28 |

[F, C, H, D]

29 |
30 |
MetricWashers : Object
31 |

Metric washer sizes 32 | Size Inside Diameter Outside Diameter Thickness

33 |
34 |
35 | 36 | 37 | 38 | ## MetricHexBoltDimensions 39 | **Kind**: global constant 40 | **See**: http://www.atlrod.com/metric-hex-bolt-dimensions/ 41 | 42 | E - Body Diameter 43 | F - Width Across Flats 44 | G - Width Across Corners 45 | H - Head Height 46 | D - Head Diameter 47 | 48 | NOMINAL SIZE (D) BODY DIAMETER HEAD THICKNESS ACROSS THE FLATS ACROSS CORNERS 49 | 50 | 51 | ## SocketCapScrewDimensions 52 | **Kind**: global constant 53 | **See**: https://www.fastenal.com/content/product_specifications/M.SHCS.4762.8.8.Z.pdf 54 | 55 | Nominal Size (d), Body Diameter Max, min, Head Diameter max, min, Head Height max, min, Socket Size max, min, Key Engagement min 56 | 57 | E - Body Diameter 58 | H - Head Height 59 | D - Head Diameter 60 | 61 | 62 | ## MetricBolts : Object 63 | http://www.atlrod.com/metric-hex-bolt-dimensions/ 64 | E - Body Diameter (D) 65 | F - Width Across Flats 66 | G - Width Across Corners (C) 67 | H - Head Height 68 | D - Head Diameter 69 | 70 | tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 71 | 72 | **Kind**: global constant 73 | 74 | 75 | ## MetricNuts : Object 76 | Dimensions of nuts for imperial bolts. 77 | F is the width across the faces, C is the width 78 | across the points, and H is the height. D is the 79 | basic diameter. 80 | 81 | [F, C, H, D] 82 | 83 | **Kind**: global constant 84 | **See**: https://en.wikipedia.org/wiki/Nut_(hardware) 85 | 86 | 87 | ## MetricWashers : Object 88 | Metric washer sizes 89 | Size Inside Diameter Outside Diameter Thickness 90 | 91 | **Kind**: global constant 92 | **See**: https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx 93 | -------------------------------------------------------------------------------- /docs/code/hardware.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: hardware 3 | --- 4 | 5 | # hardware 6 | 7 | 8 | 9 | ## jscad-hardware : Object 10 | A gear moduel for openJSCAD. 11 | ![parts example](jsdoc2md/hexagon.png) 12 | 13 | **Example** 14 | ```js 15 | include('jscad-utils-color.jscad'); 16 | 17 | function mainx(params) { 18 | util.init(CSG); 19 | 20 | // draws a blue hexagon 21 | return Parts.Hexagon(10, 5).color('blue'); 22 | } 23 | ``` 24 | 25 | * [jscad-hardware](#module_jscad-hardware) : Object 26 | * [.Washer(washer, fit)](#module_jscad-hardware.Washer) 27 | * [.PanHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)](#module_jscad-hardware.PanHeadScrew) 28 | * [.HexHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)](#module_jscad-hardware.HexHeadScrew) 29 | * [.FlatHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)](#module_jscad-hardware.FlatHeadScrew) 30 | 31 | 32 | 33 | ### jscad-hardware.Washer(washer, fit) 34 | Create a washer group from a washer type. 35 | 36 | **Kind**: static method of [jscad-hardware](#module_jscad-hardware) 37 | 38 | | Param | Type | Description | 39 | | --- | --- | --- | 40 | | washer | Object | Washer type object. | 41 | | fit | String | Clearance to add to group (tap|close|loose). | 42 | 43 | 44 | 45 | ### jscad-hardware.PanHeadScrew(headDiameter, headLength, diameter, length, clearLength, options) 46 | Creates a `Group` object with a Pan Head Screw. 47 | 48 | **Kind**: static method of [jscad-hardware](#module_jscad-hardware) 49 | 50 | | Param | Type | Description | 51 | | --- | --- | --- | 52 | | headDiameter | number | Diameter of the head of the screw | 53 | | headLength | number | Length of the head | 54 | | diameter | number | Diameter of the threaded shaft | 55 | | length | number | Length of the threaded shaft | 56 | | clearLength | number | Length of the clearance section of the head. | 57 | | options | object | Screw options include orientation and clerance scale. | 58 | 59 | 60 | 61 | ### jscad-hardware.HexHeadScrew(headDiameter, headLength, diameter, length, clearLength, options) 62 | Creates a `Group` object with a Hex Head Screw. 63 | 64 | **Kind**: static method of [jscad-hardware](#module_jscad-hardware) 65 | 66 | | Param | Type | Description | 67 | | --- | --- | --- | 68 | | headDiameter | number | Diameter of the head of the screw | 69 | | headLength | number | Length of the head | 70 | | diameter | number | Diameter of the threaded shaft | 71 | | length | number | Length of the threaded shaft | 72 | | clearLength | number | Length of the clearance section of the head. | 73 | | options | object | Screw options include orientation and clerance scale. | 74 | 75 | 76 | 77 | ### jscad-hardware.FlatHeadScrew(headDiameter, headLength, diameter, length, clearLength, options) 78 | Create a Flat Head Screw 79 | 80 | **Kind**: static method of [jscad-hardware](#module_jscad-hardware) 81 | 82 | | Param | Type | Description | 83 | | --- | --- | --- | 84 | | headDiameter | number | head diameter | 85 | | headLength | number | head length | 86 | | diameter | number | thread diameter | 87 | | length | number | thread length | 88 | | clearLength | number | clearance length | 89 | | options | object | options | 90 | 91 | -------------------------------------------------------------------------------- /docs/code/imperial.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: imperial 3 | --- 4 | 5 | # imperial 6 | 7 | ## Constants 8 | 9 |
10 |
HexBoltDimensions : Object
11 |

Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv.

12 |
13 |
SocketCapScrewDimensions
14 |

Socket cap screw dimensions.

15 |

E - Body Diameter 16 | H - Head Height 17 | D - Head Diameter

18 |
19 |
ImperialBolts : Object
20 |

http://www.americanfastener.com/cap-screws/ 21 | E - Body Diameter 22 | F - Width Across Flats 23 | G - Width Across Corners 24 | H - Head Height 25 | D - Head Diameter

26 |

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

27 |
28 |
ImperialWashers : Object
29 |

Imperial washer sizes 30 | Size Inside Diameter Outside Diameter Thickness

31 |
32 |
ImperialWoodScrews
33 |

Imperial wood screws.

34 |
35 |
ImperialNuts : Object
36 |

Dimensions of nuts for imperial bolts. 37 | F is the width across teh faces, C is the width 38 | across the points, and H is the height. D is the 39 | basic diameter.

40 |

[F, C, H, D]

41 |
42 |
43 | 44 | 45 | 46 | ## HexBoltDimensions : Object 47 | Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv. 48 | 49 | **Kind**: global constant 50 | **See** 51 | 52 | - http://www.americanfastener.com/cap-screws/ 53 | - https://www.aftfasteners.com/fully-threaded-hex-tap-bolts-dimensions-mechanical-properties/ 54 | E - Body Diameter 55 | F - Width Across Flats 56 | G - Width Across Corners 57 | H - Head Height 58 | D - Head Diameter 59 | 60 | tap sizes: @see https://littlemachineshop.com/reference/tapdrill.php 61 | 62 | 63 | 64 | ## SocketCapScrewDimensions 65 | Socket cap screw dimensions. 66 | 67 | E - Body Diameter 68 | H - Head Height 69 | D - Head Diameter 70 | 71 | **Kind**: global constant 72 | **See**: https://www.aftfasteners.com/socket-cap-screws-dimensions-and-mechanical-properties/ 73 | 74 | 75 | ## ImperialBolts : Object 76 | http://www.americanfastener.com/cap-screws/ 77 | E - Body Diameter 78 | F - Width Across Flats 79 | G - Width Across Corners 80 | H - Head Height 81 | D - Head Diameter 82 | 83 | tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 84 | 85 | **Kind**: global constant 86 | 87 | 88 | ## ImperialWashers : Object 89 | Imperial washer sizes 90 | Size Inside Diameter Outside Diameter Thickness 91 | 92 | **Kind**: global constant 93 | **See** 94 | 95 | - https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx 96 | - http://almabolt.com/pages/catalog/washers/fender.htm 97 | 98 | 99 | 100 | ## ImperialWoodScrews 101 | Imperial wood screws. 102 | 103 | **Kind**: global constant 104 | **See**: https://www.aftfasteners.com/wood-screws-dimensions-mechanical-specs/ 105 | headDiameter, headLength, diameter, tap, countersink 106 | 107 | 108 | ## ImperialNuts : Object 109 | Dimensions of nuts for imperial bolts. 110 | F is the width across teh faces, C is the width 111 | across the points, and H is the height. D is the 112 | basic diameter. 113 | 114 | [F, C, H, D] 115 | 116 | **Kind**: global constant 117 | **See** 118 | 119 | - https://en.wikipedia.org/wiki/Nut_(hardware) 120 | - https://www.boltdepot.com/fastener-information/nuts-washers/us-nut-dimensions.aspx 121 | 122 | -------------------------------------------------------------------------------- /githubdocs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | jscad parts library for screws, washers and nuts 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 |

view on npm npm module downloads

46 |

jscad-hardware

47 |
48 |

https://johnwebbcole.github.io/jscad-hardware/

49 |
50 |

bplus example

51 |

This is a collection of jscad parts that model a common Imperial and Metric bolts and washers. These models use the jscad-utils library and return jscad-utils group objects.

52 |

Installation

53 |

Install jscad-hardware using NPM:

54 |
npm install --save jscad-hardware
 55 | 
56 |

Basic usage

57 |

To use the utilities, you need to include the jscad-hardware.jscad.

58 |
include('node_modules/jscad-utils/jscad-utils.jscad');
 59 | include('node_modules/jscad-hardware/jscad-hardware.jscad');
 60 | 
 61 | main() {
 62 |   util.init(CSG);
 63 | 
 64 |   var BPlus = RaspberryPi.BPlus();
 65 | 
 66 |   return BPlus.combine();
 67 | }
 68 | 
69 |

Yeoman Generator

70 |

You can use the yeoman jscad generator which will create a project that uses this library.

71 |

Once you create your project, install jscad-hardware, and run gulp. Dragging the dist directory into http://openjscad.org/ will include this library.

72 |

Modify your main.jscad file to return a RaspberryPi object.

73 |
function main() {
 74 |     util.init(CSG);
 75 | 
 76 |     var bolt = Hardware.Bolt(
 77 |       util.inch(1),
 78 |       ImperialBolts['5/16 hex'],
 79 |       'close'
 80 |     )
 81 | 
 82 |     return bolt.combine('head,thread');
 83 | }
 84 | 
 85 | // include:js
 86 | // endinject
 87 | 
88 |

bplus example

89 | 90 |
91 | 92 | 93 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/8.362e9d24.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[8],{269:function(t,e,s){"use strict";s.r(e);var r=s(38),i=Object(r.a)({},function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"metric"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metric","aria-hidden":"true"}},[t._v("#")]),t._v(" metric")]),t._v(" "),s("h2",{attrs:{id:"constants"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#constants","aria-hidden":"true"}},[t._v("#")]),t._v(" Constants")]),t._v(" "),s("dl",[s("dt",[s("a",{attrs:{href:"#MetricHexBoltDimensions"}},[t._v("MetricHexBoltDimensions")])]),t._v(" "),s("dd"),t._v(" "),s("dt",[s("a",{attrs:{href:"#SocketCapScrewDimensions"}},[t._v("SocketCapScrewDimensions")])]),t._v(" "),s("dd"),t._v(" "),s("dt",[s("a",{attrs:{href:"#MetricBolts"}},[t._v("MetricBolts")]),t._v(" : "),s("code",[t._v("Object")])]),t._v(" "),s("dd",[s("p",[s("a",{attrs:{href:"http://www.atlrod.com/metric-hex-bolt-dimensions/"}},[t._v("http://www.atlrod.com/metric-hex-bolt-dimensions/")]),t._v("\nE - Body Diameter (D)\nF - Width Across Flats\nG - Width Across Corners (C)\nH - Head Height\nD - Head Diameter")]),t._v(" "),s("p",[t._v("tap sizes: "),s("a",{attrs:{href:"https://littlemachineshop.com/reference/TapDrillSizes.pdf"}},[t._v("https://littlemachineshop.com/reference/TapDrillSizes.pdf")])])]),t._v(" "),s("dt",[s("a",{attrs:{href:"#MetricNuts"}},[t._v("MetricNuts")]),t._v(" : "),s("code",[t._v("Object")])]),t._v(" "),s("dd",[s("p",[t._v("Dimensions of nuts for imperial bolts.\nF is the width across the faces, C is the width\nacross the points, and H is the height. D is the\nbasic diameter.")]),t._v(" "),s("p",[t._v("[F, C, H, D]")])]),t._v(" "),s("dt",[s("a",{attrs:{href:"#MetricWashers"}},[t._v("MetricWashers")]),t._v(" : "),s("code",[t._v("Object")])]),t._v(" "),s("dd",[s("p",[t._v("Metric washer sizes\nSize Inside Diameter Outside Diameter Thickness")])])]),t._v(" "),s("p",[s("a",{attrs:{name:"MetricHexBoltDimensions"}})]),t._v(" "),s("h2",{attrs:{id:"metrichexboltdimensions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metrichexboltdimensions","aria-hidden":"true"}},[t._v("#")]),t._v(" MetricHexBoltDimensions")]),t._v(" "),s("p",[s("strong",[t._v("Kind")]),t._v(": global constant"),s("br"),t._v(" "),s("strong",[t._v("See")]),t._v(": http://www.atlrod.com/metric-hex-bolt-dimensions/")]),t._v(" "),s("p",[t._v("E - Body Diameter\nF - Width Across Flats\nG - Width Across Corners\nH - Head Height\nD - Head Diameter")]),t._v(" "),s("p",[t._v("NOMINAL SIZE (D)\tBODY DIAMETER\t\tHEAD THICKNESS\t\tACROSS THE FLATS\t\tACROSS CORNERS"),s("br"),t._v(" "),s("a",{attrs:{name:"SocketCapScrewDimensions"}})]),t._v(" "),s("h2",{attrs:{id:"socketcapscrewdimensions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#socketcapscrewdimensions","aria-hidden":"true"}},[t._v("#")]),t._v(" SocketCapScrewDimensions")]),t._v(" "),s("p",[s("strong",[t._v("Kind")]),t._v(": global constant"),s("br"),t._v(" "),s("strong",[t._v("See")]),t._v(": https://www.fastenal.com/content/product_specifications/M.SHCS.4762.8.8.Z.pdf")]),t._v(" "),s("p",[t._v("Nominal Size (d), Body Diameter Max, min, Head Diameter max, min, Head Height max, min, Socket Size max, min, Key Engagement min")]),t._v(" "),s("p",[t._v("E - Body Diameter\nH - Head Height\nD - Head Diameter"),s("br"),t._v(" "),s("a",{attrs:{name:"MetricBolts"}})]),t._v(" "),s("h2",{attrs:{id:"metricbolts-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metricbolts-object","aria-hidden":"true"}},[t._v("#")]),t._v(" MetricBolts : "),s("code",[t._v("Object")])]),t._v(" "),s("p",[t._v("http://www.atlrod.com/metric-hex-bolt-dimensions/\nE - Body Diameter (D)\nF - Width Across Flats\nG - Width Across Corners (C)\nH - Head Height\nD - Head Diameter")]),t._v(" "),s("p",[t._v("tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf")]),t._v(" "),s("p",[s("strong",[t._v("Kind")]),t._v(": global constant"),s("br"),t._v(" "),s("a",{attrs:{name:"MetricNuts"}})]),t._v(" "),s("h2",{attrs:{id:"metricnuts-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metricnuts-object","aria-hidden":"true"}},[t._v("#")]),t._v(" MetricNuts : "),s("code",[t._v("Object")])]),t._v(" "),s("p",[t._v("Dimensions of nuts for imperial bolts.\nF is the width across the faces, C is the width\nacross the points, and H is the height. D is the\nbasic diameter.")]),t._v(" "),s("p",[t._v("[F, C, H, D]")]),t._v(" "),s("p",[s("strong",[t._v("Kind")]),t._v(": global constant"),s("br"),t._v(" "),s("strong",[t._v("See")]),t._v(": https://en.wikipedia.org/wiki/Nut_(hardware)"),s("br"),t._v(" "),s("a",{attrs:{name:"MetricWashers"}})]),t._v(" "),s("h2",{attrs:{id:"metricwashers-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metricwashers-object","aria-hidden":"true"}},[t._v("#")]),t._v(" MetricWashers : "),s("code",[t._v("Object")])]),t._v(" "),s("p",[t._v("Metric washer sizes\nSize\tInside Diameter\tOutside Diameter\tThickness")]),t._v(" "),s("p",[s("strong",[t._v("Kind")]),t._v(": global constant"),s("br"),t._v(" "),s("strong",[t._v("See")]),t._v(": https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx")])])},[],!1,null,null,null);e.default=i.exports}}]); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* eslint-env node */ 3 | var fs = require('fs'); 4 | var gulp = require('gulp'); 5 | // var concat = require('gulp-concat'); 6 | var del = require('del'); 7 | // var gulpLoadPlugins = require('gulp-load-plugins'); 8 | // var plugins = gulpLoadPlugins(); 9 | // var runSequence = require('run-sequence'); 10 | var rollup = require('rollup'); 11 | var merge2 = require('merge2'); 12 | var debug = require('gulp-debug'); 13 | var inject = require('gulp-inject'); 14 | var plumber = require('gulp-plumber'); 15 | var terser = require('gulp-terser'); 16 | var rollupResolve = require('rollup-plugin-node-resolve'); 17 | var rollupBabel = require('rollup-plugin-babel'); 18 | var jscadFiles = require('gulp-jscad-files'); 19 | var pkg = require('./package.json'); 20 | 21 | gulp.task('build', async function() { 22 | const bundle = await rollup.rollup({ 23 | input: './src/index.js', 24 | external: ['@jscad/scad-api', '@jscad/csg', '@jwc/jscad-utils'], 25 | plugins: [ 26 | rollupResolve({ 27 | customResolveOptions: { 28 | moduleDirectory: 'node_modules' 29 | }, 30 | browser: true 31 | }), 32 | rollupBabel({ 33 | exclude: 'node_modules/**' // only transpile our source code 34 | }) 35 | ] 36 | }); 37 | 38 | await bundle.write({ 39 | name: 'jscadHardware', 40 | file: 'dist/index.js', 41 | format: 'iife', 42 | exports: 'named', 43 | globals: { 44 | '@jscad/csg': 'jsCadCSG', 45 | '@jscad/scad-api': 'scadApi', 46 | '@jwc/jscad-utils': 'jscadUtils' 47 | }, 48 | banner: `/* 49 | * ${pkg.name} version ${pkg.version} 50 | * ${pkg.homepage} 51 | */`, 52 | footer: `/* ${pkg.name} follow me on Twitter! @johnwebbcole */` 53 | }); 54 | }); 55 | 56 | gulp.task('v1compat', function() { 57 | return gulp 58 | .src('src/v1compat.js') 59 | .pipe(plumber()) 60 | .pipe( 61 | inject(gulp.src('dist/index.js').pipe(debug({ title: 'injecting:' })), { 62 | relative: true, 63 | starttag: '// include:compat', 64 | endtag: '// end:compat', 65 | transform: function(filepath, file) { 66 | return '// ' + filepath + '\n' + file.contents.toString('utf8'); 67 | } 68 | }) 69 | ) 70 | .pipe(gulp.dest('dist')); 71 | }); 72 | 73 | // gulp.task('clean', function(done) { 74 | // del(['README.md', 'dist/*.jscad']).then(paths => { 75 | // console.log('Deleted files and folders:\n', paths.join('\n')); // eslint-disable-line no-console, no-undef 76 | // done(); 77 | // }); 78 | // }); 79 | 80 | // gulp.task('lint', function() { 81 | // return gulp 82 | // .src(['*.jscad', 'gulpfile.js']) 83 | // .pipe(plugins.plumber()) 84 | // .pipe(plugins.eslint()) 85 | // .pipe(plugins.eslint.format()); 86 | // // .pipe(plugins.eslint.failAfterError()); 87 | // }); 88 | 89 | // gulp.task('docs', function() { 90 | // return gulp 91 | // .src('*.jscad') 92 | // .pipe(plugins.plumber()) 93 | // .pipe(plugins.concat('README.md')) 94 | // .pipe( 95 | // plugins.jsdocToMarkdown({ 96 | // template: fs.readFileSync('./jsdoc2md/README.hbs', 'utf8') 97 | // }) 98 | // ) 99 | // .on('error', function(err) { 100 | // plugins.util.log('jsdoc2md failed:', err.message); 101 | // }) 102 | // .pipe(gulp.dest('.')); 103 | // }); 104 | 105 | gulp.task('examples', function() { 106 | return gulp 107 | .src('examples/*.jscad') 108 | .pipe(plumber()) 109 | .pipe( 110 | inject( 111 | merge2( 112 | gulp 113 | .src('package.json') 114 | .pipe(jscadFiles()) 115 | .pipe( 116 | terser({ 117 | ecma: 6, 118 | keep_fnames: true, 119 | mangle: false, 120 | compress: false, 121 | output: { 122 | beautify: true, 123 | max_line_len: 80 124 | } 125 | }) 126 | ), 127 | gulp.src(['dist/v1compat.js']) 128 | ).pipe(debug({ title: 'injecting:' })), 129 | { 130 | relative: true, 131 | starttag: '// include:js', 132 | endtag: '// endinject', 133 | transform: function(filepath, file) { 134 | return '// ' + filepath + '\n' + file.contents.toString('utf8'); 135 | } 136 | } 137 | ) 138 | ) 139 | .pipe(gulp.dest('dist/examples')); 140 | }); 141 | 142 | // gulp.task('github-page', ['docs', 'examples'], function() { 143 | // return gulp 144 | // .src('package.json') 145 | // .pipe(plugins.plumber()) 146 | // .pipe( 147 | // plugins.openjscadStandalone({ 148 | // filename: 'bolt.jscad', 149 | // filepath: __dirname + '/dist/bolt.jscad' 150 | // }) 151 | // ) 152 | // .pipe(gulp.dest('docs')); 153 | // }); 154 | 155 | gulp.task('all', gulp.series(['build', 'v1compat', 'examples'])); 156 | 157 | gulp.task( 158 | 'default', 159 | gulp.series(['build', 'v1compat', 'examples'], function() { 160 | gulp.watch( 161 | ['src/**/*.js', 'examples/*.jscad'], 162 | { 163 | verbose: true, 164 | followSymlinks: true, 165 | delay: 500, 166 | queue: false, 167 | ignoreInitial: false, 168 | ignored: ['**/*.*~', 'dist/*', '.vuepress/*'] 169 | }, 170 | gulp.series(['build', 'v1compat', 'examples']) 171 | ); 172 | }) 173 | ); 174 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/code/metric.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | metric 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

metric

Constants

MetricHexBoltDimensions
SocketCapScrewDimensions
MetricBolts : Object

http://www.atlrod.com/metric-hex-bolt-dimensions/ 15 | E - Body Diameter (D) 16 | F - Width Across Flats 17 | G - Width Across Corners (C) 18 | H - Head Height 19 | D - Head Diameter

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

MetricNuts : Object

Dimensions of nuts for imperial bolts. 20 | F is the width across the faces, C is the width 21 | across the points, and H is the height. D is the 22 | basic diameter.

[F, C, H, D]

MetricWashers : Object

Metric washer sizes 23 | Size Inside Diameter Outside Diameter Thickness

MetricHexBoltDimensions

Kind: global constant
See: http://www.atlrod.com/metric-hex-bolt-dimensions/

E - Body Diameter 24 | F - Width Across Flats 25 | G - Width Across Corners 26 | H - Head Height 27 | D - Head Diameter

NOMINAL SIZE (D) BODY DIAMETER HEAD THICKNESS ACROSS THE FLATS ACROSS CORNERS

SocketCapScrewDimensions

Kind: global constant
See: https://www.fastenal.com/content/product_specifications/M.SHCS.4762.8.8.Z.pdf

Nominal Size (d), Body Diameter Max, min, Head Diameter max, min, Head Height max, min, Socket Size max, min, Key Engagement min

E - Body Diameter 28 | H - Head Height 29 | D - Head Diameter

MetricBolts : Object

http://www.atlrod.com/metric-hex-bolt-dimensions/ 30 | E - Body Diameter (D) 31 | F - Width Across Flats 32 | G - Width Across Corners (C) 33 | H - Head Height 34 | D - Head Diameter

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

Kind: global constant

MetricNuts : Object

Dimensions of nuts for imperial bolts. 35 | F is the width across the faces, C is the width 36 | across the points, and H is the height. D is the 37 | basic diameter.

[F, C, H, D]

Kind: global constant
See: https://en.wikipedia.org/wiki/Nut_(hardware)

MetricWashers : Object

Metric washer sizes 38 | Size Inside Diameter Outside Diameter Thickness

Kind: global constant
See: https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx

39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /githubdocs/jscad-worker.js: -------------------------------------------------------------------------------- 1 | // jscad-worker.js 2 | // 3 | // == OpenJSCAD.org, Copyright (c) 2013-2016, Licensed under MIT License 4 | // 5 | // History: 6 | // 2016/02/02: 0.4.0: GUI refactored, functionality split up into more files, mostly done by Z3 Dev 7 | 8 | // Create an worker (thread) for processing the JSCAD script into CSG/CAG objects 9 | // 10 | // fullurl - URL to original script 11 | // script - FULL script with all possible support routines, etc 12 | // callback - function to call, returning results or errors 13 | // 14 | // This function builds the Worker thread, which is started by a message 15 | // The Worker thread (below) executes, and returns the results via another message. 16 | // (KIND OF LAME but that keeps the scope of variables and functions clean) 17 | // Upon receiving the message, the callback routine is called with the results 18 | // 19 | OpenJsCad.createJscadWorker = function(fullurl, script, callback) { 20 | var source = buildJscadWorkerScript(fullurl, script); 21 | var blobURL = OpenJsCad.textToBlobUrl(source); 22 | var w = new Worker(blobURL); 23 | 24 | //console.log("createJscadWorker: "+source); 25 | 26 | // when the worker finishes 27 | // - call back the provided function with the results 28 | w.onmessage = function(e) { 29 | if (e.data instanceof Object) { 30 | var data = e.data; 31 | if(data.cmd == 'rendered') { 32 | if (data.objects && data.objects.length) { 33 | // convert the compact formats back to CSG/CAG form 34 | var objects = []; 35 | for(var i=0; i) 67 | var relpath = fullpath; 68 | if (relpath.lastIndexOf('/') >= 0) { 69 | relpath = relpath.substring(0,relpath.lastIndexOf('/')+1); 70 | } 71 | var source = ""; 72 | source += 'onmessage = function(e) {\n'; 73 | source += ' include = includeJscad;\n'; 74 | source += ' self.relpath = "'+relpath+'";\n'; 75 | source += '\n'; 76 | source += fullscript+'\n'; 77 | source += includeJscad.toString()+'\n'; 78 | source += runJscadWorker.toString()+'\n'; 79 | source += ' runJscadWorker(e);\n'; 80 | source += '};'; 81 | return source; 82 | } 83 | 84 | // 85 | // THESE FUNCTIONS ARE SERIALIZED FOR INCLUSION IN THE FULL SCRIPT 86 | // 87 | // TODO It might be possible to cache the serialized versions 88 | // 89 | 90 | // Implement include() generally for all scripts 91 | // 92 | // (Note: This function is appended together with the JSCAD script) 93 | // 94 | function includeJscad(fn) { 95 | // include the requested script via MemFs if possible 96 | if (typeof(gMemFs) == 'object') { 97 | for (var i = 0; i < gMemFs.length; i++) { 98 | if (gMemFs[i].name == fn) { 99 | eval(gMemFs[i].source); 100 | return; 101 | } 102 | } 103 | } 104 | // include the requested script via importScripts 105 | var url = self.relpath+fn; 106 | if (fn.match(/^(https:|http:)/i)) { 107 | url = fn; 108 | } 109 | importScripts(url); 110 | return true; 111 | }; 112 | 113 | // Run the JSCAD script via main() 114 | // 115 | // The message (event) must contain: 116 | // data.cmd - 'render' 117 | // data.parameters - the parameter values to pass to main() 118 | // The message (event) can also supply: 119 | // data.libraries - the libraries (full URLs) to import 120 | // 121 | // (Note: This function is appended together with the JSCAD script) 122 | // 123 | function runJscadWorker(e) { 124 | var r = {cmd: "error", txt: "try again"}; 125 | if (e.data instanceof Object) { 126 | var data = e.data; 127 | if(data.cmd == 'render') { 128 | // verify the command contents 129 | if(!data.parameters) { throw new Error("JSCAD Processor: missing 'parameters'"); } 130 | // setup the environment 131 | if(data.libraries && data.libraries.length) { 132 | data.libraries.map( function(l) { importScripts(l); } ); 133 | } 134 | // setup the script 135 | if (typeof(main) == 'function') { 136 | var results = main( data.parameters ); 137 | if (!results.length) { results = [results]; } 138 | // convert the results to a compact format for transfer back 139 | var objects = []; 140 | for(var i=0; i 0) { 148 | r.cmd = "rendered"; 149 | r.objects = objects; 150 | } else { 151 | r.err = 'The JSCAD script must return one or more CSG or CAG solids.'; 152 | } 153 | } else { 154 | r.err = 'The JSCAD script must contain a function main() which returns one or more CSG or CAG solids.'; 155 | } 156 | } else { 157 | throw new Error('JSCAD Processor: invalid worker command: '+data.cmd); 158 | } 159 | } 160 | postMessage(r); 161 | }; 162 | 163 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/7.02f8640a.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{268:function(e,t,a){"use strict";a.r(t);var s=a(38),i=Object(s.a)({},function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"imperial"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#imperial","aria-hidden":"true"}},[e._v("#")]),e._v(" imperial")]),e._v(" "),a("h2",{attrs:{id:"constants"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#constants","aria-hidden":"true"}},[e._v("#")]),e._v(" Constants")]),e._v(" "),a("dl",[a("dt",[a("a",{attrs:{href:"#HexBoltDimensions"}},[e._v("HexBoltDimensions")]),e._v(" : "),a("code",[e._v("Object")])]),e._v(" "),a("dd",[a("p",[e._v("Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv.")])]),e._v(" "),a("dt",[a("a",{attrs:{href:"#SocketCapScrewDimensions"}},[e._v("SocketCapScrewDimensions")])]),e._v(" "),a("dd",[a("p",[e._v("Socket cap screw dimensions.")]),e._v(" "),a("p",[e._v("E - Body Diameter\nH - Head Height\nD - Head Diameter")])]),e._v(" "),a("dt",[a("a",{attrs:{href:"#ImperialBolts"}},[e._v("ImperialBolts")]),e._v(" : "),a("code",[e._v("Object")])]),e._v(" "),a("dd",[a("p",[a("a",{attrs:{href:"http://www.americanfastener.com/cap-screws/"}},[e._v("http://www.americanfastener.com/cap-screws/")]),e._v("\nE - Body Diameter\nF - Width Across Flats\nG - Width Across Corners\nH - Head Height\nD - Head Diameter")]),e._v(" "),a("p",[e._v("tap sizes: "),a("a",{attrs:{href:"https://littlemachineshop.com/reference/TapDrillSizes.pdf"}},[e._v("https://littlemachineshop.com/reference/TapDrillSizes.pdf")])])]),e._v(" "),a("dt",[a("a",{attrs:{href:"#ImperialWashers"}},[e._v("ImperialWashers")]),e._v(" : "),a("code",[e._v("Object")])]),e._v(" "),a("dd",[a("p",[e._v("Imperial washer sizes\nSize Inside Diameter Outside Diameter Thickness")])]),e._v(" "),a("dt",[a("a",{attrs:{href:"#ImperialWoodScrews"}},[e._v("ImperialWoodScrews")])]),e._v(" "),a("dd",[a("p",[e._v("Imperial wood screws.")])]),e._v(" "),a("dt",[a("a",{attrs:{href:"#ImperialNuts"}},[e._v("ImperialNuts")]),e._v(" : "),a("code",[e._v("Object")])]),e._v(" "),a("dd",[a("p",[e._v("Dimensions of nuts for imperial bolts.\nF is the width across teh faces, C is the width\nacross the points, and H is the height. D is the\nbasic diameter.")]),e._v(" "),a("p",[e._v("[F, C, H, D]")])])]),e._v(" "),a("p",[a("a",{attrs:{name:"HexBoltDimensions"}})]),e._v(" "),a("h2",{attrs:{id:"hexboltdimensions-object"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#hexboltdimensions-object","aria-hidden":"true"}},[e._v("#")]),e._v(" HexBoltDimensions : "),a("code",[e._v("Object")])]),e._v(" "),a("p",[e._v("Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv.")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("strong",[e._v("See")])]),e._v(" "),a("ul",[a("li",[e._v("http://www.americanfastener.com/cap-screws/")]),e._v(" "),a("li",[e._v("https://www.aftfasteners.com/fully-threaded-hex-tap-bolts-dimensions-mechanical-properties/\nE - Body Diameter\nF - Width Across Flats\nG - Width Across Corners\nH - Head Height\nD - Head Diameter")])]),e._v(" "),a("p",[e._v("tap sizes: @see https://littlemachineshop.com/reference/tapdrill.php")]),e._v(" "),a("p",[a("a",{attrs:{name:"SocketCapScrewDimensions"}})]),e._v(" "),a("h2",{attrs:{id:"socketcapscrewdimensions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#socketcapscrewdimensions","aria-hidden":"true"}},[e._v("#")]),e._v(" SocketCapScrewDimensions")]),e._v(" "),a("p",[e._v("Socket cap screw dimensions.")]),e._v(" "),a("p",[e._v("E - Body Diameter\nH - Head Height\nD - Head Diameter")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("strong",[e._v("See")]),e._v(": https://www.aftfasteners.com/socket-cap-screws-dimensions-and-mechanical-properties/"),a("br"),e._v(" "),a("a",{attrs:{name:"ImperialBolts"}})]),e._v(" "),a("h2",{attrs:{id:"imperialbolts-object"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#imperialbolts-object","aria-hidden":"true"}},[e._v("#")]),e._v(" ImperialBolts : "),a("code",[e._v("Object")])]),e._v(" "),a("p",[e._v("http://www.americanfastener.com/cap-screws/\nE - Body Diameter\nF - Width Across Flats\nG - Width Across Corners\nH - Head Height\nD - Head Diameter")]),e._v(" "),a("p",[e._v("tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("a",{attrs:{name:"ImperialWashers"}})]),e._v(" "),a("h2",{attrs:{id:"imperialwashers-object"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#imperialwashers-object","aria-hidden":"true"}},[e._v("#")]),e._v(" ImperialWashers : "),a("code",[e._v("Object")])]),e._v(" "),a("p",[e._v("Imperial washer sizes\nSize\tInside Diameter\tOutside Diameter\tThickness")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("strong",[e._v("See")])]),e._v(" "),a("ul",[a("li",[e._v("https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx")]),e._v(" "),a("li",[e._v("http://almabolt.com/pages/catalog/washers/fender.htm")])]),e._v(" "),a("p",[a("a",{attrs:{name:"ImperialWoodScrews"}})]),e._v(" "),a("h2",{attrs:{id:"imperialwoodscrews"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#imperialwoodscrews","aria-hidden":"true"}},[e._v("#")]),e._v(" ImperialWoodScrews")]),e._v(" "),a("p",[e._v("Imperial wood screws.")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("strong",[e._v("See")]),e._v(": https://www.aftfasteners.com/wood-screws-dimensions-mechanical-specs/\nheadDiameter, headLength, diameter, tap, countersink"),a("br"),e._v(" "),a("a",{attrs:{name:"ImperialNuts"}})]),e._v(" "),a("h2",{attrs:{id:"imperialnuts-object"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#imperialnuts-object","aria-hidden":"true"}},[e._v("#")]),e._v(" ImperialNuts : "),a("code",[e._v("Object")])]),e._v(" "),a("p",[e._v("Dimensions of nuts for imperial bolts.\nF is the width across teh faces, C is the width\nacross the points, and H is the height. D is the\nbasic diameter.")]),e._v(" "),a("p",[e._v("[F, C, H, D]")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": global constant"),a("br"),e._v(" "),a("strong",[e._v("See")])]),e._v(" "),a("ul",[a("li",[e._v("https://en.wikipedia.org/wiki/Nut_(hardware)")]),e._v(" "),a("li",[e._v("https://www.boltdepot.com/fastener-information/nuts-washers/us-nut-dimensions.aspx")])])])},[],!1,null,null,null);t.default=i.exports}}]); -------------------------------------------------------------------------------- /docs/.vuepress/dist/code/imperial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | imperial 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

imperial

Constants

HexBoltDimensions : Object

Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv.

SocketCapScrewDimensions

Socket cap screw dimensions.

E - Body Diameter 15 | H - Head Height 16 | D - Head Diameter

ImperialBolts : Object

http://www.americanfastener.com/cap-screws/ 17 | E - Body Diameter 18 | F - Width Across Flats 19 | G - Width Across Corners 20 | H - Head Height 21 | D - Head Diameter

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

ImperialWashers : Object

Imperial washer sizes 22 | Size Inside Diameter Outside Diameter Thickness

ImperialWoodScrews

Imperial wood screws.

ImperialNuts : Object

Dimensions of nuts for imperial bolts. 23 | F is the width across teh faces, C is the width 24 | across the points, and H is the height. D is the 25 | basic diameter.

[F, C, H, D]

HexBoltDimensions : Object

Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv.

Kind: global constant
See

  • http://www.americanfastener.com/cap-screws/
  • https://www.aftfasteners.com/fully-threaded-hex-tap-bolts-dimensions-mechanical-properties/ 26 | E - Body Diameter 27 | F - Width Across Flats 28 | G - Width Across Corners 29 | H - Head Height 30 | D - Head Diameter

tap sizes: @see https://littlemachineshop.com/reference/tapdrill.php

SocketCapScrewDimensions

Socket cap screw dimensions.

E - Body Diameter 31 | H - Head Height 32 | D - Head Diameter

Kind: global constant
See: https://www.aftfasteners.com/socket-cap-screws-dimensions-and-mechanical-properties/

ImperialBolts : Object

http://www.americanfastener.com/cap-screws/ 33 | E - Body Diameter 34 | F - Width Across Flats 35 | G - Width Across Corners 36 | H - Head Height 37 | D - Head Diameter

tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf

Kind: global constant

ImperialWashers : Object

Imperial washer sizes 38 | Size Inside Diameter Outside Diameter Thickness

Kind: global constant
See

  • https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx
  • http://almabolt.com/pages/catalog/washers/fender.htm

ImperialWoodScrews

Imperial wood screws.

Kind: global constant
See: https://www.aftfasteners.com/wood-screws-dimensions-mechanical-specs/ 39 | headDiameter, headLength, diameter, tap, countersink

ImperialNuts : Object

Dimensions of nuts for imperial bolts. 40 | F is the width across teh faces, C is the width 41 | across the points, and H is the height. D is the 42 | basic diameter.

[F, C, H, D]

Kind: global constant
See

  • https://en.wikipedia.org/wiki/Nut_(hardware)
  • https://www.boltdepot.com/fastener-information/nuts-washers/us-nut-dimensions.aspx
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/hardware.js: -------------------------------------------------------------------------------- 1 | import { util, Group, parts as Parts, Debug } from '@jwc/jscad-utils'; 2 | const debug = Debug('jscadHardware:hardware'); 3 | /* exported Hardware */ 4 | 5 | /** 6 | * A gear moduel for openJSCAD. 7 | * ![parts example](jsdoc2md/hexagon.png) 8 | * @example 9 | *include('jscad-utils-color.jscad'); 10 | * 11 | *function mainx(params) { 12 | * util.init(CSG); 13 | * 14 | * // draws a blue hexagon 15 | * return Parts.Hexagon(10, 5).color('blue'); 16 | *} 17 | * @type {Object} 18 | * @module jscad-hardware 19 | * @exports Hardware 20 | */ 21 | export function Bolt(length, bolt, fit, BOM) { 22 | fit = fit || 'loose'; 23 | 24 | if (BOM) { 25 | // Keep track of bolts for bill-of-materials 26 | var bomkey = `${bolt.name} - ${util.cm(length).toFixed(2)}`; 27 | if (!BOM[bomkey]) BOM[bomkey] = 0; 28 | BOM[bomkey]++; 29 | } 30 | 31 | var b = this[bolt.type](bolt.G || bolt.D, bolt.H, bolt.E, length); 32 | 33 | var clearance = bolt[fit] - bolt.E; 34 | 35 | b.add( 36 | this[bolt.type]( 37 | (bolt.G || bolt.D) + clearance, 38 | bolt.H + clearance, 39 | bolt[fit], 40 | length, 41 | length 42 | ).map(part => part.color('red')), 43 | 'tap', 44 | false, 45 | 'tap-' 46 | ); 47 | 48 | return b; 49 | } 50 | 51 | /** 52 | * Create a washer group from a washer type. 53 | * @param {Object} washer Washer type object. 54 | * @param {String} fit Clearance to add to group (tap|close|loose). 55 | */ 56 | export function Washer(washer, fit) { 57 | debug('Washer', washer, fit); 58 | var w = Group(); 59 | w.add( 60 | Parts.Tube(washer.od, washer.id, washer.thickness).color('gray'), 61 | 'washer' 62 | ); 63 | 64 | if (fit) { 65 | var tap = Clearances[fit]; 66 | if (!tap) 67 | console.error( 68 | `Washer unknown fit clearance ${fit}, should be ${Object.keys( 69 | Clearances 70 | ).join('|')}` 71 | ); 72 | w.add( 73 | Parts.Cylinder(washer.od + Clearances[fit], washer.thickness).color( 74 | 'red' 75 | ), 76 | 'clearance' 77 | ); 78 | } 79 | return w; 80 | } 81 | 82 | export function Nut(nut, fit) { 83 | debug('Nut', nut, fit); 84 | return Parts.Hexagon(nut[1] + Clearances[fit], nut[2]); 85 | } 86 | 87 | export const Screw = { 88 | PanHead: function(type, length, fit, options = {}) { 89 | debug('PanHead', type, length, fit, options); 90 | var [headDiameter, headLength, diameter, tap, countersink] = type; 91 | return PanHeadScrew( 92 | headDiameter, 93 | headLength, 94 | diameter, 95 | length, 96 | options.clearLength, 97 | options 98 | ); 99 | }, 100 | 101 | FlatHead: function(type, length, fit, options = {}) { 102 | debug('FlatHead', type, length, fit, options); 103 | var [headDiameter, headLength, diameter, tap, countersink] = type; 104 | return FlatHeadScrew( 105 | headDiameter, 106 | headLength, 107 | diameter, 108 | length, 109 | options.clearLength, 110 | options 111 | ); 112 | } 113 | // HexHead: ScrewType(PanHeadScrew, ...args) 114 | }; 115 | 116 | export const Clearances = { 117 | tap: util.inch(-0.049), 118 | close: util.inch(0.007), 119 | loose: util.inch(0.016) 120 | }; 121 | 122 | export const Orientation = { 123 | up: { 124 | head: 'outside-', 125 | clear: 'inside+' 126 | }, 127 | down: { 128 | head: 'outside+', 129 | clear: 'inside-' 130 | } 131 | }; 132 | 133 | export function CreateScrew(head, thread, headClearSpace, options = {}) { 134 | console.warn('head', head); 135 | options = Object.assign(options, { 136 | orientation: 'up', 137 | clearance: [0, 0, 0] 138 | }); 139 | var orientation = Orientation[options.orientation]; 140 | var group = Group('head,thread', { 141 | head: head.color('gray'), 142 | thread: thread.snap(head, 'z', orientation.head).color('silver') 143 | }); 144 | 145 | if (headClearSpace) { 146 | group.add( 147 | headClearSpace 148 | .enlarge(options.clearance) 149 | .snap(head, 'z', orientation.clear) 150 | .color('red'), 151 | 'headClearSpace', 152 | true 153 | ); 154 | } 155 | 156 | return group; 157 | } 158 | 159 | /** 160 | * Creates a `Group` object with a Pan Head Screw. 161 | * @param {number} headDiameter Diameter of the head of the screw 162 | * @param {number} headLength Length of the head 163 | * @param {number} diameter Diameter of the threaded shaft 164 | * @param {number} length Length of the threaded shaft 165 | * @param {number} clearLength Length of the clearance section of the head. 166 | * @param {object} options Screw options include orientation and clerance scale. 167 | */ 168 | export function PanHeadScrew( 169 | headDiameter, 170 | headLength, 171 | diameter, 172 | length, 173 | clearLength, 174 | options 175 | ) { 176 | var head = Parts.Cylinder(headDiameter, headLength); 177 | var thread = Parts.Cylinder(diameter, length); 178 | 179 | if (clearLength) { 180 | var headClearSpace = Parts.Cylinder(headDiameter, clearLength); 181 | } 182 | 183 | return CreateScrew(head, thread, headClearSpace, options); 184 | } 185 | 186 | /** 187 | * Creates a `Group` object with a Hex Head Screw. 188 | * @param {number} headDiameter Diameter of the head of the screw 189 | * @param {number} headLength Length of the head 190 | * @param {number} diameter Diameter of the threaded shaft 191 | * @param {number} length Length of the threaded shaft 192 | * @param {number} clearLength Length of the clearance section of the head. 193 | * @param {object} options Screw options include orientation and clerance scale. 194 | */ 195 | export function HexHeadScrew( 196 | headDiameter, 197 | headLength, 198 | diameter, 199 | length, 200 | clearLength, 201 | options 202 | ) { 203 | debug( 204 | 'HexHeadScrew', 205 | headDiameter, 206 | headLength, 207 | diameter, 208 | length, 209 | clearLength, 210 | options 211 | ); 212 | var head = Parts.Hexagon(headDiameter, headLength); 213 | var thread = Parts.Cylinder(diameter, length); 214 | 215 | if (clearLength) { 216 | var headClearSpace = Parts.Hexagon(headDiameter, clearLength); 217 | } 218 | 219 | return CreateScrew(head, thread, headClearSpace, options); 220 | } 221 | 222 | /** 223 | * Create a Flat Head Screw 224 | * @param {number} headDiameter head diameter 225 | * @param {number} headLength head length 226 | * @param {number} diameter thread diameter 227 | * @param {number} length thread length 228 | * @param {number} clearLength clearance length 229 | * @param {object} options options 230 | */ 231 | export function FlatHeadScrew( 232 | headDiameter, 233 | headLength, 234 | diameter, 235 | length, 236 | clearLength, 237 | options 238 | ) { 239 | var a = headDiameter; 240 | var b = diameter; 241 | if (options && options.orientation == 'down') { 242 | a = diameter; 243 | b = headDiameter; 244 | } 245 | var head = Parts.Cone(a, b, headLength); 246 | // var head = Parts.Cylinder(headDiameter, headLength); 247 | var thread = Parts.Cylinder(diameter, length); 248 | 249 | if (clearLength) { 250 | var headClearSpace = Parts.Cylinder(headDiameter, clearLength); 251 | } 252 | 253 | return CreateScrew(head, thread, headClearSpace, options); 254 | } 255 | -------------------------------------------------------------------------------- /v1/jscad-hardware.jscad: -------------------------------------------------------------------------------- 1 | /* exported Hardware */ 2 | 3 | /** 4 | * A gear moduel for openJSCAD. 5 | * ![parts example](jsdoc2md/hexagon.png) 6 | * @example 7 | *include('jscad-utils-color.jscad'); 8 | * 9 | *function mainx(params) { 10 | * util.init(CSG); 11 | * 12 | * // draws a blue hexagon 13 | * return Parts.Hexagon(10, 5).color('blue'); 14 | *} 15 | * @type {Object} 16 | * @module jscad-hardware 17 | * @exports Hardware 18 | */ 19 | Hardware = { 20 | Bolt: function Bolt(length, bolt, fit, BOM) { 21 | fit = fit || 'loose'; 22 | 23 | if (BOM) { 24 | // Keep track of bolts for bill-of-materials 25 | var bomkey = `${bolt.name} - ${util.cm(length).toFixed(2)}`; 26 | if (!BOM[bomkey]) BOM[bomkey] = 0; 27 | BOM[bomkey]++; 28 | } 29 | var b = Parts.Hardware[bolt.type](bolt.G || bolt.D, bolt.H, bolt.E, length); 30 | 31 | var clearance = bolt[fit] - bolt.E; 32 | 33 | b.add( 34 | Parts.Hardware 35 | [bolt.type]( 36 | (bolt.G || bolt.D) + clearance, 37 | bolt.H + clearance, 38 | bolt[fit], 39 | length, 40 | length 41 | ) 42 | .map(part => part.color('red')), 43 | 'tap', 44 | false, 45 | 'tap-' 46 | ); 47 | 48 | return b; 49 | }, 50 | 51 | /** 52 | * Create a washer group from a washer type. 53 | * @param {Object} washer Washer type object. 54 | * @param {String} fit Clearance to add to group (tap|close|loose). 55 | */ 56 | Washer: function Washer(washer, fit) { 57 | var w = util.group(); 58 | w.add( 59 | Parts.Tube(washer.od, washer.id, washer.thickness).color('gray'), 60 | 'washer' 61 | ); 62 | if (fit) { 63 | var tap = Hardware.Clearances[fit]; 64 | if (!tap) 65 | console.error( 66 | `Hardware.Washer unknown fit clearance ${fit}, should be ${Object.keys( 67 | Hardware.Clarances 68 | ).join('|')}` 69 | ); 70 | w.add( 71 | Parts.Cylinder( 72 | washer.od + Hardware.Clearances[fit], 73 | washer.thickness 74 | ).color('red'), 75 | 'clearance' 76 | ); 77 | } 78 | return w; 79 | }, 80 | 81 | Nut: function Nut(nut, fit) { 82 | return Parts.Hexagon(nut[1] + Hardware.Clearances[fit], nut[2]); 83 | }, 84 | 85 | Screw: { 86 | PanHead: function(type, length, fit, options = {}) { 87 | var [headDiameter, headLength, diameter, tap, countersink] = type; 88 | return Hardware.PanHeadScrew( 89 | headDiameter, 90 | headLength, 91 | diameter, 92 | length, 93 | options.clearLength, 94 | options 95 | ); 96 | }, 97 | 98 | FlatHead: function(type, length, fit, options = {}) { 99 | var [headDiameter, headLength, diameter, tap, countersink] = type; 100 | return Hardware.FlatHeadScrew( 101 | headDiameter, 102 | headLength, 103 | diameter, 104 | length, 105 | options.clearLength, 106 | options 107 | ); 108 | } 109 | // HexHead: Hardware.ScrewType(Hardware.PanHeadScrew, ...args) 110 | }, 111 | 112 | Clearances: { 113 | tap: util.inch(-0.049), 114 | close: util.inch(0.007), 115 | loose: util.inch(0.016) 116 | }, 117 | 118 | Orientation: { 119 | up: { 120 | head: 'outside-', 121 | clear: 'inside+' 122 | }, 123 | down: { 124 | head: 'outside+', 125 | clear: 'inside-' 126 | } 127 | }, 128 | 129 | CreateScrew: function(head, thread, headClearSpace, options) { 130 | options = util.defaults(options, { 131 | orientation: 'up', 132 | clearance: [0, 0, 0] 133 | }); 134 | 135 | var orientation = Parts.Hardware.Orientation[options.orientation]; 136 | var group = util.group('head,thread', { 137 | head: head.color('gray'), 138 | thread: thread.snap(head, 'z', orientation.head).color('silver') 139 | }); 140 | 141 | if (headClearSpace) { 142 | group.add( 143 | headClearSpace 144 | .enlarge(options.clearance) 145 | .snap(head, 'z', orientation.clear) 146 | .color('red'), 147 | 'headClearSpace', 148 | true 149 | ); 150 | } 151 | 152 | return group; 153 | }, 154 | 155 | /** 156 | * Creates a `Group` object with a Pan Head Screw. 157 | * @param {number} headDiameter Diameter of the head of the screw 158 | * @param {number} headLength Length of the head 159 | * @param {number} diameter Diameter of the threaded shaft 160 | * @param {number} length Length of the threaded shaft 161 | * @param {number} clearLength Length of the clearance section of the head. 162 | * @param {object} options Screw options include orientation and clerance scale. 163 | */ 164 | PanHeadScrew: function( 165 | headDiameter, 166 | headLength, 167 | diameter, 168 | length, 169 | clearLength, 170 | options 171 | ) { 172 | var head = Parts.Cylinder(headDiameter, headLength); 173 | var thread = Parts.Cylinder(diameter, length); 174 | 175 | if (clearLength) { 176 | var headClearSpace = Parts.Cylinder(headDiameter, clearLength); 177 | } 178 | 179 | return Hardware.CreateScrew(head, thread, headClearSpace, options); 180 | }, 181 | 182 | /** 183 | * Creates a `Group` object with a Hex Head Screw. 184 | * @param {number} headDiameter Diameter of the head of the screw 185 | * @param {number} headLength Length of the head 186 | * @param {number} diameter Diameter of the threaded shaft 187 | * @param {number} length Length of the threaded shaft 188 | * @param {number} clearLength Length of the clearance section of the head. 189 | * @param {object} options Screw options include orientation and clerance scale. 190 | */ 191 | HexHeadScrew: function( 192 | headDiameter, 193 | headLength, 194 | diameter, 195 | length, 196 | clearLength, 197 | options 198 | ) { 199 | var head = Parts.Hexagon(headDiameter, headLength); 200 | var thread = Parts.Cylinder(diameter, length); 201 | 202 | if (clearLength) { 203 | var headClearSpace = Parts.Hexagon(headDiameter, clearLength); 204 | } 205 | 206 | return Hardware.CreateScrew(head, thread, headClearSpace, options); 207 | }, 208 | 209 | /** 210 | * Create a Flat Head Screw 211 | * @param {number} headDiameter head diameter 212 | * @param {number} headLength head length 213 | * @param {number} diameter thread diameter 214 | * @param {number} length thread length 215 | * @param {number} clearLength clearance length 216 | * @param {object} options options 217 | */ 218 | FlatHeadScrew: function( 219 | headDiameter, 220 | headLength, 221 | diameter, 222 | length, 223 | clearLength, 224 | options 225 | ) { 226 | var a = headDiameter; 227 | var b = diameter; 228 | if (options && options.orientation == 'down') { 229 | a = diameter; 230 | b = headDiameter; 231 | } 232 | var head = Parts.Cone(a, b, headLength); 233 | // var head = Parts.Cylinder(headDiameter, headLength); 234 | var thread = Parts.Cylinder(diameter, length); 235 | 236 | if (clearLength) { 237 | var headClearSpace = Parts.Cylinder(headDiameter, clearLength); 238 | } 239 | 240 | return Hardware.CreateScrew(head, thread, headClearSpace, options); 241 | } 242 | }; 243 | -------------------------------------------------------------------------------- /src/metric.js: -------------------------------------------------------------------------------- 1 | import { util, Debug } from '@jwc/jscad-utils'; 2 | const debug = Debug('jscadHardware:metric'); 3 | /* exported MetricBolts, MetricScrews, MetricNuts */ 4 | 5 | const ScrewTapSizes = `m1.5 0.35 1.15 56 1.25 55 1.60 1/16 1.65 52 6 | m1.6 0.35 1.25 55 1.35 54 1.70 51 1.75 50 7 | m1.8 0.35 1.45 53 1.55 1/16 1.90 49 2.00 5/64 8 | m2 0.45 1.55 1/16 1.70 51 2.10 45 2.20 44 9 | m2.2 0.45 1.75 50 1.90 48 2.30 3/32 2.40 41 10 | m2.5 0.45 2.05 46 2.20 44 2.65 37 2.75 7/64 11 | m3 0.60 2.40 41 2.60 37 3.15 1/8 3.30 30 12 | m3.5 0.60 2.90 32 3.10 31 3.70 27 3.85 24 13 | m4 0.75 3.25 30 3.50 28 4.20 19 4.40 17 14 | m4.5 0.75 3.75 25 4.00 22 4.75 13 5.00 9 15 | m5 0.90 4.10 20 4.40 17 5.25 5 5.50 7/32 16 | m5.5 0.90 4.60 14 4.90 10 5.80 1 6.10 B 17 | m6 1.00 5.00 8 5.40 4 6.30 E 6.60 G 18 | m7 1.00 6.00 B 6.40 E 7.40 L 7.70 N 19 | m8 1.25 6.80 H 7.20 J 8.40 Q 8.80 S 20 | m9 1.25 7.80 N 8.20 P 9.50 3/8 9.90 25/64 21 | m10 1.25 8.80 11/32 9.20 23/64 10.50 Z 11.00 7/16 22 | m11 1.50 9.50 3/8 10.00 X 11.60 29/64 12.10 15/32 23 | m12 1.50 10.50 Z 11.00 7/16 12.60 1/2 13.20 33/64 24 | m14 1.50 12.50 1/2 13.00 33/64 14.75 37/64 15.50 39/64 25 | m15 1.50 13.50 17/32 14.00 35/64 15.75 5/8 16.50 21/32 26 | m16 2.00 14.00 35/64 14.75 37/64 16.75 21/32 17.50 11/16 27 | m17 1.50 15.50 39/64 16.00 5/8 18.00 45/64 18.50 47/64 28 | m18 2.00 16.00 5/8 16.75 21/32 19.00 3/4 20.00 25/32 29 | m19 2.50 16.50 21/32 17.50 11/16 20.00 25/32 21.00 53/64 30 | m20 2.00 18.00 45/64 18.50 47/64 21.00 53/64 22.00 55/64` 31 | .split('\n') 32 | .reduce((bolts, line, index) => { 33 | var params = line.split(' '); 34 | var name = `${params[0]}`; 35 | bolts[name] = { 36 | name, 37 | tap: parseFloat(params[2]), 38 | close: parseFloat(params[6]), 39 | loose: parseFloat(params[8]) 40 | }; 41 | return bolts; 42 | }, {}); 43 | 44 | debug('ScrewTapSizes', ScrewTapSizes); 45 | 46 | /** 47 | * @see http://www.atlrod.com/metric-hex-bolt-dimensions/ 48 | * 49 | * E - Body Diameter 50 | * F - Width Across Flats 51 | * G - Width Across Corners 52 | * H - Head Height 53 | * D - Head Diameter 54 | * 55 | * NOMINAL SIZE (D) BODY DIAMETER HEAD THICKNESS ACROSS THE FLATS ACROSS CORNERS 56 | */ 57 | const MetricHexBoltDimensions = `m10 10.00 9.78 6.63 6.17 17.00 15.73 18.48 17.77 58 | m12 12.00 11.73 7.76 4.24 19.00 17.73 20.78 20.03 59 | m14 14.00 13.73 9.09 8.51 22.00 20.67 24.25 23.35 60 | m16 16.00 15.73 10.32 9.68 24.00 23.67 27.71 26.75 61 | m20 20.00 19.67 12.88 12.12 30.00 29.16 34.64 32.95 62 | m24 24.00 23.67 15.44 14.56 36.00 35.00 41.57 39.55 63 | m30 30.00 29.67 19.48 17.92 46.00 45.00 53.12 50.85 64 | m36 36.00 35.61 23.38 21.63 55.00 53.80 63.51 60.79 65 | m42 42.00 41.38 26.97 25.03 65.00 62.90 75.06 71.71 66 | m48 48.00 47.38 31.07 28.93 75.00 72.60 86.60 82.76 67 | m56 56.00 55.26 36.2 33.80 85.00 82.20 98.15 93.71 68 | m64 64.00 63.26 41.32 38.68 95.00 91.80 109.70 104.65 69 | m72 72.00 71.26 46.45 43.55 105.00 101.40 121.24 115.60 70 | m80 80.00 79.26 51.58 48.42 115.00 111.00 132.72 126.54 71 | m90 90.00 89.13 57.74 54.26 130.00 125.50 150.11 143.07 72 | m100 90.00 99.13 63.9 60.10 145.00 140.00 167.43 159.60` 73 | .split('\n') 74 | .reduce((bolts, line) => { 75 | var params = line.split('\t'); 76 | var name = `${params[0]} hex`; 77 | var tap = ScrewTapSizes[params[0]] || { 78 | tap: parseFloat(params[1]), 79 | close: parseFloat(params[1]), 80 | loose: parseFloat(params[1]) 81 | }; 82 | bolts[name] = { 83 | ...tap, 84 | name, 85 | E: parseFloat(params[1]), 86 | F: parseFloat(params[5]), 87 | G: parseFloat(params[7]), 88 | H: parseFloat(params[3]), 89 | type: 'HexHeadScrew' 90 | }; 91 | return bolts; 92 | }, {}); 93 | 94 | debug('MetricHexBoltDimensions', MetricHexBoltDimensions); 95 | 96 | /** 97 | * @see https://www.fastenal.com/content/product_specifications/M.SHCS.4762.8.8.Z.pdf 98 | * 99 | * Nominal Size (d), Body Diameter Max, min, Head Diameter max, min, Head Height max, min, Socket Size max, min, Key Engagement min 100 | * 101 | * E - Body Diameter 102 | * H - Head Height 103 | * D - Head Diameter 104 | */ 105 | const SocketCapScrewDimensions = `m1.6 1.60 1.46 3.14 2.86 1.60 1.46 1.58 1.52 0.7 106 | m2 2.00 1.86 3.98 3.62 2.00 1.86 1.58 1.52 1 107 | m2.5 2.50 2.36 4.68 4.32 2.50 2.36 2.08 2.02 1.1 108 | m3 3.00 2.86 5.68 5.32 3.00 2.86 2.58 2.52 1.3 109 | m4 4.00 3.82 7.22 6.78 4.00 3.82 3.08 3.02 2 110 | m5 5.00 4.82 8.72 8.28 5.00 4.82 4.095 4.020 2.5 111 | m6 6.00 5.82 10.22 9.78 6.00 5.70 5.14 5.02 3 112 | m8 8.00 7.78 13.27 12.73 8.00 7.64 6.14 6.02 4 113 | m10 10.00 9.78 16.27 15.73 10.00 9.64 8.175 8.025 5 114 | m12 12.00 11.73 18.27 17.73 12.00 11.57 10.175 10.025 6 115 | m14 14.00 13.73 21.33 20.67 14.00 13.57 12.212 12.032 7 116 | m16 16.00 15.73 24.33 23.67 16.00 15.57 14.212 14.032 8 117 | m20 20.00 19.67 30.33 29.67 20.00 19.48 17.23 17.05 10 118 | m24 24.00 23.67 36.39 35.61 24.00 23.48 19.275 19.065 12 119 | m30 30.00 29.67 45.39 44.61 30.00 29.48 22.275 22.065 15.5 120 | m36 36.00 35.61 54.46 53.54 36.00 35.38 27.275 27.065 19 121 | m42 42.00 41.61 63.46 62.54 42.00 41.38 32.33 32.08 24` 122 | .split('\n') 123 | .reduce((screws, line, index) => { 124 | var params = line.split(' '); 125 | var name = `${params[0]} socket`; 126 | var tap = ScrewTapSizes[params[0]] || { 127 | tap: parseFloat(params[1]), 128 | close: parseFloat(params[1]), 129 | loose: parseFloat(params[1]) 130 | }; 131 | screws[name] = { 132 | ...tap, 133 | name, 134 | E: parseFloat(params[1]), 135 | H: parseFloat(params[5]), 136 | D: parseFloat(params[3]), 137 | type: 'PanHeadScrew' 138 | }; 139 | return screws; 140 | }, {}); 141 | 142 | debug('SocketCapScrewDimensions', SocketCapScrewDimensions); 143 | 144 | /** 145 | * http://www.atlrod.com/metric-hex-bolt-dimensions/ 146 | * E - Body Diameter (D) 147 | * F - Width Across Flats 148 | * G - Width Across Corners (C) 149 | * H - Head Height 150 | * D - Head Diameter 151 | * 152 | * tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 153 | * @type {Object} 154 | */ 155 | export const MetricBolts = { 156 | ...MetricHexBoltDimensions, 157 | ...SocketCapScrewDimensions 158 | // 'm10 hex': { 159 | // E: 10, // 10-9.78 160 | // tap: 8.5, 161 | // close: 10.5, 162 | // loose: 11, 163 | // H: 6.5, // 6.63-6.17 164 | // G: 18, // 18.48-17.77 165 | // F: 17, // 17-15.73 166 | // type: 'HexHeadScrew' 167 | // }, 168 | // 'm12 hex': { 169 | // E: 12, // 12-11.73 170 | // tap: 10.3, 171 | // close: 12.6, 172 | // loose: 13.2, 173 | // H: 7.5, // 7.76-4.24 174 | // G: 20, // 20.78-20.03 175 | // F: 19, // 19-17.73 176 | // type: 'HexHeadScrew' 177 | // } 178 | }; 179 | 180 | // headDiameter, headLength, diameter, tap, countersink 181 | export const MetricScrews = { 182 | m4: [8, 3.1, 4] 183 | }; 184 | 185 | /** 186 | * Dimensions of nuts for imperial bolts. 187 | * F is the width across the faces, C is the width 188 | * across the points, and H is the height. D is the 189 | * basic diameter. 190 | * 191 | * [F, C, H, D] 192 | * 193 | * @see https://en.wikipedia.org/wiki/Nut_(hardware) 194 | * @type {Object} 195 | */ 196 | export const MetricNuts = { 197 | m4: [7, 8.1, 3.2, 4] 198 | }; 199 | 200 | /** 201 | * Metric washer sizes 202 | * Size Inside Diameter Outside Diameter Thickness 203 | * @see https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx 204 | * @type {Object} 205 | */ 206 | export const MetricWashers = `M1 1.1mm 3.2mm 0.3mm 207 | M1.2 1.3mm 3.8mm 0.3mm 208 | M1.4 1.5mm 3.8mm 0.3mm 209 | M1.6 1.7mm 4.0mm 0.3mm 210 | M2 2.2mm 5.0mm 0.3mm 211 | M2.5 2.7mm 6.0mm 0.5mm 212 | M3 3.2mm 7.0mm 0.5mm 213 | M3.5 3.7mm 8.0mm 0.5mm 214 | M4 4.3mm 9.0mm 0.8mm 215 | M5 5.3mm 10mm 1mm 216 | M6 6.4mm 12mm 1.6mm 217 | M7 7.4mm 14mm 1.6mm 218 | M8 8.4mm 16mm 1.6mm 219 | M10 10.5mm 20mm 2.0mm 220 | M11 12mm 24mm 2.5mm 221 | M12 13mm 24mm 2.5mm 222 | M14 15mm 28mm 2.5mm 223 | M16 17mm 30mm 3.0mm 224 | M18 19mm 34mm 3.0mm 225 | M20 21mm 37mm 3.0mm` 226 | .split('\n') 227 | .reduce(function ParseWasher(washers, line) { 228 | const [size, id, od, thickness] = line 229 | .replace(/mm/g, '') 230 | .split('\t') 231 | .map(function parseValues(field, index) { 232 | return index == 0 ? field : parseFloat(field); 233 | }); 234 | washers[size] = { size, id, od, thickness }; 235 | return washers; 236 | }, {}); 237 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/code/hardware.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | hardware 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

hardware

jscad-hardware : Object

A gear moduel for openJSCAD. 15 | parts example

Example

include('jscad-utils-color.jscad');
16 | 
17 | function mainx(params) {
18 |   util.init(CSG);
19 | 
20 |   // draws a blue hexagon
21 |   return Parts.Hexagon(10, 5).color('blue');
22 | }
23 | 

jscad-hardware.Washer(washer, fit)

Create a washer group from a washer type.

Kind: static method of jscad-hardware

Param Type Description
washer Object Washer type object.
fit String Clearance to add to group (tap

jscad-hardware.PanHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)

Creates a Group object with a Pan Head Screw.

Kind: static method of jscad-hardware

Param Type Description
headDiameter number Diameter of the head of the screw
headLength number Length of the head
diameter number Diameter of the threaded shaft
length number Length of the threaded shaft
clearLength number Length of the clearance section of the head.
options object Screw options include orientation and clerance scale.

jscad-hardware.HexHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)

Creates a Group object with a Hex Head Screw.

Kind: static method of jscad-hardware

Param Type Description
headDiameter number Diameter of the head of the screw
headLength number Length of the head
diameter number Diameter of the threaded shaft
length number Length of the threaded shaft
clearLength number Length of the clearance section of the head.
options object Screw options include orientation and clerance scale.

jscad-hardware.FlatHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)

Create a Flat Head Screw

Kind: static method of jscad-hardware

Param Type Description
headDiameter number head diameter
headLength number head length
diameter number thread diameter
length number thread length
clearLength number clearance length
options object options
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /githubdocs/themes/architect/images/hr.png: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Page not found · GitHub Pages 7 | 50 | 51 | 52 | 53 |
54 | 55 |

404

56 |

File not found

57 | 58 |

59 | The site configured at this address does not 60 | contain the requested file. 61 |

62 | 63 |

64 | If this is your site, make sure that the filename case matches the URL.
65 | For root URLs (like http://example.com/) you must provide an 66 | index.html file. 67 |

68 | 69 |

70 | Read the full documentation 71 | for more information about using GitHub Pages. 72 |

73 | 74 |
75 | GitHub Status — 76 | @githubstatus 77 |
78 | 79 | 82 | 83 | 86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/js/6.4b3ce8a0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[6],{267:function(e,t,a){"use strict";a.r(t);var r=a(38),d=Object(r.a)({},function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"hardware"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#hardware","aria-hidden":"true"}},[e._v("#")]),e._v(" hardware")]),e._v(" "),a("p",[a("a",{attrs:{name:"module_jscad-hardware"}})]),e._v(" "),a("h2",{attrs:{id:"jscad-hardware-object"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jscad-hardware-object","aria-hidden":"true"}},[e._v("#")]),e._v(" jscad-hardware : "),a("code",[e._v("Object")])]),e._v(" "),a("p",[e._v("A gear moduel for openJSCAD.\n"),a("img",{attrs:{src:"jsdoc2md/hexagon.png",alt:"parts example"}})]),e._v(" "),a("p",[a("strong",[e._v("Example")])]),e._v(" "),a("div",{staticClass:"language-js extra-class"},[a("pre",{pre:!0,attrs:{class:"language-js"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("include")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v("'jscad-utils-color.jscad'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("function")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("mainx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[e._v("params")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n util"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[e._v("CSG")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// draws a blue hexagon")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("return")]),e._v(" Parts"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Hexagon")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("color")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v("'blue'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),a("ul",[a("li",[a("a",{attrs:{href:"#module_jscad-hardware"}},[e._v("jscad-hardware")]),e._v(" : "),a("code",[e._v("Object")]),e._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"#module_jscad-hardware.Washer"}},[e._v(".Washer(washer, fit)")])]),e._v(" "),a("li",[a("a",{attrs:{href:"#module_jscad-hardware.PanHeadScrew"}},[e._v(".PanHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")])]),e._v(" "),a("li",[a("a",{attrs:{href:"#module_jscad-hardware.HexHeadScrew"}},[e._v(".HexHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")])]),e._v(" "),a("li",[a("a",{attrs:{href:"#module_jscad-hardware.FlatHeadScrew"}},[e._v(".FlatHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")])])])])]),e._v(" "),a("p",[a("a",{attrs:{name:"module_jscad-hardware.Washer"}})]),e._v(" "),a("h3",{attrs:{id:"jscad-hardware-washer-washer-fit"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jscad-hardware-washer-washer-fit","aria-hidden":"true"}},[e._v("#")]),e._v(" jscad-hardware.Washer(washer, fit)")]),e._v(" "),a("p",[e._v("Create a washer group from a washer type.")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": static method of "),a("a",{attrs:{href:"#module_jscad-hardware"}},[a("code",[e._v("jscad-hardware")])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Param")]),e._v(" "),a("th",[e._v("Type")]),e._v(" "),a("th",[e._v("Description")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("washer")]),e._v(" "),a("td",[a("code",[e._v("Object")])]),e._v(" "),a("td",[e._v("Washer type object.")])]),e._v(" "),a("tr",[a("td",[e._v("fit")]),e._v(" "),a("td",[a("code",[e._v("String")])]),e._v(" "),a("td",[e._v("Clearance to add to group (tap")])])])]),e._v(" "),a("p",[a("a",{attrs:{name:"module_jscad-hardware.PanHeadScrew"}})]),e._v(" "),a("h3",{attrs:{id:"jscad-hardware-panheadscrew-headdiameter-headlength-diameter-length-clearlength-options"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jscad-hardware-panheadscrew-headdiameter-headlength-diameter-length-clearlength-options","aria-hidden":"true"}},[e._v("#")]),e._v(" jscad-hardware.PanHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")]),e._v(" "),a("p",[e._v("Creates a "),a("code",[e._v("Group")]),e._v(" object with a Pan Head Screw.")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": static method of "),a("a",{attrs:{href:"#module_jscad-hardware"}},[a("code",[e._v("jscad-hardware")])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Param")]),e._v(" "),a("th",[e._v("Type")]),e._v(" "),a("th",[e._v("Description")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("headDiameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Diameter of the head of the screw")])]),e._v(" "),a("tr",[a("td",[e._v("headLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the head")])]),e._v(" "),a("tr",[a("td",[e._v("diameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Diameter of the threaded shaft")])]),e._v(" "),a("tr",[a("td",[e._v("length")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the threaded shaft")])]),e._v(" "),a("tr",[a("td",[e._v("clearLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the clearance section of the head.")])]),e._v(" "),a("tr",[a("td",[e._v("options")]),e._v(" "),a("td",[a("code",[e._v("object")])]),e._v(" "),a("td",[e._v("Screw options include orientation and clerance scale.")])])])]),e._v(" "),a("p",[a("a",{attrs:{name:"module_jscad-hardware.HexHeadScrew"}})]),e._v(" "),a("h3",{attrs:{id:"jscad-hardware-hexheadscrew-headdiameter-headlength-diameter-length-clearlength-options"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jscad-hardware-hexheadscrew-headdiameter-headlength-diameter-length-clearlength-options","aria-hidden":"true"}},[e._v("#")]),e._v(" jscad-hardware.HexHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")]),e._v(" "),a("p",[e._v("Creates a "),a("code",[e._v("Group")]),e._v(" object with a Hex Head Screw.")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": static method of "),a("a",{attrs:{href:"#module_jscad-hardware"}},[a("code",[e._v("jscad-hardware")])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Param")]),e._v(" "),a("th",[e._v("Type")]),e._v(" "),a("th",[e._v("Description")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("headDiameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Diameter of the head of the screw")])]),e._v(" "),a("tr",[a("td",[e._v("headLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the head")])]),e._v(" "),a("tr",[a("td",[e._v("diameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Diameter of the threaded shaft")])]),e._v(" "),a("tr",[a("td",[e._v("length")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the threaded shaft")])]),e._v(" "),a("tr",[a("td",[e._v("clearLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("Length of the clearance section of the head.")])]),e._v(" "),a("tr",[a("td",[e._v("options")]),e._v(" "),a("td",[a("code",[e._v("object")])]),e._v(" "),a("td",[e._v("Screw options include orientation and clerance scale.")])])])]),e._v(" "),a("p",[a("a",{attrs:{name:"module_jscad-hardware.FlatHeadScrew"}})]),e._v(" "),a("h3",{attrs:{id:"jscad-hardware-flatheadscrew-headdiameter-headlength-diameter-length-clearlength-options"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jscad-hardware-flatheadscrew-headdiameter-headlength-diameter-length-clearlength-options","aria-hidden":"true"}},[e._v("#")]),e._v(" jscad-hardware.FlatHeadScrew(headDiameter, headLength, diameter, length, clearLength, options)")]),e._v(" "),a("p",[e._v("Create a Flat Head Screw")]),e._v(" "),a("p",[a("strong",[e._v("Kind")]),e._v(": static method of "),a("a",{attrs:{href:"#module_jscad-hardware"}},[a("code",[e._v("jscad-hardware")])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Param")]),e._v(" "),a("th",[e._v("Type")]),e._v(" "),a("th",[e._v("Description")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("headDiameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("head diameter")])]),e._v(" "),a("tr",[a("td",[e._v("headLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("head length")])]),e._v(" "),a("tr",[a("td",[e._v("diameter")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("thread diameter")])]),e._v(" "),a("tr",[a("td",[e._v("length")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("thread length")])]),e._v(" "),a("tr",[a("td",[e._v("clearLength")]),e._v(" "),a("td",[a("code",[e._v("number")])]),e._v(" "),a("td",[e._v("clearance length")])]),e._v(" "),a("tr",[a("td",[e._v("options")]),e._v(" "),a("td",[a("code",[e._v("object")])]),e._v(" "),a("td",[e._v("options")])])])])])},[],!1,null,null,null);t.default=d.exports}}]); -------------------------------------------------------------------------------- /src/imperial.js: -------------------------------------------------------------------------------- 1 | import { util, Debug } from '@jwc/jscad-utils'; 2 | const debug = Debug('jscadHardware:imperial'); 3 | 4 | /* exported ImperialBolts, ImperialWashers */ 5 | 6 | function parseImperial(field) { 7 | var value = [/(\d+)-(\d+)\/(\d+)/, /(\d+)\/(\d+)/, /(\d+)/].reduce( 8 | function parseImperial(value, re, idx) { 9 | if (!value) { 10 | var match = field.match(re); 11 | if (match && idx == 0) 12 | value = parseInt(match[1]) + parseInt(match[2]) / parseInt(match[3]); 13 | 14 | if (match && idx == 1) value = parseInt(match[1]) / parseInt(match[2]); 15 | 16 | if (match && idx == 2) value = parseInt(match[1]); 17 | } 18 | return value; 19 | }, 20 | undefined 21 | ); 22 | return util.inch(value); 23 | } 24 | 25 | function parseValues(field, index) { 26 | if (index == 0) return field; 27 | if (field == '-') return; 28 | return parseImperial(field); 29 | } 30 | 31 | const ScrewTapSizes = `0 .0600 80 .0447 3/64 .0469 55 .0520 52 .0635 50 .0700 32 | 1 .0730 64 .0538 53 .0595 1/16 .0625 48 .0760 46 .0810 33 | 2 .0860 56 .0641 50 .0700 49 .0730 43 .0890 41 .0960 34 | 3 .0990 48 .0734 47 .0785 44 .0860 37 .1040 35 .1100 35 | 4 .1120 40 .0813 43 .0890 41 .0960 32 .1160 30 .1285 36 | 5 .125 40 .0943 38 .1015 7/64 .1094 30 .1285 29 .1360 37 | 6 .138 32 .0997 36 .1065 32 .1160 27 .1440 25 .1495 38 | 8 .1640 32 .1257 29 .1360 27 .1440 18 .1695 16 .1770 39 | 10 .1900 24 .1389 25 .1495 20 .1610 9 .1960 7 .2010 40 | 12 .2160 24 .1649 16 .1770 12 .1890 2 .2210 1 .2280 41 | 1/4 .2500 20 .1887 7 .2010 7/32 .2188 F .2570 H .2660 42 | 5/16 .3125 18 .2443 F .2570 J .2770 P .3230 Q .3320 43 | 3/8 .3750 16 .2983 5/16 .3125 Q .3320 W .3860 X .3970 44 | 7/16 .4375 14 .3499 U .3680 25/64 .3906 29/64 .4531 15/32 .4687 45 | 1/2 .5000 13 .4056 27/64 .4219 29/64 .4531 33/64 .5156 17/32 .5312 46 | 9/16 .5625 12 .4603 31/64 .4844 33/64 .5156 37/64 .5781 19/32 .5938 47 | 5/8 .6250 11 .5135 17/32 .5312 9/16 .5625 41/64 .6406 21/32 .6562 48 | 11/16 .6875 24 .6364 41/64 .6406 21/32 .6562 45/64 .7031 23/32 .7188 49 | 3/4 .7500 10 .6273 21/32 .6562 11/16 .6875 49/64 .7656 25/32 .7812 50 | 13/16 .8125 20 .7512 49/64 .7656 25/32 .7812 53/64 .8281 27/32 .8438 51 | 7/8 .8750 9 .7387 49/64 .7656 51/64 .7969 57/64 .8906 29/32 .9062 52 | 15/16 .9375 20 .8762 57/64 .8906 29/32 .9062 61/64 .9531 31/32 .9688 53 | 1 1.000 8 .8466 7/8 .8750 59/64 .9219 1-1/64 1.0156 1-1/32 1.0313` 54 | .split('\n') 55 | .reduce((bolts, line, index) => { 56 | var params = line.split('\t'); 57 | var name = `${index < 10 ? '#' : ''}${params[0]}`; 58 | bolts[name] = { 59 | name, 60 | tap: util.inch(parseFloat(params[5])), 61 | close: util.inch(parseFloat(params[9])), 62 | loose: util.inch(parseFloat(params[11])) 63 | }; 64 | return bolts; 65 | }, {}); 66 | 67 | /** 68 | * Screw Size, Major Diameter, Threads Per Inch, Minor Diameter, Tap Plastic Drill Size, Tap Plastic Decimal Equiv., Tap Steel Drill Size, Tap Steel Decimal Equiv., Close Fit Drill Size, Close Fit Decimal Equiv., Free Fit Drill Size, Free Fit Decimal Equiv. 69 | * 70 | * @see http://www.americanfastener.com/cap-screws/ 71 | * @see https://www.aftfasteners.com/fully-threaded-hex-tap-bolts-dimensions-mechanical-properties/ 72 | * E - Body Diameter 73 | * F - Width Across Flats 74 | * G - Width Across Corners 75 | * H - Head Height 76 | * D - Head Diameter 77 | * 78 | * tap sizes: @see https://littlemachineshop.com/reference/tapdrill.php 79 | * @type {Object} 80 | */ 81 | const HexBoltDimensions = `1/4 7/16 .438 .428 .505 .488 5/32 .163 .150 82 | 5/16 1/2 .500 .489 .577 .557 13/64 .211 .195 83 | 3/8 9/16 .562 .551 .650 .628 15/64 .243 .226 84 | 7/16 5/8 .625 .612 .722 .698 9/32 .291 .272 85 | 1/2 3/4 .750 .736 .866 .840 5/16 .323 .302 86 | 9/16 13/16 .812 .798 .938 .910 23/64 .371 .348 87 | 5/8 15/16 .938 .922 1.083 1.051 25/64 .403 .378 88 | 3/4 1-1/8 1.125 1.100 1.299 1.254 15/32 .483 .455 89 | 7/8 1-5/16 1.312 1.269 1.516 1.447 37/64 .604 .531 90 | 1 1-1/2 1.500 1.450 1.732 1.653 43/64 .700 .591 91 | 1-1/4 1-7/8 1.875 1.812 2.165 2.066 27/32 .876 .749` 92 | .split('\n') 93 | .reduce((bolts, line) => { 94 | var params = line.split('\t'); 95 | var name = `${params[0]} hex`; 96 | var tap = ScrewTapSizes[params[0]] || { 97 | tap: parseImperial(params[0]), 98 | close: parseImperial(params[0]), 99 | loose: parseImperial(params[0]) 100 | }; 101 | bolts[name] = { 102 | ...tap, 103 | name, 104 | E: parseImperial(params[0]), 105 | F: parseImperial(params[1]), 106 | G: util.inch(parseFloat(params[4])), 107 | H: parseImperial(params[6]), 108 | type: 'HexHeadScrew' 109 | }; 110 | return bolts; 111 | }, {}); 112 | 113 | /** 114 | * Socket cap screw dimensions. 115 | * 116 | * E - Body Diameter 117 | * H - Head Height 118 | * D - Head Diameter 119 | * 120 | * @see https://www.aftfasteners.com/socket-cap-screws-dimensions-and-mechanical-properties/ 121 | */ 122 | const SocketCapScrewDimensions = `0 0.0600 0.0568 0.096 0.091 0.060 0.057 0.004 0.050 0.074 0.062 0.025 0.020 0.007 123 | 1 0.0730 0.0695 0.118 0.112 0.073 0.070 0.005 1/16 0.087 0.075 0.031 0.025 0.007 124 | 2 0.0860 0.0822 0.140 0.134 0.086 0.083 0.008 5/64 0.102 0.090 0.038 0.029 0.007 125 | 3 0.0990 0.0949 0.161 0.154 0.099 0.095 0.008 5/64 0.115 0.102 0.044 0.034 0.007 126 | 4 0.1120 0.1075 0.183 0.176 0.112 0.108 0.009 3/832 0.130 0.117 0.051 0.038 0.008 127 | 5 0.1250 0.1202 0.205 0.198 0.125 0.121 0.012 3/32 0.145 0.132 0.057 0.043 0.008 128 | 6 0.1380 0.1329 0.226 0.218 0.138 0.134 0.013 7/64 0.158 0.144 0.064 0.047 0.008 129 | 8 0.1640 0.1585 0.270 0.262 0.164 0.159 0.014 9/64 0.188 0.172 0.077 0.056 0.008 130 | 10 0.1900 0.1840 0.312 0.303 0.207 0.185 0.018 5/32 0.218 0.202 0.090 0.065 0.008 131 | 1/4 0.2500 0.2435 0.375 0.365 0.250 0.244 0.025 3/16 0.278 0.261 0.120 0.095 0.010 132 | 5/16 0.3125 0.3053 0.469 0.457 0.312 0.306 0.033 1/4 0.347 0.329 0.151 0.119 0.010 133 | 3/8 0.3750 0.3678 0.562 0.550 0.375 0.368 0.040 5/16 0.415 0.397 0.182 0.143 0.010 134 | 7/16 0.4375 0.4294 0.656 0.642 0.438 0.430 0.047 3/8 0.484 0.465 0.213 0.166 0.015 135 | 1/2 0.5000 0.4919 0.750 0.735 0.500 0.492 0.055 3/8 0.552 0.531 0.245 0.190 0.015 136 | 5/8 0.6250 0.6163 0.938 0.921 0.625 0.616 0.070 1/2 0.689 0.664 0.307 0.238 0.015 137 | 3/4 0.7500 0.7406 1.125 1.107 0.750 0.740 0.085 5/8 0.828 0.800 0.370 0.285 0.015 138 | 7/8 0.8750 0.8647 1.312 1.293 0.875 0.864 0.100 3/4 0.963 0.932 0.432 0.333 0.020 139 | 1 1.0000 0.9886 1.500 1.479 1.000 0.988 0.114 3/4 1.100 1.068 0.495 0.380 0.020 140 | 1-1/4 1.2500 1.2336 1.875 1.852 1.250 1.236 0.144 7/8 1.370 1.333 0.620 0.475 0.020 141 | 1-1/2 1.5000 1.4818 2.250 2.224 1.500 1.485 0.176 1 1.640 1.601 0.745 0.570 0.020` 142 | .split('\n') 143 | .reduce((screws, line, index) => { 144 | var params = line.split('\t'); 145 | var name = `${index < 9 ? '#' : ''}${params[0]} socket`; 146 | var tap = ScrewTapSizes[params[0]] || { 147 | tap: util.inch(parseFloat(params[3])), 148 | close: util.inch(parseFloat(params[3])), 149 | loose: util.inch(parseFloat(params[3])) 150 | }; 151 | screws[name] = { 152 | ...tap, 153 | name, 154 | E: util.inch(parseFloat(params[1])), 155 | H: util.inch(parseFloat(params[5])), 156 | D: util.inch(parseFloat(params[3])), 157 | type: 'PanHeadScrew' 158 | }; 159 | return screws; 160 | }, {}); 161 | 162 | /** 163 | * http://www.americanfastener.com/cap-screws/ 164 | * E - Body Diameter 165 | * F - Width Across Flats 166 | * G - Width Across Corners 167 | * H - Head Height 168 | * D - Head Diameter 169 | * 170 | * tap sizes: https://littlemachineshop.com/reference/TapDrillSizes.pdf 171 | * @type {Object} 172 | */ 173 | export const ImperialBolts = { 174 | ...HexBoltDimensions, 175 | ...SocketCapScrewDimensions 176 | }; 177 | 178 | /** 179 | * Imperial washer sizes 180 | * Size Inside Diameter Outside Diameter Thickness 181 | * @see https://armstrongmetalcrafts.com/Reference/WasherSizes.aspx 182 | * @see http://almabolt.com/pages/catalog/washers/fender.htm 183 | * @type {Object} 184 | */ 185 | export const ImperialWashers = Object.assign( 186 | `3/16 1/4" 9/16" 3/64" 187 | 1/4 5/16" 3/4" 1/16" 188 | 5/16 3/8" 7/8" 5/64" 189 | 3/8 7/16" 1" 5/64" 190 | 7/16 1/2" 1-1/4" 5/64" 191 | 1/2 9/16" 1-3/8" 7/64" 192 | 9/16 5/8" 1-1/2" 7/64" 193 | 5/8 11/16" 1-3/4" 9/64" 194 | 3/4 13/16" 2" 5/32" 195 | 7/8 15/16" 2-1/4" 1/64" 196 | 1 1-1/16" 2-1/2" 11/64" 197 | 1-1/8 1-1/4" 2-3/4" 11/64" 198 | 1-1/4 1-3/8" 3" 11/64" 199 | 1-3/8 1-1/2" 2-1/4" 3/16" 200 | 1-1/2 1-5/8" 3-1/2" 3/16" 201 | 1-5/8 1-3/4" 3-3/4" 3/16" 202 | 1-3/4 1-7/8" 4" 3/16" 203 | 2 2-1/8" 4-1/2" 3/16" 204 | 2-1/2 2-5/8" 4-1/2" 3/16" 205 | 3 3-1/8" 5-1/2" 9/32"` 206 | .split('\n') 207 | .reduce(function ParseWasher(washers, line) { 208 | const [size, id, od, thickness] = line 209 | .replace(/\"/g, '') 210 | .split('\t') 211 | .map(parseValues); 212 | washers[size] = { size, id, od, thickness }; 213 | return washers; 214 | }, {}), 215 | { 216 | '1/4 fender': { 217 | size: '1/4 fender', 218 | od: util.inch(1.25), 219 | id: util.inch(0.28125), 220 | thickness: util.inch(0.08) // .051/.080 221 | } 222 | } 223 | ); 224 | 225 | const WoodScrewDiameter = `2 .086 26 .090 .079 .090 .079 .075 .064 .010 226 | 3 .099 24 .103 .092 .103 .092 .086 .075 .014 227 | 4 .112 22 .116 .105 .116 .105 .095 .084 .016 228 | 5 .125 20 .129 .118 .129 .118 .107 .096 .018 229 | 6 .138 18 .142 .131 .142 .131 .118 .107 .020 230 | 7 .151 16 .155 .144 .155 .144 .127 .116 .022 231 | 8 .164 15 .168 .157 .168 .157 .136 .125 .023 232 | 9 .177 14 .181 .170 .181 .170 .147 .136 .026 233 | 10 .190 13 .194 .183 .194 .183 .157 .146 .030 234 | 12 .216 11 .220 .209 .220 .209 .176 .165 .031 235 | 14 .242 10 .246 .235 .246 .235 .201 .190 .035 236 | 16 .268 9 .272 .261 .272 .261 .214 .203 .038` 237 | .split('\n') 238 | .reduce((values, line) => { 239 | var params = line.split('\t'); 240 | values[`#${params[0]}`] = util.inch(parseFloat(params[1])); 241 | return values; 242 | }, {}); 243 | 244 | /** 245 | * Imperial wood screws. 246 | * @see https://www.aftfasteners.com/wood-screws-dimensions-mechanical-specs/ 247 | * headDiameter, headLength, diameter, tap, countersink 248 | */ 249 | export const ImperialWoodScrews = `2 1 .172 .147 .051 .031 .023 .023 .015 .102 .089 .063 .047 .017 250 | 3 1 .199 .141 .059 .035 .027 .027 .017 .107 .094 .068 .052 .018 251 | 4 1 .225 .195 .067 .039 .031 .030 .020 .128 .115 .089 .073 .018 252 | 5 2 .252 .220 .075 .043 .035 .034 .022 .154 .141 .086 .063 .027 253 | 6 2 .279 .244 .083 .048 .039 .038 .024 .174 .161 .106 .083 .029 254 | 7 2 .305 .268 .091 .048 .039 .041 .027 .189 .176 .121 .098 .030 255 | 8 2 .332 .292 .100 .054 .045 .045 .029 .204 .191 .136 .113 .032 256 | 9 2 .358 .316 .108 .054 .045 .049 .032 .214 .201 .146 .123 .033 257 | 10 3 .385 .340 .116 .060 .050 .053 .034 .258 .245 .146 .123 .034 258 | 12 3 .438 .389 .132 .067 .056 .060 .039 .283 .270 .171 .148 .036 259 | 14 3 .507 .452 .153 .075 .064 .070 .046 .283 .270 .171 .148 .036 260 | 16 3 .544 .485 .164 .075 .064 .075 .049 .303 .290 .191 .168 .039` 261 | .split('\n') 262 | .reduce((screws, line) => { 263 | var params = line 264 | .split('\t') 265 | .map((value, index) => (index > 1 ? parseFloat(value) : value)); 266 | screws[`#${params[0]}`] = [ 267 | util.inch(params[2]), 268 | util.inch(params[4]), 269 | WoodScrewDiameter[`#${params[0]}`] 270 | ]; 271 | return screws; 272 | }, {}); 273 | 274 | /** 275 | * Dimensions of nuts for imperial bolts. 276 | * F is the width across teh faces, C is the width 277 | * across the points, and H is the height. D is the 278 | * basic diameter. 279 | * 280 | * [F, C, H, D] 281 | * 282 | * @see https://en.wikipedia.org/wiki/Nut_(hardware) 283 | * @see https://www.boltdepot.com/fastener-information/nuts-washers/us-nut-dimensions.aspx 284 | * @type {Object} 285 | */ 286 | export const ImperialNuts = `#0 - 5/32" - - - 3/64" 287 | #1 - 5/32" - - - 3/64" 288 | #2 - 3/16" - - 9/64" 1/16" 289 | #3 - 3/16" - - 9/64" 1/16" 290 | #4 - 1/4" - - 9/64" 3/32" 291 | #6 - 5/16" - - 11/64" 7/64" 292 | #8 - 11/32" - - 15/64" 1/8" 293 | #10 - 3/8" - - 15/64" 1/8" 294 | #12 - 7/16" - - 5/16" 5/32" 295 | 1/4 7/16" 7/16" 7/32" 5/32" 5/16" 3/16" 296 | 5/16 1/2" 9/16" 17/64" 3/16" 11/32" 7/32" 297 | 3/8 9/16" 5/8" 21/64" 7/32" 29/64" 1/4" 298 | 7/16 11/16" - 3/8" 1/4" 29/64" - 299 | 1/2 3/4" - 7/16" 5/16" 19/32" - 300 | 9/16 7/8" - 31/64" 5/16" 41/64" - 301 | 5/8 15/16" - 35/64" 3/8" 3/4" - 302 | 3/4 1-1/8" - 41/64" 27/64" 7/8" - 303 | 7/8 1-5/16" - 3/4" 31/64" 63/64" - 304 | 1 1-1/2" - 55/64" 35/64" 1-3/64" -` 305 | .split('\n') 306 | .reduce((nuts, line) => { 307 | var params = line.split('\t').map(parseValues); 308 | var flatDiameter = params[1] || params[2]; 309 | var cornerDiameter = flatDiameter / (Math.sqrt(3) / 2); 310 | var height = params[3] || params[6]; 311 | nuts[`${params[0]} hex`] = [ 312 | flatDiameter, 313 | cornerDiameter, 314 | height, 315 | cornerDiameter / 2 // the boltdepot data does not have the hole diameter 316 | ]; 317 | return nuts; 318 | }, {}); 319 | -------------------------------------------------------------------------------- /githubdocs/themes/architect/css/style.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | /** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */ 3 | html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } 4 | 5 | /** Remove default margin. */ 6 | body { margin: 0; } 7 | 8 | /* HTML5 display definitions ========================================================================== */ 9 | /** Correct `block` display not defined for any HTML5 element in IE 8/9. Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. Correct `block` display not defined for `main` in IE 11. */ 10 | article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } 11 | 12 | /** 1. Correct `inline-block` display not defined in IE 8/9. 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. */ 13 | audio, canvas, progress, video { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } 14 | 15 | /** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */ 16 | audio:not([controls]) { display: none; height: 0; } 17 | 18 | /** Address `[hidden]` styling not present in IE 8/9/10. Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. */ 19 | [hidden], template { display: none; } 20 | 21 | /* Links ========================================================================== */ 22 | /** Remove the gray background color from active links in IE 10. */ 23 | a { background-color: transparent; } 24 | 25 | /** Improve readability when focused and also mouse hovered in all browsers. */ 26 | a:active, a:hover { outline: 0; } 27 | 28 | /* Text-level semantics ========================================================================== */ 29 | /** Address styling not present in IE 8/9/10/11, Safari, and Chrome. */ 30 | abbr[title] { border-bottom: 1px dotted; } 31 | 32 | /** Address style set to `bolder` in Firefox 4+, Safari, and Chrome. */ 33 | b, strong { font-weight: bold; } 34 | 35 | /** Address styling not present in Safari and Chrome. */ 36 | dfn { font-style: italic; } 37 | 38 | /** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari, and Chrome. */ 39 | h1 { font-size: 2em; margin: 0.67em 0; } 40 | 41 | /** Address styling not present in IE 8/9. */ 42 | mark { background: #ff0; color: #000; } 43 | 44 | /** Address inconsistent and variable font size in all browsers. */ 45 | small { font-size: 80%; } 46 | 47 | /** Prevent `sub` and `sup` affecting `line-height` in all browsers. */ 48 | sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } 49 | 50 | sup { top: -0.5em; } 51 | 52 | sub { bottom: -0.25em; } 53 | 54 | /* Embedded content ========================================================================== */ 55 | /** Remove border when inside `a` element in IE 8/9/10. */ 56 | img { border: 0; } 57 | 58 | /** Correct overflow not hidden in IE 9/10/11. */ 59 | svg:not(:root) { overflow: hidden; } 60 | 61 | /* Grouping content ========================================================================== */ 62 | /** Address margin not present in IE 8/9 and Safari. */ 63 | figure { margin: 1em 40px; } 64 | 65 | /** Address differences between Firefox and other browsers. */ 66 | hr { box-sizing: content-box; height: 0; } 67 | 68 | /** Contain overflow in all browsers. */ 69 | pre { overflow: auto; } 70 | 71 | /** Address odd `em`-unit font size rendering in all browsers. */ 72 | code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } 73 | 74 | /* Forms ========================================================================== */ 75 | /** Known limitation: by default, Chrome and Safari on OS X allow very limited styling of `select`, unless a `border` property is set. */ 76 | /** 1. Correct color not being inherited. Known issue: affects color of disabled elements. 2. Correct font properties not being inherited. 3. Address margins set differently in Firefox 4+, Safari, and Chrome. */ 77 | button, input, optgroup, select, textarea { color: inherit; /* 1 */ font: inherit; /* 2 */ margin: 0; /* 3 */ } 78 | 79 | /** Address `overflow` set to `hidden` in IE 8/9/10/11. */ 80 | button { overflow: visible; } 81 | 82 | /** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. Correct `select` style inheritance in Firefox. */ 83 | button, select { text-transform: none; } 84 | 85 | /** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */ 86 | button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } 87 | 88 | /** Re-set default cursor for disabled elements. */ 89 | button[disabled], html input[disabled] { cursor: default; } 90 | 91 | /** Remove inner padding and border in Firefox 4+. */ 92 | button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } 93 | 94 | /** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */ 95 | input { line-height: normal; } 96 | 97 | /** It's recommended that you don't attempt to style these elements. Firefox's implementation doesn't respect box-sizing, padding, or width. 1. Address box sizing set to `content-box` in IE 8/9/10. 2. Remove excess padding in IE 8/9/10. */ 98 | input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } 99 | 100 | /** Fix the cursor style for Chrome's increment/decrement buttons. For certain `font-size` values of the `input`, it causes the cursor style of the decrement button to change from `default` to `text`. */ 101 | input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } 102 | 103 | /** 1. Address `appearance` set to `searchfield` in Safari and Chrome. 2. Address `box-sizing` set to `border-box` in Safari and Chrome (include `-moz` to future-proof). */ 104 | input[type="search"] { -webkit-appearance: textfield; /* 1 */ /* 2 */ box-sizing: content-box; } 105 | 106 | /** Remove inner padding and search cancel button in Safari and Chrome on OS X. Safari (but not Chrome) clips the cancel button when the search input has padding (and `textfield` appearance). */ 107 | input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } 108 | 109 | /** Define consistent border, margin, and padding. */ 110 | fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } 111 | 112 | /** 1. Correct `color` not being inherited in IE 8/9/10/11. 2. Remove padding so people aren't caught out if they zero out fieldsets. */ 113 | legend { border: 0; /* 1 */ padding: 0; /* 2 */ } 114 | 115 | /** Remove default vertical scrollbar in IE 8/9/10/11. */ 116 | textarea { overflow: auto; } 117 | 118 | /** Don't inherit the `font-weight` (applied by a rule above). NOTE: the default cannot safely be changed in Chrome and Safari on OS X. */ 119 | optgroup { font-weight: bold; } 120 | 121 | /* Tables ========================================================================== */ 122 | /** Remove most spacing between table cells. */ 123 | table { border-collapse: collapse; border-spacing: 0; } 124 | 125 | td, th { padding: 0; } 126 | 127 | .highlight table td { padding: 5px; } 128 | 129 | .highlight table pre { margin: 0; } 130 | 131 | .highlight .cm { color: #999988; font-style: italic; } 132 | 133 | .highlight .cp { color: #999999; font-weight: bold; } 134 | 135 | .highlight .c1 { color: #999988; font-style: italic; } 136 | 137 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic; } 138 | 139 | .highlight .c, .highlight .cd { color: #999988; font-style: italic; } 140 | 141 | .highlight .err { color: #a61717; background-color: #e3d2d2; } 142 | 143 | .highlight .gd { color: #000000; background-color: #ffdddd; } 144 | 145 | .highlight .ge { color: #000000; font-style: italic; } 146 | 147 | .highlight .gr { color: #aa0000; } 148 | 149 | .highlight .gh { color: #999999; } 150 | 151 | .highlight .gi { color: #000000; background-color: #ddffdd; } 152 | 153 | .highlight .go { color: #888888; } 154 | 155 | .highlight .gp { color: #555555; } 156 | 157 | .highlight .gs { font-weight: bold; } 158 | 159 | .highlight .gu { color: #aaaaaa; } 160 | 161 | .highlight .gt { color: #aa0000; } 162 | 163 | .highlight .kc { color: #000000; font-weight: bold; } 164 | 165 | .highlight .kd { color: #000000; font-weight: bold; } 166 | 167 | .highlight .kn { color: #000000; font-weight: bold; } 168 | 169 | .highlight .kp { color: #000000; font-weight: bold; } 170 | 171 | .highlight .kr { color: #000000; font-weight: bold; } 172 | 173 | .highlight .kt { color: #445588; font-weight: bold; } 174 | 175 | .highlight .k, .highlight .kv { color: #000000; font-weight: bold; } 176 | 177 | .highlight .mf { color: #009999; } 178 | 179 | .highlight .mh { color: #009999; } 180 | 181 | .highlight .il { color: #009999; } 182 | 183 | .highlight .mi { color: #009999; } 184 | 185 | .highlight .mo { color: #009999; } 186 | 187 | .highlight .m, .highlight .mb, .highlight .mx { color: #009999; } 188 | 189 | .highlight .sb { color: #d14; } 190 | 191 | .highlight .sc { color: #d14; } 192 | 193 | .highlight .sd { color: #d14; } 194 | 195 | .highlight .s2 { color: #d14; } 196 | 197 | .highlight .se { color: #d14; } 198 | 199 | .highlight .sh { color: #d14; } 200 | 201 | .highlight .si { color: #d14; } 202 | 203 | .highlight .sx { color: #d14; } 204 | 205 | .highlight .sr { color: #009926; } 206 | 207 | .highlight .s1 { color: #d14; } 208 | 209 | .highlight .ss { color: #990073; } 210 | 211 | .highlight .s { color: #d14; } 212 | 213 | .highlight .na { color: #008080; } 214 | 215 | .highlight .bp { color: #999999; } 216 | 217 | .highlight .nb { color: #0086B3; } 218 | 219 | .highlight .nc { color: #445588; font-weight: bold; } 220 | 221 | .highlight .no { color: #008080; } 222 | 223 | .highlight .nd { color: #3c5d5d; font-weight: bold; } 224 | 225 | .highlight .ni { color: #800080; } 226 | 227 | .highlight .ne { color: #990000; font-weight: bold; } 228 | 229 | .highlight .nf { color: #990000; font-weight: bold; } 230 | 231 | .highlight .nl { color: #990000; font-weight: bold; } 232 | 233 | .highlight .nn { color: #555555; } 234 | 235 | .highlight .nt { color: #000080; } 236 | 237 | .highlight .vc { color: #008080; } 238 | 239 | .highlight .vg { color: #008080; } 240 | 241 | .highlight .vi { color: #008080; } 242 | 243 | .highlight .nv { color: #008080; } 244 | 245 | .highlight .ow { color: #000000; font-weight: bold; } 246 | 247 | .highlight .o { color: #000000; font-weight: bold; } 248 | 249 | .highlight .w { color: #bbbbbb; } 250 | 251 | .highlight { background-color: #f8f8f8; } 252 | 253 | /* LAYOUT STYLES */ 254 | body { font-family: 'Helvetica Neue', Helvetica, Arial, serif; font-size: 15px; font-weight: 400; line-height: 1.5; color: #666; background: #fafafa url(../images/body-bg.jpg) 0 0 repeat; } 255 | 256 | p { margin-top: 0; } 257 | 258 | a { color: #2879d0; } 259 | 260 | a:hover { color: #2268b2; } 261 | 262 | header { padding-top: 40px; padding-bottom: 40px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; background: #2e7bcf url(../images/header-bg.jpg) 0 0 repeat-x; border-bottom: solid 1px #275da1; } 263 | 264 | header h1 { width: 540px; margin-top: 0; margin-bottom: 0.2em; font-size: 72px; font-weight: normal; line-height: 1; color: #fff; letter-spacing: -1px; } 265 | 266 | header h2 { width: 540px; margin-top: 0; margin-bottom: 0; font-size: 26px; font-weight: normal; line-height: 1.3; color: #9ddcff; letter-spacing: 0; } 267 | 268 | .inner { position: relative; width: 940px; margin: 0 auto; } 269 | 270 | #content-wrapper { padding-top: 30px; border-top: solid 1px #fff; } 271 | 272 | #main-content { float: left; width: 690px; } 273 | 274 | #main-content img { max-width: 100%; } 275 | 276 | aside#sidebar { float: right; width: 200px; min-height: 504px; padding-left: 20px; font-size: 12px; line-height: 1.3; background: transparent url(../images/sidebar-bg.jpg) 0 0 no-repeat; } 277 | 278 | aside#sidebar p.repo-owner, aside#sidebar p.repo-owner a { font-weight: bold; } 279 | 280 | #downloads { margin-bottom: 40px; } 281 | 282 | a.button { width: 134px; height: 58px; padding-top: 22px; padding-left: 68px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 23px; line-height: 1.2; color: #fff; } 283 | 284 | a.button small { display: block; font-size: 11px; } 285 | 286 | header a.button { position: absolute; top: 0; right: 0; background: transparent url(../images/github-button.png) 0 0 no-repeat; } 287 | 288 | aside a.button { display: block; width: 138px; padding-left: 64px; margin-bottom: 20px; font-size: 21px; background: transparent url(../images/download-button.png) 0 0 no-repeat; } 289 | 290 | code, pre { margin-bottom: 30px; font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; font-size: 13px; color: #222; } 291 | 292 | code { padding: 0 3px; background-color: #f2f8fc; border: solid 1px #dbe7f3; } 293 | 294 | pre { padding: 20px; overflow: auto; text-shadow: none; background: #fff; border: solid 1px #f2f2f2; } 295 | 296 | pre code { padding: 0; color: #2879d0; background-color: #fff; border: none; } 297 | 298 | ul, ol, dl { margin-bottom: 20px; } 299 | 300 | /* COMMON STYLES */ 301 | hr { height: 0; margin-top: 1em; margin-bottom: 1em; border: 0; border-top: solid 1px #ddd; } 302 | 303 | table { width: 100%; border: 1px solid #ebebeb; } 304 | 305 | th { font-weight: 500; } 306 | 307 | td { font-weight: 300; text-align: center; border: 1px solid #ebebeb; } 308 | 309 | form { padding: 20px; background: #f2f2f2; } 310 | 311 | /* GENERAL ELEMENT TYPE STYLES */ 312 | #main-content h1 { margin-top: 0; margin-bottom: 0; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 2.8em; font-weight: normal; color: #474747; text-indent: 6px; letter-spacing: -1px; } 313 | 314 | #main-content h1:before { padding-right: 0.3em; margin-left: -0.9em; color: #9ddcff; content: "/"; } 315 | 316 | #main-content h2 { margin-bottom: 8px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 22px; font-weight: bold; color: #474747; text-indent: 4px; } 317 | 318 | #main-content h2:before { padding-right: 0.3em; margin-left: -1.5em; content: "//"; color: #9ddcff; } 319 | 320 | #main-content h3 { margin-top: 24px; margin-bottom: 8px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 18px; font-weight: bold; color: #474747; text-indent: 3px; } 321 | 322 | #main-content h3:before { padding-right: 0.3em; margin-left: -2em; content: "///"; color: #9ddcff; } 323 | 324 | #main-content h4 { margin-bottom: 8px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 15px; font-weight: bold; color: #474747; text-indent: 3px; } 325 | 326 | h4:before { padding-right: 0.3em; margin-left: -2.8em; content: "////"; color: #9ddcff; } 327 | 328 | #main-content h5 { margin-bottom: 8px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: 14px; color: #474747; text-indent: 3px; } 329 | 330 | h5:before { padding-right: 0.3em; margin-left: -3.2em; content: "/////"; color: #9ddcff; } 331 | 332 | #main-content h6 { margin-bottom: 8px; font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; font-size: .8em; color: #474747; text-indent: 3px; } 333 | 334 | h6:before { padding-right: 0.3em; margin-left: -3.7em; content: "//////"; color: #9ddcff; } 335 | 336 | p { margin-bottom: 20px; } 337 | 338 | a { text-decoration: none; } 339 | 340 | p a { font-weight: 400; } 341 | 342 | blockquote { padding: 0 0 0 30px; margin-bottom: 20px; font-size: 15px; border-left: 10px solid #e9e9e9; } 343 | 344 | ul { list-style-position: inside; list-style: disc; padding-left: 20px; } 345 | 346 | ol { list-style-position: inside; list-style: decimal; padding-left: 3px; } 347 | 348 | dl dd { font-style: italic; font-weight: 100; } 349 | 350 | footer { padding-top: 20px; padding-bottom: 30px; margin-top: 40px; font-size: 13px; color: #aaa; background: transparent url("../images/hr.png") 0 0 no-repeat; } 351 | 352 | footer a { color: #666; } 353 | 354 | footer a:hover { color: #444; } 355 | 356 | /* MISC */ 357 | .clearfix:after { display: block; height: 0; clear: both; visibility: hidden; content: '.'; } 358 | 359 | .clearfix { display: inline-block; } 360 | 361 | * html .clearfix { height: 1%; } 362 | 363 | .clearfix { display: block; } 364 | 365 | /* #Media Queries 366 | ================================================== */ 367 | /* Smaller than standard 960 (devices and browsers) */ 368 | /* Tablet Portrait size to standard 960 (devices and browsers) */ 369 | @media only screen and (min-width: 768px) and (max-width: 959px) { .inner { width: 740px; } 370 | header h1, header h2 { width: 340px; } 371 | header h1 { font-size: 60px; } 372 | header h2 { font-size: 30px; } 373 | #main-content { width: 490px; } 374 | #main-content h1:before, #main-content h2:before, #main-content h3:before, #main-content h4:before, #main-content h5:before, #main-content h6:before { padding-right: 0; margin-left: 0; content: none; } } 375 | /* All Mobile Sizes (devices and browser) */ 376 | @media only screen and (max-width: 767px) { .inner { width: 93%; } 377 | header { padding: 20px 0; } 378 | header .inner { position: relative; } 379 | header h1, header h2 { width: 100%; } 380 | header h1 { font-size: 48px; } 381 | header h2 { font-size: 24px; } 382 | header a.button { position: relative; display: inline-block; width: auto; height: auto; padding: 5px 10px; margin-top: 15px; font-size: 13px; line-height: 1; color: #2879d0; text-align: center; background-color: #9ddcff; background-image: none; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } 383 | header a.button small { display: inline; font-size: 13px; } 384 | #main-content, aside#sidebar { float: none; width: 100% !important; } 385 | aside#sidebar { min-height: 0; padding: 20px 0; margin-top: 20px; background-image: none; border-top: solid 1px #ddd; } 386 | aside#sidebar a.button { display: none; } 387 | #main-content h1:before, #main-content h2:before, #main-content h3:before, #main-content h4:before, #main-content h5:before, #main-content h6:before { padding-right: 0; margin-left: 0; content: none; } } 388 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ 389 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ 390 | -------------------------------------------------------------------------------- /githubdocs/formats.js: -------------------------------------------------------------------------------- 1 | /* 2 | ## Formats.js 3 | 4 | Copyright (c) 2014 bebbi (elghatta@gmail.com) 5 | Copyright (c) 2013 Eduard Bespalov (edwbes@gmail.com) 6 | Copyright (c) 2013 Rene K. Mueller (spiritdude@gmail.com) 7 | Copyright (c) 2012 Joost Nieuwenhuijse (joost@newhouse.nl) 8 | Copyright (c) 2011 Evan Wallace (http://evanw.github.com/csg.js/) 9 | Copyright (c) 2012 Alexandre Girard (https://github.com/alx) 10 | 11 | Exporting CSG into various formats: 12 | - AMF 13 | - X3D 14 | - STL (ASCII & Binary) 15 | Exporting CAG into various formats: 16 | - DXF 17 | - SVG 18 | 19 | License: MIT license 20 | 21 | */ 22 | 23 | // import the required modules if necessary 24 | 25 | // if(typeof module !== 'undefined') { // used via nodejs 26 | // CSG = require(lib+'csg.js').CSG; 27 | // CAG = require(lib+'csg.js').CAG; 28 | // Blob = require(lib+'Blob.js').Blob; 29 | // } 30 | 31 | //////////////////////////////////////////// 32 | // X3D Export 33 | //////////////////////////////////////////// 34 | 35 | (function(module) { 36 | 37 | CSG.prototype.toX3D = function() { 38 | // materialPolygonLists 39 | // key: a color string (e.g. "0 1 1" for yellow) 40 | // value: an array of strings specifying polygons of this color 41 | // (as space-separated indices into vertexCoords) 42 | var materialPolygonLists = {}, 43 | // list of coordinates (as "x y z" strings) 44 | vertexCoords = [], 45 | // map to look up the index in vertexCoords of a given vertex 46 | vertexTagToCoordIndexMap = {}; 47 | 48 | this.polygons.map(function(p) { 49 | var red = 0, 50 | green = 0, 51 | blue = 1; // default color is blue 52 | if (p.shared && p.shared.color) { 53 | red = p.shared.color[0]; 54 | green = p.shared.color[1]; 55 | blue = p.shared.color[2]; 56 | } 57 | 58 | var polygonVertexIndices = [], 59 | numvertices = p.vertices.length, 60 | vertex; 61 | for (var i = 0; i < numvertices; i++) { 62 | vertex = p.vertices[i]; 63 | if (!(vertex.getTag() in vertexTagToCoordIndexMap)) { 64 | vertexCoords.push(vertex.pos._x.toString() + " " + 65 | vertex.pos._y.toString() + " " + 66 | vertex.pos._z.toString() 67 | ); 68 | vertexTagToCoordIndexMap[vertex.getTag()] = vertexCoords.length - 1; 69 | } 70 | polygonVertexIndices.push(vertexTagToCoordIndexMap[vertex.getTag()]); 71 | } 72 | 73 | var polygonString = polygonVertexIndices.join(" "); 74 | 75 | var colorString = red.toString() + " " + green.toString() + " " + blue.toString(); 76 | if (!(colorString in materialPolygonLists)) { 77 | materialPolygonLists[colorString] = []; 78 | } 79 | // add this polygonString to the list of colorString-colored polygons 80 | materialPolygonLists[colorString].push(polygonString); 81 | }); 82 | 83 | 84 | // create output document 85 | var docType = document.implementation.createDocumentType("X3D", 86 | "ISO//Web3D//DTD X3D 3.1//EN","http://www.web3d.org/specifications/x3d-3.1.dtd"); 87 | var exportDoc = document.implementation.createDocument(null, "X3D", docType); 88 | exportDoc.insertBefore( 89 | exportDoc.createProcessingInstruction('xml', 'version="1.0" encoding="UTF-8"'), 90 | exportDoc.doctype); 91 | 92 | var exportRoot = exportDoc.getElementsByTagName("X3D")[0]; 93 | exportRoot.setAttribute("profile", "Interchange"); 94 | exportRoot.setAttribute("version", "3.1"); 95 | exportRoot.setAttribute("xsd:noNamespaceSchemaLocation", "http://www.web3d.org/specifications/x3d-3.1.xsd"); 96 | exportRoot.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema-instance"); 97 | 98 | var exportScene = exportDoc.createElement("Scene"); 99 | exportRoot.appendChild(exportScene); 100 | 101 | /* 102 | For each color, create a shape made of an appropriately colored 103 | material which contains all polygons that are this color. 104 | 105 | The first shape will contain the definition of all vertices, 106 | (), which will be referenced by 107 | subsequent shapes. 108 | */ 109 | var coordsMeshDefined = false; 110 | for (var colorString in materialPolygonLists) { 111 | var polygonList = materialPolygonLists[colorString]; 112 | var shape = exportDoc.createElement("Shape"); 113 | exportScene.appendChild(shape); 114 | 115 | var appearance = exportDoc.createElement("Appearance"); 116 | shape.appendChild(appearance); 117 | 118 | var material = exportDoc.createElement("Material"); 119 | appearance.appendChild(material); 120 | material.setAttribute("diffuseColor", colorString); 121 | material.setAttribute("ambientIntensity", "1.0"); 122 | 123 | var ifs = exportDoc.createElement("IndexedFaceSet"); 124 | shape.appendChild(ifs); 125 | ifs.setAttribute("solid", "true"); 126 | ifs.setAttribute("coordIndex", polygonList.join(" -1 ") + " -1"); 127 | 128 | var coordinate = exportDoc.createElement("Coordinate"); 129 | ifs.appendChild(coordinate); 130 | if (coordsMeshDefined) { 131 | coordinate.setAttribute("USE", "coords_mesh"); 132 | } else { 133 | coordinate.setAttribute("DEF", "coords_mesh"); 134 | coordinate.setAttribute("point", vertexCoords.join(" ")); 135 | coordsMeshDefined = true; 136 | } 137 | } 138 | 139 | var x3dstring = (new XMLSerializer()).serializeToString(exportDoc); 140 | return new Blob([x3dstring], { 141 | type: "model/x3d+xml" 142 | }); 143 | }; 144 | 145 | //////////////////////////////////////////// 146 | // STL Binary Export 147 | //////////////////////////////////////////// 148 | 149 | // see http://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL 150 | CSG.prototype.toStlBinary = function() { 151 | // first check if the host is little-endian: 152 | var buffer = new ArrayBuffer(4); 153 | var int32buffer = new Int32Array(buffer, 0, 1); 154 | var int8buffer = new Int8Array(buffer, 0, 4); 155 | int32buffer[0] = 0x11223344; 156 | if (int8buffer[0] != 0x44) { 157 | throw new Error("Binary STL output is currently only supported on little-endian (Intel) processors"); 158 | } 159 | 160 | var numtriangles = 0; 161 | this.polygons.map(function(p) { 162 | var numvertices = p.vertices.length; 163 | var thisnumtriangles = (numvertices >= 3) ? numvertices - 2 : 0; 164 | numtriangles += thisnumtriangles; 165 | }); 166 | var headerarray = new Uint8Array(80); 167 | for (var i = 0; i < 80; i++) { 168 | headerarray[i] = 65; 169 | } 170 | var ar1 = new Uint32Array(1); 171 | ar1[0] = numtriangles; 172 | // write the triangles to allTrianglesBuffer: 173 | var allTrianglesBuffer = new ArrayBuffer(50 * numtriangles); 174 | var allTrianglesBufferAsInt8 = new Int8Array(allTrianglesBuffer); 175 | // a tricky problem is that a Float32Array must be aligned at 4-byte boundaries (at least in certain browsers) 176 | // while each triangle takes 50 bytes. Therefore we write each triangle to a temporary buffer, and copy that 177 | // into allTrianglesBuffer: 178 | var triangleBuffer = new ArrayBuffer(50); 179 | var triangleBufferAsInt8 = new Int8Array(triangleBuffer); 180 | // each triangle consists of 12 floats: 181 | var triangleFloat32array = new Float32Array(triangleBuffer, 0, 12); 182 | // and one uint16: 183 | var triangleUint16array = new Uint16Array(triangleBuffer, 48, 1); 184 | var byteoffset = 0; 185 | this.polygons.map(function(p) { 186 | var numvertices = p.vertices.length; 187 | for (var i = 0; i < numvertices - 2; i++) { 188 | var normal = p.plane.normal; 189 | triangleFloat32array[0] = normal._x; 190 | triangleFloat32array[1] = normal._y; 191 | triangleFloat32array[2] = normal._z; 192 | var arindex = 3; 193 | for (var v = 0; v < 3; v++) { 194 | var vv = v + ((v > 0) ? i : 0); 195 | var vertexpos = p.vertices[vv].pos; 196 | triangleFloat32array[arindex++] = vertexpos._x; 197 | triangleFloat32array[arindex++] = vertexpos._y; 198 | triangleFloat32array[arindex++] = vertexpos._z; 199 | } 200 | triangleUint16array[0] = 0; 201 | // copy the triangle into allTrianglesBuffer: 202 | allTrianglesBufferAsInt8.set(triangleBufferAsInt8, byteoffset); 203 | byteoffset += 50; 204 | } 205 | }); 206 | return new Blob([headerarray.buffer, ar1.buffer, allTrianglesBuffer], { 207 | type: "application/sla" 208 | }); 209 | }; 210 | 211 | //////////////////////////////////////////// 212 | // STL String Export 213 | //////////////////////////////////////////// 214 | 215 | CSG.prototype.toStlString = function() { 216 | var result = "solid csg.js\n"; 217 | this.polygons.map(function(p) { 218 | result += p.toStlString(); 219 | }); 220 | result += "endsolid csg.js\n"; 221 | return new Blob([result], { 222 | type: "application/sla" 223 | }); 224 | }; 225 | 226 | CSG.Vector3D.prototype.toStlString = function() { 227 | return this._x + " " + this._y + " " + this._z; 228 | }; 229 | 230 | CSG.Vertex.prototype.toStlString = function() { 231 | return "vertex " + this.pos.toStlString() + "\n"; 232 | }; 233 | 234 | CSG.Polygon.prototype.toStlString = function() { 235 | var result = ""; 236 | if (this.vertices.length >= 3) // should be! 237 | { 238 | // STL requires triangular polygons. If our polygon has more vertices, create 239 | // multiple triangles: 240 | var firstVertexStl = this.vertices[0].toStlString(); 241 | for (var i = 0; i < this.vertices.length - 2; i++) { 242 | result += "facet normal " + this.plane.normal.toStlString() + "\nouter loop\n"; 243 | result += firstVertexStl; 244 | result += this.vertices[i + 1].toStlString(); 245 | result += this.vertices[i + 2].toStlString(); 246 | result += "endloop\nendfacet\n"; 247 | } 248 | } 249 | return result; 250 | }; 251 | 252 | //////////////////////////////////////////// 253 | // DXF Export 254 | //////////////////////////////////////////// 255 | 256 | CAG.PathsToDxf = function(paths) { 257 | var str = "999\nDXF generated by OpenJsCad\n"; 258 | str += " 0\nSECTION\n 2\nHEADER\n"; 259 | str += " 0\nENDSEC\n"; 260 | str += " 0\nSECTION\n 2\nTABLES\n"; 261 | str += " 0\nTABLE\n 2\nLTYPE\n 70\n1\n"; 262 | str += " 0\nLTYPE\n 2\nCONTINUOUS\n 3\nSolid Line\n 72\n65\n 73\n0\n 40\n0.0\n"; 263 | str += " 0\nENDTAB\n"; 264 | str += " 0\nTABLE\n 2\nLAYER\n 70\n1\n"; 265 | str += " 0\nLAYER\n 2\nOpenJsCad\n 62\n7\n 6\ncontinuous\n"; 266 | str += " 0\nENDTAB\n"; 267 | str += " 0\nTABLE\n 2\nSTYLE\n 70\n0\n 0\nENDTAB\n"; 268 | str += " 0\nTABLE\n 2\nVIEW\n 70\n0\n 0\nENDTAB\n"; 269 | str += " 0\nENDSEC\n"; 270 | str += " 0\nSECTION\n 2\nBLOCKS\n"; 271 | str += " 0\nENDSEC\n"; 272 | str += " 0\nSECTION\n 2\nENTITIES\n"; 273 | paths.map(function(path) { 274 | var numpoints_closed = path.points.length + (path.closed ? 1 : 0); 275 | str += " 0\nLWPOLYLINE\n 8\nOpenJsCad\n 90\n" + numpoints_closed + "\n 70\n" + (path.closed ? 1 : 0) + "\n"; 276 | for (var pointindex = 0; pointindex < numpoints_closed; pointindex++) { 277 | var pointindexwrapped = pointindex; 278 | if (pointindexwrapped >= path.points.length) pointindexwrapped -= path.points.length; 279 | var point = path.points[pointindexwrapped]; 280 | str += " 10\n" + point.x + "\n 20\n" + point.y + "\n 30\n0.0\n"; 281 | } 282 | }); 283 | str += " 0\nENDSEC\n 0\nEOF\n"; 284 | return new Blob([str], { 285 | type: "application/dxf" 286 | }); 287 | }; 288 | 289 | CAG.prototype.toDxf = function() { 290 | var paths = this.getOutlinePaths(); 291 | return CAG.PathsToDxf(paths); 292 | }; 293 | 294 | //////////////////////////////////////////// 295 | // AMF Export 296 | //////////////////////////////////////////// 297 | 298 | CSG.prototype.toAMFString = function(m) { 299 | var result = "\n\n"; 300 | for(var k in m) { 301 | result += ""+m[k]+"\n"; 302 | } 303 | result += "\n\n\n"; 304 | 305 | this.polygons.map(function(p) { // first we dump all vertices of all polygons 306 | for(var i=0; i"+color[1]+""+color[2]+""+color[3]+""; 326 | } 327 | 328 | for(var i=0; i"; 331 | result += "" + (n+i+1) + ""; 332 | result += "" + (n+i+2) + ""; 333 | result += "\n"; 334 | } 335 | n += p.vertices.length; 336 | result += "\n"; 337 | }); 338 | result += "\n\n"; 339 | result += "\n"; 340 | return new Blob([result], { 341 | type: "application/amf+xml" 342 | }); 343 | }; 344 | 345 | CSG.Vector3D.prototype.toAMFString = function() { 346 | return "" + this._x + "" + this._y + "" + this._z + ""; 347 | }; 348 | 349 | CSG.Vertex.prototype.toAMFString = function() { 350 | return "" + this.pos.toAMFString() + "\n"; 351 | }; 352 | 353 | 354 | //////////////////////////////////////////// 355 | // JSON Conversions 356 | //////////////////////////////////////////// 357 | 358 | CSG.prototype.toJSON = function() { 359 | var str = '{ "type": "csg","polygons": ['; 360 | var comma = ''; 361 | this.polygons.map( 362 | function(polygon) { 363 | str += comma; 364 | str += JSON.stringify(polygon); 365 | comma = ','; 366 | } 367 | ); 368 | str += '],'; 369 | str += '"isCanonicalized": ' + JSON.stringify(this.isCanonicalized)+','; 370 | str += '"isRetesselated": '+JSON.stringify(this.isRetesselated); 371 | str += '}'; 372 | return new Blob([str], { 373 | type: "application/json" 374 | }); 375 | }; 376 | 377 | // convert the given (anonymous JSON) object into CSG 378 | // Note: Any issues during conversion will result in exceptions 379 | CSG.prototype.fromJSON = function(o) { 380 | // verify the object IS convertable 381 | if (o.type == 'csg') { 382 | Object.setPrototypeOf(o, CSG.prototype); 383 | o.polygons.map( function(p) { 384 | Object.setPrototypeOf(p, CSG.Polygon.prototype); 385 | p.vertices.map(function(v) { 386 | Object.setPrototypeOf(v, CSG.Vertex.prototype); 387 | Object.setPrototypeOf(v.pos, CSG.Vector3D.prototype); 388 | }); 389 | Object.setPrototypeOf(p.shared, CSG.Polygon.Shared.prototype); 390 | Object.setPrototypeOf(p.plane, CSG.Plane.prototype); 391 | Object.setPrototypeOf(p.plane.normal, CSG.Vector3D.prototype); 392 | }); 393 | o.properties = new CSG.Properties(); 394 | } 395 | return o; 396 | }; 397 | 398 | CAG.prototype.toJSON = function() { 399 | var str = '{ "type": "cag","sides": ['; 400 | var comma = ''; 401 | this.sides.map( 402 | function(side) { 403 | str += comma; 404 | str += JSON.stringify(side); 405 | comma = ','; 406 | } 407 | ); 408 | str += '] }'; 409 | return new Blob([str], { 410 | type: "application/json" 411 | }); 412 | }; 413 | 414 | // convert the given (anonymous JSON) object into CAG 415 | // Note: Any issues during conversion will result in exceptions 416 | CAG.prototype.fromJSON = function(o) { 417 | // verify the object IS convertable 418 | if (o.type == 'cag') { 419 | Object.setPrototypeOf(o, CAG.prototype); 420 | o.sides.map( function(side) { 421 | Object.setPrototypeOf(side, CAG.Side.prototype); 422 | Object.setPrototypeOf(side.vertex0, CAG.Vertex.prototype); 423 | Object.setPrototypeOf(side.vertex1, CAG.Vertex.prototype); 424 | Object.setPrototypeOf(side.vertex0.pos, CSG.Vector2D.prototype); 425 | Object.setPrototypeOf(side.vertex1.pos, CSG.Vector2D.prototype); 426 | } 427 | ); 428 | } 429 | return o; 430 | }; 431 | 432 | //////////////////////////////////////////// 433 | // SVG Export 434 | //////////////////////////////////////////// 435 | 436 | CAG.PathsToSvg = function(paths,bounds) { 437 | // calculate offsets in order to create paths orientated from the 0,0 axis 438 | var xoffset = 0 - bounds[0].x; 439 | var yoffset = 0 - bounds[0].y; 440 | var str = '\n'; 441 | paths.map(function(path) { 442 | str += '\n'; 456 | }); 457 | str += '\n'; 458 | return str; 459 | }; 460 | 461 | CAG.prototype.toSvg = function() { 462 | var decimals = 1000; 463 | 464 | // mirror the CAG about the X axis in order to generate paths into the POSITIVE direction 465 | var plane = new CSG.Plane(CSG.Vector3D.Create(0, 1, 0), 0); 466 | var cag = this.transform(CSG.Matrix4x4.mirroring(plane)); 467 | 468 | var bounds = cag.getBounds(); 469 | var paths = cag.getOutlinePaths(); 470 | var width = Math.round((bounds[1].x - bounds[0].x)*decimals)/decimals; 471 | var height = Math.round((bounds[1].y - bounds[0].y)*decimals)/decimals; 472 | var svg = '\n'; 473 | svg += '\n'; 474 | svg += '\n'; 475 | svg += '\n'; 476 | svg += CAG.PathsToSvg(paths,bounds); 477 | svg += ''; 478 | return new Blob([svg], { 479 | type: "image/svg+xml" 480 | }); 481 | }; 482 | 483 | // re-export CSG and CAG with the extended prototypes 484 | module.CSG = CSG; 485 | module.CAG = CAG; 486 | })(this); 487 | 488 | -------------------------------------------------------------------------------- /docs/.vuepress/dist/assets/css/0.styles.617c345f.css: -------------------------------------------------------------------------------- 1 | #nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:1.5rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title{display:block}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:.45rem 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper .dropdown-title .arrow{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid #ccc;border-bottom:0}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}}.page-edit,.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit,.page-nav{padding:2rem}}@media (max-width:419px){.page-edit,.page-nav{padding:1.5rem}}.page{padding-bottom:2rem;display:block}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#aaa}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number,div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.badge[data-v-c13ee5b0]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-c13ee5b0],.badge.tip[data-v-c13ee5b0],.badge[data-v-c13ee5b0]{background-color:#42b983}.badge.error[data-v-c13ee5b0]{background-color:#da5961}.badge.warn[data-v-c13ee5b0],.badge.warning[data-v-c13ee5b0],.badge.yellow[data-v-c13ee5b0]{background-color:#e7c000}.badge+.badge[data-v-c13ee5b0]{margin-left:5px} --------------------------------------------------------------------------------