ASCIIGridLoader.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * ASCIIGridLoader.js
  3. *
  4. * @author realor
  5. */
  6. import { ObjectBuilder } from '../../builders/ObjectBuilder.js'
  7. import { Solid } from '../../core/Solid.js'
  8. import { SolidGeometry } from '../../core/SolidGeometry.js'
  9. import { WebUtils } from '../../utils/WebUtils.js'
  10. import * as THREE from '../../lib/three.module.js'
  11. class ASCIIGridLoader extends THREE.Loader {
  12. constructor(manager) {
  13. super(manager)
  14. this.ncols = 0
  15. this.nrows = 0
  16. this.xcenter = 0
  17. this.ycenter = 0
  18. this.cellSize = 0
  19. this.noDataValue = 0
  20. this.grid = []
  21. this.groupSize = 100
  22. this.material = new THREE.MeshPhongMaterial({ color: 0x808030 })
  23. this.options = {}
  24. }
  25. load(url, onLoad, onProgress, onError) {
  26. const loader = new FileLoader(this.manager)
  27. loader.setPath(this.path)
  28. loader.setRequestHeader(this.requestHeader)
  29. loader.setWithCredentials(this.withCredentials)
  30. loader.load(
  31. url,
  32. text => {
  33. try {
  34. onLoad(this.parse(text))
  35. } catch (ex) {
  36. if (onError) {
  37. onError(ex)
  38. } else {
  39. console.error(ex)
  40. }
  41. this.manager.itemError(url)
  42. }
  43. },
  44. onProgress,
  45. onError
  46. )
  47. }
  48. parse(text, onCompleted, onProgress, onError) {
  49. this.parseGrid(text)
  50. let terrain = new THREE.Group()
  51. terrain.name = 'Terrain'
  52. terrain.userData.selection = { type: 'none' }
  53. terrain.userData.grid = {
  54. ncols: this.ncols,
  55. nrows: this.nrows,
  56. xcenter: this.xcenter,
  57. ycenter: this.ycenter,
  58. noDataValue: this.noDataValue
  59. }
  60. const groupSize = this.groupSize
  61. let xsize = Math.ceil(this.ncols / groupSize)
  62. let ysize = Math.ceil(this.nrows / groupSize)
  63. let tileCount = xsize * ysize
  64. const createTile = tileIndex => {
  65. let i = tileIndex % xsize
  66. let j = Math.floor(tileIndex / xsize)
  67. let solid = this.createTileGeometry(groupSize * i, groupSize * j)
  68. solid.name = 'cell-' + i + '-' + j
  69. solid.edgesVisible = false
  70. terrain.add(solid)
  71. }
  72. if (onCompleted) {
  73. WebUtils.executeTasks(
  74. [
  75. { run: () => this.parseGrid(text), message: 'Parsing file...' },
  76. { run: createTile, message: 'Creating tiles...', iterations: () => tileCount }
  77. ],
  78. () => onCompleted(terrain),
  79. onProgress,
  80. error => onError(error),
  81. 100,
  82. 10
  83. )
  84. } else {
  85. this.parseGrid(text)
  86. for (let tileIndex = 0; tileIndex < tileCount; tileIndex++) {
  87. createTile(tileIndex)
  88. }
  89. }
  90. return terrain
  91. }
  92. parseGrid(text) {
  93. let lines = text.split('\n')
  94. let dataRow = []
  95. for (let line of lines) {
  96. line = line.trim()
  97. if (line.length > 0) {
  98. if (line[0].match(/[a-z]/i)) {
  99. // field
  100. this.readField(line)
  101. } else {
  102. // grid row
  103. let row = line.split(' ')
  104. for (let col = 0; col < row.length; col++) {
  105. let point = new THREE.Vector3()
  106. point.x = dataRow.length * this.cellSize
  107. point.y = this.grid.length * this.cellSize
  108. point.z = parseFloat(row[col])
  109. dataRow.push(point)
  110. }
  111. if (dataRow.length === this.ncols) {
  112. this.grid.push(dataRow)
  113. dataRow = []
  114. }
  115. }
  116. }
  117. }
  118. }
  119. createTileGeometry(ox, oy) {
  120. const groupSize = this.groupSize
  121. let geometry = new SolidGeometry()
  122. let dimx = Math.min(this.ncols - ox, groupSize + 1)
  123. let dimy = Math.min(this.nrows - oy, groupSize + 1)
  124. for (let j = oy; j < oy + dimy; j++) {
  125. for (let i = ox; i < ox + dimx; i++) {
  126. geometry.vertices.push(this.grid[j][i])
  127. }
  128. }
  129. for (let j = 0; j < dimy - 1; j++) {
  130. for (let i = 0; i < dimx - 1; i++) {
  131. geometry.addFace(j * dimx + i, j * dimx + (i + 1), (j + 1) * dimx + i)
  132. geometry.addFace(j * dimx + (i + 1), (j + 1) * dimx + (i + 1), (j + 1) * dimx + i)
  133. }
  134. }
  135. let solid = new Solid()
  136. solid.material = this.material
  137. solid.updateGeometry(geometry, false)
  138. return solid
  139. }
  140. readField(line) {
  141. line = line.toUpperCase()
  142. if (line.startsWith('NCOLS')) {
  143. this.ncols = parseInt(line.substring(6).trim())
  144. } else if (line.startsWith('NROWS')) {
  145. this.nrows = parseInt(line.substring(6).trim())
  146. } else if (line.startsWith('XLLCENTER')) {
  147. this.xcenter = parseFloat(line.substring(10).trim())
  148. } else if (line.startsWith('YLLCENTER')) {
  149. this.ycenter = parseFloat(line.substring(10).trim())
  150. } else if (line.startsWith('CELLSIZE')) {
  151. this.cellSize = parseFloat(line.substring(8).trim())
  152. } else if (line.startsWith('NODATA_VALUE')) {
  153. this.noDataValue = parseFloat(line.substring(13).trim())
  154. }
  155. }
  156. }
  157. export { ASCIIGridLoader }