POCLoader.js 11 KB

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