├── icon.icns ├── icon.ico ├── test.json ├── icons ├── 16x16.png ├── 32x32.png ├── 64x64.png └── 512x512.png ├── .gitmodules ├── main ├── img │ ├── background.png │ ├── delete.svg │ ├── zoomout.svg │ ├── zoomin.svg │ ├── minus.svg │ ├── plus.svg │ ├── arrow_right.svg │ ├── close_dark.svg │ ├── reset.svg │ ├── stop.svg │ ├── progress.svg │ ├── close.svg │ ├── start.svg │ ├── arrow_down.svg │ ├── arrow_up.svg │ ├── info.svg │ ├── credits.svg │ ├── credits_light.svg │ ├── import.svg │ ├── account.svg │ ├── account_dark.svg │ ├── shop.svg │ ├── shop_dark.svg │ ├── unlimited_light.svg │ ├── unlimited.svg │ ├── download.svg │ ├── code.svg │ ├── auth0logo.svg │ ├── settings.svg │ ├── spin.svg │ ├── spin_dark.svg │ ├── logosmall.svg │ └── logo.svg ├── font │ ├── lato-hai-webfont.eot │ ├── lato-hai-webfont.ttf │ ├── lato-hai-webfont.woff │ ├── lato-lig-webfont.eot │ ├── lato-lig-webfont.ttf │ ├── lato-lig-webfont.woff │ ├── fonts │ │ ├── LatoLatin-Bold.eot │ │ ├── LatoLatin-Bold.ttf │ │ ├── LatoLatin-Bold.woff │ │ ├── LatoLatin-Bold.woff2 │ │ ├── LatoLatin-Light.eot │ │ ├── LatoLatin-Light.ttf │ │ ├── LatoLatin-Light.woff │ │ ├── LatoLatin-Light.woff2 │ │ ├── LatoLatin-Regular.eot │ │ ├── LatoLatin-Regular.ttf │ │ ├── LatoLatin-Regular.woff │ │ ├── LatoLatin-Regular.woff2 │ │ ├── LatoLatin-BoldItalic.eot │ │ ├── LatoLatin-BoldItalic.ttf │ │ ├── LatoLatin-BoldItalic.woff │ │ └── LatoLatin-BoldItalic.woff2 │ ├── generator_config.txt │ ├── stylesheet.css │ ├── specimen_files │ │ ├── easytabs.js │ │ ├── grid_12-825-55-15.css │ │ └── specimen_stylesheet.css │ └── latolatinfonts.css ├── util │ ├── eval.js │ ├── domparser.js │ ├── hull.js │ ├── json.js │ ├── simplify.js │ ├── matrix.js │ ├── d3-polygon.js │ ├── placementworker.js │ ├── filesaver.js │ └── parallel.js ├── background.html ├── LICENSE.txt ├── login.html └── readme.md ├── minkowski ├── Release │ ├── addon.node │ ├── obj.target │ │ └── addon │ │ │ ├── addon.o │ │ │ └── minkowski.o │ └── .deps │ │ └── Release │ │ └── addon.node.d ├── binding.Makefile ├── config.gypi ├── addon.target.mk └── Makefile ├── minkowski.h ├── renderer.js ├── addon.cc ├── binding.gyp mac ├── binding.gyp ├── binding.windowsgyp ├── README.md ├── package.json ├── main.js ├── minkowski.cc └── minkowski thread.cc /icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icon.icns -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icon.ico -------------------------------------------------------------------------------- /test.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/test.json -------------------------------------------------------------------------------- /icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icons/16x16.png -------------------------------------------------------------------------------- /icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icons/32x32.png -------------------------------------------------------------------------------- /icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icons/64x64.png -------------------------------------------------------------------------------- /icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/icons/512x512.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "polygon"] 2 | path = polygon 3 | url = https://github.com/boostorg/polygon.git 4 | -------------------------------------------------------------------------------- /main/img/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/img/background.png -------------------------------------------------------------------------------- /minkowski/Release/addon.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/minkowski/Release/addon.node -------------------------------------------------------------------------------- /main/font/lato-hai-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-hai-webfont.eot -------------------------------------------------------------------------------- /main/font/lato-hai-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-hai-webfont.ttf -------------------------------------------------------------------------------- /main/font/lato-hai-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-hai-webfont.woff -------------------------------------------------------------------------------- /main/font/lato-lig-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-lig-webfont.eot -------------------------------------------------------------------------------- /main/font/lato-lig-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-lig-webfont.ttf -------------------------------------------------------------------------------- /main/font/lato-lig-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/lato-lig-webfont.woff -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Bold.eot -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Bold.ttf -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Bold.woff -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Bold.woff2 -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Light.eot -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Light.ttf -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Light.woff -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Light.woff2 -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Regular.eot -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Regular.ttf -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Regular.woff -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-Regular.woff2 -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-BoldItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-BoldItalic.eot -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-BoldItalic.ttf -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-BoldItalic.woff -------------------------------------------------------------------------------- /main/font/fonts/LatoLatin-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/main/font/fonts/LatoLatin-BoldItalic.woff2 -------------------------------------------------------------------------------- /minkowski/Release/obj.target/addon/addon.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/minkowski/Release/obj.target/addon/addon.o -------------------------------------------------------------------------------- /minkowski/Release/obj.target/addon/minkowski.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfernoEmbedded/Deepnest/HEAD/minkowski/Release/obj.target/addon/minkowski.o -------------------------------------------------------------------------------- /minkowski/binding.Makefile: -------------------------------------------------------------------------------- 1 | # This file is generated by gyp; do not edit. 2 | 3 | export builddir_name ?= ./build/. 4 | .PHONY: all 5 | all: 6 | $(MAKE) addon 7 | -------------------------------------------------------------------------------- /minkowski.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define BOOST_POLYGON_NO_DEPS 4 | #include 5 | 6 | NAN_METHOD(calculateNFP); 7 | -------------------------------------------------------------------------------- /renderer.js: -------------------------------------------------------------------------------- 1 | // This file is required by the index.html file and will 2 | // be executed in the renderer process for that window. 3 | // All of the Node.js APIs are available in this process. 4 | -------------------------------------------------------------------------------- /main/util/eval.js: -------------------------------------------------------------------------------- 1 | var isNode = typeof module !== 'undefined' && module.exports; 2 | 3 | if (isNode) { 4 | process.once('message', function (code) { 5 | eval(JSON.parse(code).data); 6 | }); 7 | } else { 8 | self.onmessage = function (code) { 9 | eval(code.data); 10 | }; 11 | } -------------------------------------------------------------------------------- /minkowski/Release/.deps/Release/addon.node.d: -------------------------------------------------------------------------------- 1 | cmd_Release/addon.node := c++ -bundle -undefined dynamic_lookup -Wl,-no_pie -Wl,-search_paths_first -mmacosx-version-min=10.7 -arch x86_64 -L./Release -o Release/addon.node Release/obj.target/addon/addon.o Release/obj.target/addon/minkowski.o 2 | -------------------------------------------------------------------------------- /main/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /main/img/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "minkowski.h" 3 | 4 | using v8::FunctionTemplate; 5 | using v8::Handle; 6 | using v8::Object; 7 | using v8::String; 8 | using Nan::GetFunction; 9 | using Nan::New; 10 | using Nan::Set; 11 | 12 | // Expose synchronous and asynchronous access to our 13 | // Estimate() function 14 | NAN_MODULE_INIT(InitAll) { 15 | Set(target, New("calculateNFP").ToLocalChecked(), 16 | GetFunction(New(calculateNFP)).ToLocalChecked()); 17 | } 18 | 19 | NODE_MODULE(addon, InitAll) 20 | -------------------------------------------------------------------------------- /main/img/zoomout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /main/font/generator_config.txt: -------------------------------------------------------------------------------- 1 | # Font Squirrel Font-face Generator Configuration File 2 | # Upload this file to the generator to recreate the settings 3 | # you used to create these fonts. 4 | 5 | {"mode":"optimal","formats":["ttf","woff","eotz"],"tt_instructor":"default","fix_vertical_metrics":"Y","fix_gasp":"xy","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"} -------------------------------------------------------------------------------- /binding.gyp mac: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "minkowski.cc" ], 6 | 'cflags!': [ '-fno-exceptions' ], 7 | 'cflags_cc!': [ '-fno-exceptions' ], 8 | 'conditions': [ 9 | ['OS=="mac"', { 10 | 'xcode_settings': { 11 | 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' 12 | } 13 | }] 14 | ], 15 | "include_dirs" : [ 16 | " 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /main/img/minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "minkowski.cc" ], 6 | 'cflags!': [ '-fno-exceptions', "-m64" ], 7 | "ldflags": [ "-m elf_i386" ], 8 | 'cflags_cc!': [ '-fno-exceptions', '-fPIC -m64' ], 9 | 'conditions': [ 10 | ['OS=="mac"', { 11 | 'xcode_settings': { 12 | 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' 13 | } 14 | }] 15 | ], 16 | "include_dirs" : [ 17 | " 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /main/img/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /main/img/close_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /main/img/reset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /main/img/stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /main/img/progress.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /main/img/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 13 | 14 | -------------------------------------------------------------------------------- /main/img/start.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/img/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /main/img/arrow_up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Deepnest 2 | 3 | **Deepnest**: A fast, robust nesting tool for laser cutters and other CNC tools 4 | 5 | **Download:** https://deepnest.io 6 | 7 | Deepnest is a desktop application based on [SVGNest](https://github.com/Jack000/SVGnest) 8 | 9 | - new nesting engine with speed critical code written in C 10 | - merges common lines for laser cuts 11 | - support for DXF files (via conversion) 12 | - new path approximation feature for highly complex parts 13 | 14 | To rebuild the native nesting engine 15 | - npm install --save-dev electron-rebuild 16 | - npm install 17 | - .\node_modules\.bin\electron-rebuild.cmd 18 | - copy contents of build/Release to minkowski/Release 19 | - To package app run electron-packager . deepnest --platform=win32 --arch=x64 -------------------------------------------------------------------------------- /main/img/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /main/font/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) on July 12, 2014 */ 2 | 3 | 4 | 5 | @font-face { 6 | font-family: 'latohairline'; 7 | src: url('lato-hai-webfont.eot'); 8 | src: url('lato-hai-webfont.eot?#iefix') format('embedded-opentype'), 9 | url('lato-hai-webfont.woff') format('woff'), 10 | url('lato-hai-webfont.ttf') format('truetype'), 11 | url('lato-hai-webfont.svg#latohairline') format('svg'); 12 | font-weight: normal; 13 | font-style: normal; 14 | 15 | } 16 | 17 | 18 | 19 | 20 | @font-face { 21 | font-family: 'latolight'; 22 | src: url('lato-lig-webfont.eot'); 23 | src: url('lato-lig-webfont.eot?#iefix') format('embedded-opentype'), 24 | url('lato-lig-webfont.woff') format('woff'), 25 | url('lato-lig-webfont.ttf') format('truetype'), 26 | url('lato-lig-webfont.svg#latolight') format('svg'); 27 | font-weight: normal; 28 | font-style: normal; 29 | 30 | } -------------------------------------------------------------------------------- /main/img/credits.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /main/img/credits_light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /main/img/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /main/util/domparser.js: -------------------------------------------------------------------------------- 1 | /* inspired by https://gist.github.com/1129031 */ 2 | /*global document, DOMParser*/ 3 | 4 | (function(DOMParser) { 5 | "use strict"; 6 | 7 | var 8 | proto = DOMParser.prototype 9 | , nativeParse = proto.parseFromString 10 | ; 11 | 12 | // Firefox/Opera/IE throw errors on unsupported types 13 | try { 14 | // WebKit returns null on unsupported types 15 | if ((new DOMParser()).parseFromString("", "text/html")) { 16 | // text/html parsing is natively supported 17 | return; 18 | } 19 | } catch (ex) {} 20 | 21 | proto.parseFromString = function(markup, type) { 22 | if (/^\s*text\/html\s*(?:;|$)/i.test(type)) { 23 | var 24 | doc = document.implementation.createHTMLDocument("") 25 | ; 26 | if (markup.toLowerCase().indexOf(' -1) { 27 | doc.documentElement.innerHTML = markup; 28 | } 29 | else { 30 | doc.body.innerHTML = markup; 31 | } 32 | return doc; 33 | } else { 34 | return nativeParse.apply(this, arguments); 35 | } 36 | }; 37 | }(DOMParser)); -------------------------------------------------------------------------------- /main/font/specimen_files/easytabs.js: -------------------------------------------------------------------------------- 1 | (function($){$.fn.easyTabs=function(option){var param=jQuery.extend({fadeSpeed:"fast",defaultContent:1,activeClass:'active'},option);$(this).each(function(){var thisId="#"+this.id;if(param.defaultContent==''){param.defaultContent=1;} 2 | if(typeof param.defaultContent=="number") 3 | {var defaultTab=$(thisId+" .tabs li:eq("+(param.defaultContent-1)+") a").attr('href').substr(1);}else{var defaultTab=param.defaultContent;} 4 | $(thisId+" .tabs li a").each(function(){var tabToHide=$(this).attr('href').substr(1);$("#"+tabToHide).addClass('easytabs-tab-content');});hideAll();changeContent(defaultTab);function hideAll(){$(thisId+" .easytabs-tab-content").hide();} 5 | function changeContent(tabId){hideAll();$(thisId+" .tabs li").removeClass(param.activeClass);$(thisId+" .tabs li a[href=#"+tabId+"]").closest('li').addClass(param.activeClass);if(param.fadeSpeed!="none") 6 | {$(thisId+" #"+tabId).fadeIn(param.fadeSpeed);}else{$(thisId+" #"+tabId).show();}} 7 | $(thisId+" .tabs li").click(function(){var tabId=$(this).find('a').attr('href').substr(1);changeContent(tabId);return false;});});}})(jQuery); -------------------------------------------------------------------------------- /main/img/account.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /main/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jack Qiao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /main/img/account_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /main/img/shop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /main/img/shop_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /main/img/unlimited_light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /main/img/unlimited.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /main/img/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/img/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Deepnest.io", 3 | "version": "1.0.5db", 4 | "description": "Deep nesting for Laser and CNC", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron .", 8 | "configure": "node-gyp configure --release", 9 | "build": "node-gyp rebuild --target=1.4.8 --arch=x64 --dist-url=https://atom.io/download/atom-shell", 10 | "clean": "node-gyp clean configure build --verbose --target=1.4.8 --arch=x64 --dist-url=https://atom.io/download/atom-shell", 11 | "pack": "build --dir", 12 | "dist": "build", 13 | "postinstall": "electron-builder install-app-deps" 14 | }, 15 | "repository": "https://github.com/Jack000", 16 | "keywords": [ 17 | "Electron", 18 | "Nesting", 19 | "CNC", 20 | "Laser" 21 | ], 22 | "author": { 23 | "name": "Jack Qiao", 24 | "email": "jak000@gmail.com", 25 | "url": "http://deepnest.io" 26 | }, 27 | "devDependencies": { 28 | "electron": "^1.4.1", 29 | "electron-builder": "^20.26.0", 30 | "electron-rebuild": "^1.8.4" 31 | }, 32 | "dependencies": { 33 | "electron-config": "^0.2.1", 34 | "electron-settings": "^2.2.2", 35 | "electron-window-manager": "^1.0.4", 36 | "filequeue": "^0.5.0", 37 | "graceful-fs": "^4.1.11", 38 | "melanke-watchjs": "^1.3.1", 39 | "nan": "^2.4.0", 40 | "paralleljs": "^0.2.1", 41 | "request": "^2.79.0", 42 | "write-file-queue": "0.0.1" 43 | }, 44 | "build": { 45 | "appId": "com.deepnest.io", 46 | "copyright": "Copyright 2016 Jack Qiao", 47 | "compression": "maximum", 48 | "nodeGypRebuild": false, 49 | "mac": { 50 | "category": "public.app-category.utilities", 51 | "icon": "icon.icns" 52 | }, 53 | "win": { 54 | "icon": "icon.ico" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /main/font/latolatinfonts.css: -------------------------------------------------------------------------------- 1 | /* Webfont: LatoLatin-Bold */@font-face { 2 | font-family: 'LatoLatinWeb'; 3 | src: url('fonts/LatoLatin-Bold.eot'); /* IE9 Compat Modes */ 4 | src: url('fonts/LatoLatin-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('fonts/LatoLatin-Bold.woff2') format('woff2'), /* Modern Browsers */ 6 | url('fonts/LatoLatin-Bold.woff') format('woff'), /* Modern Browsers */ 7 | url('fonts/LatoLatin-Bold.ttf') format('truetype'); 8 | font-style: normal; 9 | font-weight: bold; 10 | text-rendering: optimizeLegibility; 11 | } 12 | 13 | /* Webfont: LatoLatin-Regular */@font-face { 14 | font-family: 'LatoLatinWeb'; 15 | src: url('fonts/LatoLatin-Regular.eot'); /* IE9 Compat Modes */ 16 | src: url('fonts/LatoLatin-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 17 | url('fonts/LatoLatin-Regular.woff2') format('woff2'), /* Modern Browsers */ 18 | url('fonts/LatoLatin-Regular.woff') format('woff'), /* Modern Browsers */ 19 | url('fonts/LatoLatin-Regular.ttf') format('truetype'); 20 | font-style: normal; 21 | font-weight: normal; 22 | text-rendering: optimizeLegibility; 23 | } 24 | 25 | /* Webfont: LatoLatin-Light */@font-face { 26 | font-family: 'LatoLatinWebLight'; 27 | src: url('fonts/LatoLatin-Light.eot'); /* IE9 Compat Modes */ 28 | src: url('fonts/LatoLatin-Light.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 29 | url('fonts/LatoLatin-Light.woff2') format('woff2'), /* Modern Browsers */ 30 | url('fonts/LatoLatin-Light.woff') format('woff'), /* Modern Browsers */ 31 | url('fonts/LatoLatin-Light.ttf') format('truetype'); 32 | font-style: normal; 33 | font-weight: normal; 34 | text-rendering: optimizeLegibility; 35 | } -------------------------------------------------------------------------------- /main/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Deepnest login 4 | 5 | 6 | 7 | 64 | 65 | 75 | 76 | 77 |
78 | 79 |
80 | 81 | -------------------------------------------------------------------------------- /main/img/auth0logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /main/util/hull.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Graham's Scan Convex Hull Algorithm 3 | * @desc An implementation of the Graham's Scan Convex Hull algorithm in JavaScript. 4 | * @author Brian Barnett, brian@3kb.co.uk, http://brianbar.net/ || http://3kb.co.uk/ 5 | * @version 1.0.4 6 | */ 7 | function ConvexHullGrahamScan(){this.anchorPoint=void 0,this.reverse=!1,this.points=[]}ConvexHullGrahamScan.prototype={constructor:ConvexHullGrahamScan,Point:function(n,t){this.x=n,this.y=t},_findPolarAngle:function(n,t){var i,o,h=57.295779513082;if(!n||!t)return 0;if(i=t.x-n.x,o=t.y-n.y,0==i&&0==o)return 0;var r=Math.atan2(o,i)*h;return this.reverse?0>=r&&(r+=360):r>=0&&(r+=360),r},addPoint:function(n,t){return void 0===this.anchorPoint?void(this.anchorPoint=new this.Point(n,t)):this.anchorPoint.y>t&&this.anchorPoint.x>n||this.anchorPoint.y===t&&this.anchorPoint.x>n||this.anchorPoint.y>t&&this.anchorPoint.x===n?(this.points.push(new this.Point(this.anchorPoint.x,this.anchorPoint.y)),void(this.anchorPoint=new this.Point(n,t))):void this.points.push(new this.Point(n,t))},_sortPoints:function(){var n=this;return this.points.sort(function(t,i){var o=n._findPolarAngle(n.anchorPoint,t),h=n._findPolarAngle(n.anchorPoint,i);return h>o?-1:o>h?1:0})},_checkPoints:function(n,t,i){var o,h=this._findPolarAngle(n,t),r=this._findPolarAngle(n,i);return h>r?(o=h-r,!(o>180)):r>h?(o=r-h,o>180):!0},getHull:function(){var n,t,i=[];if(this.reverse=this.points.every(function(n){return n.x<0&&n.y<0}),n=this._sortPoints(),t=n.length,3>t)return n.unshift(this.anchorPoint),n;for(i.push(n.shift(),n.shift());;){var o,h,r;if(i.push(n.shift()),o=i[i.length-3],h=i[i.length-2],r=i[i.length-1],this._checkPoints(o,h,r)&&i.splice(i.length-2,1),0==n.length){if(t==i.length){var e=this.anchorPoint;return i=i.filter(function(n){return!!n}),i.some(function(n){return n.x==e.x&&n.y==e.y})||i.unshift(this.anchorPoint),i}n=i,t=n.length,i=[],i.push(n.shift(),n.shift())}}}},"function"==typeof define&&define.amd&&define(function(){return ConvexHullGrahamScan}),"undefined"!=typeof module&&(module.exports=ConvexHullGrahamScan); -------------------------------------------------------------------------------- /main/img/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /main/img/spin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/img/spin_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/util/json.js: -------------------------------------------------------------------------------- 1 | var JSON;if(!JSON){JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i 1) { 35 | x = p2.x; 36 | y = p2.y; 37 | 38 | } else if (t > 0) { 39 | x += dx * t; 40 | y += dy * t; 41 | } 42 | } 43 | 44 | dx = p.x - x; 45 | dy = p.y - y; 46 | 47 | return dx * dx + dy * dy; 48 | } 49 | // rest of the code doesn't care about point format 50 | 51 | // basic distance-based simplification 52 | function simplifyRadialDist(points, sqTolerance) { 53 | 54 | var prevPoint = points[0], 55 | newPoints = [prevPoint], 56 | point; 57 | 58 | for (var i = 1, len = points.length; i < len; i++) { 59 | point = points[i]; 60 | 61 | if (point.marked || getSqDist(point, prevPoint) > sqTolerance) { 62 | newPoints.push(point); 63 | prevPoint = point; 64 | } 65 | } 66 | 67 | if (prevPoint !== point) newPoints.push(point); 68 | 69 | return newPoints; 70 | } 71 | 72 | function simplifyDPStep(points, first, last, sqTolerance, simplified) { 73 | var maxSqDist = sqTolerance; 74 | var index = -1; 75 | var marked = false; 76 | for (var i = first + 1; i < last; i++) { 77 | var sqDist = getSqSegDist(points[i], points[first], points[last]); 78 | 79 | if (sqDist > maxSqDist) { 80 | index = i; 81 | maxSqDist = sqDist; 82 | } 83 | /*if(points[i].marked && maxSqDist <= sqTolerance){ 84 | index = i; 85 | marked = true; 86 | }*/ 87 | } 88 | 89 | /*if(!points[index] && maxSqDist > sqTolerance){ 90 | console.log('shit shit shit'); 91 | }*/ 92 | 93 | if (maxSqDist > sqTolerance || marked) { 94 | if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified); 95 | simplified.push(points[index]); 96 | if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified); 97 | } 98 | } 99 | 100 | // simplification using Ramer-Douglas-Peucker algorithm 101 | function simplifyDouglasPeucker(points, sqTolerance) { 102 | var last = points.length - 1; 103 | 104 | var simplified = [points[0]]; 105 | simplifyDPStep(points, 0, last, sqTolerance, simplified); 106 | simplified.push(points[last]); 107 | 108 | return simplified; 109 | } 110 | 111 | // both algorithms combined for awesome performance 112 | function simplify(points, tolerance, highestQuality) { 113 | 114 | if (points.length <= 2) return points; 115 | 116 | var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1; 117 | 118 | points = highestQuality ? points : simplifyRadialDist(points, sqTolerance); 119 | points = simplifyDouglasPeucker(points, sqTolerance); 120 | 121 | return points; 122 | } 123 | 124 | window.simplify = simplify; 125 | 126 | })(); -------------------------------------------------------------------------------- /main/img/logosmall.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /main/util/matrix.js: -------------------------------------------------------------------------------- 1 | // matrix utility from SvgPath 2 | // https://github.com/fontello/svgpath 3 | 4 | 'use strict'; 5 | 6 | function Matrix() { 7 | if (!(this instanceof Matrix)) { return new Matrix(); } 8 | this.queue = []; // list of matrixes to apply 9 | this.cache = null; // combined matrix cache 10 | } 11 | 12 | // combine 2 matrixes 13 | // m1, m2 - [a, b, c, d, e, g] 14 | // 15 | Matrix.prototype.combine = function(m1, m2) { 16 | return [ 17 | m1[0] * m2[0] + m1[2] * m2[1], 18 | m1[1] * m2[0] + m1[3] * m2[1], 19 | m1[0] * m2[2] + m1[2] * m2[3], 20 | m1[1] * m2[2] + m1[3] * m2[3], 21 | m1[0] * m2[4] + m1[2] * m2[5] + m1[4], 22 | m1[1] * m2[4] + m1[3] * m2[5] + m1[5] 23 | ]; 24 | } 25 | 26 | Matrix.prototype.isIdentity = function(){ 27 | if (!this.cache) { 28 | this.cache = this.toArray(); 29 | } 30 | 31 | var m = this.cache; 32 | 33 | if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) { 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | Matrix.prototype.matrix = function (m) { 40 | if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) { 41 | return this; 42 | } 43 | this.cache = null; 44 | this.queue.push(m); 45 | return this; 46 | }; 47 | 48 | 49 | Matrix.prototype.translate = function (tx, ty) { 50 | if (tx !== 0 || ty !== 0) { 51 | this.cache = null; 52 | this.queue.push([ 1, 0, 0, 1, tx, ty ]); 53 | } 54 | return this; 55 | }; 56 | 57 | 58 | Matrix.prototype.scale = function (sx, sy) { 59 | if (sx !== 1 || sy !== 1) { 60 | this.cache = null; 61 | this.queue.push([ sx, 0, 0, sy, 0, 0 ]); 62 | } 63 | return this; 64 | }; 65 | 66 | 67 | Matrix.prototype.rotate = function (angle, rx, ry) { 68 | var rad, cos, sin; 69 | 70 | if (angle !== 0) { 71 | this.translate(rx, ry); 72 | 73 | rad = angle * Math.PI / 180; 74 | cos = Math.cos(rad); 75 | sin = Math.sin(rad); 76 | 77 | this.queue.push([ cos, sin, -sin, cos, 0, 0 ]); 78 | this.cache = null; 79 | 80 | this.translate(-rx, -ry); 81 | } 82 | return this; 83 | }; 84 | 85 | 86 | Matrix.prototype.skewX = function (angle) { 87 | if (angle !== 0) { 88 | this.cache = null; 89 | this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]); 90 | } 91 | return this; 92 | }; 93 | 94 | 95 | Matrix.prototype.skewY = function (angle) { 96 | if (angle !== 0) { 97 | this.cache = null; 98 | this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]); 99 | } 100 | return this; 101 | }; 102 | 103 | 104 | // Flatten queue 105 | // 106 | Matrix.prototype.toArray = function () { 107 | if (this.cache) { 108 | return this.cache; 109 | } 110 | 111 | if (!this.queue.length) { 112 | this.cache = [ 1, 0, 0, 1, 0, 0 ]; 113 | return this.cache; 114 | } 115 | 116 | this.cache = this.queue[0]; 117 | 118 | if (this.queue.length === 1) { 119 | return this.cache; 120 | } 121 | 122 | for (var i = 1; i < this.queue.length; i++) { 123 | this.cache = this.combine(this.cache, this.queue[i]); 124 | } 125 | 126 | return this.cache; 127 | }; 128 | 129 | 130 | // Apply list of matrixes to (x,y) point. 131 | // If `isRelative` set, `translate` component of matrix will be skipped 132 | // 133 | Matrix.prototype.calc = function (x, y, isRelative) { 134 | var m, i, len; 135 | 136 | // Don't change point on empty transforms queue 137 | if (!this.queue.length) { return [ x, y ]; } 138 | 139 | // Calculate final matrix, if not exists 140 | // 141 | // NB. if you deside to apply transforms to point one-by-one, 142 | // they should be taken in reverse order 143 | 144 | if (!this.cache) { 145 | this.cache = this.toArray(); 146 | } 147 | 148 | m = this.cache; 149 | 150 | // Apply matrix to point 151 | return [ 152 | x * m[0] + y * m[2] + (isRelative ? 0 : m[4]), 153 | x * m[1] + y * m[3] + (isRelative ? 0 : m[5]) 154 | ]; 155 | }; 156 | -------------------------------------------------------------------------------- /main/util/d3-polygon.js: -------------------------------------------------------------------------------- 1 | // https://d3js.org/d3-polygon/ Version 1.0.2. Copyright 2016 Mike Bostock. 2 | (function (global, factory) { 3 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 4 | typeof define === 'function' && define.amd ? define(['exports'], factory) : 5 | (factory((global.d3 = global.d3 || {}))); 6 | }(this, (function (exports) { 'use strict'; 7 | 8 | var area = function(polygon) { 9 | var i = -1, 10 | n = polygon.length, 11 | a, 12 | b = polygon[n - 1], 13 | area = 0; 14 | 15 | while (++i < n) { 16 | a = b; 17 | b = polygon[i]; 18 | area += a[1] * b[0] - a[0] * b[1]; 19 | } 20 | 21 | return area / 2; 22 | }; 23 | 24 | var centroid = function(polygon) { 25 | var i = -1, 26 | n = polygon.length, 27 | x = 0, 28 | y = 0, 29 | a, 30 | b = polygon[n - 1], 31 | c, 32 | k = 0; 33 | 34 | while (++i < n) { 35 | a = b; 36 | b = polygon[i]; 37 | k += c = a[0] * b[1] - b[0] * a[1]; 38 | x += (a[0] + b[0]) * c; 39 | y += (a[1] + b[1]) * c; 40 | } 41 | 42 | return k *= 3, [x / k, y / k]; 43 | }; 44 | 45 | // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of 46 | // the 3D cross product in a quadrant I Cartesian coordinate system (+x is 47 | // right, +y is up). Returns a positive value if ABC is counter-clockwise, 48 | // negative if clockwise, and zero if the points are collinear. 49 | var cross = function(a, b, c) { 50 | return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); 51 | }; 52 | 53 | function lexicographicOrder(a, b) { 54 | return a[0] - b[0] || a[1] - b[1]; 55 | } 56 | 57 | // Computes the upper convex hull per the monotone chain algorithm. 58 | // Assumes points.length >= 3, is sorted by x, unique in y. 59 | // Returns an array of indices into points in left-to-right order. 60 | function computeUpperHullIndexes(points) { 61 | var n = points.length, 62 | indexes = [0, 1], 63 | size = 2; 64 | 65 | for (var i = 2; i < n; ++i) { 66 | while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size; 67 | indexes[size++] = i; 68 | } 69 | 70 | return indexes.slice(0, size); // remove popped points 71 | } 72 | 73 | var hull = function(points) { 74 | if ((n = points.length) < 3) return null; 75 | 76 | var i, 77 | n, 78 | sortedPoints = new Array(n), 79 | flippedPoints = new Array(n); 80 | 81 | for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i]; 82 | sortedPoints.sort(lexicographicOrder); 83 | for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]]; 84 | 85 | var upperIndexes = computeUpperHullIndexes(sortedPoints), 86 | lowerIndexes = computeUpperHullIndexes(flippedPoints); 87 | 88 | // Construct the hull polygon, removing possible duplicate endpoints. 89 | var skipLeft = lowerIndexes[0] === upperIndexes[0], 90 | skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], 91 | hull = []; 92 | 93 | // Add upper hull in right-to-l order. 94 | // Then add lower hull in left-to-right order. 95 | for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]); 96 | for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]); 97 | 98 | return hull; 99 | }; 100 | 101 | var contains = function(polygon, point) { 102 | var n = polygon.length, 103 | p = polygon[n - 1], 104 | x = point[0], y = point[1], 105 | x0 = p[0], y0 = p[1], 106 | x1, y1, 107 | inside = false; 108 | 109 | for (var i = 0; i < n; ++i) { 110 | p = polygon[i], x1 = p[0], y1 = p[1]; 111 | if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside; 112 | x0 = x1, y0 = y1; 113 | } 114 | 115 | return inside; 116 | }; 117 | 118 | var length = function(polygon) { 119 | var i = -1, 120 | n = polygon.length, 121 | b = polygon[n - 1], 122 | xa, 123 | ya, 124 | xb = b[0], 125 | yb = b[1], 126 | perimeter = 0; 127 | 128 | while (++i < n) { 129 | xa = xb; 130 | ya = yb; 131 | b = polygon[i]; 132 | xb = b[0]; 133 | yb = b[1]; 134 | xa -= xb; 135 | ya -= yb; 136 | perimeter += Math.sqrt(xa * xa + ya * ya); 137 | } 138 | 139 | return perimeter; 140 | }; 141 | 142 | exports.polygonArea = area; 143 | exports.polygonCentroid = centroid; 144 | exports.polygonHull = hull; 145 | exports.polygonContains = contains; 146 | exports.polygonLength = length; 147 | 148 | Object.defineProperty(exports, '__esModule', { value: true }); 149 | 150 | }))); 151 | -------------------------------------------------------------------------------- /main/font/specimen_files/grid_12-825-55-15.css: -------------------------------------------------------------------------------- 1 | /*Notes about grid: 2 | Columns: 12 3 | Grid Width: 825px 4 | Column Width: 55px 5 | Gutter Width: 15px 6 | -------------------------------*/ 7 | 8 | 9 | 10 | .section {margin-bottom: 18px; 11 | } 12 | .section:after {content: ".";display: block;height: 0;clear: both;visibility: hidden;} 13 | .section {*zoom: 1;} 14 | 15 | .section .firstcolumn, 16 | .section .firstcol {margin-left: 0;} 17 | 18 | 19 | /* Border on left hand side of a column. */ 20 | .border { 21 | padding-left: 7px; 22 | margin-left: 7px; 23 | border-left: 1px solid #eee; 24 | } 25 | 26 | /* Border with more whitespace, spans one column. */ 27 | .colborder { 28 | padding-left: 42px; 29 | margin-left: 42px; 30 | border-left: 1px solid #eee; 31 | } 32 | 33 | 34 | 35 | /* The Grid Classes */ 36 | .grid1, .grid1_2cols, .grid1_3cols, .grid1_4cols, .grid2, .grid2_3cols, .grid2_4cols, .grid3, .grid3_2cols, .grid3_4cols, .grid4, .grid4_3cols, .grid5, .grid5_2cols, .grid5_3cols, .grid5_4cols, .grid6, .grid6_4cols, .grid7, .grid7_2cols, .grid7_3cols, .grid7_4cols, .grid8, .grid8_3cols, .grid9, .grid9_2cols, .grid9_4cols, .grid10, .grid10_3cols, .grid10_4cols, .grid11, .grid11_2cols, .grid11_3cols, .grid11_4cols, .grid12 37 | {margin-left: 15px;float: left;display: inline; overflow: hidden;} 38 | 39 | 40 | .width1, .grid1, .span-1 {width: 55px;} 41 | .width1_2cols,.grid1_2cols {width: 20px;} 42 | .width1_3cols,.grid1_3cols {width: 8px;} 43 | .width1_4cols,.grid1_4cols {width: 2px;} 44 | .input_width1 {width: 49px;} 45 | 46 | .width2, .grid2, .span-2 {width: 125px;} 47 | .width2_3cols,.grid2_3cols {width: 31px;} 48 | .width2_4cols,.grid2_4cols {width: 20px;} 49 | .input_width2 {width: 119px;} 50 | 51 | .width3, .grid3, .span-3 {width: 195px;} 52 | .width3_2cols,.grid3_2cols {width: 90px;} 53 | .width3_4cols,.grid3_4cols {width: 37px;} 54 | .input_width3 {width: 189px;} 55 | 56 | .width4, .grid4, .span-4 {width: 265px;} 57 | .width4_3cols,.grid4_3cols {width: 78px;} 58 | .input_width4 {width: 259px;} 59 | 60 | .width5, .grid5, .span-5 {width: 335px;} 61 | .width5_2cols,.grid5_2cols {width: 160px;} 62 | .width5_3cols,.grid5_3cols {width: 101px;} 63 | .width5_4cols,.grid5_4cols {width: 72px;} 64 | .input_width5 {width: 329px;} 65 | 66 | .width6, .grid6, .span-6 {width: 405px;} 67 | .width6_4cols,.grid6_4cols {width: 90px;} 68 | .input_width6 {width: 399px;} 69 | 70 | .width7, .grid7, .span-7 {width: 475px;} 71 | .width7_2cols,.grid7_2cols {width: 230px;} 72 | .width7_3cols,.grid7_3cols {width: 148px;} 73 | .width7_4cols,.grid7_4cols {width: 107px;} 74 | .input_width7 {width: 469px;} 75 | 76 | .width8, .grid8, .span-8 {width: 545px;} 77 | .width8_3cols,.grid8_3cols {width: 171px;} 78 | .input_width8 {width: 539px;} 79 | 80 | .width9, .grid9, .span-9 {width: 615px;} 81 | .width9_2cols,.grid9_2cols {width: 300px;} 82 | .width9_4cols,.grid9_4cols {width: 142px;} 83 | .input_width9 {width: 609px;} 84 | 85 | .width10, .grid10, .span-10 {width: 685px;} 86 | .width10_3cols,.grid10_3cols {width: 218px;} 87 | .width10_4cols,.grid10_4cols {width: 160px;} 88 | .input_width10 {width: 679px;} 89 | 90 | .width11, .grid11, .span-11 {width: 755px;} 91 | .width11_2cols,.grid11_2cols {width: 370px;} 92 | .width11_3cols,.grid11_3cols {width: 241px;} 93 | .width11_4cols,.grid11_4cols {width: 177px;} 94 | .input_width11 {width: 749px;} 95 | 96 | .width12, .grid12, .span-12 {width: 825px;} 97 | .input_width12 {width: 819px;} 98 | 99 | /* Subdivided grid spaces */ 100 | .emptycols_left1, .prepend-1 {padding-left: 70px;} 101 | .emptycols_right1, .append-1 {padding-right: 70px;} 102 | .emptycols_left2, .prepend-2 {padding-left: 140px;} 103 | .emptycols_right2, .append-2 {padding-right: 140px;} 104 | .emptycols_left3, .prepend-3 {padding-left: 210px;} 105 | .emptycols_right3, .append-3 {padding-right: 210px;} 106 | .emptycols_left4, .prepend-4 {padding-left: 280px;} 107 | .emptycols_right4, .append-4 {padding-right: 280px;} 108 | .emptycols_left5, .prepend-5 {padding-left: 350px;} 109 | .emptycols_right5, .append-5 {padding-right: 350px;} 110 | .emptycols_left6, .prepend-6 {padding-left: 420px;} 111 | .emptycols_right6, .append-6 {padding-right: 420px;} 112 | .emptycols_left7, .prepend-7 {padding-left: 490px;} 113 | .emptycols_right7, .append-7 {padding-right: 490px;} 114 | .emptycols_left8, .prepend-8 {padding-left: 560px;} 115 | .emptycols_right8, .append-8 {padding-right: 560px;} 116 | .emptycols_left9, .prepend-9 {padding-left: 630px;} 117 | .emptycols_right9, .append-9 {padding-right: 630px;} 118 | .emptycols_left10, .prepend-10 {padding-left: 700px;} 119 | .emptycols_right10, .append-10 {padding-right: 700px;} 120 | .emptycols_left11, .prepend-11 {padding-left: 770px;} 121 | .emptycols_right11, .append-11 {padding-right: 770px;} 122 | .pull-1 {margin-left: -70px;} 123 | .push-1 {margin-right: -70px;margin-left: 18px;float: right;} 124 | .pull-2 {margin-left: -140px;} 125 | .push-2 {margin-right: -140px;margin-left: 18px;float: right;} 126 | .pull-3 {margin-left: -210px;} 127 | .push-3 {margin-right: -210px;margin-left: 18px;float: right;} 128 | .pull-4 {margin-left: -280px;} 129 | .push-4 {margin-right: -280px;margin-left: 18px;float: right;} -------------------------------------------------------------------------------- /minkowski/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "debug_devtools": "node", 13 | "force_dynamic_crt": 0, 14 | "host_arch": "x64", 15 | "icu_data_file": "icudt58l.dat", 16 | "icu_data_in": "../../deps/icu-small/source/data/in/icudt58l.dat", 17 | "icu_endianness": "l", 18 | "icu_gyp_path": "tools/icu/icu-generic.gyp", 19 | "icu_locales": "en,root", 20 | "icu_path": "deps/icu-small", 21 | "icu_small": "true", 22 | "icu_ver_major": "58", 23 | "llvm_version": 0, 24 | "node_byteorder": "little", 25 | "node_enable_d8": "false", 26 | "node_enable_v8_vtunejit": "false", 27 | "node_install_npm": "true", 28 | "node_module_version": 51, 29 | "node_no_browser_globals": "false", 30 | "node_prefix": "/", 31 | "node_release_urlbase": "https://nodejs.org/download/release/", 32 | "node_shared": "false", 33 | "node_shared_cares": "false", 34 | "node_shared_http_parser": "false", 35 | "node_shared_libuv": "false", 36 | "node_shared_openssl": "false", 37 | "node_shared_zlib": "false", 38 | "node_tag": "", 39 | "node_use_bundled_v8": "true", 40 | "node_use_dtrace": "true", 41 | "node_use_etw": "false", 42 | "node_use_lttng": "false", 43 | "node_use_openssl": "true", 44 | "node_use_perfctr": "false", 45 | "node_use_v8_platform": "true", 46 | "openssl_fips": "", 47 | "openssl_no_asm": 0, 48 | "shlib_suffix": "51.dylib", 49 | "target_arch": "x64", 50 | "uv_parent_path": "/deps/uv/", 51 | "uv_use_dtrace": "true", 52 | "v8_enable_gdbjit": 0, 53 | "v8_enable_i18n_support": 1, 54 | "v8_inspector": "true", 55 | "v8_no_strict_aliasing": 1, 56 | "v8_optimized_debug": 0, 57 | "v8_random_seed": 0, 58 | "v8_use_snapshot": "true", 59 | "want_separate_host_toolset": 0, 60 | "want_separate_host_toolset_mkpeephole": 0, 61 | "xcode_version": "7.0", 62 | "nodedir": "/Users/jackqiao/.node-gyp/iojs-1.4.8", 63 | "copy_dev_lib": "true", 64 | "standalone_static_library": 1, 65 | "target": "1.4.8", 66 | "dry_run": "", 67 | "legacy_bundling": "", 68 | "save_dev": "", 69 | "browser": "", 70 | "only": "", 71 | "viewer": "man", 72 | "also": "", 73 | "rollback": "true", 74 | "usage": "", 75 | "globalignorefile": "/Users/jackqiao/.nvm/versions/node/v7.1.0/etc/npmignore", 76 | "init_author_url": "", 77 | "maxsockets": "50", 78 | "shell": "/bin/bash", 79 | "parseable": "", 80 | "shrinkwrap": "true", 81 | "init_license": "ISC", 82 | "if_present": "", 83 | "cache_max": "Infinity", 84 | "init_author_email": "", 85 | "sign_git_tag": "", 86 | "cert": "", 87 | "git_tag_version": "true", 88 | "local_address": "", 89 | "long": "", 90 | "fetch_retries": "2", 91 | "npat": "", 92 | "registry": "https://registry.npmjs.org/", 93 | "key": "", 94 | "message": "%s", 95 | "versions": "", 96 | "globalconfig": "/Users/jackqiao/.nvm/versions/node/v7.1.0/etc/npmrc", 97 | "always_auth": "", 98 | "cache_lock_retries": "10", 99 | "global_style": "", 100 | "heading": "npm", 101 | "fetch_retry_mintimeout": "10000", 102 | "proprietary_attribs": "true", 103 | "access": "", 104 | "json": "", 105 | "description": "true", 106 | "engine_strict": "", 107 | "https_proxy": "", 108 | "init_module": "/Users/jackqiao/.npm-init.js", 109 | "userconfig": "/Users/jackqiao/.npmrc", 110 | "node_version": "7.1.0", 111 | "user": "501", 112 | "editor": "vi", 113 | "save": "", 114 | "tag": "latest", 115 | "global": "", 116 | "progress": "true", 117 | "optional": "true", 118 | "bin_links": "true", 119 | "force": "", 120 | "searchopts": "", 121 | "depth": "Infinity", 122 | "rebuild_bundle": "true", 123 | "searchsort": "name", 124 | "unicode": "true", 125 | "fetch_retry_maxtimeout": "60000", 126 | "ca": "", 127 | "save_prefix": "^", 128 | "strict_ssl": "true", 129 | "tag_version_prefix": "v", 130 | "dev": "", 131 | "fetch_retry_factor": "10", 132 | "group": "20", 133 | "save_exact": "", 134 | "cache_lock_stale": "60000", 135 | "version": "", 136 | "cache_min": "10", 137 | "cache": "/Users/jackqiao/.npm", 138 | "searchexclude": "", 139 | "color": "true", 140 | "save_optional": "", 141 | "user_agent": "npm/3.10.9 node/v7.1.0 darwin x64", 142 | "ignore_scripts": "", 143 | "cache_lock_wait": "10000", 144 | "production": "", 145 | "save_bundle": "", 146 | "init_version": "1.0.0", 147 | "umask": "0022", 148 | "git": "git", 149 | "init_author_name": "", 150 | "scope": "", 151 | "onload_script": "", 152 | "tmp": "/var/folders/my/zf1p50091f7glgvp_98zz8780000gn/T", 153 | "unsafe_perm": "true", 154 | "link": "", 155 | "prefix": "/Users/jackqiao/.nvm/versions/node/v7.1.0" 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /minkowski/addon.target.mk: -------------------------------------------------------------------------------- 1 | # This file is generated by gyp; do not edit. 2 | 3 | TOOLSET := target 4 | TARGET := addon 5 | DEFS_Debug := \ 6 | '-DNODE_GYP_MODULE_NAME=addon' \ 7 | '-DUSING_UV_SHARED=1' \ 8 | '-DUSING_V8_SHARED=1' \ 9 | '-DV8_DEPRECATION_WARNINGS=1' \ 10 | '-D_DARWIN_USE_64_BIT_INODE=1' \ 11 | '-D_LARGEFILE_SOURCE' \ 12 | '-D_FILE_OFFSET_BITS=64' \ 13 | '-DBUILDING_NODE_EXTENSION' \ 14 | '-DDEBUG' \ 15 | '-D_DEBUG' 16 | 17 | # Flags passed to all source files. 18 | CFLAGS_Debug := \ 19 | -O0 \ 20 | -gdwarf-2 \ 21 | -mmacosx-version-min=10.7 \ 22 | -arch x86_64 \ 23 | -Wall \ 24 | -Wendif-labels \ 25 | -W \ 26 | -Wno-unused-parameter 27 | 28 | # Flags passed to only C files. 29 | CFLAGS_C_Debug := \ 30 | -fno-strict-aliasing 31 | 32 | # Flags passed to only C++ files. 33 | CFLAGS_CC_Debug := \ 34 | -std=gnu++0x \ 35 | -fno-rtti \ 36 | -fno-threadsafe-statics \ 37 | -fno-strict-aliasing 38 | 39 | # Flags passed to only ObjC files. 40 | CFLAGS_OBJC_Debug := 41 | 42 | # Flags passed to only ObjC++ files. 43 | CFLAGS_OBJCC_Debug := 44 | 45 | INCS_Debug := \ 46 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/include/node \ 47 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/src \ 48 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/deps/uv/include \ 49 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/deps/v8/include \ 50 | -I$(srcdir)/node_modules/nan \ 51 | -I/Users/jackqiao/boost_1_62_0 52 | 53 | DEFS_Release := \ 54 | '-DNODE_GYP_MODULE_NAME=addon' \ 55 | '-DUSING_UV_SHARED=1' \ 56 | '-DUSING_V8_SHARED=1' \ 57 | '-DV8_DEPRECATION_WARNINGS=1' \ 58 | '-D_DARWIN_USE_64_BIT_INODE=1' \ 59 | '-D_LARGEFILE_SOURCE' \ 60 | '-D_FILE_OFFSET_BITS=64' \ 61 | '-DBUILDING_NODE_EXTENSION' 62 | 63 | # Flags passed to all source files. 64 | CFLAGS_Release := \ 65 | -Os \ 66 | -gdwarf-2 \ 67 | -mmacosx-version-min=10.7 \ 68 | -arch x86_64 \ 69 | -Wall \ 70 | -Wendif-labels \ 71 | -W \ 72 | -Wno-unused-parameter 73 | 74 | # Flags passed to only C files. 75 | CFLAGS_C_Release := \ 76 | -fno-strict-aliasing 77 | 78 | # Flags passed to only C++ files. 79 | CFLAGS_CC_Release := \ 80 | -std=gnu++0x \ 81 | -fno-rtti \ 82 | -fno-threadsafe-statics \ 83 | -fno-strict-aliasing 84 | 85 | # Flags passed to only ObjC files. 86 | CFLAGS_OBJC_Release := 87 | 88 | # Flags passed to only ObjC++ files. 89 | CFLAGS_OBJCC_Release := 90 | 91 | INCS_Release := \ 92 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/include/node \ 93 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/src \ 94 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/deps/uv/include \ 95 | -I/Users/jackqiao/.node-gyp/iojs-1.4.8/deps/v8/include \ 96 | -I$(srcdir)/node_modules/nan \ 97 | -I/Users/jackqiao/boost_1_62_0 98 | 99 | OBJS := \ 100 | $(obj).target/$(TARGET)/addon.o \ 101 | $(obj).target/$(TARGET)/minkowski.o 102 | 103 | # Add to the list of files we specially track dependencies for. 104 | all_deps += $(OBJS) 105 | 106 | # CFLAGS et al overrides must be target-local. 107 | # See "Target-specific Variable Values" in the GNU Make manual. 108 | $(OBJS): TOOLSET := $(TOOLSET) 109 | $(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) 110 | $(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) 111 | $(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) 112 | $(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) 113 | 114 | # Suffix rules, putting all outputs into $(obj). 115 | 116 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD 117 | @$(call do_cmd,cxx,1) 118 | 119 | # Try building from generated source, too. 120 | 121 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD 122 | @$(call do_cmd,cxx,1) 123 | 124 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD 125 | @$(call do_cmd,cxx,1) 126 | 127 | # End of this set of suffix rules 128 | ### Rules for final target. 129 | LDFLAGS_Debug := \ 130 | -undefined dynamic_lookup \ 131 | -Wl,-no_pie \ 132 | -Wl,-search_paths_first \ 133 | -mmacosx-version-min=10.7 \ 134 | -arch x86_64 \ 135 | -L$(builddir) 136 | 137 | LIBTOOLFLAGS_Debug := \ 138 | -undefined dynamic_lookup \ 139 | -Wl,-no_pie \ 140 | -Wl,-search_paths_first 141 | 142 | LDFLAGS_Release := \ 143 | -undefined dynamic_lookup \ 144 | -Wl,-no_pie \ 145 | -Wl,-search_paths_first \ 146 | -mmacosx-version-min=10.7 \ 147 | -arch x86_64 \ 148 | -L$(builddir) 149 | 150 | LIBTOOLFLAGS_Release := \ 151 | -undefined dynamic_lookup \ 152 | -Wl,-no_pie \ 153 | -Wl,-search_paths_first 154 | 155 | LIBS := 156 | 157 | $(builddir)/addon.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) 158 | $(builddir)/addon.node: LIBS := $(LIBS) 159 | $(builddir)/addon.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) 160 | $(builddir)/addon.node: TOOLSET := $(TOOLSET) 161 | $(builddir)/addon.node: $(OBJS) FORCE_DO_CMD 162 | $(call do_cmd,solink_module) 163 | 164 | all_deps += $(builddir)/addon.node 165 | # Add target alias 166 | .PHONY: addon 167 | addon: $(builddir)/addon.node 168 | 169 | # Short alias for building this executable. 170 | .PHONY: addon.node 171 | addon.node: $(builddir)/addon.node 172 | 173 | # Add executable to "all" target. 174 | .PHONY: all 175 | all: $(builddir)/addon.node 176 | 177 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | const { Menu, ipcMain } = electron 3 | const fs = require('graceful-fs'); 4 | 5 | // Module to control application life. 6 | const app = electron.app 7 | 8 | app.commandLine.appendSwitch('--enable-precise-memory-info'); 9 | 10 | // Module to create native browser window. 11 | const BrowserWindow = electron.BrowserWindow 12 | 13 | const path = require('path') 14 | const url = require('url') 15 | /* 16 | // main menu for mac 17 | const template = [ 18 | { 19 | label: 'Deepnest', 20 | submenu: [ 21 | { 22 | role: 'about' 23 | }, 24 | { 25 | type: 'separator' 26 | }, 27 | { 28 | role: 'services', 29 | submenu: [] 30 | }, 31 | { 32 | type: 'separator' 33 | }, 34 | { 35 | role: 'hide' 36 | }, 37 | { 38 | role: 'hideothers' 39 | }, 40 | { 41 | role: 'unhide' 42 | }, 43 | { 44 | type: 'separator' 45 | }, 46 | { 47 | role: 'quit' 48 | } 49 | ] 50 | } 51 | ]; 52 | 53 | const menu = Menu.buildFromTemplate(template); 54 | Menu.setApplicationMenu(menu); 55 | */ 56 | 57 | // Keep a global reference of the window object, if you don't, the window will 58 | // be closed automatically when the JavaScript object is garbage collected. 59 | let mainWindow = null; 60 | var backgroundWindows = []; 61 | 62 | // single instance 63 | const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { 64 | // Someone tried to run a second instance, we should focus our window. 65 | if (mainWindow) { 66 | if (mainWindow.isMinimized()) mainWindow.restore() 67 | mainWindow.focus() 68 | } 69 | }) 70 | 71 | if (shouldQuit) { 72 | app.quit() 73 | } 74 | 75 | function createMainWindow() { 76 | 77 | // Create the browser window. 78 | const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize; 79 | 80 | var frameless = process.platform == 'darwin'; 81 | //var frameless = true; 82 | 83 | mainWindow = new BrowserWindow({width: Math.ceil(width*0.9), height: Math.ceil(height*0.9), frame: !frameless, show: false}) 84 | 85 | // and load the index.html of the app. 86 | mainWindow.loadURL(url.format({ 87 | pathname: path.join(__dirname, './main/index.html'), 88 | protocol: 'file:', 89 | slashes: true 90 | })); 91 | 92 | mainWindow.setMenu(null); 93 | 94 | // Open the DevTools. 95 | //mainWindow.webContents.openDevTools() 96 | 97 | // Emitted when the window is closed. 98 | mainWindow.on('closed', function () { 99 | // Dereference the window object, usually you would store windows 100 | // in an array if your app supports multi windows, this is the time 101 | // when you should delete the corresponding element. 102 | mainWindow = null 103 | }) 104 | } 105 | 106 | let winCount = 0; 107 | 108 | function createBackgroundWindows() { 109 | //busyWindows = []; 110 | // used to have 8, now just 1 background window 111 | if(winCount < 1){ 112 | var back = new BrowserWindow({ 113 | show: false 114 | }); 115 | 116 | //back.webContents.openDevTools(); 117 | 118 | back.loadURL(url.format({ 119 | pathname: path.join(__dirname, './main/background.html'), 120 | protocol: 'file:', 121 | slashes: true 122 | })); 123 | 124 | backgroundWindows[winCount] = back; 125 | 126 | back.once('ready-to-show', () => { 127 | //back.show(); 128 | winCount++; 129 | createBackgroundWindows(); 130 | }); 131 | } 132 | } 133 | 134 | // This method will be called when Electron has finished 135 | // initialization and is ready to create browser windows. 136 | // Some APIs can only be used after this event occurs. 137 | app.on('ready', () => { 138 | createMainWindow(); 139 | mainWindow.once('ready-to-show', () => { 140 | mainWindow.show(); 141 | createBackgroundWindows(); 142 | }) 143 | mainWindow.on('closed', () => { 144 | app.quit(); 145 | }); 146 | }) 147 | 148 | // Quit when all windows are closed. 149 | app.on('window-all-closed', function () { 150 | app.quit() 151 | }) 152 | 153 | app.on('activate', function () { 154 | // On OS X it's common to re-create a window in the app when the 155 | // dock icon is clicked and there are no other windows open. 156 | if (mainWindow === null) { 157 | createWindow() 158 | } 159 | }) 160 | 161 | app.on('before-quit', function(){ 162 | var p = path.join(__dirname, './nfpcache') 163 | if( fs.existsSync(p) ) { 164 | fs.readdirSync(p).forEach(function(file,index){ 165 | var curPath = p + "/" + file; 166 | fs.unlinkSync(curPath); 167 | }); 168 | } 169 | }); 170 | 171 | //ipcMain.on('background-response', (event, payload) => mainWindow.webContents.send('background-response', payload)); 172 | //ipcMain.on('background-start', (event, payload) => backgroundWindows[0].webContents.send('background-start', payload)); 173 | 174 | ipcMain.on('background-start', function(event, payload){ 175 | console.log('starting background!'); 176 | for(var i=0; i 0){ 40 | rotated.children = []; 41 | for(var j=0; j 0){ 87 | 88 | var placed = []; 89 | var placements = []; 90 | fitness += 1; // add 1 for each new bin opened (lower fitness is better) 91 | 92 | for(i=0; i 2 && area > 0.1*self.config.clipperScale*self.config.clipperScale){ 173 | clipper.AddPath(clone, ClipperLib.PolyType.ptSubject, true); 174 | } 175 | } 176 | } 177 | 178 | if(!clipper.Execute(ClipperLib.ClipType.ctUnion, combinedNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){ 179 | continue; 180 | } 181 | 182 | // difference with bin polygon 183 | var finalNfp = new ClipperLib.Paths(); 184 | clipper = new ClipperLib.Clipper(); 185 | 186 | clipper.AddPaths(combinedNfp, ClipperLib.PolyType.ptClip, true); 187 | clipper.AddPaths(clipperBinNfp, ClipperLib.PolyType.ptSubject, true); 188 | if(!clipper.Execute(ClipperLib.ClipType.ctDifference, finalNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){ 189 | continue; 190 | } 191 | 192 | finalNfp = ClipperLib.Clipper.CleanPolygons(finalNfp, 0.0001*self.config.clipperScale); 193 | 194 | for(j=0; j= 0){ 273 | paths.splice(index,1); 274 | } 275 | } 276 | 277 | if(placements && placements.length > 0){ 278 | allplacements.push(placements); 279 | } 280 | else{ 281 | break; // something went wrong 282 | } 283 | } 284 | 285 | // there were parts that couldn't be placed 286 | fitness += 2*paths.length; 287 | 288 | return {placements: allplacements, fitness: fitness, paths: paths, area: binarea }; 289 | }; 290 | 291 | } 292 | 293 | // clipperjs uses alerts for warnings 294 | function alert(message) { 295 | console.log('alert: ', message); 296 | } -------------------------------------------------------------------------------- /main/font/specimen_files/specimen_stylesheet.css: -------------------------------------------------------------------------------- 1 | @import url('grid_12-825-55-15.css'); 2 | 3 | /* 4 | CSS Reset by Eric Meyer - Released under Public Domain 5 | http://meyerweb.com/eric/tools/css/reset/ 6 | */ 7 | html, body, div, span, applet, object, iframe, 8 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 9 | a, abbr, acronym, address, big, cite, code, 10 | del, dfn, em, font, img, ins, kbd, q, s, samp, 11 | small, strike, strong, sub, sup, tt, var, 12 | b, u, i, center, dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, table, 14 | caption, tbody, tfoot, thead, tr, th, td 15 | {margin: 0;padding: 0;border: 0;outline: 0; 16 | font-size: 100%;vertical-align: baseline; 17 | background: transparent;} 18 | body {line-height: 1;} 19 | ol, ul {list-style: none;} 20 | blockquote, q {quotes: none;} 21 | blockquote:before, blockquote:after, 22 | q:before, q:after {content: ''; content: none;} 23 | :focus {outline: 0;} 24 | ins {text-decoration: none;} 25 | del {text-decoration: line-through;} 26 | table {border-collapse: collapse;border-spacing: 0;} 27 | 28 | 29 | 30 | 31 | body { 32 | color: #000; 33 | background-color: #dcdcdc; 34 | } 35 | 36 | a { 37 | text-decoration: none; 38 | color: #1883ba; 39 | } 40 | 41 | h1{ 42 | font-size: 32px; 43 | font-weight: normal; 44 | font-style: normal; 45 | margin-bottom: 18px; 46 | } 47 | 48 | h2{ 49 | font-size: 18px; 50 | } 51 | 52 | #container { 53 | width: 865px; 54 | margin: 0px auto; 55 | } 56 | 57 | 58 | #header { 59 | padding: 20px; 60 | font-size: 36px; 61 | background-color: #000; 62 | color: #fff; 63 | } 64 | 65 | #header span { 66 | color: #666; 67 | } 68 | #main_content { 69 | background-color: #fff; 70 | padding: 60px 20px 20px; 71 | } 72 | 73 | 74 | #footer p { 75 | margin: 0; 76 | padding-top: 10px; 77 | padding-bottom: 50px; 78 | color: #333; 79 | font: 10px Arial, sans-serif; 80 | } 81 | 82 | .tabs { 83 | width: 100%; 84 | height: 31px; 85 | background-color: #444; 86 | } 87 | .tabs li { 88 | float: left; 89 | margin: 0; 90 | overflow: hidden; 91 | background-color: #444; 92 | } 93 | .tabs li a { 94 | display: block; 95 | color: #fff; 96 | text-decoration: none; 97 | font: bold 11px/11px 'Arial'; 98 | text-transform: uppercase; 99 | padding: 10px 15px; 100 | border-right: 1px solid #fff; 101 | } 102 | 103 | .tabs li a:hover { 104 | background-color: #00b3ff; 105 | 106 | } 107 | 108 | .tabs li.active a { 109 | color: #000; 110 | background-color: #fff; 111 | } 112 | 113 | 114 | 115 | div.huge { 116 | 117 | font-size: 300px; 118 | line-height: 1em; 119 | padding: 0; 120 | letter-spacing: -.02em; 121 | overflow: hidden; 122 | } 123 | div.glyph_range { 124 | font-size: 72px; 125 | line-height: 1.1em; 126 | } 127 | 128 | .size10{ font-size: 10px; } 129 | .size11{ font-size: 11px; } 130 | .size12{ font-size: 12px; } 131 | .size13{ font-size: 13px; } 132 | .size14{ font-size: 14px; } 133 | .size16{ font-size: 16px; } 134 | .size18{ font-size: 18px; } 135 | .size20{ font-size: 20px; } 136 | .size24{ font-size: 24px; } 137 | .size30{ font-size: 30px; } 138 | .size36{ font-size: 36px; } 139 | .size48{ font-size: 48px; } 140 | .size60{ font-size: 60px; } 141 | .size72{ font-size: 72px; } 142 | .size90{ font-size: 90px; } 143 | 144 | 145 | .psample_row1 { height: 120px;} 146 | .psample_row1 { height: 120px;} 147 | .psample_row2 { height: 160px;} 148 | .psample_row3 { height: 160px;} 149 | .psample_row4 { height: 160px;} 150 | 151 | .psample { 152 | overflow: hidden; 153 | position: relative; 154 | } 155 | .psample p { 156 | line-height: 1.3em; 157 | display: block; 158 | overflow: hidden; 159 | margin: 0; 160 | } 161 | 162 | .psample span { 163 | margin-right: .5em; 164 | } 165 | 166 | .white_blend { 167 | width: 100%; 168 | height: 61px; 169 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNrs3TsKgFAMRUE/eer+NxztxMYuEWQG3ECKwwUF58ycAKixOAGAyAKILAAiCyCyACILgMgCiCyAyAIgsgAiCyCyAIgsgMgCiCwAIgsgsgAiC4DIAogsACIL0CWuZ3UGgLrIhjMA1EV2OAOAJQtgyQLwjOzmDAAiCyCyAIgsQFtkd2cAEFkAkQVAZAHaIns4A4AlC2DJAiCyACILILIAiCzAV5H1dQGAJQsgsgCILIDIAvwisl58AViyAJYsACILILIAIgvAe2T9EhxAZAFEFgCRBeiL7HAGgLrIhjMAWLIAliwAt1OAAQDwygTBulLIlQAAAABJRU5ErkJggg==); 170 | position: absolute; 171 | bottom: 0; 172 | } 173 | .black_blend { 174 | width: 100%; 175 | height: 61px; 176 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNrs3TEKhTAQRVGjibr/9QoxhY2N3Ywo50A28IrLwP9g6b1PAMSYTQAgsgAiC4DIAogsgMgCILIAIgsgsgCILIDIAogsACILILIAIguAyAKILIDIAiCyACILgMgCZCnjLWYAiFGvB0BQZJsZAFyyAC5ZAO6RXc0AILIAIguAyAKkRXYzA4DIAogsACILkBbZ3QwALlkAlywAIgsgsgAiC4DIArwVWf8uAHDJAogsACILILIAv4isH74AXLIALlkARBZAZAFEFoDnyPokOIDIAogsACILkBfZZgaAuMhWMwC4ZAE+p4x3mAEgxinAAJ+XBbPWGkwAAAAAAElFTkSuQmCC); 177 | position: absolute; 178 | bottom: 0; 179 | } 180 | .fullreverse { 181 | background: #000 !important; 182 | color: #fff !important; 183 | margin-left: -20px; 184 | padding-left: 20px; 185 | margin-right: -20px; 186 | padding-right: 20px; 187 | padding: 20px; 188 | margin-bottom:0; 189 | } 190 | 191 | 192 | .sample_table td { 193 | padding-top: 3px; 194 | padding-bottom:5px; 195 | padding-left: 5px; 196 | vertical-align: middle; 197 | line-height: 1.2em; 198 | } 199 | 200 | .sample_table td:first-child { 201 | background-color: #eee; 202 | text-align: right; 203 | padding-right: 5px; 204 | padding-left: 0; 205 | padding: 5px; 206 | font: 11px/12px "Courier New", Courier, mono; 207 | } 208 | 209 | code { 210 | white-space: pre; 211 | background-color: #eee; 212 | display: block; 213 | padding: 10px; 214 | margin-bottom: 18px; 215 | overflow: auto; 216 | } 217 | 218 | 219 | .bottom,.last {margin-bottom:0 !important; padding-bottom:0 !important;} 220 | 221 | .box { 222 | padding: 18px; 223 | margin-bottom: 18px; 224 | background: #eee; 225 | } 226 | 227 | .reverse,.reversed { background: #000 !important;color: #fff !important; border: none !important;} 228 | 229 | #bodycomparison { 230 | position: relative; 231 | overflow: hidden; 232 | font-size: 72px; 233 | height: 90px; 234 | white-space: nowrap; 235 | } 236 | 237 | #bodycomparison div{ 238 | font-size: 72px; 239 | line-height: 90px; 240 | display: inline; 241 | margin: 0 15px 0 0; 242 | padding: 0; 243 | } 244 | 245 | #bodycomparison div span{ 246 | font: 10px Arial; 247 | position: absolute; 248 | left: 0; 249 | } 250 | #xheight { 251 | float: none; 252 | position: absolute; 253 | color: #d9f3ff; 254 | font-size: 72px; 255 | line-height: 90px; 256 | } 257 | 258 | .fontbody { 259 | position: relative; 260 | } 261 | .arialbody{ 262 | font-family: Arial; 263 | position: relative; 264 | } 265 | .verdanabody{ 266 | font-family: Verdana; 267 | position: relative; 268 | } 269 | .georgiabody{ 270 | font-family: Georgia; 271 | position: relative; 272 | } 273 | 274 | /* @group Layout page 275 | */ 276 | 277 | #layout h1 { 278 | font-size: 36px; 279 | line-height: 42px; 280 | font-weight: normal; 281 | font-style: normal; 282 | } 283 | 284 | #layout h2 { 285 | font-size: 24px; 286 | line-height: 23px; 287 | font-weight: normal; 288 | font-style: normal; 289 | } 290 | 291 | #layout h3 { 292 | font-size: 22px; 293 | line-height: 1.4em; 294 | margin-top: 1em; 295 | font-weight: normal; 296 | font-style: normal; 297 | } 298 | 299 | 300 | #layout p.byline { 301 | font-size: 12px; 302 | margin-top: 18px; 303 | line-height: 12px; 304 | margin-bottom: 0; 305 | } 306 | #layout p { 307 | font-size: 14px; 308 | line-height: 21px; 309 | margin-bottom: .5em; 310 | } 311 | 312 | #layout p.large{ 313 | font-size: 18px; 314 | line-height: 26px; 315 | } 316 | 317 | #layout .sidebar p{ 318 | font-size: 12px; 319 | line-height: 1.4em; 320 | } 321 | 322 | #layout p.caption { 323 | font-size: 10px; 324 | margin-top: -16px; 325 | margin-bottom: 18px; 326 | } 327 | 328 | /* @end */ 329 | 330 | /* @group Glyphs */ 331 | 332 | #glyph_chart div{ 333 | background-color: #d9f3ff; 334 | color: black; 335 | float: left; 336 | font-size: 36px; 337 | height: 1.2em; 338 | line-height: 1.2em; 339 | margin-bottom: 1px; 340 | margin-right: 1px; 341 | text-align: center; 342 | width: 1.2em; 343 | position: relative; 344 | padding: .6em .2em .2em; 345 | } 346 | 347 | #glyph_chart div p { 348 | position: absolute; 349 | left: 0; 350 | top: 0; 351 | display: block; 352 | text-align: center; 353 | font: bold 9px Arial, sans-serif; 354 | background-color: #3a768f; 355 | width: 100%; 356 | color: #fff; 357 | padding: 2px 0; 358 | } 359 | 360 | 361 | #glyphs h1 { 362 | font-family: Arial, sans-serif; 363 | } 364 | /* @end */ 365 | 366 | /* @group Installing */ 367 | 368 | #installing { 369 | font: 13px Arial, sans-serif; 370 | } 371 | 372 | #installing p, 373 | #glyphs p{ 374 | line-height: 1.2em; 375 | margin-bottom: 18px; 376 | font: 13px Arial, sans-serif; 377 | } 378 | 379 | 380 | 381 | #installing h3{ 382 | font-size: 15px; 383 | margin-top: 18px; 384 | } 385 | 386 | /* @end */ 387 | 388 | #rendering h1 { 389 | font-family: Arial, sans-serif; 390 | } 391 | .render_table td { 392 | font: 11px "Courier New", Courier, mono; 393 | vertical-align: middle; 394 | } 395 | 396 | 397 | -------------------------------------------------------------------------------- /main/util/filesaver.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 1.1.20151003 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: MIT 7 | * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 8 | */ 9 | 10 | /*global self */ 11 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 12 | 13 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 14 | 15 | var saveAs = saveAs || (function(view) { 16 | "use strict"; 17 | // IE <10 is explicitly unsupported 18 | if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 19 | return; 20 | } 21 | var 22 | doc = view.document 23 | // only get URL when necessary in case Blob.js hasn't overridden it yet 24 | , get_URL = function() { 25 | return view.URL || view.webkitURL || view; 26 | } 27 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 28 | , can_use_save_link = "download" in save_link 29 | , click = function(node) { 30 | var event = new MouseEvent("click"); 31 | node.dispatchEvent(event); 32 | } 33 | , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent) 34 | , webkit_req_fs = view.webkitRequestFileSystem 35 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 36 | , throw_outside = function(ex) { 37 | (view.setImmediate || view.setTimeout)(function() { 38 | throw ex; 39 | }, 0); 40 | } 41 | , force_saveable_type = "application/octet-stream" 42 | , fs_min_size = 0 43 | // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and 44 | // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 45 | // for the reasoning behind the timeout and revocation flow 46 | , arbitrary_revoke_timeout = 500 // in ms 47 | , revoke = function(file) { 48 | var revoker = function() { 49 | if (typeof file === "string") { // file is an object URL 50 | get_URL().revokeObjectURL(file); 51 | } else { // file is a File 52 | file.remove(); 53 | } 54 | }; 55 | if (view.chrome) { 56 | revoker(); 57 | } else { 58 | setTimeout(revoker, arbitrary_revoke_timeout); 59 | } 60 | } 61 | , dispatch = function(filesaver, event_types, event) { 62 | event_types = [].concat(event_types); 63 | var i = event_types.length; 64 | while (i--) { 65 | var listener = filesaver["on" + event_types[i]]; 66 | if (typeof listener === "function") { 67 | try { 68 | listener.call(filesaver, event || filesaver); 69 | } catch (ex) { 70 | throw_outside(ex); 71 | } 72 | } 73 | } 74 | } 75 | , auto_bom = function(blob) { 76 | // prepend BOM for UTF-8 XML and text/* types (including HTML) 77 | if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 78 | return new Blob(["\ufeff", blob], {type: blob.type}); 79 | } 80 | return blob; 81 | } 82 | , FileSaver = function(blob, name, no_auto_bom) { 83 | if (!no_auto_bom) { 84 | blob = auto_bom(blob); 85 | } 86 | // First try a.download, then web filesystem, then object URLs 87 | var 88 | filesaver = this 89 | , type = blob.type 90 | , blob_changed = false 91 | , object_url 92 | , target_view 93 | , dispatch_all = function() { 94 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 95 | } 96 | // on any filesys errors revert to saving with object URLs 97 | , fs_error = function() { 98 | if (target_view && is_safari && typeof FileReader !== "undefined") { 99 | // Safari doesn't allow downloading of blob urls 100 | var reader = new FileReader(); 101 | reader.onloadend = function() { 102 | var base64Data = reader.result; 103 | target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/)); 104 | filesaver.readyState = filesaver.DONE; 105 | dispatch_all(); 106 | }; 107 | reader.readAsDataURL(blob); 108 | filesaver.readyState = filesaver.INIT; 109 | return; 110 | } 111 | // don't create more object URLs than needed 112 | if (blob_changed || !object_url) { 113 | object_url = get_URL().createObjectURL(blob); 114 | } 115 | if (target_view) { 116 | target_view.location.href = object_url; 117 | } else { 118 | var new_tab = view.open(object_url, "_blank"); 119 | if (new_tab == undefined && is_safari) { 120 | //Apple do not allow window.open, see http://bit.ly/1kZffRI 121 | view.location.href = object_url 122 | } 123 | } 124 | filesaver.readyState = filesaver.DONE; 125 | dispatch_all(); 126 | revoke(object_url); 127 | } 128 | , abortable = function(func) { 129 | return function() { 130 | if (filesaver.readyState !== filesaver.DONE) { 131 | return func.apply(this, arguments); 132 | } 133 | }; 134 | } 135 | , create_if_not_found = {create: true, exclusive: false} 136 | , slice 137 | ; 138 | filesaver.readyState = filesaver.INIT; 139 | if (!name) { 140 | name = "download"; 141 | } 142 | if (can_use_save_link) { 143 | object_url = get_URL().createObjectURL(blob); 144 | setTimeout(function() { 145 | save_link.href = object_url; 146 | save_link.download = name; 147 | click(save_link); 148 | dispatch_all(); 149 | revoke(object_url); 150 | filesaver.readyState = filesaver.DONE; 151 | }); 152 | return; 153 | } 154 | // Object and web filesystem URLs have a problem saving in Google Chrome when 155 | // viewed in a tab, so I force save with application/octet-stream 156 | // http://code.google.com/p/chromium/issues/detail?id=91158 157 | // Update: Google errantly closed 91158, I submitted it again: 158 | // https://code.google.com/p/chromium/issues/detail?id=389642 159 | if (view.chrome && type && type !== force_saveable_type) { 160 | slice = blob.slice || blob.webkitSlice; 161 | blob = slice.call(blob, 0, blob.size, force_saveable_type); 162 | blob_changed = true; 163 | } 164 | // Since I can't be sure that the guessed media type will trigger a download 165 | // in WebKit, I append .download to the filename. 166 | // https://bugs.webkit.org/show_bug.cgi?id=65440 167 | if (webkit_req_fs && name !== "download") { 168 | name += ".download"; 169 | } 170 | if (type === force_saveable_type || webkit_req_fs) { 171 | target_view = view; 172 | } 173 | if (!req_fs) { 174 | fs_error(); 175 | return; 176 | } 177 | fs_min_size += blob.size; 178 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 179 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 180 | var save = function() { 181 | dir.getFile(name, create_if_not_found, abortable(function(file) { 182 | file.createWriter(abortable(function(writer) { 183 | writer.onwriteend = function(event) { 184 | target_view.location.href = file.toURL(); 185 | filesaver.readyState = filesaver.DONE; 186 | dispatch(filesaver, "writeend", event); 187 | revoke(file); 188 | }; 189 | writer.onerror = function() { 190 | var error = writer.error; 191 | if (error.code !== error.ABORT_ERR) { 192 | fs_error(); 193 | } 194 | }; 195 | "writestart progress write abort".split(" ").forEach(function(event) { 196 | writer["on" + event] = filesaver["on" + event]; 197 | }); 198 | writer.write(blob); 199 | filesaver.abort = function() { 200 | writer.abort(); 201 | filesaver.readyState = filesaver.DONE; 202 | }; 203 | filesaver.readyState = filesaver.WRITING; 204 | }), fs_error); 205 | }), fs_error); 206 | }; 207 | dir.getFile(name, {create: false}, abortable(function(file) { 208 | // delete file if it already exists 209 | file.remove(); 210 | save(); 211 | }), abortable(function(ex) { 212 | if (ex.code === ex.NOT_FOUND_ERR) { 213 | save(); 214 | } else { 215 | fs_error(); 216 | } 217 | })); 218 | }), fs_error); 219 | }), fs_error); 220 | } 221 | , FS_proto = FileSaver.prototype 222 | , saveAs = function(blob, name, no_auto_bom) { 223 | return new FileSaver(blob, name, no_auto_bom); 224 | } 225 | ; 226 | // IE 10+ (native saveAs) 227 | if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 228 | return function(blob, name, no_auto_bom) { 229 | if (!no_auto_bom) { 230 | blob = auto_bom(blob); 231 | } 232 | return navigator.msSaveOrOpenBlob(blob, name || "download"); 233 | }; 234 | } 235 | 236 | FS_proto.abort = function() { 237 | var filesaver = this; 238 | filesaver.readyState = filesaver.DONE; 239 | dispatch(filesaver, "abort"); 240 | }; 241 | FS_proto.readyState = FS_proto.INIT = 0; 242 | FS_proto.WRITING = 1; 243 | FS_proto.DONE = 2; 244 | 245 | FS_proto.error = 246 | FS_proto.onwritestart = 247 | FS_proto.onprogress = 248 | FS_proto.onwrite = 249 | FS_proto.onabort = 250 | FS_proto.onerror = 251 | FS_proto.onwriteend = 252 | null; 253 | 254 | return saveAs; 255 | }( 256 | typeof self !== "undefined" && self 257 | || typeof window !== "undefined" && window 258 | || this.content 259 | )); 260 | // `self` is undefined in Firefox for Android content script context 261 | // while `this` is nsIContentFrameMessageManager 262 | // with an attribute `content` that corresponds to the window 263 | 264 | if (typeof module !== "undefined" && module.exports) { 265 | module.exports.saveAs = saveAs; 266 | } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { 267 | define([], function() { 268 | return saveAs; 269 | }); 270 | } -------------------------------------------------------------------------------- /main/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /minkowski.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "minkowski.h" 3 | 4 | #include 5 | #define BOOST_POLYGON_NO_DEPS 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #undef min 13 | #undef max 14 | 15 | typedef boost::polygon::point_data point; 16 | typedef boost::polygon::polygon_set_data polygon_set; 17 | typedef boost::polygon::polygon_with_holes_data polygon; 18 | typedef std::pair edge; 19 | using namespace boost::polygon::operators; 20 | 21 | void convolve_two_segments(std::vector& figure, const edge& a, const edge& b) { 22 | using namespace boost::polygon; 23 | figure.clear(); 24 | figure.push_back(point(a.first)); 25 | figure.push_back(point(a.first)); 26 | figure.push_back(point(a.second)); 27 | figure.push_back(point(a.second)); 28 | convolve(figure[0], b.second); 29 | convolve(figure[1], b.first); 30 | convolve(figure[2], b.first); 31 | convolve(figure[3], b.second); 32 | } 33 | 34 | template 35 | void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { 36 | using namespace boost::polygon; 37 | if(ab == ae || bb == be) 38 | return; 39 | point first_a = *ab; 40 | point prev_a = *ab; 41 | std::vector vec; 42 | polygon poly; 43 | ++ab; 44 | for( ; ab != ae; ++ab) { 45 | point first_b = *bb; 46 | point prev_b = *bb; 47 | itrT2 tmpb = bb; 48 | ++tmpb; 49 | for( ; tmpb != be; ++tmpb) { 50 | convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); 51 | set_points(poly, vec.begin(), vec.end()); 52 | result.insert(poly); 53 | prev_b = *tmpb; 54 | } 55 | prev_a = *ab; 56 | } 57 | } 58 | 59 | template 60 | void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector& polygons) { 61 | using namespace boost::polygon; 62 | for(std::size_t i = 0; i < polygons.size(); ++i) { 63 | convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); 64 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygons[i]); 65 | itrh != end_holes(polygons[i]); ++itrh) { 66 | convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); 67 | } 68 | } 69 | } 70 | 71 | void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { 72 | using namespace boost::polygon; 73 | result.clear(); 74 | std::vector a_polygons; 75 | std::vector b_polygons; 76 | a.get(a_polygons); 77 | b.get(b_polygons); 78 | for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { 79 | convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), 80 | end_points(a_polygons[ai]), b_polygons); 81 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); 82 | itrh != end_holes(a_polygons[ai]); ++itrh) { 83 | convolve_point_sequence_with_polygons(result, begin_points(*itrh), 84 | end_points(*itrh), b_polygons); 85 | } 86 | for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { 87 | polygon tmp_poly = a_polygons[ai]; 88 | result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); 89 | tmp_poly = b_polygons[bi]; 90 | result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); 91 | } 92 | } 93 | } 94 | 95 | double inputscale; 96 | 97 | using v8::Local; 98 | using v8::Array; 99 | using v8::Isolate; 100 | using v8::String; 101 | using v8::Handle; 102 | using v8::Object; 103 | using v8::Value; 104 | 105 | using namespace boost::polygon; 106 | 107 | NAN_METHOD(calculateNFP) { 108 | //std::stringstream buffer; 109 | //std::streambuf * old = std::cout.rdbuf(buffer.rdbuf()); 110 | 111 | Isolate* isolate = info.GetIsolate(); 112 | 113 | Handle group = Handle::Cast(info[0]); 114 | Handle A = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"A"))); 115 | Handle B = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"B"))); 116 | 117 | polygon_set a, b, c; 118 | std::vector polys; 119 | std::vector pts; 120 | 121 | // get maximum bounds for scaling factor 122 | unsigned int len = A->Length(); 123 | double Amaxx = 0; 124 | double Aminx = 0; 125 | double Amaxy = 0; 126 | double Aminy = 0; 127 | for (unsigned int i = 0; i < len; i++) { 128 | Local obj = Local::Cast(A->Get(i)); 129 | Amaxx = (std::max)(Amaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 130 | Aminx = (std::min)(Aminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 131 | Amaxy = (std::max)(Amaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 132 | Aminy = (std::min)(Aminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 133 | } 134 | 135 | len = B->Length(); 136 | double Bmaxx = 0; 137 | double Bminx = 0; 138 | double Bmaxy = 0; 139 | double Bminy = 0; 140 | for (unsigned int i = 0; i < len; i++) { 141 | Local obj = Local::Cast(B->Get(i)); 142 | Bmaxx = (std::max)(Bmaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 143 | Bminx = (std::min)(Bminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 144 | Bmaxy = (std::max)(Bmaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 145 | Bminy = (std::min)(Bminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 146 | } 147 | 148 | double Cmaxx = Amaxx + Bmaxx; 149 | double Cminx = Aminx + Bminx; 150 | double Cmaxy = Amaxy + Bmaxy; 151 | double Cminy = Aminy + Bminy; 152 | 153 | double maxxAbs = (std::max)(Cmaxx, std::fabs(Cminx)); 154 | double maxyAbs = (std::max)(Cmaxy, std::fabs(Cminy)); 155 | 156 | double maxda = (std::max)(maxxAbs, maxyAbs); 157 | int maxi = std::numeric_limits::max(); 158 | 159 | if(maxda < 1){ 160 | maxda = 1; 161 | } 162 | 163 | // why 0.1? dunno. it doesn't screw up with 0.1 164 | inputscale = (0.1f * (double)(maxi)) / maxda; 165 | 166 | //double scale = 1000; 167 | len = A->Length(); 168 | 169 | for (unsigned int i = 0; i < len; i++) { 170 | Local obj = Local::Cast(A->Get(i)); 171 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 172 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 173 | 174 | pts.push_back(point(x, y)); 175 | } 176 | 177 | polygon poly; 178 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 179 | a+=poly; 180 | 181 | // subtract holes from a here... 182 | Handle holes = Handle::Cast(A->Get(String::NewFromUtf8(isolate,"children"))); 183 | len = holes->Length(); 184 | 185 | for(unsigned int i=0; i hole = Handle::Cast(holes->Get(i)); 187 | pts.clear(); 188 | unsigned int hlen = hole->Length(); 189 | for(unsigned int j=0; j obj = Local::Cast(hole->Get(j)); 191 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 192 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 193 | pts.push_back(point(x, y)); 194 | } 195 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 196 | a -= poly; 197 | } 198 | 199 | //and then load points B 200 | pts.clear(); 201 | len = B->Length(); 202 | 203 | //javascript nfps are referenced with respect to the first point 204 | double xshift = 0; 205 | double yshift = 0; 206 | 207 | for (unsigned int i = 0; i < len; i++) { 208 | Local obj = Local::Cast(B->Get(i)); 209 | int x = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 210 | int y = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 211 | pts.push_back(point(x, y)); 212 | 213 | if(i==0){ 214 | xshift = (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue(); 215 | yshift = (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue(); 216 | } 217 | } 218 | 219 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 220 | b+=poly; 221 | 222 | polys.clear(); 223 | 224 | convolve_two_polygon_sets(c, a, b); 225 | c.get(polys); 226 | 227 | Local result_list = Array::New(isolate); 228 | 229 | for(unsigned int i = 0; i < polys.size(); ++i ){ 230 | 231 | Local pointlist = Array::New(isolate); 232 | int j = 0; 233 | 234 | for(polygon_traits::iterator_type itr = polys[i].begin(); itr != polys[i].end(); ++itr) { 235 | Local p = Object::New(isolate); 236 | // std::cout << (double)(*itr).get(boost::polygon::HORIZONTAL) / inputscale << std::endl; 237 | p->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 238 | p->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 239 | 240 | pointlist->Set(j, p); 241 | j++; 242 | } 243 | 244 | // holes 245 | Local children = Array::New(isolate); 246 | int k = 0; 247 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polys[i]); itrh != end_holes(polys[i]); ++itrh){ 248 | Local child = Array::New(isolate); 249 | int z = 0; 250 | for(polygon_traits::iterator_type itr2 = (*itrh).begin(); itr2 != (*itrh).end(); ++itr2) { 251 | Local c = Object::New(isolate); 252 | c->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 253 | c->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 254 | 255 | child->Set(z, c); 256 | z++; 257 | } 258 | children->Set(k, child); 259 | k++; 260 | } 261 | 262 | pointlist->Set(String::NewFromUtf8(isolate, "children"), children); 263 | 264 | result_list->Set(i, pointlist); 265 | } 266 | 267 | //std::string text = buffer.str(); 268 | 269 | info.GetReturnValue().Set(result_list); 270 | } 271 | -------------------------------------------------------------------------------- /main/util/parallel.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | //var isCommonJS = typeof module !== 'undefined' && module.exports; 3 | //var isNode = !(typeof window !== 'undefined' && this === window); 4 | var isCommonJS = false; 5 | var isNode = false; 6 | var setImmediate = setImmediate || function (cb) { 7 | setTimeout(cb, 0); 8 | }; 9 | var Worker = isNode ? require(__dirname + '/Worker.js') : self.Worker; 10 | var URL = typeof self !== 'undefined' ? (self.URL ? self.URL : self.webkitURL) : null; 11 | var _supports = (isNode || self.Worker) ? true : false; // node always supports parallel 12 | 13 | function extend(from, to) { 14 | if (!to) to = {}; 15 | for (var i in from) { 16 | if (to[i] === undefined) to[i] = from[i]; 17 | } 18 | return to; 19 | } 20 | 21 | function Operation() { 22 | this._callbacks = []; 23 | this._errCallbacks = []; 24 | 25 | this._resolved = 0; 26 | this._result = null; 27 | } 28 | 29 | Operation.prototype.resolve = function (err, res) { 30 | if (!err) { 31 | this._resolved = 1; 32 | this._result = res; 33 | 34 | for (var i = 0; i < this._callbacks.length; ++i) { 35 | this._callbacks[i](res); 36 | } 37 | } else { 38 | this._resolved = 2; 39 | this._result = err; 40 | 41 | for (var iE = 0; iE < this._errCallbacks.length; ++iE) { 42 | this._errCallbacks[iE](err); 43 | } 44 | } 45 | 46 | this._callbacks = []; 47 | this._errCallbacks = []; 48 | }; 49 | 50 | Operation.prototype.then = function (cb, errCb) { 51 | if (this._resolved === 1) { // result 52 | if (cb) { 53 | cb(this._result); 54 | } 55 | 56 | return; 57 | } else if (this._resolved === 2) { // error 58 | if (errCb) { 59 | errCb(this._result); 60 | } 61 | return; 62 | } 63 | 64 | if (cb) { 65 | this._callbacks[this._callbacks.length] = cb; 66 | } 67 | 68 | if (errCb) { 69 | this._errCallbacks[this._errCallbacks.length] = errCb; 70 | } 71 | return this; 72 | }; 73 | 74 | var defaults = { 75 | evalPath: isNode ? __dirname + '/eval.js' : null, 76 | maxWorkers: isNode ? require('os').cpus().length : (navigator.hardwareConcurrency || 4), 77 | synchronous: true, 78 | env: {}, 79 | envNamespace: 'env' 80 | }; 81 | 82 | function Parallel(data, options) { 83 | this.data = data; 84 | this.options = extend(defaults, options); 85 | this.operation = new Operation(); 86 | this.operation.resolve(null, this.data); 87 | this.requiredScripts = []; 88 | this.requiredFunctions = []; 89 | } 90 | 91 | // static method 92 | Parallel.isSupported = function () { return _supports; } 93 | 94 | Parallel.prototype.getWorkerSource = function (cb, env) { 95 | var that = this; 96 | var preStr = ''; 97 | var i = 0; 98 | if (!isNode && this.requiredScripts.length !== 0) { 99 | preStr += 'importScripts("' + this.requiredScripts.join('","') + '");\r\n'; 100 | } 101 | 102 | for (i = 0; i < this.requiredFunctions.length; ++i) { 103 | if (this.requiredFunctions[i].name) { 104 | preStr += 'var ' + this.requiredFunctions[i].name + ' = ' + this.requiredFunctions[i].fn.toString() + ';'; 105 | } else { 106 | preStr += this.requiredFunctions[i].fn.toString(); 107 | } 108 | } 109 | 110 | env = JSON.stringify(env || {}); 111 | 112 | var ns = this.options.envNamespace; 113 | 114 | if (isNode) { 115 | return preStr + 'process.on("message", function(e) {global.' + ns + ' = ' + env + ';process.send(JSON.stringify((' + cb.toString() + ')(JSON.parse(e).data)))})'; 116 | } else { 117 | return preStr + 'self.onmessage = function(e) {var global = {}; global.' + ns + ' = ' + env + ';self.postMessage((' + cb.toString() + ')(e.data))}'; 118 | } 119 | }; 120 | 121 | Parallel.prototype.require = function () { 122 | var args = Array.prototype.slice.call(arguments, 0), 123 | func; 124 | 125 | for (var i = 0; i < args.length; i++) { 126 | func = args[i]; 127 | 128 | if (typeof func === 'string') { 129 | this.requiredScripts.push(func); 130 | } else if (typeof func === 'function') { 131 | this.requiredFunctions.push({ fn: func }); 132 | } else if (typeof func === 'object') { 133 | this.requiredFunctions.push(func); 134 | } 135 | } 136 | 137 | return this; 138 | }; 139 | 140 | Parallel.prototype._spawnWorker = function (cb, env) { 141 | var wrk; 142 | var src = this.getWorkerSource(cb, env); 143 | if (isNode) { 144 | wrk = new Worker(this.options.evalPath); 145 | wrk.postMessage(src); 146 | } else { 147 | if (Worker === undefined) { 148 | return undefined; 149 | } 150 | 151 | try { 152 | if (this.requiredScripts.length !== 0) { 153 | if (this.options.evalPath !== null) { 154 | wrk = new Worker(this.options.evalPath); 155 | wrk.postMessage(src); 156 | } else { 157 | throw new Error('Can\'t use required scripts without eval.js!'); 158 | } 159 | } else if (!URL) { 160 | throw new Error('Can\'t create a blob URL in this browser!'); 161 | } else { 162 | var blob = new Blob([src], { type: 'text/javascript' }); 163 | var url = URL.createObjectURL(blob); 164 | 165 | wrk = new Worker(url); 166 | } 167 | } catch (e) { 168 | if (this.options.evalPath !== null) { // blob/url unsupported, cross-origin error 169 | wrk = new Worker(this.options.evalPath); 170 | wrk.postMessage(src); 171 | } else { 172 | throw e; 173 | } 174 | } 175 | } 176 | 177 | return wrk; 178 | }; 179 | 180 | Parallel.prototype.spawn = function (cb, env) { 181 | var that = this; 182 | var newOp = new Operation(); 183 | 184 | env = extend(this.options.env, env || {}); 185 | 186 | this.operation.then(function () { 187 | var wrk = that._spawnWorker(cb, env); 188 | if (wrk !== undefined) { 189 | wrk.onmessage = function (msg) { 190 | wrk.terminate(); 191 | that.data = msg.data; 192 | newOp.resolve(null, that.data); 193 | }; 194 | wrk.onerror = function (e) { 195 | wrk.terminate(); 196 | newOp.resolve(e, null); 197 | }; 198 | wrk.postMessage(that.data); 199 | } else if (that.options.synchronous) { 200 | setImmediate(function () { 201 | try { 202 | that.data = cb(that.data); 203 | newOp.resolve(null, that.data); 204 | } catch (e) { 205 | newOp.resolve(e, null); 206 | } 207 | }); 208 | } else { 209 | throw new Error('Workers do not exist and synchronous operation not allowed!'); 210 | } 211 | }); 212 | this.operation = newOp; 213 | return this; 214 | }; 215 | 216 | Parallel.prototype._spawnMapWorker = function (i, cb, done, env, wrk) { 217 | var that = this; 218 | 219 | if (!wrk) wrk = that._spawnWorker(cb, env); 220 | 221 | if (wrk !== undefined) { 222 | wrk.onmessage = function (msg) { 223 | that.data[i] = msg.data; 224 | done(null, wrk); 225 | }; 226 | wrk.onerror = function (e) { 227 | wrk.terminate(); 228 | done(e); 229 | }; 230 | wrk.postMessage(that.data[i]); 231 | } else if (that.options.synchronous) { 232 | setImmediate(function () { 233 | that.data[i] = cb(that.data[i]); 234 | done(); 235 | }); 236 | } else { 237 | throw new Error('Workers do not exist and synchronous operation not allowed!'); 238 | } 239 | }; 240 | 241 | Parallel.prototype.map = function (cb, env) { 242 | env = extend(this.options.env, env || {}); 243 | 244 | if (!this.data.length) { 245 | return this.spawn(cb, env); 246 | } 247 | 248 | var that = this; 249 | var startedOps = 0; 250 | var doneOps = 0; 251 | function done(err, wrk) { 252 | if (err) { 253 | newOp.resolve(err, null); 254 | } else if (++doneOps === that.data.length) { 255 | newOp.resolve(null, that.data); 256 | if (wrk) wrk.terminate(); 257 | } else if (startedOps < that.data.length) { 258 | that._spawnMapWorker(startedOps++, cb, done, env, wrk); 259 | } else { 260 | if (wrk) wrk.terminate(); 261 | } 262 | } 263 | 264 | var newOp = new Operation(); 265 | this.operation.then(function () { 266 | for (; startedOps - doneOps < that.options.maxWorkers && startedOps < that.data.length; ++startedOps) { 267 | that._spawnMapWorker(startedOps, cb, done, env); 268 | } 269 | }, function (err) { 270 | newOp.resolve(err, null); 271 | }); 272 | this.operation = newOp; 273 | return this; 274 | }; 275 | 276 | Parallel.prototype._spawnReduceWorker = function (data, cb, done, env, wrk) { 277 | var that = this; 278 | if (!wrk) wrk = that._spawnWorker(cb, env); 279 | 280 | if (wrk !== undefined) { 281 | wrk.onmessage = function (msg) { 282 | that.data[that.data.length] = msg.data; 283 | done(null, wrk); 284 | }; 285 | wrk.onerror = function (e) { 286 | wrk.terminate(); 287 | done(e, null); 288 | } 289 | wrk.postMessage(data); 290 | } else if (that.options.synchronous) { 291 | setImmediate(function () { 292 | that.data[that.data.length] = cb(data); 293 | done(); 294 | }); 295 | } else { 296 | throw new Error('Workers do not exist and synchronous operation not allowed!'); 297 | } 298 | }; 299 | 300 | Parallel.prototype.reduce = function (cb, env) { 301 | env = extend(this.options.env, env || {}); 302 | 303 | if (!this.data.length) { 304 | throw new Error('Can\'t reduce non-array data'); 305 | } 306 | 307 | var runningWorkers = 0; 308 | var that = this; 309 | function done(err, wrk) { 310 | --runningWorkers; 311 | if (err) { 312 | newOp.resolve(err, null); 313 | } else if (that.data.length === 1 && runningWorkers === 0) { 314 | that.data = that.data[0]; 315 | newOp.resolve(null, that.data); 316 | if (wrk) wrk.terminate(); 317 | } else if (that.data.length > 1) { 318 | ++runningWorkers; 319 | that._spawnReduceWorker([that.data[0], that.data[1]], cb, done, env, wrk); 320 | that.data.splice(0, 2); 321 | } else { 322 | if (wrk) wrk.terminate(); 323 | } 324 | } 325 | 326 | var newOp = new Operation(); 327 | this.operation.then(function () { 328 | if (that.data.length === 1) { 329 | newOp.resolve(null, that.data[0]); 330 | } else { 331 | for (var i = 0; i < that.options.maxWorkers && i < Math.floor(that.data.length / 2) ; ++i) { 332 | ++runningWorkers; 333 | that._spawnReduceWorker([that.data[i * 2], that.data[i * 2 + 1]], cb, done, env); 334 | } 335 | 336 | that.data.splice(0, i * 2); 337 | } 338 | }); 339 | this.operation = newOp; 340 | return this; 341 | }; 342 | 343 | Parallel.prototype.then = function (cb, errCb) { 344 | var that = this; 345 | var newOp = new Operation(); 346 | errCb = typeof errCb === 'function' ? errCb : function(){}; 347 | 348 | this.operation.then(function () { 349 | var retData; 350 | 351 | try { 352 | if (cb) { 353 | retData = cb(that.data); 354 | if (retData !== undefined) { 355 | that.data = retData; 356 | } 357 | } 358 | newOp.resolve(null, that.data); 359 | } catch (e) { 360 | if (errCb) { 361 | retData = errCb(e); 362 | if (retData !== undefined) { 363 | that.data = retData; 364 | } 365 | 366 | newOp.resolve(null, that.data); 367 | } else { 368 | newOp.resolve(null, e); 369 | } 370 | } 371 | }, function (err) { 372 | if (errCb) { 373 | var retData = errCb(err); 374 | if (retData !== undefined) { 375 | that.data = retData; 376 | } 377 | 378 | newOp.resolve(null, that.data); 379 | } else { 380 | newOp.resolve(null, err); 381 | } 382 | }); 383 | this.operation = newOp; 384 | return this; 385 | }; 386 | 387 | if (isCommonJS) { 388 | module.exports = Parallel; 389 | } else { 390 | self.Parallel = Parallel; 391 | } 392 | })(); -------------------------------------------------------------------------------- /minkowski/Makefile: -------------------------------------------------------------------------------- 1 | # We borrow heavily from the kernel build setup, though we are simpler since 2 | # we don't have Kconfig tweaking settings on us. 3 | 4 | # The implicit make rules have it looking for RCS files, among other things. 5 | # We instead explicitly write all the rules we care about. 6 | # It's even quicker (saves ~200ms) to pass -r on the command line. 7 | MAKEFLAGS=-r 8 | 9 | # The source directory tree. 10 | srcdir := .. 11 | abs_srcdir := $(abspath $(srcdir)) 12 | 13 | # The name of the builddir. 14 | builddir_name ?= . 15 | 16 | # The V=1 flag on command line makes us verbosely print command lines. 17 | ifdef V 18 | quiet= 19 | else 20 | quiet=quiet_ 21 | endif 22 | 23 | # Specify BUILDTYPE=Release on the command line for a release build. 24 | BUILDTYPE ?= Release 25 | 26 | # Directory all our build output goes into. 27 | # Note that this must be two directories beneath src/ for unit tests to pass, 28 | # as they reach into the src/ directory for data with relative paths. 29 | builddir ?= $(builddir_name)/$(BUILDTYPE) 30 | abs_builddir := $(abspath $(builddir)) 31 | depsdir := $(builddir)/.deps 32 | 33 | # Object output directory. 34 | obj := $(builddir)/obj 35 | abs_obj := $(abspath $(obj)) 36 | 37 | # We build up a list of every single one of the targets so we can slurp in the 38 | # generated dependency rule Makefiles in one pass. 39 | all_deps := 40 | 41 | 42 | 43 | CC.target ?= $(CC) 44 | CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS) 45 | CXX.target ?= $(CXX) 46 | CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS) 47 | LINK.target ?= $(LINK) 48 | LDFLAGS.target ?= $(LDFLAGS) 49 | AR.target ?= $(AR) 50 | 51 | # C++ apps need to be linked with g++. 52 | LINK ?= $(CXX.target) 53 | 54 | # TODO(evan): move all cross-compilation logic to gyp-time so we don't need 55 | # to replicate this environment fallback in make as well. 56 | CC.host ?= gcc 57 | CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host) 58 | CXX.host ?= g++ 59 | CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host) 60 | LINK.host ?= $(CXX.host) 61 | LDFLAGS.host ?= 62 | AR.host ?= ar 63 | 64 | # Define a dir function that can handle spaces. 65 | # http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions 66 | # "leading spaces cannot appear in the text of the first argument as written. 67 | # These characters can be put into the argument value by variable substitution." 68 | empty := 69 | space := $(empty) $(empty) 70 | 71 | # http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces 72 | replace_spaces = $(subst $(space),?,$1) 73 | unreplace_spaces = $(subst ?,$(space),$1) 74 | dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) 75 | 76 | # Flags to make gcc output dependency info. Note that you need to be 77 | # careful here to use the flags that ccache and distcc can understand. 78 | # We write to a dep file on the side first and then rename at the end 79 | # so we can't end up with a broken dep file. 80 | depfile = $(depsdir)/$(call replace_spaces,$@).d 81 | DEPFLAGS = -MMD -MF $(depfile).raw 82 | 83 | # We have to fixup the deps output in a few ways. 84 | # (1) the file output should mention the proper .o file. 85 | # ccache or distcc lose the path to the target, so we convert a rule of 86 | # the form: 87 | # foobar.o: DEP1 DEP2 88 | # into 89 | # path/to/foobar.o: DEP1 DEP2 90 | # (2) we want missing files not to cause us to fail to build. 91 | # We want to rewrite 92 | # foobar.o: DEP1 DEP2 \ 93 | # DEP3 94 | # to 95 | # DEP1: 96 | # DEP2: 97 | # DEP3: 98 | # so if the files are missing, they're just considered phony rules. 99 | # We have to do some pretty insane escaping to get those backslashes 100 | # and dollar signs past make, the shell, and sed at the same time. 101 | # Doesn't work with spaces, but that's fine: .d files have spaces in 102 | # their names replaced with other characters. 103 | define fixup_dep 104 | # The depfile may not exist if the input file didn't have any #includes. 105 | touch $(depfile).raw 106 | # Fixup path as in (1). 107 | sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) 108 | # Add extra rules as in (2). 109 | # We remove slashes and replace spaces with new lines; 110 | # remove blank lines; 111 | # delete the first line and append a colon to the remaining lines. 112 | sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ 113 | grep -v '^$$' |\ 114 | sed -e 1d -e 's|$$|:|' \ 115 | >> $(depfile) 116 | rm $(depfile).raw 117 | endef 118 | 119 | # Command definitions: 120 | # - cmd_foo is the actual command to run; 121 | # - quiet_cmd_foo is the brief-output summary of the command. 122 | 123 | quiet_cmd_cc = CC($(TOOLSET)) $@ 124 | cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< 125 | 126 | quiet_cmd_cxx = CXX($(TOOLSET)) $@ 127 | cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 128 | 129 | quiet_cmd_objc = CXX($(TOOLSET)) $@ 130 | cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< 131 | 132 | quiet_cmd_objcxx = CXX($(TOOLSET)) $@ 133 | cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< 134 | 135 | # Commands for precompiled header files. 136 | quiet_cmd_pch_c = CXX($(TOOLSET)) $@ 137 | cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 138 | quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ 139 | cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 140 | quiet_cmd_pch_m = CXX($(TOOLSET)) $@ 141 | cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< 142 | quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ 143 | cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< 144 | 145 | # gyp-mac-tool is written next to the root Makefile by gyp. 146 | # Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd 147 | # already. 148 | quiet_cmd_mac_tool = MACTOOL $(4) $< 149 | cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" 150 | 151 | quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ 152 | cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) 153 | 154 | quiet_cmd_infoplist = INFOPLIST $@ 155 | cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" 156 | 157 | quiet_cmd_touch = TOUCH $@ 158 | cmd_touch = touch $@ 159 | 160 | quiet_cmd_copy = COPY $@ 161 | # send stderr to /dev/null to ignore messages when linking directories. 162 | cmd_copy = rm -rf "$@" && cp -af "$<" "$@" 163 | 164 | quiet_cmd_alink = LIBTOOL-STATIC $@ 165 | cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) 166 | 167 | quiet_cmd_link = LINK($(TOOLSET)) $@ 168 | cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) 169 | 170 | quiet_cmd_solink = SOLINK($(TOOLSET)) $@ 171 | cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) 172 | 173 | quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ 174 | cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) 175 | 176 | 177 | # Define an escape_quotes function to escape single quotes. 178 | # This allows us to handle quotes properly as long as we always use 179 | # use single quotes and escape_quotes. 180 | escape_quotes = $(subst ','\'',$(1)) 181 | # This comment is here just to include a ' to unconfuse syntax highlighting. 182 | # Define an escape_vars function to escape '$' variable syntax. 183 | # This allows us to read/write command lines with shell variables (e.g. 184 | # $LD_LIBRARY_PATH), without triggering make substitution. 185 | escape_vars = $(subst $$,$$$$,$(1)) 186 | # Helper that expands to a shell command to echo a string exactly as it is in 187 | # make. This uses printf instead of echo because printf's behaviour with respect 188 | # to escape sequences is more portable than echo's across different shells 189 | # (e.g., dash, bash). 190 | exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' 191 | 192 | # Helper to compare the command we're about to run against the command 193 | # we logged the last time we ran the command. Produces an empty 194 | # string (false) when the commands match. 195 | # Tricky point: Make has no string-equality test function. 196 | # The kernel uses the following, but it seems like it would have false 197 | # positives, where one string reordered its arguments. 198 | # arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ 199 | # $(filter-out $(cmd_$@), $(cmd_$(1)))) 200 | # We instead substitute each for the empty string into the other, and 201 | # say they're equal if both substitutions produce the empty string. 202 | # .d files contain ? instead of spaces, take that into account. 203 | command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ 204 | $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) 205 | 206 | # Helper that is non-empty when a prerequisite changes. 207 | # Normally make does this implicitly, but we force rules to always run 208 | # so we can check their command lines. 209 | # $? -- new prerequisites 210 | # $| -- order-only dependencies 211 | prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) 212 | 213 | # Helper that executes all postbuilds until one fails. 214 | define do_postbuilds 215 | @E=0;\ 216 | for p in $(POSTBUILDS); do\ 217 | eval $$p;\ 218 | E=$$?;\ 219 | if [ $$E -ne 0 ]; then\ 220 | break;\ 221 | fi;\ 222 | done;\ 223 | if [ $$E -ne 0 ]; then\ 224 | rm -rf "$@";\ 225 | exit $$E;\ 226 | fi 227 | endef 228 | 229 | # do_cmd: run a command via the above cmd_foo names, if necessary. 230 | # Should always run for a given target to handle command-line changes. 231 | # Second argument, if non-zero, makes it do asm/C/C++ dependency munging. 232 | # Third argument, if non-zero, makes it do POSTBUILDS processing. 233 | # Note: We intentionally do NOT call dirx for depfile, since it contains ? for 234 | # spaces already and dirx strips the ? characters. 235 | define do_cmd 236 | $(if $(or $(command_changed),$(prereq_changed)), 237 | @$(call exact_echo, $($(quiet)cmd_$(1))) 238 | @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" 239 | $(if $(findstring flock,$(word 2,$(cmd_$1))), 240 | @$(cmd_$(1)) 241 | @echo " $(quiet_cmd_$(1)): Finished", 242 | @$(cmd_$(1)) 243 | ) 244 | @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) 245 | @$(if $(2),$(fixup_dep)) 246 | $(if $(and $(3), $(POSTBUILDS)), 247 | $(call do_postbuilds) 248 | ) 249 | ) 250 | endef 251 | 252 | # Declare the "all" target first so it is the default, 253 | # even though we don't have the deps yet. 254 | .PHONY: all 255 | all: 256 | 257 | # make looks for ways to re-generate included makefiles, but in our case, we 258 | # don't have a direct way. Explicitly telling make that it has nothing to do 259 | # for them makes it go faster. 260 | %.d: ; 261 | 262 | # Use FORCE_DO_CMD to force a target to run. Should be coupled with 263 | # do_cmd. 264 | .PHONY: FORCE_DO_CMD 265 | FORCE_DO_CMD: 266 | 267 | TOOLSET := target 268 | # Suffix rules, putting all outputs into $(obj). 269 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD 270 | @$(call do_cmd,cc,1) 271 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD 272 | @$(call do_cmd,cxx,1) 273 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD 274 | @$(call do_cmd,cxx,1) 275 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD 276 | @$(call do_cmd,cxx,1) 277 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD 278 | @$(call do_cmd,objc,1) 279 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD 280 | @$(call do_cmd,objcxx,1) 281 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD 282 | @$(call do_cmd,cc,1) 283 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD 284 | @$(call do_cmd,cc,1) 285 | 286 | # Try building from generated source, too. 287 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD 288 | @$(call do_cmd,cc,1) 289 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD 290 | @$(call do_cmd,cxx,1) 291 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD 292 | @$(call do_cmd,cxx,1) 293 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD 294 | @$(call do_cmd,cxx,1) 295 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD 296 | @$(call do_cmd,objc,1) 297 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD 298 | @$(call do_cmd,objcxx,1) 299 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD 300 | @$(call do_cmd,cc,1) 301 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD 302 | @$(call do_cmd,cc,1) 303 | 304 | $(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD 305 | @$(call do_cmd,cc,1) 306 | $(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD 307 | @$(call do_cmd,cxx,1) 308 | $(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD 309 | @$(call do_cmd,cxx,1) 310 | $(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD 311 | @$(call do_cmd,cxx,1) 312 | $(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD 313 | @$(call do_cmd,objc,1) 314 | $(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD 315 | @$(call do_cmd,objcxx,1) 316 | $(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD 317 | @$(call do_cmd,cc,1) 318 | $(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD 319 | @$(call do_cmd,cc,1) 320 | 321 | 322 | ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ 323 | $(findstring $(join ^,$(prefix)),\ 324 | $(join ^,addon.target.mk)))),) 325 | include addon.target.mk 326 | endif 327 | 328 | quiet_cmd_regen_makefile = ACTION Regenerating $@ 329 | cmd_regen_makefile = cd $(srcdir); /Users/jackqiao/.nvm/versions/node/v7.1.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Users/jackqiao/Documents/Deepnest/deepnest/build/config.gypi -I/Users/jackqiao/.nvm/versions/node/v7.1.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/jackqiao/.node-gyp/iojs-1.4.8/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/jackqiao/.node-gyp/iojs-1.4.8" "-Dnode_gyp_dir=/Users/jackqiao/.nvm/versions/node/v7.1.0/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=iojs.lib" "-Dmodule_root_dir=/Users/jackqiao/Documents/Deepnest/deepnest" binding.gyp 330 | Makefile: $(srcdir)/../../../.nvm/versions/node/v7.1.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/../../../.node-gyp/iojs-1.4.8/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp 331 | $(call do_cmd,regen_makefile) 332 | 333 | # "all" is a concatenation of the "all" targets from all the included 334 | # sub-makefiles. This is just here to clarify. 335 | all: 336 | 337 | # Add in dependency-tracking rules. $(all_deps) is the list of every single 338 | # target in our tree. Only consider the ones with .d (dependency) info: 339 | d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) 340 | ifneq ($(d_files),) 341 | include $(d_files) 342 | endif 343 | -------------------------------------------------------------------------------- /minkowski thread.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "minkowski.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #undef min 14 | #undef max 15 | 16 | typedef boost::polygon::point_data point; 17 | typedef boost::polygon::polygon_set_data polygon_set; 18 | typedef boost::polygon::polygon_with_holes_data polygon; 19 | typedef std::pair edge; 20 | using namespace boost::polygon::operators; 21 | 22 | void convolve_two_segments(std::vector& figure, const edge& a, const edge& b) { 23 | using namespace boost::polygon; 24 | figure.clear(); 25 | figure.push_back(point(a.first)); 26 | figure.push_back(point(a.first)); 27 | figure.push_back(point(a.second)); 28 | figure.push_back(point(a.second)); 29 | convolve(figure[0], b.second); 30 | convolve(figure[1], b.first); 31 | convolve(figure[2], b.first); 32 | convolve(figure[3], b.second); 33 | } 34 | 35 | template 36 | void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { 37 | using namespace boost::polygon; 38 | if(ab == ae || bb == be) 39 | return; 40 | point first_a = *ab; 41 | point prev_a = *ab; 42 | std::vector vec; 43 | polygon poly; 44 | ++ab; 45 | for( ; ab != ae; ++ab) { 46 | point first_b = *bb; 47 | point prev_b = *bb; 48 | itrT2 tmpb = bb; 49 | ++tmpb; 50 | for( ; tmpb != be; ++tmpb) { 51 | convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); 52 | set_points(poly, vec.begin(), vec.end()); 53 | result.insert(poly); 54 | prev_b = *tmpb; 55 | } 56 | prev_a = *ab; 57 | } 58 | } 59 | 60 | template 61 | void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector& polygons) { 62 | using namespace boost::polygon; 63 | for(std::size_t i = 0; i < polygons.size(); ++i) { 64 | convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); 65 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygons[i]); 66 | itrh != end_holes(polygons[i]); ++itrh) { 67 | convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); 68 | } 69 | } 70 | } 71 | 72 | void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { 73 | using namespace boost::polygon; 74 | result.clear(); 75 | std::vector a_polygons; 76 | std::vector b_polygons; 77 | a.get(a_polygons); 78 | b.get(b_polygons); 79 | for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { 80 | convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), 81 | end_points(a_polygons[ai]), b_polygons); 82 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); 83 | itrh != end_holes(a_polygons[ai]); ++itrh) { 84 | convolve_point_sequence_with_polygons(result, begin_points(*itrh), 85 | end_points(*itrh), b_polygons); 86 | } 87 | for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { 88 | polygon tmp_poly = a_polygons[ai]; 89 | result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); 90 | tmp_poly = b_polygons[bi]; 91 | result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); 92 | } 93 | } 94 | } 95 | 96 | class thread_pool 97 | { 98 | private: 99 | boost::asio::io_service io_service_; 100 | boost::asio::io_service::work work_; 101 | boost::thread_group threads_; 102 | std::size_t available_; 103 | boost::mutex mutex_; 104 | public: 105 | 106 | /// @brief Constructor. 107 | thread_pool( std::size_t pool_size ) 108 | : work_( io_service_ ), 109 | available_( pool_size ) 110 | { 111 | for ( std::size_t i = 0; i < pool_size; ++i ) 112 | { 113 | threads_.create_thread( boost::bind( &boost::asio::io_service::run, 114 | &io_service_ ) ); 115 | } 116 | } 117 | 118 | void join(){ 119 | try 120 | { 121 | threads_.join_all(); 122 | } 123 | catch ( const std::exception& ) {} 124 | } 125 | 126 | /// @brief Destructor. 127 | ~thread_pool() 128 | { 129 | // Force all threads to return from io_service::run(). 130 | io_service_.stop(); 131 | 132 | // Suppress all exceptions. 133 | try 134 | { 135 | threads_.join_all(); 136 | } 137 | catch ( const std::exception& ) {} 138 | } 139 | 140 | /// @brief Adds a task to the thread pool if a thread is currently available. 141 | template < typename Task > 142 | void run_task( Task task ) 143 | { 144 | boost::unique_lock< boost::mutex > lock( mutex_ ); 145 | 146 | // If no threads are available, then return. 147 | if ( 0 == available_ ) return; 148 | 149 | // Decrement count, indicating thread is no longer available. 150 | --available_; 151 | 152 | // Post a wrapped task into the queue. 153 | io_service_.post( boost::bind( &thread_pool::wrap_task, this, 154 | boost::function< void() >( task ) ) ); 155 | } 156 | 157 | private: 158 | /// @brief Wrap a task so that the available count can be increased once 159 | /// the user provided task has completed. 160 | void wrap_task( boost::function< void() > task ) 161 | { 162 | // Run the user supplied task. 163 | try 164 | { 165 | task(); 166 | } 167 | // Suppress all exceptions. 168 | catch ( const std::exception& ) {} 169 | 170 | // Task has finished, so increment count of available threads. 171 | boost::unique_lock< boost::mutex > lock( mutex_ ); 172 | ++available_; 173 | } 174 | }; 175 | 176 | double inputscale; 177 | 178 | using v8::Local; 179 | using v8::Array; 180 | using v8::Isolate; 181 | using v8::String; 182 | using v8::Handle; 183 | using v8::Object; 184 | using v8::Value; 185 | 186 | using namespace boost::polygon; 187 | 188 | class Worker{ 189 | public: 190 | Handle Alist; 191 | Handle B; 192 | Local all_results; 193 | Isolate* isolate; 194 | 195 | void Do(int index){ 196 | 197 | Handle A = Handle::Cast(Alist->Get(index)); 198 | 199 | polygon_set a, b, c; 200 | std::vector polys; 201 | std::vector pts; 202 | 203 | // get maximum bounds for scaling factor 204 | unsigned int len = A->Length(); 205 | double Amaxx = 0; 206 | double Aminx = 0; 207 | double Amaxy = 0; 208 | double Aminy = 0; 209 | for (unsigned int i = 0; i < len; i++) { 210 | Local obj = Local::Cast(A->Get(i)); 211 | Amaxx = (std::max)(Amaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 212 | Aminx = (std::min)(Aminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 213 | Amaxy = (std::max)(Amaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 214 | Aminy = (std::min)(Aminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 215 | } 216 | 217 | len = B->Length(); 218 | double Bmaxx = 0; 219 | double Bminx = 0; 220 | double Bmaxy = 0; 221 | double Bminy = 0; 222 | for (unsigned int i = 0; i < len; i++) { 223 | Local obj = Local::Cast(B->Get(i)); 224 | Bmaxx = (std::max)(Bmaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 225 | Bminx = (std::min)(Bminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 226 | Bmaxy = (std::max)(Bmaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 227 | Bminy = (std::min)(Bminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 228 | } 229 | 230 | double Cmaxx = Amaxx + Bmaxx; 231 | double Cminx = Aminx + Bminx; 232 | double Cmaxy = Amaxy + Bmaxy; 233 | double Cminy = Aminy + Bminy; 234 | 235 | double maxxAbs = (std::max)(Cmaxx, std::fabs(Cminx)); 236 | double maxyAbs = (std::max)(Cmaxy, std::fabs(Cminy)); 237 | 238 | double maxda = (std::max)(maxxAbs, maxyAbs); 239 | int maxi = std::numeric_limits::max(); 240 | 241 | if(maxda < 1){ 242 | maxda = 1; 243 | } 244 | 245 | // why 0.1? dunno. it doesn't screw up with 0.1 246 | inputscale = (0.1f * (double)(maxi)) / maxda; 247 | 248 | //double scale = 1000; 249 | len = A->Length(); 250 | 251 | for (unsigned int i = 0; i < len; i++) { 252 | Local obj = Local::Cast(A->Get(i)); 253 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 254 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 255 | 256 | pts.push_back(point(x, y)); 257 | } 258 | 259 | polygon poly; 260 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 261 | a+=poly; 262 | 263 | // subtract holes from a here... 264 | Handle holes = Handle::Cast(A->Get(String::NewFromUtf8(isolate,"children"))); 265 | len = holes->Length(); 266 | 267 | for(unsigned int i=0; i hole = Handle::Cast(holes->Get(i)); 269 | pts.clear(); 270 | unsigned int hlen = hole->Length(); 271 | for(unsigned int j=0; j obj = Local::Cast(hole->Get(j)); 273 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 274 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 275 | pts.push_back(point(x, y)); 276 | } 277 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 278 | a -= poly; 279 | } 280 | 281 | //and then load points B 282 | pts.clear(); 283 | len = B->Length(); 284 | 285 | //javascript nfps are referenced with respect to the first point 286 | double xshift = 0; 287 | double yshift = 0; 288 | 289 | for (unsigned int i = 0; i < len; i++) { 290 | Local obj = Local::Cast(B->Get(i)); 291 | int x = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 292 | int y = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 293 | pts.push_back(point(x, y)); 294 | 295 | if(i==0){ 296 | xshift = (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue(); 297 | yshift = (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue(); 298 | } 299 | } 300 | 301 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 302 | b+=poly; 303 | 304 | polys.clear(); 305 | 306 | convolve_two_polygon_sets(c, a, b); 307 | c.get(polys); 308 | 309 | Local result_list = Array::New(isolate); 310 | 311 | for(unsigned int i = 0; i < polys.size(); ++i ){ 312 | 313 | Local pointlist = Array::New(isolate); 314 | int j = 0; 315 | 316 | for(polygon_traits::iterator_type itr = polys[i].begin(); itr != polys[i].end(); ++itr) { 317 | Local p = Object::New(isolate); 318 | // std::cout << (double)(*itr).get(boost::polygon::HORIZONTAL) / inputscale << std::endl; 319 | p->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 320 | p->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 321 | 322 | pointlist->Set(j, p); 323 | j++; 324 | } 325 | 326 | // holes 327 | Local children = Array::New(isolate); 328 | int k = 0; 329 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polys[i]); itrh != end_holes(polys[i]); ++itrh){ 330 | Local child = Array::New(isolate); 331 | int z = 0; 332 | for(polygon_traits::iterator_type itr2 = (*itrh).begin(); itr2 != (*itrh).end(); ++itr2) { 333 | Local c = Object::New(isolate); 334 | c->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 335 | c->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 336 | 337 | child->Set(z, c); 338 | z++; 339 | } 340 | children->Set(k, child); 341 | k++; 342 | } 343 | 344 | pointlist->Set(String::NewFromUtf8(isolate, "children"), children); 345 | 346 | result_list->Set(i, pointlist); 347 | 348 | all_results->Set(index, result_list); 349 | } 350 | } 351 | }; 352 | 353 | NAN_METHOD(calculateNFP) { 354 | Isolate* isolate = info.GetIsolate(); 355 | 356 | Handle group = Handle::Cast(info[0]); 357 | Handle A = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"A"))); 358 | Handle B = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"B"))); 359 | 360 | polygon_set a, b, c; 361 | std::vector polys; 362 | std::vector pts; 363 | 364 | // get maximum bounds for scaling factor 365 | unsigned int len = A->Length(); 366 | double Amaxx = 0; 367 | double Aminx = 0; 368 | double Amaxy = 0; 369 | double Aminy = 0; 370 | for (unsigned int i = 0; i < len; i++) { 371 | Local obj = Local::Cast(A->Get(i)); 372 | Amaxx = (std::max)(Amaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 373 | Aminx = (std::min)(Aminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 374 | Amaxy = (std::max)(Amaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 375 | Aminy = (std::min)(Aminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 376 | } 377 | 378 | len = B->Length(); 379 | double Bmaxx = 0; 380 | double Bminx = 0; 381 | double Bmaxy = 0; 382 | double Bminy = 0; 383 | for (unsigned int i = 0; i < len; i++) { 384 | Local obj = Local::Cast(B->Get(i)); 385 | Bmaxx = (std::max)(Bmaxx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 386 | Bminx = (std::min)(Bminx, (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 387 | Bmaxy = (std::max)(Bmaxy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 388 | Bminy = (std::min)(Bminy, (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 389 | } 390 | 391 | double Cmaxx = Amaxx + Bmaxx; 392 | double Cminx = Aminx + Bminx; 393 | double Cmaxy = Amaxy + Bmaxy; 394 | double Cminy = Aminy + Bminy; 395 | 396 | double maxxAbs = (std::max)(Cmaxx, std::fabs(Cminx)); 397 | double maxyAbs = (std::max)(Cmaxy, std::fabs(Cminy)); 398 | 399 | double maxda = (std::max)(maxxAbs, maxyAbs); 400 | int maxi = std::numeric_limits::max(); 401 | 402 | if(maxda < 1){ 403 | maxda = 1; 404 | } 405 | 406 | // why 0.1? dunno. it doesn't screw up with 0.1 407 | inputscale = (0.1f * (double)(maxi)) / maxda; 408 | 409 | //double scale = 1000; 410 | len = A->Length(); 411 | 412 | for (unsigned int i = 0; i < len; i++) { 413 | Local obj = Local::Cast(A->Get(i)); 414 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 415 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 416 | 417 | pts.push_back(point(x, y)); 418 | } 419 | 420 | polygon poly; 421 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 422 | a+=poly; 423 | 424 | // subtract holes from a here... 425 | Handle holes = Handle::Cast(A->Get(String::NewFromUtf8(isolate,"children"))); 426 | len = holes->Length(); 427 | 428 | for(unsigned int i=0; i hole = Handle::Cast(holes->Get(i)); 430 | pts.clear(); 431 | unsigned int hlen = hole->Length(); 432 | for(unsigned int j=0; j obj = Local::Cast(hole->Get(j)); 434 | int x = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 435 | int y = (int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 436 | pts.push_back(point(x, y)); 437 | } 438 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 439 | a -= poly; 440 | } 441 | 442 | //and then load points B 443 | pts.clear(); 444 | len = B->Length(); 445 | 446 | //javascript nfps are referenced with respect to the first point 447 | double xshift = 0; 448 | double yshift = 0; 449 | 450 | for (unsigned int i = 0; i < len; i++) { 451 | Local obj = Local::Cast(B->Get(i)); 452 | int x = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue()); 453 | int y = -(int)(inputscale * (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue()); 454 | pts.push_back(point(x, y)); 455 | 456 | if(i==0){ 457 | xshift = (double)obj->Get(String::NewFromUtf8(isolate,"x"))->NumberValue(); 458 | yshift = (double)obj->Get(String::NewFromUtf8(isolate,"y"))->NumberValue(); 459 | } 460 | } 461 | 462 | boost::polygon::set_points(poly, pts.begin(), pts.end()); 463 | b+=poly; 464 | 465 | polys.clear(); 466 | 467 | convolve_two_polygon_sets(c, a, b); 468 | c.get(polys); 469 | 470 | Local result_list = Array::New(isolate); 471 | 472 | for(unsigned int i = 0; i < polys.size(); ++i ){ 473 | 474 | Local pointlist = Array::New(isolate); 475 | int j = 0; 476 | 477 | for(polygon_traits::iterator_type itr = polys[i].begin(); itr != polys[i].end(); ++itr) { 478 | Local p = Object::New(isolate); 479 | // std::cout << (double)(*itr).get(boost::polygon::HORIZONTAL) / inputscale << std::endl; 480 | p->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 481 | p->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 482 | 483 | pointlist->Set(j, p); 484 | j++; 485 | } 486 | 487 | // holes 488 | Local children = Array::New(isolate); 489 | int k = 0; 490 | for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polys[i]); itrh != end_holes(polys[i]); ++itrh){ 491 | Local child = Array::New(isolate); 492 | int z = 0; 493 | for(polygon_traits::iterator_type itr2 = (*itrh).begin(); itr2 != (*itrh).end(); ++itr2) { 494 | Local c = Object::New(isolate); 495 | c->Set(String::NewFromUtf8(isolate, "x"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::HORIZONTAL)) / inputscale + xshift)); 496 | c->Set(String::NewFromUtf8(isolate, "y"), v8::Number::New(isolate, ((double)(*itr2).get(boost::polygon::VERTICAL)) / inputscale + yshift)); 497 | 498 | child->Set(z, c); 499 | z++; 500 | } 501 | children->Set(k, child); 502 | k++; 503 | } 504 | 505 | pointlist->Set(String::NewFromUtf8(isolate, "children"), children); 506 | 507 | result_list->Set(i, pointlist); 508 | } 509 | /*Worker worker; 510 | worker.Alist = Array::New(isolate); 511 | worker.Alist->Set(0, Handle::Cast(group->Get(String::NewFromUtf8(isolate,"A")))); 512 | worker.B = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"B"))); 513 | worker.all_results = Array::New(isolate); 514 | worker.isolate = isolate; 515 | 516 | worker.Do(0); 517 | 518 | info.GetReturnValue().Set(Local::Cast(worker.all_results->Get(0)));*/ 519 | 520 | info.GetReturnValue().Set(result_list); 521 | } 522 | 523 | NAN_METHOD(calculateNFPBatch) { 524 | //std::stringstream buffer; 525 | //std::streambuf * old = std::cout.rdbuf(buffer.rdbuf()); 526 | 527 | Isolate* isolate = info.GetIsolate(); 528 | 529 | Handle group = Handle::Cast(info[0]); 530 | 531 | Worker worker; 532 | worker.Alist = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"Alist"))); 533 | worker.B = Handle::Cast(group->Get(String::NewFromUtf8(isolate,"B"))); 534 | worker.all_results = Array::New(isolate); 535 | worker.isolate = isolate; 536 | 537 | thread_pool pool( 1 ); 538 | 539 | unsigned int len = worker.Alist->Length(); 540 | for(unsigned int i = 0; i < len; ++i){ 541 | pool.run_task(boost::bind(&Worker::Do, &worker, i)); // Callable object. 542 | } 543 | 544 | //std::string text = buffer.str(); 545 | pool.join(); 546 | 547 | info.GetReturnValue().Set(worker.all_results); 548 | } --------------------------------------------------------------------------------