Permalink
Browse files

Merge remote-tracking branch 'refs/remotes/origin/feature/svg_export'…

… into gh-pages
  • Loading branch information...
2 parents 3cc80df + 2c44d83 commit 5333869e63623f16b3530a700044a99d6d0af674 @lautr3k committed Jul 27, 2016
Showing with 120 additions and 8 deletions.
  1. +6 −0 index.html
  2. +114 −8 js/main.js
View
@@ -184,6 +184,12 @@ <h3 class="panel-title">Slicer</h3>
<input type="radio" name="slicer-mirror" id="slicer-mirror-no" value="no" checked="checked" /> no
</div>
+ <div class="form-group">
+ <label for="slicer-image-extension">Output type</label>
+ <input type="radio" name="slicer-image-extension" id="slicer-image-extension-png" value="png" checked="checked" /> png
+ <input type="radio" name="slicer-image-extension" id="slicer-image-extension-svg" value="svg" /> svg
+ </div>
+
<hr />
<div class="form-group hidden">
View
@@ -18,6 +18,8 @@ var settings = new SLAcer.Settings({
off: 500
},
zip: true,
+ svg: false,
+ png: true,
speed: false,
speedDelay: 10, // ms
panel: {
@@ -163,10 +165,6 @@ function getSlice(layerNumber) {
shape = shapes[i];
slice = shape.clone();
- if (settings.get('slicer.mirror')) {
- slice.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
- }
-
slice.material = slice.material.clone();
slice.material.color.setHex(0xffffff);
viewer2d.addObject(slice);
@@ -185,12 +183,93 @@ function getSlice(layerNumber) {
viewer2d.screenshot(function(dataURL) {
sliceImage(dataURL);
- if (zipFolder) {
+ if (PNGExport) {
var fileName = layerNumber + '.png';
var imgData = dataURL.substr(dataURL.indexOf(',') + 1);
zipFolder.file(fileName, imgData, { base64: true });
}
});
+
+ // SVG export
+ if (SVGExport) {
+ // offset for positive coords
+ var xOffset = Math.abs(slicer.mesh.geometry.boundingBox.min.x);
+ var yOffset = Math.abs(slicer.mesh.geometry.boundingBox.min.y);
+
+ function SVGPath(actions, dir) {
+ var path = [];
+ var area = 0;
+ var a, b, c, x, y;
+
+ if (dir != 'ccw') {
+ dir = 'cw';
+ }
+
+ actions.push({ action: 'lineTo', args: actions[0].args });
+
+ for (var i = 0, il = actions.length; i < il; i++) {
+ a = actions[i];
+
+ if (i > 0) {
+ b = actions[i - 1];
+ area += a.args[0] * b.args[1];
+ area -= b.args[0] * a.args[1];
+ }
+
+ c = a.action == 'moveTo' ? 'M' : 'L';
+ x = (a.args[0] + xOffset);
+ y = (a.args[1] + yOffset);
+
+ path.push(c + x + ' ' + y);
+ }
+
+ if (dir == 'cw' && area < 0 || dir == 'ccw' && area > 0) {
+ path = path.reverse();
+ path[0] = path[0].replace(/^L/, 'M');
+ path[actions.length - 1] = path[actions.length - 1].replace(/^M/, 'L');
+ }
+
+ return path.join(' ') + ' Z ';
+ }
+
+ // svg start
+ var size = slicer.mesh.getSize();
+ var svg = '<svg version="1.1" width="' + size.x + '" height="' + size.y + '" baseProfile="full" xmlns="http://www.w3.org/2000/svg">\n';
+
+ // svg background
+ svg += '<rect x="0" y="0" width="100%" height="100%" style="fill:black; stroke:none"/>\n';
+
+ // fix coordinate system (rotate 180°)
+ svg += '<g transform="translate(0, ' + size.y + ') scale(1, -1)">\n';
+
+ // draw main paths
+ var actions;
+ for (var i = 0, il = faces.shapes.length; i < il; i++) {
+ actions = faces.shapes[i].actions;
+
+ // path start
+ svg += '<path d="';
+
+ // main paths
+ svg += SVGPath(actions, 'cw');
+
+ // holes paths
+ var holes = faces.shapes[i].holes;
+ for (var j = 0, jl = holes.length; j < jl; j++) {
+ svg += SVGPath(holes[j].actions, 'ccw');
+ }
+
+ // path end
+ svg += '" style="fill:white; stroke:none" />\n';
+ }
+
+ // svg end
+ svg += '</g>';
+ svg += '</svg>';
+
+ // add svg file to zip
+ zipFolder.file(layerNumber + '.svg', svg);
+ }
}
// -----------------------------------------------------------------------------
@@ -392,6 +471,9 @@ var $slicerLiftingHeight = $slicerBody.find('#slicer-lifting-height');
var $slicerMirrorYes = $slicerBody.find('#slicer-mirror-yes');
var $slicerMirrorNo = $slicerBody.find('#slicer-mirror-no');
+var $slicerExportPNG = $slicerBody.find('#slicer-image-extension-png');
+var $slicerExportSVG = $slicerBody.find('#slicer-image-extension-svg');
+
var $slicerSpeedYes = $slicerBody.find('#slicer-speed-yes');
var $slicerSpeedNo = $slicerBody.find('#slicer-speed-no');
var $slicerSpeedDelay = $slicerBody.find('#slicer-speed-delay');
@@ -423,6 +505,9 @@ function updateSlicerSettings() {
settings.set('slicer.mirror', $slicerMirrorYes[0].checked);
+ settings.set('slicer.png', $slicerExportPNG[0].checked);
+ settings.set('slicer.svg', $slicerExportSVG[0].checked);
+
settings.set('slicer.zip', $slicerMakeZipYes[0].checked);
settings.set('slicer.speed', $slicerSpeedYes[0].checked);
settings.set('slicer.speedDelay', $slicerSpeedDelay.val());
@@ -432,13 +517,24 @@ function updateSlicerSettings() {
updateSliderUI();
}
+function flipGeometry() {
+ loadGeometry(slicer.mesh.geometry, true);
+ getSlice($sliderInput.slider('getValue'));
+}
+
+$slicerMirrorYes.on('change', flipGeometry);
+$slicerMirrorNo.on('change', flipGeometry);
+
var sliceInterval;
var expectedSliceInterval;
var currentSliceNumber;
var slicesNumber;
var zipFile;
var zipFolder;
+var SVGExport;
+var PNGExport;
+
var layerHeight;
var zPosition;
@@ -494,13 +590,15 @@ function startSlicing() {
zipFile = null;
zipFolder = null;
+ SVGExport = null;
+ PNGExport = null;
if (settings.get('slicer.zip')) {
zipFile = new JSZip();
zipFolder = zipFile.folder('slices');
zipFile.file("README.txt", 'Generated by SLAcer.js\r\nhttp://lautr3k.github.io/SLAcer.js/\r\n');
zipFile.file("slacer.json", JSON.stringify({
- imageExtension: '.png',
+ imageExtension: settings.get('slicer.png') ? 'png' : 'svg',
imageDirectory: 'slices',
screenWidth : settings.get('screen.width'),
screenHeight : settings.get('screen.height'),
@@ -512,6 +610,8 @@ function startSlicing() {
liftingSpeed : parseInt(settings.get('slicer.lifting.speed')), // mm/min
liftingHeight : parseInt(settings.get('slicer.lifting.height')) // mm
}, null, 2));
+ SVGExport = settings.get('slicer.svg');
+ PNGExport = settings.get('slicer.png');
}
slicesNumber && slice();
@@ -543,6 +643,7 @@ $abortButton.on('click', function(e) {
endSlicing();
});
+$('#slicer-image-extension-' + (settings.get('slicer.png') ? 'png' : 'svg')).prop('checked', true);
$('#slicer-mirror-' + (settings.get('slicer.mirror') ? 'yes' : 'no')).prop('checked', true);
$('#slicer-make-zip-' + (settings.get('slicer.zip') ? 'yes' : 'no')).prop('checked', true);
$('#slicer-speed-' + (settings.get('slicer.speed') ? 'yes' : 'no')).prop('checked', true);
@@ -881,17 +982,22 @@ resizeUI();
var loader = new MeshesJS.STLLoader($main[0]); // drop target
// Load an geometry
-function loadGeometry(geometry) {
+function loadGeometry(geometry, mirror) {
try {
// remove old mesh and plane
slicer.mesh && viewer3d.removeObject(slicer.mesh);
// remove old shapes
removeShapes();
+ // flip geometry
+ if (mirror || settings.get('slicer.mirror')) {
+ geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
+ }
+
// load new mesh in slicer
slicer.loadMesh(new SLAcer.Mesh(geometry, new THREE.MeshPhongMaterial({
- color: hexToDec(settings.get('colors.mesh'))
+ color: hexToDec(settings.get('colors.mesh')), side: THREE.DoubleSide
})));
// add new mesh and render view

0 comments on commit 5333869

Please sign in to comment.