@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
121 lines (106 loc) • 4.44 kB
text/typescript
import {BufferGeometry, Float32BufferAttribute, LineSegments, Mesh, Object3D, Vector2} from 'three';
import {ObjectType} from '../../geometry/Constant';
import {BaseSopNodeType} from '../../../engine/nodes/sop/_Base';
import {CoordinatesCollection} from './CoordinatesCollection';
import {arraySum} from '../../ArrayUtils';
import {CoreGeometryBuilderMerge} from '../../geometry/modules/three/builders/Merge';
import {CoreMapboxString} from './String';
import {corePointClassFactory} from '../../geometry/CoreObjectFactory';
import {ThreejsPoint} from '../../geometry/modules/three/ThreejsPoint';
import {pointsFromObject} from '../../geometry/entities/point/CorePointUtils';
import {CorePoint} from '../../geometry/entities/point/CorePoint';
import {CoreObjectType} from '../../geometry/ObjectContent';
const MULTILINESTRING = 'MultiLineString';
const LINESTRING = 'LineString';
const dummyMesh = new Mesh();
const _points: CorePoint<CoreObjectType>[] = [];
export class FeatureConverter {
id: number | undefined;
constructor(private node: BaseSopNodeType, private name: string, private features: any[]) {}
createObject(): Object3D | undefined {
const coordinatesCollections = this._createAllCoordinatesCollections();
const perimeter: number = arraySum(coordinatesCollections.map((f) => f.perimeter()));
const sortedFeatures = CoordinatesCollection.sort(coordinatesCollections);
const lines = sortedFeatures.map((feature) => {
return this._createLine(feature);
});
lines.forEach((line) => {
const corePointClass = corePointClassFactory(line);
corePointClass.addNumericAttribute(line, 'perimeter', 1, perimeter);
});
const geometries = lines.map((l) => l.geometry) as BufferGeometry[];
const mergedGeometry = CoreGeometryBuilderMerge.merge(geometries);
if (!mergedGeometry) {
return;
}
// pti
dummyMesh.geometry = mergedGeometry;
pointsFromObject(dummyMesh, _points);
const pointsCount = _points.length;
for (let i = 0; i < pointsCount; i++) {
const point = _points[i];
const pti = i / (pointsCount - 1);
point.setAttribValue('pti', pti);
}
const mergedObject = this.node.createObject(mergedGeometry, ObjectType.LINE_SEGMENTS);
return mergedObject;
}
_createLine(coordinatesCollection: CoordinatesCollection): LineSegments {
const pointsCount = coordinatesCollection.coordinates.length;
const positions: number[] = [];
const indices: number[] = [];
for (let i = 0; i < pointsCount; i++) {
const coordinates = coordinatesCollection.coordinates[i];
positions.push(coordinates.x);
positions.push(0);
positions.push(coordinates.y);
if (i > 0) {
indices.push(i - 1);
indices.push(i);
}
}
const geometry = new BufferGeometry();
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
geometry.setIndex(indices);
const object = this.node.createObject(geometry, ObjectType.LINE_SEGMENTS);
dummyMesh.geometry = geometry;
const id_from_name = CoreMapboxString.toId(this.name) % 10000000;
// console.log(this.name, id_from_name)
ThreejsPoint.addNumericAttribute(dummyMesh, 'id', 1, this.id);
ThreejsPoint.addNumericAttribute(dummyMesh, 'name_id', 1, id_from_name);
return object;
}
private _createAllCoordinatesCollections(): CoordinatesCollection[] {
const coordinates_collections: CoordinatesCollection[] = [];
this.features.forEach((feature) => {
this.id = this.id || feature['id'];
const feature_geometry = feature.geometry;
if (feature_geometry) {
const type = feature_geometry['type'];
switch (type) {
case MULTILINESTRING:
const multi_coordinates = feature_geometry['coordinates'];
if (multi_coordinates) {
for (let i = 0; i < multi_coordinates.length; i++) {
const coordinates = multi_coordinates[i];
coordinates_collections.push(this._create_coordinates(coordinates));
}
}
break;
case LINESTRING:
coordinates_collections.push(this._create_coordinates(feature_geometry['coordinates']));
break;
default:
console.warn(`type ${type} not taken into account`);
}
}
});
return coordinates_collections;
}
private _create_coordinates(raw_coordinates: [number, number][]): CoordinatesCollection {
const vectors = raw_coordinates.map((raw_coordinate) => {
return new Vector2(raw_coordinate[0], raw_coordinate[1]);
});
return new CoordinatesCollection(vectors);
}
}