in packages/layers/xyz-aoi-tile/src/AOILayer.ts [576:804]
private async _createTileMesh(
geojson: any,
projection: Projection,
polaris: AbstractPolaris,
key?: string
): Promise<TileRenderables | undefined> {
if (!geojson.type || geojson.type !== 'FeatureCollection') {
return
}
const mesh = new Mesh({
name: key ? key : 'aois',
extras: { isAOI: true },
})
mesh.renderOrder = this.getProp('renderOrder')
// styles
const featureIdKey = this.getProp('featureIdKey')
const baseAlt = this.getProp('baseAlt')
const featureFilter = this.getProp('featureFilter')
const getColor = functionlize(this.getProp('getColor'))
const getOpacity = functionlize(this.getProp('getOpacity'))
const lineHeight = this.getProp('indicatorLinesHeight')
const pickable = this.getProp('pickable')
// caches
const meshFeatures: any[] = []
const tileRenderables: Mesh[] = []
const idLineRangeMap: Map<number | string, { offset: number; count: number }[]> = new Map()
// attrs
const positions: number[] = []
const colors: number[] = []
const indices: number[] = []
const linePosArr: number[][] = []
let linePosOffset = 0
let offset = 0
const features = geojson.features as any[]
const loadPromises = features.map(async (feature) => {
if (!feature.geometry) {
return
}
const geometry = feature.geometry
// apply filter
if (featureFilter) {
const filterResult = featureFilter(feature)
if (filterResult === undefined || filterResult === false) {
return
}
}
// add 'index' prop to feature
feature.index = this._featureCount
this._featureCount++
const id = feature.properties[featureIdKey] as number | string
if (id === undefined || id === null) {
console.error(`AOILayer - No feature id prop found, skip`)
return
}
if (geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
// polygon triangles generation
// use workers if available
const result = this._workerManager
? await this._workerManager.execute({
data: {
task: 'getFeatureTriangles',
feature,
projectionDesc: projection.toDesc(),
baseAlt,
},
transferables: [],
})
: getFeatureTriangles(feature, projection, baseAlt)
const { positions: featPositions, indices: featIndices } = result
const indexStart = indices.length
// const indexRange = new Uint32Array([indices.length, 0])
// const colorRange = new Uint32Array([offset * 4, 0])
for (let i = 0; i < featPositions.length; i += 3) {
positions.push(featPositions[i + 0], featPositions[i + 1], featPositions[i + 2])
}
for (let i = 0; i < featIndices.length; i++) {
indices.push(featIndices[i] + offset)
}
const count = featPositions.length / 3
const offset4 = offset * 4
const color = new Color(getColor(feature))
const alpha = getOpacity(feature) ?? 1.0
const colorUint = colorToUint8Array(color, alpha)
for (let i = 0; i < count; i++) {
const i4 = offset4 + i * 4
colors[i4 + 0] = colorUint[0]
colors[i4 + 1] = colorUint[1]
colors[i4 + 2] = colorUint[2]
colors[i4 + 3] = colorUint[3]
}
offset += count
// Store index range for feature
const indexEnd = indices.length - 1
// indexRange[1] = indices.length - 1
// // Store feature vert range
// colorRange[1] = offset * 4
this._featureIndexRangeMap.set(feature, createRangeArray(indexStart, indexEnd))
} else if (
pickable &&
(geometry.type === 'LineString' || geometry.type === 'MultiLineString')
) {
// use workers if available
// const linePositions: Float32Array[] = this._workerManager
// ? (
// await this._workerManager.execute({
// data: {
// task: 'featureToLinePositions',
// feature,
// projectionDesc: projection.toDesc(),
// baseAlt: baseAlt + lineHeight,
// },
// transferables: [],
// })
// ).linePositions
// : featureToLinePositions(feature, projection, baseAlt + lineHeight)
// outline positions generation
const linePositions = featureToLinePositions(feature, projection, baseAlt + lineHeight)
if (!linePositions) return
for (let i = 0; i < linePositions.length; i++) {
const linePos = linePositions[i]
const count = linePos.length / 3
const arr: number[] = []
for (let j = 0, jl = linePos.length; j < jl; j += 3) {
arr.push(linePos[j + 0], linePos[j + 1], linePos[j + 2])
}
linePosArr.push(arr)
const range = {
offset: linePosOffset,
count,
}
const lineRanges = idLineRangeMap.get(id)
if (lineRanges) {
lineRanges.push(range)
} else {
idLineRangeMap.set(id, [range])
}
// update offset
linePosOffset += count
}
}
meshFeatures.push(feature)
})
const results = await Promise.all(loadPromises)
const posAttr = new Attr(new Float32Array(positions), 3)
const colorAttr = new Attr(new Uint8Array(colors), 4)
const indicesArray = offset > 65535 ? new Uint32Array(indices) : new Uint16Array(indices)
const indicesAttr = new Attr(indicesArray, 1)
const geom = new Geom({
mode: 'TRIANGLES',
attributes: {
position: posAttr,
aColor: colorAttr,
},
indices: indicesAttr,
})
computeBSphere(geom)
computeBBox(geom)
mesh.geometry = geom
mesh.material = this.matr
// geom.boundingSphere = new Sphere(new Vector3(), Infinity)
// geom.boundingBox = new Box3(
// new Vector3(-Infinity, -Infinity, -Infinity),
// new Vector3(Infinity, Infinity, Infinity)
// )
if (this.getProp('debug') && geom.boundingSphere) {
console.warn('debug unimplemented')
// TODO: gen wire frame is a GSI processor now
// const wireframe = new Mesh({
// name: 'bsphere-wireframe',
// geometry: genBSphereWireframe(geom.boundingSphere),
// // geometry: genBBoxWireframe(geom.boundingBox),
// material: new UnlitMaterial({ baseColorFactor: { r: 1, g: 0, b: 1 } }),
// })
// mesh.add(wireframe)
}
this._renderableFeatureMap.set(mesh, meshFeatures)
// LineIndicators
if (pickable && linePosArr.length > 0) {
const { hoverIndicator, selectIndicator } = this._genLineIndicators(polaris, linePosArr)
tileRenderables.push(hoverIndicator.gline, selectIndicator.gline)
this._indicators.add(hoverIndicator)
this._indicators.add(selectIndicator)
this._cacheIndicatorRanges(idLineRangeMap, hoverIndicator, selectIndicator)
idLineRangeMap.forEach((ranges, id) => {
if (this._hoveredIds.has(id)) this._setStyleById(id, 'hover')
if (this._selectedIds.has(id)) this._setStyleById(id, 'select')
})
}
tileRenderables.push(mesh)
return { meshes: tileRenderables, layers: [] }
}