UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

250 lines (233 loc) 7.08 kB
import { LoadingManager, FileLoader, Loader, BufferGeometry, Float32BufferAttribute, Group, Shape, Vector2, Object3D, } from 'three'; import type {OnSuccess, OnProgress, OnError} from '../Common'; import { // GeoJsonGeometryTypes, // GeoJsonTypes, // BBox, // Position, // GeoJsonObject, GeoJSON, Geometry, Point, // MultiPoint, LineString, // MultiLineString, Polygon, MultiPolygon, // GeometryCollection, GeoJsonProperties, Feature, // FeatureCollection, } from 'geojson'; import {BaseSopOperation} from '../../../../engine/operations/sop/_Base'; import {ObjectType} from '../../../geometry/Constant'; import {createGeometriesFromTypeFlat} from '../../../geometry/text/TextFlat'; import {arrayCompact} from '../../../ArrayUtils'; import {isArray} from '../../../Type'; import {ThreejsCoreObject} from '../../../geometry/modules/three/ThreejsCoreObject'; export class GEOJSONLoader extends Loader<Group> { constructor(manager: LoadingManager) { super(manager); } override load(url: string, onLoad: OnSuccess<Group>, onProgress?: OnProgress, onError?: OnError) { const scope = this; // const path = scope.path === '' ? LoaderUtils.extractUrlBase(url) : scope.path; const loader = new FileLoader(this.manager); loader.setPath(scope.path); loader.setResponseType('json'); loader.setRequestHeader(scope.requestHeader); loader.setWithCredentials(scope.withCredentials); loader.load( url, (buffer) => { try { const json = buffer as any as GeoJSON; onLoad(this.parse(json)); } catch (e) { if (onError) { onError(e); } else { console.error(e); } scope.manager.itemError(url); } }, onProgress, onError ); } private parse(data: GeoJSON): Group { const group = new Group(); this._parseGeojson(group, data); return group; } private _parseGeojson(group: Group, data: GeoJSON) { const type = data.type; switch (type) { // case 'Point': { // break; // } // case 'MultiPoint': { // break; // } // case 'LineString': { // break; // } // case 'MultiLineString': { // break; // } // case 'Polygon': { // break; // } // case 'MultiPolygon': { // break; // } // case 'GeometryCollection': { // break; // } // case 'Feature': { // break; // } case 'FeatureCollection': { return this._parseFeatureCollection(group, data.features); } } console.warn(`_parseGeojson:${type} not implemented`); } private _parseFeatureCollection(group: Group, features: Array<Feature<Geometry, GeoJsonProperties>>) { for (const feature of features) { const objects = this._parseFeature(feature); if (objects) { if (isArray(objects)) { for (const object of objects) { this._addAttributes(object, feature); group.add(object); } } else { this._addAttributes(objects, feature); group.add(objects); } } } } private _addAttributes(object: Object3D, feature: Feature<Geometry, GeoJsonProperties>) { if (!feature.properties) { return; } const propertyNames = Object.keys(feature.properties); for (let propertyName of propertyNames) { const value = feature.properties[propertyName]; ThreejsCoreObject.addAttribute(object, propertyName, value); } } private _parseFeature(feature: Feature<Geometry, GeoJsonProperties>) { const geometry = feature.geometry; const type = geometry.type; switch (type) { case 'Point': { return this._parseFeaturePoint(feature as Feature<Point, GeoJsonProperties>); } // case 'MultiPoint': { // console.warn('MultiPoint not implemented') // break; // } case 'LineString': { return this._parseFeatureLineString(feature as Feature<LineString, GeoJsonProperties>); } // case 'MultiLineString': { // console.warn('MultiPoint not implemented') // break; // } case 'Polygon': { return this._parseFeaturePolygon(feature as Feature<Polygon, GeoJsonProperties>); } case 'MultiPolygon': { return this._parseFeatureMultiPolygon(feature as Feature<MultiPolygon, GeoJsonProperties>); } // case 'GeometryCollection': { // break; // } } console.warn(`_parseFeature:${type} not implemented`); } private _parseFeaturePoint(feature: Feature<Point, GeoJsonProperties>) { const coordinates = feature.geometry.coordinates; const pointsCount = 1; const positions: number[] = new Array(pointsCount * 3); const indices: number[] = new Array(pointsCount); // for (let i = 0; i < pointsCount; i++) { const i = 0; positions[i * 3] = coordinates[0]; positions[i * 3 + 1] = 0; positions[i * 3 + 2] = coordinates[1]; indices[0] = 0; // if (i > 0) { // indices[(i - 1) * 2] = i - 1; // indices[(i - 1) * 2 + 1] = i; // } // } const geometry = new BufferGeometry(); geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); geometry.setIndex(indices); return BaseSopOperation.createObject(geometry, ObjectType.POINTS); } private _parseFeatureLineString(feature: Feature<LineString, GeoJsonProperties>) { const coordinates = feature.geometry.coordinates; const pointsCount = coordinates.length; const positions: number[] = new Array(pointsCount * 3); const indices: number[] = new Array(pointsCount); for (let i = 0; i < pointsCount; i++) { positions[i * 3] = coordinates[i][0]; positions[i * 3 + 1] = 0; positions[i * 3 + 2] = coordinates[i][1]; if (i > 0) { indices[(i - 1) * 2] = i - 1; indices[(i - 1) * 2 + 1] = i; } } const geometry = new BufferGeometry(); geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); geometry.setIndex(indices); return BaseSopOperation.createObject(geometry, ObjectType.LINE_SEGMENTS); } private _parseFeaturePolygon(feature: Feature<Polygon, GeoJsonProperties>) { const coordinates = feature.geometry.coordinates; // const pointsCount = coordinates.length; const shapes = coordinates.map((coordinate) => new Shape(coordinate.map((c) => new Vector2(c[0], c[1])))); const geometries = createGeometriesFromTypeFlat({shapes: [shapes]}); if (!geometries) { return; } const compactGeometries: BufferGeometry[] = []; arrayCompact(geometries, compactGeometries); return compactGeometries.map((geometry) => BaseSopOperation.createObject(geometry.rotateX(-0.5 * Math.PI), ObjectType.MESH) ); } private _parseFeatureMultiPolygon(feature: Feature<MultiPolygon, GeoJsonProperties>) { const coordinates = feature.geometry.coordinates; // const pointsCount = coordinates.length; const shapes = coordinates.map((coordinate) => coordinate.map((c) => new Shape(c.map((c2) => new Vector2(c2[0], c2[1])))) ); const geometries = createGeometriesFromTypeFlat({shapes}); if (!geometries) { return; } const compactGeometries: BufferGeometry[] = []; arrayCompact(geometries, compactGeometries); return compactGeometries.map((geometry) => BaseSopOperation.createObject(geometry.rotateX(-0.5 * Math.PI), ObjectType.MESH) ); } }