├── .editorconfig
├── .gitignore
├── Dockerfile
├── README.md
├── agpl-3.0.txt
├── authors.txt
├── changelog.txt
├── config.js
├── i
├── css
│ ├── bootstrap-notify.css
│ ├── bootstrap-theme.min.css
│ ├── bootstrap.min.css
│ ├── bootswatch.min.css
│ ├── font-awesome.css
│ ├── images
│ │ ├── paypal.png
│ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_228ef1_256x240.png
│ │ ├── ui-icons_ef8c08_256x240.png
│ │ ├── ui-icons_ffd27a_256x240.png
│ │ └── ui-icons_ffffff_256x240.png
│ ├── jquery-ui.css
│ └── screen.css
├── dxf
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── bower.json
│ ├── dxf-parser.js
│ ├── gcode
│ │ ├── cp-eagle.js
│ │ └── three2gcode.js
│ ├── package.json
│ ├── renderer.js
│ ├── sample
│ │ ├── data
│ │ │ └── api-cw750-details.dxf
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── libs
│ │ │ └── js
│ │ │ │ ├── OrbitControls.js
│ │ │ │ └── dxf-parser.js
│ │ └── three-dxf.js
│ ├── test.html
│ └── three-dxf.js
├── favicon.ico
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── gcode-viewer
│ ├── GridRect._OLD
│ ├── gcode-parser.js
│ ├── renderer.js
│ ├── test.html
│ └── ui.js
├── index.html
├── js
│ ├── bootstrap-notify.js
│ ├── bootstrap.min.js
│ ├── clipper_unminified.js
│ ├── jog.js
│ ├── jquery-ui.js
│ ├── jquery.min.js
│ ├── jquery.min.js_old
│ ├── justgage.js
│ ├── paper-full.min.js
│ └── raphael-2.1.4.min.js
├── main.js
├── millcrum
│ ├── dxf.js
│ ├── mc.js
│ └── svg.js
├── mobile.html
├── openjscad
│ ├── LaserWebapps.js
│ ├── img
│ │ ├── InternalGear_Small.png
│ │ ├── RackAndPinion_Small.png
│ │ └── RegularSpurGear_Small.png
│ ├── lib
│ │ ├── canvasrenderer.js
│ │ └── projector.js
│ ├── openjscad.css
│ ├── src
│ │ ├── csg.js
│ │ ├── formats.js
│ │ ├── openjscad.js
│ │ ├── openscad.js
│ │ └── threecsg.js
│ └── test.html
├── openjscad_files
│ ├── gear.jscad
│ └── lasercut_box.jscad
├── raster
│ ├── calibration.jpg
│ ├── calibration.svg
│ ├── laserraster.js
│ ├── openbuilds.png
│ ├── random grayscale pic from google images.jpg
│ └── tiny.png
├── svg
│ └── js
│ │ ├── SVGReader.js
│ │ ├── SVGRenderer.js
│ │ ├── array.find.js
│ │ ├── jquery.js
│ │ ├── main.js
│ │ ├── poly2tri.js
│ │ ├── svg2gcode.js
│ │ └── vec2.js
└── threejs
│ ├── GridRect.js
│ ├── TrackballControls.js
│ ├── orbitcontrols.js
│ ├── three.min.js
│ └── three.min.js_74
├── machines
├── package.json
├── presets
├── rrw_timelapse.sh
├── screenshots
├── 50%.png
├── Scale Widget.png
├── Screenshot from 2016-01-22 15-24-02.png
├── controlmodal.PNG
├── ctrl+shift+i is debug logs.png
├── dxf.png
├── dxf1.png
├── hackaday.jpg
├── job modal.png
├── jog widget.png
├── laserweb.PNG
├── parametricgenerator.png
├── port selector.png
├── raster calibration.png
├── raster gcode viewer.png
├── raster.png
├── serial console.png
├── svg.png
├── terminal.png
└── top toolbar.png
├── server.js
├── slBaseOpts.js
└── update.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = tab
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #laserweb
2 | machines
3 | presets
4 |
5 | # Compiled source #
6 | ###################
7 | *.com
8 | *.class
9 | *.dll
10 | *.exe
11 | *.o
12 | *.so
13 |
14 | # Packages #
15 | ############
16 | # it's better to unpack these files and commit the raw source
17 | # git has its own built in compression methods
18 | *.7z
19 | *.dmg
20 | *.gz
21 | *.iso
22 | *.jar
23 | *.rar
24 | *.tar
25 | *.zip
26 |
27 | # Logs and databases #
28 | ######################
29 | *.log
30 | *.sql
31 | *.sqlite
32 |
33 | # OS generated files #
34 | ######################
35 | .DS_Store
36 | .DS_Store?
37 | ._*
38 | .Spotlight-V100
39 | .Trashes
40 | Icon?
41 | ehthumbs.db
42 | Thumbs.db
43 | *~
44 | node_modules
45 |
46 | # Local settings #
47 | ##################
48 | .env
49 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:testing
2 | MAINTAINER joseph@cauldrondevelopment.com
3 |
4 | # Install prerequisites
5 | RUN apt-get update && \
6 | apt-get install -y --no-install-recommends less debian-keyring \
7 | debian-archive-keyring ca-certificates nodejs nodejs-legacy npm \
8 | build-essential git
9 |
10 | # LaserWeb
11 | RUN git clone --depth=1 https://github.com/openhardwarecoza/LaserWeb.git
12 | RUN cd LaserWeb && npm install
13 |
14 | # Container config
15 | EXPOSE 8000
16 | WORKDIR /LaserWeb
17 | ENTRYPOINT nodejs server.js
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## DEPRECATED!
2 |
3 | LASERWEB3 is available! See [https://github.com/openhardwarecoza/LaserWeb3](https://github.com/openhardwarecoza/LaserWeb3) for details!
4 |
--------------------------------------------------------------------------------
/authors.txt:
--------------------------------------------------------------------------------
1 | Peter van der Walt
2 |
--------------------------------------------------------------------------------
/changelog.txt:
--------------------------------------------------------------------------------
1 | 7 April 2016: Please consider helping us test the beta of LaserWeb 2.0 at https://github.com/openhardwarecoza/LaserWeb2
2 | 1 Mar 2016: Completed switch to new DXF Library co-authored by @johnlauer @bzuillsmith and @openhardwarecoza ! Let the testing begin. Now supports Arcs and Circles too
3 | 28 Feb 2016: Fixed SVG Feedrate + Massive speed increase on 3D Renderer
4 | 17 Feb 2016: Fix for incorrectly evaluated boolean to enable/disable variable Raster Speed
5 | 01 Feb 2016: SVG: Added per-color (Stroke) power/speed setting
6 | 31 Jan 2016: Optimised whitespace in raster (Experimental - please report if issues)
7 | 30 Jan 2016: Made raster gcode output more Grbl compatible
8 | 29 Jan 2016: Fixed issues #94, #85, #70
9 | 28 Jan 2016: Fixed Serial Console Bug, added Websocket Server status indicator
10 | 26 Jan 2016: Project was featured on hackaday.com
11 | 22 Jan 2016: Fixed bug with Raster preview+gcode for Smoothieboards, added Progress Bars to Raster and 3D Viewer renders
12 | 21 Jan 2016: Closed several support Issues - fixed code for issues #68, #69, updated screenshots
13 | 20 Jan 2016: Added hardwareless debug option for developers who doesn't have hardware
14 | 18 Jan 2016: Added Estimated Job Time calculation
15 | 16 Jan 2016: Updated install instructions for Windows based users
16 | 12 Jan 2016: SVG support with scaling, laser power, feed and seek all live now! Go test!
17 | 11 Jan 2016: Working (but early) SVG cutting support is back
18 | 10 Jan 2016: Starting to port over to a new DXF library. Nothing users can use yet...
19 | 8 Jan 2016: Added Automatic Update to UI
20 | 8 Jan 2016: Massive code Cleanup, added Authors to various files, moved Changelog to seperate file (out of readme)
21 | 7 Jan 2016: Added Beta proof of concept 3D printer support
22 | 6 Jan 2016: Raster Engraving is live! Click the Raster button under the file open toolbar
23 | 4 Jan 2016: Added working S?? support to the 3D viewer's Gcode parser to show the laser intensity on the 3D viewer - screenshot below
24 | 31 Dec 2015: Working Javascript/PaperScript based Raster to GCODE code committed - long way from a fully support Raster Engraving solution, but thats the first most major step done: See detailed implementation log on https://github.com/openhardwarecoza/LaserWeb/issues/32
25 | 30 Dec 2014: Added a parametric Tabbed Box Generator based on http://ingegno.be/Manuals/openjscad/boxmaker.html
26 | 30 Dec 2015: Added a parametric Gear Generator based on hessmer.org/gears/InvoluteSpurGearBuilder.html
27 | 30 Dec 2015: Added a OpenJSCAD based engine to allow in-Laserweb apps like the ones above
28 | 27 Dec 2015: Added a little more instructions to readme
29 | 26 Dec 2015: Consider SVG broken for now. Please test DXF etc - we may need to switch to a different SVG Library - let me know if you can help
30 | 25 Dec 2015: Added per-layer (DXF) and per-path (SVG) Laser Power and Feedrate settings to the DXF/SVG Importing code
31 | 25 Dec 2015: Merry Christmas! And merged in @oxydum's Grbl-compatible mc.js code
32 | 24 Dec 2015: Added error handling for /dev/ttyS ports on linux, @Cinezaster contributed a fix for package.json, @oxydum contributed better mc.js code for Grbl lasers
33 | 23 Dec 2015: @danawoodman contributed code to handle serial port errors elegantly, allow overriding config using environment variables, and add some editor/gitignore to help the developers
34 | 22 Dec 2015: Added capability to run various controllers off one PC, all with different firmwares. Switching in the browser's dropdown between serial ports, changes the UI to match the firmware in use on that port! Groundbreaking!
35 | 22 Dec 2015: Added Grbl Support
36 | 21 Dec 2015: Added Lasersaur Support - Autodetect which firmware is loaded on the machine, and adapts Gcode dialect, UI elements, etc to suit the features of the attached machine
37 | 20 Dec 2015: Added a right-click context menu to 3D viewer
38 | 20 Dec 2015: Fixed Window resize didnt fix viewport bug
39 | 16 Dec 2015: Added Webcam Widget
40 | 15 Dec 2015: Added Scale, Translate, Flip functions
41 | 15 Dec 2015: Added Support for SmoothieBoard / SmoothieWare to Master branch
42 | 15 Dec 2015: Added Clear GCode button instead of clearing GCode automatically. Helps if you want to repeat same job a few times.
43 | 19 Nov 2015: Upgraded to latest socket.io and serialport versions (Socket.io 1.3.7 and SerialPort 2.0.5) since there are precompiled binaries for Windows - no more recompile required
44 | 18 Nov 2015: Upgraded to Bootstrap 3.3.5 and changed to a responsive layout
45 | 17 Nov 2015: Integrated Millcrum.com libraries to provide DXF, SVG and MILLCRUM support
46 | 10 Nov 2015: Added FontAwesome icons, moved Jogging to a Modal widget so its out of the way when not in use
47 | 8 Nov 2015: Project started
48 |
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | require('dotenv').load({ silent: true });
2 |
3 | var config = {};
4 |
5 | config.webPort = process.env.WEB_PORT || 8000;
6 | config.serialBaudRate = process.env.SERIAL_BAUD_RATE || 115200;
7 | config.webcamPort = process.env.WEBCAM_PORT || 8080; // expects a webcam stream from mjpg_streamer
8 | config.xmax = process.env.X_MAX || 600 // Max length of X Axis in mm
9 | config.ymax = process.env.Y_MAX || 400 // Max length of Y Axis in mm
10 |
11 | module.exports = config;
12 |
--------------------------------------------------------------------------------
/i/css/bootstrap-notify.css:
--------------------------------------------------------------------------------
1 | .notifications {
2 | position: fixed;
3 | z-index: 9999;
4 | }
5 |
6 | /* Positioning */
7 | .notifications.top-right {
8 | right: 10px;
9 | top: 25px;
10 | }
11 |
12 | .notifications.top-left {
13 | left: 10px;
14 | top: 25px;
15 | }
16 |
17 | .notifications.bottom-left {
18 | left: 10px;
19 | bottom: 25px;
20 | }
21 |
22 | .notifications.bottom-right {
23 | right: 10px;
24 | bottom: 25px;
25 | }
26 |
27 | /* Notification Element */
28 | .notifications > div {
29 | position: relative;
30 | margin: 5px 0px;
31 | }
32 |
--------------------------------------------------------------------------------
/i/css/images/paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/paypal.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/i/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/i/css/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/i/css/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/i/css/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/i/css/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/i/css/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/css/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/i/css/screen.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
4 |
5 | textarea {
6 | outline: none;
7 | }
8 |
9 | #canvas-1 {
10 | border: 1px solid black;
11 | }
12 |
13 | #renderArea {
14 | cursor: pointer;
15 | background-color: #ffffff;
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | right: 0;
20 | bottom: 00;
21 | border: 1px #000;
22 | float: left;
23 | margin-right: 1%;
24 | }
25 |
26 |
27 |
28 | .btn-file {
29 | position: relative;
30 | overflow: hidden;
31 | }
32 |
33 | .btn-file input[type=file] {
34 | position: absolute;
35 | top: 0;
36 | right: 0;
37 | min-width: 100%;
38 | min-height: 100%;
39 | font-size: 100px;
40 | text-align: right;
41 | filter: alpha(opacity=0);
42 | opacity: 0;
43 | outline: none;
44 | background: white;
45 | cursor: inherit;
46 | display: block;
47 | }
48 |
49 | .xyzButton {
50 | height: 40px;
51 | width: 40px;
52 | padding: 0px;
53 | }
54 |
55 | #console {
56 | height: 200px;
57 | width: auto;
58 | overflow-y: auto;
59 | text-align: left;
60 | background-color: #eee;
61 | padding: 10px;
62 | font-size: 10px;
63 | }
64 |
65 | #gcodelines {
66 | height: 300px;
67 | width: auto;
68 | overflow-y: auto;
69 | text-align: left;
70 | background-color: #eee;
71 | padding: 00px;
72 | font-size: 10px;
73 | font-weight: 500;
74 | }
75 |
76 | .table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
77 | background-color: #ffc299;
78 | color: #000;
79 | }
80 |
81 |
82 | #console p {
83 | margin-top: 0px;
84 | margin-bottom: 0px;
85 | }
86 |
87 | #mainStatus {
88 | width: auto;
89 | margin: 10px;
90 | }
91 |
92 | .pf {
93 | white-space: pre;
94 | }
95 |
96 |
97 |
98 | .spinner {
99 | width: 100px;
100 | }
101 | .spinner input {
102 | text-align: right;
103 | }
104 | .input-group-btn-vertical {
105 | position: relative;
106 | white-space: nowrap;
107 | width: 1%;
108 | vertical-align: middle;
109 | display: table-cell;
110 | }
111 | .input-group-btn-vertical > .btn {
112 | display: block;
113 | float: none;
114 | width: 100%;
115 | max-width: 100%;
116 | padding: 8px;
117 | margin-left: -1px;
118 | position: relative;
119 | border-radius: 0;
120 | }
121 | .input-group-btn-vertical > .btn:first-child {
122 | border-top-right-radius: 4px;
123 | }
124 | .input-group-btn-vertical > .btn:last-child {
125 | margin-top: -2px;
126 | border-bottom-right-radius: 4px;
127 | }
128 | .input-group-btn-vertical i{
129 | position: absolute;
130 | top: 0;
131 | left: 4px;
132 | }
133 |
134 | .modal
135 | {
136 | overflow: hidden;
137 | }
138 |
139 |
140 | .modal-backdrop {
141 | display: none !important;
142 | }
143 |
144 | .simplebox {
145 | outline: none;
146 | border: none !important;
147 | -webkit-box-shadow: none !important;
148 | -moz-box-shadow: none !important;
149 | box-shadow: none !important;
150 | text-align:right;
151 | }
152 |
153 | /* navbar */
154 | .navbar-primary .navbar { background:#666666; border-bottom:none; }
155 | .navbar-primary .navbar .nav > li > a {color: #501762;}
156 | .navbar-primary .navbar .nav > li > a:hover {color: #fff; background-color: #8e49a3;}
157 | .navbar-primary .navbar .nav .active > a,.navbar .nav .active > a:hover {color: #fff; background-color: #501762;}
158 | .navbar-primary .navbar .nav li > a .caret, .tnav .navbar .nav li > a:hover .caret {border-top-color: #fff;border-bottom-color: #fff;}
159 | .navbar-primary .navbar .nav > li.dropdown.open.active > a:hover {}
160 | .navbar-primary .navbar .nav > li.dropdown.open > a {color: #fff;background-color: #9f58b5;border-color: #fff;}
161 | .navbar-primary .navbar .nav > li.dropdown.open.active > a:hover .caret, .tnav .navbar .nav > li.dropdown.open > a .caret {border-top-color: #fff;}
162 | .navbar-primary .navbar .navbar-brand {color:#fff;}
163 | .navbar-primary .navbar .nav.pull-right {margin-left: 10px; margin-right: 0;}
164 | .navbar-xs .navbar-primary .navbar { min-height:28px; height: 28px; }
165 | .navbar-xs .navbar-primary .navbar .navbar-brand{ padding: 0px 12px;font-size: 16px;line-height: 28px; }
166 | .navbar-xs .navbar-primary .navbar .navbar-nav > li > a { padding-top: 0px; padding-bottom: 0px; line-height: 28px; }
167 | .navbar-sm .navbar-primary .navbar { min-height:28px; height: 28px; }
168 | .navbar-sm .navbar-primary .navbar .navbar-brand{ padding: 0px 12px;font-size: 16px;line-height: 28px; }
169 | .navbar-sm .navbar-primary .navbar .navbar-nav > li > a { padding-top: 0px; padding-bottom: 0px; line-height: 28px; }
170 |
171 | .navbar {
172 | min-height: 28px;
173 | margin-bottom: 23px;
174 | border: 1px solid transparent;
175 | }
176 |
177 | .navbar-brand {
178 | float: left;
179 | font-size: 17px;
180 | line-height: 23px;
181 | height: 28px;
182 | }
183 |
184 | #rasterProgressShroud {
185 | position: relative;
186 | top: 0;
187 | left: 0;
188 | right: 0;
189 | padding: 20px;
190 | background-color: white;
191 | z-index: 999;
192 | height: 100%;
193 | display: none;
194 | }
195 |
196 | #rasterProgressShroud .progress {
197 | position: relative;
198 | top: 0;
199 | bottom: 0;
200 | height: 25px;
201 | width: 300px;
202 | margin: auto;
203 | left: 0;
204 | right: 0
205 | -webkit-transition: none !important;
206 | transition: none !important;;
207 | }
208 |
209 | #rasterProgressShroud .progress-bar {
210 | -webkit-transition: none !important;
211 | transition: none !important;;
212 | }
213 |
214 |
215 | #rasterProgressShroud h1 {
216 | text-align: center;
217 | }
218 |
219 | #renderprogressholder {
220 | position: relative;
221 | top: 0;
222 | left: 0;
223 | right: 0;
224 | padding: 12px;
225 | background-color: white;
226 | z-index: 999;
227 | height: 100%;
228 | display: none;
229 | }
230 |
231 | #renderprogressholder .progress {
232 | position: relative;
233 | top: 0;
234 | bottom: 0;
235 | height: 26px;
236 | width: 300px;
237 | margin: auto;
238 | left: 0;
239 | right: 0
240 | -webkit-transition: none !important;
241 | transition: none !important;;
242 | }
243 |
244 | #renderprogressholder .progress-bar {
245 | -webkit-transition: none !important;
246 | transition: none !important;;
247 | }
248 |
249 |
250 | #renderprogressholder h1 {
251 | text-align: center;
252 | }
253 |
--------------------------------------------------------------------------------
/i/dxf/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 | private/
--------------------------------------------------------------------------------
/i/dxf/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 GDS Storefront Estimating
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
13 | all 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
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/i/dxf/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Three-Dxf
3 |
4 | **Three-Dxf** is a javascript viewer for dxf files. It takes dxf objects produced from Dxf-Parser and renders them using
5 | three.js.
6 |
7 | #### Install
8 | ```
9 | // Coming soon
10 | //bower install three-dxf
11 | ```
12 |
13 | For now we recommend cloning the repo, and starting with our sample. See **Run Samples** below.
14 |
15 | #### Usage
16 | TODO
17 |
18 | #### Run Samples
19 | ```
20 | > npm install -g http-server
21 | > cd sample
22 | > http-server .
23 | # use `http-server -c-1 .` to prevent caching
24 | ```
25 |
26 | After performing the steps above, you can see the example at localhost:8080. You can use the dxf file included in the sample.
27 |
28 | #### Current Version v0.0.1
29 | Supports:
30 | * Headers
31 | * Most Simple entities (lines, polylines, circles, etc)
32 | * Layers
33 | * Some support for line types
34 | * Simple Text
35 |
36 | Does not yet support:
37 | * Attributes
38 | * 3DSolids
39 | * All types of Leaders
40 | * MText
41 | * other less common objects and entities.
42 |
43 | #### Run Tests
44 | TODO
45 |
46 | #### Contributors
47 | bzuillsmith@gdsestimating.com
48 |
--------------------------------------------------------------------------------
/i/dxf/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-dxf",
3 | "main": "three-dxf.js",
4 | "version": "0.0.1",
5 | "authors": [
6 | "GDS Storefront Estimating (gdsestimating.com)"
7 | ],
8 | "description": "A dxf viewer for the browser using three.js.",
9 | "keywords": [
10 | "dxf",
11 | "cad",
12 | "viewer"
13 | ],
14 | "license": "MIT",
15 | "homepage": "https://github.com/gdsestimating/three-dxf",
16 | "ignore": [
17 | "**/.*",
18 | "node_modules",
19 | "bower_components",
20 | "test",
21 | "tests"
22 | ],
23 | "dependencies": {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/i/dxf/gcode/three2gcode.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | AUTHOR: John Lauer
4 | -- changes by AUTHOR: Peter van der Walt
5 |
6 | */
7 |
8 | var options = {};
9 |
10 | /**
11 | * Iterate over the text3d that was generated and create
12 | * Gcode to mill/cut the three.js object.
13 | */
14 | function generateGcodeCallback(threeGroup, cutSpeed, laserPwr, rapidSpeed) {
15 |
16 | console.log('inside generateGcodeCallback')
17 | console.log('Group', threeGroup);
18 | console.log('CutSpeed', cutSpeed);
19 | console.log('Laser Power', laserPwr);
20 | console.log('RapidSpeed', rapidSpeed);
21 | // get settings
22 | //getSettings();
23 |
24 | // Firmware specific Sxxx params
25 | if (firmware.indexOf('Grbl') == 0) {
26 | laserPwr = laserPwr * 2.55;
27 | laserPwr = laserPwr.toFixed(0);
28 | } else if (firmware.indexOf('Smooth') == 0) {
29 | laserPwr = laserPwr / 100; //.map(0, 100, 0, 1);
30 | laserPwr = laserPwr.toFixed(2);
31 | } else if (firmware.indexOf('Lasaur') == 0) {
32 | laserPwr = laserPwr * 2.55;
33 | laserPwr = laserPwr.toFixed(0);
34 | } else {
35 | laserPwr = laserPwr;
36 | }
37 |
38 |
39 | options["pointsperpath"] = 1;
40 | options["holes"] = 0;
41 | options["cut"] = 'solid';
42 | options["dashPercent"] = 20;
43 | options["mode"] = 'laser';
44 | options["laseron"] = 'M3';
45 | options["lasersvalue"] = laserPwr;
46 | options["millclearanceheight"] = 5.00;
47 | options["milldepthcut"] = 3.00;
48 | options["millfeedrateplunge"] = 200.00;
49 | options["feedrate"] = cutSpeed;
50 |
51 | var g = "";
52 |
53 | // get the THREE.Group() that is the txt3d
54 | var grp = threeGroup
55 | var txtGrp = threeGroup;
56 |
57 | var that = this;
58 | var isLaserOn = false;
59 | var isAtClearanceHeight = false;
60 | var isFeedrateSpecifiedAlready = false;
61 | subj_paths = [];
62 | subj_path2 = [];
63 | console.log(txtGrp);
64 | txtGrp.traverse( function(child) {
65 | if (child.type == "Line") {
66 | // let's create gcode for all points in line
67 | for (i = 0; i < child.geometry.vertices.length; i++) {
68 |
69 | var localPt = child.geometry.vertices[i];
70 | var worldPt = grp.localToWorld(localPt.clone());
71 | if (i == 0) {
72 | // first point in line where we start lasering/milling
73 | // move to point
74 |
75 | // if milling, we need to move to clearance height
76 | if (options.mode == "mill") {
77 | if (!isAtClearanceHeight) {
78 | g += "G0 Z" + options.millclearanceheight + "\n";
79 | }
80 | }
81 |
82 | // move to start point
83 | g += "G0 X" + worldPt.x.toFixed(3) +
84 | " Y" + worldPt.y.toFixed(3) + " F" + rapidSpeed + "\n";
85 |
86 |
87 | //subj_paths.push(worldPt.x.toFixed(3) +',' + worldPt.y.toFixed(3));
88 | // if milling move back to depth cut
89 | if (options.mode == "mill") {
90 | var halfDistance = (options.millclearanceheight - options.milldepthcut) / 2;
91 | g += "G0 Z" + (options.millclearanceheight - halfDistance).toFixed(3)
92 | + "\n";
93 | g += "G1 F" + options.millfeedrateplunge +
94 | " Z" + options.milldepthcut + "\n";
95 | isAtClearanceHeight = false;
96 | }
97 |
98 | }
99 | else {
100 |
101 | // we are in a non-first line so this is normal moving
102 |
103 | // see if laser or milling
104 | if (options.mode == "laser") {
105 |
106 | // if the laser is not on, we need to turn it on
107 | if (firmware.indexOf('Grbl') == 0) {
108 | if (!isLaserOn) {
109 | if (options.laseron == "M3") {
110 | g += "M3 S" + options.lasersvalue;
111 | } else {
112 | g += options.laseron;
113 | }
114 | g += " ;laser on\n";
115 | isLaserOn = true;
116 | }
117 | }
118 | } else {
119 | // this is milling. if we are not at depth cut
120 | // we need to get there
121 |
122 |
123 | }
124 |
125 | // do normal feedrate move
126 | var feedrate;
127 | if (isFeedrateSpecifiedAlready) {
128 | feedrate = "";
129 | } else {
130 | feedrate = " F" + options.feedrate;
131 | isFeedrateSpecifiedAlready = true;
132 | }
133 | //console.log('World', worldPt);
134 | //console.log('Local', localPt);
135 | g += "G1" + feedrate;
136 | g += " X" + worldPt.x.toFixed(3);
137 | g += " Y" + worldPt.y.toFixed(3);
138 | g += " S" + options.lasersvalue + "\n";
139 | //subj_paths.push(worldPt.x.toFixed(3) +',' + worldPt.y.toFixed(3));
140 | var xpos = parseFloat(worldPt.x.toFixed(3));
141 | var ypos = parseFloat(worldPt.y.toFixed(3));
142 | subj_paths.push({X:xpos,Y:ypos});
143 |
144 |
145 | }
146 | }
147 |
148 | // make feedrate have to get specified again on next line
149 | // if there is one
150 | isFeedrateSpecifiedAlready = false;
151 |
152 | // see if laser or milling
153 | if (options.mode == "laser") {
154 | // turn off laser at end of line
155 | isLaserOn = false;
156 | if (firmware.indexOf('Grbl') == 0) {
157 | if (options.laseron == "M3")
158 | g += "M5 ;laser off;\n";
159 | else
160 | g += "M9 ;laser off;\n";
161 | }
162 | } else {
163 | // milling. move back to clearance height
164 | g += "G0 Z" + options.millclearanceheight + "\n";
165 | isAtClearanceHeight = true;
166 | }
167 | console.log('Input Path', subj_paths);
168 | subj_path2 = getInflatedPath(subj_paths, 5);
169 | console.log('Output Path', subj_path2);
170 |
171 | // var mesh = createClipperPathsAsMesh(subj_path2, 0xff0000, 0.2, subj_path2);
172 | // tool_offset = createClipperPathsAsLines(subj_path2);
173 | // tool_offset.translateX(laserxmax /2 * -1);
174 | // tool_offset.translateY(laserymax /2 * -1);
175 | // tool_offset.name = 'Mill Path';
176 | //scene.add(tool_offset); // Plasma Mode! W.I.P
177 |
178 |
179 |
180 | }
181 | });
182 |
183 | console.log("generated gcode. length:", g.length);
184 |
185 | isGcodeInRegeneratingState = false;
186 |
187 | // Remove DXF Preview
188 | if (typeof(dxfObject) !== 'undefined') {
189 | scene.remove(dxfObject);
190 | };
191 |
192 | // Send to LaserWeb
193 | //document.getElementById("gcodepreview").value = g;
194 | return g;
195 |
196 | };
197 |
198 |
199 | function getInflatedPath(paths, delta, joinType) {
200 | var scale = 10000;
201 | console.log('Inside getInflatedPath');
202 | ClipperLib.JS.ScaleUpPath(paths, scale);
203 | console.log('Scaled Path: ', paths);
204 | var miterLimit = 2;
205 | var arcTolerance = 10;
206 | joinType = joinType ? joinType : ClipperLib.JoinType.jtRound
207 | var co = new ClipperLib.ClipperOffset(miterLimit, arcTolerance);
208 | co.AddPath(paths, joinType, ClipperLib.EndType.etClosedPolygon);
209 | //var delta = 0.0625; // 1/16 inch endmill
210 | var offsetted_paths = new ClipperLib.Path();
211 | co.Execute(offsetted_paths, delta * scale);
212 |
213 | console.log('Offset Path: ', offsetted_paths);
214 | // scale back down
215 | for (var i = 0; i < offsetted_paths.length; i++) {
216 | for (var j = 0; j < offsetted_paths[i].length; j++) {
217 | offsetted_paths[i][j].X = offsetted_paths[i][j].X / scale;
218 | offsetted_paths[i][j].Y = offsetted_paths[i][j].Y / scale;
219 | }
220 | }
221 | ClipperLib.JS.ScaleDownPaths(paths, scale);
222 | return offsetted_paths;
223 |
224 | };
225 |
226 | function createClipperPathsAsLines(paths) {
227 |
228 | var geometry = new THREE.Geometry(),
229 | color = 0xff0000,
230 | material, lineType, vertex, startPoint, endPoint, i, line;
231 |
232 |
233 | if (paths.length == 1) {
234 | var shape = new THREE.Shape();
235 | var i = 0;
236 | for (var j = 0; j < paths[i].length; j++) {
237 | var pt = paths[i][j];
238 | //if (j == 0) shape.moveTo(pt.X, pt.Y);
239 | //else shape.lineTo(pt.X, pt.Y);
240 | geometry.vertices.push(new THREE.Vector3(pt.X, pt.Y, 0));
241 | }
242 | };
243 |
244 | material = new THREE.LineBasicMaterial({ linewidth: 1, color: color, transparent: true });
245 |
246 | millgeom = new THREE.Line(geometry, material);
247 | return millgeom;
248 |
249 | };
250 |
251 | function createClipperPathsAsMesh(paths, color, opacity, holePath) {
252 | //console.log("createClipperPathsAsMesh. paths:", paths, "holePath:", holePath);
253 | if(color === undefined)
254 | color = 0xff0000;
255 | var mat = new THREE.MeshBasicMaterial({
256 | color: color,
257 | transparent: true,
258 | opacity: opacity,
259 | side: THREE.DoubleSide,
260 | depthWrite: false
261 | });
262 |
263 |
264 | if (paths.length == 1) {
265 | var shape = new THREE.Shape();
266 | var i = 0;
267 | for (var j = 0; j < paths[i].length; j++) {
268 | var pt = paths[i][j];
269 | if (j == 0) shape.moveTo(pt.X, pt.Y);
270 | else shape.lineTo(pt.X, pt.Y);
271 | }
272 |
273 | // see if asked to create hole
274 | // multiple holes supported now
275 | if (holePath !== undefined && holePath != null) {
276 | if (!(Array.isArray(holePath))) {
277 | holePath = [holePath];
278 | }
279 |
280 | for (var hi = 0; hi < holePath.length; hi++) {
281 | var hp = holePath[hi];
282 | console.log("adding hole:", hp);
283 | var hole = new THREE.Path();
284 | //var i = 0;
285 | for (var j = 0; j < hp.length; j++) {
286 | var pt = hp[j];
287 | if (j == 0) hole.moveTo(pt.X, pt.Y);
288 | else hole.lineTo(pt.X, pt.Y);
289 | }
290 | shape.holes.push(hole);
291 | }
292 | }
293 |
294 | var geometry = new THREE.ShapeGeometry( shape );
295 | var shapeMesh = new THREE.Mesh(geometry, mat);
296 |
297 | //group.add(shapeMesh);
298 | return shapeMesh;
299 | } else {
300 | var group = new THREE.Object3D();
301 |
302 | for (var i = 0; i < paths.length; i++) {
303 | var shape = new THREE.Shape();
304 | for (var j = 0; j < paths[i].length; j++) {
305 | var pt = paths[i][j];
306 | if (j == 0) shape.moveTo(pt.X, pt.Y);
307 | else shape.lineTo(pt.X, pt.Y);
308 | }
309 |
310 | // see if asked to create hole
311 | // multiple holes supported now
312 | if (holePath !== undefined && holePath != null) {
313 | if (!(Array.isArray(holePath))) {
314 | holePath = [holePath];
315 | }
316 |
317 | for (var hi = 0; hi < holePath.length; hi++) {
318 | var hp = holePath[hi];
319 | console.log("adding hole:", hp);
320 | var hole = new THREE.Path();
321 | //var i = 0;
322 | for (var j = 0; j < hp.length; j++) {
323 | var pt = hp[j];
324 | if (j == 0) hole.moveTo(pt.X, pt.Y);
325 | else hole.lineTo(pt.X, pt.Y);
326 | }
327 | shape.holes.push(hole);
328 | }
329 | }
330 |
331 | var geometry = new THREE.ShapeGeometry( shape );
332 | var shapeMesh = new THREE.Mesh(geometry, mat);
333 |
334 | group.add(shapeMesh);
335 | }
336 | return group;
337 | }
338 | //this.sceneAdd(group);
339 |
340 | };
341 |
--------------------------------------------------------------------------------
/i/dxf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-dxf",
3 | "version": "0.1.0",
4 | "description": "A dxf viewer for the browser using three.js.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha test"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/gdsestimating/three-dxf"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/gdsestimating/three-dxf/issues",
15 | "email": "bzuillsmith@gmail.com"
16 | },
17 | "homepage": "https://github.com/gdsestimating/three-dxf",
18 | "author": "GDS Storefront Estimating (gdsestimating.com)",
19 | "contributors": [
20 | "Ben Zuill-Smith While hovering over the canvas: Right click to pan. Mouse wheel to zoom in an out. The starting view is
52 | arbitrary at the moment so you may need to zoom out and pan around to find the drawing. This will be fixed
53 | in future versions. WebGL detected! CRITICAL ERROR: No WebGL Support!' + output.join('') + '
';
27 |
28 | $progress.addClass('loading');
29 |
30 | var reader = new FileReader();
31 | reader.onprogress = updateProgress;
32 | reader.onloadend = onSuccess;
33 | reader.onabort = abortUpload;
34 | reader.onerror = errorHandler;
35 | reader.readAsText(file);
36 | }
37 |
38 | function abortUpload() {
39 | console.log('Aborted read!')
40 | }
41 |
42 | function errorHandler(evt) {
43 | switch(evt.target.error.code) {
44 | case evt.target.error.NOT_FOUND_ERR:
45 | alert('File Not Found!');
46 | break;
47 | case evt.target.error.NOT_READABLE_ERR:
48 | alert('File is not readable');
49 | break;
50 | case evt.target.error.ABORT_ERR:
51 | break; // noop
52 | default:
53 | alert('An error occurred reading this file.');
54 | }
55 | }
56 |
57 | function updateProgress(evt) {
58 | console.log('progress');
59 | console.log(Math.round((evt.loaded /evt.total) * 100));
60 | if(evt.lengthComputable) {
61 | var percentLoaded = Math.round((evt.loaded /evt.total) * 100);
62 | if (percentLoaded < 100) {
63 | progress.style.width = percentLoaded + '%';
64 | progress.textContent = percentLoaded + '%';
65 | }
66 | }
67 | }
68 |
69 | function onSuccess(evt){
70 | var fileReader = evt.target;
71 | if(fileReader.error) return console.log("error onloadend!?");
72 | progress.style.width = '100%';
73 | progress.textContent = '100%';
74 | setTimeout(function() { $progress.removeClass('loading'); }, 2000);
75 | var parser = new window.DxfParser();
76 | var dxf = parser.parseSync(fileReader.result);
77 | cadCanvas = new ThreeDxfViewer(dxf, document.getElementById('cad-view'), 400, 400);
78 | }
79 |
80 | function handleDragOver(evt) {
81 | evt.stopPropagation();
82 | evt.preventDefault();
83 | evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
84 | }
85 |
--------------------------------------------------------------------------------
/i/dxf/sample/libs/js/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | */
8 | /*global THREE, console */
9 |
10 | // This set of controls performs orbiting, dollying (zooming), and panning. It maintains
11 | // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
12 | // supported.
13 | //
14 | // Orbit - left mouse / touch: one finger move
15 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
16 | // Pan - right mouse, or arrow keys / touch: three finter swipe
17 | //
18 | // This is a drop-in replacement for (most) TrackballControls used in examples.
19 | // That is, include this js file and wherever you see:
20 | // controls = new THREE.TrackballControls( camera );
21 | // controls.target.z = 150;
22 | // Simple substitute "OrbitControls" and the control should work as-is.
23 |
24 | THREE.OrbitControls = function ( object, domElement ) {
25 |
26 | this.object = object;
27 | this.domElement = ( domElement !== undefined ) ? domElement : document;
28 |
29 | // API
30 |
31 | // Set to false to disable this control
32 | this.enabled = true;
33 |
34 | // "target" sets the location of focus, where the control orbits around
35 | // and where it pans with respect to.
36 | this.target = new THREE.Vector3();
37 |
38 | // center is old, deprecated; use "target" instead
39 | this.center = this.target;
40 |
41 | // This option actually enables dollying in and out; left as "zoom" for
42 | // backwards compatibility
43 | this.noZoom = false;
44 | this.zoomSpeed = 1.0;
45 |
46 | // Limits to how far you can dolly in and out
47 | this.minDistance = 0;
48 | this.maxDistance = Infinity;
49 |
50 | // Set to true to disable this control
51 | this.noRotate = false;
52 | this.rotateSpeed = 1.0;
53 |
54 | // Set to true to disable this control
55 | this.noPan = false;
56 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
57 |
58 | // Set to true to automatically rotate around the target
59 | this.autoRotate = false;
60 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
61 |
62 | // How far you can orbit vertically, upper and lower limits.
63 | // Range is 0 to Math.PI radians.
64 | this.minPolarAngle = 0; // radians
65 | this.maxPolarAngle = Math.PI; // radians
66 |
67 | // Set to true to disable use of the keys
68 | this.noKeys = false;
69 |
70 | // The four arrow keys
71 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
72 |
73 | ////////////
74 | // internals
75 |
76 | var scope = this;
77 |
78 | var EPS = 0.000001;
79 |
80 | var rotateStart = new THREE.Vector2();
81 | var rotateEnd = new THREE.Vector2();
82 | var rotateDelta = new THREE.Vector2();
83 |
84 | var panStart = new THREE.Vector2();
85 | var panEnd = new THREE.Vector2();
86 | var panDelta = new THREE.Vector2();
87 | var panOffset = new THREE.Vector3();
88 |
89 | var offset = new THREE.Vector3();
90 |
91 | var dollyStart = new THREE.Vector2();
92 | var dollyEnd = new THREE.Vector2();
93 | var dollyDelta = new THREE.Vector2();
94 |
95 | var phiDelta = 0;
96 | var thetaDelta = 0;
97 | var scale = 1;
98 | var pan = new THREE.Vector3();
99 |
100 | var lastPosition = new THREE.Vector3();
101 |
102 | var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
103 |
104 | var state = STATE.NONE;
105 |
106 | // for reset
107 |
108 | this.target0 = this.target.clone();
109 | this.position0 = this.object.position.clone();
110 |
111 | // events
112 |
113 | var changeEvent = { type: 'change' };
114 | var startEvent = { type: 'start'};
115 | var endEvent = { type: 'end'};
116 |
117 | this.rotateLeft = function ( angle ) {
118 |
119 | if ( angle === undefined ) {
120 |
121 | angle = getAutoRotationAngle();
122 |
123 | }
124 |
125 | thetaDelta -= angle;
126 |
127 | };
128 |
129 | this.rotateUp = function ( angle ) {
130 |
131 | if ( angle === undefined ) {
132 |
133 | angle = getAutoRotationAngle();
134 |
135 | }
136 |
137 | phiDelta -= angle;
138 |
139 | };
140 |
141 | // pass in distance in world space to move left
142 | this.panLeft = function ( distance ) {
143 |
144 | var te = this.object.matrix.elements;
145 |
146 | // get X column of matrix
147 | panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
148 | panOffset.multiplyScalar( - distance );
149 |
150 | pan.add( panOffset );
151 |
152 | };
153 |
154 | // pass in distance in world space to move up
155 | this.panUp = function ( distance ) {
156 |
157 | var te = this.object.matrix.elements;
158 |
159 | // get Y column of matrix
160 | panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
161 | panOffset.multiplyScalar( distance );
162 |
163 | pan.add( panOffset );
164 |
165 | };
166 |
167 | // pass in x,y of change desired in pixel space,
168 | // right and down are positive
169 | this.pan = function ( deltaX, deltaY ) {
170 |
171 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
172 |
173 | if ( scope.object.fov !== undefined ) {
174 |
175 | // perspective
176 | var position = scope.object.position;
177 | var offset = position.clone().sub( scope.target );
178 | var targetDistance = offset.length();
179 |
180 | // half of the fov is center to top of screen
181 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
182 |
183 | // we actually don't use screenWidth, since perspective camera is fixed to screen height
184 | scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
185 | scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
186 |
187 | } else if ( scope.object.top !== undefined ) {
188 |
189 | // orthographic
190 | scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
191 | scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
192 |
193 | } else {
194 |
195 | // camera neither orthographic or perspective
196 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
197 |
198 | }
199 |
200 | };
201 |
202 | this.dollyIn = function ( dollyScale ) {
203 |
204 | if ( dollyScale === undefined ) {
205 |
206 | dollyScale = getZoomScale();
207 |
208 | }
209 |
210 | scale /= dollyScale;
211 |
212 | };
213 |
214 | this.dollyOut = function ( dollyScale ) {
215 |
216 | if ( dollyScale === undefined ) {
217 |
218 | dollyScale = getZoomScale();
219 |
220 | }
221 |
222 | scale *= dollyScale;
223 |
224 | };
225 |
226 | this.update = function () {
227 |
228 | if(scope.object.top !== undefined) {
229 | this.object.top = (scale*this.object.top);
230 | this.object.bottom = (scale*this.object.bottom);
231 | this.object.left = (scale*this.object.left);
232 | this.object.right = (scale*this.object.right);
233 |
234 | this.object.updateProjectionMatrix();
235 |
236 | }
237 |
238 |
239 | var position = this.object.position;
240 |
241 | offset.copy( position ).sub( this.target );
242 | //
243 | // // angle from z-axis around y-axis
244 | //
245 | // var theta = Math.atan2( offset.x, offset.z );
246 | //
247 | // // angle from y-axis
248 | //
249 | // var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
250 | //
251 | // if ( this.autoRotate ) {
252 | //
253 | // this.rotateLeft( getAutoRotationAngle() );
254 | //
255 | // }
256 | //
257 | // theta += thetaDelta;
258 | // phi += phiDelta;
259 | //
260 | // // restrict phi to be between desired limits
261 | // phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
262 | //
263 | // // restrict phi to be betwee EPS and PI-EPS
264 | // phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
265 | //
266 | // var radius = offset.length() * scale;
267 | //
268 | // // restrict radius to be between desired limits
269 | // radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
270 | //
271 | // // move target to panned location
272 | this.target.add( pan );
273 | //
274 | // offset.x = radius * Math.sin( phi ) * Math.sin( theta );
275 | // offset.y = radius * Math.cos( phi );
276 | // offset.z = radius * Math.sin( phi ) * Math.cos( theta );
277 | //
278 | position.copy( this.target ).add( offset );
279 |
280 | this.object.lookAt( this.target );
281 |
282 |
283 | // if ( lastPosition.distanceTo( this.object.position ) > 0 || scale !== 1 ) {
284 |
285 | this.dispatchEvent( changeEvent );
286 |
287 | // lastPosition.copy( this.object.position );
288 |
289 | // }
290 |
291 | // thetaDelta = 0;
292 | // phiDelta = 0;
293 | scale = 1;
294 | pan.set( 0, 0, 0 );
295 |
296 | };
297 |
298 |
299 | this.reset = function () {
300 |
301 | state = STATE.NONE;
302 |
303 | this.target.copy( this.target0 );
304 | this.object.position.copy( this.position0 );
305 |
306 | this.update();
307 |
308 | };
309 |
310 | function getAutoRotationAngle() {
311 |
312 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
313 |
314 | }
315 |
316 | function getZoomScale() {
317 |
318 | return Math.pow( 0.95, scope.zoomSpeed );
319 |
320 | }
321 |
322 | function onMouseDown( event ) {
323 |
324 | if ( scope.enabled === false ) return;
325 | event.preventDefault();
326 |
327 | if ( event.button === 0 ) {
328 | if ( scope.noRotate === true ) return;
329 |
330 | state = STATE.ROTATE;
331 |
332 | rotateStart.set( event.clientX, event.clientY );
333 |
334 | } else if ( event.button === 1 ) {
335 | if ( scope.noZoom === true ) return;
336 |
337 | state = STATE.DOLLY;
338 |
339 | dollyStart.set( event.clientX, event.clientY );
340 |
341 | } else if ( event.button === 2 ) {
342 | if ( scope.noPan === true ) return;
343 |
344 | state = STATE.PAN;
345 |
346 | panStart.set( event.clientX, event.clientY );
347 |
348 | }
349 |
350 | scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
351 | scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
352 | scope.dispatchEvent( startEvent );
353 |
354 | }
355 |
356 | function onMouseMove( event ) {
357 |
358 | if ( scope.enabled === false ) return;
359 |
360 | event.preventDefault();
361 |
362 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
363 |
364 | if ( state === STATE.ROTATE ) {
365 |
366 | if ( scope.noRotate === true ) return;
367 |
368 | rotateEnd.set( event.clientX, event.clientY );
369 | rotateDelta.subVectors( rotateEnd, rotateStart );
370 |
371 | // rotating across whole screen goes 360 degrees around
372 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
373 |
374 | // rotating up and down along whole screen attempts to go 360, but limited to 180
375 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
376 |
377 | rotateStart.copy( rotateEnd );
378 |
379 | } else if ( state === STATE.DOLLY ) {
380 |
381 | if ( scope.noZoom === true ) return;
382 |
383 | dollyEnd.set( event.clientX, event.clientY );
384 | dollyDelta.subVectors( dollyEnd, dollyStart );
385 |
386 | if ( dollyDelta.y > 0 ) {
387 |
388 | scope.dollyIn();
389 |
390 | } else {
391 |
392 | scope.dollyOut();
393 |
394 | }
395 |
396 | dollyStart.copy( dollyEnd );
397 |
398 | } else if ( state === STATE.PAN ) {
399 |
400 | if ( scope.noPan === true ) return;
401 |
402 | panEnd.set( event.clientX, event.clientY );
403 | panDelta.subVectors( panEnd, panStart );
404 |
405 | scope.pan( panDelta.x, panDelta.y );
406 |
407 | panStart.copy( panEnd );
408 |
409 | }
410 |
411 | scope.update();
412 |
413 | }
414 |
415 | function onMouseUp( /* event */ ) {
416 |
417 | if ( scope.enabled === false ) return;
418 |
419 | scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
420 | scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
421 | scope.dispatchEvent( endEvent );
422 | state = STATE.NONE;
423 |
424 | }
425 |
426 | function onMouseWheel( event ) {
427 |
428 | if ( scope.enabled === false || scope.noZoom === true ) return;
429 |
430 | event.preventDefault();
431 |
432 | var delta = 0;
433 |
434 | if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
435 |
436 | delta = event.wheelDelta;
437 |
438 | } else if ( event.detail !== undefined ) { // Firefox
439 |
440 | delta = - event.detail;
441 |
442 | }
443 |
444 | if ( delta > 0 ) {
445 |
446 | scope.dollyOut();
447 |
448 | } else {
449 |
450 | scope.dollyIn();
451 |
452 | }
453 |
454 | scope.update();
455 | scope.dispatchEvent( startEvent );
456 | scope.dispatchEvent( endEvent );
457 |
458 | }
459 |
460 | function onKeyDown( event ) {
461 |
462 | if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
463 |
464 | switch ( event.keyCode ) {
465 |
466 | case scope.keys.UP:
467 | scope.pan( 0, scope.keyPanSpeed );
468 | scope.update();
469 | break;
470 |
471 | case scope.keys.BOTTOM:
472 | scope.pan( 0, - scope.keyPanSpeed );
473 | scope.update();
474 | break;
475 |
476 | case scope.keys.LEFT:
477 | scope.pan( scope.keyPanSpeed, 0 );
478 | scope.update();
479 | break;
480 |
481 | case scope.keys.RIGHT:
482 | scope.pan( - scope.keyPanSpeed, 0 );
483 | scope.update();
484 | break;
485 |
486 | }
487 |
488 | }
489 |
490 | function touchstart( event ) {
491 |
492 | if ( scope.enabled === false ) return;
493 |
494 | switch ( event.touches.length ) {
495 |
496 | case 1: // one-fingered touch: rotate
497 |
498 | if ( scope.noRotate === true ) return;
499 |
500 | state = STATE.TOUCH_ROTATE;
501 |
502 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
503 | break;
504 |
505 | case 2: // two-fingered touch: dolly
506 |
507 | if ( scope.noZoom === true ) return;
508 |
509 | state = STATE.TOUCH_DOLLY;
510 |
511 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
512 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
513 | var distance = Math.sqrt( dx * dx + dy * dy );
514 | dollyStart.set( 0, distance );
515 | break;
516 |
517 | case 3: // three-fingered touch: pan
518 |
519 | if ( scope.noPan === true ) return;
520 |
521 | state = STATE.TOUCH_PAN;
522 |
523 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
524 | break;
525 |
526 | default:
527 |
528 | state = STATE.NONE;
529 |
530 | }
531 |
532 | scope.dispatchEvent( startEvent );
533 |
534 | }
535 |
536 | function touchmove( event ) {
537 |
538 | if ( scope.enabled === false ) return;
539 |
540 | event.preventDefault();
541 | event.stopPropagation();
542 |
543 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
544 |
545 | switch ( event.touches.length ) {
546 |
547 | case 1: // one-fingered touch: rotate
548 |
549 | if ( scope.noRotate === true ) return;
550 | if ( state !== STATE.TOUCH_ROTATE ) return;
551 |
552 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
553 | rotateDelta.subVectors( rotateEnd, rotateStart );
554 |
555 | // rotating across whole screen goes 360 degrees around
556 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
557 | // rotating up and down along whole screen attempts to go 360, but limited to 180
558 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
559 |
560 | rotateStart.copy( rotateEnd );
561 |
562 | scope.update();
563 | break;
564 |
565 | case 2: // two-fingered touch: dolly
566 |
567 | if ( scope.noZoom === true ) return;
568 | if ( state !== STATE.TOUCH_DOLLY ) return;
569 |
570 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
571 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
572 | var distance = Math.sqrt( dx * dx + dy * dy );
573 |
574 | dollyEnd.set( 0, distance );
575 | dollyDelta.subVectors( dollyEnd, dollyStart );
576 |
577 | if ( dollyDelta.y > 0 ) {
578 |
579 | scope.dollyOut();
580 |
581 | } else {
582 |
583 | scope.dollyIn();
584 |
585 | }
586 |
587 | dollyStart.copy( dollyEnd );
588 |
589 | scope.update();
590 | break;
591 |
592 | case 3: // three-fingered touch: pan
593 |
594 | if ( scope.noPan === true ) return;
595 | if ( state !== STATE.TOUCH_PAN ) return;
596 |
597 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
598 | panDelta.subVectors( panEnd, panStart );
599 |
600 | scope.pan( panDelta.x, panDelta.y );
601 |
602 | panStart.copy( panEnd );
603 |
604 | scope.update();
605 | break;
606 |
607 | default:
608 |
609 | state = STATE.NONE;
610 |
611 | }
612 |
613 | }
614 |
615 | function touchend( /* event */ ) {
616 |
617 | if ( scope.enabled === false ) return;
618 |
619 | scope.dispatchEvent( endEvent );
620 | state = STATE.NONE;
621 |
622 | }
623 |
624 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
625 | this.domElement.addEventListener( 'mousedown', onMouseDown, false );
626 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
627 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
628 |
629 | this.domElement.addEventListener( 'touchstart', touchstart, false );
630 | this.domElement.addEventListener( 'touchend', touchend, false );
631 | this.domElement.addEventListener( 'touchmove', touchmove, false );
632 |
633 | window.addEventListener( 'keydown', onKeyDown, false );
634 |
635 | };
636 |
637 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
--------------------------------------------------------------------------------
/i/dxf/sample/three-dxf.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Returns the angle in radians of the vector (p1,p2). In other words, imagine
4 | * putting the base of the vector at coordinates (0,0) and finding the angle
5 | * from vector (1,0) to (p1,p2).
6 | * @param {Object} p1 start point of the vector
7 | * @param {Object} p2 end point of the vector
8 | * @return {Number} the angle
9 | */
10 | THREE.Math.angle2 = function(p1, p2) {
11 | var v1 = new THREE.Vector2(p1.x, p1.y);
12 | var v2 = new THREE.Vector2(p2.x, p2.y);
13 | v2.sub(v1); // sets v2 to be our chord
14 | v2.normalize(); // normalize because cos(theta) =
15 | // if(v2.y < 0) return Math.PI + (Math.PI - Math.acos(v2.x));
16 | if(v2.y < 0) return -Math.acos(v2.x);
17 | return Math.acos(v2.x);
18 | };
19 |
20 |
21 | THREE.Math.polar = function(point, distance, angle) {
22 | var result = {};
23 | result.x = point.x + distance * Math.cos(angle);
24 | result.y = point.y + distance * Math.sin(angle);
25 | return result;
26 | };
27 |
28 | /**
29 | * Calculates points for a curve between two points
30 | * @param startPoint - the starting point of the curve
31 | * @param endPoint - the ending point of the curve
32 | * @param bulge - a value indicating how much to curve
33 | * @param segments - number of segments between the two given points
34 | */
35 | THREE.BulgeGeometry = function ( startPoint, endPoint, bulge, segments ) {
36 |
37 | var vertex, i,
38 | center, p0, p1, angle,
39 | radius, startAngle,
40 | thetaAngle;
41 |
42 | THREE.Geometry.call( this );
43 |
44 | this.startPoint = p0 = startPoint ? new THREE.Vector2(startPoint.x, startPoint.y) : new THREE.Vector2(0,0);
45 | this.endPoint = p1 = endPoint ? new THREE.Vector2(endPoint.x, endPoint.y) : new THREE.Vector2(1,0);
46 | this.bulge = bulge = bulge || 1;
47 |
48 | angle = 4 * Math.atan(bulge);
49 | radius = p0.distanceTo(p1) / 2 / Math.sin(angle/2);
50 | center = THREE.Math.polar(startPoint, radius, THREE.Math.angle2(p0,p1) + (Math.PI / 2 - angle/2));
51 |
52 | this.segments = segments = segments || Math.max( Math.abs(Math.ceil(angle/(Math.PI/18))), 6); // By default want a segment roughly every 10 degrees
53 | startAngle = THREE.Math.angle2(center, p0);
54 | thetaAngle = angle / segments;
55 |
56 |
57 | this.vertices.push(new THREE.Vector3(p0.x, p0.y, 0));
58 |
59 | for(i = 1; i <= segments - 1; i++) {
60 |
61 | vertex = THREE.Math.polar(center, Math.abs(radius), startAngle + thetaAngle * i);
62 |
63 | this.vertices.push(new THREE.Vector3(vertex.x, vertex.y, 0));
64 |
65 | }
66 |
67 | };
68 |
69 | THREE.BulgeGeometry.prototype = Object.create( THREE.Geometry.prototype );
70 |
71 | /**
72 | * Viewer class for a dxf object.
73 | * @param {Object} data - the dxf object
74 | * @param {Object} parent - the parent element to which we attach the rendering canvas
75 | * @param {Number} width - width of the rendering canvas in pixels
76 | * @param {Number} height - height of the rendering canvas in pixels
77 | * @constructor
78 | */
79 | function ThreeDxfViewer(data, parent, width, height) {
80 | var self = this;
81 | var $parent = $(parent);
82 |
83 | var scene = new THREE.Scene();
84 | width = width || $parent.innerWidth();
85 | height = height || $parent.innerHeight();
86 | var aspectRatio = width / height;
87 | var viewSize = 30;
88 | var camera = new THREE.OrthographicCamera(viewSize * aspectRatio / -2, viewSize * aspectRatio / 2, viewSize / 2, viewSize / -2, 1, 19);
89 | camera.position.z = 10;
90 | camera.position.x = 570;
91 | camera.position.y = 335;
92 | // camera.position.x = 0;
93 | // camera.position.y = 0;
94 |
95 | // var renderer = this.renderer = new THREE.CanvasRenderer();
96 | var renderer = this.renderer = new THREE.WebGLRenderer();
97 | renderer.setSize(width, height);
98 | renderer.setClearColor(0xfffffff, 1);
99 |
100 | $parent.append(renderer.domElement);
101 | $parent.show();
102 |
103 | var controls = new THREE.OrbitControls(camera, parent);
104 | controls.target.x = camera.position.x;
105 | controls.target.y = camera.position.y;
106 | controls.target.z = 0;
107 | controls.zoomSpeed = 3;
108 |
109 | createLineTypeShaders(data);
110 |
111 | var i, entity;
112 |
113 | for(i = 0; i < data.entities.length; i++) {
114 | entity = data.entities[i];
115 |
116 | if(entity.type === 'DIMENSION') {
117 | if(entity.block) {
118 | var block = data.blocks[entity.block];
119 | for(j = 0; j < block.entities.length; j++) {
120 | drawEntity(block.entities[j], data);
121 | }
122 | } else {
123 | console.log('WARNING: No block for DIMENSION entity');
124 | }
125 | } else {
126 | drawEntity(entity, data);
127 | }
128 | }
129 |
130 | this.render = function() {
131 | renderer.render(scene, camera);
132 | };
133 |
134 | controls.addEventListener('change', this.render);
135 | this.render();
136 |
137 | $parent.on('click', function(event) {
138 | var $el = $(renderer.domElement);
139 |
140 | var vector = new THREE.Vector3(
141 | ( (event.pageX - $el.offset().left) / $el.innerWidth() ) * 2 - 1,
142 | -( (event.pageY - $el.offset().top) / $el.innerHeight() ) * 2 + 1,
143 | 0.5);
144 | var projector = new THREE.Projector();
145 | projector.unprojectVector(vector, camera);
146 |
147 | var dir = vector.sub(camera.position).normalize();
148 |
149 | var distance = -camera.position.z / dir.z;
150 |
151 | var pos = camera.position.clone().add(dir.multiplyScalar(distance));
152 |
153 | console.log(pos.x, pos.y); // Position in cad that is clicked
154 | });
155 |
156 | this.resize = function(width, height) {
157 | var originalWidth = renderer.domElement.width;
158 | var originalHeight = renderer.domElement.height;
159 |
160 | var hscale = width / originalWidth;
161 | var vscale = height / originalHeight;
162 |
163 |
164 | camera.top = (vscale * camera.top);
165 | camera.bottom = (vscale * camera.bottom);
166 | camera.left = (hscale * camera.left);
167 | camera.right = (hscale * camera.right);
168 |
169 | // camera.updateProjectionMatrix();
170 |
171 | renderer.setSize(width, height);
172 | renderer.setClearColor(0xfffffff, 1);
173 | this.render();
174 | };
175 |
176 | function drawEntity(entity, data) {
177 | if(entity.type === 'CIRCLE' || entity.type === 'ARC') {
178 | drawCircle(entity, data);
179 | } else if(entity.type === 'LWPOLYLINE' || entity.type === 'LINE') {
180 | drawLine(entity, data);
181 | } else if(entity.type === 'TEXT') {
182 | drawText(entity, data);
183 | } else if(entity.type === 'SOLID') {
184 | drawSolid(entity, data);
185 | } else if(entity.type === 'POINT') {
186 | drawPoint(entity, data);
187 | }
188 | }
189 |
190 | function drawLine(entity, data) {
191 | var geometry = new THREE.Geometry(),
192 | color = getColor(entity, data),
193 | material, lineType, vertex, startPoint, endPoint, bulgeGeometry,
194 | bulge, i, line;
195 |
196 | // create geometry
197 | for(i = 0; i < entity.vertices.length; i++) {
198 |
199 | if(entity.vertices[i].bulge) {
200 | bulge = entity.vertices[i].bulge;
201 | startPoint = entity.vertices[i];
202 | endPoint = i + 1 < entity.vertices.length ? entity.vertices[i + 1] : geometry.vertices[0];
203 |
204 | bulgeGeometry = new THREE.BulgeGeometry(startPoint, endPoint, bulge);
205 |
206 | geometry.vertices.push.apply(geometry.vertices, bulgeGeometry.vertices);
207 | } else {
208 | vertex = entity.vertices[i];
209 | geometry.vertices.push(new THREE.Vector3(vertex.x, vertex.y, 0));
210 | }
211 |
212 | }
213 | if(entity.shape) geometry.vertices.push(geometry.vertices[0]);
214 |
215 |
216 | // set material
217 | if(entity.lineType) {
218 | lineType = data.tables.lineTypes[entity.lineType];
219 | }
220 |
221 | if(lineType && lineType.pattern && lineType.pattern.length !== 0) {
222 | material = new THREE.LineDashedMaterial({ color: color, gapSize: 4, dashSize: 4});
223 | } else {
224 | material = new THREE.LineBasicMaterial({ linewidth: 1, color: color });
225 | }
226 |
227 | // if(lineType && lineType.pattern && lineType.pattern.length !== 0) {
228 |
229 | // geometry.computeLineDistances();
230 |
231 | // // Ugly hack to add diffuse to this. Maybe copy the uniforms object so we
232 | // // don't add diffuse to a material.
233 | // lineType.material.uniforms.diffuse = { type: 'c', value: new THREE.Color(color) };
234 |
235 | // material = new THREE.ShaderMaterial({
236 | // uniforms: lineType.material.uniforms,
237 | // vertexShader: lineType.material.vertexShader,
238 | // fragmentShader: lineType.material.fragmentShader
239 | // });
240 | // }else {
241 | // material = new THREE.LineBasicMaterial({ linewidth: 1, color: color });
242 | // }
243 |
244 | line = new THREE.Line(geometry, material);
245 | scene.add(line);
246 | }
247 |
248 | function drawCircle(entity, data) {
249 | var geometry, material, circle;
250 |
251 | geometry = new THREE.CircleGeometry(entity.radius, 32, entity.startAngle, entity.angleLength);
252 | geometry.vertices.shift();
253 |
254 | material = new THREE.LineBasicMaterial({ color: getColor(entity, data) });
255 |
256 | circle = new THREE.Line(geometry, material);
257 | circle.position.x = entity.center.x;
258 | circle.position.y = entity.center.y;
259 | circle.position.z = entity.center.z;
260 |
261 | scene.add(circle);
262 | }
263 |
264 | function drawSolid(entity, data) {
265 | var material, mesh, solid, verts;
266 | geometry = new THREE.Geometry();
267 |
268 | verts = geometry.vertices;
269 | verts.push(new THREE.Vector3(entity.points[0].x, entity.points[0].y, entity.points[0].z));
270 | verts.push(new THREE.Vector3(entity.points[1].x, entity.points[1].y, entity.points[1].z));
271 | verts.push(new THREE.Vector3(entity.points[2].x, entity.points[2].y, entity.points[2].z));
272 | verts.push(new THREE.Vector3(entity.points[3].x, entity.points[3].y, entity.points[3].z));
273 |
274 | // Calculate which direction the points are facing (clockwise or counter-clockwise)
275 | var vector1 = new THREE.Vector3();
276 | var vector2 = new THREE.Vector3();
277 | vector1.subVectors(verts[1], verts[0]);
278 | vector2.subVectors(verts[2], verts[0]);
279 | vector1.cross(vector2);
280 |
281 | // If z < 0 then we must draw these in reverse order
282 | if(vector1.z < 0) {
283 | geometry.faces.push(new THREE.Face3(2, 1, 0));
284 | geometry.faces.push(new THREE.Face3(2, 3, 0));
285 | } else {
286 | geometry.faces.push(new THREE.Face3(0, 1, 2));
287 | geometry.faces.push(new THREE.Face3(0, 3, 2));
288 | }
289 |
290 |
291 | material = new THREE.MeshBasicMaterial({ color: getColor(entity, data) });
292 |
293 | mesh = new THREE.Mesh(geometry, material);
294 | scene.add(mesh);
295 | }
296 |
297 | function drawText(entity, data) {
298 | var geometry, material, text;
299 |
300 | geometry = new THREE.TextGeometry(entity.text, { height: 0, size: entity.textHeight || 12 });
301 |
302 | material = new THREE.MeshBasicMaterial({ color: getColor(entity, data) });
303 |
304 | text = new THREE.Mesh(geometry, material);
305 | text.position.x = entity.startPoint.x;
306 | text.position.y = entity.startPoint.y;
307 | text.position.z = entity.startPoint.z;
308 |
309 | scene.add(text);
310 | }
311 |
312 | function drawPoint(entity, data) {
313 | var geometry, material, point;
314 |
315 | geometry = new THREE.Geometry();
316 |
317 | geometry.vertices.push(new THREE.Vector3(entity.position.x, entity.position.y, entity.position.z));
318 |
319 | // TODO: could be more efficient. PointCloud per layer?
320 |
321 | var numPoints = 1;
322 |
323 | var color = getColor(entity, data);
324 | var colors = new Float32Array( numPoints*3 );
325 | colors[0] = color.r;
326 | colors[1] = color.g;
327 | colors[2] = color.b;
328 |
329 | geometry.colors = colors;
330 | geometry.computeBoundingBox();
331 |
332 | material = new THREE.PointCloudMaterial( { size: 0.05, vertexColors: THREE.VertexColors } );
333 | point = new THREE.PointCloud(geometry, material);
334 | scene.add(point);
335 | }
336 |
337 | function getColor(entity, data) {
338 | var color = entity.color || data.tables.layers[entity.layer].color;
339 | if(color === 0xffffff) {
340 | color = 0x000000;
341 | }
342 | return color;
343 | }
344 |
345 | function createLineTypeShaders(data) {
346 | var ltype, type;
347 | var ltypes = data.tables.lineTypes;
348 |
349 | for(type in ltypes) {
350 | ltype = ltypes[type];
351 | if(!ltype.pattern) continue;
352 | ltype.material = createDashedLineShader(ltype.pattern);
353 | }
354 | }
355 |
356 | function createDashedLineShader(pattern) {
357 | var i,
358 | dashedLineShader = {},
359 | totalLength = 0.0;
360 |
361 | for(i = 0; i < pattern.length; i++) {
362 | totalLength += Math.abs(pattern[i]);
363 | }
364 |
365 | dashedLineShader.uniforms = THREE.UniformsUtils.merge([
366 |
367 | THREE.UniformsLib[ 'common' ],
368 | THREE.UniformsLib[ 'fog' ],
369 |
370 | {
371 | 'pattern': { type: 'fv1', value: pattern },
372 | 'patternLength': { type: 'f', value: totalLength }
373 | }
374 |
375 | ]);
376 |
377 | dashedLineShader.vertexShader = [
378 | 'attribute float lineDistance;',
379 |
380 | 'varying float vLineDistance;',
381 |
382 | THREE.ShaderChunk[ 'color_pars_vertex' ],
383 |
384 | 'void main() {',
385 |
386 | THREE.ShaderChunk[ 'color_vertex' ],
387 |
388 | 'vLineDistance = lineDistance;',
389 |
390 | 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
391 |
392 | '}'
393 | ].join('\n');
394 |
395 | dashedLineShader.fragmentShader = [
396 | 'uniform vec3 diffuse;',
397 | 'uniform float opacity;',
398 |
399 | 'uniform float pattern[' + pattern.length + '];',
400 | 'uniform float patternLength;',
401 |
402 | 'varying float vLineDistance;',
403 |
404 | THREE.ShaderChunk[ 'color_pars_fragment' ],
405 | THREE.ShaderChunk[ 'fog_pars_fragment' ],
406 |
407 | 'void main() {',
408 |
409 | 'float pos = mod(vLineDistance, patternLength);',
410 |
411 | 'for ( int i = 0; i < ' + pattern.length + '; i++ ) {',
412 | 'pos = pos - abs(pattern[i]);',
413 | 'if( pos < 0.0 ) {',
414 | 'if( pattern[i] > 0.0 ) {',
415 | 'gl_FragColor = vec4(1.0, 0.0, 0.0, opacity );',
416 | 'break;',
417 | '}',
418 | 'discard;',
419 | '}',
420 |
421 | '}',
422 |
423 | THREE.ShaderChunk[ 'color_fragment' ],
424 | THREE.ShaderChunk[ 'fog_fragment' ],
425 |
426 | '}'
427 | ].join('\n');
428 |
429 | return dashedLineShader;
430 | }
431 |
432 | }
--------------------------------------------------------------------------------
/i/dxf/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/i/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/favicon.ico
--------------------------------------------------------------------------------
/i/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/i/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/i/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/i/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/i/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/i/gcode-viewer/GridRect._OLD:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | AUTHOR: Mr Doob
4 |
5 | */
6 |
7 | // Code courtesy of https://github.com/mrdoob/three.js/issues/6549
8 |
9 |
10 | THREE.GridHelperRect = function ( sizeX, stepX, sizeZ, stepZ ) {
11 |
12 | var x = Math.round( sizeX / stepX );
13 | var y = Math.round( sizeZ / stepZ );
14 |
15 | sizeX = x * stepX;
16 | sizeZ = y * stepZ;
17 |
18 | // console.log( "Grid sizeX: " + sizeX * 2 );
19 | //console.log( "Grid sizeZ: " + sizeZ * 2 );
20 |
21 | var geometry = new THREE.Geometry();
22 | var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
23 |
24 | this.color1 = new THREE.Color( 0x444444 );
25 | this.color2 = new THREE.Color( 0x888888 );
26 |
27 | for ( var i = - 1 * sizeX; i <= sizeX; i += stepX ) {
28 |
29 | geometry.vertices.push(
30 | new THREE.Vector3( i, 0, - 1 * sizeZ ), //x Y z
31 | new THREE.Vector3( i, 0, sizeZ ) //x Y z
32 | );
33 |
34 | var color = i === 0 ? this.color1 : this.color2;
35 |
36 | geometry.colors.push( color, color, color, color );
37 |
38 | }
39 |
40 | for ( var i = - 1 * sizeZ; i <= sizeZ; i += stepZ ) {
41 |
42 | geometry.vertices.push(
43 | new THREE.Vector3( - 1 * sizeX, 0, i ), //x Y z
44 | new THREE.Vector3( sizeX, 0, i ) //x Y z
45 | );
46 |
47 | var color = i === 0 ? this.color1 : this.color2;
48 |
49 | geometry.colors.push( color, color, color, color );
50 |
51 | }
52 |
53 | THREE.Line.call( this, geometry, material, THREE.LinePieces );
54 |
55 | };
56 |
57 | THREE.GridHelperRect.prototype = Object.create( THREE.Line.prototype );
58 | THREE.GridHelperRect.prototype.constructor = THREE.GridHelper;
59 |
60 | THREE.GridHelperRect.prototype.setColors = function( colorCenterLine, colorGrid ) {
61 |
62 | this.color1.set( colorCenterLine );
63 | this.color2.set( colorGrid );
64 |
65 | this.geometry.colorsNeedUpdate = true;
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/i/gcode-viewer/renderer.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | AUTHOR: John Lauer
4 |
5 | */
6 |
7 | function createScene(element) {
8 |
9 |
10 | var canvas = !! window.CanvasRenderingContext2D;
11 | var webgl = ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )();
12 |
13 | if (webgl) {
14 | $('#console').append('
Continuing with best Laserweb 3D Viewer Experience
');
15 | $('#console').scrollTop($("#console")[0].scrollHeight - $("#console").height());
16 |
17 | renderer = new THREE.WebGLRenderer({
18 | autoClearColor: true
19 | });
20 |
21 | } else if (canvas) {
22 |
23 | $('#console').append('
Laserweb may not work on this computer! Try another computer with WebGL support
Try the following:
Sorry! :(
');
24 | $('#console').scrollTop($("#console")[0].scrollHeight - $("#console").height());
25 |
26 | $( "#noWebGL" ).append('No WebGL Support found!
Laserweb may not work on this computer!
Try another computer with WebGL support
3D Render completed in '+elapsed+' ms
'); 187 | $('#console').scrollTop($("#console")[0].scrollHeight - $("#console").height()); 188 | 189 | // Pretty Gcode Viewer 190 | //$("#gcodelinestbody").empty(); 191 | 192 | // rest of gcodelinestbody is written by the doChunk on gcode-parser 193 | 194 | } 195 | 196 | 197 | function makeSprite(scene, rendererType, vals) { 198 | var canvas = document.createElement('canvas'), 199 | context = canvas.getContext('2d'), 200 | metrics = null, 201 | textHeight = 100, 202 | textWidth = 0, 203 | actualFontSize = 10; 204 | var txt = vals.text; 205 | if (vals.size) actualFontSize = vals.size; 206 | 207 | context.font = "normal " + textHeight + "px Arial"; 208 | metrics = context.measureText(txt); 209 | var textWidth = metrics.width; 210 | 211 | canvas.width = textWidth; 212 | canvas.height = textHeight; 213 | context.font = "normal " + textHeight + "px Arial"; 214 | context.textAlign = "center"; 215 | context.textBaseline = "middle"; 216 | //context.fillStyle = "#ff0000"; 217 | context.fillStyle = vals.color; 218 | 219 | context.fillText(txt, textWidth / 2, textHeight / 2); 220 | 221 | var texture = new THREE.Texture(canvas); 222 | texture.needsUpdate = true; 223 | texture.minFilter = THREE.LinearFilter; 224 | 225 | var material = new THREE.SpriteMaterial({ 226 | map: texture, 227 | useScreenCoordinates: false, 228 | transparent: true, 229 | opacity: 0.6 230 | }); 231 | material.transparent = true; 232 | //var textObject = new THREE.Sprite(material); 233 | var textObject = new THREE.Object3D(); 234 | textObject.position.x = vals.x; 235 | textObject.position.y = vals.y; 236 | textObject.position.z = vals.z; 237 | var sprite = new THREE.Sprite(material); 238 | textObject.textHeight = actualFontSize; 239 | textObject.textWidth = (textWidth / textHeight) * textObject.textHeight; 240 | if (rendererType == "2d") { 241 | sprite.scale.set(textObject.textWidth / textWidth, textObject.textHeight / textHeight, 1); 242 | } else { 243 | sprite.scale.set(textWidth / textHeight * actualFontSize, actualFontSize, 1); 244 | } 245 | 246 | textObject.add(sprite); 247 | 248 | //scene.add(textObject); 249 | return textObject; 250 | } 251 | -------------------------------------------------------------------------------- /i/js/bootstrap-notify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * bootstrap-notify.js v1.0 3 | * -- 4 | * Copyright 2012 Goodybag, Inc. 5 | * -- 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | (function ($) { 20 | var Notification = function (element, options) { 21 | // Element collection 22 | this.$element = $(element); 23 | this.$note = $(''); 24 | this.options = $.extend(true, {}, $.fn.notify.defaults, options); 25 | 26 | // Setup from options 27 | if(this.options.transition) { 28 | if(this.options.transition == 'fade') 29 | this.$note.addClass('in').addClass(this.options.transition); 30 | else 31 | this.$note.addClass(this.options.transition); 32 | } else 33 | this.$note.addClass('fade').addClass('in'); 34 | 35 | if(this.options.type) 36 | this.$note.addClass('alert-' + this.options.type); 37 | else 38 | this.$note.addClass('alert-success'); 39 | 40 | if(!this.options.message && this.$element.data("message") !== '') // dom text 41 | this.$note.html(this.$element.data("message")); 42 | else 43 | if(typeof this.options.message === 'object') { 44 | if(this.options.message.html) 45 | this.$note.html(this.options.message.html); 46 | else if(this.options.message.text) 47 | this.$note.text(this.options.message.text); 48 | } else 49 | this.$note.html(this.options.message); 50 | 51 | if(this.options.closable) { 52 | var link = $('×'); 53 | $(link).on('click', $.proxy(onClose, this)); 54 | this.$note.prepend(link); 55 | } 56 | 57 | return this; 58 | }; 59 | 60 | var onClose = function() { 61 | this.options.onClose(); 62 | $(this.$note).remove(); 63 | this.options.onClosed(); 64 | return false; 65 | }; 66 | 67 | Notification.prototype.show = function () { 68 | if(this.options.fadeOut.enabled) 69 | this.$note.delay(this.options.fadeOut.delay || 3000).fadeOut('slow', $.proxy(onClose, this)); 70 | 71 | this.$element.append(this.$note); 72 | this.$note.alert(); 73 | }; 74 | 75 | Notification.prototype.hide = function () { 76 | if(this.options.fadeOut.enabled) 77 | this.$note.delay(this.options.fadeOut.delay || 3000).fadeOut('slow', $.proxy(onClose, this)); 78 | else onClose.call(this); 79 | }; 80 | 81 | $.fn.notify = function (options) { 82 | return new Notification(this, options); 83 | }; 84 | 85 | $.fn.notify.defaults = { 86 | type: 'success', 87 | closable: true, 88 | transition: 'fade', 89 | fadeOut: { 90 | enabled: true, 91 | delay: 3000 92 | }, 93 | message: null, 94 | onClose: function () {}, 95 | onClosed: function () {} 96 | } 97 | })(window.jQuery); 98 | -------------------------------------------------------------------------------- /i/js/jog.js: -------------------------------------------------------------------------------- 1 | 2 | function initJog() { 3 | 4 | $('#xp').on('click', function() { 5 | var dist = $('#jogstp').val() 6 | console.log('Jog Distance', dist); 7 | sendGcode('G91\nG0 X'+ +'\nG90') { 8 | }; 9 | 10 | 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /i/openjscad/LaserWebapps.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | AUTHOR: Peter van der Walt 4 | 5 | */ 6 | // Show all exceptions to the user: 7 | OpenJsCad.AlertUserOfUncaughtExceptions(); 8 | 9 | function updateSolid() 10 | { 11 | gProcessor.setJsCad(document.getElementById('code').value); 12 | } 13 | 14 | function loadGeargen() 15 | { 16 | gProcessor = new OpenJsCad.Processor(document.getElementById("viewer")); 17 | getProg('openjscad_files/gear.jscad'); 18 | $('#JSHelp').empty(); 19 | $( "#JSHelp" ).append("Try Negative and Zero Teeth Count too: (works best on Gear 1)![]() | ![]() | ![]() |
Tooth count < 0 | Tooth count = 0 | Tooth count > 0 |
Raster completed in {0}ms
'.format(elapsed)) 349 | .scrollTop($("#console")[0].scrollHeight - $("#console").height()); 350 | 351 | if (this.config.completed) { 352 | this.config.completed(); 353 | } 354 | }; 355 | 356 | 357 | this.RasterNow = function(config) { 358 | console.time("Process Raster"); 359 | 360 | var rasterizer = new Rasterizer(config); 361 | rasterizer.init(); 362 | }; 363 | -------------------------------------------------------------------------------- /i/raster/openbuilds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/raster/openbuilds.png -------------------------------------------------------------------------------- /i/raster/random grayscale pic from google images.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/raster/random grayscale pic from google images.jpg -------------------------------------------------------------------------------- /i/raster/tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaserWeb/deprecated-LaserWeb1/6baa9df3621b51ce57b71a10488f68813e601f2a/i/raster/tiny.png -------------------------------------------------------------------------------- /i/svg/js/SVGRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.SVGRenderer = function () { 6 | 7 | console.log( 'THREE.SVGRenderer', THREE.REVISION ); 8 | 9 | var _this = this, 10 | _renderData, _elements, _lights, 11 | _projector = new THREE.Projector(), 12 | _svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), 13 | _svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf, 14 | 15 | _v1, _v2, _v3, _v4, 16 | 17 | _clipBox = new THREE.Box2(), 18 | _elemBox = new THREE.Box2(), 19 | 20 | _color = new THREE.Color(), 21 | _diffuseColor = new THREE.Color(), 22 | _ambientLight = new THREE.Color(), 23 | _directionalLights = new THREE.Color(), 24 | _pointLights = new THREE.Color(), 25 | 26 | _w, // z-buffer to w-buffer 27 | _vector3 = new THREE.Vector3(), // Needed for PointLight 28 | 29 | _svgPathPool = [], _svgLinePool = [], _svgRectPool = [], 30 | _svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0, 31 | _quality = 1; 32 | 33 | this.domElement = _svg; 34 | 35 | this.autoClear = true; 36 | this.sortObjects = true; 37 | this.sortElements = true; 38 | 39 | this.info = { 40 | 41 | render: { 42 | 43 | vertices: 0, 44 | faces: 0 45 | 46 | } 47 | 48 | } 49 | 50 | this.setQuality = function( quality ) { 51 | 52 | switch(quality) { 53 | 54 | case "high": _quality = 1; break; 55 | case "low": _quality = 0; break; 56 | 57 | } 58 | 59 | }; 60 | 61 | // WebGLRenderer compatibility 62 | 63 | this.supportsVertexTextures = function () {}; 64 | this.setFaceCulling = function () {}; 65 | 66 | this.setClearColor = function ( color, alpha ) { 67 | 68 | // TODO 69 | 70 | }; 71 | 72 | this.setSize = function( width, height ) { 73 | 74 | _svgWidth = width; _svgHeight = height; 75 | _svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2; 76 | 77 | _svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight ); 78 | _svg.setAttribute( 'width', _svgWidth ); 79 | _svg.setAttribute( 'height', _svgHeight ); 80 | 81 | _clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf ); 82 | _clipBox.max.set( _svgWidthHalf, _svgHeightHalf ); 83 | 84 | }; 85 | 86 | this.clear = function () { 87 | 88 | _pathCount = 0; 89 | _lineCount = 0; 90 | _rectCount = 0; 91 | 92 | while ( _svg.childNodes.length > 0 ) { 93 | 94 | _svg.removeChild( _svg.childNodes[ 0 ] ); 95 | 96 | } 97 | 98 | }; 99 | 100 | this.render = function ( scene, camera ) { 101 | 102 | if ( camera instanceof THREE.Camera === false ) { 103 | 104 | console.error( 'THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.' ); 105 | return; 106 | 107 | } 108 | 109 | if ( this.autoClear === true ) this.clear(); 110 | 111 | _this.info.render.vertices = 0; 112 | _this.info.render.faces = 0; 113 | 114 | _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); 115 | _elements = _renderData.elements; 116 | _lights = _renderData.lights; 117 | 118 | calculateLights( _lights ); 119 | 120 | for ( var e = 0, el = _elements.length; e < el; e ++ ) { 121 | 122 | var element = _elements[ e ]; 123 | var material = element.material; 124 | 125 | if ( material === undefined || material.visible === false ) continue; 126 | 127 | _elemBox.makeEmpty(); 128 | 129 | if ( element instanceof THREE.RenderableSprite ) { 130 | 131 | _v1 = element; 132 | _v1.x *= _svgWidthHalf; _v1.y *= - _svgHeightHalf; 133 | 134 | renderSprite( _v1, element, material ); 135 | 136 | } else if ( element instanceof THREE.RenderableLine ) { 137 | 138 | _v1 = element.v1; _v2 = element.v2; 139 | 140 | _v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf; 141 | _v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf; 142 | 143 | _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] ); 144 | 145 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { 146 | 147 | renderLine( _v1, _v2, element, material ); 148 | 149 | } 150 | 151 | } else if ( element instanceof THREE.RenderableFace ) { 152 | 153 | _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; 154 | 155 | if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; 156 | if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; 157 | if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; 158 | 159 | _v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf; 160 | _v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf; 161 | _v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf; 162 | 163 | _elemBox.setFromPoints( [ 164 | _v1.positionScreen, 165 | _v2.positionScreen, 166 | _v3.positionScreen 167 | ] ); 168 | 169 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { 170 | 171 | renderFace3( _v1, _v2, _v3, element, material ); 172 | 173 | } 174 | 175 | } 176 | 177 | } 178 | 179 | }; 180 | 181 | function calculateLights( lights ) { 182 | 183 | _ambientLight.setRGB( 0, 0, 0 ); 184 | _directionalLights.setRGB( 0, 0, 0 ); 185 | _pointLights.setRGB( 0, 0, 0 ); 186 | 187 | for ( var l = 0, ll = lights.length; l < ll; l++ ) { 188 | 189 | var light = lights[ l ]; 190 | var lightColor = light.color; 191 | 192 | if ( light instanceof THREE.AmbientLight ) { 193 | 194 | _ambientLight.r += lightColor.r; 195 | _ambientLight.g += lightColor.g; 196 | _ambientLight.b += lightColor.b; 197 | 198 | } else if ( light instanceof THREE.DirectionalLight ) { 199 | 200 | _directionalLights.r += lightColor.r; 201 | _directionalLights.g += lightColor.g; 202 | _directionalLights.b += lightColor.b; 203 | 204 | } else if ( light instanceof THREE.PointLight ) { 205 | 206 | _pointLights.r += lightColor.r; 207 | _pointLights.g += lightColor.g; 208 | _pointLights.b += lightColor.b; 209 | 210 | } 211 | 212 | } 213 | 214 | } 215 | 216 | function calculateLight( lights, position, normal, color ) { 217 | 218 | for ( var l = 0, ll = lights.length; l < ll; l ++ ) { 219 | 220 | var light = lights[ l ]; 221 | var lightColor = light.color; 222 | 223 | if ( light instanceof THREE.DirectionalLight ) { 224 | 225 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); 226 | 227 | var amount = normal.dot( lightPosition ); 228 | 229 | if ( amount <= 0 ) continue; 230 | 231 | amount *= light.intensity; 232 | 233 | color.r += lightColor.r * amount; 234 | color.g += lightColor.g * amount; 235 | color.b += lightColor.b * amount; 236 | 237 | } else if ( light instanceof THREE.PointLight ) { 238 | 239 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); 240 | 241 | var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); 242 | 243 | if ( amount <= 0 ) continue; 244 | 245 | amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); 246 | 247 | if ( amount == 0 ) continue; 248 | 249 | amount *= light.intensity; 250 | 251 | color.r += lightColor.r * amount; 252 | color.g += lightColor.g * amount; 253 | color.b += lightColor.b * amount; 254 | 255 | } 256 | 257 | } 258 | 259 | } 260 | 261 | function renderSprite( v1, element, material ) { 262 | 263 | var scaleX = element.scale.x * _svgWidthHalf; 264 | var scaleY = element.scale.y * _svgHeightHalf; 265 | 266 | _svgNode = getRectNode( _rectCount ++ ); 267 | 268 | _svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) ); 269 | _svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) ); 270 | _svgNode.setAttribute( 'width', scaleX ); 271 | _svgNode.setAttribute( 'height', scaleY ); 272 | 273 | if ( material instanceof THREE.SpriteMaterial ) { 274 | 275 | _svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() ); 276 | 277 | } 278 | 279 | _svg.appendChild( _svgNode ); 280 | 281 | } 282 | 283 | function renderLine( v1, v2, element, material ) { 284 | 285 | _svgNode = getLineNode( _lineCount ++ ); 286 | 287 | _svgNode.setAttribute( 'x1', v1.positionScreen.x ); 288 | _svgNode.setAttribute( 'y1', v1.positionScreen.y ); 289 | _svgNode.setAttribute( 'x2', v2.positionScreen.x ); 290 | _svgNode.setAttribute( 'y2', v2.positionScreen.y ); 291 | 292 | if ( material instanceof THREE.LineBasicMaterial ) { 293 | 294 | _svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin ); 295 | 296 | _svg.appendChild( _svgNode ); 297 | 298 | } 299 | 300 | } 301 | 302 | function renderFace3( v1, v2, v3, element, material ) { 303 | 304 | _this.info.render.vertices += 3; 305 | _this.info.render.faces ++; 306 | 307 | _svgNode = getPathNode( _pathCount ++ ); 308 | _svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' ); 309 | 310 | if ( material instanceof THREE.MeshBasicMaterial ) { 311 | 312 | _color.copy( material.color ); 313 | 314 | if ( material.vertexColors === THREE.FaceColors ) { 315 | 316 | _color.multiply( element.color ); 317 | 318 | } 319 | 320 | } else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { 321 | 322 | _diffuseColor.copy( material.color ); 323 | 324 | if ( material.vertexColors === THREE.FaceColors ) { 325 | 326 | _diffuseColor.multiply( element.color ); 327 | 328 | } 329 | 330 | _color.copy( _ambientLight ); 331 | 332 | calculateLight( _lights, element.centroidModel, element.normalModel, _color ); 333 | 334 | _color.multiply( _diffuseColor ).add( material.emissive ); 335 | 336 | } else if ( material instanceof THREE.MeshDepthMaterial ) { 337 | 338 | _w = 1 - ( material.__2near / (material.__farPlusNear - element.z * material.__farMinusNear) ); 339 | _color.setRGB( _w, _w, _w ); 340 | 341 | } else if ( material instanceof THREE.MeshNormalMaterial ) { 342 | 343 | var normal = element.normalModelView; 344 | 345 | _color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); 346 | 347 | } 348 | 349 | if ( material.wireframe ) { 350 | 351 | _svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin ); 352 | 353 | } else { 354 | 355 | _svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity ); 356 | 357 | } 358 | 359 | _svg.appendChild( _svgNode ); 360 | 361 | } 362 | 363 | function getLineNode( id ) { 364 | 365 | if ( _svgLinePool[ id ] == null ) { 366 | 367 | _svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' ); 368 | 369 | if ( _quality == 0 ) { 370 | 371 | _svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed 372 | 373 | } 374 | 375 | return _svgLinePool[ id ]; 376 | 377 | } 378 | 379 | return _svgLinePool[ id ]; 380 | 381 | } 382 | 383 | function getPathNode( id ) { 384 | 385 | if ( _svgPathPool[ id ] == null ) { 386 | 387 | _svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' ); 388 | 389 | if ( _quality == 0 ) { 390 | 391 | _svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed 392 | 393 | } 394 | 395 | return _svgPathPool[ id ]; 396 | 397 | } 398 | 399 | return _svgPathPool[ id ]; 400 | 401 | } 402 | 403 | function getRectNode( id ) { 404 | 405 | if ( _svgRectPool[ id ] == null ) { 406 | 407 | _svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' ); 408 | 409 | if ( _quality == 0 ) { 410 | 411 | _svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed 412 | 413 | } 414 | 415 | return _svgRectPool[ id ]; 416 | 417 | } 418 | 419 | return _svgRectPool[ id ]; 420 | 421 | } 422 | 423 | }; 424 | -------------------------------------------------------------------------------- /i/svg/js/array.find.js: -------------------------------------------------------------------------------- 1 | // Author Jordan Sitkin https://github.com/dustMason/Machine-Art 2 | 3 | // if (Array.prototype.find) return; 4 | 5 | var find = function(predicate) { 6 | var list = Object(this); 7 | var length = list.length >>> 0; // ES.ToUint32; 8 | if (length === 0) return undefined; 9 | if (typeof predicate !== 'function') { 10 | throw new TypeError('Array#find: predicate must be a function'); 11 | } 12 | var thisArg = arguments[1]; 13 | for (var i = 0, value; i < length && i in list; i++) { 14 | value = list[i]; 15 | if (predicate.call(thisArg, value, i, list)) return value; 16 | } 17 | return undefined; 18 | }; 19 | 20 | if (Object.defineProperty) { 21 | try { 22 | Object.defineProperty(Array.prototype, 'find', { 23 | value: find, configurable: true, enumerable: false, writable: true 24 | }); 25 | } catch(e) {} 26 | } 27 | 28 | if (!Array.prototype.find) { 29 | Array.prototype.find = find; 30 | } 31 | -------------------------------------------------------------------------------- /i/svg/js/main.js: -------------------------------------------------------------------------------- 1 | // Author Jordan Sitkin https://github.com/dustMason/Machine-Art 2 | 3 | // not used directly in laserweb, but this is where I ported the code from (peter van der walt) 4 | 5 | console.log('In svg main'); 6 | 7 | var artworks = [ 8 | './art/homer.svg', 9 | './art/phone.svg' 10 | ]; 11 | 12 | var $svgElm = $("#svg"), 13 | $menu = $("#menu-art"), 14 | generateButton = document.getElementById("btn-generate"), 15 | copyButton = document.getElementById("btn-copy"), 16 | gcodeText = document.getElementById("gcode"); 17 | 18 | artworks.forEach(function(artwork) { 19 | $menu.append($("")); 20 | }); 21 | 22 | $menu.change(function(e) { 23 | e.preventDefault(); 24 | var artwork = $(this).val(); 25 | $svgElm.html(""); 26 | $("#work-area").find("canvas").remove(); 27 | 28 | generateButton.onclick = function(e) { 29 | e.preventDefault(); 30 | var XMLS = new XMLSerializer(); 31 | var svgfile = XMLS.serializeToString($svgElm.get(0)); 32 | 33 | gcodeText.innerHTML = svg2gcode(svgfile, { 34 | feedRate: 1500, 35 | seekRate: 10000, 36 | bitWidth: 1, 37 | scale: 0.75 38 | }); 39 | }; 40 | 41 | if (artwork.indexOf("js") > 0) { 42 | $.getScript(artwork); 43 | } else if (artwork.indexOf("svg") > 0) { 44 | $.get(artwork, null, function(data) { 45 | var svgNode = $("svg", data); 46 | var docNode = document.adoptNode(svgNode[0]); 47 | $svgElm.html(docNode); 48 | }, 'xml'); 49 | } 50 | }).change(); 51 | -------------------------------------------------------------------------------- /i/svg/js/svg2gcode.js: -------------------------------------------------------------------------------- 1 | // Author Jordan Sitkin https://github.com/dustMason/Machine-Art 2 | 3 | globalpaths = {}; 4 | var hexvalue = []; 5 | var svgcolors = []; 6 | var svgcolorsoptions = []; 7 | var intensity = 100; 8 | var svglaserpwr = 0; 9 | 10 | // Helper function 11 | Array.prototype.unique = function() 12 | { 13 | var n = {},r=[]; 14 | for(var i = 0; i < this.length; i++) 15 | { 16 | if (!n[this[i]]) 17 | { 18 | n[this[i]] = true; 19 | r.push(this[i]); 20 | } 21 | } 22 | return r; 23 | } 24 | 25 | // Helper function 26 | RGBToHex = function(r,g,b){ 27 | var bin = r << 16 | g << 8 | b; 28 | return (function(h){ 29 | return new Array(7-h.length).join("0")+h 30 | })(bin.toString(16).toUpperCase()) 31 | } 32 | 33 | function pullcolors(svg) { 34 | var hexvalue = []; 35 | var svgcolors = []; 36 | var svgcolorsoptions = []; 37 | svg = svg.replace(/^[\n\r \t]/gm, ''); 38 | var paths = SVGReader.preview(svg, {}).allcolors, 39 | gcode, 40 | path, 41 | idx = paths.length, 42 | minX = Infinity, 43 | maxX = -Infinity, 44 | minY = Infinity, 45 | maxY = -Infinity; 46 | 47 | //var svgcolorsoptions = []; 48 | 49 | for (i = 0; i < paths.length; i++) { 50 | //onsole.log('PATH: '+i+', FILL: '+paths[i].node.fill+', STROKE: '+paths[i].node.stroke+', COLOR: '+paths[i].node.color+', OPACTITY: '+paths[i].node.opacity) 51 | //if (paths[i].node.fill) { svgcolors.push(paths[i].node.fill) }; 52 | if (paths[i].node.stroke) { svgcolors.push(paths[i].node.stroke) }; 53 | //if (paths[i].node.color) { svgcolors.push(paths[i].node.color) }; 54 | } 55 | //svgcolorsoptions = svgcolors.unique(); 56 | //for (c = 0; c < svgcolorsoptions.length; c++) { 57 | // var r = svgcolorsoptions[c][0]; 58 | // var g = svgcolorsoptions[c][1]; 59 | // var b = svgcolorsoptions[c][2]; 60 | // hexvalue.push('#'+RGBToHex(r, g, b)); 61 | //}; 62 | //console.log(svgcolors); 63 | return svgcolors; 64 | }; 65 | 66 | 67 | function svg2gcode(svg, settings) { 68 | // clean off any preceding whitespace 69 | svg = svg.replace(/^[\n\r \t]/gm, ''); 70 | settings = settings || {}; 71 | settings.scale = settings.scale || -1; 72 | settings.cutZ = settings.cutZ || 0; // cut z 73 | settings.safeZ = settings.safeZ || 90; // safe z 74 | settings.feedRate = settings.feedRate || 1400; 75 | settings.seekRate = settings.seekRate || 1100; 76 | settings.bitWidth = settings.bitWidth || 1; // in mm 77 | settings.verticalSlices = settings.verticalSlices || 1; 78 | settings.horizontalSlices = settings.horizontalSlices || 1; 79 | settings.offsetX = settings.offsetX || 0; 80 | settings.offsetY = settings.offsetY || 0; 81 | settings.laserpwr = settings.laserpwr || 100; 82 | settings.gcodePreamble = settings.gcodePreamble || [ 83 | 'G90', 84 | 'G21', 85 | 'G0 Z' + settings.safeZ 86 | 87 | ]; 88 | settings.gcodePostamble = settings.gcodePostamble || []; 89 | 90 | console.log('SVG Laser Power: '+settings.laserpwr+'%'); 91 | var svglaserpwr = parseInt(settings.laserpwr, 10) 92 | 93 | var scale = function(val) { 94 | return val * settings.scale; 95 | }; 96 | 97 | var paths = SVGReader.parse(svg, {}).allcolors, 98 | gcode, 99 | path, 100 | idx = paths.length, 101 | minX = Infinity, 102 | maxX = -Infinity, 103 | minY = Infinity, 104 | maxY = -Infinity; 105 | 106 | //console.log(paths); 107 | globalpaths = paths; 108 | 109 | //for (i = 0; i < paths.length; i++) { 110 | // console.log('PATH: '+i+', FILL: '+paths[i].node.fill+', STROKE: '+paths[i].node.stroke+', COLOR: '+paths[i].node.color+', OPACTITY: '+paths[i].node.opacity) 111 | //} 112 | 113 | while(idx--) { 114 | var subidx = paths[idx].length; 115 | var bounds = { x : Infinity , y : Infinity, x2 : -Infinity, y2: -Infinity, area : 0}; 116 | 117 | // find lower and upper bounds 118 | while(subidx--) { 119 | if (paths[idx][subidx].x < bounds.x) 120 | bounds.x = paths[idx][subidx].x; 121 | if (paths[idx][subidx].x < minX) 122 | minX = paths[idx][subidx].x; 123 | 124 | if (paths[idx][subidx].y < bounds.y) 125 | bounds.y = paths[idx][subidx].y; 126 | if (paths[idx][subidx].y < minY) 127 | minY = paths[idx][subidx].y; 128 | 129 | if (paths[idx][subidx].x > bounds.x2) 130 | bounds.x2 = paths[idx][subidx].x; 131 | if (paths[idx][subidx].x > maxX) 132 | maxX = paths[idx][subidx].x; 133 | 134 | if (paths[idx][subidx].y > bounds.y2) 135 | bounds.y2 = paths[idx][subidx].y; 136 | if (paths[idx][subidx].y > maxY) 137 | maxY = paths[idx][subidx].y; 138 | } 139 | 140 | // calculate area 141 | bounds.area = (1 + bounds.x2 - bounds.x) * (1 + bounds.y2-bounds.y); 142 | paths[idx].bounds = bounds; 143 | } 144 | 145 | if (settings.verticalSlices > 1 || settings.horizontalSlices > 1) { 146 | // break the job up into slices, work in small chunks 147 | var columnWidth = totalWidth / settings.verticalSlices; 148 | var rowHeight = totalHeight / settings.horizontalSlices; 149 | var sortedPaths = []; 150 | // create empty data structure 151 | for (i = 0; i < settings.horizontalSlices; i++) { 152 | sortedPaths[i] = []; 153 | for (j = 0; j < settings.verticalSlices; j++) { 154 | sortedPaths[i][j] = []; 155 | } 156 | } 157 | // populate it with paths 158 | paths.forEach(function(path) { 159 | var rowIndex = Math.floor((path[0].y + (totalHeight/2)) / rowHeight); 160 | var colIndex = Math.floor((path[0].x + (totalWidth/2)) / columnWidth); 161 | // console.log(rowIndex-2, colIndex-2); 162 | if (rowIndex < settings.verticalSlices && colIndex < settings.horizontalSlices) { 163 | sortedPaths[rowIndex][colIndex].push(path); 164 | } else { 165 | console.log("warning: skipped path"); 166 | } 167 | }); 168 | // concatenate all the paths together 169 | paths = sortedPaths.map(function(row, i) { 170 | if ((i % 2) == 1) row.reverse(); 171 | return [].concat.apply([], row); 172 | }); 173 | paths = [].concat.apply([], paths); 174 | } 175 | 176 | gcode = settings.gcodePreamble.slice(0); 177 | 178 | if (firmware.indexOf('Lasaur') == 0) { 179 | gcode.push('M80'); // Air Assist on 180 | }; 181 | 182 | // Firmware Specific Gcode Output 183 | if (firmware.indexOf('Grbl') == 0) { 184 | intensity = svglaserpwr.map(0, 100, 0, 255); 185 | //console.log('Mapping Intensity range for Grbl S0-S255'); 186 | intensity = intensity.toFixed(0); 187 | } else if (firmware.indexOf('Smooth') == 0) { 188 | intensity = svglaserpwr.map(0, 100, 0, 1); 189 | //console.log('Mapping Intensity range for Smoothieware S0-S1'); 190 | intensity = intensity.toFixed(2); 191 | } else if (firmware.indexOf('Lasaur') == 0) { 192 | intensity = svglaserpwr.map(0, 100, 0, 255); 193 | //console.log('Mapping Intensity range for Smoothieware S0-S1'); 194 | intensity = intensity.toFixed(0); 195 | } else { 196 | intensity = svglaserpwr.map(0, 100, 0, 100); 197 | //console.log('Mapping Intensity range for S0-S100'); 198 | intensity = intensity.toFixed(0); 199 | } 200 | 201 | 202 | for (var pathIdx = 0, pathLength = paths.length; pathIdx < pathLength; pathIdx++) { 203 | path = paths[pathIdx]; 204 | 205 | // seek to index 0 206 | gcode.push(['G0', 207 | 'X' + scale(path[0].x + settings.offsetX), 208 | 'Y' + scale(-path[0].y + settings.offsetY), 209 | 'F' + settings.seekRate, 210 | '; Seek to 0' 211 | ].join(' ')); 212 | 213 | 214 | // begin the cut by dropping the tool to the work 215 | gcode.push(['G0', 216 | 'Z' + (settings.cutZ), 217 | 'F' + settings.feedRate 218 | ].join(' ')); 219 | 220 | // keep track of the current path being cut, as we may need to reverse it 221 | // var localPath = []; 222 | for (var segmentIdx=0, segmentLength = path.length; segmentIdx