UNPKG

s2-tools

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

201 lines 7.3 kB
import { Way } from './way'; import { DenseNodes, Node } from './node'; import { Relation, getNodeRelationPairs } from './relation'; /** * NOTE: currently relations are stored, but we don't wait for the Block to store all relations * before we start testing primtiveHandle against the data. This is a problem because * relations reference eachother at times, and we need to be able to resolve those references * before we can run relationHandle against the data. This isn't an important issue since * in practice, all relations that reference eachother often produce garbage or unusable data. * But it would be *nice* to fix this. Morbidly enough, the "BEST" solution is to treat relations * like we do nodes and ways since relations could possibly reference eachother outside their own block. * From a practical standpoint, I can't see this being worth the effort or memory/time cost. */ export class PrimitiveBlock { pbf; reader; stringtable; primitiveGroups = []; // Granularity, units of nanodegrees, used to store coordinates in this block. granularity = 100; // Offset value between the output coordinates and the granularity grid in units of nanodegrees. latOffset = 0; lonOffset = 0; // Granularity of dates, normally represented in units of milliseconds since the 1970 epoch. dateGranularity = 1000; /** * @param pbf - the Protobuf object to read from * @param reader - the OSMReader to modify */ constructor(pbf, reader) { this.pbf = pbf; this.reader = reader; pbf.readFields(this.#readLayer, this, 0); } /** * Get a string from the string table at the given index * @param index - the index of the string in the string table * @returns - the string */ getString(index) { return this.stringtable.get(index); } /** * Get a record of strings from the string table * @param keys - list of indices for the keys * @param values - list of indices for the values * @returns - the record or object containing the key-value pairs */ tags(keys, values) { const res = {}; for (let i = 0; i < keys.length; i++) { res[this.getString(keys[i])] = this.getString(values[i]); } return res; } /** * Read the primitive block's contents into an object * @param tag - the tag of the message * @param pb - the primitive block to modify * @param pbf - the Protobuf object to read from */ #readLayer(tag, pb, pbf) { if (tag === 1) pb.stringtable = new StringTable(pbf); else if (tag === 2) pb.primitiveGroups.push(new PrimitiveGroup(pb, pbf)); else if (tag === 17) pb.granularity = pbf.readVarint(); else if (tag === 18) pb.dateGranularity = pbf.readVarint(); else if (tag === 19) pb.latOffset = pbf.readVarint(); else if (tag === 20) pb.lonOffset = pbf.readVarint(); else throw new Error(`unknown tag ${tag}`); } } /** Group of OSMPrimitives. All primitives in a group must be the same type. */ export class PrimitiveGroup { primitiveBlock; pbf; // changesets: ChangeSet[] = []; /** * @param primitiveBlock - the parent PrimitiveBlock * @param pbf - the Protobuf object to read from */ constructor(primitiveBlock, pbf) { this.primitiveBlock = primitiveBlock; this.pbf = pbf; pbf.readMessage(this.#readLayer, this); } /** * @param tag - the tag of the message * @param pg - the primitive group to modify * @param pbf - the Protobuf object to read from */ #readLayer(tag, pg, pbf) { const { primitiveBlock } = pg; const { reader } = primitiveBlock; const { skipWays, skipRelations } = reader; const skipWR = skipWays && skipRelations; if (tag === 1) { const node = new Node(primitiveBlock, reader, pbf); if (!node.isFilterable()) reader.nodes.set(node.id, node.toVectorFeature()); if (!skipWR) reader.nodeGeometry.set(node.id, node.toVectorGeometry()); } else if (tag === 2) { const dn = new DenseNodes(primitiveBlock, reader, pbf); for (const node of dn.nodes()) { if (!node.isFilterable()) reader.nodes.set(node.id, node.toVectorFeature()); if (!skipWR) reader.nodeGeometry.set(node.id, node.toVectorGeometry()); } } else if (tag === 3) { if (skipWR) return; const way = new Way(primitiveBlock, reader, pbf); const refs = way.nodeRefs(); const ivf = way.toVectorFeature(); if (refs.length >= 2) reader.wayGeometry.set(way.id, refs); if (ivf !== undefined && !way.isFilterable()) reader.ways.set(way.id, ivf); } else if (tag === 4) { if (skipRelations) return; const relation = new Relation(primitiveBlock, reader, pbf); const ivf = relation.toIntermediateFeature(); if (ivf === undefined) return; for (const member of getNodeRelationPairs(ivf.members)) { reader.nodeRelationPairs.set(member.node, member); } if (!relation.isFilterable()) reader.relations.set(relation.id, ivf); } // else if (tag === 5) { // this.changesets.push(new ChangeSet(pbf)); // } } } /** * String table, contains the common strings in each block. * Note that we reserve index '0' as a delimiter, so the entry at that * index in the table is ALWAYS blank and unused. * NOTE: OSM isn't safe and allows " inside of strings, so we have to replace them with ' * NOTE: OSM isn't safe and allows \ at the end of strings, so we have to remove them so it can be properly parsed. */ export class StringTable { strings = []; /** * @param pbf - the Protobuf object to read from */ constructor(pbf) { pbf.readMessage(this.#readLayer, this); } /** * @param index - the index of the string * @returns - the string */ get(index) { return this.strings[index]; } /** * @param tag - the tag of the message * @param st - the string table to modify * @param pbf - the Protobuf object to read from */ #readLayer(tag, st, pbf) { if (tag === 1) st.strings.push(pbf.readString()); else throw new Error(`unknown tag ${tag}`); } } /** This is kept for backwards compatibility but not used anywhere. */ // export class ChangeSet { // id = 0; // /** // * @param pbf // */ // constructor(pbf: Protobuf) { // pbf.readMessage(this.#readLayer, this); // } // /** // * @param tag // * @param cs // * @param pbf // */ // #readLayer(tag: number, cs: ChangeSet, pbf: Protobuf): void { // if (tag === 1) cs.id = pbf.readVarint(); // else throw new Error(`unknown tag ${tag}`); // } // } //# sourceMappingURL=primitive.js.map