ShapefileLoader.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {Line2} from "../../libs/three.js/lines/Line2.js";
  3. import {LineGeometry} from "../../libs/three.js/lines/LineGeometry.js";
  4. import {LineMaterial} from "../../libs/three.js/lines/LineMaterial.js";
  5. export class ShapefileLoader{
  6. constructor(){
  7. this.transform = null;
  8. }
  9. async load(path){
  10. const matLine = new LineMaterial( {
  11. color: 0xff0000,
  12. linewidth: 3, // in pixels
  13. resolution: new THREE.Vector2(1000, 1000),
  14. dashed: false
  15. } );
  16. const features = await this.loadShapefileFeatures(path);
  17. const node = new THREE.Object3D();
  18. for(const feature of features){
  19. const fnode = this.featureToSceneNode(feature, matLine);
  20. node.add(fnode);
  21. }
  22. let setResolution = (x, y) => {
  23. matLine.resolution.set(x, y);
  24. };
  25. const result = {
  26. features: features,
  27. node: node,
  28. setResolution: setResolution,
  29. };
  30. return result;
  31. }
  32. featureToSceneNode(feature, matLine){
  33. let geometry = feature.geometry;
  34. let color = new THREE.Color(1, 1, 1);
  35. let transform = this.transform;
  36. if(transform === null){
  37. transform = {forward: (v) => v};
  38. }
  39. if(feature.geometry.type === "Point"){
  40. let sg = new THREE.SphereGeometry(1, 18, 18);
  41. let sm = new THREE.MeshNormalMaterial();
  42. let s = new THREE.Mesh(sg, sm);
  43. let [long, lat] = geometry.coordinates;
  44. let pos = transform.forward([long, lat]);
  45. s.position.set(...pos, 20);
  46. s.scale.set(10, 10, 10);
  47. return s;
  48. }else if(geometry.type === "LineString"){
  49. let coordinates = [];
  50. let min = new THREE.Vector3(Infinity, Infinity, Infinity);
  51. for(let i = 0; i < geometry.coordinates.length; i++){
  52. let [long, lat] = geometry.coordinates[i];
  53. let pos = transform.forward([long, lat]);
  54. min.x = Math.min(min.x, pos[0]);
  55. min.y = Math.min(min.y, pos[1]);
  56. min.z = Math.min(min.z, 20);
  57. coordinates.push(...pos, 20);
  58. if(i > 0 && i < geometry.coordinates.length - 1){
  59. coordinates.push(...pos, 20);
  60. }
  61. }
  62. for(let i = 0; i < coordinates.length; i += 3){
  63. coordinates[i+0] -= min.x;
  64. coordinates[i+1] -= min.y;
  65. coordinates[i+2] -= min.z;
  66. }
  67. const lineGeometry = new LineGeometry();
  68. lineGeometry.setPositions( coordinates );
  69. const line = new Line2( lineGeometry, matLine );
  70. line.computeLineDistances();
  71. line.scale.set( 1, 1, 1 );
  72. line.position.copy(min);
  73. return line;
  74. }else if(geometry.type === "Polygon"){
  75. for(let pc of geometry.coordinates){
  76. let coordinates = [];
  77. let min = new THREE.Vector3(Infinity, Infinity, Infinity);
  78. for(let i = 0; i < pc.length; i++){
  79. let [long, lat] = pc[i];
  80. let pos = transform.forward([long, lat]);
  81. min.x = Math.min(min.x, pos[0]);
  82. min.y = Math.min(min.y, pos[1]);
  83. min.z = Math.min(min.z, 20);
  84. coordinates.push(...pos, 20);
  85. if(i > 0 && i < pc.length - 1){
  86. coordinates.push(...pos, 20);
  87. }
  88. }
  89. for(let i = 0; i < coordinates.length; i += 3){
  90. coordinates[i+0] -= min.x;
  91. coordinates[i+1] -= min.y;
  92. coordinates[i+2] -= min.z;
  93. }
  94. const lineGeometry = new LineGeometry();
  95. lineGeometry.setPositions( coordinates );
  96. const line = new Line2( lineGeometry, matLine );
  97. line.computeLineDistances();
  98. line.scale.set( 1, 1, 1 );
  99. line.position.copy(min);
  100. return line;
  101. }
  102. }else{
  103. console.log("unhandled feature: ", feature);
  104. }
  105. }
  106. async loadShapefileFeatures(file){
  107. let features = [];
  108. let source = await shapefile.open(file);
  109. while(true){
  110. let result = await source.read();
  111. if (result.done) {
  112. break;
  113. }
  114. if (result.value && result.value.type === 'Feature' && result.value.geometry !== undefined) {
  115. features.push(result.value);
  116. }
  117. }
  118. return features;
  119. }
  120. };