s2-tools
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
177 lines • 5.53 kB
JavaScript
import { Info } from './info';
import { extendBBox } from '../../geometry';
/**
* Convert an intermediate way to a vector feature
* @param way - intermediate way
* @param reader - OSM reader
* @returns - way vector feature
*/
export async function intermediateWayToVectorFeature(way, reader) {
const { addBBox } = reader;
const { id, isArea, wayNodes, properties, metadata } = way;
// build line
const vectorLine = [];
for (const ref of wayNodes) {
const node = await reader.nodeGeometry.get(ref);
if (node === undefined)
return;
vectorLine.push({ ...node });
}
let bbox;
if (addBBox) {
for (const node of vectorLine)
bbox = extendBBox(bbox, node);
}
// build geometry
const geometry = isArea
? { type: 'Polygon', is3D: false, coordinates: [vectorLine], bbox }
: { type: 'LineString', is3D: false, coordinates: vectorLine, bbox };
return {
id,
type: 'VectorFeature',
properties,
geometry,
metadata: { info: metadata },
};
}
/**
* Way Class
*/
export class Way {
primitiveBlock;
reader;
id = -1;
info;
// Parallel arrays
#keys = [];
#vals = [];
#refs = []; // DELTA coded
// Optional infield lat-lon
// NOTE: I'm not going to bother implementing this, I've never seen it used.
// #lats: number[] = []; // optional DELTA coded
// #lons: number[] = []; // optional DELTA coded
/**
* @param primitiveBlock - the primitive block to access keys and values
* @param reader - the OSM reader
* @param pbf - the Protobuf object to read from
*/
constructor(primitiveBlock, reader, pbf) {
this.primitiveBlock = primitiveBlock;
this.reader = reader;
pbf.readMessage(this.#readLayer, this);
}
/**
* Checks if the way is filterable or not
* @returns - true if the way is filterable
*/
isFilterable() {
const { tagFilter, skipWays } = this.reader;
if (skipWays)
return true;
if (tagFilter !== undefined) {
for (let i = 0; i < this.#keys.length; i++) {
const keyStr = this.primitiveBlock.getString(this.#keys[i]);
const valStr = this.primitiveBlock.getString(this.#vals[i]);
if (tagFilter.matchFound('Way', keyStr, valStr))
return false;
}
// if we make it here, we didn't find any matching tags
return true;
}
return false;
}
/**
* Access the way's properties
* @returns - the way's properties
*/
properties() {
return this.primitiveBlock.tags(this.#keys, this.#vals);
}
/**
* Access the way's node IDs associated with this way
* @returns - the way's nodes
*/
nodeRefs() {
const res = [];
let ref = 0;
for (let i = 0; i < this.#refs.length; i++) {
ref += this.#refs[i];
res.push(ref);
}
return res;
}
/**
* Checks if the way has a key-value pair (value optional)
* @param key - the key
* @param val - the value
* @returns - true if the way has the key and value
*/
hasKeyValue(key, val) {
const { primitiveBlock: pb } = this;
for (let i = 0; i < this.#keys.length; i++) {
if (pb.getString(this.#keys[i]) === key) {
if (val === undefined)
return true;
if (pb.getString(this.#vals[i]) === val)
return true;
}
}
return false;
}
/**
* Checks if the way is an area based on it's key-value pairs
* @returns - true if the way is an area
*/
isArea() {
const { upgradeWaysToAreas } = this.reader;
if ((upgradeWaysToAreas &&
this.#refs.length >= 4 &&
this.#refs[0] === this.#refs[this.#refs.length - 1]) ||
this.hasKeyValue('area', 'yes')) {
return true;
}
return false;
}
/**
* Converts the way to an intermediate vector feature (way's nodes have not been parsed)
* @returns - the way as an intermediate vector feature
*/
toVectorFeature() {
const isArea = this.isArea();
const wayNodes = this.nodeRefs();
if (wayNodes.length < 2)
return;
return {
id: this.id,
isArea,
properties: this.properties(),
wayNodes,
metadata: this.info?.toBlock() ?? {},
};
}
/**
* @param tag - the tag of the message
* @param way - the way to modify
* @param pbf - the Protobuf object to read from
*/
#readLayer(tag, way, pbf) {
if (tag === 1)
way.id = pbf.readVarint();
else if (tag === 2)
way.#keys = pbf.readPackedVarint();
else if (tag === 3)
way.#vals = pbf.readPackedVarint();
else if (tag === 4)
way.info = new Info(way.primitiveBlock, pbf);
else if (tag === 8)
way.#refs = pbf.readPackedSVarint();
// skip, not used.
else if (tag === 9 || tag === 10)
return;
// else if (tag === 9) way.#lats = pbf.readPackedSVarint();
// else if (tag === 10) way.#lons = pbf.readPackedSVarint();
else
throw new Error(`Unknown tag: ${tag}`);
}
}
//# sourceMappingURL=way.js.map