// ----------------------------------------------------------------------------- // Variables // ----------------------------------------------------------------------------- //window.localStorage.clear(); var settings = new SLAcer.Settings({ file: { panel: { collapsed: false, position : 0 } }, slicer: { layers: { height: 100 // μm }, light: { on : 1000, off: 500 }, zip: true, svg: false, png: true, speed: false, speedDelay: 10, // ms panel: { collapsed: false, position : 1 }, lifting: { speed : 50, // mm/min height: 3, // mm } }, mesh: { panel: { collapsed: false, position : 2 } }, transform: { panel: { collapsed: false, position : 3 }, mirror: false }, buildVolume: { size : { x: 100, y: 100, z: 100 }, // mm unit : 'mm', // mm or in color : 0xcccccc, opacity : 0.1, panel : { collapsed: false, position : 4 } }, resin: { density : 1.1, // g/cm3 price : 50, // $ panel : { collapsed: false, position : 5 } }, screen: { width : window.screen.width, height : window.screen.height, diagonal : { size: 22, unit: 'in' }, panel : { collapsed: false, position : 6 } }, colors: { mesh : '#eb0984', slice: '#88ee11', panel: { collapsed: false, position : 7 } }, viewer3d: { color: 0xffffff } }); // ----------------------------------------------------------------------------- // Error handler // ----------------------------------------------------------------------------- function errorHandler(error) { console.error(error); } // ----------------------------------------------------------------------------- // Slicer // ----------------------------------------------------------------------------- var slicer = new SLAcer.Slicer(); var shapes, slices; function removeShapes() { if (shapes && shapes.length) { for (var i = 0, il = shapes.length; i < il; i++) { viewer3d.removeObject(shapes[i]); } } } function removeSlices() { if (slices && slices.length) { for (var i = 0, il = slices.length; i < il; i++) { viewer2d.removeObject(slices[i]); } } sliceImage('none'); } function hexToDec(hex) { return parseInt(hex.toString().replace('#', ''), 16); } function sliceImage(dataURL) { settings.set('slice.dataURL', dataURL || 'none'); } function getSlice(layerNumber) { // remove old shapes removeSlices(); removeShapes(); // ... $slicerLayerValue.html(layerNumber); if (layerNumber < 1) { viewer2d.render(); viewer3d.render(); return; } if (transformations.update) { throw 'transformations not applyed...'; } // get position layerHeight = settings.get('slicer.layers.height') / 1000; zPosition = layerNumber * layerHeight; // get faces var faces = slicer.getFaces(zPosition); //console.log('layer number:', layerNumber); //console.log('z position :', zPosition); // get new shapes list shapes = faces.meshes; zPosition -= viewer3d.buildVolume.size.z / 2; // slices slices = []; var slice, shape; var sliceColor = hexToDec(settings.get('colors.slice')); // add new shapes for (var i = 0, il = shapes.length; i < il; i++) { shape = shapes[i]; slice = shape.clone(); slice.material = slice.material.clone(); slice.material.color.setHex(0xffffff); viewer2d.addObject(slice); slices.push(slice); shape.material.color.setHex(sliceColor); shape.material.depthTest = false; shape.position.z = zPosition; viewer3d.scene.add(shape); } // render 3D view viewer3d.render(); // render 2D view viewer2d.screenshot(function(dataURL) { sliceImage(dataURL); 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 = '\n'; // svg background svg += '\n'; // fix coordinate system (rotate 180°) svg += '\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 += '\n'; } // svg end svg += ''; svg += ''; // add svg file to zip zipFolder.file(layerNumber + '.svg', svg); } } // ----------------------------------------------------------------------------- // UI // ----------------------------------------------------------------------------- // Main container var $main = $('#main'); // Viewer 3D var $viewer3d = $('#viewer3d'); var viewer3d = new SLAcer.Viewer3D({ color : settings.get('viewer3d.color'), buildVolume: settings.get('buildVolume'), target : $viewer3d[0] }); // Triangulation algorithm //THREE.Triangulation.setTimer(true); THREE.Triangulation.setLibrary('earcut'); //THREE.Triangulation.setLibrary('libtess'); //THREE.Triangulation.setLibrary('poly2tri'); // Viewer 2D var viewer2dWin = null; var $openViewer2D = $('#open-viewer-2d'); var viewer2d = new SLAcer.Viewer2D({ target : null, // off-screen color : 0x000000, buildPlate : { size : settings.get('buildVolume.size'), unit : settings.get('buildVolume.unit'), color : 0x000000, opacity: 0 // hide build plate }, size: settings.get('screen') }); $openViewer2D.click(function(e) { if (viewer2dWin == null || viewer2dWin.closed) { var screen = settings.get('screen'); var size = 'width=' + screen.width + ', height=' + screen.height; var opts = 'menubar=0, toolbar=0, location=0, directories=0, personalbar=0, status=0, resizable=1, dependent=0' viewer2dWin = window.open('viewer2d.html', 'SLAcerViewer2D', size + ', ' + opts); $(viewer2dWin).on('beforeunload', function(e) { viewer2dWin = null; }) .load(function(e) { getSlice($sliderInput.slider('getValue')); }); } else { viewer2dWin.focus(); } return false; }); // Slider var $sliderInput = $('#slider input'); $sliderInput.slider({ reversed : true }).on('change', function(e) { getSlice(e.value.newValue); }); var $sliderElement = $('#slider .slider'); var $sliderMaxValue = $('#slider .max'); function updateSliderUI() { var layersHeight = settings.get('slicer.layers.height') / 1000; var layersNumber = Math.floor(slicer.mesh.getSize().z / layersHeight); $sliderInput.slider('setAttribute', 'max', layersNumber); $sliderMaxValue.html(layersNumber); $slicerLayersValue.html(layersNumber); } // Sidebar var $sidebar = $('#sidebar'); var $panels = $sidebar.find('.panel'); $sidebar.sortable({ axis : 'y', handle : '.panel-heading', cancel : '.panel-toggle', placeholder: 'panel-placeholder', forcePlaceholderSize: true, // update panel position stop: function(e, ui) { $sidebar.find('.panel').each(function(i, element) { settings.set(_.camelCase(element.id) + '.panel.position', i); }); } }); // Sort panels var panels = []; var panel; _.forEach(settings.settings, function(item, namespace) { if (item && item.panel) { panels[item.panel.position] = $('#' + _.kebabCase(namespace)); } }); for (var i in panels) { $sidebar.append(panels[i]); } // Init panel function initPanel(name) { var id = _.kebabCase(name); var name = _.camelCase(name); var $body = $('#' + id + '-body'); $body.on('hidden.bs.collapse', function () { settings.set(name + '.panel.collapsed', true); }); $body.on('shown.bs.collapse', function () { settings.set(name + '.panel.collapsed', false); }); if (settings.get(name + '.panel.collapsed')) { $body.collapse('hide'); } return $body; } // Unit converter function parseUnit(value, unit) { return parseFloat(unit == 'in' ? (value / 25.4) : (value * 25.4)); } // File panel var $fileBody = initPanel('file'); var $fileInput = $fileBody.find('#file-input'); var loadedFile = null; $fileInput.on('change', function(e) { resetTransformValues(); loadedFile = e.target.files[0]; loader.loadFile(loadedFile); }); // Mesh panel var $meshBody = initPanel('mesh'); var $meshFaces = $meshBody.find('#mesh-faces'); var $meshVolume = $meshBody.find('#mesh-volume'); var $meshWeight = $meshBody.find('#mesh-weight'); var $meshCost = $meshBody.find('#mesh-cost'); var $meshSizeX = $meshBody.find('#mesh-size-x'); var $meshSizeY = $meshBody.find('#mesh-size-y'); var $meshSizeZ = $meshBody.find('#mesh-size-z'); var $meshSizeUnit = $meshBody.find('.mesh-size-unit'); function updateMeshInfoUI() { var mesh = slicer.mesh; var size = mesh.getSize(); var unit = settings.get('buildVolume.unit'); updateSliderUI(); $meshSizeUnit.html(unit); if (unit == 'in') { size.x = parseUnit(size.x, 'in'); size.y = parseUnit(size.y, 'in'); size.z = parseUnit(size.z, 'in'); } $meshSizeX.html(size.x.toFixed(2)); $meshSizeY.html(size.y.toFixed(2)); $meshSizeZ.html(size.z.toFixed(2)); var volume = parseInt(mesh.getVolume() / 1000); // cm3/ml var weight = (volume * settings.get('resin.density')).toFixed(2); // g var cost = volume * settings.get('resin.price') / 1000; $meshFaces.html(mesh.geometry.faces.length); $meshVolume.html(volume); $meshWeight.html(weight); $meshCost.html(cost); } // Slicer panel var $slicerBody = initPanel('slicer'); var $slicerLayerHeight = $slicerBody.find('#slicer-layers-height'); var $slicerLayersValue = $slicerBody.find('#slicer-layers-value'); var $slicerLayerValue = $slicerBody.find('#slicer-layer-value'); var $slicerLightOff = $slicerBody.find('#slicer-light-off'); var $slicerLightOn = $slicerBody.find('#slicer-light-on'); var $slicerLiftingSpeed = $slicerBody.find('#slicer-lifting-speed'); var $slicerLiftingHeight = $slicerBody.find('#slicer-lifting-height'); 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'); var $slicerMakeZipYes = $slicerBody.find('#slicer-make-zip-yes'); var $slicerMakeZipNo = $slicerBody.find('#slicer-make-zip-no'); var $sliceButton = $sidebar.find('#slice-button'); var $abortButton = $sidebar.find('#abort-button'); var $zipButton = $sidebar.find('#zip-button'); function updateSlicerUI() { var slicer = settings.get('slicer'); $slicerSpeedDelay.val(slicer.speedDelay); $slicerLayerHeight.val(slicer.layers.height); $slicerLightOff.val(slicer.light.off); $slicerLightOn.val(slicer.light.on); $slicerLiftingSpeed.val(slicer.lifting.speed); $slicerLiftingHeight.val(slicer.lifting.height); } function updateSlicerSettings() { settings.set('slicer.layers.height', $slicerLayerHeight.val()); settings.set('slicer.light.off', $slicerLightOff.val()); settings.set('slicer.light.on', $slicerLightOn.val()); settings.set('slicer.lifting.speed', $slicerLiftingSpeed.val()); settings.set('slicer.lifting.height', $slicerLiftingHeight.val()); 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()); getSlice($sliderInput.slider('getValue')); updateSliderUI(); } var sliceInterval; var expectedSliceInterval; var currentSliceNumber; var slicesNumber; var zipFile; var zipFolder; var SVGExport; var PNGExport; var layerHeight; var zPosition; var exposureTime; var liftingSpeed; var liftingHeight; var liftingTime; var estimatedTime; function slice() { currentSliceNumber++; if (currentSliceNumber > slicesNumber) { return endSlicing(); } getSlice(currentSliceNumber); $sliderInput.slider('setValue', currentSliceNumber); var time = Date.now(); var diff = time - expectedSliceInterval; !settings.get('slicer.speed') && viewer2dWin && setTimeout(function() { sliceImage('none'); }, settings.get('slicer.light.on')); expectedSliceInterval += sliceInterval; setTimeout(slice, Math.max(0, sliceInterval - diff)); } function endSlicing() { sliceImage('none'); $sidebar.find('input, button').prop('disabled', false); $sliderInput.slider('enable'); $abortButton.addClass('hidden'); $sliceButton.removeClass('hidden'); $zipButton.prop('disabled', !zipFile); } function startSlicing() { var times = settings.get('slicer.light'); if (settings.get('slicer.speed')) { sliceInterval = parseInt(settings.get('slicer.speedDelay')); } else { sliceInterval = parseInt(times.on) + parseInt(times.off); } expectedSliceInterval = Date.now() + sliceInterval; slicesNumber = parseInt($slicerLayersValue.html()); currentSliceNumber = 0; 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: settings.get('slicer.png') ? 'png' : 'svg', imageDirectory: 'slices', screenWidth : settings.get('screen.width'), screenHeight : settings.get('screen.height'), screenSize : settings.get('screen.diagonal.size'), screenUnit : settings.get('screen.diagonal.unit'), layersNumber : slicesNumber, layersHeight : settings.get('slicer.layers.height') / 1000, // mm exposureTime : parseInt(settings.get('slicer.light.on')), // ms 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(); } $zipButton.on('click', function(e) { if (zipFile) { var name = 'SLAcer'; if (loadedFile && loadedFile.name) { name = loadedFile.name; } saveAs(zipFile.generate({type: 'blob'}), name + '.zip'); } }); $sliceButton.on('click', function(e) { $sidebar.find('input, button').prop('disabled', true); $('.panel-heading button').prop('disabled', false); $openViewer2D.prop('disabled', false); $sliderInput.slider('disable'); $abortButton.prop('disabled', false); $abortButton.removeClass('hidden'); $sliceButton.addClass('hidden'); startSlicing(); }); $abortButton.on('click', function(e) { currentSliceNumber = slicesNumber + 1; endSlicing(); }); $('#slicer-image-extension-' + (settings.get('slicer.png') ? 'png' : 'svg')).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); $('#slicer input').on('input, change', updateSlicerSettings); updateSlicerUI(); // Build volume panel var $buildVolumeBody = initPanel('buildVolume'); var $buildVolumeX = $buildVolumeBody.find('#build-volume-x'); var $buildVolumeY = $buildVolumeBody.find('#build-volume-y'); var $buildVolumeZ = $buildVolumeBody.find('#build-volume-z'); function updateBuildVolumeUI() { var buildVolume = settings.get('buildVolume'); $buildVolumeX.val(buildVolume.size.x); $buildVolumeY.val(buildVolume.size.y); $buildVolumeZ.val(buildVolume.size.z); updateBuildVolumeSizeStep(); } function updateBuildVolumeSizeStep() { var step = (settings.get('buildVolume.unit') == 'in') ? 0.01 : 1; $buildVolumeX.prop('step', step); $buildVolumeY.prop('step', step); $buildVolumeZ.prop('step', step); } function updateBuildVolumeSettings() { var unit = $('#build-volume input[type=radio]:checked').val(); if (unit != settings.get('buildVolume.unit')) { var size = settings.get('buildVolume.size'); $buildVolumeX.val(parseUnit(size.x, unit)); $buildVolumeY.val(parseUnit(size.y, unit)); $buildVolumeZ.val(parseUnit(size.z, unit)); } settings.set('buildVolume', { size: { x: $buildVolumeX.val(), y: $buildVolumeY.val(), z: $buildVolumeZ.val() }, unit: unit }); viewer3d.setBuildVolume(settings.get('buildVolume')); slicer.mesh && viewer3d.dropObject(slicer.mesh); viewer3d.render(); size && updateMeshInfoUI(); updateBuildVolumeSizeStep(); getSlice($sliderInput.slider('getValue')); } $('#build-volume-unit-' + settings.get('buildVolume.unit')).prop('checked', true); $('#build-volume input[type=radio]').on('change', updateBuildVolumeSettings); $('#build-volume input').on('input', updateBuildVolumeSettings); updateBuildVolumeUI(); // Resin panel var $resinBody = initPanel('resin'); var $resinPrice = $resinBody.find('#resin-price'); var $resinDensity = $resinBody.find('#resin-density'); function updateResinUI() { var resin = settings.get('resin'); $resinDensity.val(resin.density); $resinPrice.val(resin.price); } function updateResinSettings() { settings.set('resin.price' , $resinPrice.val()); settings.set('resin.density', $resinDensity.val()); updateMeshInfoUI(); } $('#resin input').on('input', updateResinSettings); updateResinUI(); // Screen var $screenBody = initPanel('screen'); var $screenWidth = $screenBody.find('#screen-width'); var $screenHeight = $screenBody.find('#screen-height'); var $screenDiagonalSize = $screenBody.find('#screen-diagonal-size'); var $screenDotPitch = $screenBody.find('#screen-dot-pitch'); function updateScreenUI() { var screen = settings.get('screen'); $screenWidth.val(screen.width); $screenHeight.val(screen.height); $screenDiagonalSize.val(screen.diagonal.size); $screenDotPitch.html(viewer2d.dotPitch.toFixed(2)); viewer2d.setScreenResolution(screen); } function updateScreenSettings() { var unit = $('#screen input[type=radio]:checked').val(); if (unit != settings.get('screen.diagonal.unit')) { $screenDiagonalSize.val( parseUnit(settings.get('screen.diagonal.size'), unit) ); } settings.set('screen', { width : $screenWidth.val(), height : $screenHeight.val(), diagonal: { size: $screenDiagonalSize.val(), unit: unit } }); viewer2d.setScreenResolution(settings.get('screen')); $screenDotPitch.html(viewer2d.dotPitch.toFixed(2)); getSlice($sliderInput.slider('getValue')); } $('#screen-diagonal-unit-' + settings.get('screen.diagonal.unit')).prop('checked', true); $('#screen input[type=radio]').on('change', updateScreenSettings); $('#screen input').on('input', updateScreenSettings); updateScreenUI(); // Colors var $colorsBody = initPanel('colors'); var $meshColor = $colorsBody.find('#mesh-color'); var $sliceColor = $colorsBody.find('#slice-color'); function updateColorsUI() { var colors = settings.get('colors'); $meshColor.val(colors.mesh); $sliceColor.val(colors.slice); } updateColorsUI(); $meshColor.colorpicker({ format: 'hex' }); $sliceColor.colorpicker({ format: 'hex' }); $meshColor.colorpicker().on('changeColor.colorpicker', function(e) { if (slicer.mesh && slicer.mesh.material) { var hexString = e.color.toHex(); var hexInteger = hexToDec(hexString); settings.set('colors.mesh', hexString); slicer.mesh.material.color.setHex(hexInteger); viewer3d.render(); } }); $sliceColor.colorpicker().on('changeColor.colorpicker', function(e) { if (shapes && shapes.length) { var hexString = e.color.toHex(); var hexInteger = hexToDec(hexString); settings.set('colors.slice', hexString); for (var i = 0, il = shapes.length; i < il; i++) { shapes[i].material.color.setHex(hexInteger); } viewer3d.render(); } }); // Alert var $alertPanel = $('#alert'); var $alertMessage = $alertPanel.find('.message'); // Transform var $transformBody = initPanel('transform'); var $transformAction = $transformBody.find('#transform-action'); var $transformUniform = $transformBody.find('#transform-uniform'); var $transformX = $transformBody.find('#transform-x'); var $transformY = $transformBody.find('#transform-y'); var $transformZ = $transformBody.find('#transform-z'); var $transformButtons = $transformBody.find('button'); var $transformMirrorYes = $transformBody.find('#transform-mirror-yes'); var $transformMirrorNo = $transformBody.find('#transform-mirror-no'); var transformAction, transformations; function resetTransformValues() { transformAction = 'scale'; transformations = { scale : { x:1, y:1 , z:1 }, rotate : { x:0, y:0 , z:0 }, translate: { x:0, y:0 , z:0 } }; updateTransformAction(); } function updateTransformAction() { transformAction = $transformAction.val(); var axis = transformations[transformAction]; var min, max, step; if (transformAction == 'scale') { min = 0.01; max = 999; step = 0.01; } else if (transformAction == 'rotate') { min = 0; max = 360; step = 1; } else { min = -9999; max = 9999; step = 1; } $transformUniform.toggleClass('hidden', transformAction != 'scale'); $transformZ.parent().toggleClass('hidden', transformAction == 'translate'); $transformX.prop('min', min); $transformY.prop('min', min); $transformZ.prop('min', min); $transformX.prop('max', max); $transformY.prop('max', max); $transformZ.prop('max', max); $transformX.prop('step', step); $transformY.prop('step', step); $transformZ.prop('step', step); $transformX.val(axis.x); $transformY.val(axis.y); $transformZ.val(axis.z); } function updateTransformValues() { var current = transformations[transformAction]; var uniform = $('#transform-uniform input[type=radio]:checked').val() == 'yes'; var input = { x: parseFloat($transformX.val()), y: parseFloat($transformY.val()), z: parseFloat($transformZ.val()) }; input.x = isNaN(input.x) ? current.x : input.x; input.y = isNaN(input.y) ? current.y : input.y; input.z = isNaN(input.z) ? current.z : input.z; $transformX.val(input.x); $transformY.val(input.y); $transformZ.val(input.z); if (transformAction == 'scale') { if (uniform) { if (input.x != current.x) { var ratio = current.x / input.x; input.y = (current.y / ratio).toFixed(2); input.z = (current.z / ratio).toFixed(2); $transformY.val(input.y); $transformZ.val(input.z); } else if (input.y != current.y) { var ratio = current.y / input.y; input.x = (current.x / ratio).toFixed(2); input.z = (current.z / ratio).toFixed(2); $transformX.val(input.x); $transformZ.val(input.z); } else if (input.z != current.z) { var ratio = current.z / input.z; input.x = (current.x / ratio).toFixed(2); input.y = (current.y / ratio).toFixed(2); $transformX.val(input.x); $transformY.val(input.y); } } input.x <= 0 && (input.x = 1); input.y <= 0 && (input.y = 1); input.z <= 0 && (input.z = 1); slicer.mesh.geometry.scale( input.x / current.x, input.y / current.y, input.z / current.z ); } else if (transformAction == 'rotate') { var deg = Math.PI / 180; var offsets = { x: input.x - current.x, y: input.y - current.y, z: input.z - current.z }; slicer.mesh.geometry.rotateX(offsets.x * deg); slicer.mesh.geometry.rotateY(offsets.y * deg); slicer.mesh.geometry.rotateZ(offsets.z * deg); } else { var offsets = { x: input.x - current.x, y: input.y - current.y }; slicer.mesh.geometry.translate(offsets.x, offsets.y, 0); } current.x = input.x; current.y = input.y; current.z = input.z; if (transformAction != 'translate') { loadGeometry(slicer.mesh.geometry, false); // stay at current position var current = transformations['translate']; slicer.mesh.geometry.translate(current.x, current.y, current.z); } getSlice($sliderInput.slider('getValue')); } $transformButtons.on('click', function(e) { var $this = $(this); var axis = $this.data('axis'); var action = $this.data('action'); var value = transformations[transformAction][axis]; var $target = $transformBody.find('#transform-' + axis); $target.val(value + (action == '+' ? 1 : -1)); updateTransformValues(); }); function flipGeometry() { settings.set('transform.mirror', $transformMirrorYes[0].checked); loadGeometry(slicer.mesh.geometry, true); getSlice($sliderInput.slider('getValue')); } $transformMirrorYes.on('change', flipGeometry); $transformMirrorNo.on('change', flipGeometry); $('#transform-mirror-' + (settings.get('transform.mirror') ? 'yes' : 'no')).prop('checked', true); $('#transform select').on('change', updateTransformAction); $('#transform input').on('change', updateTransformValues); resetTransformValues(); // UI resize function resizeUI() { var width = $main.width(); var height = $main.height(); $sliderElement.height(height - 80); viewer3d.setSize({ width : width, height: height }); viewer3d.render(); } $(window).resize(resizeUI); resizeUI(); // ----------------------------------------------------------------------------- // STL loader // ----------------------------------------------------------------------------- // Loader instance var loader = new MeshesJS.STLLoader($main[0]); // drop target // Load an 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) { 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')), side: THREE.DoubleSide }))); // add new mesh and render view viewer3d.addObject(slicer.mesh); viewer3d.render(); // update mesh info updateMeshInfoUI(); // get first slice //getSlice(1); } catch(e) { errorHandler(e); } } // Haaaaaaaaaaaaaaaaaa!!!! function ultraMegaDirtyFix() { $transformBody.find('#transform-x').val(1.1); $transformBody.find('#transform-y').val(1.1); $transformBody.find('#transform-z').val(1.1); updateTransformValues(); $transformBody.find('#transform-x').val(1); $transformBody.find('#transform-y').val(1); $transformBody.find('#transform-z').val(1); updateTransformValues(); } // On Geometry loaded loader.onGeometry = function(geometry) { resetTransformValues(); loadGeometry(geometry, settings.get('transform.mirror')); ultraMegaDirtyFix(); }; // On loading error loader.onError = errorHandler; // ----------------------------------------------------------------------------- // load example // ----------------------------------------------------------------------------- // example STL file //var stl = 'stl/Octocat-v2.stl'; var stl = 'stl/StressTest.stl'; //var stl = 'stl/SLAcer.stl'; // File url // var url = 'http://' + window.location.hostname + window.location.pathname + stl; var url = window.location.href + stl; // Create http request object var xmlhttp = new XMLHttpRequest(); // Get the file contents xmlhttp.open("GET", url); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == XMLHttpRequest.DONE) { if(xmlhttp.status == 200){ loader.loadString(xmlhttp.responseText); }else{ errorHandler('xmlhttp: ' + xmlhttp.statusText); } } } xmlhttp.send();