1527 lines
45 KiB
JavaScript
1527 lines
45 KiB
JavaScript
|
var Arena ={
|
|||
|
create:function(id, config, options){
|
|||
|
var ar = {};
|
|||
|
|
|||
|
///////// function init code here /////////
|
|||
|
ar.init = function(id){
|
|||
|
|
|||
|
// public vars
|
|||
|
ar.units = [];
|
|||
|
ar.options = {
|
|||
|
showSky: true,
|
|||
|
dynamicSky: false,
|
|||
|
showShadow: true,
|
|||
|
dynamicShadow: true
|
|||
|
};
|
|||
|
ar.id = id;
|
|||
|
ar.domId = "#" + id;
|
|||
|
ar.cruise = {
|
|||
|
target : new THREE.Vector3(),
|
|||
|
lon: 90,
|
|||
|
lat: 0,
|
|||
|
phi: 0,
|
|||
|
theta : 0
|
|||
|
};
|
|||
|
ar.temp = {};
|
|||
|
ar.shape3Ds = [];
|
|||
|
ar.mouse = new THREE.Vector2();
|
|||
|
|
|||
|
function getViewSize(){
|
|||
|
var SCREEN_WIDTH = window.innerWidth - $(ar.domId).offset().left;
|
|||
|
var SCREEN_HEIGHT = window.innerHeight - $(ar.domId).offset().top - 17;
|
|||
|
|
|||
|
return { width: SCREEN_WIDTH, height: SCREEN_HEIGHT };
|
|||
|
}
|
|||
|
|
|||
|
function initScene(){
|
|||
|
ar.raycaster = new THREE.Raycaster();
|
|||
|
ar.scene = new THREE.Scene();
|
|||
|
//ar.scene.overrideMaterial = new THREE.MeshDepthMaterial();
|
|||
|
}
|
|||
|
|
|||
|
function initRender(){
|
|||
|
if(Detector.webgl){
|
|||
|
ar.renderer = new THREE.WebGLRenderer({ antialias:true});
|
|||
|
|
|||
|
if (ar.options.showShadow){
|
|||
|
ar.renderer.shadowMap.enabled = true;
|
|||
|
ar.renderer.shadowMapSoft = true;
|
|||
|
ar.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|||
|
}
|
|||
|
console.info("webGL render is working.");
|
|||
|
}else{
|
|||
|
ar.renderer = new THREE.CanvasRenderer(); //WebGLRenderer
|
|||
|
console.info("canvas render is working. restart brower remote to enable WebGL");
|
|||
|
}
|
|||
|
|
|||
|
ar.renderer.sortObjects = false;
|
|||
|
ar.renderer.setClearColor( 0x0086b3 ,1);
|
|||
|
ar.renderer.setPixelRatio( window.devicePixelRatio );
|
|||
|
ar.renderer.setSize(getViewSize().width,getViewSize().height);
|
|||
|
}
|
|||
|
|
|||
|
function initCamera(){
|
|||
|
// camera attributes
|
|||
|
var VIEW_ANGLE = 45, ASPECT = getViewSize().width / getViewSize().height,
|
|||
|
NEAR = 10, FAR = 50000;
|
|||
|
|
|||
|
ar.camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
|
|||
|
|
|||
|
ar.camera.position.set(-100, 1600, 1800);
|
|||
|
ar.camera.lookAt(ar.scene.position);
|
|||
|
ar.scene.add(ar.camera);
|
|||
|
//ar.scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
|
|||
|
//ar.scene.fog.color.setHSL( 0.6, 0, 1 );
|
|||
|
}
|
|||
|
|
|||
|
function initSky(){
|
|||
|
var texture_placeholder = document.createElement( 'canvas' );
|
|||
|
texture_placeholder.width = 128;
|
|||
|
texture_placeholder.height = 128;
|
|||
|
|
|||
|
var context = texture_placeholder.getContext( '2d' );
|
|||
|
context.fillStyle = 'rgb( 200, 200, 200 )';
|
|||
|
context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height );
|
|||
|
|
|||
|
function loadTexture( path ) {
|
|||
|
|
|||
|
var texture = new THREE.Texture( texture_placeholder );
|
|||
|
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
|
|||
|
|
|||
|
var image = new Image();
|
|||
|
image.onload = function () {
|
|||
|
|
|||
|
texture.image = this;
|
|||
|
texture.needsUpdate = true;
|
|||
|
|
|||
|
};
|
|||
|
image.src = path;
|
|||
|
|
|||
|
return material;
|
|||
|
}
|
|||
|
|
|||
|
var materials = [
|
|||
|
|
|||
|
loadTexture('/img/3d/skybox/skybox_02.png'),
|
|||
|
loadTexture('/img/3d/skybox/skybox_04.png'),
|
|||
|
loadTexture('/img/3d/skybox/skybox_05.png'),
|
|||
|
loadTexture('/img/3d/skybox/skybox_06.png'),
|
|||
|
loadTexture('/img/3d/skybox/skybox_01.png'),
|
|||
|
loadTexture('/img/3d/skybox/skybox_03.png')
|
|||
|
];
|
|||
|
|
|||
|
// var materials = [
|
|||
|
|
|||
|
// loadTexture( '/img/3d/skybox/px.jpg' ), // right
|
|||
|
// loadTexture( '/img/3d/skybox/nx.jpg' ), // left
|
|||
|
// loadTexture( '/img/3d/skybox/py.jpg' ), // top
|
|||
|
// loadTexture( '/img/3d/skybox/ny.jpg' ), // bottom
|
|||
|
// loadTexture( '/img/3d/skybox/pz.jpg' ), // back
|
|||
|
// loadTexture( '/img/3d/skybox/nz.jpg' ) // front
|
|||
|
|
|||
|
// ];
|
|||
|
|
|||
|
var mesh = new THREE.Mesh(
|
|||
|
new THREE.BoxGeometry( 30000, 30000, 30000, 7, 7, 7 ),
|
|||
|
new THREE.MeshFaceMaterial( materials ) );
|
|||
|
mesh.scale.x = - 1;
|
|||
|
ar.scene.add( mesh );
|
|||
|
}
|
|||
|
|
|||
|
function initResize(){
|
|||
|
$(window).resize(function (){
|
|||
|
ar.camera.aspect = getViewSize().width / getViewSize().height;
|
|||
|
ar.camera.updateProjectionMatrix();
|
|||
|
ar.renderer.setSize( getViewSize().width, getViewSize().height);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
function initControl(){
|
|||
|
//ar.controls = new THREE.OrbitControls(ar.camera, ar.renderer.domElement);
|
|||
|
ar.controls = new THREE.OrbitControls( ar.camera );
|
|||
|
ar.controls.addEventListener( 'change', ar.render );
|
|||
|
ar.controls.minDistance = 500;
|
|||
|
ar.controls.maxDistance = 5000;
|
|||
|
ar.controls.maxPolarAngle = Math.PI * 0.5;
|
|||
|
//ar.controls.minPolarAngle = Math.PI * 0.1;
|
|||
|
|
|||
|
ar.container.style.position = "relative";
|
|||
|
var btnContainer = document.createElement('div');
|
|||
|
btnContainer.id = "btnContainer";
|
|||
|
btnContainer.style.cssText = "position:absolute;left:20px;bottom:20px;margin:10px;";
|
|||
|
|
|||
|
var vi = document.createElement('img');
|
|||
|
vi.id = "veilimg";
|
|||
|
vi.style.cssText = "padding:3px;cursor:pointer;";
|
|||
|
vi.src = 'img/3d/veilView-h.png';
|
|||
|
vi.onclick = function(){
|
|||
|
if (this.src.indexOf('img/3d/veilView-h.png') >= 0)
|
|||
|
{
|
|||
|
this.src = 'img/3d/veilView-i.png';
|
|||
|
document.getElementById("overimg").src="img/3d/overview-h.png";
|
|||
|
ar.cartoon('veilview');
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var oi = document.createElement('img');
|
|||
|
oi.id = "overimg";
|
|||
|
oi.style.cssText = "padding:3px;cursor:pointer;";
|
|||
|
oi.src = "img/3d/overview-h.png";
|
|||
|
oi.onclick = function(){
|
|||
|
if (this.src.indexOf('img/3d/overview-h.png') >= 0)
|
|||
|
{
|
|||
|
this.src = 'img/3d/overview-i.png';
|
|||
|
document.getElementById("veilimg").src="img/3d/veilView-h.png";
|
|||
|
ar.cartoon('overview');
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
btnContainer.appendChild(vi);
|
|||
|
btnContainer.appendChild(oi);
|
|||
|
ar.container.appendChild(btnContainer);
|
|||
|
}
|
|||
|
|
|||
|
function initDebugParts(){
|
|||
|
// axes
|
|||
|
var axes = new THREE.AxisHelper(100);
|
|||
|
ar.scene.add( axes );
|
|||
|
|
|||
|
// displays current and past frames per second attained by scene
|
|||
|
ar.stats = new Stats();
|
|||
|
ar.stats.domElement.style.position = 'absolute';
|
|||
|
ar.stats.domElement.style.bottom = '0px';
|
|||
|
ar.stats.domElement.style.zIndex = 100;
|
|||
|
ar.container.appendChild(ar.stats.domElement);
|
|||
|
|
|||
|
// Grid
|
|||
|
var size = 800, step = 80;
|
|||
|
|
|||
|
var geometry = new THREE.Geometry();
|
|||
|
|
|||
|
for (var i = -size; i <= size; i += step) {
|
|||
|
geometry.vertices.push(new THREE.Vector3(-size, 0, i));
|
|||
|
geometry.vertices.push(new THREE.Vector3(size, 0, i));
|
|||
|
geometry.vertices.push(new THREE.Vector3(i, 0, -size));
|
|||
|
geometry.vertices.push(new THREE.Vector3(i, 0, size));
|
|||
|
}
|
|||
|
|
|||
|
var material = new THREE.LineBasicMaterial({color: 0xeeeeee, opacity: 0.7});
|
|||
|
|
|||
|
var line = new THREE.Line(geometry, material, THREE.LinePieces);
|
|||
|
ar.scene.add(line);
|
|||
|
|
|||
|
//ArrowHelper
|
|||
|
var directionV3 = new THREE.Vector3(1, 0, 1);
|
|||
|
var originV3 = new THREE.Vector3(0, 200, 0);
|
|||
|
// 100 is length, 20 and 10 are head length and width
|
|||
|
var arrowHelper = new THREE.ArrowHelper(directionV3, originV3, 100, 0xff0000, 20, 10);
|
|||
|
ar.scene.add(arrowHelper);
|
|||
|
|
|||
|
// 3. BoundingBoxHelper
|
|||
|
//bboxHelper = new THREE.BoundingBoxHelper(group, 0x999999);
|
|||
|
//ar.scene.add(bboxHelper);
|
|||
|
}
|
|||
|
|
|||
|
function defineMouseBehavior(){
|
|||
|
ar.container.addEventListener( 'mousemove', onDocumentMouseMove, false );
|
|||
|
ar.container.addEventListener( 'mousedown', onDocumentMouseDown, false );
|
|||
|
function onDocumentMouseMove( event ) {
|
|||
|
ar.mouse.x = ( (event.clientX - $(ar.domId).position().left)/ $(ar.domId).width()) * 2 - 1;
|
|||
|
ar.mouse.y = - ( (event.clientY - $(ar.domId).position().top) / $(ar.domId).height()) * 2 + 1;
|
|||
|
event.preventDefault();
|
|||
|
}
|
|||
|
function onDocumentMouseDown( e ) {
|
|||
|
e.preventDefault();
|
|||
|
if (ar.INTERSECTED){
|
|||
|
var shp = ar.getShapeByMesh(ar.INTERSECTED);
|
|||
|
if (shp.config.bindings.length > 0) {
|
|||
|
var devId = shp.config.bindings[0].id;
|
|||
|
ar.options.shell.$location.url('/deviceInfo/' + devId);
|
|||
|
//alert(angular.toJson(shp.config));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function attachToDom(){
|
|||
|
ar.container = document.getElementById(ar.id);
|
|||
|
ar.container.appendChild(ar.renderer.domElement);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
initScene();
|
|||
|
initRender();
|
|||
|
initCamera();
|
|||
|
attachToDom();
|
|||
|
if (ar.options.showSky) initSky();
|
|||
|
initResize();
|
|||
|
initControl();
|
|||
|
//initDebugParts();
|
|||
|
defineMouseBehavior();
|
|||
|
};
|
|||
|
|
|||
|
ar.clear = function(){
|
|||
|
ar.shape3Ds = [];
|
|||
|
};
|
|||
|
|
|||
|
ar.load = function(config){
|
|||
|
ar.clear();
|
|||
|
if (config) {
|
|||
|
ar.loadConfig = config;
|
|||
|
}
|
|||
|
else {
|
|||
|
ar.loadConfig = bn.demoConfig;
|
|||
|
}
|
|||
|
|
|||
|
ar.loadConfig.shapes.forEach(function (shp) {
|
|||
|
if (shp.param3D) ar.loadUnit(shp.param3D);
|
|||
|
});
|
|||
|
|
|||
|
ar.initLight();
|
|||
|
};
|
|||
|
|
|||
|
ar.loadUnit = function(param) {
|
|||
|
var ut = _.find(ar.units, function (item) {
|
|||
|
return item.name === param.unit;
|
|||
|
});
|
|||
|
|
|||
|
if (_.isUndefined(ut)) return;
|
|||
|
if (_.isUndefined(ut.create)) return;
|
|||
|
|
|||
|
var mesh = ut.create(param);
|
|||
|
mesh.unit = ut;
|
|||
|
|
|||
|
var shp = _.extend({}, ar.shape3DClass);
|
|||
|
shp.mesh = mesh;
|
|||
|
shp.config = param;
|
|||
|
shp.id = _.uniqueId();
|
|||
|
|
|||
|
ar.shape3Ds.push(shp);
|
|||
|
ar.scene.add(mesh);
|
|||
|
};
|
|||
|
|
|||
|
ar.animate = function(){
|
|||
|
ar.aniframeId = requestAnimationFrame(ar.animate);
|
|||
|
TWEEN.update();
|
|||
|
ar.render();
|
|||
|
ar.controls.update();
|
|||
|
};
|
|||
|
|
|||
|
ar.render = function(){
|
|||
|
if (!ar) return;
|
|||
|
ar.update();
|
|||
|
ar.renderer.render(ar.scene, ar.camera);
|
|||
|
};
|
|||
|
|
|||
|
ar.update = function() {
|
|||
|
if (ar.options.dynamicSky){
|
|||
|
ar.cruise.lon += 0.1;
|
|||
|
|
|||
|
ar.cruise.lat = Math.max( - 85, Math.min( 85, ar.cruise.lat ) );
|
|||
|
ar.cruise.phi = THREE.Math.degToRad( 90 - ar.cruise.lat );
|
|||
|
ar.cruise.theta = THREE.Math.degToRad( ar.cruise.lon );
|
|||
|
|
|||
|
ar.cruise.target.x = 500 * Math.sin( ar.cruise.phi ) * Math.cos( ar.cruise.theta );
|
|||
|
ar.cruise.target.y = 500 * Math.cos( ar.cruise.phi );
|
|||
|
ar.cruise.target.z = 500 * Math.sin( ar.cruise.phi ) * Math.sin( ar.cruise.theta );
|
|||
|
|
|||
|
ar.camera.lookAt( ar.cruise.target );
|
|||
|
}
|
|||
|
|
|||
|
if (ar.options.dynamicShadow){
|
|||
|
var timer = Date.now() * 0.0001;
|
|||
|
ar.light.position.x = Math.sin(timer) * 1000;
|
|||
|
ar.light.position.z = Math.cos(timer) * 1000;
|
|||
|
ar.light.target.position.set(0, 0, 0);
|
|||
|
}
|
|||
|
|
|||
|
ar.shape3Ds.forEach(function(shp){
|
|||
|
if (shp.mesh.unit.isFlat) shp.mesh.lookAt( ar.camera.position );
|
|||
|
});
|
|||
|
|
|||
|
// high light mouse indicator
|
|||
|
ar.raycaster.setFromCamera( ar.mouse, ar.camera );
|
|||
|
var intersects = ar.raycaster.intersectObjects( ar.scene.children, true );
|
|||
|
|
|||
|
if ( intersects.length > 0 ) {
|
|||
|
|
|||
|
if ( ar.INTERSECTED != intersects[ 0 ].object ) {
|
|||
|
if ( ar.INTERSECTED ) ar.util.maskColor(ar.INTERSECTED, ar.INTERSECTED.currentHex);
|
|||
|
ar.INTERSECTED = intersects[ 0 ].object;
|
|||
|
ar.INTERSECTED.currentHex = ar.util.getMaskColor(ar.INTERSECTED);
|
|||
|
ar.util.maskColor(ar.INTERSECTED, 0x223366);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
if ( ar.INTERSECTED ) ar.util.maskColor(ar.INTERSECTED, ar.INTERSECTED.currentHex);
|
|||
|
ar.INTERSECTED = null;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
ar.getUnit = function(name){
|
|||
|
return _.find(ar.units, function (unit) {
|
|||
|
return unit.name === name;
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
ar.initLight = function () {
|
|||
|
//泛光可调整整个房间的明暗度
|
|||
|
//var ambient = new THREE.AmbientLight( 0x888888);
|
|||
|
//ar.scene.add( ambient );
|
|||
|
|
|||
|
//半球面环境光,模拟天空到大地的光线,可作为主环境光
|
|||
|
var envlight = new THREE.HemisphereLight( 0xffffff, 0xA2C9ED, 0.8);
|
|||
|
//var envlight = new THREE.HemisphereLight( 0x888888, 0x111111, 0.8);
|
|||
|
//envlight.position.set( 0, 1500, 0 );
|
|||
|
|
|||
|
//envlight.shadowCameraFov = 60;
|
|||
|
ar.scene.add(envlight);
|
|||
|
|
|||
|
// 5000 is sphere size, 3000 is arrow length
|
|||
|
//var hlightHelper = new THREE.HemisphereLightHelper(envlight, 10000, 1000);
|
|||
|
//ar.scene.add(hlightHelper);
|
|||
|
|
|||
|
//平行光,用于产生阴影
|
|||
|
var light = new THREE.DirectionalLight(0x222222);
|
|||
|
light.position.set(0, 1000, 2000);
|
|||
|
light.target.position.set(0, 0, 0);
|
|||
|
|
|||
|
|
|||
|
light.castShadow = true;
|
|||
|
light.shadowDarkness = 0.7;
|
|||
|
//light.shadowCameraNear = 2;
|
|||
|
//light.shadowCameraFar = 5000;
|
|||
|
light.shadowCameraLeft = -3000;
|
|||
|
light.shadowCameraRight = 3000;
|
|||
|
light.shadowCameraTop = 3000;
|
|||
|
light.shadowCameraBottom = -3000;
|
|||
|
//light.shadowCameraFov = 60000;
|
|||
|
light.shadowMapWidth = light.shadowMapHeight = 1024;
|
|||
|
|
|||
|
ar.scene.add(light);
|
|||
|
ar.light = light;
|
|||
|
|
|||
|
//ar.camera.updateMatrix();
|
|||
|
//var cameraHelper = new THREE.CameraHelper( light.shadow );
|
|||
|
//this.scene.add(cameraHelper);
|
|||
|
|
|||
|
//// 50 is helper size
|
|||
|
//dlightHelper = new THREE.DirectionalLightHelper(light, 500);
|
|||
|
//ar.scene.add(dlightHelper);
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
ar.dispose = function(){
|
|||
|
|
|||
|
var disposeObject = function(obj){
|
|||
|
for(var b in obj){
|
|||
|
if(typeof(obj[b]) === "function" && obj[b].name === "event"){
|
|||
|
obj[b] = undefined;
|
|||
|
}
|
|||
|
else if(typeof(obj[b]) === "function" && obj[b].length > 0){
|
|||
|
disposeObject(obj[b]);
|
|||
|
}
|
|||
|
else if(typeof(obj[b]) === "object" && b === "dispatch"){
|
|||
|
disposeObject(obj[b]);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var disposeNode = function(node)
|
|||
|
{
|
|||
|
if (node instanceof THREE.Camera)
|
|||
|
{
|
|||
|
node = undefined;
|
|||
|
}
|
|||
|
else if (node instanceof THREE.Light)
|
|||
|
{
|
|||
|
if (!node.dispose){
|
|||
|
disposeObject(node);
|
|||
|
}
|
|||
|
else
|
|||
|
node.dispose ();
|
|||
|
node = undefined;
|
|||
|
}
|
|||
|
else if (node instanceof THREE.Mesh)
|
|||
|
{
|
|||
|
if (node.geometry)
|
|||
|
{
|
|||
|
node.geometry.dispose ();
|
|||
|
node.geometry = undefined;
|
|||
|
delete node.geometry;
|
|||
|
}
|
|||
|
|
|||
|
if (node.material)
|
|||
|
{
|
|||
|
if (node.material instanceof THREE.MeshFaceMaterial)
|
|||
|
{
|
|||
|
$.each (node.material.materials, function (idx, mtrl)
|
|||
|
{
|
|||
|
if (!mtrl) return;
|
|||
|
mtrl.dispose();
|
|||
|
if (mtrl.map)
|
|||
|
{
|
|||
|
mtrl.map.dispose();
|
|||
|
mtrl.map = undefined;
|
|||
|
delete mtrl.map;
|
|||
|
}
|
|||
|
|
|||
|
if (mtrl.lightMap) mtrl.lightMap.dispose();
|
|||
|
if (mtrl.bumpMap) mtrl.bumpMap.dispose();
|
|||
|
if (mtrl.normalMap) mtrl.normalMap.dispose();
|
|||
|
if (mtrl.specularMap) mtrl.specularMap.dispose();
|
|||
|
if (mtrl.envMap) mtrl.envMap.dispose();
|
|||
|
|
|||
|
mtrl.dispose(); // disposes any programs associated with the material
|
|||
|
mtrl = undefined;
|
|||
|
delete mtrl;
|
|||
|
});
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (node.material.map)
|
|||
|
{
|
|||
|
node.material.map.dispose();
|
|||
|
node.material.map = undefined;
|
|||
|
delete node.material.map;
|
|||
|
}
|
|||
|
|
|||
|
if (node.material.lightMap) node.material.lightMap.dispose ();
|
|||
|
if (node.material.bumpMap) node.material.bumpMap.dispose ();
|
|||
|
if (node.material.normalMap) node.material.normalMap.dispose ();
|
|||
|
if (node.material.specularMap) node.material.specularMap.dispose ();
|
|||
|
if (node.material.envMap) node.material.envMap.dispose ();
|
|||
|
|
|||
|
node.material.dispose (); // disposes any programs associated with the material
|
|||
|
node.material = undefined;
|
|||
|
delete node.material;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
node = undefined;
|
|||
|
}
|
|||
|
else if (node instanceof THREE.Object3D)
|
|||
|
{
|
|||
|
node = undefined;
|
|||
|
delete node;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var disposeHierarchy = function(node, callback)
|
|||
|
{
|
|||
|
for (var i = node.children.length - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
var child = node.children[i];
|
|||
|
disposeHierarchy (child, callback);
|
|||
|
callback (child);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
//stop data pooling
|
|||
|
if (ar.provider) ar.provider.dispose();
|
|||
|
//remove event for controller
|
|||
|
$(window).off();
|
|||
|
$(window).unbind();
|
|||
|
$(document).off();
|
|||
|
$(document).unbind();
|
|||
|
$(ar.domId).off();
|
|||
|
$(ar.domId).unbind();
|
|||
|
if (ar.renderer) $(ar.renderer.domElement).off();
|
|||
|
|
|||
|
//stop animation
|
|||
|
TWEEN.removeAll();
|
|||
|
if (ar.aniframeId) window.cancelAnimationFrame(ar.aniframeId);
|
|||
|
//remove shapes
|
|||
|
// if (ar.shape3Ds){
|
|||
|
// ar.shape3Ds.forEach(function(shp){
|
|||
|
// if (shp.mesh){
|
|||
|
// ar.scene.remove(shp.mesh);
|
|||
|
// disposeHierarchy(shp.mesh, disposeNode);
|
|||
|
// }
|
|||
|
// });
|
|||
|
// disposeObject(ar.shape3Ds);
|
|||
|
// ar.shape3Ds = undefined;
|
|||
|
// delete ar.shape3Ds;
|
|||
|
// }
|
|||
|
|
|||
|
//remove scene
|
|||
|
if (ar.controls) ar.controls.dispose();
|
|||
|
if (ar.raycaster) disposeObject(ar.raycaster);
|
|||
|
// $.each(ar.scene.children, function(idx, obj) {
|
|||
|
// if (obj !== undefined) {
|
|||
|
// if (obj.geometry) {
|
|||
|
// obj.geometry.dispose();
|
|||
|
// }
|
|||
|
|
|||
|
// if (obj.material) {
|
|||
|
// if (obj.material instanceof THREE.MeshFaceMaterial) {
|
|||
|
// $.each(obj.material.materials, function(idx, obj) {
|
|||
|
// obj.dispose();
|
|||
|
// });
|
|||
|
// } else {
|
|||
|
// obj.material.dispose();
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
// if (obj.dispose) {
|
|||
|
// obj.dispose();
|
|||
|
// }
|
|||
|
// }
|
|||
|
// });
|
|||
|
|
|||
|
//clear all resource
|
|||
|
|
|||
|
if (ar.camera) disposeObject(ar.camera);
|
|||
|
//if (ar.scene) disposeHierarchy (ar.scene, disposeNode);
|
|||
|
if (ar.container) disposeObject(ar.container);
|
|||
|
|
|||
|
if (ar.renderer)
|
|||
|
{
|
|||
|
ar.renderer.forceContextLoss();
|
|||
|
ar.renderer.context = null;
|
|||
|
ar.renderer.domElement = null;
|
|||
|
disposeObject(ar.renderer);
|
|||
|
ar.renderer = null;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
doDispose(ar.scene);
|
|||
|
|
|||
|
function doDispose(obj) {
|
|||
|
if (obj !== null) {
|
|||
|
for (var i = 0; i < obj.children.length; i++) {
|
|||
|
doDispose(obj.children[i]);
|
|||
|
}
|
|||
|
if (obj.geometry) {
|
|||
|
obj.geometry.dispose();
|
|||
|
obj.geometry = undefined;
|
|||
|
}
|
|||
|
if (obj.material) {
|
|||
|
if (obj.material instanceof THREE.MeshFaceMaterial) {
|
|||
|
$.each(obj.material.materials, function(idx, o) {
|
|||
|
if (!o) return;
|
|||
|
if (o.map)
|
|||
|
{
|
|||
|
o.map.dispose();
|
|||
|
o.map = undefined;
|
|||
|
delete o.map;
|
|||
|
}
|
|||
|
o.dispose();
|
|||
|
});
|
|||
|
} else {
|
|||
|
obj.material.dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
if(obj.dispose) {
|
|||
|
obj.dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
obj = undefined;
|
|||
|
}
|
|||
|
|
|||
|
ar.scene = null;
|
|||
|
|
|||
|
disposeObject(ar);
|
|||
|
ar = undefined;
|
|||
|
};
|
|||
|
|
|||
|
ar.cartoon = function(type){
|
|||
|
if (type == "overview"){
|
|||
|
var position = {x:0,y:3000,z:0};
|
|||
|
var target = {x:0,y:0,z:-1};
|
|||
|
ar.tweenCamera(position, target);
|
|||
|
}
|
|||
|
|
|||
|
if (type == "veilview"){
|
|||
|
var position = {x:-3000,y:3000,z:-3000};
|
|||
|
var target = {x:0,y:0,z:0};
|
|||
|
ar.tweenCamera(position, target);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
ar.tweenCamera = function tweenCamera(position, target){
|
|||
|
//TWEEN.removeAll();
|
|||
|
|
|||
|
new TWEEN.Tween(ar.camera.position).to({
|
|||
|
x: position.x,
|
|||
|
y: position.y,
|
|||
|
z: position.z
|
|||
|
},3000).easing(TWEEN.Easing.Linear.None).onUpdate(function () {
|
|||
|
ar.camera.lookAt(target);
|
|||
|
}).onComplete(function () {
|
|||
|
}).start();
|
|||
|
};
|
|||
|
|
|||
|
ar.getShapeByMesh = function (mesh){
|
|||
|
if (!mesh) return;
|
|||
|
|
|||
|
var obj = mesh;
|
|||
|
while(!(obj.parent instanceof THREE.Scene)){
|
|||
|
obj = obj.parent;
|
|||
|
}
|
|||
|
|
|||
|
var selected;
|
|||
|
ar.shape3Ds.forEach(function(shp){
|
|||
|
if (shp.mesh === obj){
|
|||
|
selected = shp;
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return selected;
|
|||
|
};
|
|||
|
|
|||
|
ar.loadUnits = function(){
|
|||
|
ar.units = [
|
|||
|
{
|
|||
|
name : "floor",
|
|||
|
buildFloor: function(param){
|
|||
|
//因为SVG无法使用底图(只能使用UV贴图),作为地板非常难看。
|
|||
|
//这里取消平面自动地板生成功能(可生成不规则地板)限制为仅能使用矩形地板(使用BOX模拟)
|
|||
|
//所以下面代码注释掉:
|
|||
|
//var floorG = ar.transformSVGPath(param.path);
|
|||
|
//var planeMesh = ar.createShape(floorG, 0xdddddd, 0, 0, 0, Math.PI/2, 0, 0, 1);
|
|||
|
//group.add(planeMesh);
|
|||
|
//planeMesh.geometry.center();
|
|||
|
|
|||
|
var tileSize = 64;
|
|||
|
|
|||
|
var floorTexture = new THREE.TextureLoader().load(param.floorTexture);
|
|||
|
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
|
|||
|
floorTexture.repeat.set( param.floorWidth / tileSize, param.floorHeight / tileSize );
|
|||
|
|
|||
|
var floorMaterial = new THREE.MeshPhongMaterial( {
|
|||
|
map: floorTexture, side: THREE.DoubleSide} );
|
|||
|
|
|||
|
var floorGeometry = new THREE.PlaneGeometry(param.floorWidth, param.floorHeight,1,1);
|
|||
|
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
|
|||
|
floor.position.y = -0.5;
|
|||
|
floor.rotation.x = Math.PI / 2;
|
|||
|
|
|||
|
floor.receiveShadow = true;
|
|||
|
return floor;
|
|||
|
},
|
|||
|
create: function (param){
|
|||
|
//create an empty container
|
|||
|
var group = new THREE.Object3D();
|
|||
|
|
|||
|
var floor = this.buildFloor(param);
|
|||
|
group.add(floor);
|
|||
|
|
|||
|
//get enclosure lines
|
|||
|
|
|||
|
|
|||
|
var lines = [];
|
|||
|
|
|||
|
var lineX1 = {};
|
|||
|
lineX1.start = {x: -(param.floorWidth / 2), y:0, z: -(param.floorHeight / 2)};
|
|||
|
lineX1.end = {x: param.floorWidth / 2, y:0, z: -(param.floorHeight / 2)};
|
|||
|
lines.push(lineX1);
|
|||
|
|
|||
|
var lineX2 = {};
|
|||
|
lineX2.start = {x: -(param.floorWidth / 2), y:0, z: param.floorHeight / 2};
|
|||
|
lineX2.end = {x: param.floorWidth / 2, y:0, z: param.floorHeight / 2};
|
|||
|
lines.push(lineX2);
|
|||
|
|
|||
|
var lineX3 = {};
|
|||
|
lineX3.start = {x: -(param.floorWidth / 2), y:0, z: -(param.floorHeight / 2)};
|
|||
|
lineX3.end = {x: -(param.floorWidth / 2), y:0, z: param.floorHeight / 2};
|
|||
|
lines.push(lineX3);
|
|||
|
|
|||
|
var lineX4 = {};
|
|||
|
lineX4.start = {x: param.floorWidth / 2, y:0, z: -(param.floorHeight / 2)};
|
|||
|
lineX4.end = {x: param.floorWidth / 2, y:0, z: param.floorHeight / 2};
|
|||
|
lines.push(lineX4);
|
|||
|
|
|||
|
//build walls
|
|||
|
lines.forEach(function(line){
|
|||
|
var mold = ar.util.getMold(param.moldId);
|
|||
|
group.add(ar.util.buildWall(mold, line));
|
|||
|
});
|
|||
|
|
|||
|
return group;
|
|||
|
}
|
|||
|
},{
|
|||
|
name : "door",
|
|||
|
create: function (param) {
|
|||
|
|
|||
|
return ar.util.buildWallPart(param);
|
|||
|
}
|
|||
|
//},{
|
|||
|
// name : "window",
|
|||
|
// create: function (param) {
|
|||
|
// return ar.util.buildWallPart(param);
|
|||
|
// }
|
|||
|
},{
|
|||
|
name:"rack",
|
|||
|
create: function(param){
|
|||
|
|
|||
|
var mold = ar.util.getMold(param.moldId);
|
|||
|
|
|||
|
var faces = [];
|
|||
|
// order of faces: x+,x-,y+,y-,z+,z-
|
|||
|
var rightFace = ar.util.newFace(mold.faces.rightFace);
|
|||
|
faces.push(rightFace);
|
|||
|
var leftFace = ar.util.newFace(mold.faces.leftFace);
|
|||
|
faces.push(leftFace);
|
|||
|
var topFace = ar.util.newFace(mold.faces.topFace);
|
|||
|
faces.push(topFace);
|
|||
|
var bottomFace = ar.util.newFace(mold.faces.bottomFace);
|
|||
|
faces.push(bottomFace);
|
|||
|
var frontFace = ar.util.newFace(mold.faces.frontFace);
|
|||
|
faces.push(frontFace);
|
|||
|
var backFace = ar.util.newFace(mold.faces.backFace);
|
|||
|
faces.push(backFace);
|
|||
|
|
|||
|
var cubeMaterials = new THREE.MeshFaceMaterial(faces);
|
|||
|
var cubeGeometry = new THREE.CubeGeometry(
|
|||
|
mold.size.width, mold.size.high, mold.size.depth);
|
|||
|
|
|||
|
var cube = new THREE.Mesh(cubeGeometry, cubeMaterials);
|
|||
|
|
|||
|
cube.position.x = param.position.x;
|
|||
|
cube.position.y = mold.size.high / 2 + param.aboveGround;
|
|||
|
cube.position.z = param.position.z;
|
|||
|
|
|||
|
//if (param.angle > 0 )
|
|||
|
cube.rotateY( 0 - ar.util.radians(param.angle));
|
|||
|
cube.castShadow = true;
|
|||
|
return cube;
|
|||
|
}
|
|||
|
},{
|
|||
|
name:"line",
|
|||
|
create: function(param){
|
|||
|
|
|||
|
var geometry = new THREE.Geometry();
|
|||
|
param.lines.forEach(function(line){
|
|||
|
geometry.vertices.push(new THREE.Vector3(
|
|||
|
line.start.x,
|
|||
|
line.start.y,
|
|||
|
line.start.z
|
|||
|
));
|
|||
|
geometry.vertices.push(new THREE.Vector3(
|
|||
|
line.end.x,
|
|||
|
line.end.y,
|
|||
|
line.end.z
|
|||
|
));
|
|||
|
});
|
|||
|
|
|||
|
var m = new THREE.LineBasicMaterial({
|
|||
|
color: param.color,fog:true});
|
|||
|
|
|||
|
var line = new THREE.Line(geometry, m);
|
|||
|
|
|||
|
return line;
|
|||
|
}
|
|||
|
},{
|
|||
|
name:"flat",
|
|||
|
isFlat:true,
|
|||
|
create: function(param){
|
|||
|
var mold = ar.util.getMold(param.moldId);
|
|||
|
|
|||
|
var obj = ar.util.flatObject(param, mold,param.position, parseFloat(param.aboveGround));
|
|||
|
|
|||
|
return obj.mesh;
|
|||
|
}
|
|||
|
},{
|
|||
|
name:"wallPath",
|
|||
|
create: function(param){
|
|||
|
var group = new THREE.Object3D();
|
|||
|
var mold = ar.util.getMold(param.moldId);
|
|||
|
if (param.moldId !== "wallpath-null")
|
|||
|
{
|
|||
|
param.lines.forEach(function(line){
|
|||
|
group.add(ar.util.buildWall(mold, line));
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
//if (param.angle > 0 )
|
|||
|
group.rotateY( 0 - ar.util.radians(param.angle));
|
|||
|
return group;
|
|||
|
}
|
|||
|
},{
|
|||
|
name:"camera",
|
|||
|
create: function(param){
|
|||
|
//var transparentColor = 0xffffff;
|
|||
|
//var size = {x:64,y:64};
|
|||
|
//var imgurl = "img/3d/CCTV-icon.png";
|
|||
|
//
|
|||
|
//var obj = ar.util.flatObject(imgurl, transparentColor,
|
|||
|
// size,param.position);
|
|||
|
//
|
|||
|
//return obj.mesh;
|
|||
|
|
|||
|
var geometry = new THREE.SphereGeometry( 30, 16, 16 );
|
|||
|
var material = new THREE.MeshBasicMaterial( {
|
|||
|
map: THREE.ImageUtils.loadTexture('img/3d/global.jpg')});
|
|||
|
var sphere = new THREE.Mesh( geometry, material );
|
|||
|
sphere.position.x = param.position.x;
|
|||
|
sphere.position.y = param.position.y;
|
|||
|
sphere.position.z = param.position.z;
|
|||
|
return sphere;
|
|||
|
}
|
|||
|
}
|
|||
|
];
|
|||
|
};
|
|||
|
|
|||
|
ar.shape3DClass = {
|
|||
|
mesh: undefined,
|
|||
|
tws:[],
|
|||
|
defaultColors:[],
|
|||
|
update:function(status){
|
|||
|
if (status.state === this.alarmLevel) return;
|
|||
|
|
|||
|
this.alarmLevel = status.state;
|
|||
|
|
|||
|
var needRemove=null;
|
|||
|
|
|||
|
this.tws.forEach(function(fso){
|
|||
|
if (fso.id === this.id)
|
|||
|
{
|
|||
|
fso.twarray.forEach(function(tw){
|
|||
|
tw.stop();
|
|||
|
});
|
|||
|
needRemove = fso;
|
|||
|
}
|
|||
|
});
|
|||
|
this.tws = _.without(this.tws, needRemove);
|
|||
|
|
|||
|
this.resetColor();
|
|||
|
|
|||
|
if (this.alarmLevel == 0) return;
|
|||
|
this.shining(this.alarmLevel);
|
|||
|
},
|
|||
|
resetColor:function(){
|
|||
|
var that = this;
|
|||
|
if (that.mesh.material instanceof THREE.MultiMaterial)
|
|||
|
{
|
|||
|
var i=0;
|
|||
|
that.mesh.material.materials.forEach(
|
|||
|
function(m) {
|
|||
|
m.color = {r:1,g:1,b:1};
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
shining: function(alarmLevel){
|
|||
|
var that = this;
|
|||
|
var color = {r:1,g:1,b:1};
|
|||
|
switch(alarmLevel)
|
|||
|
{
|
|||
|
case "1":
|
|||
|
color={r:0,g:0,b:2};
|
|||
|
break;
|
|||
|
case "2":
|
|||
|
color={r:2,g:2,b:0};
|
|||
|
break;
|
|||
|
case "3":
|
|||
|
color={r:2, g: 1, b:0};
|
|||
|
break;
|
|||
|
case "4":
|
|||
|
color={r:2, g: 0, b:0};
|
|||
|
break;
|
|||
|
default:
|
|||
|
}
|
|||
|
|
|||
|
if (that.mesh.material instanceof THREE.MultiMaterial)
|
|||
|
{
|
|||
|
var kso = {id:that.id,twarray:[]};
|
|||
|
that.mesh.material.materials.forEach(function(m){
|
|||
|
var tw = new TWEEN.Tween(m.color)
|
|||
|
.to(color, 3000)
|
|||
|
.repeat(Infinity)
|
|||
|
.easing(TWEEN.Easing.Quartic.InOut)
|
|||
|
.start();
|
|||
|
|
|||
|
kso.twarray.push(tw);
|
|||
|
|
|||
|
});
|
|||
|
that.tws.push(kso);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
ar.util = {};
|
|||
|
ar.util.createShape = function ( shape, color, x, y, z, rx, ry, rz, s ) {
|
|||
|
// flat shape like svg
|
|||
|
|
|||
|
var geometry = new THREE.ShapeGeometry( shape );
|
|||
|
var material = new THREE.MeshBasicMaterial({
|
|||
|
color: color,
|
|||
|
side: THREE.DoubleSide,
|
|||
|
overdraw: true
|
|||
|
});
|
|||
|
|
|||
|
var mesh = new THREE.Mesh( geometry, material );
|
|||
|
mesh.position.set( x, y, z );
|
|||
|
mesh.rotation.set( rx, ry, rz );
|
|||
|
mesh.scale.set( s, s, s );
|
|||
|
|
|||
|
return mesh;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.transformSVGPath = function (pathStr) {
|
|||
|
|
|||
|
const DIGIT_0 = 48, DIGIT_9 = 57, COMMA = 44, SPACE = 32, PERIOD = 46,
|
|||
|
MINUS = 45;
|
|||
|
|
|||
|
var path = new THREE.Shape();
|
|||
|
|
|||
|
var idx = 1, len = pathStr.length, activeCmd,
|
|||
|
x = 0, y = 0, nx = 0, ny = 0, firstX = null, firstY = null,
|
|||
|
x1 = 0, x2 = 0, y1 = 0, y2 = 0,
|
|||
|
rx = 0, ry = 0, xar = 0, laf = 0, sf = 0, cx, cy;
|
|||
|
|
|||
|
function eatNum() {
|
|||
|
var sidx, c, isFloat = false, s;
|
|||
|
// eat delims
|
|||
|
while (idx < len) {
|
|||
|
c = pathStr.charCodeAt(idx);
|
|||
|
if (c !== COMMA && c !== SPACE)
|
|||
|
break;
|
|||
|
idx++;
|
|||
|
}
|
|||
|
if (c === MINUS)
|
|||
|
sidx = idx++;
|
|||
|
else
|
|||
|
sidx = idx;
|
|||
|
// eat number
|
|||
|
while (idx < len) {
|
|||
|
c = pathStr.charCodeAt(idx);
|
|||
|
if (DIGIT_0 <= c && c <= DIGIT_9) {
|
|||
|
idx++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
else if (c === PERIOD) {
|
|||
|
idx++;
|
|||
|
isFloat = true;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
s = pathStr.substring(sidx, idx);
|
|||
|
return isFloat ? parseFloat(s) : parseInt(s);
|
|||
|
}
|
|||
|
|
|||
|
s = pathStr.substring(sidx);
|
|||
|
return isFloat ? parseFloat(s) : parseInt(s);
|
|||
|
}
|
|||
|
|
|||
|
function nextIsNum() {
|
|||
|
var c;
|
|||
|
// do permanently eat any delims...
|
|||
|
while (idx < len) {
|
|||
|
c = pathStr.charCodeAt(idx);
|
|||
|
if (c !== COMMA && c !== SPACE)
|
|||
|
break;
|
|||
|
idx++;
|
|||
|
}
|
|||
|
c = pathStr.charCodeAt(idx);
|
|||
|
return (c === MINUS || (DIGIT_0 <= c && c <= DIGIT_9));
|
|||
|
}
|
|||
|
|
|||
|
var canRepeat;
|
|||
|
activeCmd = pathStr[0];
|
|||
|
while (idx <= len) {
|
|||
|
canRepeat = true;
|
|||
|
switch (activeCmd) {
|
|||
|
// moveto commands, become lineto's if repeated
|
|||
|
case 'M':
|
|||
|
x = eatNum();
|
|||
|
y = eatNum();
|
|||
|
path.moveTo(x, y);
|
|||
|
activeCmd = 'L';
|
|||
|
break;
|
|||
|
case 'm':
|
|||
|
x += eatNum();
|
|||
|
y += eatNum();
|
|||
|
path.moveTo(x, y);
|
|||
|
activeCmd = 'l';
|
|||
|
break;
|
|||
|
case 'Z':
|
|||
|
case 'z':
|
|||
|
canRepeat = false;
|
|||
|
if (x !== firstX || y !== firstY)
|
|||
|
path.lineTo(firstX, firstY);
|
|||
|
break;
|
|||
|
// - lines!
|
|||
|
case 'L':
|
|||
|
case 'H':
|
|||
|
case 'V':
|
|||
|
nx = (activeCmd === 'V') ? x : eatNum();
|
|||
|
ny = (activeCmd === 'H') ? y : eatNum();
|
|||
|
path.lineTo(nx, ny);
|
|||
|
x = nx;
|
|||
|
y = ny;
|
|||
|
break;
|
|||
|
case 'l':
|
|||
|
case 'h':
|
|||
|
case 'v':
|
|||
|
nx = (activeCmd === 'v') ? x : (x + eatNum());
|
|||
|
ny = (activeCmd === 'h') ? y : (y + eatNum());
|
|||
|
path.lineTo(nx, ny);
|
|||
|
x = nx;
|
|||
|
y = ny;
|
|||
|
break;
|
|||
|
// - cubic bezier
|
|||
|
case 'C':
|
|||
|
x1 = eatNum(); y1 = eatNum();
|
|||
|
case 'S':
|
|||
|
if (activeCmd === 'S') {
|
|||
|
x1 = 2 * x - x2; y1 = 2 * y - y2;
|
|||
|
}
|
|||
|
x2 = eatNum();
|
|||
|
y2 = eatNum();
|
|||
|
nx = eatNum();
|
|||
|
ny = eatNum();
|
|||
|
path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
|
|||
|
x = nx; y = ny;
|
|||
|
break;
|
|||
|
case 'c':
|
|||
|
x1 = x + eatNum();
|
|||
|
y1 = y + eatNum();
|
|||
|
case 's':
|
|||
|
if (activeCmd === 's') {
|
|||
|
x1 = 2 * x - x2;
|
|||
|
y1 = 2 * y - y2;
|
|||
|
}
|
|||
|
x2 = x + eatNum();
|
|||
|
y2 = y + eatNum();
|
|||
|
nx = x + eatNum();
|
|||
|
ny = y + eatNum();
|
|||
|
path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
|
|||
|
x = nx; y = ny;
|
|||
|
break;
|
|||
|
// - quadratic bezier
|
|||
|
case 'Q':
|
|||
|
x1 = eatNum(); y1 = eatNum();
|
|||
|
case 'T':
|
|||
|
if (activeCmd === 'T') {
|
|||
|
x1 = 2 * x - x1;
|
|||
|
y1 = 2 * y - y1;
|
|||
|
}
|
|||
|
nx = eatNum();
|
|||
|
ny = eatNum();
|
|||
|
path.quadraticCurveTo(x1, y1, nx, ny);
|
|||
|
x = nx;
|
|||
|
y = ny;
|
|||
|
break;
|
|||
|
case 'q':
|
|||
|
x1 = x + eatNum();
|
|||
|
y1 = y + eatNum();
|
|||
|
case 't':
|
|||
|
if (activeCmd === 't') {
|
|||
|
x1 = 2 * x - x1;
|
|||
|
y1 = 2 * y - y1;
|
|||
|
}
|
|||
|
nx = x + eatNum();
|
|||
|
ny = y + eatNum();
|
|||
|
path.quadraticCurveTo(x1, y1, nx, ny);
|
|||
|
x = nx; y = ny;
|
|||
|
break;
|
|||
|
// - elliptical arc
|
|||
|
case 'A':
|
|||
|
rx = eatNum();
|
|||
|
ry = eatNum();
|
|||
|
xar = eatNum() * DEGS_TO_RADS;
|
|||
|
laf = eatNum();
|
|||
|
sf = eatNum();
|
|||
|
nx = eatNum();
|
|||
|
ny = eatNum();
|
|||
|
if (rx !== ry) {
|
|||
|
console.warn("Forcing elliptical arc to be a circular one :(",
|
|||
|
rx, ry);
|
|||
|
}
|
|||
|
// SVG implementation notes does all the math for us! woo!
|
|||
|
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
|||
|
// step1, using x1 as x1'
|
|||
|
x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
|
|||
|
y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
|
|||
|
// step 2, using x2 as cx'
|
|||
|
var norm = Math.sqrt(
|
|||
|
(rx*rx * ry*ry - rx*rx * y1*y1 - ry*ry * x1*x1) /
|
|||
|
(rx*rx * y1*y1 + ry*ry * x1*x1));
|
|||
|
if (laf === sf)
|
|||
|
norm = -norm;
|
|||
|
x2 = norm * rx * y1 / ry;
|
|||
|
y2 = norm * -ry * x1 / rx;
|
|||
|
// step 3
|
|||
|
cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
|
|||
|
cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
|
|||
|
|
|||
|
var u = new THREE.Vector2(1, 0),
|
|||
|
v = new THREE.Vector2((x1 - x2) / rx,
|
|||
|
(y1 - y2) / ry);
|
|||
|
var startAng = Math.acos(u.dot(v) / u.length() / v.length());
|
|||
|
if (u.x * v.y - u.y * v.x < 0)
|
|||
|
startAng = -startAng;
|
|||
|
|
|||
|
// we can reuse 'v' from start angle as our 'u' for delta angle
|
|||
|
u.x = (-x1 - x2) / rx;
|
|||
|
u.y = (-y1 - y2) / ry;
|
|||
|
|
|||
|
var deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
|
|||
|
// This normalization ends up making our curves fail to triangulate...
|
|||
|
if (v.x * u.y - v.y * u.x < 0)
|
|||
|
deltaAng = -deltaAng;
|
|||
|
if (!sf && deltaAng > 0)
|
|||
|
deltaAng -= Math.PI * 2;
|
|||
|
if (sf && deltaAng < 0)
|
|||
|
deltaAng += Math.PI * 2;
|
|||
|
|
|||
|
path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
|
|||
|
x = nx;
|
|||
|
y = ny;
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new Error("weird path command: " + activeCmd);
|
|||
|
}
|
|||
|
if (firstX === null) {
|
|||
|
firstX = x;
|
|||
|
firstY = y;
|
|||
|
}
|
|||
|
// just reissue the command
|
|||
|
if (canRepeat && nextIsNum())
|
|||
|
continue;
|
|||
|
activeCmd = pathStr[idx++];
|
|||
|
}
|
|||
|
|
|||
|
return path;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.gradientTexture = function (){
|
|||
|
function generateMeterial() {
|
|||
|
|
|||
|
var size = 512;
|
|||
|
|
|||
|
// create canvas
|
|||
|
var canvas = document.createElement( 'canvas' );
|
|||
|
canvas.width = size;
|
|||
|
canvas.height = size;
|
|||
|
|
|||
|
// get context
|
|||
|
var context = canvas.getContext( '2d' );
|
|||
|
|
|||
|
// draw gradient
|
|||
|
context.rect( 0, 0, size, size );
|
|||
|
var gradient = context.createLinearGradient( 0, 0, 0, size );
|
|||
|
gradient.addColorStop(0, '#99ddff'); // light blue
|
|||
|
gradient.addColorStop(1, 'transparent'); // dark blue
|
|||
|
context.fillStyle = gradient;
|
|||
|
context.fill();
|
|||
|
|
|||
|
var texture = new THREE.Texture( canvas );
|
|||
|
texture.needsUpdate = true;
|
|||
|
var material = new THREE.MeshBasicMaterial( {
|
|||
|
map: texture, transparent: true } );
|
|||
|
|
|||
|
return material;
|
|||
|
}
|
|||
|
|
|||
|
return generateMeterial();
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
ar.util.flatObject = function(param, mold, position,aboveGround){
|
|||
|
|
|||
|
var material = ar.util.newFace(mold.face);
|
|||
|
|
|||
|
var geometry = new THREE.PlaneGeometry( mold.size.width, mold.size.high, 1, 1 );
|
|||
|
|
|||
|
var flat = new THREE.Mesh(geometry, material);
|
|||
|
|
|||
|
flat.position.x = position.x;
|
|||
|
flat.position.y = mold.size.high / 2 + aboveGround;
|
|||
|
flat.position.z = position.z;
|
|||
|
|
|||
|
var shp = _.extend({}, ar.shape3DClass);
|
|||
|
shp.mesh = flat;
|
|||
|
shp.isFlat = true;
|
|||
|
shp.id = _.uniqueId();
|
|||
|
ar.shape3Ds.push(shp);
|
|||
|
|
|||
|
shp.config = param;
|
|||
|
|
|||
|
return shp;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.buildWall = function(mold, segment){
|
|||
|
|
|||
|
function updateLine(segment){
|
|||
|
if (segment.start.x === segment.end.x){
|
|||
|
segment.length = Math.abs(segment.end.z - segment.start.z);
|
|||
|
segment.direct = "Z";
|
|||
|
}
|
|||
|
if (segment.start.z === segment.end.z){
|
|||
|
segment.length = Math.abs(segment.end.x - segment.start.x);
|
|||
|
segment.direct = "X";
|
|||
|
}
|
|||
|
return segment;
|
|||
|
}
|
|||
|
|
|||
|
var line = updateLine(segment);
|
|||
|
|
|||
|
var sideMaterial = ar.util.newFace(mold.faces.sideFace,line.length);
|
|||
|
var wallMaterial = sideMaterial;
|
|||
|
var topMaterial = ar.util.newFace(mold.faces.topFace, line.length);
|
|||
|
|
|||
|
var xlen,ylen,zlen,xm,ym,zm,px,py,pz;
|
|||
|
|
|||
|
ylen = mold.size.high;
|
|||
|
py = ylen/2;
|
|||
|
|
|||
|
if (line.direct === "X")
|
|||
|
{
|
|||
|
xlen = line.length + mold.size.width - 0.1;
|
|||
|
zlen = mold.size.width;
|
|||
|
zm = wallMaterial;
|
|||
|
ym = topMaterial;
|
|||
|
xm = sideMaterial;
|
|||
|
if (line.start.x < line.end.x)
|
|||
|
px = line.length/ 2 + line.start.x;
|
|||
|
if (line.start.x > line.end.x)
|
|||
|
px = line.start.x - line.length/2;
|
|||
|
pz = line.start.z;
|
|||
|
}
|
|||
|
|
|||
|
if (line.direct === "Z")
|
|||
|
{
|
|||
|
zlen = line.length + mold.size.width / 2 - 0.1;
|
|||
|
xlen = mold.size.width;
|
|||
|
xm = wallMaterial;
|
|||
|
zm = sideMaterial;
|
|||
|
ym = topMaterial;
|
|||
|
if (line.start.z > line.end.z)
|
|||
|
pz = line.start.z - line.length / 2;
|
|||
|
if (line.start.z < line.end.z)
|
|||
|
pz = line.length /2 + line.start.z;
|
|||
|
px = line.start.x;
|
|||
|
}
|
|||
|
|
|||
|
var wall = new THREE.Mesh(new THREE.CubeGeometry(xlen,ylen,zlen),
|
|||
|
new THREE.MeshFaceMaterial(
|
|||
|
[
|
|||
|
xm, // +x
|
|||
|
xm, // -x
|
|||
|
ym, // +y
|
|||
|
ym, // -y
|
|||
|
zm, // +z
|
|||
|
zm // -z
|
|||
|
]));
|
|||
|
|
|||
|
wall.position.x = px;
|
|||
|
wall.position.y = py;
|
|||
|
wall.position.z = pz;
|
|||
|
wall.castShadow = true;
|
|||
|
wall.receiveShadow = true;
|
|||
|
return wall;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.buildWallPart = function(param){
|
|||
|
var mold = ar.util.getMold(param.moldId);
|
|||
|
|
|||
|
//var doorMaterial = ar.util.newFace(mold.faces.topFace);
|
|||
|
var frontMaterial = ar.util.newFace(mold.faces.frontFace);
|
|||
|
var backMaterial = ar.util.newFace(mold.faces.backFace);
|
|||
|
|
|||
|
var sideMaterial = ar.util.newFace(mold.faces.sideFace);
|
|||
|
|
|||
|
var xlen,ylen,zlen,xm1,xm2,ym1,ym2,zm1,zm2,px,py,pz;
|
|||
|
|
|||
|
ylen = mold.size.high;
|
|||
|
py = mold.size.high /2 + param.position.y;
|
|||
|
|
|||
|
if (param.direct === "X")
|
|||
|
{
|
|||
|
xlen = mold.size.width;
|
|||
|
zlen = mold.size.depth;
|
|||
|
zm1 = frontMaterial;
|
|||
|
zm2 = backMaterial;
|
|||
|
ym1 = sideMaterial;
|
|||
|
ym2 = sideMaterial;
|
|||
|
xm1 = sideMaterial;
|
|||
|
xm2 = sideMaterial;
|
|||
|
px = param.position.x;
|
|||
|
pz = param.position.z;
|
|||
|
}
|
|||
|
|
|||
|
if (param.direct === "Z")
|
|||
|
{
|
|||
|
zlen = mold.size.width;
|
|||
|
xlen = mold.size.depth;
|
|||
|
xm1 = frontMaterial;
|
|||
|
xm2 = backMaterial;
|
|||
|
zm1 = sideMaterial;
|
|||
|
zm2 = sideMaterial;
|
|||
|
ym1 = sideMaterial;
|
|||
|
ym2 = sideMaterial;
|
|||
|
pz = param.position.z;
|
|||
|
px = param.position.x;
|
|||
|
}
|
|||
|
|
|||
|
var door = new THREE.Mesh(new THREE.CubeGeometry(xlen,ylen,zlen),
|
|||
|
new THREE.MeshFaceMaterial(
|
|||
|
[
|
|||
|
xm1, // +x
|
|||
|
xm2, // -x
|
|||
|
ym1, // +y
|
|||
|
ym2, // -y
|
|||
|
zm1, // +z
|
|||
|
zm2 // -z
|
|||
|
]));
|
|||
|
|
|||
|
door.position.x = px;
|
|||
|
door.position.y = py;
|
|||
|
door.position.z = pz;
|
|||
|
|
|||
|
return door;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.getMold = function(id){
|
|||
|
var res;
|
|||
|
molds.forEach(function(m){
|
|||
|
if (m.id === id) res = m;
|
|||
|
});
|
|||
|
|
|||
|
return res;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.radians = function(degrees) {
|
|||
|
return degrees * Math.PI / 180;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.newFace = function(cfg, faceSize){
|
|||
|
|
|||
|
var param = {};
|
|||
|
|
|||
|
if (cfg.texture) {
|
|||
|
param.map = new THREE.TextureLoader().load( cfg.texture );
|
|||
|
|
|||
|
if (cfg.tileWay){
|
|||
|
param.map.wrapS = param.map.wrapT = THREE.RepeatWrapping;
|
|||
|
var walltileSize = cfg.textureSize;
|
|||
|
|
|||
|
if (cfg.tileWay == "H")
|
|||
|
param.map.repeat.set( faceSize / walltileSize, 1);
|
|||
|
|
|||
|
if (cfg.tileWay == "T")
|
|||
|
param.map.repeat.set( faceSize / walltileSize, faceSize / walltileSize);
|
|||
|
|
|||
|
if (cfg.tileWay == "V")
|
|||
|
param.map.repeat.set(1, faceSize / walltileSize);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (cfg.side) param.side = cfg.side;
|
|||
|
if (cfg.color) param.color = new THREE.Color(cfg.color);
|
|||
|
|
|||
|
if (cfg.transparent) param.transparent = cfg.transparent;
|
|||
|
|
|||
|
var material = new THREE.MeshPhongMaterial(param);
|
|||
|
|
|||
|
if (cfg.opacity) {
|
|||
|
material.opacity = cfg.opacity;
|
|||
|
}
|
|||
|
else{
|
|||
|
material.opacity = 1;
|
|||
|
}
|
|||
|
if (material.opacity !== 1) material.depthWrite = false;
|
|||
|
|
|||
|
return material;
|
|||
|
};
|
|||
|
|
|||
|
ar.util.maskColor = function(mesh, color){
|
|||
|
if (!mesh) return;
|
|||
|
try {
|
|||
|
if (mesh.material instanceof THREE.MeshPhongMaterial)
|
|||
|
{
|
|||
|
mesh.material.emissive.setHex( color );
|
|||
|
//mesh.material.color.setHex( color );
|
|||
|
}
|
|||
|
|
|||
|
if (mesh.material instanceof THREE.MultiMaterial)
|
|||
|
{
|
|||
|
mesh.material.materials.forEach(function(m){
|
|||
|
//m.color.setHex( color );
|
|||
|
m.emissive.setHex( color );
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
catch(err) {
|
|||
|
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
ar.util.getMaskColor = function(mesh){
|
|||
|
if (!mesh) return;
|
|||
|
if (mesh.material instanceof THREE.MeshPhongMaterial)
|
|||
|
{
|
|||
|
return mesh.material.emissive.getHex();
|
|||
|
}
|
|||
|
|
|||
|
if (mesh.material instanceof THREE.MultiMaterial)
|
|||
|
{
|
|||
|
return mesh.material.materials[0].emissive.getHex();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
ar.provider = {
|
|||
|
collectBinding : function(){
|
|||
|
var res = [];
|
|||
|
|
|||
|
ar.shape3Ds.forEach(function(shp){
|
|||
|
if (shp.config.bindings.length > 0)
|
|||
|
{
|
|||
|
var pack = { id:shp.id, bs:shp.config.bindings};
|
|||
|
res.push(pack);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return res;
|
|||
|
},
|
|||
|
start : function(){
|
|||
|
if (!ar.options.shell) return;
|
|||
|
|
|||
|
var bindingSet = this.collectBinding();
|
|||
|
|
|||
|
//http ask for result by interval
|
|||
|
this.stop = ar.options.shell.$interval(function() {
|
|||
|
//get data and refresh shapes status
|
|||
|
ar.options.shell.$srv.getData(bindingSet).then(function(data){
|
|||
|
ar.shape3Ds.forEach(function(shp){
|
|||
|
var status = _.find(data, function(item){
|
|||
|
return item.id === shp.id;
|
|||
|
});
|
|||
|
|
|||
|
if (status) shp.update(status);
|
|||
|
});
|
|||
|
});
|
|||
|
}, 5000);
|
|||
|
},
|
|||
|
dispose :function(){
|
|||
|
if (!ar.options.shell) return;
|
|||
|
if (this.stop)
|
|||
|
ar.options.shell.$interval.cancel(this.stop);
|
|||
|
|
|||
|
ar.options.shell.$srv = undefined;
|
|||
|
ar.options.shell.$interval = undefined;
|
|||
|
ar.options.shell.$location = undefined;
|
|||
|
this.stop = undefined;
|
|||
|
}
|
|||
|
};
|
|||
|
///////// create main code here /////////
|
|||
|
ar.init(id);
|
|||
|
ar.loadUnits();
|
|||
|
if (config)
|
|||
|
ar.load(config);
|
|||
|
else
|
|||
|
ar.load();
|
|||
|
|
|||
|
if (options)
|
|||
|
ar.options = _.extend(ar.options, options);
|
|||
|
|
|||
|
//start 3D time line
|
|||
|
ar.animate();
|
|||
|
|
|||
|
ar.provider.start();
|
|||
|
return ar;
|
|||
|
}
|
|||
|
};
|