Skip to content

Commit

Permalink
improved image folder group/organization; gtfs tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr Martian committed Dec 27, 2024
1 parent 0dd0989 commit 5276178
Show file tree
Hide file tree
Showing 86 changed files with 959 additions and 41 deletions.
62 changes: 54 additions & 8 deletions src/readers/csv/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,20 +131,66 @@ export class CSVReader<
*/
export function parseCSVAsRecord<T = Record<string, string>>(source: string): T[] {
const res: T[] = [];
const split = source.split('\n');
const firstLine = split[0].split(',').map((s) => s.trim());
for (let line of split.slice(1)) {
line = line.trim();
const lines = source.split('\n');
const header = parseCSVLine(lines[0]);

for (const rawLine of lines.slice(1)) {
const line = rawLine.trim();
if (line.length === 0) continue;

const record: Record<string, string> = {};
const values = line.split(',');
for (let i = 0; i < firstLine.length; i++) {
const value: string | undefined = values[i].replaceAll('"', '');
const values = parseCSVLine(line);

for (let i = 0; i < header.length; i++) {
const value = values[i];
if (value === '' || value === ' ') continue;
record[firstLine[i]] = value;
record[header[i]] = values[i] ?? '';
}

res.push(record as T);
}

return res;
}

/**
* @param line
*/
function parseCSVLine(line: string): string[] {
const result: string[] = [];
let current = '';
let inQuotes = false;
let quoteChar = '';

for (let i = 0; i < line.length; i++) {
const ch = line[i];

// If we encounter a quote and we aren't in quoted text yet
if ((ch === '"' || ch === "'") && !inQuotes) {
inQuotes = true;
quoteChar = ch;
}
// If we see the same quote again, it might be the closing quote
else if (ch === quoteChar && inQuotes) {
// Check if it's an escaped quote by looking at the next character
if (i < line.length - 1 && line[i + 1] === quoteChar) {
current += quoteChar;
i++;
} else {
inQuotes = false;
}
}
// Split by commas only if not inside quotes
else if (ch === ',' && !inQuotes) {
result.push(current.trim());
current = '';
} else {
current += ch;
}
}

// Push the final field
if (current !== undefined) result.push(current.trim());

return result;
}
2 changes: 1 addition & 1 deletion src/readers/geotiff/decoder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jpegDecoder } from './jpeg';
import { jpegDecoder } from '../image';
import { decompressStream, lzwDecoder } from '../../util';

/** What to expect from the decoder */
Expand Down
1 change: 0 additions & 1 deletion src/readers/grib2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type { FeatureIterator, Reader, ReaderInputs } from '..';
import type { Grib2ProductDefinition, Grib2Sections } from './sections';
import type { Properties, VectorFeature, VectorMultiPointGeometry } from '../../geometry';

export * from './jpeg2000';
export * from './sections';

export type { Grib2ProductDefinition, getGrib2Template4 } from './sections';
Expand Down
2 changes: 1 addition & 1 deletion src/readers/grib2/sections/7/templates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JpxImage } from '../../jpeg2000';
import { JpxImage } from '../../../image';
import { complexUnpacking } from './complexUnpacking';

import type { Grib2BitMapSection } from '../6';
Expand Down
22 changes: 18 additions & 4 deletions src/readers/gtfs/schedule/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { type GTFSPathway, parseGTFSPathways } from './pathways';
import { type GTFSRoute, parseGTFSRoutes } from './routes';
import { type GTFSRouteNetwork, parseGTFSRouteNetworks } from './routeNetworks';
import { GTFSShapeProperties, parseGTFSShapes } from './shapes';
import { type GTFSStop, parseGTFSStops } from './stops';
import { type GTFSStop, type GTFSStopProperties, parseGTFSStops } from './stops';
import { type GTFSStopArea, parseGTFSStopAreas } from './stopAreas';
import { type GTFSStopTime, parseGTFSStopTimes } from './stopTimes';
import { type GTFSTimeframe, parseGTFSTimeframes } from './timeframes';
Expand All @@ -39,6 +39,7 @@ import type {
LineStringGeometry,
MValue,
MultiPolygonGeometry,
PointGeometry,
PolygonGeometry,
Properties,
} from '../../../geometry';
Expand Down Expand Up @@ -75,8 +76,6 @@ export * from './translations';
export * from './trips';

// TODO: postprocess all interactions like `Trips -> shape_id [Link]` & `StopTime -> On-demand Service Routing Behavior [Link]`
// TODO: `geojson(schedule: Schedule) => Feature[]` functions for those that need it like `Stop` objects.
// TODO: get all geojson objects

/** A piece of the GTFS schedule */
export interface Piece {
Expand Down Expand Up @@ -178,12 +177,14 @@ export class GTFSSchedule implements FeatureIterator {
}

/**
* TODO: Add proeprties from other files like "color"
* Yields all of the shapes
* @yields an iterator that contains shapes, stops, location data, and routes
*/
async *[Symbol.asyncIterator](): AsyncGenerator<
| Feature<undefined, MValue, GTFSShapeProperties, LineStringGeometry>
| Feature<undefined, MValue, GTFSLocationsProperties, MultiPolygonGeometry | PolygonGeometry>
| Feature<undefined, MValue, GTFSStopProperties, PointGeometry>
> {
if (this.geojson !== undefined) {
for await (const feature of this.geojson)
Expand All @@ -195,7 +196,20 @@ export class GTFSSchedule implements FeatureIterator {
>;
}
if (this.shapes !== undefined) {
for (const shape of Object.values(this.shapes ?? {})) yield shape;
for (const shape of Object.values(this.shapes)) yield shape;
}
if (this.stops !== undefined) {
for (const stop of Object.values(this.stops)) {
const { lon, lat } = stop;
if (lon !== undefined && lat !== undefined) {
const stopFeature: Feature<undefined, MValue, GTFSStopProperties, PointGeometry> = {
type: 'Feature',
properties: stop.properties(),
geometry: { type: 'Point', coordinates: [lon, lat] },
};
yield stopFeature;
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/readers/gtfs/schedule/pathways.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class GTFSPathway {
constructor(data: Record<string, string>) {
this.id = data.pathway_id;
this.fromStopId = data.from_stop_id;
this.toStopId = data.to_stop_id;
this.toStopId = data.to_stop_id ?? data.to_stop_id_pathway_mode;
// Required numeric fields
this.mode =
data.pathway_mode !== undefined
Expand Down
43 changes: 43 additions & 0 deletions src/readers/gtfs/schedule/stops.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
import { parseCSVAsRecord } from '../../';

import type { Properties } from '../../..';

/**
* Properties object from GTFS stops
*/
export interface GTFSStopProperties extends Properties {
id: string;
code: string;
name: string;
ttsName: string;
desc: string;
zoneId: string;
url: string;
locationType: number;
parentStation: string;
timezone: string;
wheelchairBoarding: number;
levelId: string;
platformCode: string;
}

/**
* # Stop Information
*
Expand Down Expand Up @@ -117,6 +138,28 @@ export class GTFSStop {
this.levelId = data.level_id;
this.platformCode = data.platform_code;
}

/**
* Returns the properties of this stop
* @returns - the properties of this stop
*/
properties(): GTFSStopProperties {
return {
id: this.id,
code: this.code ?? '',
name: this.name ?? '',
ttsName: this.ttsName ?? '',
desc: this.desc ?? '',
zoneId: this.zoneId ?? '',
url: this.url ?? '',
locationType: this.locationType ?? -1,
parentStation: this.parentStation ?? '',
timezone: this.timezone ?? '',
wheelchairBoarding: this.wheelchairBoarding ?? -1,
levelId: this.levelId ?? '',
platformCode: this.platformCode ?? '',
};
}
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/readers/image/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './jpeg2000';
export * from './jpeg';
export * from './lanczos';
export * from './util';
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/tools/lanczos.ts → src/readers/image/lanczos.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { copyImage, createImage, resizeImage } from '../util';
import { copyImage, createImage, resizeImage } from '..';

/**
* Lanczos filter function for downscaling
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions src/readers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './gbfs';
export * from './geotiff';
export * from './grib2';
export * from './gtfs';
export * from './image';
export * from './json';
export * from './netcdf';
export * from './osm';
Expand Down
1 change: 0 additions & 1 deletion src/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './delaunator';
export * from './lanczos';
export * from './orthodrome';
export * from './polylabel';
1 change: 0 additions & 1 deletion src/util/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from './gzip';
export * from './image';
export * from './lzw';

/** The formats available to DecompressionStream */
Expand Down
2 changes: 1 addition & 1 deletion tests/readers/gbfs/v3_0.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,5 @@ testFunc('version 3.0', async () => {
await server.stop();

const features = await Array.fromAsync(gbfsReader);
expect(features.length).toBe(102);
expect(features.length).toBe(104);
});
4 changes: 4 additions & 0 deletions tests/readers/gtfs/fixtures/areas.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
area_id,area_name
ASHB,
GLEN,
OAKL,
3 changes: 3 additions & 0 deletions tests/readers/gtfs/fixtures/booking_rules.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
booking_rule_id,booking_type,prior_notice_duration_min,message,phone_number,info_url,booking_url
flächenrufbus_angermünde_weekdays,1,60,"Anmeldung mind. 60min vorher erforderlich, per Anruf zwischen 08:00 und 24:00 möglich, oder online rund um die Uhr",+49 3332 442 755,https://uvg-online.com/rufbus-angermuende/,https://uvg.tdimo.net/bapp/#/astBuchungenView
flächenrufbus_angermünde_weekends,1,60,"1€ Komfortzuschlag pro Person; Anmeldung mind. 60min vorher erforderlich, per Anruf zwischen 08:00 und 24:00 möglich, oder online rund um die Uhr",+49 3332 442 755,https://uvg-online.com/rufbus-angermuende/,https://uvg.tdimo.net/bapp/#/astBuchungenView
6 changes: 6 additions & 0 deletions tests/readers/gtfs/fixtures/fare_leg_join_rules.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from_network_id,to_network_id,from_stop_id,to_stop_id
networkA,networkB,stop1,stop2
networkC,networkD,,
networkE,networkF,stop3,stop4
networkG,networkH,stop5,stop6
networkI,networkJ,,
5 changes: 5 additions & 0 deletions tests/readers/gtfs/fixtures/fare_leg_rules.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
leg_group_id,network_id,fare_product_id
core_local_one_way_trip,core,core_local_oneway_fare
core_local_one_way_trip,core,core_local_1_day_fare
core_local_one_way_trip,core,core_local_31_day_fare
core_local_one_way_trip,core,core_local_7_day_fare
4 changes: 4 additions & 0 deletions tests/readers/gtfs/fixtures/fare_media.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fare_media_id,fare_media_name,fare_media_type
clipper,Clipper,2
munimobile,SFMTA MuniMobile,4
cash,Cash,0
5 changes: 5 additions & 0 deletions tests/readers/gtfs/fixtures/fare_products.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fare_product_id,fare_product_name,amount,currency
core_local_oneway_fare,One Way Full Fare,2.00,USD
core_local_1_day_fare,1-Day Pass - Core Service,4.60,USD
core_local_31_day_fare,31-Day Pass - Core Service,77.00,USD
core_local_7_day_fare,7-Day Pass - Core Service,22.00,USD
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/fare_transfer_rules.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from_leg_group_id,to_leg_group_id,duration_limit,duration_limit_type,fare_transfer_type,transfer_count
core_local_one_way_trip,core_local_one_way_trip,5400,1,0,-1
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/feed_info.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feed_publisher_name,feed_publisher_url,feed_lang,feed_start_date,feed_end_date,feed_version
Transport for Cairo,http://transportforcairo.com/,en,20160101,20161201,0.5
3 changes: 3 additions & 0 deletions tests/readers/gtfs/fixtures/frequencies.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
trip_id,start_time,end_time,headway_secs
22M-GLOBAUX-00-S_1_2,16:01:25,16:19:25,180
22M-GLOBAUX-00-S_1_2,16:19:25,17:03:25,165
8 changes: 8 additions & 0 deletions tests/readers/gtfs/fixtures/levels.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
level_id,level_index,level_name
L1,0,Ground
L2,1,Mezzanine
L3,-1,Basement
L4,2,
L5,3,"Upper Level, East"
L6,4,"Observation Deck, West"
L7,5,
3 changes: 3 additions & 0 deletions tests/readers/gtfs/fixtures/location_group_stops.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location_group_id, stop_id
476_stops,de:12073:900340004::1
476_stops,de:12073:900340004::2
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/location_groups.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
location_group_id,location_group_name
476_stops,durch den RufBus 476 bedientes Gebiet im Raum Angermünde
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/networks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
network_id,network_name
mnr_hudson,MNR Hudson Line
3 changes: 3 additions & 0 deletions tests/readers/gtfs/fixtures/pathways.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pathway_id,from_stop_id,to_stop_id_pathway_mode,is_bidirectional
stairsA,90,95,2,1
escalatorA,96,91,4,0
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/route_networks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
network_id,route_id
mnr_hudson,669
11 changes: 11 additions & 0 deletions tests/readers/gtfs/fixtures/stop_areas.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
area_id,stop_id
mnr_1,ITO1887
mnr_1,ITO2383
mnr_HUD-5,ITO1804
mnr_HUD-6,ITO1669
mnr_HUD-6,ITO1824
mnr_HUD-7,ITO1856
mnr_HUD-7,ITO1897
mnr_HUD-8,ITO1777
mnr_HUD-8,ITO1789
mnr_HUD-9,ITO2096
9 changes: 9 additions & 0 deletions tests/readers/gtfs/fixtures/timeframes.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
timeframe_group_id,start_time,end_time,service_id
TF1,06:00:00,10:00:00,SVC1
TF1,10:00:00,14:00:00,SVC1
TF2,,,"SVC2"
TF3,18:00:00,,"SVC3"
TF4,22:00:00,24:00:00,SVC4
TF5,"00:00:00","24:00:00",SVC5
TF6,12:30:00,15:45:00,SVC6
TF7,09:00:00,09:00:00,SVC7
12 changes: 12 additions & 0 deletions tests/readers/gtfs/fixtures/transfers.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from_stop_id,to_stop_id,from_route_id,to_route_id,from_trip_id,to_trip_id,transfer_type,min_transfer_time
STOP1,STOP2,ROUTE1,ROUTE2,,,"0",
STOP3,STOP4,ROUTE3,ROUTE4,TRIP3,TRIP4,"1",
STOP5,STOP6,ROUTE5,ROUTE6,,,"2",300
STOP7,STOP8,ROUTE7,ROUTE8,TRIP7,TRIP8,"3",
STOP9,STOP10,ROUTE9,ROUTE10,TRIP9,TRIP10,"4",
STOP11,STOP12,ROUTE11,ROUTE12,TRIP11,TRIP12,"5",
STOP13,STOP14,,,,,"0",
,STOP15,ROUTE13,ROUTE14,TRIP13,TRIP14,"1",
STOP16,,ROUTE15,ROUTE16,TRIP15,TRIP16,"2",180
STOP17,STOP18,ROUTE17,ROUTE18,TRIP17,TRIP18,"", # TransferType default to 0
STOP19,STOP20,ROUTE19,ROUTE20,TRIP19,TRIP20,"2", # Missing min_transfer_time
2 changes: 2 additions & 0 deletions tests/readers/gtfs/fixtures/translations.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
table_name,field_name,record_id,language,translation
stops,stop_name,S8815040,nl,Brussel-West
Loading

0 comments on commit 5276178

Please sign in to comment.