@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
96 lines (84 loc) • 3.28 kB
text/typescript
import {Vector3, BufferGeometry, Float32BufferAttribute} from 'three';
import {BaseCorePoint} from '../../../entities/point/CorePoint';
import {uniqWithoutPreservingOrder, arrayCompact} from '../../../../ArrayUtils';
import {PolyDictionary} from '../../../../../types/GlobalTypes';
import {CoreObjectType, ObjectContent} from '../../../ObjectContent';
export abstract class CoreGeometryBuilderBase {
fromPoints<T extends CoreObjectType>(object: ObjectContent<T>, points: BaseCorePoint[]): BufferGeometry {
points = this._filterPoints(points);
const geometry = new BufferGeometry();
// const coreGeometry = new CoreGeometry(geometry);
const firstPoint = points[0];
if (!firstPoint) {
return geometry;
}
const oldGeometry = firstPoint.geometry();
if (!oldGeometry) {
return geometry;
}
// index
const new_index_by_old_index: PolyDictionary<number> = {};
for (let i = 0; i < points.length; i++) {
new_index_by_old_index[points[i].index()] = i;
}
const indices = this._indicesFromPoints(new_index_by_old_index, oldGeometry);
if (indices) {
geometry.setIndex(indices);
}
// attributes
const {attributes} = oldGeometry;
// const new_attributes = {}
for (const attribute_name of Object.keys(attributes)) {
const attrib_values = firstPoint.userDataAttribs()[attribute_name];
const is_attrib_indexed = attrib_values != null;
if (is_attrib_indexed) {
const new_values: string[] = [];
const uniqValues: string[] = [];
uniqWithoutPreservingOrder(
points.map((point) => point.indexedAttribValue(attribute_name)),
uniqValues
);
arrayCompact(uniqValues, new_values);
const new_index_by_value: PolyDictionary<number> = {};
new_values.forEach((new_value, i) => (new_index_by_value[new_value] = i));
firstPoint.userDataAttribs()[attribute_name] = new_values;
// const old_attrib = old_geometry.getAttribute(attribute_name)
// const old_attrib_array = old_attrib.array
const new_attrib_indices = [];
for (const point of points) {
// const old_index = old_attrib_array[point.index()]
const oldIndex = point.indexedAttribValue(attribute_name);
if (oldIndex) {
const new_index = new_index_by_value[oldIndex];
new_attrib_indices.push(new_index);
}
}
geometry.setAttribute(attribute_name, new Float32BufferAttribute(new_attrib_indices, 1));
} else {
const attrib_size = attributes[attribute_name].itemSize;
const values: number[] = new Array(points.length * attrib_size);
switch (attrib_size) {
case 1:
for (let i = 0; i < points.length; i++) {
values[i] = points[i].attribValue(attribute_name) as number;
}
break;
default:
let value: Vector3;
for (let i = 0; i < points.length; i++) {
value = points[i].attribValue(attribute_name) as Vector3;
value.toArray(values, i * attrib_size);
}
break;
}
geometry.setAttribute(attribute_name, new Float32BufferAttribute(values, attrib_size));
}
}
return geometry;
}
protected abstract _filterPoints(points: BaseCorePoint[]): BaseCorePoint[];
protected abstract _indicesFromPoints(
new_index_by_old_index: PolyDictionary<number>,
old_geometry: BufferGeometry
): number[] | undefined;
}