UNPKG

s2maps-gpu

Version:

S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.

190 lines (189 loc) 5.92 kB
import { flattenGeometryToLines, lineLength } from './lineTools.js'; /** * Flatten all geometry types to points * @param geometry - vector geometry * @param type - geometry type * @returns vector points */ export function flattenGeometryToPoints(geometry, type) { if (type === 'Point') return [geometry]; if (type === 'MultiPoint') return geometry; const res = []; const lines = flattenGeometryToLines(geometry, type); for (const line of lines) { for (const point of line) res.push(point); } return res; } /** * Get the center points of the geometry * @param geometry - vector geometry * @param type - geometry type * @returns vector points at the center of the geometry */ export function getCenterPoints(geometry, type) { if (type === 'Point') return [geometry]; if (type === 'MultiPoint') return geometry; return findCenterPoints(geometry, type, 0).map((sp) => sp.point); } /** * Get the spaced points of the geometry * @param geometry - vector geometry * @param type - geometry type * @param spacing - distance between points * @param extent - extent is the tile "pixel" size * @returns vector points spaced along the line */ export function getSpacedPoints(geometry, type, spacing, extent) { if (type === 'Point') return [geometry]; if (type === 'MultiPoint') return geometry; return findSpacedPoints(geometry, type, spacing, extent).map((sp) => sp.point); } /** * Find center points of the geometry * @param geometry - vector geometry * @param type - geometry type * @param extent - extent is the tile "pixel" size * @returns vector points at the centers of the geometry(s) */ export function findCenterPoints(geometry, type, extent) { const res = []; if (type === 'Point' || type === 'MultiPoint') return res; const lines = flattenGeometryToLines(geometry, type); for (const line of lines) { const { length, distIndex } = lineLength(line); const center = Math.floor(length / 2); const { point, pathLeft, pathRight } = buildPointAtDistance(line, distIndex, center, extent); res.push({ point, distance: center, pathLeft, pathRight, }); } return res; } /** * Find points along the line at a given distance * @param geometry - vector geometry * @param type - geometry type * @param spacing - distance between points * @param extent - extent is the tile "pixel" size * @returns vector points spaced along the line */ export function findSpacedPoints(geometry, type, spacing, extent) { const res = []; if (type === 'Point' || type === 'MultiPoint') return res; // safety check if (spacing <= 50) return res; const lines = flattenGeometryToLines(geometry, type); for (const line of lines) { const { length, distIndex } = lineLength(line); // every spacing distance, add a point const distances = []; let distance = spacing; while (distance < length) { distances.push(distance); distance += spacing; } for (const d of distances) { const { point, pathLeft, pathRight } = buildPointAtDistance(line, distIndex, d, extent); res.push({ point, distance: d, pathLeft, pathRight, }); } } return res; } /** * NOTE: Currently assumes the line is longer then the distance * @param line - the line * @param index - index of the line * @param distance - distance along the line * @param extent - extent is the tile "pixel" size * @returns path structure */ function buildPointAtDistance(line, index, distance, extent) { const fourthExtent = extent * 0.25; let i = 0; while (i < index.length - 1 && index[i + 1] < distance) i++; const p1 = line[i]; const p2 = line[i + 1]; const d1 = index[i]; const d2 = index[i + 1]; const t = (distance - d1) / (d2 - d1); const point = { x: p1.x + (p2.x - p1.x) * t, y: p1.y + (p2.y - p1.y) * t, }; // store either 7 points or as many as possible const pathLeft = []; const pathRight = []; let l = i; let r = i + 1; let curAngle = pointAngle(point, line[l]) ?? 0; while (l >= 0 && pathLeft.length < 3) { pathLeft.push(duplicatePoint(line[l])); l--; curAngle = pointAngle(line[l + 1], line[l]) ?? curAngle; } // pathLeft length needs to be 4; add 1 at pathAngle while (pathLeft.length < 4) { const { x, y } = pathLeft[pathLeft.length - 1]; pathLeft.push({ x: x + fourthExtent * Math.cos(curAngle), y: y + fourthExtent * Math.sin(curAngle), }); } curAngle = pointAngle(point, line[r]) ?? 0; while (r < line.length && pathRight.length < 3) { pathRight.push(duplicatePoint(line[r])); r++; curAngle = pointAngle(line[r - 1], line[r]) ?? curAngle; } while (pathRight.length < 4) { const { x, y } = pathRight[pathRight.length - 1]; pathRight.push({ x: x + fourthExtent * Math.cos(curAngle), y: y + fourthExtent * Math.sin(curAngle), }); } return { point, pathLeft: pathLeft, pathRight: pathRight, }; } /** * Duplicate a point * @param point - the point to duplicate * @returns the duplicated point */ export function duplicatePoint(point) { return { x: point.x, y: point.y, m: point.m, t: point.t }; } /** * Get the angle between 2 points * @param a - first point * @param b - second point * @returns the angle */ export function pointAngle(a, b) { if (b === undefined || (a.x === b.x && a.y === b.y)) return undefined; return Math.atan2(b.y - a.y, b.x - a.x); }