Verison 1.0.3 Release
Based on Buildbotics 0.4.14
This commit is contained in:
759
src/js/path-viewer.js
Normal file
759
src/js/path-viewer.js
Normal file
@@ -0,0 +1,759 @@
|
||||
/******************************************************************************\
|
||||
|
||||
Copyright 2018. Buildbotics LLC
|
||||
All Rights Reserved.
|
||||
|
||||
For information regarding this software email:
|
||||
Joseph Coffland
|
||||
joseph@buildbotics.com
|
||||
|
||||
This software is free software: you clan redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License
|
||||
as published by the Free Software Foundation, either version 2.1 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This software is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the C! library. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
'use strict'
|
||||
|
||||
var orbit = require('./orbit');
|
||||
var cookie = require('./cookie')('bbctrl-');
|
||||
var api = require('./api');
|
||||
var font = require('./helvetiker_regular.typeface.json')
|
||||
|
||||
|
||||
function get(obj, name, defaultValue) {
|
||||
return typeof obj[name] == 'undefined' ? defaultValue : obj[name];
|
||||
}
|
||||
|
||||
|
||||
var surfaceModes = ['cut', 'wire', 'solid', 'off'];
|
||||
|
||||
|
||||
module.exports = {
|
||||
template: '#path-viewer-template',
|
||||
props: ['toolpath'],
|
||||
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
enabled: false,
|
||||
loading: false,
|
||||
dirty: true,
|
||||
snapView: cookie.get('snap-view', 'isometric'),
|
||||
small: cookie.get_bool('small-path-view', true),
|
||||
surfaceMode: 'cut',
|
||||
showPath: cookie.get_bool('show-path', true),
|
||||
showTool: cookie.get_bool('show-tool', true),
|
||||
showBBox: cookie.get_bool('show-bbox', true),
|
||||
showAxes: cookie.get_bool('show-axes', true),
|
||||
showIntensity: cookie.get_bool('show-intensity', false)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
computed: {
|
||||
target: function () {return $(this.$el).find('.path-viewer-content')[0]}
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
toolpath: function () {Vue.nextTick(this.update)},
|
||||
surfaceMode: function (mode) {this.update_surface_mode(mode)},
|
||||
|
||||
|
||||
small: function (enable) {
|
||||
cookie.set_bool('small-path-view', enable);
|
||||
Vue.nextTick(this.update_view)
|
||||
},
|
||||
|
||||
|
||||
showPath: function (enable) {
|
||||
cookie.set_bool('show-path', enable);
|
||||
this.set_visible(this.pathView, enable)
|
||||
},
|
||||
|
||||
|
||||
showTool: function (enable) {
|
||||
cookie.set_bool('show-tool', enable);
|
||||
this.set_visible(this.toolView, enable)
|
||||
},
|
||||
|
||||
|
||||
showAxes: function (enable) {
|
||||
cookie.set_bool('show-axes', enable);
|
||||
this.set_visible(this.axesView, enable)
|
||||
},
|
||||
|
||||
|
||||
showIntensity: function (enable) {
|
||||
cookie.set_bool('show-intensity', enable);
|
||||
Vue.nextTick(this.update)
|
||||
},
|
||||
|
||||
|
||||
showBBox: function (enable) {
|
||||
cookie.set_bool('show-bbox', enable);
|
||||
this.set_visible(this.bboxView, enable);
|
||||
this.set_visible(this.envelopeView, enable);
|
||||
},
|
||||
|
||||
|
||||
x: function () {this.axis_changed()},
|
||||
y: function () {this.axis_changed()},
|
||||
z: function () {this.axis_changed()}
|
||||
},
|
||||
|
||||
|
||||
ready: function () {
|
||||
this.graphics();
|
||||
Vue.nextTick(this.update);
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
update: function () {
|
||||
if (!this.state.selected) {
|
||||
this.dirty = true;
|
||||
this.scene = new THREE.Scene();
|
||||
|
||||
} else if (!this.toolpath.filename && !this.loading) {
|
||||
this.loading = true;
|
||||
this.dirty = true;
|
||||
this.draw_loading();
|
||||
}
|
||||
|
||||
if (!this.enabled || !this.toolpath.filename) return;
|
||||
|
||||
function get(url) {
|
||||
var d = $.Deferred();
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', url + '?' + Math.random(), true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (xhr.response) d.resolve(new Float32Array(xhr.response));
|
||||
else d.reject();
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
|
||||
return d.promise();
|
||||
}
|
||||
|
||||
var d1 = get('/api/path/' + this.toolpath.filename + '/positions');
|
||||
var d2 = get('/api/path/' + this.toolpath.filename + '/speeds');
|
||||
|
||||
$.when(d1, d2).done(function (positions, speeds) {
|
||||
this.positions = positions
|
||||
this.speeds = speeds;
|
||||
this.loading = false;
|
||||
|
||||
// Update scene
|
||||
this.scene = new THREE.Scene();
|
||||
this.draw(this.scene);
|
||||
this.snap(this.snapView);
|
||||
|
||||
this.update_view();
|
||||
}.bind(this))
|
||||
},
|
||||
|
||||
|
||||
update_surface_mode: function (mode) {
|
||||
if (!this.enabled) return;
|
||||
|
||||
if (typeof this.surfaceMaterial != 'undefined') {
|
||||
this.surfaceMaterial.wireframe = mode == 'wire';
|
||||
this.surfaceMaterial.needsUpdate = true;
|
||||
}
|
||||
|
||||
this.set_visible(this.surfaceMesh, mode == 'cut' || mode == 'wire');
|
||||
this.set_visible(this.workpieceMesh, mode == 'solid');
|
||||
},
|
||||
|
||||
|
||||
load_surface: function (surface) {
|
||||
if (typeof surface == 'undefined') {
|
||||
this.vertices = undefined;
|
||||
this.normals = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this.vertices = surface.vertices;
|
||||
|
||||
// Expand normals
|
||||
this.normals = [];
|
||||
for (var i = 0; i < surface.normals.length / 3; i++)
|
||||
for (var j = 0; j < 3; j++)
|
||||
for (var k = 0; k < 3; k++)
|
||||
this.normals.push(surface.normals[i * 3 + k]);
|
||||
},
|
||||
|
||||
|
||||
set_visible: function (target, visible) {
|
||||
if (typeof target != 'undefined') target.visible = visible;
|
||||
this.dirty = true;
|
||||
},
|
||||
|
||||
|
||||
get_dims: function () {
|
||||
var t = $(this.target);
|
||||
var width = t.innerWidth();
|
||||
var height = t.innerHeight();
|
||||
return {width: width, height: height};
|
||||
},
|
||||
|
||||
|
||||
update_view: function () {
|
||||
if (!this.enabled) return;
|
||||
var dims = this.get_dims();
|
||||
|
||||
this.camera.aspect = dims.width / dims.height;
|
||||
this.camera.updateProjectionMatrix();
|
||||
this.renderer.setSize(dims.width, dims.height);
|
||||
|
||||
if (this.loading) {
|
||||
this.controls.reset();
|
||||
this.camera.position.copy(new THREE.Vector3(0, 0, 600));
|
||||
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
|
||||
}
|
||||
|
||||
this.dirty = true;
|
||||
},
|
||||
|
||||
|
||||
update_tool: function (tool) {
|
||||
if (!this.enabled) return;
|
||||
if (typeof tool == 'undefined') tool = this.toolView;
|
||||
if (typeof tool == 'undefined') return;
|
||||
tool.position.x = this.x.pos;
|
||||
tool.position.y = this.y.pos;
|
||||
tool.position.z = this.z.pos;
|
||||
},
|
||||
|
||||
|
||||
update_envelope: function (envelope) {
|
||||
if (!this.enabled || !this.axes.homed) return;
|
||||
if (typeof envelope == 'undefined') envelope = this.envelopeView;
|
||||
if (typeof envelope == 'undefined') return;
|
||||
|
||||
var min = new THREE.Vector3();
|
||||
var max = new THREE.Vector3();
|
||||
|
||||
for (var axis of 'xyz') {
|
||||
min[axis] = this[axis].min - this[axis].off;
|
||||
max[axis] = this[axis].max - this[axis].off;
|
||||
}
|
||||
|
||||
var bounds = new THREE.Box3(min, max);
|
||||
if (bounds.isEmpty()) envelope.geometry = this.create_empty_geom();
|
||||
else envelope.geometry = this.create_bbox_geom(bounds);
|
||||
},
|
||||
|
||||
|
||||
axis_changed: function () {
|
||||
this.update_tool();
|
||||
this.update_envelope();
|
||||
this.dirty = true;
|
||||
},
|
||||
|
||||
|
||||
graphics: function () {
|
||||
try {
|
||||
// Renderer
|
||||
this.renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
this.renderer.setClearColor(0, 0);
|
||||
this.target.appendChild(this.renderer.domElement);
|
||||
|
||||
} catch (e) {
|
||||
console.log('WebGL not supported: ', e);
|
||||
return;
|
||||
}
|
||||
this.enabled = true;
|
||||
|
||||
// Camera
|
||||
this.camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 10000);
|
||||
|
||||
// Lighting
|
||||
this.ambient = new THREE.AmbientLight(0xffffff, 0.5);
|
||||
|
||||
var keyLight = new THREE.DirectionalLight
|
||||
(new THREE.Color('hsl(30, 100%, 75%)'), 0.75);
|
||||
keyLight.position.set(-100, 0, 100);
|
||||
|
||||
var fillLight = new THREE.DirectionalLight
|
||||
(new THREE.Color('hsl(240, 100%, 75%)'), 0.25);
|
||||
fillLight.position.set(100, 0, 100);
|
||||
|
||||
var backLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||
backLight.position.set(100, 0, -100).normalize();
|
||||
|
||||
this.lights = new THREE.Group();
|
||||
this.lights.add(keyLight);
|
||||
this.lights.add(fillLight);
|
||||
this.lights.add(backLight);
|
||||
|
||||
// Surface material
|
||||
this.surfaceMaterial = this.create_surface_material();
|
||||
|
||||
// Controls
|
||||
this.controls = new orbit(this.camera, this.renderer.domElement);
|
||||
this.controls.enableDamping = true;
|
||||
this.controls.dampingFactor = 0.2;
|
||||
this.controls.rotateSpeed = 0.25;
|
||||
this.controls.enableZoom = true;
|
||||
|
||||
// Move lights with scene
|
||||
this.controls.addEventListener('change', function (scope) {
|
||||
return function () {
|
||||
keyLight.position.copy(scope.camera.position);
|
||||
fillLight.position.copy(scope.camera.position);
|
||||
backLight.position.copy(scope.camera.position);
|
||||
keyLight.lookAt(scope.controls.target);
|
||||
fillLight.lookAt(scope.controls.target);
|
||||
backLight.lookAt(scope.controls.target);
|
||||
scope.dirty = true;
|
||||
}
|
||||
}(this))
|
||||
|
||||
// Events
|
||||
window.addEventListener('resize', this.update_view, false);
|
||||
|
||||
// Start it
|
||||
this.render();
|
||||
},
|
||||
|
||||
|
||||
create_surface_material: function () {
|
||||
return new THREE.MeshPhongMaterial({
|
||||
specular: 0x111111,
|
||||
shininess: 10,
|
||||
side: THREE.FrontSide,
|
||||
color: 0x0c2d53
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
draw_loading: function () {
|
||||
this.scene = new THREE.Scene();
|
||||
|
||||
var geometry = new THREE.TextGeometry('Loading 3D View...', {
|
||||
font: new THREE.Font(font),
|
||||
size: 40,
|
||||
height: 5,
|
||||
curveSegments: 12,
|
||||
bevelEnabled: true,
|
||||
bevelThickness: 10,
|
||||
bevelSize: 8,
|
||||
bevelSegments: 5
|
||||
});
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
var center = geometry.center();
|
||||
var mesh = new THREE.Mesh(geometry, this.surfaceMaterial);
|
||||
|
||||
this.scene.add(mesh);
|
||||
this.scene.add(this.ambient);
|
||||
this.scene.add(this.lights);
|
||||
this.update_view();
|
||||
},
|
||||
|
||||
|
||||
draw_workpiece: function (scene, material) {
|
||||
if (typeof this.workpiece == 'undefined') return;
|
||||
|
||||
var min = this.workpiece.min;
|
||||
var max = this.workpiece.max;
|
||||
|
||||
min = new THREE.Vector3(min[0], min[1], min[2]);
|
||||
max = new THREE.Vector3(max[0], max[1], max[2]);
|
||||
var dims = max.clone().sub(min);
|
||||
|
||||
var geometry = new THREE.BoxGeometry(dims.x, dims.y, dims.z)
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
var offset = dims.clone();
|
||||
offset.divideScalar(2);
|
||||
offset.add(min);
|
||||
|
||||
mesh.position.add(offset);
|
||||
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
scene.add(mesh);
|
||||
|
||||
return mesh;
|
||||
},
|
||||
|
||||
|
||||
draw_surface: function (scene, material) {
|
||||
if (typeof this.vertices == 'undefined') return;
|
||||
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
|
||||
geometry.addAttribute
|
||||
('position', new THREE.Float32BufferAttribute(this.vertices, 3));
|
||||
geometry.addAttribute
|
||||
('normal', new THREE.Float32BufferAttribute(this.normals, 3));
|
||||
|
||||
geometry.computeBoundingSphere();
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
return new THREE.Mesh(geometry, material);
|
||||
},
|
||||
|
||||
|
||||
draw_tool: function (scene, bbox) {
|
||||
// Tool size is relative to bounds
|
||||
var size = bbox.getSize(new THREE.Vector3());
|
||||
var length = (size.x + size.y + size.z) / 24;
|
||||
|
||||
if (length < 1) length = 1;
|
||||
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
transparent: true,
|
||||
opacity: 0.75,
|
||||
specular: 0x161616,
|
||||
shininess: 10,
|
||||
color: 0xffa500 // Orange
|
||||
});
|
||||
|
||||
var geometry = new THREE.CylinderGeometry(length / 2, 0, length, 128);
|
||||
geometry.translate(0, length / 2, 0);
|
||||
geometry.rotateX(0.5 * Math.PI);
|
||||
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
this.update_tool(mesh);
|
||||
mesh.visible = this.showTool;
|
||||
scene.add(mesh);
|
||||
return mesh;
|
||||
},
|
||||
|
||||
|
||||
draw_axis: function (axis, up, length, radius) {
|
||||
var color;
|
||||
|
||||
if (axis == 0) color = 0xff0000; // Red
|
||||
else if (axis == 1) color = 0x00ff00; // Green
|
||||
else if (axis == 2) color = 0x0000ff; // Blue
|
||||
|
||||
var group = new THREE.Group();
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
specular: 0x161616, shininess: 10, color: color
|
||||
});
|
||||
var geometry = new THREE.CylinderGeometry(radius, radius, length, 128);
|
||||
geometry.translate(0, -length / 2, 0);
|
||||
group.add(new THREE.Mesh(geometry, material));
|
||||
|
||||
geometry = new THREE.CylinderGeometry(1.5 * radius, 0, 2 * radius, 128);
|
||||
geometry.translate(0, -length - radius, 0);
|
||||
group.add(new THREE.Mesh(geometry, material));
|
||||
|
||||
if (axis == 0) group.rotateZ((up ? 0.5 : 1.5) * Math.PI);
|
||||
else if (axis == 1) group.rotateX((up ? 0 : 1 ) * Math.PI);
|
||||
else if (axis == 2) group.rotateX((up ? 1.5 : 0.5) * Math.PI);
|
||||
|
||||
return group;
|
||||
},
|
||||
|
||||
|
||||
draw_axes: function (scene, bbox) {
|
||||
var size = bbox.getSize(new THREE.Vector3());
|
||||
var length = (size.x + size.y + size.z) / 3;
|
||||
length /= 10;
|
||||
|
||||
if (length < 1) length = 1;
|
||||
|
||||
var radius = length / 20;
|
||||
|
||||
var group = new THREE.Group();
|
||||
|
||||
for (var axis = 0; axis < 3; axis++)
|
||||
for (var up = 0; up < 2; up++)
|
||||
group.add(this.draw_axis(axis, up, length, radius));
|
||||
|
||||
group.visible = this.showAxes;
|
||||
scene.add(group);
|
||||
|
||||
return group;
|
||||
},
|
||||
|
||||
|
||||
get_color: function (speed) {
|
||||
if (isNaN(speed)) return [255, 0, 0]; // Rapid
|
||||
|
||||
var intensity = speed / this.toolpath.maxSpeed;
|
||||
if (typeof speed == 'undefined' || !this.showIntensity) intensity = 1;
|
||||
return [0, 255 * intensity, 127 * (1 - intensity)];
|
||||
},
|
||||
|
||||
|
||||
draw_path: function (scene) {
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
var material =
|
||||
new THREE.LineBasicMaterial({
|
||||
vertexColors: THREE.VertexColors,
|
||||
linewidth: 1.5
|
||||
});
|
||||
|
||||
var positions = new THREE.Float32BufferAttribute(this.positions, 3);
|
||||
geometry.addAttribute('position', positions);
|
||||
|
||||
var colors = [];
|
||||
for (var i = 0; i < this.speeds.length; i++) {
|
||||
var color = this.get_color(this.speeds[i]);
|
||||
Array.prototype.push.apply(colors, color);
|
||||
}
|
||||
|
||||
colors = new THREE.Uint8BufferAttribute(colors, 3, true);
|
||||
geometry.addAttribute('color', colors);
|
||||
|
||||
geometry.computeBoundingSphere();
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
var line = new THREE.Line(geometry, material);
|
||||
|
||||
line.visible = this.showPath;
|
||||
scene.add(line);
|
||||
|
||||
return line;
|
||||
},
|
||||
|
||||
|
||||
create_empty_geom: function () {
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
geometry.addAttribute('position',
|
||||
new THREE.Float32BufferAttribute([], 3));
|
||||
return geometry;
|
||||
},
|
||||
|
||||
|
||||
create_bbox_geom: function (bbox) {
|
||||
var vertices = [];
|
||||
|
||||
if (!bbox.isEmpty()) {
|
||||
// Top
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.min.z);
|
||||
|
||||
// Bottom
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.max.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.min.z);
|
||||
|
||||
// Sides
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.min.z);
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.min.z);
|
||||
vertices.push(bbox.max.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.max.x, bbox.max.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.min.y, bbox.max.z);
|
||||
vertices.push(bbox.min.x, bbox.max.y, bbox.max.z);
|
||||
}
|
||||
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
|
||||
geometry.addAttribute('position',
|
||||
new THREE.Float32BufferAttribute(vertices, 3));
|
||||
|
||||
return geometry;
|
||||
},
|
||||
|
||||
|
||||
draw_bbox: function (scene, bbox) {
|
||||
var geometry = this.create_bbox_geom(bbox);
|
||||
var material = new THREE.LineBasicMaterial({color: 0xffffff});
|
||||
var line = new THREE.LineSegments(geometry, material);
|
||||
|
||||
line.visible = this.showBBox;
|
||||
|
||||
scene.add(line);
|
||||
|
||||
return line;
|
||||
},
|
||||
|
||||
|
||||
draw_envelope: function (scene) {
|
||||
var geometry = this.create_empty_geom();
|
||||
var material = new THREE.LineBasicMaterial({color: 0x00f7ff});
|
||||
var line = new THREE.LineSegments(geometry, material);
|
||||
|
||||
line.visible = this.showBBox;
|
||||
|
||||
scene.add(line);
|
||||
this.update_envelope(line);
|
||||
|
||||
return line;
|
||||
},
|
||||
|
||||
|
||||
draw: function (scene) {
|
||||
// Lights
|
||||
scene.add(this.ambient);
|
||||
scene.add(this.lights);
|
||||
|
||||
// Model
|
||||
this.pathView = this.draw_path(scene);
|
||||
this.surfaceMesh = this.draw_surface(scene, this.surfaceMaterial);
|
||||
this.workpieceMesh = this.draw_workpiece(scene, this.surfaceMaterial);
|
||||
this.update_surface_mode(this.surfaceMode);
|
||||
|
||||
// Compute bounding box
|
||||
var bbox = this.get_model_bounds();
|
||||
|
||||
// Tool, axes & bounds
|
||||
this.toolView = this.draw_tool(scene, bbox);
|
||||
this.axesView = this.draw_axes(scene, bbox);
|
||||
this.bboxView = this.draw_bbox(scene, bbox);
|
||||
this.envelopeView = this.draw_envelope(scene);
|
||||
},
|
||||
|
||||
|
||||
render: function () {
|
||||
window.requestAnimationFrame(this.render);
|
||||
if (typeof this.scene == 'undefined') return;
|
||||
|
||||
if (this.controls.update() || this.dirty) {
|
||||
this.dirty = false;
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
get_model_bounds: function () {
|
||||
var bbox = new THREE.Box3(new THREE.Vector3(0, 0, 0),
|
||||
new THREE.Vector3(0.00001, 0.00001, 0.00001));
|
||||
|
||||
function add(o) {
|
||||
if (typeof o != 'undefined') {
|
||||
var oBBox = new THREE.Box3();
|
||||
oBBox.setFromObject(o);
|
||||
bbox.union(oBBox);
|
||||
}
|
||||
}
|
||||
|
||||
add(this.pathView);
|
||||
add(this.surfaceMesh);
|
||||
add(this.workpieceMesh);
|
||||
|
||||
return bbox;
|
||||
},
|
||||
|
||||
|
||||
snap: function (view) {
|
||||
if (this.loading) return;
|
||||
if (view != this.snapView) {
|
||||
this.snapView = view;
|
||||
cookie.set('snap-view', view);
|
||||
}
|
||||
|
||||
var bbox = this.get_model_bounds();
|
||||
this.controls.reset();
|
||||
bbox.getCenter(this.controls.target);
|
||||
this.update_view();
|
||||
|
||||
// Compute new camera position
|
||||
var center = bbox.getCenter(new THREE.Vector3());
|
||||
var offset = new THREE.Vector3();
|
||||
|
||||
if (view == 'isometric') {offset.y -= 1; offset.z += 1;}
|
||||
if (view == 'front') offset.y -= 1;
|
||||
if (view == 'back') offset.y += 1;
|
||||
if (view == 'left') offset.x -= 1;
|
||||
if (view == 'right') offset.x += 1;
|
||||
if (view == 'top') offset.z += 1;
|
||||
if (view == 'bottom') offset.z -= 1;
|
||||
offset.normalize();
|
||||
|
||||
// Initial camera position
|
||||
var position = new THREE.Vector3().copy(center).add(offset);
|
||||
this.camera.position.copy(position);
|
||||
this.camera.lookAt(center); // Get correct camera orientation
|
||||
|
||||
var theta = this.camera.fov / 180 * Math.PI; // View angle
|
||||
var cameraLine = new THREE.Line3(center, position);
|
||||
var cameraUp = new THREE.Vector3().copy(this.camera.up)
|
||||
.applyQuaternion(this.camera.quaternion);
|
||||
var cameraLeft =
|
||||
new THREE.Vector3().copy(offset).cross(cameraUp).normalize();
|
||||
|
||||
var corners = [
|
||||
new THREE.Vector3(bbox.min.x, bbox.min.y, bbox.min.z),
|
||||
new THREE.Vector3(bbox.min.x, bbox.min.y, bbox.max.z),
|
||||
new THREE.Vector3(bbox.min.x, bbox.max.y, bbox.min.z),
|
||||
new THREE.Vector3(bbox.min.x, bbox.max.y, bbox.max.z),
|
||||
new THREE.Vector3(bbox.max.x, bbox.min.y, bbox.min.z),
|
||||
new THREE.Vector3(bbox.max.x, bbox.min.y, bbox.max.z),
|
||||
new THREE.Vector3(bbox.max.x, bbox.max.y, bbox.min.z),
|
||||
new THREE.Vector3(bbox.max.x, bbox.max.y, bbox.max.z),
|
||||
]
|
||||
|
||||
var dist = this.camera.near; // Min camera dist
|
||||
|
||||
for (var i = 0; i < corners.length; i++) {
|
||||
// Project on to camera line
|
||||
var p1 = cameraLine
|
||||
.closestPointToPoint(corners[i], false, new THREE.Vector3());
|
||||
|
||||
// Compute distance from projection to center
|
||||
var d = p1.distanceTo(center);
|
||||
if (cameraLine.closestPointToPointParameter(p1, false) < 0) d = -d;
|
||||
|
||||
// Compute up line
|
||||
var up =
|
||||
new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraUp));
|
||||
|
||||
// Project on to up line
|
||||
var p2 = up.closestPointToPoint(corners[i], false, new THREE.Vector3());
|
||||
|
||||
// Compute length
|
||||
var l = p1.distanceTo(p2);
|
||||
|
||||
// Update min camera distance
|
||||
dist = Math.max(dist, d + l / Math.tan(theta / 2));
|
||||
|
||||
// Compute left line
|
||||
var left =
|
||||
new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraLeft));
|
||||
|
||||
// Project on to left line
|
||||
var p3 =
|
||||
left.closestPointToPoint(corners[i], false, new THREE.Vector3());
|
||||
|
||||
// Compute length
|
||||
l = p1.distanceTo(p3);
|
||||
|
||||
// Update min camera distance
|
||||
dist = Math.max(dist, d + l / Math.tan(theta / 2) / this.camera.aspect);
|
||||
}
|
||||
|
||||
this.camera.position.copy(offset.multiplyScalar(dist * 1.2).add(center));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
mixins: [require('./axis-vars')]
|
||||
}
|
||||
Reference in New Issue
Block a user