UNPKG

@kylebarron/snap-to-tin

Version:

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

74 lines (73 loc) 2.99 kB
import Flatbush from "flatbush"; import { splitLine2d, triangleToBounds } from "./geom"; // Get triangles from terrain export function constructRTree(indices, positions) { // 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, positions) { 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, index, maxPctArea = 0.01) { // 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 = 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) { 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, indexArea, maxPctArea = 0.01) { 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)); }