POCLoaderNew.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {PointCloudOctreeGeometry, PointCloudOctreeGeometryNode} from "../PointCloudOctreeGeometry.js";
  3. import {Version} from "../Version.js";
  4. import {XHRFactory} from "../XHRFactory.js";
  5. import {LasLazLoader} from "./LasLazLoader.js";
  6. import {BinaryLoader} from "./BinaryLoader.js";
  7. import {Utils} from "../utils.js";
  8. import {PointAttribute, PointAttributes, PointAttributeTypes} from "./PointAttributes.js";
  9. function parseAttributes(cloudjs){
  10. let version = new Version(cloudjs.version);
  11. const replacements = {
  12. "COLOR_PACKED": "rgba",
  13. "RGBA": "rgba",
  14. "INTENSITY": "intensity",
  15. "CLASSIFICATION": "classification",
  16. "GPS_TIME": "gps-time",
  17. };
  18. const replaceOldNames = (old) => {
  19. if(replacements[old]){
  20. return replacements[old];
  21. }else{
  22. return old;
  23. }
  24. };
  25. const pointAttributes = [];
  26. if(version.upTo('1.7')){
  27. for(let attributeName of cloudjs.pointAttributes){
  28. const oldAttribute = PointAttribute[attributeName];
  29. const attribute = {
  30. name: oldAttribute.name,
  31. size: oldAttribute.byteSize,
  32. elements: oldAttribute.numElements,
  33. elementSize: oldAttribute.byteSize / oldAttribute.numElements,
  34. type: oldAttribute.type.name,
  35. description: "",
  36. };
  37. pointAttributes.push(attribute);
  38. }
  39. }else{
  40. pointAttributes.push(...cloudjs.pointAttributes);
  41. }
  42. {
  43. const attributes = new PointAttributes();
  44. const typeConversion = {
  45. int8: PointAttributeTypes.DATA_TYPE_INT8,
  46. int16: PointAttributeTypes.DATA_TYPE_INT16,
  47. int32: PointAttributeTypes.DATA_TYPE_INT32,
  48. int64: PointAttributeTypes.DATA_TYPE_INT64,
  49. uint8: PointAttributeTypes.DATA_TYPE_UINT8,
  50. uint16: PointAttributeTypes.DATA_TYPE_UINT16,
  51. uint32: PointAttributeTypes.DATA_TYPE_UINT32,
  52. uint64: PointAttributeTypes.DATA_TYPE_UINT64,
  53. double: PointAttributeTypes.DATA_TYPE_DOUBLE,
  54. float: PointAttributeTypes.DATA_TYPE_FLOAT,
  55. };
  56. for(let jsAttribute of pointAttributes){
  57. if(jsAttribute.name == void 0){ //add 有的是这个,也有的不是(点云编辑页的)
  58. var attribute_ = PointAttribute[jsAttribute]
  59. attributes.add(attribute_);
  60. continue;
  61. }
  62. const name = replaceOldNames(jsAttribute.name);
  63. const type = typeConversion[jsAttribute.type];
  64. const numElements = jsAttribute.elements;
  65. const description = jsAttribute.description;
  66. const attribute = new PointAttribute(name, type, numElements);
  67. attributes.add(attribute);
  68. }
  69. {
  70. // check if it has normals
  71. let hasNormals =
  72. pointAttributes.find(a => a.name === "NormalX") !== undefined &&
  73. pointAttributes.find(a => a.name === "NormalY") !== undefined &&
  74. pointAttributes.find(a => a.name === "NormalZ") !== undefined;
  75. if(hasNormals){
  76. let vector = {
  77. name: "NORMAL",
  78. attributes: ["NormalX", "NormalY", "NormalZ"],
  79. };
  80. attributes.addVector(vector);
  81. }
  82. }
  83. return attributes;
  84. }
  85. }
  86. function lasLazAttributes(fMno){
  87. const attributes = new PointAttributes();
  88. attributes.add(PointAttribute.POSITION_CARTESIAN);
  89. attributes.add(new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_UINT8, 4));
  90. attributes.add(new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  91. attributes.add(new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  92. attributes.add(new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1));
  93. attributes.add(new PointAttribute("number of returns", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  94. attributes.add(new PointAttribute("return number", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  95. attributes.add(new PointAttribute("source id", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  96. //attributes.add(new PointAttribute("pointSourceID", PointAttributeTypes.DATA_TYPE_INT8, 4));
  97. return attributes;
  98. }
  99. export class POCLoader {
  100. static load(url, timeStamp, callback){ //add timeStamp
  101. try {
  102. let pco = new PointCloudOctreeGeometry();
  103. pco.timeStamp = timeStamp
  104. pco.url = url;
  105. let xhr = XHRFactory.createXMLHttpRequest();
  106. xhr.open('GET', url+'?m='+timeStamp, true);
  107. xhr.onreadystatechange = function () {
  108. if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 0)) {
  109. let fMno = JSON.parse(xhr.responseText);
  110. let version = new Version(fMno.version);
  111. // assume octreeDir is absolute if it starts with http
  112. if (fMno.octreeDir.indexOf('http') === 0) {
  113. pco.octreeDir = fMno.octreeDir;
  114. } else {
  115. pco.octreeDir = url + '/../' + fMno.octreeDir;
  116. }
  117. pco.spacing = fMno.spacing;
  118. pco.hierarchyStepSize = fMno.hierarchyStepSize;
  119. pco.pointAttributes = fMno.pointAttributes;
  120. let min = new THREE.Vector3(fMno.boundingBox.lx, fMno.boundingBox.ly, fMno.boundingBox.lz);
  121. let max = new THREE.Vector3(fMno.boundingBox.ux, fMno.boundingBox.uy, fMno.boundingBox.uz);
  122. let boundingBox = new THREE.Box3(min, max);
  123. let tightBoundingBox = boundingBox.clone();
  124. if (fMno.tightBoundingBox) {//这个才是真实的bounding,前面那个bounding的size是个正方体,似乎取了最长边作为边长
  125. tightBoundingBox.min.copy(new THREE.Vector3(fMno.tightBoundingBox.lx, fMno.tightBoundingBox.ly, fMno.tightBoundingBox.lz));
  126. tightBoundingBox.max.copy(new THREE.Vector3(fMno.tightBoundingBox.ux, fMno.tightBoundingBox.uy, fMno.tightBoundingBox.uz));
  127. }
  128. let offset = min.clone(); //将成为点云的position,被我用作旋转中心(但在点云中不那么居中,navvis也是这样, 这样可能是为了让模型在这数据的bounding上)
  129. boundingBox.min.sub(offset); //点云的真实坐标的min都是0,0,0吗(我看案例是,因绕角落旋转,也就是原点)
  130. boundingBox.max.sub(offset);
  131. tightBoundingBox.min.sub(offset);
  132. tightBoundingBox.max.sub(offset);
  133. //改
  134. //pco.projection = fMno.projection || "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs ",
  135. //"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" //给地图
  136. pco.boundingBox = boundingBox;
  137. pco.tightBoundingBox = tightBoundingBox;
  138. pco.boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
  139. pco.tightBoundingSphere = tightBoundingBox.getBoundingSphere(new THREE.Sphere());
  140. pco.offset = offset;
  141. if (fMno.pointAttributes === 'LAS') {
  142. pco.loader = new LasLazLoader(fMno.version, "las");
  143. pco.pointAttributes = lasLazAttributes(fMno);
  144. } else if (fMno.pointAttributes === 'LAZ') {
  145. pco.loader = new LasLazLoader(fMno.version, "laz");
  146. pco.pointAttributes = lasLazAttributes(fMno);
  147. } else {
  148. pco.loader = new BinaryLoader(fMno.version, boundingBox, fMno.scale);
  149. pco.pointAttributes = parseAttributes(fMno);
  150. }
  151. let nodes = {};
  152. { // load root
  153. let name = 'r';
  154. let root = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  155. root.level = 0;
  156. root.hasChildren = true;
  157. root.spacing = pco.spacing;
  158. if (version.upTo('1.5')) {
  159. root.numPoints = fMno.hierarchy[0][1];
  160. } else {
  161. root.numPoints = 0;
  162. }
  163. pco.root = root;
  164. pco.root.load();
  165. nodes[name] = root;
  166. }
  167. // load remaining hierarchy
  168. if (version.upTo('1.4')) {
  169. for (let i = 1; i < fMno.hierarchy.length; i++) {
  170. let name = fMno.hierarchy[i][0];
  171. let numPoints = fMno.hierarchy[i][1];
  172. let index = parseInt(name.charAt(name.length - 1));
  173. let parentName = name.substring(0, name.length - 1);
  174. let parentNode = nodes[parentName];
  175. let level = name.length - 1;
  176. //let boundingBox = POCLoader.createChildAABB(parentNode.boundingBox, index);
  177. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  178. let node = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  179. node.level = level;
  180. node.numPoints = numPoints;
  181. node.spacing = pco.spacing / Math.pow(2, level);
  182. parentNode.addChild(node);
  183. nodes[name] = node;
  184. }
  185. }
  186. pco.nodes = nodes;
  187. callback(pco);
  188. }
  189. };
  190. xhr.send(null);
  191. } catch (e) {
  192. console.log("loading failed: '" + url + "'");
  193. console.log(e);
  194. callback();
  195. }
  196. }
  197. loadPointAttributes(mno){
  198. let fpa = mno.pointAttributes;
  199. let pa = new PointAttributes();
  200. for (let i = 0; i < fpa.length; i++) {
  201. let pointAttribute = PointAttribute[fpa[i]];
  202. pa.add(pointAttribute);
  203. }
  204. return pa;
  205. }
  206. createChildAABB(aabb, index){
  207. let min = aabb.min.clone();
  208. let max = aabb.max.clone();
  209. let size = new THREE.Vector3().subVectors(max, min);
  210. if ((index & 0b0001) > 0) {
  211. min.z += size.z / 2;
  212. } else {
  213. max.z -= size.z / 2;
  214. }
  215. if ((index & 0b0010) > 0) {
  216. min.y += size.y / 2;
  217. } else {
  218. max.y -= size.y / 2;
  219. }
  220. if ((index & 0b0100) > 0) {
  221. min.x += size.x / 2;
  222. } else {
  223. max.x -= size.x / 2;
  224. }
  225. return new THREE.Box3(min, max);
  226. }
  227. }