UNPKG

@kylebarron/snap-to-tin

Version:

Snap vector features to the faces of a triangulated irregular network (TIN).

101 lines (87 loc) 3.1 kB
import Flatbush from "flatbush"; import { splitLine2d, triangleToBounds } from "./geom"; import { LineSegment, FloatArray } from "./types"; // Get triangles from terrain export function constructRTree(indices: Int32Array, positions: FloatArray) { // Create list of objects for insertion into RTree const triangles = createTriangles(indices, positions); // initialize Flatbush for # of items // each triangle has 3 vertices of 3 coordinates each // 16 is default for nodeSize // store coordinates in flatbush internally as Float32Array const index = new Flatbush(triangles.length / 9, 16, Float32Array); // fill it with bounding boxes of triangles for (let i = 0; i < triangles.length / 9; i++) { const triangle = triangles.subarray(i * 9, (i + 1) * 9); const [minX, minY, maxX, maxY] = triangleToBounds(triangle); index.add(minX, minY, maxX, maxY); } // perform the indexing index.finish(); return { index, triangles }; } export function createTriangles( indices: Int32Array, positions: FloatArray ): FloatArray { const triangles = new Float32Array(indices.length * 3); for (let i = 0; i < indices.length; i += 3) { // The indices within `positions` of the three vertices of the triangle const aIndex = indices[i]; const bIndex = indices[i + 1]; const cIndex = indices[i + 2]; // The three vertices of the triangle, where each vertex is an array of [x, y, z] const a = positions.subarray(aIndex * 3, (aIndex + 1) * 3); const b = positions.subarray(bIndex * 3, (bIndex + 1) * 3); const c = positions.subarray(cIndex * 3, (cIndex + 1) * 3); triangles.set(a, i * 3); triangles.set(b, (i + 1) * 3); triangles.set(c, (i + 2) * 3); } return triangles; } export function searchLineInIndex( line: LineSegment, index: Flatbush, maxPctArea: number = 0.01 ): number[] { // Reduce total area searched in rtree to reduce false positives const indexArea = getIndexArea(index); const nSegments = getNumLineSegments(line, indexArea, maxPctArea); const lineSegments = splitLine2d(line, nSegments); const resultIndices: Set<number> = new Set(); for (const lineSegment of lineSegments) { const [minX, minY] = lineSegment[0]; const [maxX, maxY] = lineSegment[1]; index .search(minX, minY, maxX, maxY) .forEach(item => resultIndices.add(item)); } return Array.from(resultIndices); } export function getIndexArea(index: Flatbush): number | null { let area; if ( index.minX !== Infinity && index.minY !== Infinity && index.maxX !== -Infinity && index.maxY !== -Infinity ) { area = (index.maxX - index.minX) * (index.maxY - index.minY); } return area; } export function getNumLineSegments( line: LineSegment, indexArea: number | null, maxPctArea: number = 0.01 ): number { if (!indexArea) { return 1; } const [minX, minY] = line[0]; const [maxX, maxY] = line[1]; const searchArea = (maxX - minX) * (maxY - minY); const pctSearch = searchArea / indexArea; return Math.max(1, Math.ceil(pctSearch / maxPctArea)); }