|
| 1 | +// math.gl |
| 2 | +// SPDX-License-Identifier: MIT |
| 3 | +// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors |
| 4 | + |
| 5 | +import type {GeometryProps} from '../lib/geometry'; |
| 6 | +import {assertSegments, makeIndices, type PrimitiveGeometryProps} from './geometry-helpers'; |
| 7 | +export const FULL_CIRCLE = Math.PI * 2; |
| 8 | +export type Vector = [number, number, number]; |
| 9 | +export type Vertex = {position: Vector; normal: Vector; textureCoordinates: [number, number]}; |
| 10 | +export function radial(angle: number, direction = 1): Vector { |
| 11 | + return [Math.cos(angle) * direction, 0, -Math.sin(angle) * direction]; |
| 12 | +} |
| 13 | +export function vertex( |
| 14 | + radius: number, |
| 15 | + height: number, |
| 16 | + angle: number, |
| 17 | + normal: Vector, |
| 18 | + textureCoordinates?: [number, number] |
| 19 | +): Vertex { |
| 20 | + return { |
| 21 | + position: [radius * Math.cos(angle), height, -radius * Math.sin(angle)], |
| 22 | + normal, |
| 23 | + textureCoordinates: textureCoordinates ?? [(Math.cos(angle) + 1) / 2, (Math.sin(angle) + 1) / 2] |
| 24 | + }; |
| 25 | +} |
| 26 | +export function validateArc(segments: number, startAngle: number, sweepAngle: number): void { |
| 27 | + assertSegments(segments, 'segments', 3); |
| 28 | + if (!Number.isFinite(startAngle)) throw new Error('startAngle must be finite'); |
| 29 | + if (!Number.isFinite(sweepAngle) || sweepAngle <= 0 || sweepAngle > FULL_CIRCLE) |
| 30 | + throw new Error('sweepAngle must be positive and at most 2π'); |
| 31 | +} |
| 32 | +export class PrimitiveMeshBuilder { |
| 33 | + private positions: number[] = []; |
| 34 | + private normals: number[] = []; |
| 35 | + private textureCoordinates: number[] = []; |
| 36 | + private indices: number[] = []; |
| 37 | + private addVertex(current: Vertex): number { |
| 38 | + const index = this.positions.length / 3; |
| 39 | + this.positions.push(...current.position); |
| 40 | + this.normals.push(...current.normal); |
| 41 | + this.textureCoordinates.push(...current.textureCoordinates); |
| 42 | + return index; |
| 43 | + } |
| 44 | + private addTriangle(first: Vertex, second: Vertex, third: Vertex, indices: number[]): void { |
| 45 | + const firstEdge = second.position.map((value, index) => value - first.position[index]); |
| 46 | + const secondEdge = third.position.map((value, index) => value - first.position[index]); |
| 47 | + const cross = [ |
| 48 | + firstEdge[1] * secondEdge[2] - firstEdge[2] * secondEdge[1], |
| 49 | + firstEdge[2] * secondEdge[0] - firstEdge[0] * secondEdge[2], |
| 50 | + firstEdge[0] * secondEdge[1] - firstEdge[1] * secondEdge[0] |
| 51 | + ]; |
| 52 | + const orientation = cross.reduce( |
| 53 | + (sum, value, index) => |
| 54 | + sum + value * (first.normal[index] + second.normal[index] + third.normal[index]), |
| 55 | + 0 |
| 56 | + ); |
| 57 | + this.indices.push(...(orientation < 0 ? [indices[0], indices[2], indices[1]] : indices)); |
| 58 | + } |
| 59 | + triangle(first: Vertex, second: Vertex, third: Vertex): void { |
| 60 | + this.addTriangle(first, second, third, [ |
| 61 | + this.addVertex(first), |
| 62 | + this.addVertex(second), |
| 63 | + this.addVertex(third) |
| 64 | + ]); |
| 65 | + } |
| 66 | + quad(first: Vertex, second: Vertex, third: Vertex, fourth: Vertex): void { |
| 67 | + const indices = [first, second, third, fourth].map(current => this.addVertex(current)); |
| 68 | + this.addTriangle(first, second, third, indices.slice(0, 3)); |
| 69 | + this.addTriangle(first, third, fourth, [indices[0], indices[2], indices[3]]); |
| 70 | + } |
| 71 | + getProps(props: PrimitiveGeometryProps): GeometryProps { |
| 72 | + return { |
| 73 | + id: props.id, |
| 74 | + topology: 'triangle-list', |
| 75 | + indices: makeIndices(this.positions.length / 3, this.indices), |
| 76 | + attributes: { |
| 77 | + POSITION: {size: 3, value: new Float32Array(this.positions)}, |
| 78 | + NORMAL: {size: 3, value: new Float32Array(this.normals)}, |
| 79 | + TEXCOORD_0: {size: 2, value: new Float32Array(this.textureCoordinates)}, |
| 80 | + ...props.attributes |
| 81 | + } |
| 82 | + }; |
| 83 | + } |
| 84 | +} |
0 commit comments