Forráskód Böngészése

fix: 准备更新three做动画

xzw 5 hónapja
szülő
commit
9c29fed68d

+ 481 - 0
libs/shapefile/shapefile.js

@@ -0,0 +1,481 @@
+// https://github.com/mbostock/shapefile Version 0.6.2. Copyright 2017 Mike Bostock.
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+	typeof define === 'function' && define.amd ? define(['exports'], factory) :
+	(factory((global.shapefile = global.shapefile || {})));
+}(this, (function (exports) { 'use strict';
+
+var array_cancel = function() {
+  this._array = null;
+  return Promise.resolve();
+};
+
+var array_read = function() {
+  var array = this._array;
+  this._array = null;
+  return Promise.resolve(array ? {done: false, value: array} : {done: true, value: undefined});
+};
+
+function array(array) {
+  return new ArraySource(array instanceof Uint8Array ? array : new Uint8Array(array));
+}
+
+function ArraySource(array) {
+  this._array = array;
+}
+
+ArraySource.prototype.read = array_read;
+ArraySource.prototype.cancel = array_cancel;
+
+var fetchPath = function(url) {
+  return fetch(url).then(function(response) {
+    return response.body && response.body.getReader
+        ? response.body.getReader()
+        : response.arrayBuffer().then(array);
+  });
+};
+
+var requestPath = function(url) {
+  return new Promise(function(resolve, reject) {
+    var request = new XMLHttpRequest;
+    request.responseType = "arraybuffer";
+    request.onload = function() { resolve(array(request.response)); };
+    request.onerror = reject;
+    request.ontimeout = reject;
+    request.open("GET", url, true);
+    request.send();
+  });
+};
+
+function path(path) {
+  return (typeof fetch === "function" ? fetchPath : requestPath)(path);
+}
+
+function stream(source) {
+  return typeof source.read === "function" ? source : source.getReader();
+}
+
+var empty = new Uint8Array(0);
+
+var slice_cancel = function() {
+  return this._source.cancel();
+};
+
+function concat(a, b) {
+  if (!a.length) return b;
+  if (!b.length) return a;
+  var c = new Uint8Array(a.length + b.length);
+  c.set(a);
+  c.set(b, a.length);
+  return c;
+}
+
+var slice_read = function() {
+  var that = this, array = that._array.subarray(that._index);
+  return that._source.read().then(function(result) {
+    that._array = empty;
+    that._index = 0;
+    return result.done ? (array.length > 0
+        ? {done: false, value: array}
+        : {done: true, value: undefined})
+        : {done: false, value: concat(array, result.value)};
+  });
+};
+
+var slice_slice = function(length) {
+  if ((length |= 0) < 0) throw new Error("invalid length");
+  var that = this, index = this._array.length - this._index;
+
+  // If the request fits within the remaining buffer, resolve it immediately.
+  if (this._index + length <= this._array.length) {
+    return Promise.resolve(this._array.subarray(this._index, this._index += length));
+  }
+
+  // Otherwise, read chunks repeatedly until the request is fulfilled.
+  var array = new Uint8Array(length);
+  array.set(this._array.subarray(this._index));
+  return (function read() {
+    return that._source.read().then(function(result) {
+
+      // When done, it’s possible the request wasn’t fully fullfilled!
+      // If so, the pre-allocated array is too big and needs slicing.
+      if (result.done) {
+        that._array = empty;
+        that._index = 0;
+        return index > 0 ? array.subarray(0, index) : null;
+      }
+
+      // If this chunk fulfills the request, return the resulting array.
+      if (index + result.value.length >= length) {
+        that._array = result.value;
+        that._index = length - index;
+        array.set(result.value.subarray(0, length - index), index);
+        return array;
+      }
+
+      // Otherwise copy this chunk into the array, then read the next chunk.
+      array.set(result.value, index);
+      index += result.value.length;
+      return read();
+    });
+  })();
+};
+
+function slice(source) {
+  return typeof source.slice === "function" ? source :
+      new SliceSource(typeof source.read === "function" ? source
+          : source.getReader());
+}
+
+function SliceSource(source) {
+  this._source = source;
+  this._array = empty;
+  this._index = 0;
+}
+
+SliceSource.prototype.read = slice_read;
+SliceSource.prototype.slice = slice_slice;
+SliceSource.prototype.cancel = slice_cancel;
+
+var dbf_cancel = function() {
+  return this._source.cancel();
+};
+
+var readBoolean = function(value) {
+  return /^[nf]$/i.test(value) ? false
+      : /^[yt]$/i.test(value) ? true
+      : null;
+};
+
+var readDate = function(value) {
+  return new Date(+value.substring(0, 4), value.substring(4, 6) - 1, +value.substring(6, 8));
+};
+
+var readNumber = function(value) {
+  return !(value = value.trim()) || isNaN(value = +value) ? null : value;
+};
+
+var readString = function(value) {
+  return value.trim() || null;
+};
+
+var types = {
+  B: readNumber,
+  C: readString,
+  D: readDate,
+  F: readNumber,
+  L: readBoolean,
+  M: readNumber,
+  N: readNumber
+};
+
+var dbf_read = function() {
+  var that = this, i = 1;
+  return that._source.slice(that._recordLength).then(function(value) {
+    return value && (value[0] !== 0x1a) ? {done: false, value: that._fields.reduce(function(p, f) {
+      p[f.name] = types[f.type](that._decode(value.subarray(i, i += f.length)));
+      return p;
+    }, {})} : {done: true, value: undefined};
+  });
+};
+
+var view = function(array) {
+  return new DataView(array.buffer, array.byteOffset, array.byteLength);
+};
+
+var dbf = function(source, decoder) {
+  source = slice(source);
+  return source.slice(32).then(function(array) {
+    var head = view(array);
+    return source.slice(head.getUint16(8, true) - 32).then(function(array) {
+      return new Dbf(source, decoder, head, view(array));
+    });
+  });
+};
+
+function Dbf(source, decoder, head, body) {
+  this._source = source;
+  this._decode = decoder.decode.bind(decoder);
+  this._recordLength = head.getUint16(10, true);
+  this._fields = [];
+  for (var n = 0; body.getUint8(n) !== 0x0d; n += 32) {
+    for (var j = 0; j < 11; ++j) if (body.getUint8(n + j) === 0) break;
+    this._fields.push({
+      name: this._decode(new Uint8Array(body.buffer, body.byteOffset + n, j)),
+      type: String.fromCharCode(body.getUint8(n + 11)),
+      length: body.getUint8(n + 16)
+    });
+  }
+}
+
+var prototype = Dbf.prototype;
+prototype.read = dbf_read;
+prototype.cancel = dbf_cancel;
+
+function cancel() {
+  return this._source.cancel();
+}
+
+var readMultiPoint = function(record) {
+  var i = 40, j, n = record.getInt32(36, true), coordinates = new Array(n);
+  for (j = 0; j < n; ++j, i += 16) coordinates[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
+  return {type: "MultiPoint", coordinates: coordinates};
+};
+
+var readNull = function() {
+  return null;
+};
+
+var readPoint = function(record) {
+  return {type: "Point", coordinates: [record.getFloat64(4, true), record.getFloat64(12, true)]};
+};
+
+var readPolygon = function(record) {
+  var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m), polygons = [], holes = [];
+  for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
+  for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
+
+  parts.forEach(function(i, j) {
+    var ring = points.slice(i, parts[j + 1]);
+    if (ringClockwise(ring)) polygons.push([ring]);
+    else holes.push(ring);
+  });
+
+  holes.forEach(function(hole) {
+    polygons.some(function(polygon) {
+      if (ringContainsSome(polygon[0], hole)) {
+        polygon.push(hole);
+        return true;
+      }
+    }) || polygons.push([hole]);
+  });
+
+  return polygons.length === 1
+      ? {type: "Polygon", coordinates: polygons[0]}
+      : {type: "MultiPolygon", coordinates: polygons};
+};
+
+function ringClockwise(ring) {
+  if ((n = ring.length) < 4) return false;
+  var i = 0, n, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
+  while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
+  return area >= 0;
+}
+
+function ringContainsSome(ring, hole) {
+  var i = -1, n = hole.length, c;
+  while (++i < n) {
+    if (c = ringContains(ring, hole[i])) {
+      return c > 0;
+    }
+  }
+  return false;
+}
+
+function ringContains(ring, point) {
+  var x = point[0], y = point[1], contains = -1;
+  for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) {
+    var pi = ring[i], xi = pi[0], yi = pi[1],
+        pj = ring[j], xj = pj[0], yj = pj[1];
+    if (segmentContains(pi, pj, point)) {
+      return 0;
+    }
+    if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) {
+      contains = -contains;
+    }
+  }
+  return contains;
+}
+
+function segmentContains(p0, p1, p2) {
+  var x20 = p2[0] - p0[0], y20 = p2[1] - p0[1];
+  if (x20 === 0 && y20 === 0) return true;
+  var x10 = p1[0] - p0[0], y10 = p1[1] - p0[1];
+  if (x10 === 0 && y10 === 0) return false;
+  var t = (x20 * x10 + y20 * y10) / (x10 * x10 + y10 * y10);
+  return t < 0 || t > 1 ? false : t === 0 || t === 1 ? true : t * x10 === x20 && t * y10 === y20;
+}
+
+var readPolyLine = function(record) {
+  var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m);
+  for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
+  for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
+  return n === 1
+      ? {type: "LineString", coordinates: points}
+      : {type: "MultiLineString", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })};
+};
+
+var readPolyLineZ = function(record) {
+  var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m);
+  for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
+  for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
+  // Advance two doubles (z min, z max)
+  i += 16;
+  for (j = 0; j < m; ++j, i += 8) points[j].push(record.getFloat64(i, true));
+  return n === 1
+      ? {type: "LineStringZ", coordinates: points}
+      : {type: "MultiLineStringZ", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })};
+};
+
+var shp_read = function() {
+  var that = this;
+  return that._source.slice(8).then(function(array) {
+    if (array == null) return {done: true, value: undefined};
+    var header = view(array);
+    return that._source.slice(header.getInt32(4, false) * 2).then(function(array) {
+      var record = view(array);
+      return {done: false, value: record.getInt32(0, true) ? that._type(record) : readNull()};
+    });
+  });
+};
+
+var types$1 = {
+  0: readNull,
+  1: readPoint,
+  3: readPolyLine,
+  5: readPolygon,
+  8: readMultiPoint,
+  11: readPoint,
+  13: readPolyLineZ,
+  15: readPolygon,
+  18: readMultiPoint
+};
+
+var shp = function(source) {
+  source = slice(source);
+  return source.slice(100).then(function(array) {
+    return new Shp(source, view(array));
+  });
+};
+
+function Shp(source, header) {
+  var type = header.getInt32(32, true);
+  if (!(type in types$1)) throw new Error("unsupported shape type: " + type);
+  this._source = source;
+  this._type = types$1[type];
+  this.bbox = [header.getFloat64(36, true), header.getFloat64(44, true), header.getFloat64(52, true), header.getFloat64(60, true)];
+}
+
+var prototype$2 = Shp.prototype;
+prototype$2.read = shp_read;
+prototype$2.cancel = cancel;
+
+function noop() {}
+
+var shapefile_cancel = function() {
+  return Promise.all([
+    this._dbf && this._dbf.cancel(),
+    this._shp.cancel()
+  ]).then(noop);
+};
+
+var shapefile_read = function() {
+  var that = this;
+  return Promise.all([
+    that._dbf ? that._dbf.read() : {value: {}},
+    that._shp.read()
+  ]).then(function(results) {
+    var dbf = results[0], shp = results[1];
+    return shp.done ? shp : {
+      done: false,
+      value: {
+        type: "Feature",
+        properties: dbf.value,
+        geometry: shp.value
+      }
+    };
+  });
+};
+
+var shapefile = function(shpSource, dbfSource, decoder) {
+  return Promise.all([
+    shp(shpSource),
+    dbfSource && dbf(dbfSource, decoder)
+  ]).then(function(sources) {
+    return new Shapefile(sources[0], sources[1]);
+  });
+};
+
+function Shapefile(shp$$1, dbf$$1) {
+  this._shp = shp$$1;
+  this._dbf = dbf$$1;
+  this.bbox = shp$$1.bbox;
+}
+
+var prototype$1 = Shapefile.prototype;
+prototype$1.read = shapefile_read;
+prototype$1.cancel = shapefile_cancel;
+
+function open(shp$$1, dbf$$1, options) {
+  if (typeof dbf$$1 === "string") {
+    if (!/\.dbf$/.test(dbf$$1)) dbf$$1 += ".dbf";
+    dbf$$1 = path(dbf$$1, options);
+  } else if (dbf$$1 instanceof ArrayBuffer || dbf$$1 instanceof Uint8Array) {
+    dbf$$1 = array(dbf$$1);
+  } else if (dbf$$1 != null) {
+    dbf$$1 = stream(dbf$$1);
+  }
+  if (typeof shp$$1 === "string") {
+    if (!/\.shp$/.test(shp$$1)) shp$$1 += ".shp";
+    if (dbf$$1 === undefined) dbf$$1 = path(shp$$1.substring(0, shp$$1.length - 4) + ".dbf", options).catch(function() {});
+    shp$$1 = path(shp$$1, options);
+  } else if (shp$$1 instanceof ArrayBuffer || shp$$1 instanceof Uint8Array) {
+    shp$$1 = array(shp$$1);
+  } else {
+    shp$$1 = stream(shp$$1);
+  }
+  return Promise.all([shp$$1, dbf$$1]).then(function(sources) {
+    var shp$$1 = sources[0], dbf$$1 = sources[1], encoding = "windows-1252";
+    if (options && options.encoding != null) encoding = options.encoding;
+    return shapefile(shp$$1, dbf$$1, dbf$$1 && new TextDecoder(encoding));
+  });
+}
+
+function openShp(source, options) {
+  if (typeof source === "string") {
+    if (!/\.shp$/.test(source)) source += ".shp";
+    source = path(source, options);
+  } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
+    source = array(source);
+  } else {
+    source = stream(source);
+  }
+  return Promise.resolve(source).then(shp);
+}
+
+function openDbf(source, options) {
+  var encoding = "windows-1252";
+  if (options && options.encoding != null) encoding = options.encoding;
+  encoding = new TextDecoder(encoding);
+  if (typeof source === "string") {
+    if (!/\.dbf$/.test(source)) source += ".dbf";
+    source = path(source, options);
+  } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
+    source = array(source);
+  } else {
+    source = stream(source);
+  }
+  return Promise.resolve(source).then(function(source) {
+    return dbf(source, encoding);
+  });
+}
+
+function read(shp$$1, dbf$$1, options) {
+  return open(shp$$1, dbf$$1, options).then(function(source) {
+    var features = [], collection = {type: "FeatureCollection", features: features, bbox: source.bbox};
+    return source.read().then(function read(result) {
+      if (result.done) return collection;
+      features.push(result.value);
+      return source.read().then(read);
+    });
+  });
+}
+
+exports.open = open;
+exports.openShp = openShp;
+exports.openDbf = openDbf;
+exports.read = read;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 38325
libs/three.js/build/three.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 2
libs/three.js/build/three.min.js


+ 2 - 2
libs/three.js/build/three.module.js

@@ -17424,7 +17424,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
 
 			console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors );
-            //add:
+            //xzw add:
             if(fragmentErrors){
                 console.log(fragmentGlsl.split("\n").map((a, i) => `${i + 1}`.padEnd(5) + a).join("\n") )
             }else{
@@ -23573,7 +23573,7 @@ function WebGLRenderer( parameters ) {
 		_this.state = state;
 		_this.info = info;
 
-        _this._textures = textures;//add 
+        _this._textures = textures;//xzw add 
         
 	}
 

+ 1 - 0
src/Potree.js

@@ -41,6 +41,7 @@ export * from "./Points.js";
 export * from "./PotreeRenderer.js";
 export * from "./ProfileRequest.js";
 export * from "./custom/objects/TextSprite.js";
+export * from "./custom/objects/3dgs/Splat.js";
 export * from "./utils.js";
 export * from "./Version.js";
 export * from "./WorkerPool.js";

+ 1 - 0
src/custom/materials/BasicMaterial.js

@@ -16,6 +16,7 @@ class BasicMaterial  extends THREE.ShaderMaterial{
                 color:  {type:'v3',   value: o.color || new THREE.Color("#FFF")} ,
                 map:    {type: 't',    value: o.map },
                 opacity : {type:'f',    value : o.opacity == void 0 ? 1 : o.opacity }
+                 
             },
             vertexShader: Shaders['basicTextured.vs'],   
             fragmentShader: Shaders['basicTextured.fs'], 

+ 28 - 13
src/custom/mergeStartTest.js

@@ -353,7 +353,10 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     ], tileIndex = 0
     
      let glbUrls = [ 
-        
+        `${Potree.resourcePath}/models/glb/animation/dog.glb`, 
+         `${Potree.resourcePath}/models/glb/animation/Soldier.glb`, 
+        {url:`${Potree.resourcePath}/models/glb/animation/man--running.glb`, scale:[100,100,100]}, 
+        `${Potree.resourcePath}/models/glb/animation/man--walk.glb`, 
         `${Potree.resourcePath}/models/glb/26k.glb`, 
 
         `${Potree.resourcePath}/models/glb/cloud_glb_239.glb`, 
@@ -564,14 +567,26 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                 },callback,onprogress) */ 
                 
             }else if(name == 'glb'){  
-                let angle = 0  
+                let angle = 0 , scale 
+                
+                let info = glbUrls[glbIndex++]
+                
+                if(info.url){
+                    angle = info.angle || 0
+                    url = info.url
+                    scale = info.scale
+                }else{
+                    url = info
+                }
+                
                 viewer.loadModel({ 
                     fileType:'glb',
                     name, 
-                    url: glbUrls[glbIndex++],
+                    url ,
                     transform : { 
                         rotation : [angle,  0,   0],
-                        position : [0,0,0]  
+                        position : [0,0,0],
+                        scale: scale  || [1,1,1]
                     } 
                 },callback,onprogress)
                         
@@ -732,17 +747,17 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         }  
     }
      
-    let getModelByName = (name)=>{
-        if(name == 'laser'){
+    let getModelByType = (type)=>{
+        if(type == 'laser'){
             return viewer.scene.pointclouds[0]
         }else{
-            return viewer.objs.children.find(e=>e.name == name)
+            return viewer.objs.children.find(e=>e.fileType == type)
         }    
     }
     
-    Potree.removeModel = function(name){
-        let model = getModelByName(name)
-        if(name == 'laser'){ 
+    Potree.removeModel = function(type){
+        let model = getModelByType(type)
+        if(type == 'laser'){ 
             viewer.scene.removePointCloud(model);
             viewer.updateModelBound() 
         }else{  
@@ -752,9 +767,9 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     }
      
     
-    Potree.selectModel = function(name){
-        let model = getModelByName(name) 
-        model && MergeEditor.selectModel(model,true)
+    Potree.selectModel = function(type){
+        let model = getModelByType(type) 
+        model && MergeEditor.selectModel(model,true,true)
     } 
     
     //Potree.loadDatasets(Potree.loadDatasetsCallback) 

+ 118 - 35
src/custom/modules/clipModel/Clip.js

@@ -548,7 +548,7 @@ var Clip = {
     
     
     
-    getRulerBound(){//坐标尺边界
+    getRulerBound(){//坐标尺边界
         let camera = viewer.mainViewport.camera
         if(!camera.isOrthographicCamera)return
         let w = camera.right / camera.zoom //half
@@ -576,16 +576,29 @@ var Clip = {
             top: camPos.y - h,
         }
         //console.log(bound)
-
+        //标尺里又改为左下角原点了
         return bound_ 
     },
     
     
     
-    screenshot: async (rulerBound, rulerMargin, unitText='像素 : 米' )=>{ //测绘图下载。顶视图|侧视图
+    screenshot: async ( rulerToolFactory /*unitText = '像素 : 米' */ )=>{ //测绘图下载。顶视图|侧视图
+    
+        let getRulerUnit = (num)=>{
+            let unitSystem = 'metric'
+            let str = viewer.unitConvert.convert(num, 'distance', 0,  unitSystem, true , 
+                {
+                    'imperial': {minFactor: 0.01 },  
+                    'metric': {minFactor:  0.001 } 
+                }
+            )  
+            return str.trim()
+        }
+     
+    
         return new Promise((resolve,reject)=>{ 
             if(Clip.screenshoting )return reject()
-             
+            let rulerBound = {}//因为margin 扩大bound  
             
          
             let visiPointclouds = viewer.scene.pointclouds.filter(e=> Potree.Utils.getObjVisiByReason(e, 'datasetSelection'))
@@ -674,10 +687,12 @@ var Clip = {
             
             let meterPerPixel = boundSize.x / w
             
-            let text = `1 : ${(meterPerPixel).toFixed(4)}(${unitText})`
+            /* let text = `1 : ${(meterPerPixel).toFixed(4)}(${unitText})` */
+            
+             
             
             let beforeScreenshot = ()=>{
-                if(rulerBound){
+                if(rulerToolFactory){
                     let ruler = Clip.getRulerBound()
                     Object.assign(rulerBound,ruler)
                 }
@@ -697,28 +712,25 @@ var Clip = {
                     const fontsize = math.linearClamp(w, [100, 700, 8000], [12, 20, 30])
                     
                     const marginSelf = {//img外的margin(标尺内)
-                        left :  rulerBound ? 76 : 40,
-                        right :  rulerBound ? 30 : 40,
-                        bottom :  rulerBound ? 20 + fontsize*2 : 40 + fontsize*2,
-                        top :  rulerBound ? 60 : 40,
+                        left :  rulerToolFactory ? 76 : 40,
+                        right :  rulerToolFactory ? 30 : 40,
+                        bottom :  (70 + fontsize*2) ,/*  rulerToolFactory ? (70 + fontsize*2) : (40 + fontsize*2) ,*/
+                        top :  rulerToolFactory ? 60 : 40,
                     }
-                    //const Margin = rulerMargin + marginSelf
-                    
                     
                     //文字的边距
-                    let bottomRatioToImg = - Math.min(fontsize*2.5,   rulerBound ? marginSelf.bottom : marginSelf.bottom*0.9 ) / h//- (marginSelf.bottom - fontsize)/ h  //在img之下. text底部到img底部的距离
-                    //let leftRatioToImg = Margin / w  
-                    
-                     
+                    let bottomRatioToImg = - Math.min(fontsize*2.5,   rulerToolFactory ? marginSelf.bottom : marginSelf.bottom*0.8 ) / h//- (marginSelf.bottom - fontsize)/ h  //在img之下. text底部到img底部的距离
+  
+                    let rulerMargin = 20//标尺外的margin  px 
                     let labelInfo = {
                         bottomRatioToImg, horizonCenter:true,//leftRatioToImg,  
-                        textColor: rulerBound ? {r: 0, g: 0, b: 0, a: 1} : { r: 255, g: 255, b: 255, a: 1 }, 
+                        textColor: /* rulerToolFactory ? */ {r: 0, g: 0, b: 0, a: 1} /* : { r: 255, g: 255, b: 255, a: 1 } */, 
                         textBorderColor : { r: 30, g: 30, b: 30, a: 1 },
-                        textBorderThick : rulerBound ? 0 : 1 ,
+                        textBorderThick : rulerToolFactory ? 0 : 1 ,
                         fontsize,
-                        fontWeight: rulerBound ? 'normal':'Bold',
-                        outputCanvas : !!rulerBound,
-                        bgColor: rulerBound ? {r:255,g:255,b:255,a:255}:null
+                        fontWeight: /* rulerToolFactory ? */ 'normal'/* :'Bold' */,
+                        outputCanvas : true,
+                        bgColor: rulerToolFactory ? {r:255,g:255,b:255,a:255}:null
                     }
                      
                     labelInfo.bgMargin = {//img外需要多少margin
@@ -728,30 +740,101 @@ var Clip = {
                         top: marginSelf.top + rulerMargin
                     } 
                     
-                    if(rulerBound){//因为margin 扩大bound 
-                        rulerBound.left -= marginSelf.left * meterPerPixel
+                    
+                    
+                    //console.log('topRatioToImg',topRatioToImg,'leftRatioToImg',leftRatioToImg,'fontsize', labelInfo.fontsize)
+                    let rulerImg, drawRuler, labelGot, rulerGot,  canvas  , unitText, resultSrc, unitLen
+                    
+                    if(rulerToolFactory){
+                        
+                        rulerBound.left -= marginSelf.left * meterPerPixel  //标尺范围内的宽度(米)
                         rulerBound.right += marginSelf.right * meterPerPixel 
                         rulerBound.top -= marginSelf.top * meterPerPixel 
                         rulerBound.bottom += marginSelf.bottom * meterPerPixel 
+                         
+                        let width = img.width + marginSelf.left + marginSelf.right  //标尺范围内的像素宽度
+                        let height = img.height + marginSelf.top + marginSelf.bottom
+                        let xNumTicks = Math.round( width / 100 )///THREE.Math.clamp(Math.round(canvas.width / 100), 1, 30) //大格子数量(但结果不会和这个一模一样)
+                        let yNumTicks = Math.round( height / 100 ) //THREE.Math.clamp(Math.round(canvas.height / 100), 1, 30),//yNumTicks.value,
+                            
+                         
+                        let result = await rulerToolFactory(//绘制标尺
+                            [rulerBound.left, rulerBound.right],    //xRang.value,
+                            [rulerBound.top, rulerBound.bottom],    //yRang.value,
+                            xNumTicks,  yNumTicks,  width,  height,  '#000000' 
+                        ); 
+                        
+                        rulerImg = new Image 
+                        rulerImg.src = result.url 
+                        //Common.downloadFile(result.url, 'ruler.png') 
+                        drawRuler = ()=>{
+                            if(!labelGot || !rulerGot)return
+                            resultSrc = Potree.Common.imgAddLabel(canvas, rulerImg,{
+                                topRatioToImg : rulerMargin / canvas.height,
+                                leftRatioToImg : rulerMargin / canvas.width, 
+                            })
+                            resolve( resultSrc ) 
+                        }
+                        rulerImg.onload = ()=>{ 
+                            rulerGot = true 
+                            drawRuler() 
+                        }  
+                        
+                        console.log('xUnit', result.xUnit, 'yUnit',  result.yUnit  )
+                        
+                        unitLen = result.xUnit  
+                    }else{
+                        unitLen = boundSize.x / 10  //假定一个
+                       
                     }
+                    unitText = '1:' + getRulerUnit(unitLen)
                     
-                    //console.log('topRatioToImg',topRatioToImg,'leftRatioToImg',leftRatioToImg,'fontsize', labelInfo.fontsize)
-                    
-                    
-                 
-                    let result = await Potree.Utils.imgAddText(img, text , labelInfo )
+                    canvas = await Potree.Utils.imgAddText(img, unitText, labelInfo )
+                   
+                    { //绘制比例尺参照横线
+                        let ctx = canvas.getContext('2d') 
+                        // 开始新的路径
+                        ctx.beginPath(); 
+                        // 移动到起点
+                        
+                        let lenX = Math.round(unitLen / meterPerPixel) ,
+                            lenY = 7, 
+                            x = Math.round(img.width / 2 + labelInfo.bgMargin.left - lenX / 2  ),
+                            y = Math.round(canvas.height - rulerMargin - 58) 
+                             
+                        //left ver line
+                        ctx.moveTo(x, y);   
+                        ctx.lineTo(x, y+lenY);
+                        //right ver line 
+                        ctx.moveTo(x+lenX, y);  
+                        ctx.lineTo(x+lenX, y+lenY);
+                        //horizon line
+                        ctx.moveTo(x, y+lenY/2);
+                        ctx.lineTo(x+lenX, y+lenY/2);
+                        
+                        // 设置线条样式(可选)
+                        ctx.strokeStyle = '#000'; 
+                        ctx.lineWidth = 1; // 线条宽度 
+                        // 绘制线段
+                        ctx.stroke(); 
+                    }
                     
+                    labelGot = true
                     
+                   
                     //Common.downloadFile(finalDataUrl, 'screenshot11.png') 
                      
                     visiPointclouds.forEach((e,i)=>e.material = materials[i])
                     Clip.screenshoting = false
                     viewer.viewports = [viewer.mainViewport]
-                    
-                    resolve(result) 
-                }
-                
-                
+                     
+                    if(rulerToolFactory){
+                        drawRuler()
+                    }else{
+                        resultSrc = canvas.toDataURL('image/png' )
+                        resolve( resultSrc ) 
+                    } 
+                } 
             })
             
        
@@ -765,9 +848,9 @@ var Clip = {
         return finishPromise
         
          
-    }
+    } 
+    
     
-   
     
 }
 

+ 191 - 57
src/custom/modules/datasetAlignment/Alignment.js

@@ -3,12 +3,15 @@ import * as THREE from "../../../../libs/three.js/build/three.module.js";
 import SplitScreen4Views from "../../utils/SplitScreen4Views.js"
 import math from "../../utils/math.js"
 import History from "../../utils/History.js"
+import {TransformControls} from "../../objects/tool/TransformControls.js";
+import CursorDeal from "../../utils/CursorDeal.js";
+
 
 var Alignment = {
     SplitScreen: SplitScreen4Views, 
     handleState:null,  //操作状态 'translate'|'rotate'
     bus: new THREE.EventDispatcher(), 
-    
+    selectedClouds:[],
     
 
     /* prepareRecord : true, 
@@ -46,11 +49,33 @@ var Alignment = {
             }
         } )
     },
-    
+     
+     
+    getDatasetQuaternion(pointcloud){
+        let quaternion
+        if(typeof(pointcloud.orientationUser) == 'number' ){
+            quaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), pointcloud.orientationUser)     
+        }else{ 
+            quaternion = pointcloud.orientationUser
+        }
+        return quaternion
+    },
+    getDatasetOrient(pointcloud){
+        let orientation
+        if(typeof(pointcloud.orientationUser) == 'number' ){
+            orientation = pointcloud.orientationUser
+        }else{ 
+            orientation = math.getYawPitchByQua(pointcloud.orientationUser)
+        }
+        return orientation
+    },
     
     
     init:function(){ 
-        let transfromInfo 
+        let transfromInfo, sideRotHovered
+        
+        
+        
         
         this.history = new History({ 
             applyData: (data)=>{    
@@ -65,6 +90,73 @@ var Alignment = {
         })
         
         
+        {//侧视图旋转
+            this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
+                dontHideWhenFaceCamera: true,
+                rotFullCircle:true
+            }) 
+            this.transformControls.name = 'Alignment-transformControls'
+            this.transformControls.setSize(0.5)
+            viewer.scene.scene.add(this.transformControls) 
+            this.transformControls.setMode('rotate')
+            this.transformControls.setRotateMethod(2)
+            this.transformControls._gizmo.hideAxis =  {rotate:['x','z','y'] } 
+            this.fakeMarkerForTran = new THREE.Mesh(new THREE.BoxBufferGeometry(0.3,0.3,0.3) , new THREE.MeshBasicMaterial({
+                color:"#F00",  opacity:0.9,  transparent:true, visible:false
+            }));//一个看不见的mesh,只是为了让transformControls移动点云
+            this.fakeMarkerForTran.name = 'fakeMarkerForTran'
+            viewer.scene.scene.add(this.fakeMarkerForTran)
+            
+            let afterMoveCtl = (type)=>{
+                if(Alignment.afterMoveCtl){
+                    Alignment.afterMoveCtl(type)
+                }else{
+                    if(type == 'position'){
+                        let moveVec = new THREE.Vector3().subVectors(this.fakeMarkerForTran.position, this.fakeMarkerForTran.oldState.position)
+                        Alignment.translate(this.selectedClouds[0], moveVec)
+                    }else{
+                        let center = this.selectedClouds[0].translateUser;
+                        
+                        let diffQua = new THREE.Quaternion().multiplyQuaternions(this.fakeMarkerForTran.quaternion, this.fakeMarkerForTran.oldState.quaternion.clone().invert())
+                        CursorDeal.add('rotatePointcloud') 
+                        //Alignment.rotateAround(center, this.selectedClouds, diffQua)
+                        Alignment.rotate(this.selectedClouds[0], null, diffQua)
+                        
+                    }
+                }
+                
+                this.fakeMarkerForTran.oldState = {
+                    position: this.fakeMarkerForTran.position.clone(),
+                    quaternion: this.fakeMarkerForTran.quaternion.clone(),
+                }
+             
+                Alignment.history.beforeChange(this.selectedClouds) 
+                
+            }
+        
+         
+            this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCtl.bind(this,'position')) 
+            this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCtl.bind(this,'rotation') )
+          
+            this.transformControls.addEventListener('mouseUp',()=>{
+                 Alignment.history.afterChange(this.selectedClouds)
+            }) 
+            this.transformControls.addEventListener('axisHoveredChange',(e)=>{
+                if(e.axis && e.mode == 'rotate'){
+                    CursorDeal.add('rotatePointcloud'),
+                    sideRotHovered = true
+                }else{
+                    CursorDeal.remove('rotatePointcloud') 
+                    sideRotHovered = false
+                } 
+            })
+            this.history.addEventListener('undo',()=>{
+                this.updateFakeMarker()
+            })
+             
+            
+        }
+        
         viewer.fpControls.addEventListener("transformPointcloud",(e)=>{ 
             if(e.pointclouds[0].dataset_id == Potree.settings.originDatasetId && Potree.settings.editType != 'pano'){//禁止手动移动初始数据集
                 return this.bus.dispatchEvent('forbitMoveOriginDataset') 
@@ -81,10 +173,10 @@ var Alignment = {
             
             if(this.handleState == 'translate'){
                 e.pointclouds.forEach(cloud=>Alignment.translate(cloud, e.moveVec))
-                
+                this.updateFakeMarker()
                 
             }else if(this.handleState == 'rotate'){
-                if(Potree.settings.editType == 'pano'){  
+                //if(Potree.settings.editType == 'pano'){  
                     //旋转中心是intersectStart的版本
                     /* let center = e.intersectStart //旋转中心是mousedown的位置
                     if(e.intersect.equals(center))return
@@ -140,7 +232,7 @@ var Alignment = {
                     }
                     //this.bus.dispatchEvent({type:'rotate', endPoint: e.intersect})
                     
-                }else{ 
+                /* }else{ //旧版数据集校准只转z轴
                     let center = e.pointclouds[0].translateUser //移动到的位置就是中心
                     if(e.intersect.equals(center))return
                     if(!transfromInfo.vecStart){  
@@ -152,7 +244,7 @@ var Alignment = {
                         let diffAngle = transfromInfo.orientationUser + angle - transfromInfo.pointclouds[0].orientationUser
                         Alignment.rotate(transfromInfo.pointclouds[0], null, diffAngle)
                     }
-                }    
+                }  */   
             } 
         })
         
@@ -174,34 +266,22 @@ var Alignment = {
             
             if(e.hoverViewport.alignment && handleState && e.hoverViewport.alignment[handleState]){
                 if(handleState == 'translate'){
-                    if( e.intersect && e.intersect.location ){ 
-                        viewer.dispatchEvent({
-                            type : "CursorChange", action : "add",  name:"movePointcloud"
-                        })
+                    if( e.intersect && e.intersect.location ){  
+                        CursorDeal.add('movePointcloud')  
                     }else{
-                        viewer.dispatchEvent({
-                            type : "CursorChange", action : "remove",  name:"movePointcloud"
-                        })
+                        CursorDeal.remove('movePointcloud')  
                     }
                 }else if(handleState == 'rotate'){ 
-                    if( e.intersect && e.intersect.location ){ 
-                        viewer.dispatchEvent({
-                            type : "CursorChange", action : "add",  name:"rotatePointcloud"
-                        })
-                    }else{
-                        viewer.dispatchEvent({
-                            type : "CursorChange", action : "remove",  name:"rotatePointcloud"
-                        })
+                    if( e.intersect && e.intersect.location ){  
+                        CursorDeal.add('rotatePointcloud')  
+                    }else{ 
+                        CursorDeal.remove('rotatePointcloud')  
                     }
                 }  
-            }else{
+            }else{  
                 //清空:
-                viewer.dispatchEvent({
-                    type : "CursorChange", action : "remove",  name:"movePointcloud" 
-                })
-                viewer.dispatchEvent({
-                    type : "CursorChange", action : "remove",  name:"rotatePointcloud" 
-                })
+                CursorDeal.remove('movePointcloud')  
+                if(!sideRotHovered) CursorDeal.remove('rotatePointcloud') 
             }                
         }
         
@@ -291,19 +371,23 @@ var Alignment = {
         
         if(deg || typeof(angle) == 'number'){
             angle = angle != void 0 ? angle : THREE.Math.degToRad(deg)   //正逆负顺             
+        }else if(angle instanceof Array){//when init
+            qua = new THREE.Quaternion().fromArray(angle)
         }else{
             qua = angle
         }
         
         if(typeof(pointcloud.orientationUser) == 'number' ){
-            pointcloud.orientationUser += angle
-        }else{ 
-            if(!qua){
-                qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle)     
-            } 
-            pointcloud.orientationUser.premultiply(qua)
-        }
+            //pointcloud.orientationUser += angle
+            pointcloud.orientationUser = this.getDatasetQuaternion(pointcloud)
+        } 
         
+        if(!qua){
+            qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle)     
+        } 
+        pointcloud.orientationUser.premultiply(qua)
+         
+        //新版全部使用qua
         Alignment.setMatrix(pointcloud)
     },
     
@@ -329,8 +413,41 @@ var Alignment = {
         viewer.viewports.find(e=>e.name == 'mapViewport').alignment = {rotate:true,translate:true};
         viewer.viewports.find(e=>e.name == 'right').alignment = {translate:true, translateVec:new THREE.Vector3(0,0,1)}; //只能上下移动
         viewer.viewports.find(e=>e.name == 'back').alignment = {translate:true, translateVec:new THREE.Vector3(0,0,1)}; //只能上下移动
-        
-        
+        viewer.viewports.forEach(e=>{
+            if(e.name == 'right' || e.name == 'back' ){
+                e.layersAdd('sideVisi') 
+                /* if(e.name == 'right') e.layersAdd('layer1') 
+                else if(e.name == 'back') e.layersAdd('layer2')  */
+            }  
+        })
+        Potree.Utils.setObjectLayers(this.transformControls, 'sideVisi' )
+        /* Potree.Utils.setObjectLayers(this.transformControls, 'layer1' )
+        Potree.Utils.setObjectLayers(this.transformControls, 'layer2' ) */
+         
+        { 
+            /* viewer.viewports.forEach(e=>{
+                let oldFun = e.beforeRender 
+                e.beforeRender = function(){
+                    oldFun.bind(this)()
+                    if(e.name == 'right'){
+                        Alignment.transformControls._gizmo.hideAxis =  {rotate:['e','z','y'] }  
+                    }else if(e.name == 'back'){
+                        Alignment.transformControls._gizmo.hideAxis =  {rotate:['e','z','x'] }  
+                    }
+                }
+                 
+            }) */
+            /* viewer.viewports.find(e=>e.name == 'right').beforeRender = function(){
+                oldFun.bind(this)()
+                if(this.name == right)
+                
+            }
+            viewer.viewports.find(e=>e.name == 'back').beforeRender = (e)=>{
+                old2()
+                this.transformControls._gizmo.hideAxis =  {rotate:['e','z','x'] }  
+            }  */  
+        }
+         
         this.editing = true
         
         viewer.updateFpVisiDatasets()
@@ -358,32 +475,47 @@ var Alignment = {
         this.editing = false
         this.history.clear() 
         viewer.updateFpVisiDatasets()
-        viewer.dispatchEvent({
-            type : "CursorChange", action : "remove",  name:"movePointcloud" 
-        })
-        viewer.dispatchEvent({
-            type : "CursorChange", action : "remove",  name:"rotatePointcloud" 
-        })
+        CursorDeal.remove('movePointcloud')  
+        CursorDeal.remove('rotatePointcloud') 
+
     } 
     
     ,
     switchHandle:function(state){
+        console.log('switchHandle',state)
         this.handleState = state
-        //清空:
-        viewer.dispatchEvent({
-            type : "CursorChange", action : "remove",  name:"movePointcloud" 
-        })
-        viewer.dispatchEvent({
-            type : "CursorChange", action : "remove",  name:"rotatePointcloud" 
-        })
-        
+        //清空: 
+        CursorDeal.remove('movePointcloud') 
+        CursorDeal.remove('rotatePointcloud') 
         this.bus.dispatchEvent({type:'switchHandle' , state })
         
-        
+        this.updateCtlDisplay() 
 
     },
     
+    updateCtlDisplay(){//仅数据集校准执行
+        if(!this.editing)return  
+        let selected = this.handleState == 'rotate' && this.selectedClouds.length > 0
+        if(selected){
+            this.updateFakeMarker()
+        }else{
+            this.transformControls.detach()
+        }
+    },
     
+    updateFakeMarker(){
+        this.transformControls.attach(this.fakeMarkerForTran)
+  
+        let position = this.selectedClouds[0].translateUser
+        let quaternion = this.getDatasetQuaternion(this.selectedClouds[0])
+        this.fakeMarkerForTran.position.copy(position)
+        this.fakeMarkerForTran.quaternion.copy(quaternion)
+        this.fakeMarkerForTran.oldState = {
+            position: position.clone(),
+            quaternion: quaternion.clone() 
+        }
+    }
+    ,
     save: function(){//保存所有数据集的位置和旋转
         let callback = ()=>{//保存成功后
             this.originData = this.getTemp()   //this.saveTemp();
@@ -393,16 +525,18 @@ var Alignment = {
             viewer.images360.updateCube(viewer.bound)
         }
         
+        let initialPointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == Potree.settings.originDatasetId)
         var data = viewer.scene.pointclouds.map(e=>{
             let pos = viewer.transform.lonlatToLocal.inverse(e.translateUser.clone())
-            let initialPointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == Potree.settings.originDatasetId)
-            
-            return {
+            let data = {
                 id: e.dataset_id,
-                orientation : e.orientationUser,
+                quaternion: this.getDatasetQuaternion(e).toArray(),
+                orientation : this.getDatasetOrient(e).yaw,
                 location:[pos.x, pos.y, pos.z + initialPointcloud.datasetData.location[2]],
                 //transformMatrix: e.transformMatrix.elements,
             }
+             
+            return data
         })
         //data = JSON.stringify(data)
         

+ 45 - 49
src/custom/modules/panoEdit/panoEditor.js

@@ -179,39 +179,33 @@ class PanoEditor extends THREE.EventDispatcher{
             
             
             {
-                this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
+                /* this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
                     dontHideWhenFaceCamera: true,
                     rotFullCircle:true
                 }); 
                 this.transformControls.setSize(1.5)
                 viewer.scene.scene.add(this.transformControls)
-                this.transformControls._gizmo.hideAxis = {/* translate:['x','y'], */ rotate:['e'] }
+                this.transformControls._gizmo.hideAxis = {  rotate:['e'] }
                 this.transformControls.setRotateMethod(2)
                 
                 this.fakeMarkerForTran = new THREE.Mesh(new THREE.BoxBufferGeometry(0.3,0.3,0.3) , new THREE.MeshBasicMaterial({
                     color:"#FFFFFF",  opacity:0.4,  transparent:true, visible:false
                 }));//一个看不见的mesh,只是为了让transformControls移动点云
-                viewer.scene.scene.add(this.fakeMarkerForTran)
+                viewer.scene.scene.add(this.fakeMarkerForTran) */
+                this.transformControls = Alignment.transformControls
+                this.fakeMarkerForTran = Alignment.fakeMarkerForTran
+                this.transformControls.setSize(1.5)
+                this.transformControls.setSpace('world') //side view translate vertical
                 
                 
-           
-                let afterMoveCircle = (type)=>{
+                
+                Alignment.afterMoveCtl = (type)=>{
                       
                     if(type == 'position'){
                         let moveVec = new THREE.Vector3().subVectors(this.fakeMarkerForTran.position, this.fakeMarkerForTran.oldState.position)
                         this.selectedClouds.forEach(cloud=>Alignment.translate(cloud, moveVec))
                     }else{
                         let center = this.selectedPano.position;
-                        /* let forward = new THREE.Vector3(0,1,0);
-                        let vec1 = forward.clone().applyQuaternion(this.fakeMarkerForTran.oldState.quaternion)
-                        let vec2 = forward.clone().applyQuaternion(this.fakeMarkerForTran.quaternion)
-                         
-                        let diffAngle = math.getAngle(vec1,vec2,'z')    
-                            
-                        this.selectedClouds.forEach(cloud=>{ 
-                            Alignment.rotateAround(center, cloud, null, diffAngle)    
-                        }) */
-                        
                         
                         let diffQua = new THREE.Quaternion().multiplyQuaternions(this.fakeMarkerForTran.quaternion, this.fakeMarkerForTran.oldState.quaternion.clone().invert())
                         
@@ -219,26 +213,27 @@ class PanoEditor extends THREE.EventDispatcher{
                             Alignment.rotateAround(center, cloud, diffQua)    
                         }) 
                     }
+                    Alignment.selectedClouds = this.selectedClouds
                     
-                    
-                    this.fakeMarkerForTran.oldState = {
+                   /*  this.fakeMarkerForTran.oldState = {
                         position: this.fakeMarkerForTran.position.clone(),
                         quaternion: this.fakeMarkerForTran.quaternion.clone(),
                     }
                  
-                    Alignment.history.beforeChange(this.selectedClouds) 
+                    Alignment.history.beforeChange(this.selectedClouds)  */
                 }
                  
-                this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCircle.bind(this,'position')) 
-                this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCircle.bind(this,'rotation') )
+                /* this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCtl.bind(this,'position')) 
+                this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCtl.bind(this,'rotation') )
               
                 this.transformControls.addEventListener('mouseUp',()=>{
                      Alignment.history.afterChange(this.selectedClouds)
-                })
-                
+                }) */
+                Alignment.updateFakeMarker = this.updateFakeMarker.bind(this)
                 Alignment.history.addEventListener('undo',()=>{
-                    this.updateTranCtl()
+                    this.updateFakeMarker()
                 })
+                
             }
             
              
@@ -367,8 +362,7 @@ class PanoEditor extends THREE.EventDispatcher{
         Potree.settings.displayMode = 'showPointCloud'
         Potree.settings.ifShowMarker = false
         Potree.Utils.updateVisible(this.panoMeshs, 'entered', true)
-        Potree.Utils.updateVisible(this.lineMeshes, 'entered', true) 
-        this.transformControls.setSpace('local')
+        Potree.Utils.updateVisible(this.lineMeshes, 'entered', true)  
         Potree.settings.unableNavigate = true
          
         let originFloor = viewer.modules.SiteModel.inEntity  //还未编辑时的楼层 
@@ -448,14 +442,15 @@ class PanoEditor extends THREE.EventDispatcher{
     
     
     setTranMode(mode){//rotate or translate 
-        //console.log('setTranMode',mode)
+        console.log('panoeditor setTranMode',mode)
         this.tranMode = mode
+        
         if(this.activeViewName != 'top'){
             mode && this.transformControls.setMode(mode)
-            this.updateTranCtl() 
-        }else{
-            Alignment.switchHandle(mode) 
+            this.updateFakeMarker() 
         } 
+        Alignment.switchHandle(mode) 
+        
         this.updateIntersectEnable()
     }
     
@@ -465,22 +460,7 @@ class PanoEditor extends THREE.EventDispatcher{
          
     }
     
-    updateTranCtl(){// 设置3D页面的transformControls相关
-        if(!this.tranMode || !this.selectedPano || this.activeViewName == 'top' ) {
-            return this.transformControls.detach() 
-        }else if(this.checkIfAllLinked({group:this.selectedGroup})){
-            this.dispatchEvent('needToDisConnect')
-            return this.transformControls.detach()
-        }
-        this.transformControls.attach(this.fakeMarkerForTran)
-        let {position, quaternion} = this.getPanoPose(this.selectedPano);
-        this.fakeMarkerForTran.position.copy(position)
-        this.fakeMarkerForTran.quaternion.copy(quaternion)
-        this.fakeMarkerForTran.oldState = {
-            position: position.clone(),
-            quaternion: quaternion.clone() 
-        }
-    }
+    
     
     
      
@@ -697,7 +677,7 @@ class PanoEditor extends THREE.EventDispatcher{
         
         
         
-        this.updateTranCtl()
+        this.updateFakeMarker()
         this.setTranMode(this.tranMode) // update
         this.setZoomInState(false) //取消放大模式
         //this.updatePointLevels() 
@@ -1335,7 +1315,7 @@ class PanoEditor extends THREE.EventDispatcher{
         
         
         this.updateCursor() 
-        this.updateTranCtl()
+        this.updateFakeMarker()
 
         
 
@@ -1362,7 +1342,22 @@ class PanoEditor extends THREE.EventDispatcher{
     }
     
     
-    
+    updateFakeMarker(){// 设置3D页面的transformControls相关
+        if(!this.tranMode || !this.selectedPano || this.activeViewName == 'top' ) {
+            return this.transformControls.detach() 
+        }else if(this.checkIfAllLinked({group:this.selectedGroup})){
+            this.dispatchEvent('needToDisConnect')
+            return this.transformControls.detach()
+        }
+        this.transformControls.attach(this.fakeMarkerForTran)
+        let {position, quaternion} = this.getPanoPose(this.selectedPano);
+        this.fakeMarkerForTran.position.copy(position)
+        this.fakeMarkerForTran.quaternion.copy(quaternion)
+        this.fakeMarkerForTran.oldState = {
+            position: position.clone(),
+            quaternion: quaternion.clone() 
+        }
+    }
     /* updatePointLevels(){
         if(this.pauseUpdateLevels)return
         let maxBudget = Potree.config.pointDensity.panoEdit.pointBudget
@@ -1596,7 +1591,8 @@ class PanoEditor extends THREE.EventDispatcher{
                         translation : dealData(position), 
                         rotation : dealData(quaternion) 
                     }, 
-                    use_rtk : !!pano.rtkState   
+                    use_rtk : !!pano.rtkState,
+                    exist:  pano.isCalc == void 0 ? true : pano.isCalc
                 })
                 
                 if(this.version != 'old' ){

+ 1 - 2
src/custom/modules/panos/Panorama.js

@@ -106,8 +106,7 @@ class Panorama extends THREE.EventDispatcher{
             this.sid = this.pointcloud.dataset_id + '|' + this.uuid  //不会更改的标记  用于entity.panos里的标记
             
             delete o.pointcloud
-            this.panoData = o
-            
+            this.panoData = o 
             
             /* //数据中原本的位置朝向
             this.dataPosition = new THREE.Vector3().copy(o.pose.translation) 

+ 7 - 7
src/custom/modules/siteModel/BuildingBox.js

@@ -330,7 +330,7 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
         
         
         if(this.buildType == 'floor'){
-            Potree.Utils.setObjectLayers(mesh, 'siteModelMapUnvisi' ) //楼层默认在地图不显示,为了不会叠加透明度
+            Potree.Utils.setObjectLayers(mesh, 'mapUnvisi' ) //楼层默认在地图不显示,为了不会叠加透明度
             //mesh.renderOrder = 1
         }else{
             /* if(this.buildType == 'room'){
@@ -354,7 +354,7 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
         let marker = new Sprite({mat:this.getMarkerMaterial('default'), renderOrder : 3, sizeInfo: markerSizeInfo, dontFixOrient: true, name:"building_marker"} )
        
          
-        Potree.Utils.setObjectLayers(marker, 'siteModeOnlyMapVisi' ) 
+        Potree.Utils.setObjectLayers(marker, 'onlyMapVisi' ) 
         
         o.marker = marker
         super.addMarker(o)
@@ -403,7 +403,7 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
         
         marker.renderOrder = 3 
          
-        Potree.Utils.setObjectLayers(marker, 'siteModeOnlyMapVisi' ) 
+        Potree.Utils.setObjectLayers(marker, 'onlyMapVisi' ) 
         { // Event Listeners  
             let mouseover = (e) => {
                 this.setMarkerSelected(e.object, 'hover', 'single'); 
@@ -748,11 +748,11 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
               
             if(this.buildType == 'floor'){
                 Potree.Utils.setObjectLayers(this.box, 'bothMapAndScene' ) 
-                Potree.Utils.setObjectLayers(this.buildParent.box, 'siteModelMapUnvisi' ) //当选中floor或room时,building在地图不可见
+                Potree.Utils.setObjectLayers(this.buildParent.box, 'mapUnvisi' ) //当选中floor或room时,building在地图不可见
             }
         }else if(this.buildType == 'room'){
             Potree.Utils.setObjectLayers(this.buildParent.box, 'bothMapAndScene' )
-            Potree.Utils.setObjectLayers(this.buildParent.buildParent.box, 'siteModelMapUnvisi' )
+            Potree.Utils.setObjectLayers(this.buildParent.buildParent.box, 'mapUnvisi' )
         }
         
         
@@ -784,12 +784,12 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
             })  
             
             if(this.buildType == 'floor'){
-                Potree.Utils.setObjectLayers(this.box, 'siteModelMapUnvisi' ) 
+                Potree.Utils.setObjectLayers(this.box, 'mapUnvisi' ) 
                 Potree.Utils.setObjectLayers(this.buildParent.box, 'bothMapAndScene' ) 
             }
             
         }else if(this.buildType == 'room'){
-            Potree.Utils.setObjectLayers(this.buildParent.box, 'siteModelMapUnvisi' )
+            Potree.Utils.setObjectLayers(this.buildParent.box, 'mapUnvisi' )
             Potree.Utils.setObjectLayers(this.buildParent.buildParent.box, 'bothMapAndScene' )
         }
         

+ 8 - 8
src/custom/modules/siteModel/SiteModel.js

@@ -219,19 +219,19 @@ var SiteModel = {
         
         viewer.viewports.forEach(e=>{
             if(e.name != 'mapViewport'){
-                e.layersAdd('siteModelMapUnvisi') 
+                e.layersAdd('mapUnvisi') 
             }
             if(e.name == 'right' || e.name == 'back'){
-                e.layersAdd('siteModeSideVisi') 
+                e.layersAdd('sideVisi') 
             }
         })   
         
         
         viewer.images360.panos.forEach(pano=>{
-            Potree.Utils.setObjectLayers(pano.marker, 'siteModelMapUnvisi' )
+            Potree.Utils.setObjectLayers(pano.marker, 'mapUnvisi' )
             //Potree.Utils.setObjectLayers(pano.label2, 'bothMapAndScene')             
         }) 
-        mapViewport.layersAdd('siteModeOnlyMapVisi') //只有mapViewport能看到marker
+        mapViewport.layersAdd('onlyMapVisi') //只有mapViewport能看到marker
        
           
         
@@ -248,10 +248,10 @@ var SiteModel = {
 
         viewer.viewports.forEach(e=>{
             if(e.name != 'mapViewport'){
-                e.layersRemove('siteModelMapUnvisi') 
+                e.layersRemove('mapUnvisi') 
             } 
             if(e.name == 'right' || e.name == 'back'){
-                e.layersRemove('siteModeSideVisi') 
+                e.layersRemove('sideVisi') 
             }
         })
 
@@ -260,7 +260,7 @@ var SiteModel = {
             //Potree.Utils.setObjectLayers(pano.label2, 'bothMapAndScene') 
         })
         
-        mapViewport.layersRemove('siteModeOnlyMapVisi') 
+        mapViewport.layersRemove('onlyMapVisi') 
         this.clear()   
         this.editing = false
         
@@ -967,7 +967,7 @@ var SiteModel = {
         this.meshGroup.add(this.height_pull_box) 
         height_pull_box_up.position.set(0,0,1/2/* 3/8 */)
         height_pull_box_down.position.set(0,0,-1/2/* -3/8 */)
-        Potree.Utils.setObjectLayers(this.height_pull_box, 'siteModeSideVisi' )
+        Potree.Utils.setObjectLayers(this.height_pull_box, 'sideVisi' )
         
         
         

+ 8 - 46
src/custom/objects/tool/Compass.js

@@ -183,19 +183,11 @@ class Compass extends THREE.EventDispatcher{
     
     
     
-    setNorth(){ //设置北方向,这决定了指南针自身的朝向。 
-        const floors = store.getters['scene/houstFloor'].floors
-        if(!floors || !floors.length){
-            return 
-        }
-        const floor = floors[0] 
-        const metadata = app.store.getters['scene/metadata'] || {}
-         
-        this.angle = (floor && floor.dire || 0) + THREE.Math.radToDeg(parseFloat(metadata.floorPlanAngle || 0))  //基础朝向  
-        this.cones.rotation.y = Math.PI / 2 - THREE.Math.degToRad(this.angle) 
-        //console.log("dir:"+floor.dire+", floorPlanAngle:"+metadata.floorPlanAngle)
-        this.update() 
-   
+    setNorth(angle){ //设置北方向,这决定了指南针自身的朝向。  
+        if(angle === this.angle ) return 
+        this.angle = angle
+        this.cones.rotation.z = -THREE.Math.degToRad(angle)
+        this.update()
     }
     
     update(quaternion){ 
@@ -206,41 +198,11 @@ class Compass extends THREE.EventDispatcher{
         this.render()
          
     }
-    
-    
-    /*updateLabel(quaternion){//更新北标签
-          
-        var dir = viewer.mainViewport.view.direction;
-        var oriDir = initDir.clone()  //指南针最初始时的北方向
-        var extraQua 
-        if(objects.player.mode == "transitioning"){//当transitioning时,相机的quaternion不是用control的lookAt算出来,而是直接由一个quaternion过渡到另一个,这样相机将会是歪的,投影面也就不会是原先的水平面。
-            var tempCamera = new THREE.Camera();   //借用camera的lookAt算出如果正视同样的target, quaternion会是什么值。 将它乘以当前相机quaternion,得到的就是相机歪的旋转值。
-            tempCamera.position.copy(this.camera.position); 
-            tempCamera.lookAt(tempCamera.position.clone().add(dir)) 
-            var q = tempCamera.quaternion.inverse()
-            extraQua = q.premultiply(quaternion) //歪掉的额外旋转值
-            
-        }  
-         
-        //北标签的方向为指南针轮盘方向,也就是要将camera的方向投影到水平面上。 但是如果相机歪了,看到的世界都会歪一定角度,投影面也要歪一定角度。
-        var up = new THREE.Vector3(0,0,1) //投影水平面的法线,也是相机的摆正的up方向
-        extraQua && up.applyQuaternion(extraQua)
-        dir.projectOnPlane(up)   //将方向投影到水平面上; 如果相机不是正视(extraQua不为0001),就要将水平面也转动 
-        oriDir.projectOnPlane(up)//为什么initDir投影了和没有投影angle结果一样 
-        var angle = dir.angleTo(oriDir)
-        if(dir.cross(oriDir).y > 0)angle = -angle
-         
-        var deg = this.angle - 90 + THREE.Math.radToDeg(angle) //因为css写的样式初始是指向右方,和initDir差了90°,所以减去。
-        
-        
-        this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" )
-        this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)")
-    } */
-    
+     
 
 
     updateLabel(quaternion){//更新北标签
-        let deg = THREE.Math.radToDeg(this.viewport.view.yaw) - 90
+        let deg = THREE.Math.radToDeg(this.viewport.view.yaw) - 90 + this.angle
         this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" )
         this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)")
     }
@@ -279,7 +241,7 @@ class Compass extends THREE.EventDispatcher{
     
     
     setAutoDisplay(state){//被直接改变了dom的显示
-        
+        if(this.autoJudgeShow == state)return
         this.autoJudgeShow = state
         
         if(state){ 

+ 134 - 0
src/custom/objects/tool/FloorCompass.js

@@ -0,0 +1,134 @@
+
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+
+import math from "../../utils/math.js"; 
+
+
+
+
+
+
+
+
+let planeGeo = new THREE.PlaneGeometry(1.6, 1.6, 1, 1)
+let texLoader = new THREE.TextureLoader()  
+
+var lastQ = new THREE.Quaternion()
+
+
+export class FloorCompass extends THREE.Object3D{
+    
+    
+    constructor(viewer){
+        super()
+        this.angle = 0
+        this.build()
+        Potree.Utils.updateVisible(this,'isAtPano',false)
+        viewer.scene.scene.add(this) 
+        
+        viewer.addEventListener('camera_changed', e => { 
+            if(e.viewport == viewer.mainViewport && e.changeInfo.quaternionChanged ){  
+                 this.updateRot()
+            }
+        })
+        let init = ()=>{
+            let setPano = (pano)=>{ 
+                this.position.copy(pano.floorPosition)
+                this.position.z += 0.05
+                Potree.Utils.updateVisible(this,'isAtPano',true)
+            }
+            if(viewer.images360.currentPano){
+                setPano(viewer.images360.currentPano)
+            } 
+            viewer.images360.addEventListener('flyToPano', e => { 
+                //console.log('floorcompass set pano',e.toPano.pano.id) 
+                setPano(e.toPano.pano)
+            })
+        }
+        if(viewer.allLoaded){
+            init()
+        }else{
+            viewer.addEventListener('allLoaded',e=>{
+                init()
+            })
+        }
+        
+        this.addEventListener('isVisible',e=>{//visi change
+            if(this.visible)this.updateRot()
+            viewer.dispatchEvent('content_changed')    
+        })
+        
+    }
+    
+    
+    
+    build(){ 
+           
+        let count = 0
+        let loaded = tex => {
+            count++
+            if (count == 2) { 
+             
+                this.underLayer = new THREE.Mesh(
+                    planeGeo,
+                    new THREE.MeshBasicMaterial({
+                        map: compassMap,
+                        transparent: true,
+                        side: THREE.SingleSide,
+                        depthTest: false,
+                    })
+                )
+                this.underLayer.name = 'underLayer' 
+                this.underLayer.renderOrder = 2
+            
+                this.arrow = new THREE.Mesh(
+                    planeGeo,
+                    new THREE.MeshBasicMaterial({
+                        map: arrowMap,
+                        transparent: true,
+                        side: THREE.SingleSide,
+                        depthTest: false,
+                    })
+                )
+                this.arrow.name = 'compassArrow' 
+                this.arrow.position.set(0, 0, 0.01)  
+                this.arrow.renderOrder = 3
+                this.add(this.underLayer)  
+                this.add(this.arrow) 
+                this.updateRot()
+                //this.setAngle()  
+                //done && done()
+            }
+        }
+        
+        
+        let arrowMap = texLoader.load(Potree.resourcePath+'/textures/compass_arrow.png', loaded)
+        let compassMap = texLoader.load(Potree.resourcePath+'/textures/compass_floor.png', loaded) 
+     
+    }
+    
+    
+    setAngle(angle){
+        if(angle === this.angle ) return 
+        this.angle = angle
+        this.rotation.set(0, 0, -THREE.Math.degToRad(angle))  
+        viewer.dispatchEvent('content_changed')
+    }
+    
+    updateRot() {
+        
+      
+        /* rotation = new THREE.Euler(0, 0, yaw - this.firstLogo.rotation.z)
+        this.compassArrow1.rotation.copy(rotation) */
+        if(!this.arrow || !this.visible)return
+        this.arrow.rotation.z = viewer.mainViewport.view.yaw - this.rotation.z
+               
+       
+        
+    }
+    
+   
+    
+}
+
+ 

+ 307 - 221
src/custom/objects/tool/Measure.js

@@ -6,11 +6,14 @@ import  Label  from "../Label.js";
 import {LineDraw} from "../../utils/DrawUtil.js";
 import math from "../../utils/math.js"; 
 import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
+import BasicMaterial from '../../materials/BasicMaterial.js'  
 import Sprite from '../Sprite.js'
 import {config} from '../../settings.js'
 import browser from "../../utils/browser.js";
 import {ctrlPolygon} from './ctrlPolygon.js'
 
+ 
+ 
 
 let texLoader = new THREE.TextureLoader()  
 let defaultColor = new THREE.Color(config.measure.default.color);
@@ -18,9 +21,7 @@ let highlightColor = new THREE.Color(config.measure.highlight.color);
 
 let color = new THREE.Color(config.measure.color)
 let textColor = new THREE.Color(config.measure.textColor) 
-var markerMats;  
-var lineMats;  
-var planeMats 
+let markerMaps 
  
 const textSizeRatio = math.linearClamp(window.outerWidth * window.outerHeight , [360*720, 1920*1080], [0.7, 1])  //pc字显示大一些 用
  
@@ -81,20 +82,18 @@ const guideShowMinAngle = {min: angle, max: Math.PI/2 - angle}
  
 export class Measure extends ctrlPolygon{
 	constructor (prop) {
-        prop.dimension = '2d'
-        
+        prop.dimension = '2d' 
 		super('measure',prop);
 		this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
         
         
         this.name = this.name || this.measureType + this.constructor.counter  
-        this.selectStates = {}
-	  
+        this.selectStates = {} 
 		
 		this.edgeLabels = []; 
 		this.coordinateLabels = [];
         this.area = {value:0,string:''}
-         
+        this.expands = [] 
         
         if( this.showArea  ){
             this.areaLabel = this.createAreaLabel(); 
@@ -125,7 +124,7 @@ export class Measure extends ctrlPolygon{
          
         
         //addMarkers:
-         
+        
         this.initData(prop)
         this.pointsPos2d = new Map //屏幕上的二维坐标
          
@@ -155,6 +154,11 @@ export class Measure extends ctrlPolygon{
         }else{
             this.failBuilded = true
         }
+        if(prop.expands){ //基本不会从这加
+            for(let data of prop.expands){ 
+                this.addExpand(data)
+            }
+        }
     }
  
      
@@ -218,7 +222,19 @@ export class Measure extends ctrlPolygon{
         this.setSelected(false)//隐藏edgelabel
          
     }
- 
+    
+    
+    changeColor(color){
+        this.color = color //'#ffffff'
+        this.edges.forEach(e=>e.material = this.getMat('edgeDefault'))  //update
+        this.markers.forEach(e=>e.material = this.getMat('markerDefault'))
+        this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault') )    
+        this.expands.forEach(e=>e.edges.forEach(a=>a.material = this.getMat('edgeExpand')))
+        viewer.dispatchEvent('content_changed')
+    }
+    
+    
+    
 	update(options={}) { 
         if(options.index == -1)return
         
@@ -277,17 +293,18 @@ export class Measure extends ctrlPolygon{
          
         
         let setLabel = (index)=>{
+            if(index == null)return
             let previousIndex = this.getIndex(index, -1)
             let nextIndex = this.getIndex(index, +1)
             let previousPoint = this.points[previousIndex];
             let point = this.points[index];
             let nextPoint = this.points[nextIndex];
             
-            if(this.showDistances){ // edge labels
-                let edgeLabel = this.edgeLabels[index];
-                let distance = point.distanceTo(nextPoint)
+            if(this.showDistances ){ // edge labels
+                let edgeLabel = this.edgeLabels[index]; 
+                let distance = nextPoint && point.distanceTo(nextPoint)
                 this.edges[index].distance_ = distance
-                edgeLabel.shouldVisi = (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0 
+                edgeLabel.shouldVisi = nextPoint && (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0 
                 //this.closed || edgeLabel.setVisible(edgeLabel.shouldVisi)  //closed的在setEdgesDisplay中设置
                 Utils.updateVisible(edgeLabel, 'shouldVisi', edgeLabel.shouldVisi, 2)
                 if(edgeLabel.shouldVisi){
@@ -369,7 +386,7 @@ export class Measure extends ctrlPolygon{
             }  
         }
           
-        
+        this.expands.forEach(e=>e.update(options))
 	};
     
         
@@ -582,7 +599,7 @@ export class Measure extends ctrlPolygon{
 	addMarker (o={}) {
         var index = o.index == void 0 ? this.points.length : o.index  //要当第几个
         
-        let marker = o.marker || new Sprite({mat:this.getMarkerMaterial('default'), sizeInfo: markerSizeInfo, name:"measure_point"} )
+        let marker = o.marker || new Sprite({mat:this.getMat('markerDefault'), sizeInfo: markerSizeInfo, name:"measure_point"} )
         //Potree.Utils.setObjectLayers(marker, 'measure' )
         marker.pickOrder = marker.renderOrder = Potree.config.renderOrders.measureMarker 
         marker.markerSelectStates = {} 
@@ -639,7 +656,7 @@ export class Measure extends ctrlPolygon{
         //marker.measure = this 
         let edge
 		{ // edges 
-            edge = o.edge || LineDraw.createFatLine( [ ],{mat:this.getLineMat('edgeDefault')} ) 
+            edge = o.edge || LineDraw.createFatLine( [ ],{mat:this.getMat('edgeDefault')} ) 
             edge.pickOrder = 0
             //Potree.Utils.setObjectLayers(edge, 'measure' ) 
 
@@ -725,7 +742,8 @@ export class Measure extends ctrlPolygon{
 			marker: marker
 		};
 		this.dispatchEvent(event);
-
+        
+        this.expands.forEach(e=>e.addMarker(o))
 		//this.setMarker(this.points.length - 1, point);
         this.update({index})//更新一下倒数第二条线   
         return marker;//add
@@ -779,10 +797,10 @@ export class Measure extends ctrlPolygon{
             }
         }
         if(absoluteState){
-            marker.material = this.getMarkerMaterial('select')
+            marker.material = this.getMat('markerSelect')
             marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker+1
         }else{
-            marker.material = this.getMarkerMaterial('default')
+            marker.material = this.getMat('markerDefault')
             marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker
         }
         
@@ -830,10 +848,10 @@ export class Measure extends ctrlPolygon{
             
             this.edges.forEach(e=>{
                 e.renderOrder = Potree.config.renderOrders.line + 1
-                e.material = this.getLineMat('edgeSelect')   
+                e.material = this.getMat('edgeSelect')   
             }) 
             
-			this.areaPlane && (this.areaPlane.material = planeMats.selected)
+			this.areaPlane && (this.areaPlane.material = this.getMat('planeSelected'))
              
             
             //this.areaLabel && this.areaLabel.elem.addClass('highLight')
@@ -845,8 +863,8 @@ export class Measure extends ctrlPolygon{
               
         }else{
             this.markers.forEach(e=>this.setMarkerSelected(e, 'unhover', 'selectAll' ))
-            this.edges.forEach(e=>e.material = this.getLineMat('edgeDefault')  )
-            this.areaPlane && (this.areaPlane.material = planeMats.default)
+            this.edges.forEach(e=>e.material = this.getMat('edgeDefault')  )
+            this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault'))
             this.setEdgesDisplay(false, hoverObject=="screenshot")
             //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
             //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight')  )
@@ -878,7 +896,7 @@ export class Measure extends ctrlPolygon{
             this.edgeLabels[edgeIndex].dispose() 
             this.edgeLabels.splice(edgeIndex, 1);
         }
-         
+        this.expands.forEach(e=>e.removeMarker(index))
         this.update({index: this.getIndex(index, -1)}); 
         this.dispatchEvent({type: 'marker_removed', measurement: this});
     }
@@ -898,6 +916,7 @@ export class Measure extends ctrlPolygon{
         var labels = this.edgeLabels.concat(this.coordinateLabels)
         this.areaLabel && labels.push(this.areaLabel)
         labels.forEach(e=>e.dispose())
+        this.expands.forEach(e=>e.dispose())
         super.dispose()
         this.dispatchEvent('disposed')
     }
@@ -948,18 +967,18 @@ export class Measure extends ctrlPolygon{
      
     
     createGuideLine(){//add 辅助线 
-        var guideLine = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
+        var guideLine = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
         guideLine.visible = false 
         this.guideLine = guideLine
         this.add(guideLine);
     }
     createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
-        var verGuideEdge = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
+        var verGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
         verGuideEdge.visible = false 
         this.verGuideEdge = verGuideEdge
         verGuideEdge.name = 'verGuideEdge'
         
-        var horGuideEdge = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
+        var horGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
         horGuideEdge.visible = false 
         horGuideEdge.name = 'horGuideEdge'
         this.horGuideEdge = horGuideEdge
@@ -1046,97 +1065,162 @@ export class Measure extends ctrlPolygon{
     
     
     
+   
     
     
-    getMarkerMaterial(type) { 
-        if(!markerMats){
-            let maps = [texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png' ),
-                       texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' )]    
-            maps.forEach(map=>{
-                map.repeat.set(1/markerMapShrink,1/markerMapShrink) 
-                map.offset.set((markerMapShrink-1)/2/markerMapShrink,  (markerMapShrink-1)/2/markerMapShrink)
-            })
-                       
-            markerMats = {  
-                default:    new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
-                    transparent: !0,
-                    opacity: 1,
-                    map: maps[0] , 
-                    useDepth:true ,
-                    //mapScale: markerMapShrink
-                })),
-                select:    new THREE.MeshBasicMaterial({  
-                    transparent: !0,
-                    opacity: 1,
-                    depthTest:false,
-                    map: maps[1], 
-                }),   
-            }
-            Measure.markerMats = markerMats
-              
-        }
-        return markerMats[type]
-        
-    }
-    
+     
     
     
     
-    getLineMat(type) { 
-        if(!Measure.lineMats){ 
-            Measure.lineMats = { 
-                edgeDefault:  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
-                    color: config.measure.default.color, 
-                    lineWidth: config.measure.lineWidth,
-                    useDepth :true,
-                    dashWithDepth :true,  // 只在被遮住的部分显示虚线,因为实线容易挡住label 
-                    dashed :true,   
-                    dashSize : 0.04,
-                    gapSize: 0.04,    
-                    transparent: true,
-                    opacity: config.measure.default.opacity,
-                    depthTestWhenPick:true,
-                })),
-                edgeSelect:  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
-                    color: config.measure.highlight.color,//'#f0ff00',
-                    dashSize: 0.5, 
-                    gapSize: 0.2, 
-                    lineWidth: config.measure.lineWidth  ,
-                    transparent: true,
-                    opacity: config.measure.highlight.opacity
-                })),
-                guide:   LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
+    getMat(type) {  
+        if(!Measure.Mats){ //不变色的部分
+            Measure.Mats = {  
+                edgeGuide:   LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
                     color:config.measure.guide.color, 
                     dashSize: 0.1, 
                     gapSize: 0.02,
                     dashed: true,
                     lineWidth: config.measure.lineWidth/2  
                 })), 
+                multiColors:{}
+            }  
+            {
+                markerMaps = [texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ), //pic_point_s32
+                           texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' )]    
+                markerMaps.forEach(map=>{
+                    map.repeat.set(1/markerMapShrink,1/markerMapShrink) 
+                    map.offset.set((markerMapShrink-1)/2/markerMapShrink,  (markerMapShrink-1)/2/markerMapShrink)
+                }) 
+                markerMaps[0].minFilter = 1006 //禁黑边
             }
+          
+                
         }
-        return Measure.lineMats[type]
         
+        
+        let mat = Measure.Mats[type]
+        let multiColors = Measure.Mats.multiColors
+        //console.log('getMat', this.name, this.color, type)
+        if(!mat){
+            
+            let colorObject = multiColors[this.color]
+            if(!colorObject){
+                
+                 
+                let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 }) 
+                let expandColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3: c.l + 0.3)
+                        //new THREE.Color().setHSL(c.h, c.s > 0.5 ? c.s - 0.2 : c.s + 0.2,   c.l >= 0.6 ? c.l - 0.1 : c.l + 0.1 ) 
+                
+                
+                colorObject = { 
+                    edgeDefault:  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
+                        color: this.color || config.measure.default.color, 
+                        lineWidth: config.measure.lineWidth,
+                        useDepth :true,
+                        dashWithDepth :true,  // 只在被遮住的部分显示虚线,因为实线容易挡住label 
+                        dashed :true,   
+                        dashSize : 0.04,
+                        gapSize: 0.04,    
+                        transparent: true,
+                        opacity: config.measure.default.opacity,
+                        depthTestWhenPick:true,
+                    })),
+                    edgeSelect:  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
+                        color: this.color || config.measure.highlight.color,//'#f0ff00',
+                        dashSize: 0.5, 
+                        gapSize: 0.2, 
+                        lineWidth: config.measure.lineWidth  ,
+                        transparent: true,
+                        opacity: config.measure.highlight.opacity
+                    })),
+                    
+                    edgeExpand :  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
+                        color: expandColor, 
+                        useDepth :true,
+                        lineWidth: 2 ,
+                        transparent: true,
+                        opacity: config.measure.default.opacity,
+                    })),
+                    markerDefault:    new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
+                        transparent: !0,
+                        opacity: 1,
+                        map: markerMaps[0] ,  
+                        useDepth:true ,
+                        color: this.color,
+                        //mapScale: markerMapShrink
+                    })),
+                    markerSelect:    new BasicMaterial({  
+                        transparent: !0,
+                        opacity: 1,
+                        depthTest:false,
+                        map: markerMaps[1],  
+                    }),
+                    planeDefault : new DepthBasicMaterial( $.extend({},lineDepthInfo,{
+                        color : this.color || color,
+                        side:THREE.DoubleSide,
+                        opacity:0.2,
+                        transparent:true,
+                        useDepth:true,             
+                    })), 
+                    planeSelected: new THREE.MeshBasicMaterial({
+                        color: this.color || color,
+                        side:THREE.DoubleSide,
+                        opacity:0.3,
+                        transparent:true, 
+                        //wireframe:true                
+                    })
+                } 
+                colorObject.markerSelect.defines.replaceColor = '' //将绿色部分替换成color 
+                colorObject.markerSelect.uniforms.newMapColor = {type:'v3',   value: new THREE.Color(this.color)} 
+                colorObject.markerSelect.onBeforeCompile = function ( shader ) {
+                    shader.fragmentShader = shader.fragmentShader
+                    .replace( 'uniform sampler2D map;', `uniform sampler2D map; uniform vec3 newMapColor;` )//将图中绿色#00C8AF换成指定色
+                    .replace( 'gl_FragColor = texColor * color_;', `
+                        vec3 texWhite = vec3(1.0,1.0,1.0);  //中心部分白色不变,外围原本绿色的r刚好为0,所以r值越高越往白色过渡
+                        texColor.rgb = mix(newMapColor, texWhite, texColor.r);      
+                        gl_FragColor = texColor * color_;` )
+                }
+                multiColors[this.color] = colorObject 
+                 
+                {//清理不用的colorObject
+                    let measures = viewer.scene.measurements.slice()
+                    measures.includes(this) || measures.push(this)
+                    for(let co in multiColors){
+                        multiColors[co].useCount = 0
+                    } 
+                    measures.forEach(e=>{
+                        multiColors[e.color].useCount ++ 
+                    })
+                    let deletes = []
+                    for(let co in multiColors){
+                        if(multiColors[co].useCount == 0){
+                            deletes.push(co)
+                            delete multiColors[co].useCount
+                            for(let i in multiColors[co]){
+                                multiColors[co][i].dispose()
+                            }
+                        }
+                    }
+                    deletes.forEach(co=>delete multiColors[co]) 
+                }  
+            }
+            
+            
+            mat = colorObject[type]
+            
+            
+            
+        } 
+        
+        return mat 
     }
     
     
-    createAreaPlane(){
-        planeMats || (planeMats = { 
-            default: new DepthBasicMaterial( $.extend({},lineDepthInfo,{
-                color:color,
-                side:THREE.DoubleSide,
-                opacity:0.2,
-                transparent:true,
-                useDepth:true,             
-            })), 
-            selected: new THREE.MeshBasicMaterial({
-                color:  color ,
-                side:THREE.DoubleSide,
-                opacity:0.3,
-                transparent:true, 
-                //wireframe:true                
-            })
-        },Measure.planeMats = planeMats)
-        return super.createAreaPlane(planeMats.default)
+    
+    
+    
+    createAreaPlane(){ 
+        return super.createAreaPlane(this.getMat('planeDefault'))
     }
     
      
@@ -1294,6 +1378,7 @@ export class Measure extends ctrlPolygon{
                 
             }
             this.unitSystem = unitSystem
+            this.expands.forEach(e=>e.unitSystem = unitSystem)
             this.update()
         }
     }
@@ -1317,10 +1402,28 @@ export class Measure extends ctrlPolygon{
     } 
 	 
  
-
+    addExpand(data){//{offset,color}
+        data.measure = this
+        let expand = new ExpandLine(data)
+        this.expands.push(expand) 
+        viewer.scene.overlayScene.add(expand) //this.add(expand) //因为其可见性不随父结点所以分开
+    }
+    
+    removeExpand(expand){
+        let index = this.expands.indexOf(expand)
+        if(index > -1){
+            expand.dispose()
+            this.expands.splice(index,1)
+            //this.remove(expand)
+        }
+    }
 }
 
 
+
+
+
+
 function setLabelHightState(label, state){ 
     if(state){  
         let color = new THREE.Color(Potree.config.measure.highlight.color) 
@@ -1341,26 +1444,8 @@ function setLabelHightState(label, state){
     label.updateTexture()  
 }
 
-/* function setLabelHightState(label, state){
-    if(state){ 
-        label.setBackgroundColor({r: highlightColor.r*255, g: highlightColor.g*255, b: highlightColor.b*255, a:config.measure.highlight.labelOpacity})
-        label.sprite.material.useDepth = false;
-        
-    }else{
-        label.setBackgroundColor(mainLabelProp.backgroundColor)  
-        label.sprite.material.useDepth = true
-        
-    } 
-    label.updateTexture() 
-    //label.sprite.material.needsUpdate = true 
-}
  
 
-   */ 
-
-
-
-
 
 function createCircleRadiusLabel(){
 	const circleRadiusLabel = new TextSprite("");
@@ -1377,24 +1462,7 @@ function createCircleRadiusLabel(){
 }
 
 function createCircleRadiusLine(){
-	/* const lineGeometry = new LineGeometry();
-
-	lineGeometry.setPositions([
-		0, 0, 0,
-		0, 0, 0,
-	]);
-
-	const lineMaterial = new LineMaterial({ 
-		color: 0xff0000, 
-		lineWidth: 2, 
-		resolution:  new THREE.Vector2(1000, 1000),
-		gapSize: 1,
-		dashed: true,
-	});
-
-	lineMaterial.depthTest = false;
-
-	const circleRadiusLine = new Line2(lineGeometry, lineMaterial);*/
+	 
 	
     var circleRadiusLine = LineDraw.createFatLine([ ],{
         color:0xff0000,   
@@ -1432,22 +1500,7 @@ function createCircleLine(){
 		);
 	}
 
-	/* const geometry = new LineGeometry();
-	geometry.setPositions(coordinates);
-
-	const material = new LineMaterial({ 
-		color: 0xff0000, 
-		dashSize: 5, 
-		gapSize: 2,
-		lineWidth: 2, 
-		resolution:  new THREE.Vector2(1000, 1000),
-	}); 
-
-	material.depthTest = false;
-
-	const circleLine = new Line2(geometry, material);
-	circleLine.visible = false;
-	circleLine.computeLineDistances();*/
+ 
 
     var circleLine = LineDraw.createFatLine(coordinates,{
         color: 0xff0000,
@@ -1459,16 +1512,7 @@ function createCircleLine(){
 
 	return circleLine;
 }
-
-/* function createCircleCenter(){
-	const sg = new THREE.markerGeometry(1, 32, 32);
-	const sm = new THREE.MeshNormalMaterial();
-	
-	const circleCenter = new THREE.Mesh(sg, sm);
-	circleCenter.visible = false;
-
-	return circleCenter;
-} */
+ 
 
 function createLine(){
 	 
@@ -1522,66 +1566,108 @@ function createCircle(){
 
 }
 
-/* function createAzimuth(){
-
-	const azimuth = {
-		label: null,
-		center: null,
-		target: null,
-		north: null,
-		centerToNorth: null,
-		centerToTarget: null,
-		centerToTargetground: null,
-		targetgroundToTarget: null,
-		circle: null,
-
-		node: null,
-	};
-
-	const sg = new THREE.markerGeometry(1, 32, 32);
-	const sm = new THREE.MeshNormalMaterial();
-
-	{
-		const label = new TextSprite("");
-
-		label.setTextColor({r: 140, g: 250, b: 140, a: 1.0});
-		label.setBorderColor({r: 0, g: 0, b: 0, a: 1.0});
-		label.setBackgroundColor({r: 0, g: 0, b: 0, a: 1.0});
-		label.fontsize = 16;
-		label.material.depthTest = false;
-		label.material.opacity = 1;
-
-		azimuth.label = label;
-	}
-
-	azimuth.center = new THREE.Mesh(sg, sm);
-	azimuth.target = new THREE.Mesh(sg, sm);
-	azimuth.north = new THREE.Mesh(sg, sm);
-	azimuth.centerToNorth = createLine();
-	azimuth.centerToTarget = createLine();
-	azimuth.centerToTargetground = createLine();
-	azimuth.targetgroundToTarget = createLine();
-	azimuth.circle = createCircle();
-
-	azimuth.node = new THREE.Object3D();
-	azimuth.node.add(
-		azimuth.centerToNorth,
-		azimuth.centerToTarget,
-		azimuth.centerToTargetground,
-		azimuth.targetgroundToTarget,
-		azimuth.circle,
-		azimuth.label,
-		azimuth.center,
-		azimuth.target,
-		azimuth.north,
-	);
-
-	return azimuth;
-} */
 
 
 
+//缓冲区扩展,随measure改变,不可拖拽
+class ExpandLine extends ctrlPolygon{
+    
+    constructor (prop) { 
+        prop.points = prop.measure.points.map(e=>e.clone()) //先复制 用来加marker
+        prop.unitSystem = prop.measure.unitSystem
+        prop.atPlane = prop.measure.atPlane
+        prop.closed = prop.measure.closed
+		super('expandLine',prop);
+        
+        this.name = 'measureExpand_'+prop.measure.name
+        
+        
+        this.initData(prop) 
+        
+        //offset 正数为朝外
+    }
+    
+    update(options={}){//暂时每次都全部更新,以后再改
+         
+        let points = this.measure.points
+        let count = this.measure.points.length
+        let newPoints = []
+        let facePlane = this.getFacePlane(true) //更新normal.  不用measure的是因为measure没更新normal
+        let normal = facePlane?.normal //this.measure.facePlane.normal
+        if(!normal)return //暂时不知道怎么写        
+        let offset = this.offset //Potree.math.getArea(this.measure.point2dInfo.points2d) > 0 ? -this.offset : this.offset // 时针受normal影响
+        //console.log('offset',offset, 'normal', normal.toArray(), 'clockwise', Potree.math.getArea(this.measure.point2dInfo.points2d) > 0) 
+        
+        for(let i=0; i<count; i++){
+                
+            let O = points[i]    //该点
+            let A = this.measure.getPoint(i,-1)//points[i-1]  //上一个点
+            let B = this.measure.getPoint(i,1)//points[i+1]  //下一个点
+           
+            
+            let p1, p2      //该点两边的折点
+            let sideVec     //该点两边对应的向量
+            //如果是线段的话,
+            
+            if(!A || !B){ //端点
+                let vec = new THREE.Vector3().subVectors(i==0 ? B : O,   i==0 ? O : A)
+                sideVec = new THREE.Vector3().crossVectors(normal, vec).normalize().multiplyScalar(offset)
+                //sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: i==0 ? B : O, p2: i==0 ? O : A})).setZ(0).multiplyScalar(this.halfPathWidth)  //垂线
+               
+            }else{ 
+                let OA = new THREE.Vector3().subVectors(A,O).normalize()    //只保证俯视角度正确。(如果两点有高度差,该段四个点不会在同一平面,看起来有扭转,有的地方会肥大,但从俯视角度看是正确的。)
+                let OB = new THREE.Vector3().subVectors(B,O).normalize() 
+                let angle = math.getAngle(OA, OB, normal) 
+              
+                if(math.closeTo(angle,0,1e-4) || math.closeTo(angle,Math.PI,1e-4) || math.closeTo(angle, -Math.PI,1e-4)){ //这时候直接加两个向量算出的平分线不准,故直接找垂线
+                    
+                    let vec = new THREE.Vector3().subVectors(O, A)
+                    sideVec = new THREE.Vector3().crossVectors(normal, vec).normalize().multiplyScalar(offset) 
+                    
+                    //sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: O, p2: A}))  //垂线
+                    //console.log('接近0或180',angle, sideVec)
+                }else{
+                    let midVecLength = offset / Math.sin(angle/2)   
+                    sideVec = new THREE.Vector3().addVectors(OA,OB).normalize().multiplyScalar(midVecLength) //角平分线  ( 和上一个方向保持在同一侧,故而顺时针和逆时针方向不同  )
+                } 
+                 
+            }  
+            
+            let p = new THREE.Vector3().addVectors(O, sideVec)  
+            newPoints.push(p) 
+        }
+        this.points = newPoints
+        super.update()
+    }
+    
+    changeOffset(offset){
+        this.offset = offset
+        this.update()
+    }
+    
+     
+    
+    addMarker({point,index }={}){
+        super.addMarker({index, point, edge: LineDraw.createFatLine( [ ],{ mat: this.measure.getMat('edgeExpand')  })})
+    }
+    
+    getArea(){
+         
+        if(!this.closed)return 
+        this.getPoint2dInfo(this.points)
+        this.measure.getArea.call(this)
+        this.measure.getArea()
+         
+        let area = Math.abs(this.measure.area.value - this.area.value)
+        this.area = {value:area, string: this.getConvertString(area, 'area')   }
+        return this.area
+    }
+}
+ExpandLine.prototype.getPoint2dInfo = Measure.prototype.getPoint2dInfo
+ExpandLine.prototype.getConvertString = Measure.prototype.getConvertString
+ 
 
+ 
 
 
 

+ 46 - 27
src/custom/objects/tool/TransformControls.js

@@ -3,7 +3,7 @@ import * as THREE from "../../../../libs/three.js/build/three.module.js";
 import math from "../../utils/math.js";
     
  
-
+let lastUseCamera
 var TransformControls = function ( camera, domElement, options ) {
 
 	if ( domElement === undefined ) {
@@ -97,7 +97,7 @@ var TransformControls = function ( camera, domElement, options ) {
 	var worldQuaternionInv = new THREE.Quaternion();
 	var worldScale = new THREE.Vector3();
 
-	var eye = new THREE.Vector3(); 
+	var eye = new THREE.Vector3();  //整体共用
 
 	var positionStart = new THREE.Vector3();
 	var quaternionStart = new THREE.Quaternion();
@@ -212,7 +212,7 @@ var TransformControls = function ( camera, domElement, options ) {
 
 
 	// Defined getter, setter and store for a property
-	function defineProperty( propName, defaultValue ) {
+	function defineProperty( propName, defaultValue ) { //三个共用参数
 
 		var propValue = defaultValue;
 
@@ -248,8 +248,20 @@ var TransformControls = function ( camera, domElement, options ) {
 	}
  
 	// updateMatrixWorld  updates key transformation variables
-	this.updateMatrixWorld = function () {
+    
+    this.updateEye = function(camera){
+        if(camera.type == "OrthographicCamera"){//xzw add
+            eye.set(0,0,-1).applyQuaternion(camera.quaternion) // this.view.direction
+        }else{
+            eye.copy( cameraPosition ).sub( worldPosition ).normalize();
+        }
+        
+    }
+    
+	this.updateMatrixWorld = function () {//TransformControls
         if(!this.visible)return//add
+        let camera = arguments[1]?.isCamera ? arguments[1] : (Potree.currentRender?.camera || this.camera)
+        lastUseCamera = camera //add 使用父级使用的camera
 		if ( this.object !== undefined ) {
  
 			this.object.updateMatrixWorld();
@@ -274,27 +286,23 @@ var TransformControls = function ( camera, domElement, options ) {
 
 		} 
 
-		this.camera.updateMatrixWorld();
-		this.camera.matrixWorld.decompose( cameraPosition, cameraQuaternion, cameraScale );
+		camera.updateMatrixWorld();
+		camera.matrixWorld.decompose( cameraPosition, cameraQuaternion, cameraScale );
 
 
+        this.updateEye(camera)
         
         
-        if(this.camera.type == "OrthographicCamera"){//xzw add
-            eye.set(0,0,-1).applyQuaternion(this.camera.quaternion) // this.view.direction
-        }else{
-            eye.copy( cameraPosition ).sub( worldPosition ).normalize();
-        }
 		
 
-		THREE.Object3D.prototype.updateMatrixWorld.call( this );
+		THREE.Object3D.prototype.updateMatrixWorld.call( this  ); 
 
 	};
 
 	this.pointerHover = function () {
         let pointer = viewer.inputHandler.pointer
 		if ( this.object === undefined)return
-        
+        let camera =  viewer.inputHandler.hoverViewport?.camera
 
         //if(this.dragging === true /* || ( pointer.button !== undefined && pointer.button !== 0 )  */) return;
 
@@ -309,12 +317,13 @@ var TransformControls = function ( camera, domElement, options ) {
                 ['sceneObjects','mapObjects',/* 'measure',  */ 'transformationTool', 'model'],
                 viewer.inputHandler.hoverViewport && viewer.inputHandler.hoverViewport.extraEnableLayers
             )
-
-
+    
+            camera && camera!=lastUseCamera && this.updateMatrixWorld(null, camera)  //add 多viewport时重新根据hover的camera更新下
+            
             var intersect = ray.intersectObjects( _gizmo.picker[ this.mode ].children.filter(e=>e.visible), true )[ 0 ] || false;
 
             if ( intersect ) {
-
+                
                 this.axis = intersect.object.name;
 
             } else {
@@ -322,7 +331,12 @@ var TransformControls = function ( camera, domElement, options ) {
                 this.axis = null;
 
             }
+            
+            //console.log('hover', !!intersect)
+            
+            
             if(oldAxis != this.axis){
+                this.dispatchEvent({type:'axisHoveredChange',axis:this.axis, mode:this.mode})
                 viewer.dispatchEvent('content_changed') 
             }
         }else{
@@ -337,7 +351,7 @@ var TransformControls = function ( camera, domElement, options ) {
 
 		if ( /* ( pointer.button === 0 || pointer.button === undefined ) && */ this.axis !== null ) {
 
-			//ray.setFromCamera( pointer, this.camera ); //这句会在floorplan模式get不到intersect
+			//ray.setFromCamera( pointer, camera ); //这句会在floorplan模式get不到intersect
 			let {origin, direction} = viewer.inputHandler.getMouseDirection()  
             ray.set(origin,  direction);
             
@@ -395,6 +409,7 @@ var TransformControls = function ( camera, domElement, options ) {
 			} 
 
 			this.dragging = true;
+            //console.log('this.dragging = true;')
 			mouseDownEvent.mode = this.mode;
 			this.dispatchEvent( mouseDownEvent );
 
@@ -403,11 +418,13 @@ var TransformControls = function ( camera, domElement, options ) {
 	};
 
 	this.pointerMove = function ( /* pointer */ ) {
+        //console.log('pointerMove')
         let pointer = viewer.inputHandler.pointer
 		var axis = this.axis;
 		var mode = this.mode;
 		var object = this.object;
 		var space = this.space;
+        let camera =  viewer.inputHandler.hoverViewport?.camera
 
 		if ( mode === 'scale' ) {
 
@@ -422,7 +439,7 @@ var TransformControls = function ( camera, domElement, options ) {
 
 		if ( object === undefined || axis === null || this.dragging === false || ( pointer.button !== undefined && pointer.button !== 0 ) ) return;
 
-		//ray.setFromCamera( pointer, this.camera ); //这句会在floorplan模式get不到intersect
+		//ray.setFromCamera( pointer, camera ); //这句会在floorplan模式get不到intersect
         let {origin, direction} = viewer.inputHandler.getMouseDirection()  
 		ray.set(origin,  direction);
 
@@ -431,7 +448,9 @@ var TransformControls = function ( camera, domElement, options ) {
             viewer.inputHandler.hoverViewport && viewer.inputHandler.hoverViewport.extraEnableLayers
         )
 
-
+        
+        camera && camera!=lastUseCamera && this.updateMatrixWorld(null, camera)  //add 多viewport时重新根据hover的camera更新下
+            
 
 		var planeIntersect = ray.intersectObjects( [ _plane ], true )[ 0 ] || false;
 
@@ -640,7 +659,7 @@ var TransformControls = function ( camera, domElement, options ) {
                     endNorm.copy( pointEnd ).normalize();
 
                     rotationAngle *= ( endNorm.cross( startNorm ).dot( eye ) < 0 ? 1 : - 1 ); //角度
-
+                    
                 }else{
                     if ( axis === 'XYZE' ) {//像滚球一样拨动,鼠标滑动方向为拨动方向,在plane面上滚动
                         offset.copy( pointEnd ).sub( pointStart );
@@ -792,7 +811,7 @@ var TransformControls = function ( camera, domElement, options ) {
 		}
 
 		this.dragging = false;
-
+         
 		//if ( pointer.button === undefined ) this.axis = null;
 		
 		/* if(this.player.cameraControls.activeControl){
@@ -1377,10 +1396,10 @@ var TransformControlsGizmo = function (options) {
 
 	// updateMatrixWorld will update transformations and appearance of individual handles
 
-	this.updateMatrixWorld = function () {
+	this.updateMatrixWorld = function () { //TransformControlsGizmo
         if(!this.parent.visible)return //add
 		var space = this.space;
-
+        let camera = lastUseCamera || Potree.currentRender?.camera || this.camera 
 		if ( this.mode === 'scale' ) space = 'local'; // scale always oriented to local rotation
 
 		var quaternion = space === "local" ? this.worldQuaternion : identityQuaternion;
@@ -1418,8 +1437,8 @@ var TransformControlsGizmo = function (options) {
 			handle.position.copy( this.worldPosition );
 
 
-            if(this.camera.type == "OrthographicCamera"){
-                var eyeDistance = 800 / this.camera.zoom
+            if(camera.type == "OrthographicCamera"){
+                var eyeDistance = 800 / camera.zoom
             }else{
                 var eyeDistance = this.worldPosition.distanceTo( this.cameraPosition );
             }
@@ -1860,7 +1879,7 @@ var TransformControlsGizmo = function (options) {
   */
 
 
-
+ 
 var TransformControlsPlane = function (options) {
 
 	'use strict';
@@ -1882,7 +1901,7 @@ var TransformControlsPlane = function (options) {
 	var tempMatrix = new THREE.Matrix4();
 	var identityQuaternion = new THREE.Quaternion();
 
-	this.updateMatrixWorld = function () {
+	this.updateMatrixWorld = function () {//TransformControlsPlane
         if(!this.visible)return//add 
         var space = this.space;
 

+ 18 - 9
src/custom/objects/tool/ctrlPolygon.js

@@ -4,7 +4,7 @@ import * as THREE from "../../../../libs/three.js/build/three.module.js";
  
 import {LineDraw, MeshDraw} from "../../utils/DrawUtil.js";
 import math from "../../utils/math.js";
-
+import {config} from '../../settings.js'
 
 
 
@@ -20,12 +20,13 @@ export class ctrlPolygon extends THREE.Object3D {
         this.Type = type
         
         this.maxMarkers = Number.MAX_SAFE_INTEGER;
-       
+        
          
         this.transformData(prop);
         for(let i in prop){
             this[i] = prop[i]
         }
+        this.color = this.color || config.measure.default.color
         
         if((this.atPlane || this.showArea ) && this.closed && this.dimension == '2d'){
             this.areaPlane = this.createAreaPlane(); 
@@ -535,12 +536,12 @@ export class ctrlPolygon extends THREE.Object3D {
     };
     
      
-    getFacePlane(){//最普通一种get方法,根据顶点。且假设所有点已经共面,且不重合
+    getFacePlane(force){//最普通一种get方法,根据顶点。且假设所有点已经共面,且不重合
     
         if(/* !this.atPlane ||  */this.points.length<3) return
         /* this.facePlane = new THREE.Plane().setFromCoplanarPoints(...this.points.slice(0,3) ) */ 
         let facePlane = this.facePlane
-        if(!this.atPlane || !facePlane){//多折线 没有实时更新facePlane所以重新算
+        if(force || !this.atPlane || !facePlane){//多折线 没有实时更新facePlane所以重新算
             let normal = new THREE.Vector3, len = this.points.length - 2
             for(let i=0;i<len;i++){ //获取normal的顺序方法必须和setFromCoplanarPoints一致
                 let vec0 = new THREE.Vector3().subVectors(this.points[i+2], this.points[i+1], )
@@ -750,8 +751,14 @@ export class ctrlPolygon extends THREE.Object3D {
     
     getIndex(index, add){
         let lastIndex = this.points.length - 1
-        if(add == -1) return (index === 0) ? lastIndex : index - 1;
-        else if(add == 1)  return (index + 1 > lastIndex) ? 0 : index + 1; 
+        if(add == -1) return (index === 0) ? (this.closed ? lastIndex : null) : index - 1;
+        else if(add == 1)  return (index + 1 > lastIndex) ? (this.closed ? 0 : null)  : index + 1; 
+    }
+     
+    
+    getPoint(index, add){
+        let index_ = this.getIndex(index, add)
+        return index_ == null ? null : this.points[index_]
     }
      
     updateEdge(index, p1,p2){
@@ -771,9 +778,11 @@ export class ctrlPolygon extends THREE.Object3D {
             this.updateMarker(this.markers[options.index], this.points[options.index])
             let previousIndex = this.getIndex(options.index, -1)
             let nextIndex = this.getIndex(options.index, +1) 
-            if( this.closed || nextIndex != 0  ) this.updateEdge(options.index, [this.points[options.index], this.points[nextIndex]]) //LineDraw.updateLine( this.edges[options.index], [this.points[options.index], this.points[nextIndex]]) 
+            /* if( this.closed || nextIndex != 0  ) this.updateEdge(options.index, [this.points[options.index], this.points[nextIndex]]) //LineDraw.updateLine( this.edges[options.index], [this.points[options.index], this.points[nextIndex]]) 
             if( this.closed || previousIndex != lastIndex  ) this.updateEdge(previousIndex, [this.points[options.index], this.points[previousIndex]]) //LineDraw.updateLine( this.edges[previousIndex], [this.points[options.index], this.points[previousIndex]]) 
-     
+            */
+            if( nextIndex != null  ) this.updateEdge(options.index, [this.points[options.index], this.points[nextIndex]]) 
+            if( previousIndex != null  ) this.updateEdge(previousIndex, [this.points[options.index], this.points[previousIndex]]) //LineDraw.updateLine( this.edges[previousIndex], [this.points[options.index], this.points[previousIndex]]) 
         }else{
             
             for (let index = 0; index <= lastIndex; index++) {
@@ -790,7 +799,7 @@ export class ctrlPolygon extends THREE.Object3D {
                 }   
                 
                 
-                if(!this.closed && nextIndex == 0  )break; //add
+                if(!nextPoint /* this.closed && nextIndex == 0  */ )break; //add
                 { 
                     this.updateEdge(index,[point, nextPoint])
                     /* let edge = this.edges[index]; 

+ 4 - 4
src/custom/settings.js

@@ -254,9 +254,9 @@ const config = {//配置参数   不可修改
          
         bothMapAndScene: 3,
         
-        siteModeOnlyMapVisi:12,//只能mapViewer可见
-        siteModelMapUnvisi:13,//只有mapViewer不可见
-        siteModeSideVisi:14,//只有侧面可见
+        onlyMapVisi:12,//只能mapViewer可见
+        mapUnvisi:13,//只有mapViewer不可见
+        sideVisi:14,//只有侧面可见
         
         
         layer1: 18,// 备用1
@@ -375,7 +375,7 @@ const config = {//配置参数   不可修改
     maxLRUPoints:40e6,
     depthTexUVyLimit: 0.141, // 在这个范围内是没有深度的,从图片算的0.14003, 设置为稍大于这个数值
     
-    maxSplatCount: 3000000, //整个网页最大支持显示多少个
+    maxSplatCount: 2000000, //整个网页最大支持显示多少个
     
     //neighbourPath:'data/1111/extraNeighbours.js' //本地版手动额外配置,权重最高
 }

+ 43 - 19
src/custom/start.js

@@ -23,12 +23,13 @@ var transformPointcloud = (pointcloud, dataset)=>{
     
     //dataset.orientation = 0
     let Alignment = viewer.modules.Alignment
-    Alignment.rotate(pointcloud, null, dataset.orientation)   
+    Alignment.rotate(pointcloud, null, dataset.quaternion||dataset.orientation)   
     Alignment.translate(pointcloud, new THREE.Vector3(location[0], location[1],  dataset.location[2]-baseZ)) //要使初始数据集的z为0,所以要减去初始数据集的z
     
     pointcloud.updateMatrixWorld()
      
-    Potree.Log(`点云${pointcloud.dataset_id}(${pointcloud.name})旋转值:${pointcloud.orientationUser}, 位置${math.toPrecision(pointcloud.translateUser.toArray(),3)}, 经纬度 ${dataset.location}, spacing ${pointcloud.material.spacing}`,{font:{color:"#f49",fontSize:13}} )
+    Potree.Log(`点云${pointcloud.dataset_id}(${pointcloud.name})旋转值: qua  ${dataset.quaternion||''}、orient ${ math.toPrecision(dataset.orientation,3) }, 
+        位置${math.toPrecision(pointcloud.translateUser.toArray(),3)},  经纬度 ${dataset.location}, spacing ${pointcloud.material.spacing}`,{font:{color:"#f49",fontSize:13}} )
      
 }
 
@@ -686,7 +687,13 @@ export function mergeEditStart(dom, mapDom){
     Potree.settings.boundAddObjs = true
     Potree.settings.unableNavigate = true
    
-    
+    if(Potree.settings.queryCloudLonLatUrl){ //点云使用其经纬度作为默认位置
+        Potree.loadControlPoint = /* async  */function(callback,sceneCode,onError,prefix){//点云绑定地图 
+            return Potree.loadFile(Potree.settings.queryCloudLonLatUrl.replace('{sceneCode}', sceneCode),  {
+                fetchMethod: 'post'
+            }, callback,onError) 
+        }   
+    }
     
     let viewer = new Potree.Viewer(dom, mapDom );
    
@@ -711,7 +718,7 @@ export function mergeEditStart(dom, mapDom){
     
     Potree.settings.sizeFitToLevel = true//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
     Potree.loadPointCloudScene = function(url, type, id, title, done, onError, prefix){//对应4dkk的场景码
-        let dataset 
+        let dataset , useLonLat
         let loadCloud = ({cloudPath, sceneName, sceneCode, timeStamp, color } )=>{
             
             Potree.loadPointCloud(cloudPath, sceneName , sceneCode, timeStamp, e => {
@@ -734,14 +741,13 @@ export function mergeEditStart(dom, mapDom){
                 pointcloud.changePointSize(config.realPointSize)  //material.size =  config.pointSize;
                 pointcloud.changePointOpacity(1)
                 
-                dataset && (transformPointcloud(pointcloud,  dataset),  pointcloud.hasLonLat = true)
+                dataset && useLonLat && (transformPointcloud(pointcloud,  dataset),  pointcloud.hasLonLat = true)
                 
                 material.shape = Potree.PointShape.SQUARE; 
                 color && (pointcloud.color = pointcloud.material.color = color)     
                 pointcloud.timeStamp = timeStamp 
                 scene.addPointCloud(pointcloud);
-                 
-                
+                  
                 {
                     
                     viewer.updateModelBound()
@@ -764,19 +770,35 @@ export function mergeEditStart(dom, mapDom){
         }
         
         if(type == 'laser'){ 
-            let sceneCode = url
-            Potree.loadDatasets((data)=>{ 
+            let sceneCode = url 
+            let load = ()=>{
+                Potree.loadDatasets((data)=>{ 
                 let originDataset = data.find(e=>e.sceneCode == sceneCode);//只加载初始数据集  
-                /* if(!originDataset){
-                    //应该是data为空,原因未知
-                } */
-                
-                let timeStamp = originDataset.updateTime ? originDataset.updateTime.replace(/[^0-9]/ig,'') : '';  //每重算一次后缀随updateTime更新一次 
-                //let cloudPath = `${Potree.settings.urls.prefix1}/${Potree.settings.webSite}/${sceneCode}/data/${sceneCode}/webcloud/cloud.js` 
-                let cloudPath = `${Potree.settings.urls.prefix1}/${originDataset.webBin}`  //webBin添加原因:每次裁剪之类的操作会换路径,因为oss文件缓存太严重,更新慢
-                dataset = originDataset
-                loadCloud({cloudPath, sceneName:originDataset.sceneName, sceneCode, timeStamp, color:originDataset.color})
-            }, sceneCode, onError, prefix)
+                    /* if(!originDataset){
+                        //应该是data为空,原因未知
+                    } */
+                    
+                    let timeStamp = originDataset.updateTime ? originDataset.updateTime.replace(/[^0-9]/ig,'') : '';  //每重算一次后缀随updateTime更新一次 
+                    //let cloudPath = `${Potree.settings.urls.prefix1}/${Potree.settings.webSite}/${sceneCode}/data/${sceneCode}/webcloud/cloud.js` 
+                    let cloudPath = `${Potree.settings.urls.prefix1}/${originDataset.webBin}`  //webBin添加原因:每次裁剪之类的操作会换路径,因为oss文件缓存太严重,更新慢
+                    dataset = originDataset
+                    loadCloud({cloudPath, sceneName:originDataset.sceneName, sceneCode, timeStamp, color:originDataset.color})
+                }, sceneCode, onError, prefix)
+            } 
+            if(Potree.settings.queryCloudLonLatUrl){
+                Potree.loadControlPoint((ctlData)=>{
+                    useLonLat = ctlData.controlPoint.status==1  //设置了地理位置 
+                    load()    
+                }, sceneCode, (e)=>{
+                    console.error('loadControlPoint error',e)
+                    load()
+                })
+            }else{
+                load()
+            }
+            
+            
+            
         
         }else{//las or ply  直接用url
             let name = type + '|' + id + '|' + title
@@ -1109,6 +1131,8 @@ export function mergeEditStart(dom, mapDom){
         }else{  
              
             prop.url instanceof Array && (prop.url = prop.url[0]) //deal bug
+            
+            
             Potree.loadPointCloudScene(prop.url, prop.type, prop.modelId, prop.title, (pointcloud)=>{   
                 { 
                     pointcloud.matrixAutoUpdate = true

+ 1 - 1
src/custom/three.shim.js

@@ -117,7 +117,7 @@ THREE.WebGLRenderer.prototype.paramThreeToGL = function(e) {
     }
     return 0
 }
-
+ 
 
 THREE.EventDispatcher.prototype.addEventListener = function(type, listener, {importance=0, once}={}){    //add importance
 	if ( this._listeners === undefined ) this._listeners = {};

+ 8 - 3
src/custom/utils/math.js

@@ -3,7 +3,7 @@ import * as THREE from "../../../libs/three.js/build/three.module.js";
 import searchRings from "./searchRings.js";
 import {ExtendView} from '../../viewer/ExtendView.js'
  
-
+let view = new ExtendView()
 var math = {
     getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) .  Math.log 返回一个数的自然对数
         return Math.log(y) / Math.log(x);
@@ -607,12 +607,18 @@ var math = {
     getQuaFromPosAim( position, target ){ 
         /* let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1)) //这里垂直的话会默认给一个右向所以不这么写
         return (new THREE.Quaternion).setFromRotationMatrix(matrix) */
-        let view = new ExtendView()
+        
         view.direction = new THREE.Vector3().subVectors(target,position) 
         return view.quaternion
     },
     
     
+    getYawPitchByQua(qua){
+        view.quaternion = qua
+        return {yaw:view.yaw, pitch:view.pitch}
+    },
+    
+    
     getBoundByPoints(points, minSize){ 
         var bound = new THREE.Box3
         points.forEach(point=>{
@@ -630,7 +636,6 @@ var math = {
         }
     },
 
-        
     /* linearClamp(value,  x1,x2, y1, y2){//x为bound.min, bound.max
         value = THREE.Math.clamp(value, x1,x2)
         return y1 + ( y2 - y1) * (value - x1)  / (x2 - x1)  

+ 59 - 21
src/custom/viewer/ViewerNew.js

@@ -15,6 +15,7 @@ import Stats from "../../../libs/stats.js/stats.js";
 import {ClipTask, ClipMethod, CameraMode, LengthUnits, ElevationGradientRepeat} from "../../defines.js";
 import {TagTool} from "../objects/tool/TagTool.js"; 
 import Compass from "../objects/tool/Compass.js";
+import {FloorCompass} from "../objects/tool/FloorCompass.js";
 import AxisViewer from "../objects/tool/AxisViewer.js";
  
     
@@ -47,7 +48,7 @@ import math from "../utils/math.js";
 import {MeshDraw}  from '../utils/DrawUtil.js'
 import {UoMService}  from '../utils/UnitConvert.js'
 import {ClippingTool} from "../../utils/ClippingTool.js";
-import {TransformationTool} from "../../utils/TransformationToolNew.js";
+import {TransformationTool} from "../../utils/TransformationToolNew.js"; 
 import {Utils} from "../../utils.js";
 import {BoxVolume} from "../../utils/VolumeNew.js";
 import {VolumeTool} from "../../utils/VolumeTool.js";
@@ -528,9 +529,11 @@ export class Viewer extends ViewerBase{
                     left:0, bottom:0, width:1, height: 1, name:'MainView' 
                 }) 
                 this.viewports = [this.mainViewport]       
-                Potree.settings.showCompass && (this.compass = new Compass(Potree.settings.compassDom, this.mainViewport));
+                Potree.settings.showCompass && this.addCompass()
+                
+                
+                
                 
-                 
                 //this.axis = new AxisViewer(this.mainViewport, this.renderArea )
                 
                  
@@ -782,13 +785,8 @@ export class Viewer extends ViewerBase{
         } 
         
         this.addEventListener('allLoaded', ()=>{
-            
-            this.splatMesh = new Splat()
-            this.splatMesh.addPointcloud(this.scene.pointclouds[0])
-            
-            
-            
-            
+            this.allLoaded = true
+             
             setTimeout(this.testPointcloudsMaxLevel.bind(this), 1000) //延迟一丢丢,等画面出现
             
             //Potree.settings.renderAllViewports = browser.maybeQilin() && this.renderer.capabilities.maxCubemapSize <= 2048 && //麒麟chromium若获取过webgl2只渲染一个viewport的话其他的会变黑
@@ -994,6 +992,18 @@ export class Viewer extends ViewerBase{
         
 	}
     
+    
+    addCompass(){
+        if(this.compass)return
+        
+        this.compass = new Compass(Potree.settings.compassDom, this.mainViewport) ; 
+        
+        if(!Potree.settings.editType){//激光场景
+            this.floorCompass = new FloorCompass(this)
+        }
+    }
+    
+    
     lazyRenderViewports(updateCount){
         //本来要写this.needRender = true的, 但在分四个屏时防止太卡而排队render
         let viewports = this.viewports
@@ -3354,7 +3364,7 @@ export class Viewer extends ViewerBase{
             params.useModelOnRT = Potree.settings.intersectOnObjs && pRenderer.canUseRTPoint()  
                                 && pRenderer.getIfRtEDL_(params) && !pRenderer.getIfuseEdl(params) //模型是否绘制在rtEDL上且能直接绘制到屏幕(感觉容易错)
                         
-        
+            
             
             var left,bottom,width,height
             { 
@@ -3428,7 +3438,10 @@ export class Viewer extends ViewerBase{
                  
                 this.renderBG(viewport)
                  
-                 
+                if(this.splatMesh){
+                    Potree.Utils.setCameraLayers(params.camera, ['model'])
+                    this.renderer.render(this.splatMesh, params.camera) 
+                } 
    
                 if(Potree.settings.notAdditiveBlending ){
                     params.renderBeforeCloud = true
@@ -3460,11 +3473,7 @@ export class Viewer extends ViewerBase{
                this.renderOverlay(params)                 
             }
                
-            if(this.splatMesh){
-                Potree.Utils.setCameraLayers(params.camera, ['model'])
-                this.renderer.render(this.splatMesh, params.camera) 
-                
-            }
+            
                
                
             viewport.afterRender && viewport.afterRender() 
@@ -5071,7 +5080,17 @@ export class Viewer extends ViewerBase{
         
         
         this.setAllTilesets(model=>model.runtime.update(deltaTime, this.renderer, this.mainViewport.camera))
-       
+        
+        let hasAnimation
+        this.objs.children.forEach(model=>{
+            if(model.aniMixer){
+                hasAnimation = true
+                model.aniMixer.update(deltaTime)
+            }
+        })
+        hasAnimation && (this.dispatchEvent('content_changed'))
+        
+        
         
 		// let vrActive = viewer.renderer.xr.isPresenting;
 		// if(vrActive){
@@ -5778,7 +5797,7 @@ export class Viewer extends ViewerBase{
     
     
     
-        if(fileInfo.fileType == 'obj'){
+        if(fileInfo.fileType == 'obj' && !fileInfo.objurl){
             let a = fileInfo.url.split('/') 
             let tails = a.pop().split('.') 
             let head = a.join('/') + '/'
@@ -5809,8 +5828,27 @@ export class Viewer extends ViewerBase{
         }else if(fileInfo.fileType == 'glb'){ 
             loaders.glbLoader.unlitMat = true//!!fileInfo.unlit
             loaders.glbLoader.load(fileInfo.url,  ( gltf, total )=>{    
-                //console.log('loadGLTF', gltf)
-                loadDone(gltf.scene/* , total, fileInfo.url */) 
+                console.log('loadGLTF', gltf)
+                let model = gltf.scene
+                if(gltf.animations.length){
+                    //let skeleton = new THREE.SkeletonHelper( model );
+					//skeleton.visible = true;
+					//model.add( skeleton ); 
+                    /* viewer.scene.scene.add(skeleton)
+                    model.skeletonHelper = skeleton //注意:不能覆盖model.skeleton,因其另有 */
+                    
+                    let mixer = new THREE.AnimationMixer( model);
+                   
+                    gltf.animations.forEach(ani=>{
+                        let action = mixer.clipAction( ani ); 
+                    })
+                    model.aniMixer = mixer
+                }
+                model.gltf = gltf
+                
+                
+                
+                loadDone(model) 
             }, onProgress, onError)
             
         }else if(fileInfo.fileType == 'ply'){

+ 8 - 1
src/custom/viewer/viewerBase.js

@@ -75,6 +75,13 @@ export class ViewerBase extends THREE.EventDispatcher{
         this.renderer.domElement.addEventListener('mousedown', () => {
             this.renderer.domElement.focus();
         });
+        {
+            let oldRender = this.renderer.render
+            this.renderer.render = function(scene, camera){
+                Potree.currentRender = {renderer: this,  scene, camera }
+                oldRender.apply(this, arguments)
+            }    
+        }
         //this.renderer.domElement.focus();
 
         // NOTE: If extension errors occur, pass the string into this.renderer.extensions.get(x) before enabling
@@ -99,7 +106,7 @@ export class ViewerBase extends THREE.EventDispatcher{
                                                             
                            
  
-                                                
+                                       
                                       
                                
                                                                             

+ 1 - 1
src/loader/BinaryLoader.js

@@ -107,7 +107,7 @@ export class BinaryLoader{
 					let bufferAttribute = new THREE.BufferAttribute(new Float32Array(buffer), 6);
 					geometry.setAttribute('covs', bufferAttribute);
                   
-				} else if(property === 'GS3D'){//改
+				} else if(property != 'GS3D'){//改
                     //geometry.setAttribute("rgba", new THREE.BufferAttribute(new Uint8Array(buffer), 4, true));
 					const bufferAttribute = new THREE.BufferAttribute(new Float32Array(buffer), 1);
  

+ 16 - 14
src/viewer/EDLRendererNew.js

@@ -236,7 +236,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         if(!params.magnifier){ 
             if(Potree.settings.displayMode == 'showPanos' || Potree.settings.testCube ){
                  
-                Potree.Utils.setCameraLayers(camera, ['skybox'])
+                Potree.Utils.setCameraLayers(camera, ['skybox']) //注:model等也可能是skybox
             
                 if((Potree.settings.displayMode == 'showPanos' ) && (viewer.images360.currentPano.pointcloud.hasDepthTex || Potree.settings.modelSkybox && viewer.images360.currentPano.pointcloud.is4dkkModel) && rtEDL){//渲染深度图
                      
@@ -259,7 +259,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                     if(Potree.settings.fastTran && viewer.images360.fastTranMaskPass.enabled){
                         viewer.images360.fastTranMaskPass.render()
                     } 
-                    if(viewer.objs.children.length == 0 || !params.useModelOnRT) return 
+                    if( viewer.objs.children.length == 0 || !params.useModelOnRT  ) return //没有模型需要绘制遮挡
                 }
                  
                  
@@ -267,15 +267,17 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
             
         }  
          
-        
-		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => Potree.Utils.getObjVisiByReason(pc,'datasetSelection')  ); //需要绘制到rtEDL的
-		const showPointClouds = params.magnifier ? visiblePointClouds2.length>0 : viewer.scene.pointclouds.some(e=>e.visible) //是否有需要绘制到屏幕的
+        const pointclouds = viewer.scene.pointclouds.filter(pc => !pc.isSplat)
+		const visiblePointClouds2 = pointclouds.filter(pc => pc.visible/* Potree.Utils.getObjVisiByReason(pc,'datasetSelection') */  ); //需要绘制到rtEDL的
+		const showPointClouds = params.magnifier ? visiblePointClouds2.length>0 : pointclouds.some(e=>e.visible) //是否有需要绘制到屏幕的
          
-        visiblePointClouds2.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云
+        /* visiblePointClouds2.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下 
             e.oldVisi = e.visible
             e.visible = true; 
-        })
- 
+        }) */
+        //好难写- -,太多东西了,无depTex时要把不显示的点云和模型绘制到rt上,但是rt又可能直接绘制到画面。有的模型是要在全景模式显示的
+        //所以决定去掉不显示的点云,无深度图的话就无遮挡   http://192.168.0.21/index.php?m=bug&f=view&bugID=49575
+        
         Potree.Utils.setCameraLayers(camera, ['pointcloud']) //设置多少都会渲染出来,因为渲染里没有sort
         //camera.layers.set(Potree.config.renderLayers.pointcloud);
 		
@@ -330,11 +332,11 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 		viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer });
 		renderer.setRenderTarget( target );
         
-        if(!params.magnifier)visiblePointClouds2.forEach(e=>{//放大镜显示点云
+        /* if(!params.magnifier)visiblePointClouds2.forEach(e=>{//放大镜显示点云
             e.visible = e.oldVisi
-        })
+        }) */
          
-        
+       
         
         {//绘制点云到画布
             if(useEDL){  //设置edlMaterial  //Features.EXT_DEPTH不支持的话不会到这一块
@@ -355,7 +357,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                      
                     Utils.screenPass.render(renderer, this.edlMaterial, target);  //相当于一个描边后期特效。 缺点: 因为target上的没有抗锯齿,所以点云在晃动镜头时会不稳定地闪烁1px位置。优点:比不打开edl少绘制一次点云,更流畅了?!
                 }
-            }else if(this.canUseRTPoint() && rtEDL){ 
+            }else if(this.canUseRTPoint() && rtEDL ){  
                 //半透明点云在clearAlpha为非1的状态下截图 或 在useRTPoints时绘制到屏幕上透明度不对,亮度变低 。深度值遮挡也不对。 只能在半透明时关闭一下useRTPoint
                 this.recoverToScreenMat.uniforms.tDiffuse.value = rtEDL.texture; 
                 if(this.recoverToScreenMat.defines.useDepth){
@@ -379,9 +381,9 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
             }
         }   
            
-        visiblePointClouds2.forEach(e=>{
+        /* visiblePointClouds2.forEach(e=>{
             e.visible = e.oldVisi
-        })
+        }) */
 
    
         //viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});

+ 7 - 7
src/workers/BinaryDecoderWorker.js

@@ -106,7 +106,7 @@ onmessage = function (event) {
 	let tightBoxMin = [ Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY ];
 	let tightBoxMax = [ Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY ];
 	let mean = [0, 0, 0];
-	
+	let pos = event.data.min // add geometryNode.sceneNode.position  node的偏移
 
 	let attributeBuffers = {};
 	let inOffset = 0;
@@ -160,13 +160,13 @@ onmessage = function (event) {
                 let centersInt = new Int32Array(buff2);
                 let centersFloat = new Float32Array(buff3);
                 for(let i=0;i<numPoints;i++){
-                    centersFloat[4 * i + 0] = positions[3 * i + 0]
-                    centersFloat[4 * i + 1] = positions[3 * i + 1]
-                    centersFloat[4 * i + 2] = positions[3 * i + 2]
+                    centersFloat[4 * i + 0] = positions[3 * i + 0] + pos[0]
+                    centersFloat[4 * i + 1] = positions[3 * i + 1] + pos[1]
+                    centersFloat[4 * i + 2] = positions[3 * i + 2] + pos[2]
                     centersFloat[4 * i + 3] = 1;
-                    centersInt[4 * i + 0] = positions[3 * i + 0] * 1000
-                    centersInt[4 * i + 1] = positions[3 * i + 1] * 1000
-                    centersInt[4 * i + 2] = positions[3 * i + 2] * 1000
+                    centersInt[4 * i + 0] = centersFloat[4 * i + 0] * 1000
+                    centersInt[4 * i + 1] = centersFloat[4 * i + 1] * 1000
+                    centersInt[4 * i + 2] = centersFloat[4 * i + 2] * 1000
                     centersInt[4 * i + 3] = 1000
                 }
                 attributeBuffers['centersInt'] = { buffer: buff2, attribute: pointAttribute };