aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/app/AppContext.tsx29
-rw-r--r--src/frontend/app/components/GroupedTable.tsx24
-rw-r--r--src/frontend/app/components/LineIcon.css295
-rw-r--r--src/frontend/app/components/LineIcon.tsx17
-rw-r--r--src/frontend/app/components/RegionSelector.tsx33
-rw-r--r--src/frontend/app/components/RegularTable.tsx23
-rw-r--r--src/frontend/app/components/StopItem.tsx7
-rw-r--r--src/frontend/app/components/StopSheet.tsx17
-rw-r--r--src/frontend/app/components/TimetableTable.tsx4
-rw-r--r--src/frontend/app/data/RegionConfig.ts49
-rw-r--r--src/frontend/app/data/StopDataProvider.ts113
-rw-r--r--src/frontend/app/routes/estimates-$id.tsx54
-rw-r--r--src/frontend/app/routes/map.tsx8
-rw-r--r--src/frontend/app/routes/settings.tsx22
-rw-r--r--src/frontend/app/routes/stoplist.tsx16
-rw-r--r--src/frontend/app/routes/timetable-$id.tsx35
-rw-r--r--src/frontend/public/pwa-worker.js5
-rw-r--r--src/frontend/public/stops/santiago.json8585
-rw-r--r--src/frontend/public/stops/vigo.json (renamed from src/frontend/public/stops.json)0
19 files changed, 8994 insertions, 342 deletions
diff --git a/src/frontend/app/AppContext.tsx b/src/frontend/app/AppContext.tsx
index 9013463..1a9b511 100644
--- a/src/frontend/app/AppContext.tsx
+++ b/src/frontend/app/AppContext.tsx
@@ -7,6 +7,7 @@ import {
type ReactNode,
} from "react";
import { type LngLatLike } from "maplibre-gl";
+import { type RegionId, DEFAULT_REGION, getRegionConfig, isValidRegion } from "./data/RegionConfig";
export type Theme = "light" | "dark" | "system";
type TableStyle = "regular" | "grouped";
@@ -37,6 +38,9 @@ interface AppContextProps {
mapPositionMode: MapPositionMode;
setMapPositionMode: (mode: MapPositionMode) => void;
+
+ region: RegionId;
+ setRegion: (region: RegionId) => void;
}
// Coordenadas por defecto centradas en Vigo
@@ -153,6 +157,29 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
}, [mapPositionMode]);
//#endregion
+ //#region Region
+ const [region, setRegionState] = useState<RegionId>(() => {
+ const savedRegion = localStorage.getItem("region");
+ if (savedRegion && isValidRegion(savedRegion)) {
+ return savedRegion;
+ }
+ return DEFAULT_REGION;
+ });
+
+ const setRegion = (newRegion: RegionId) => {
+ setRegionState(newRegion);
+ localStorage.setItem("region", newRegion);
+
+ // Update map to region's default center and zoom
+ const regionConfig = getRegionConfig(newRegion);
+ updateMapState(regionConfig.defaultCenter, regionConfig.defaultZoom);
+ };
+
+ useEffect(() => {
+ localStorage.setItem("region", region);
+ }, [region]);
+ //#endregion
+
//#region Map State
const [mapState, setMapState] = useState<MapState>(() => {
const savedMapState = localStorage.getItem("mapState");
@@ -253,6 +280,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
updateMapState,
mapPositionMode,
setMapPositionMode,
+ region,
+ setRegion,
}}
>
{children}
diff --git a/src/frontend/app/components/GroupedTable.tsx b/src/frontend/app/components/GroupedTable.tsx
index 47c2d31..fd97d5b 100644
--- a/src/frontend/app/components/GroupedTable.tsx
+++ b/src/frontend/app/components/GroupedTable.tsx
@@ -1,12 +1,14 @@
import { type StopDetails } from "../routes/estimates-$id";
import LineIcon from "./LineIcon";
+import { type RegionConfig } from "../data/RegionConfig";
interface GroupedTable {
data: StopDetails;
dataDate: Date | null;
+ regionConfig: RegionConfig;
}
-export const GroupedTable: React.FC<GroupedTable> = ({ data, dataDate }) => {
+export const GroupedTable: React.FC<GroupedTable> = ({ data, dataDate, regionConfig }) => {
const formatDistance = (meters: number) => {
if (meters > 1024) {
return `${(meters / 1000).toFixed(1)} km`;
@@ -43,7 +45,7 @@ export const GroupedTable: React.FC<GroupedTable> = ({ data, dataDate }) => {
<th>Línea</th>
<th>Ruta</th>
<th>Llegada</th>
- <th>Distancia</th>
+ {regionConfig.showMeters && <th>Distancia</th>}
</tr>
</thead>
@@ -53,16 +55,18 @@ export const GroupedTable: React.FC<GroupedTable> = ({ data, dataDate }) => {
<tr key={`${line}-${idx}`}>
{idx === 0 && (
<td rowSpan={groupedEstimates[line].length}>
- <LineIcon line={line} />
+ <LineIcon line={line} region={regionConfig.id} />
</td>
)}
<td>{estimate.route}</td>
<td>{`${estimate.minutes} min`}</td>
- <td>
- {estimate.meters > -1
- ? formatDistance(estimate.meters)
- : "No disponible"}
- </td>
+ {regionConfig.showMeters && (
+ <td>
+ {estimate.meters > -1
+ ? formatDistance(estimate.meters)
+ : "No disponible"}
+ </td>
+ )}
</tr>
)),
)}
@@ -71,7 +75,9 @@ export const GroupedTable: React.FC<GroupedTable> = ({ data, dataDate }) => {
{data?.estimates.length === 0 && (
<tfoot>
<tr>
- <td colSpan={4}>No hay estimaciones disponibles</td>
+ <td colSpan={regionConfig.showMeters ? 4 : 3}>
+ No hay estimaciones disponibles
+ </td>
</tr>
</tfoot>
)}
diff --git a/src/frontend/app/components/LineIcon.css b/src/frontend/app/components/LineIcon.css
index 4613a85..7d46b98 100644
--- a/src/frontend/app/components/LineIcon.css
+++ b/src/frontend/app/components/LineIcon.css
@@ -1,49 +1,75 @@
+/* Vigo line colors */
:root {
- --line-c1: rgb(237, 71, 19);
- --line-c3d: rgb(255, 204, 0);
- --line-c3i: rgb(255, 204, 0);
- --line-l4a: rgb(0, 153, 0);
- --line-l4c: rgb(0, 153, 0);
- --line-l5a: rgb(0, 176, 240);
- --line-l5b: rgb(0, 176, 240);
- --line-l6: rgb(204, 51, 153);
- --line-l7: rgb(150, 220, 153);
- --line-l9b: rgb(244, 202, 140);
- --line-l10: rgb(153, 51, 0);
- --line-l11: rgb(226, 0, 38);
- --line-l12a: rgb(106, 150, 190);
- --line-l12b: rgb(106, 150, 190);
- --line-l13: rgb(0, 176, 240);
- --line-l14: rgb(129, 142, 126);
- --line-l15a: rgb(216, 168, 206);
- --line-l15b: rgb(216, 168, 206);
- --line-l15c: rgb(216, 168, 168);
- --line-l16: rgb(129, 142, 126);
- --line-l17: rgb(214, 245, 31);
- --line-l18a: rgb(212, 80, 168);
- --line-l18b: rgb(0, 0, 0);
- --line-l18h: rgb(0, 0, 0);
- --line-l23: rgb(0, 70, 210);
- --line-l24: rgb(191, 191, 191);
- --line-l25: rgb(172, 100, 4);
- --line-l27: rgb(112, 74, 42);
- --line-l28: rgb(176, 189, 254);
- --line-l29: rgb(248, 184, 90);
- --line-l31: rgb(255, 255, 0);
- --line-a: rgb(119, 41, 143);
- --line-h: rgb(0, 96, 168);
- --line-h1: rgb(0, 96, 168);
- --line-h2: rgb(0, 96, 168);
- --line-h3: rgb(0, 96, 168);
- --line-lzd: rgb(61, 78, 167);
- --line-n1: rgb(191, 191, 191);
- --line-n4: rgb(102, 51, 102);
- --line-psa1: rgb(0, 153, 0);
- --line-psa4: rgb(0, 153, 0);
- --line-ptl: rgb(150, 220, 153);
- --line-turistico: rgb(102, 51, 102);
- --line-u1: rgb(172, 100, 4);
- --line-u2: rgb(172, 100, 4);
+ --line-vigo-c1: rgb(237, 71, 19);
+ --line-vigo-c3d: rgb(255, 204, 0);
+ --line-vigo-c3i: rgb(255, 204, 0);
+ --line-vigo-l4a: rgb(0, 153, 0);
+ --line-vigo-l4c: rgb(0, 153, 0);
+ --line-vigo-l5a: rgb(0, 176, 240);
+ --line-vigo-l5b: rgb(0, 176, 240);
+ --line-vigo-l6: rgb(204, 51, 153);
+ --line-vigo-l7: rgb(150, 220, 153);
+ --line-vigo-l9b: rgb(244, 202, 140);
+ --line-vigo-l10: rgb(153, 51, 0);
+ --line-vigo-l11: rgb(226, 0, 38);
+ --line-vigo-l12a: rgb(106, 150, 190);
+ --line-vigo-l12b: rgb(106, 150, 190);
+ --line-vigo-l13: rgb(0, 176, 240);
+ --line-vigo-l14: rgb(129, 142, 126);
+ --line-vigo-l15a: rgb(216, 168, 206);
+ --line-vigo-l15b: rgb(216, 168, 206);
+ --line-vigo-l15c: rgb(216, 168, 168);
+ --line-vigo-l16: rgb(129, 142, 126);
+ --line-vigo-l17: rgb(214, 245, 31);
+ --line-vigo-l18a: rgb(212, 80, 168);
+ --line-vigo-l18b: rgb(0, 0, 0);
+ --line-vigo-l18h: rgb(0, 0, 0);
+ --line-vigo-l23: rgb(0, 70, 210);
+ --line-vigo-l24: rgb(191, 191, 191);
+ --line-vigo-l25: rgb(172, 100, 4);
+ --line-vigo-l27: rgb(112, 74, 42);
+ --line-vigo-l28: rgb(176, 189, 254);
+ --line-vigo-l29: rgb(248, 184, 90);
+ --line-vigo-l31: rgb(255, 255, 0);
+ --line-vigo-a: rgb(119, 41, 143);
+ --line-vigo-h: rgb(0, 96, 168);
+ --line-vigo-h1: rgb(0, 96, 168);
+ --line-vigo-h2: rgb(0, 96, 168);
+ --line-vigo-h3: rgb(0, 96, 168);
+ --line-vigo-lzd: rgb(61, 78, 167);
+ --line-vigo-n1: rgb(191, 191, 191);
+ --line-vigo-n4: rgb(102, 51, 102);
+ --line-vigo-psa1: rgb(0, 153, 0);
+ --line-vigo-psa4: rgb(0, 153, 0);
+ --line-vigo-ptl: rgb(150, 220, 153);
+ --line-vigo-turistico: rgb(102, 51, 102);
+ --line-vigo-u1: rgb(172, 100, 4);
+ --line-vigo-u2: rgb(172, 100, 4);
+
+ --line-santiago-l1: #f32621;
+ --line-santiago-l4: #ffcc33;
+ --line-santiago-l5: #fa8405;
+ --line-santiago-l6: #d73983;
+ --line-santiago-l6a: #d73983;
+ --line-santiago-l7: #488bc1;
+ --line-santiago-l8: #6aaf48;
+ --line-santiago-l9: #46b8bb;
+ --line-santiago-c11: #aec741;
+ --line-santiago-l12: #842e14;
+ --line-santiago-l13: #336600;
+ --line-santiago-l15: #7a4b2a;
+ --line-santiago-c2: #283a87;
+ --line-santiago-c4: #283a87;
+ --line-santiago-c5: #999999;
+ --line-santiago-c6: #006666;
+ --line-santiago-p1: #537eb3;
+ --line-santiago-p2: #d23354;
+ --line-santiago-p3: #75bd96;
+ --line-santiago-p4: #f1c54f;
+ --line-santiago-p6: #999999;
+ --line-santiago-p7: #d2438c;
+ --line-santiago-p8: #e28c3a;
+
}
.line-icon {
@@ -55,187 +81,8 @@
font-weight: 600;
text-transform: uppercase;
border-radius: 0.25rem 0.25rem 0 0;
-
color: var(--text-color);
background-color: var(--background-color);
}
-.line-c1 {
- border-color: var(--line-c1);
-}
-
-.line-c3d {
- border-color: var(--line-c3d);
-}
-
-.line-c3i {
- border-color: var(--line-c3i);
-}
-
-.line-l4a {
- border-color: var(--line-l4a);
-}
-
-.line-l4c {
- border-color: var(--line-l4c);
-}
-
-.line-l5a {
- border-color: var(--line-l5a);
-}
-
-.line-l5b {
- border-color: var(--line-l5b);
-}
-
-.line-l6 {
- border-color: var(--line-l6);
-}
-
-.line-l7 {
- border-color: var(--line-l7);
-}
-
-.line-l9b {
- border-color: var(--line-l9b);
-}
-
-.line-l10 {
- border-color: var(--line-l10);
-}
-
-.line-l11 {
- border-color: var(--line-l11);
-}
-
-.line-l12a {
- border-color: var(--line-l12a);
-}
-
-.line-l12b {
- border-color: var(--line-l12b);
-}
-
-.line-l13 {
- border-color: var(--line-l13);
-}
-
-.line-l14 {
- border-color: var(--line-l14);
-}
-
-.line-l15a {
- border-color: var(--line-l15a);
-}
-
-.line-l15b {
- border-color: var(--line-l15b);
-}
-
-.line-l15c {
- border-color: var(--line-l15c);
-}
-
-.line-l16 {
- border-color: var(--line-l16);
-}
-
-.line-l17 {
- border-color: var(--line-l17);
-}
-
-.line-l18a {
- border-color: var(--line-l18a);
-}
-.line-l18b {
- border-color: var(--line-l18b);
-}
-
-.line-l18h {
- border-color: var(--line-l18h);
-}
-
-.line-l23 {
- border-color: var(--line-l23);
-}
-
-.line-l24 {
- border-color: var(--line-l24);
-}
-
-.line-l25 {
- border-color: var(--line-l25);
-}
-
-.line-l27 {
- border-color: var(--line-l27);
-}
-
-.line-l28 {
- border-color: var(--line-l28);
-}
-
-.line-l29 {
- border-color: var(--line-l29);
-}
-
-.line-l31 {
- border-color: var(--line-l31);
-}
-
-.line-a {
- border-color: var(--line-a);
-}
-
-.line-h {
- border-color: var(--line-h);
-}
-
-.line-h1 {
- border-color: var(--line-h1);
-}
-
-.line-h2 {
- border-color: var(--line-h2);
-}
-
-.line-h3 {
- border-color: var(--line-h3);
-}
-
-.line-lzd {
- border-color: var(--line-lzd);
-}
-
-.line-n1 {
- border-color: var(--line-n1);
-}
-
-.line-n4 {
- border-color: var(--line-n4);
-}
-
-.line-psa1 {
- border-color: var(--line-psa1);
-}
-
-.line-psa4 {
- border-color: var(--line-psa4);
-}
-
-.line-ptl {
- border-color: var(--line-ptl);
-}
-
-.line-turistico {
- border-color: var(--line-turistico);
-}
-
-.line-u1 {
- border-color: var(--line-u1);
-}
-
-.line-u2 {
- border-color: var(--line-u2);
-}
diff --git a/src/frontend/app/components/LineIcon.tsx b/src/frontend/app/components/LineIcon.tsx
index 3d613e6..4f4bfd9 100644
--- a/src/frontend/app/components/LineIcon.tsx
+++ b/src/frontend/app/components/LineIcon.tsx
@@ -1,14 +1,23 @@
-import React from "react";
+import React, { useMemo } from "react";
import "./LineIcon.css";
+import { type RegionId } from "../data/RegionConfig";
interface LineIconProps {
line: string;
+ region?: RegionId;
}
-const LineIcon: React.FC<LineIconProps> = ({ line }) => {
- const formattedLine = /^[a-zA-Z]/.test(line) ? line : `L${line}`;
+const LineIcon: React.FC<LineIconProps> = ({ line, region = "vigo" }) => {
+ const formattedLine = useMemo(() => {
+ return /^[a-zA-Z]/.test(line) ? line : `L${line}`;
+ }, [line]);
+ const cssVarName = `--line-${region}-${formattedLine.toLowerCase()}`;
+
return (
- <span className={`line-icon line-${formattedLine.toLowerCase()}`}>
+ <span
+ className="line-icon"
+ style={{ borderColor: `var(${cssVarName})` }}
+ >
{formattedLine}
</span>
);
diff --git a/src/frontend/app/components/RegionSelector.tsx b/src/frontend/app/components/RegionSelector.tsx
new file mode 100644
index 0000000..6c9fe8b
--- /dev/null
+++ b/src/frontend/app/components/RegionSelector.tsx
@@ -0,0 +1,33 @@
+import { useApp } from "../AppContext";
+import { getAvailableRegions } from "../data/RegionConfig";
+import "./RegionSelector.css";
+
+export function RegionSelector() {
+ const { region, setRegion } = useApp();
+ const regions = getAvailableRegions();
+
+ const handleRegionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
+ const newRegion = e.target.value as any;
+ setRegion(newRegion);
+ };
+
+ return (
+ <div className="region-selector">
+ <label htmlFor="region-select" className="region-label">
+ Región:
+ </label>
+ <select
+ id="region-select"
+ className="region-select"
+ value={region}
+ onChange={handleRegionChange}
+ >
+ {regions.map((r) => (
+ <option key={r.id} value={r.id}>
+ {r.name}
+ </option>
+ ))}
+ </select>
+ </div>
+ );
+}
diff --git a/src/frontend/app/components/RegularTable.tsx b/src/frontend/app/components/RegularTable.tsx
index 8b01410..68b732a 100644
--- a/src/frontend/app/components/RegularTable.tsx
+++ b/src/frontend/app/components/RegularTable.tsx
@@ -1,15 +1,18 @@
import { useTranslation } from "react-i18next";
import { type StopDetails } from "../routes/estimates-$id";
import LineIcon from "./LineIcon";
+import { type RegionConfig } from "../data/RegionConfig";
interface RegularTableProps {
data: StopDetails;
dataDate: Date | null;
+ regionConfig: RegionConfig;
}
export const RegularTable: React.FC<RegularTableProps> = ({
data,
dataDate,
+ regionConfig,
}) => {
const { t } = useTranslation();
@@ -46,7 +49,9 @@ export const RegularTable: React.FC<RegularTableProps> = ({
<th>{t("estimates.line", "Línea")}</th>
<th>{t("estimates.route", "Ruta")}</th>
<th>{t("estimates.arrival", "Llegada")}</th>
- <th>{t("estimates.distance", "Distancia")}</th>
+ {regionConfig.showMeters && (
+ <th>{t("estimates.distance", "Distancia")}</th>
+ )}
</tr>
</thead>
@@ -56,7 +61,7 @@ export const RegularTable: React.FC<RegularTableProps> = ({
.map((estimate, idx) => (
<tr key={idx}>
<td>
- <LineIcon line={estimate.line} />
+ <LineIcon line={estimate.line} region={regionConfig.id} />
</td>
<td>{estimate.route}</td>
<td>
@@ -64,11 +69,13 @@ export const RegularTable: React.FC<RegularTableProps> = ({
? absoluteArrivalTime(estimate.minutes)
: `${estimate.minutes} ${t("estimates.minutes", "min")}`}
</td>
- <td>
- {estimate.meters > -1
- ? formatDistance(estimate.meters)
- : t("estimates.not_available", "No disponible")}
- </td>
+ {regionConfig.showMeters && (
+ <td>
+ {estimate.meters > -1
+ ? formatDistance(estimate.meters)
+ : t("estimates.not_available", "No disponible")}
+ </td>
+ )}
</tr>
))}
</tbody>
@@ -76,7 +83,7 @@ export const RegularTable: React.FC<RegularTableProps> = ({
{data?.estimates.length === 0 && (
<tfoot>
<tr>
- <td colSpan={4}>
+ <td colSpan={regionConfig.showMeters ? 4 : 3}>
{t("estimates.none", "No hay estimaciones disponibles")}
</td>
</tr>
diff --git a/src/frontend/app/components/StopItem.tsx b/src/frontend/app/components/StopItem.tsx
index b781eb9..7d89d7d 100644
--- a/src/frontend/app/components/StopItem.tsx
+++ b/src/frontend/app/components/StopItem.tsx
@@ -2,19 +2,22 @@ import React from "react";
import { Link } from "react-router";
import StopDataProvider, { type Stop } from "../data/StopDataProvider";
import LineIcon from "./LineIcon";
+import { useApp } from "../AppContext";
interface StopItemProps {
stop: Stop;
}
const StopItem: React.FC<StopItemProps> = ({ stop }) => {
+ const { region } = useApp();
+
return (
<li className="list-item">
<Link className="list-item-link" to={`/estimates/${stop.stopId}`}>
{stop.favourite && <span className="favourite-icon">★</span>} (
- {stop.stopId}) {StopDataProvider.getDisplayName(stop)}
+ {stop.stopId}) {StopDataProvider.getDisplayName(region, stop)}
<div className="line-icons">
- {stop.lines?.map((line) => <LineIcon key={line} line={line} />)}
+ {stop.lines?.map((line) => <LineIcon key={line} line={line} region={region} />)}
</div>
</Link>
</li>
diff --git a/src/frontend/app/components/StopSheet.tsx b/src/frontend/app/components/StopSheet.tsx
index 702c574..7255884 100644
--- a/src/frontend/app/components/StopSheet.tsx
+++ b/src/frontend/app/components/StopSheet.tsx
@@ -7,6 +7,8 @@ import LineIcon from "./LineIcon";
import { StopSheetSkeleton } from "./StopSheetSkeleton";
import { ErrorDisplay } from "./ErrorDisplay";
import { type StopDetails } from "../routes/estimates-$id";
+import { type RegionId, getRegionConfig } from "../data/RegionConfig";
+import { useApp } from "../AppContext";
import "./StopSheet.css";
interface StopSheetProps {
@@ -22,8 +24,9 @@ interface ErrorInfo {
message?: string;
}
-const loadStopData = async (stopId: number): Promise<StopDetails> => {
- const resp = await fetch(`/api/GetStopEstimates?id=${stopId}`, {
+const loadStopData = async (region: RegionId, stopId: number): Promise<StopDetails> => {
+ const regionConfig = getRegionConfig(region);
+ const resp = await fetch(`${regionConfig.estimatesEndpoint}?id=${stopId}`, {
headers: {
Accept: "application/json",
},
@@ -43,6 +46,8 @@ export const StopSheet: React.FC<StopSheetProps> = ({
stopName,
}) => {
const { t } = useTranslation();
+ const { region } = useApp();
+ const regionConfig = getRegionConfig(region);
const [data, setData] = useState<StopDetails | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<ErrorInfo | null>(null);
@@ -72,7 +77,7 @@ export const StopSheet: React.FC<StopSheetProps> = ({
setError(null);
setData(null);
- const stopData = await loadStopData(stopId);
+ const stopData = await loadStopData(region, stopId);
setData(stopData);
setLastUpdated(new Date());
} catch (err) {
@@ -87,7 +92,7 @@ export const StopSheet: React.FC<StopSheetProps> = ({
if (isOpen && stopId) {
loadData();
}
- }, [isOpen, stopId]);
+ }, [isOpen, stopId, region]);
const formatTime = (minutes: number) => {
if (minutes > 15) {
@@ -157,7 +162,7 @@ export const StopSheet: React.FC<StopSheetProps> = ({
{limitedEstimates.map((estimate, idx) => (
<div key={idx} className="stop-sheet-estimate-item">
<div className="stop-sheet-estimate-line">
- <LineIcon line={estimate.line} />
+ <LineIcon line={estimate.line} region={region} />
</div>
<div className="stop-sheet-estimate-details">
<div className="stop-sheet-estimate-route">
@@ -165,7 +170,7 @@ export const StopSheet: React.FC<StopSheetProps> = ({
</div>
<div className="stop-sheet-estimate-time">
{formatTime(estimate.minutes)}
- {estimate.meters > -1 && (
+ {regionConfig.showMeters && estimate.meters > -1 && (
<span className="stop-sheet-estimate-distance">
{" • "}
{formatDistance(estimate.meters)}
diff --git a/src/frontend/app/components/TimetableTable.tsx b/src/frontend/app/components/TimetableTable.tsx
index 86896ca..8215141 100644
--- a/src/frontend/app/components/TimetableTable.tsx
+++ b/src/frontend/app/components/TimetableTable.tsx
@@ -1,6 +1,7 @@
import { useTranslation } from "react-i18next";
import LineIcon from "./LineIcon";
import "./TimetableTable.css";
+import { useApp } from "../AppContext";
export interface TimetableEntry {
line: {
@@ -97,6 +98,7 @@ export const TimetableTable: React.FC<TimetableTableProps> = ({
currentTime
}) => {
const { t } = useTranslation();
+ const { region } = useApp();
const displayData = showAll ? data : findNearbyEntries(data, currentTime || '');
const nowMinutes = currentTime ? timeToMinutes(currentTime) : timeToMinutes(new Date().toTimeString().slice(0, 8));
@@ -126,7 +128,7 @@ export const TimetableTable: React.FC<TimetableTableProps> = ({
>
<div className="card-header">
<div className="line-info">
- <LineIcon line={entry.line.name} />
+ <LineIcon line={entry.line.name} region={region} />
</div>
<div className="destination-info">
diff --git a/src/frontend/app/data/RegionConfig.ts b/src/frontend/app/data/RegionConfig.ts
new file mode 100644
index 0000000..0ce66e6
--- /dev/null
+++ b/src/frontend/app/data/RegionConfig.ts
@@ -0,0 +1,49 @@
+export type RegionId = "vigo" | "santiago";
+
+export interface RegionConfig {
+ id: RegionId;
+ name: string;
+ stopsEndpoint: string;
+ estimatesEndpoint: string;
+ timetableEndpoint: string | null;
+ defaultCenter: [number, number]; // [lat, lng]
+ defaultZoom: number;
+ showMeters: boolean; // Whether to show distance in meters
+}
+
+export const REGIONS: Record<RegionId, RegionConfig> = {
+ vigo: {
+ id: "vigo",
+ name: "Vigo",
+ stopsEndpoint: "/stops/vigo.json",
+ estimatesEndpoint: "/api/vigo/GetStopEstimates",
+ timetableEndpoint: "/api/vigo/GetStopTimetable",
+ defaultCenter: [42.229188855975046, -8.72246955783102],
+ defaultZoom: 14,
+ showMeters: true,
+ },
+ santiago: {
+ id: "santiago",
+ name: "Santiago de Compostela",
+ stopsEndpoint: "/stops/santiago.json",
+ estimatesEndpoint: "/api/santiago/GetStopEstimates",
+ timetableEndpoint: null, // Not available for Santiago
+ defaultCenter: [42.8782, -8.5448],
+ defaultZoom: 14,
+ showMeters: false, // Santiago doesn't provide distance data
+ },
+};
+
+export const DEFAULT_REGION: RegionId = "vigo";
+
+export function getRegionConfig(regionId: RegionId): RegionConfig {
+ return REGIONS[regionId];
+}
+
+export function getAvailableRegions(): RegionConfig[] {
+ return Object.values(REGIONS);
+}
+
+export function isValidRegion(regionId: string): regionId is RegionId {
+ return regionId === "vigo" || regionId === "santiago";
+}
diff --git a/src/frontend/app/data/StopDataProvider.ts b/src/frontend/app/data/StopDataProvider.ts
index 3959400..e49faaa 100644
--- a/src/frontend/app/data/StopDataProvider.ts
+++ b/src/frontend/app/data/StopDataProvider.ts
@@ -1,3 +1,5 @@
+import { type RegionId, getRegionConfig } from "./RegionConfig";
+
export interface CachedStopList {
timestamp: number;
data: Stop[];
@@ -17,48 +19,52 @@ export interface Stop {
favourite?: boolean;
}
-// In-memory cache and lookup map
-let cachedStops: Stop[] | null = null;
-let stopsMap: Record<number, Stop> = {};
-// Custom names loaded from localStorage
-let customNames: Record<number, string> = {};
+// In-memory cache and lookup map per region
+const cachedStopsByRegion: Record<string, Stop[] | null> = {};
+const stopsMapByRegion: Record<string, Record<number, Stop>> = {};
+// Custom names loaded from localStorage per region
+const customNamesByRegion: Record<string, Record<number, string>> = {};
-// Initialize cachedStops and customNames once
-async function initStops() {
- if (!cachedStops) {
- const response = await fetch("/stops.json");
+// Initialize cachedStops and customNames once per region
+async function initStops(region: RegionId) {
+ if (!cachedStopsByRegion[region]) {
+ const regionConfig = getRegionConfig(region);
+ const response = await fetch(regionConfig.stopsEndpoint);
const stops = (await response.json()) as Stop[];
// build array and map
- stopsMap = {};
- cachedStops = stops.map((stop) => {
+ stopsMapByRegion[region] = {};
+ cachedStopsByRegion[region] = stops.map((stop) => {
const entry = { ...stop, favourite: false } as Stop;
- stopsMap[stop.stopId] = entry;
+ stopsMapByRegion[region][stop.stopId] = entry;
return entry;
});
// load custom names
- const rawCustom = localStorage.getItem("customStopNames");
- if (rawCustom)
- customNames = JSON.parse(rawCustom) as Record<number, string>;
+ const rawCustom = localStorage.getItem(`customStopNames_${region}`);
+ if (rawCustom) {
+ customNamesByRegion[region] = JSON.parse(rawCustom) as Record<number, string>;
+ } else {
+ customNamesByRegion[region] = {};
+ }
}
}
-async function getStops(): Promise<Stop[]> {
- await initStops();
+async function getStops(region: RegionId): Promise<Stop[]> {
+ await initStops(region);
// update favourites
- const rawFav = localStorage.getItem("favouriteStops");
+ const rawFav = localStorage.getItem(`favouriteStops_${region}`);
const favouriteStops = rawFav ? (JSON.parse(rawFav) as number[]) : [];
- cachedStops!.forEach(
+ cachedStopsByRegion[region]!.forEach(
(stop) => (stop.favourite = favouriteStops.includes(stop.stopId)),
);
- return cachedStops!;
+ return cachedStopsByRegion[region]!;
}
// New: get single stop by id
-async function getStopById(stopId: number): Promise<Stop | undefined> {
- await initStops();
- const stop = stopsMap[stopId];
+async function getStopById(region: RegionId, stopId: number): Promise<Stop | undefined> {
+ await initStops(region);
+ const stop = stopsMapByRegion[region]?.[stopId];
if (stop) {
- const rawFav = localStorage.getItem("favouriteStops");
+ const rawFav = localStorage.getItem(`favouriteStops_${region}`);
const favouriteStops = rawFav ? (JSON.parse(rawFav) as number[]) : [];
stop.favourite = favouriteStops.includes(stopId);
}
@@ -66,30 +72,36 @@ async function getStopById(stopId: number): Promise<Stop | undefined> {
}
// Updated display name to include custom names
-function getDisplayName(stop: Stop): string {
+function getDisplayName(region: RegionId, stop: Stop): string {
+ const customNames = customNamesByRegion[region] || {};
if (customNames[stop.stopId]) return customNames[stop.stopId];
const nameObj = stop.name;
return nameObj.intersect || nameObj.original;
}
// New: set or remove custom names
-function setCustomName(stopId: number, label: string) {
- customNames[stopId] = label;
- localStorage.setItem("customStopNames", JSON.stringify(customNames));
+function setCustomName(region: RegionId, stopId: number, label: string) {
+ if (!customNamesByRegion[region]) {
+ customNamesByRegion[region] = {};
+ }
+ customNamesByRegion[region][stopId] = label;
+ localStorage.setItem(`customStopNames_${region}`, JSON.stringify(customNamesByRegion[region]));
}
-function removeCustomName(stopId: number) {
- delete customNames[stopId];
- localStorage.setItem("customStopNames", JSON.stringify(customNames));
+function removeCustomName(region: RegionId, stopId: number) {
+ if (customNamesByRegion[region]) {
+ delete customNamesByRegion[region][stopId];
+ localStorage.setItem(`customStopNames_${region}`, JSON.stringify(customNamesByRegion[region]));
+ }
}
// New: get custom label for a stop
-function getCustomName(stopId: number): string | undefined {
- return customNames[stopId];
+function getCustomName(region: RegionId, stopId: number): string | undefined {
+ return customNamesByRegion[region]?.[stopId];
}
-function addFavourite(stopId: number) {
- const rawFavouriteStops = localStorage.getItem("favouriteStops");
+function addFavourite(region: RegionId, stopId: number) {
+ const rawFavouriteStops = localStorage.getItem(`favouriteStops_${region}`);
let favouriteStops: number[] = [];
if (rawFavouriteStops) {
favouriteStops = JSON.parse(rawFavouriteStops) as number[];
@@ -97,23 +109,23 @@ function addFavourite(stopId: number) {
if (!favouriteStops.includes(stopId)) {
favouriteStops.push(stopId);
- localStorage.setItem("favouriteStops", JSON.stringify(favouriteStops));
+ localStorage.setItem(`favouriteStops_${region}`, JSON.stringify(favouriteStops));
}
}
-function removeFavourite(stopId: number) {
- const rawFavouriteStops = localStorage.getItem("favouriteStops");
+function removeFavourite(region: RegionId, stopId: number) {
+ const rawFavouriteStops = localStorage.getItem(`favouriteStops_${region}`);
let favouriteStops: number[] = [];
if (rawFavouriteStops) {
favouriteStops = JSON.parse(rawFavouriteStops) as number[];
}
const newFavouriteStops = favouriteStops.filter((id) => id !== stopId);
- localStorage.setItem("favouriteStops", JSON.stringify(newFavouriteStops));
+ localStorage.setItem(`favouriteStops_${region}`, JSON.stringify(newFavouriteStops));
}
-function isFavourite(stopId: number): boolean {
- const rawFavouriteStops = localStorage.getItem("favouriteStops");
+function isFavourite(region: RegionId, stopId: number): boolean {
+ const rawFavouriteStops = localStorage.getItem(`favouriteStops_${region}`);
if (rawFavouriteStops) {
const favouriteStops = JSON.parse(rawFavouriteStops) as number[];
return favouriteStops.includes(stopId);
@@ -123,8 +135,8 @@ function isFavourite(stopId: number): boolean {
const RECENT_STOPS_LIMIT = 10;
-function pushRecent(stopId: number) {
- const rawRecentStops = localStorage.getItem("recentStops");
+function pushRecent(region: RegionId, stopId: number) {
+ const rawRecentStops = localStorage.getItem(`recentStops_${region}`);
let recentStops: Set<number> = new Set();
if (rawRecentStops) {
recentStops = new Set(JSON.parse(rawRecentStops) as number[]);
@@ -137,19 +149,19 @@ function pushRecent(stopId: number) {
recentStops.delete(val);
}
- localStorage.setItem("recentStops", JSON.stringify(Array.from(recentStops)));
+ localStorage.setItem(`recentStops_${region}`, JSON.stringify(Array.from(recentStops)));
}
-function getRecent(): number[] {
- const rawRecentStops = localStorage.getItem("recentStops");
+function getRecent(region: RegionId): number[] {
+ const rawRecentStops = localStorage.getItem(`recentStops_${region}`);
if (rawRecentStops) {
return JSON.parse(rawRecentStops) as number[];
}
return [];
}
-function getFavouriteIds(): number[] {
- const rawFavouriteStops = localStorage.getItem("favouriteStops");
+function getFavouriteIds(region: RegionId): number[] {
+ const rawFavouriteStops = localStorage.getItem(`favouriteStops_${region}`);
if (rawFavouriteStops) {
return JSON.parse(rawFavouriteStops) as number[];
}
@@ -157,8 +169,9 @@ function getFavouriteIds(): number[] {
}
// New function to load stops from network
-async function loadStopsFromNetwork(): Promise<Stop[]> {
- const response = await fetch("/stops.json");
+async function loadStopsFromNetwork(region: RegionId): Promise<Stop[]> {
+ const regionConfig = getRegionConfig(region);
+ const response = await fetch(regionConfig.stopsEndpoint);
const stops = (await response.json()) as Stop[];
return stops.map((stop) => ({ ...stop, favourite: false } as Stop));
}
diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx
index dc45198..c48932c 100644
--- a/src/frontend/app/routes/estimates-$id.tsx
+++ b/src/frontend/app/routes/estimates-$id.tsx
@@ -13,6 +13,7 @@ import { TimetableSkeleton } from "../components/TimetableSkeleton";
import { ErrorDisplay } from "../components/ErrorDisplay";
import { PullToRefresh } from "../components/PullToRefresh";
import { useAutoRefresh } from "../hooks/useAutoRefresh";
+import { type RegionId, getRegionConfig } from "../data/RegionConfig";
export interface StopDetails {
stop: {
@@ -35,8 +36,9 @@ interface ErrorInfo {
message?: string;
}
-const loadData = async (stopId: string): Promise<StopDetails> => {
- const resp = await fetch(`/api/GetStopEstimates?id=${stopId}`, {
+const loadData = async (region: RegionId, stopId: string): Promise<StopDetails> => {
+ const regionConfig = getRegionConfig(region);
+ const resp = await fetch(`${regionConfig.estimatesEndpoint}?id=${stopId}`, {
headers: {
Accept: "application/json",
},
@@ -49,9 +51,16 @@ const loadData = async (stopId: string): Promise<StopDetails> => {
return await resp.json();
};
-const loadTimetableData = async (stopId: string): Promise<TimetableEntry[]> => {
+const loadTimetableData = async (region: RegionId, stopId: string): Promise<TimetableEntry[]> => {
+ const regionConfig = getRegionConfig(region);
+
+ // Check if timetable is available for this region
+ if (!regionConfig.timetableEndpoint) {
+ throw new Error("Timetable not available for this region");
+ }
+
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
- const resp = await fetch(`/api/GetStopTimetable?date=${today}&stopId=${stopId}`, {
+ const resp = await fetch(`${regionConfig.timetableEndpoint}?date=${today}&stopId=${stopId}`, {
headers: {
Accept: "application/json",
},
@@ -83,7 +92,8 @@ export default function Estimates() {
const [favourited, setFavourited] = useState(false);
const [isManualRefreshing, setIsManualRefreshing] = useState(false);
- const { tableStyle } = useApp();
+ const { tableStyle, region } = useApp();
+ const regionConfig = getRegionConfig(region);
const parseError = (error: any): ErrorInfo => {
if (!navigator.onLine) {
@@ -108,10 +118,10 @@ export default function Estimates() {
setEstimatesLoading(true);
setEstimatesError(null);
- const body = await loadData(params.id!);
+ const body = await loadData(region, params.id!);
setData(body);
setDataDate(new Date());
- setCustomName(StopDataProvider.getCustomName(stopIdNum));
+ setCustomName(StopDataProvider.getCustomName(region, stopIdNum));
} catch (error) {
console.error('Error loading estimates data:', error);
setEstimatesError(parseError(error));
@@ -120,14 +130,20 @@ export default function Estimates() {
} finally {
setEstimatesLoading(false);
}
- }, [params.id, stopIdNum]);
+ }, [params.id, stopIdNum, region]);
const loadTimetableDataAsync = useCallback(async () => {
+ // Skip loading timetable if not available for this region
+ if (!regionConfig.timetableEndpoint) {
+ setTimetableLoading(false);
+ return;
+ }
+
try {
setTimetableLoading(true);
setTimetableError(null);
- const timetableBody = await loadTimetableData(params.id!);
+ const timetableBody = await loadTimetableData(region, params.id!);
setTimetableData(timetableBody);
} catch (error) {
console.error('Error loading timetable data:', error);
@@ -136,7 +152,7 @@ export default function Estimates() {
} finally {
setTimetableLoading(false);
}
- }, [params.id]);
+ }, [params.id, region, regionConfig.timetableEndpoint]);
const refreshData = useCallback(async () => {
await Promise.all([
@@ -168,16 +184,16 @@ export default function Estimates() {
loadEstimatesData();
loadTimetableDataAsync();
- StopDataProvider.pushRecent(parseInt(params.id ?? ""));
- setFavourited(StopDataProvider.isFavourite(parseInt(params.id ?? "")));
- }, [params.id, loadEstimatesData, loadTimetableDataAsync]);
+ StopDataProvider.pushRecent(region, parseInt(params.id ?? ""));
+ setFavourited(StopDataProvider.isFavourite(region, parseInt(params.id ?? "")));
+ }, [params.id, region, loadEstimatesData, loadTimetableDataAsync]);
const toggleFavourite = () => {
if (favourited) {
- StopDataProvider.removeFavourite(stopIdNum);
+ StopDataProvider.removeFavourite(region, stopIdNum);
setFavourited(false);
} else {
- StopDataProvider.addFavourite(stopIdNum);
+ StopDataProvider.addFavourite(region, stopIdNum);
setFavourited(true);
}
};
@@ -188,10 +204,10 @@ export default function Estimates() {
if (input === null) return; // cancelled
const trimmed = input.trim();
if (trimmed === "") {
- StopDataProvider.removeCustomName(stopIdNum);
+ StopDataProvider.removeCustomName(region, stopIdNum);
setCustomName(undefined);
} else {
- StopDataProvider.setCustomName(stopIdNum, trimmed);
+ StopDataProvider.setCustomName(region, stopIdNum, trimmed);
setCustomName(trimmed);
}
};
@@ -270,9 +286,9 @@ export default function Estimates() {
/>
) : data ? (
tableStyle === "grouped" ? (
- <GroupedTable data={data} dataDate={dataDate} />
+ <GroupedTable data={data} dataDate={dataDate} regionConfig={regionConfig} />
) : (
- <RegularTable data={data} dataDate={dataDate} />
+ <RegularTable data={data} dataDate={dataDate} regionConfig={regionConfig} />
)
) : null}
</div>
diff --git a/src/frontend/app/routes/map.tsx b/src/frontend/app/routes/map.tsx
index 56a9c79..c3a1308 100644
--- a/src/frontend/app/routes/map.tsx
+++ b/src/frontend/app/routes/map.tsx
@@ -38,7 +38,7 @@ export default function StopMap() {
name: string;
} | null>(null);
const [isSheetOpen, setIsSheetOpen] = useState(false);
- const { mapState, updateMapState, theme } = useApp();
+ const { mapState, updateMapState, theme, region } = useApp();
const mapRef = useRef<MapRef>(null);
const [mapStyleKey, setMapStyleKey] = useState<string>("light");
@@ -56,7 +56,7 @@ export default function StopMap() {
};
useEffect(() => {
- StopDataProvider.getStops().then((data) => {
+ StopDataProvider.getStops(region).then((data) => {
const features: GeoJsonFeature<
Point,
{ stopId: number; name: string; lines: string[] }
@@ -70,7 +70,7 @@ export default function StopMap() {
}));
setStops(features);
});
- }, []);
+ }, [region]);
useEffect(() => {
//const styleName = "carto";
@@ -115,7 +115,7 @@ export default function StopMap() {
const handlePointClick = (feature: any) => {
const props: any = feature.properties;
// fetch full stop to get lines array
- StopDataProvider.getStopById(props.stopId).then((stop) => {
+ StopDataProvider.getStopById(region, props.stopId).then((stop) => {
if (!stop) return;
setSelectedStop({
stopId: stop.stopId,
diff --git a/src/frontend/app/routes/settings.tsx b/src/frontend/app/routes/settings.tsx
index bcda311..eae6ad8 100644
--- a/src/frontend/app/routes/settings.tsx
+++ b/src/frontend/app/routes/settings.tsx
@@ -2,6 +2,7 @@ import { type Theme, useApp } from "../AppContext";
import "./settings.css";
import { useTranslation } from "react-i18next";
import { useState } from "react";
+import { getAvailableRegions } from "../data/RegionConfig";
export default function Settings() {
const { t, i18n } = useTranslation();
@@ -12,8 +13,12 @@ export default function Settings() {
setTableStyle,
mapPositionMode,
setMapPositionMode,
+ region,
+ setRegion,
} = useApp();
+ const regions = getAvailableRegions();
+
return (
<div className="page-container">
<h1 className="page-title">{t("about.title")}</h1>
@@ -21,6 +26,23 @@ export default function Settings() {
<section className="settings-section">
<h2>{t("about.settings")}</h2>
<div className="settings-content-inline">
+ <label htmlFor="region" className="form-label-inline">
+ Región:
+ </label>
+ <select
+ id="region"
+ className="form-select-inline"
+ value={region}
+ onChange={(e) => setRegion(e.target.value as any)}
+ >
+ {regions.map((r) => (
+ <option key={r.id} value={r.id}>
+ {r.name}
+ </option>
+ ))}
+ </select>
+ </div>
+ <div className="settings-content-inline">
<label htmlFor="theme" className="form-label-inline">
{t("about.theme")}
</label>
diff --git a/src/frontend/app/routes/stoplist.tsx b/src/frontend/app/routes/stoplist.tsx
index 8b0ebe2..13d3584 100644
--- a/src/frontend/app/routes/stoplist.tsx
+++ b/src/frontend/app/routes/stoplist.tsx
@@ -5,9 +5,11 @@ import StopItemSkeleton from "../components/StopItemSkeleton";
import Fuse from "fuse.js";
import "./stoplist.css";
import { useTranslation } from "react-i18next";
+import { useApp } from "../AppContext";
export default function StopList() {
const { t } = useTranslation();
+ const { region } = useApp();
const [data, setData] = useState<Stop[] | null>(null);
const [loading, setLoading] = useState(true);
const [searchResults, setSearchResults] = useState<Stop[] | null>(null);
@@ -29,19 +31,19 @@ export default function StopList() {
// Load favourite and recent IDs immediately from localStorage
useEffect(() => {
- setFavouriteIds(StopDataProvider.getFavouriteIds());
- setRecentIds(StopDataProvider.getRecent());
- }, []);
+ setFavouriteIds(StopDataProvider.getFavouriteIds(region));
+ setRecentIds(StopDataProvider.getRecent(region));
+ }, [region]);
// Load stops from network
const loadStops = useCallback(async () => {
try {
setLoading(true);
- const stops = await StopDataProvider.loadStopsFromNetwork();
+ const stops = await StopDataProvider.loadStopsFromNetwork(region);
// Add favourite flags to stops
- const favouriteStopsIds = StopDataProvider.getFavouriteIds();
+ const favouriteStopsIds = StopDataProvider.getFavouriteIds(region);
const stopsWithFavourites = stops.map(stop => ({
...stop,
favourite: favouriteStopsIds.includes(stop.stopId)
@@ -55,7 +57,7 @@ export default function StopList() {
);
setFavouriteStops(favStops);
- const recIds = StopDataProvider.getRecent();
+ const recIds = StopDataProvider.getRecent(region);
const recStops = recIds
.map(id => stopsWithFavourites.find(stop => stop.stopId === id))
.filter(Boolean) as Stop[];
@@ -66,7 +68,7 @@ export default function StopList() {
} finally {
setLoading(false);
}
- }, []);
+ }, [region]);
useEffect(() => {
loadStops();
diff --git a/src/frontend/app/routes/timetable-$id.tsx b/src/frontend/app/routes/timetable-$id.tsx
index cb55f53..1942ce8 100644
--- a/src/frontend/app/routes/timetable-$id.tsx
+++ b/src/frontend/app/routes/timetable-$id.tsx
@@ -7,6 +7,8 @@ import { TimetableSkeleton } from "../components/TimetableSkeleton";
import { ErrorDisplay } from "../components/ErrorDisplay";
import LineIcon from "../components/LineIcon";
import { useTranslation } from "react-i18next";
+import { type RegionId, getRegionConfig } from "../data/RegionConfig";
+import { useApp } from "../AppContext";
import "./timetable-$id.css";
interface ErrorInfo {
@@ -15,12 +17,19 @@ interface ErrorInfo {
message?: string;
}
-const loadTimetableData = async (stopId: string): Promise<TimetableEntry[]> => {
+const loadTimetableData = async (region: RegionId, stopId: string): Promise<TimetableEntry[]> => {
+ const regionConfig = getRegionConfig(region);
+
+ // Check if timetable is available for this region
+ if (!regionConfig.timetableEndpoint) {
+ throw new Error("Timetable not available for this region");
+ }
+
// Add delay to see skeletons in action (remove in production)
await new Promise(resolve => setTimeout(resolve, 1000));
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
- const resp = await fetch(`/api/GetStopTimetable?date=${today}&stopId=${stopId}`, {
+ const resp = await fetch(`${regionConfig.timetableEndpoint}?date=${today}&stopId=${stopId}`, {
headers: {
Accept: "application/json",
},
@@ -99,6 +108,7 @@ const parseServiceId = (serviceId: string): string => {
export default function Timetable() {
const { t } = useTranslation();
+ const { region } = useApp();
const params = useParams();
const stopIdNum = parseInt(params.id ?? "");
const [timetableData, setTimetableData] = useState<TimetableEntry[]>([]);
@@ -107,6 +117,7 @@ export default function Timetable() {
const [error, setError] = useState<ErrorInfo | null>(null);
const [showPastEntries, setShowPastEntries] = useState(false);
const nextEntryRef = useRef<HTMLDivElement>(null);
+ const regionConfig = getRegionConfig(region);
const currentTime = new Date().toTimeString().slice(0, 8); // HH:MM:SS
const filteredData = filterTimetableData(timetableData, currentTime, showPastEntries);
@@ -130,11 +141,22 @@ export default function Timetable() {
};
const loadData = async () => {
+ // Check if timetable is available for this region
+ if (!regionConfig.timetableEndpoint) {
+ setError({
+ type: 'server',
+ status: 501,
+ message: 'Timetable not available for this region'
+ });
+ setLoading(false);
+ return;
+ }
+
try {
setLoading(true);
setError(null);
- const timetableBody = await loadTimetableData(params.id!);
+ const timetableBody = await loadTimetableData(region, params.id!);
setTimetableData(timetableBody);
if (timetableBody.length > 0) {
@@ -168,8 +190,8 @@ export default function Timetable() {
useEffect(() => {
loadData();
- setCustomName(StopDataProvider.getCustomName(stopIdNum));
- }, [params.id]);
+ setCustomName(StopDataProvider.getCustomName(region, stopIdNum));
+ }, [params.id, region]);
if (loading) {
return (
@@ -266,6 +288,7 @@ const TimetableTableWithScroll: React.FC<{
nextEntryRef: React.RefObject<HTMLDivElement | null>;
}> = ({ data, showAll, currentTime, nextEntryRef }) => {
const { t } = useTranslation();
+ const { region } = useApp();
const nowMinutes = timeToMinutes(currentTime);
return (
@@ -295,7 +318,7 @@ const TimetableTableWithScroll: React.FC<{
>
<div className="card-header">
<div className="line-info">
- <LineIcon line={entry.line.name} />
+ <LineIcon line={entry.line.name} region={region} />
</div>
<div className="destination-info">
diff --git a/src/frontend/public/pwa-worker.js b/src/frontend/public/pwa-worker.js
index 9995828..6f5b9ef 100644
--- a/src/frontend/public/pwa-worker.js
+++ b/src/frontend/public/pwa-worker.js
@@ -4,10 +4,11 @@ const STATIC_CACHE_ASSETS = [
"/favicon.ico",
"/logo-256.png",
"/logo-512.jpg",
- "/stops.json"
+ "/stops/vigo.json",
+ "/stops/santiago.json"
];
-const EXPR_CACHE_AFTER_FIRST_VIEW = /(\/assets\/.*)|(\/api\/GetStopTimetable.*)/;
+const EXPR_CACHE_AFTER_FIRST_VIEW = /(\/assets\/.*)|(\/api\/(vigo|santiago)\/GetStopTimetable.*)/;
const ESTIMATES_MIN_AGE = 15 * 1000;
const ESTIMATES_MAX_AGE = 30 * 1000;
diff --git a/src/frontend/public/stops/santiago.json b/src/frontend/public/stops/santiago.json
new file mode 100644
index 0000000..b23d46d
--- /dev/null
+++ b/src/frontend/public/stops/santiago.json
@@ -0,0 +1,8585 @@
+[
+ {
+ "stopId": 1,
+ "name": {
+ "original": "A Barcia"
+ },
+ "latitude": 42.8734893636941,
+ "longitude": -8.58813285827637,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 2,
+ "name": {
+ "original": "A Barcia (cruce Figueiras)"
+ },
+ "latitude": 42.8732131853499,
+ "longitude": -8.58324185013771,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 3,
+ "name": {
+ "original": "A Barcia (cruce Larañiño)"
+ },
+ "latitude": 42.8729546970255,
+ "longitude": -8.58446896076202,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 4,
+ "name": {
+ "original": "A Barcia (Turgalicia)"
+ },
+ "latitude": 42.873519831692,
+ "longitude": -8.58878463506699,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 5,
+ "name": {
+ "original": "A Cacharela"
+ },
+ "latitude": 42.8647542564465,
+ "longitude": -8.49574148654938,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 6,
+ "name": {
+ "original": "A Cacharela (dir. Fornás)"
+ },
+ "latitude": 42.8646785670954,
+ "longitude": -8.49574148654938,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 7,
+ "name": {
+ "original": "A Castiñeira"
+ },
+ "latitude": 42.9147272899916,
+ "longitude": -8.43936681747437,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 8,
+ "name": {
+ "original": "A Devesa"
+ },
+ "latitude": 42.8582918209728,
+ "longitude": -8.51557910442352,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 9,
+ "name": {
+ "original": "A Devesa (c. Senande 1)"
+ },
+ "latitude": 42.8581325616653,
+ "longitude": -8.51248115301132,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 10,
+ "name": {
+ "original": "A Devesa (c. Senande)"
+ },
+ "latitude": 42.858223005273,
+ "longitude": -8.51255089044571,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 11,
+ "name": {
+ "original": "A Devesa nº 26"
+ },
+ "latitude": 42.858219072945,
+ "longitude": -8.51547986268997,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 16,
+ "name": {
+ "original": "A Pena"
+ },
+ "latitude": 42.8750746624514,
+ "longitude": -8.49863022565842,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 17,
+ "name": {
+ "original": "A Ponte"
+ },
+ "latitude": 42.9509316594446,
+ "longitude": -8.5505336523056,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 18,
+ "name": {
+ "original": "A Ponte (igrexa)"
+ },
+ "latitude": 42.9493767779918,
+ "longitude": -8.54905307292938,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 19,
+ "name": {
+ "original": "A Ponte (igrexa) 1"
+ },
+ "latitude": 42.9494749408613,
+ "longitude": -8.54910135269165,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 20,
+ "name": {
+ "original": "A Ponte 1"
+ },
+ "latitude": 42.951359637597,
+ "longitude": -8.55095744132996,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 21,
+ "name": {
+ "original": "A Portela de Villestro"
+ },
+ "latitude": 42.8749478793621,
+ "longitude": -8.6196380853653,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 22,
+ "name": {
+ "original": "A Sionlla (ferretería)"
+ },
+ "latitude": 42.9277182225271,
+ "longitude": -8.48109126091003,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 23,
+ "name": {
+ "original": "A Sionlla (N-550)"
+ },
+ "latitude": 42.9282327751849,
+ "longitude": -8.48075062036514,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 24,
+ "name": {
+ "original": "A Torre"
+ },
+ "latitude": 42.9292697232067,
+ "longitude": -8.46385538578033,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 25,
+ "name": {
+ "original": "A Torre 1"
+ },
+ "latitude": 42.9292225895844,
+ "longitude": -8.46387147903442,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 28,
+ "name": {
+ "original": "A Xesteira"
+ },
+ "latitude": 42.9293099831472,
+ "longitude": -8.5253718495369,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 29,
+ "name": {
+ "original": "AC-543 (Brandía) 1"
+ },
+ "latitude": 42.8716750164462,
+ "longitude": -8.57894495129585,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 30,
+ "name": {
+ "original": "AC-543 (Brandía) 2"
+ },
+ "latitude": 42.8709811078947,
+ "longitude": -8.57843399047852,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 31,
+ "name": {
+ "original": "AC-7804 (dir. Miramontes)"
+ },
+ "latitude": 42.9304794738353,
+ "longitude": -8.55736792087555,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 32,
+ "name": {
+ "original": "AC-7804 (dir. Santiago)"
+ },
+ "latitude": 42.9304676906646,
+ "longitude": -8.55742692947388,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 33,
+ "name": {
+ "original": "Agra dos Campos"
+ },
+ "latitude": 42.8781940340906,
+ "longitude": -8.49982380867004,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 34,
+ "name": {
+ "original": "Agra dos Campos (c. Senande)"
+ },
+ "latitude": 42.878115412924,
+ "longitude": -8.49995255470276,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 35,
+ "name": {
+ "original": "Albudiño nº 12"
+ },
+ "latitude": 42.9559258614147,
+ "longitude": -8.55875730514526,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 36,
+ "name": {
+ "original": "CDC 2"
+ },
+ "latitude": 42.8709843,
+ "longitude": -8.5231494,
+ "lines": [
+ "9",
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 37,
+ "name": {
+ "original": "Aldea de Abaixo"
+ },
+ "latitude": 42.9255107035718,
+ "longitude": -8.46477806568146,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 38,
+ "name": {
+ "original": "Amañecida 1"
+ },
+ "latitude": 42.8664449554247,
+ "longitude": -8.57972949743271,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 39,
+ "name": {
+ "original": "Amañecida 2"
+ },
+ "latitude": 42.8664528190327,
+ "longitude": -8.57966244220734,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 40,
+ "name": {
+ "original": "Amor Ruibal (IES Pontepedriña)"
+ },
+ "latitude": 42.868080564322,
+ "longitude": -8.54691803455353,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 41,
+ "name": {
+ "original": "Amor Ruibal (Pintor Laxeiro)"
+ },
+ "latitude": 42.8689435664539,
+ "longitude": -8.54823768138886,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 42,
+ "name": {
+ "original": "Amor Ruibal nº 17"
+ },
+ "latitude": 42.8682427467367,
+ "longitude": -8.54697167873383,
+ "lines": [
+ "6",
+ "12",
+ "C6",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 43,
+ "name": {
+ "original": "Andrade (c. Vilacova)"
+ },
+ "latitude": 42.8586634244262,
+ "longitude": -8.50874751806259,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 44,
+ "name": {
+ "original": "Andrade (igresario)"
+ },
+ "latitude": 42.8607514403378,
+ "longitude": -8.5075056552887,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 45,
+ "name": {
+ "original": "Andrade nº 10"
+ },
+ "latitude": 42.8586201691127,
+ "longitude": -8.50891649723053,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 46,
+ "name": {
+ "original": "Andrade nº 25 (igresario)"
+ },
+ "latitude": 42.8607140847413,
+ "longitude": -8.50742518901825,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 47,
+ "name": {
+ "original": "Anxo Casal (st. pza.) 1"
+ },
+ "latitude": 42.8882645771859,
+ "longitude": -8.53578418493271,
+ "lines": [
+ "6",
+ "9",
+ "C6",
+ "P7",
+ "5",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 48,
+ "name": {
+ "original": "Anxo Casal (st. pza.) 2"
+ },
+ "latitude": 42.888215446989,
+ "longitude": -8.53567689657211,
+ "lines": [
+ "C2",
+ "P1",
+ "P2",
+ "P7",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 49,
+ "name": {
+ "original": "Anxo Casal (Xunta) 1"
+ },
+ "latitude": 42.8882115165715,
+ "longitude": -8.53533357381821,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 50,
+ "name": {
+ "original": "Anxo Casal (Xunta) 2"
+ },
+ "latitude": 42.8882508207347,
+ "longitude": -8.53540331125259,
+ "lines": [
+ "C2",
+ "C4",
+ "P1",
+ "P2",
+ "P7",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 51,
+ "name": {
+ "original": "As Moas de Arriba 1"
+ },
+ "latitude": 42.8862295716698,
+ "longitude": -8.57297167181969,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 52,
+ "name": {
+ "original": "As Moas de Arriba 2"
+ },
+ "latitude": 42.8863121130356,
+ "longitude": -8.57298240065575,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 53,
+ "name": {
+ "original": "As Pereiras"
+ },
+ "latitude": 42.9246691152418,
+ "longitude": -8.51013153791428,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 54,
+ "name": {
+ "original": "As Pereiras 1"
+ },
+ "latitude": 42.8331286732589,
+ "longitude": -8.50716769695282,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 55,
+ "name": {
+ "original": "As Pereiras 2"
+ },
+ "latitude": 42.8326802041119,
+ "longitude": -8.50673854351044,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 58,
+ "name": {
+ "original": "Avda. Castelao (Centro saúde Vite)"
+ },
+ "latitude": 42.8905009423197,
+ "longitude": -8.53984236717224,
+ "lines": [
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 59,
+ "name": {
+ "original": "Avda. Castelao (filoloxía)"
+ },
+ "latitude": 42.8917370003803,
+ "longitude": -8.54535430669785,
+ "lines": [
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 60,
+ "name": {
+ "original": "Avda. Castelao (García Lorca)"
+ },
+ "latitude": 42.8896470848849,
+ "longitude": -8.53748738765717,
+ "lines": [
+ "8",
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 61,
+ "name": {
+ "original": "Avda. Castelao (parque Pablo Iglesias)"
+ },
+ "latitude": 42.8896470848849,
+ "longitude": -8.53690803050995,
+ "lines": [
+ "8",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 62,
+ "name": {
+ "original": "Avda. Castelao (Xesús Carro)"
+ },
+ "latitude": 42.8903889294748,
+ "longitude": -8.54023933410645,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 63,
+ "name": {
+ "original": "Avda. Castelao (xornalismo)"
+ },
+ "latitude": 42.8920160434467,
+ "longitude": -8.54410171508789,
+ "lines": [
+ "15",
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 64,
+ "name": {
+ "original": "N634 CRTVG rotonda"
+ },
+ "latitude": 42.8946413,
+ "longitude": -8.4752162,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 65,
+ "name": {
+ "original": "Avda. Castelao nº 13"
+ },
+ "latitude": 42.8924974880225,
+ "longitude": -8.54249238967896,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 66,
+ "name": {
+ "original": "Avda. Castelao nº 26"
+ },
+ "latitude": 42.8919138588083,
+ "longitude": -8.5410413146019,
+ "lines": [
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 67,
+ "name": {
+ "original": "Avda. Castelao nº 40"
+ },
+ "latitude": 42.8925977066249,
+ "longitude": -8.54252994060516,
+ "lines": [
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 68,
+ "name": {
+ "original": "Avda. Castelao nº 7"
+ },
+ "latitude": 42.8918991206253,
+ "longitude": -8.54120627045631,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 69,
+ "name": {
+ "original": "Avda. Coimbra nº 2"
+ },
+ "latitude": 42.8855407400123,
+ "longitude": -8.54121565818787,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 70,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 1 (Castrosua)"
+ },
+ "latitude": 42.9048035074155,
+ "longitude": -8.51686120033264,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 71,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 2"
+ },
+ "latitude": 42.9031060004495,
+ "longitude": -8.51979285478592,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 72,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 3 (EGASA)"
+ },
+ "latitude": 42.9009172477152,
+ "longitude": -8.52348357439041,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 73,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 4 (Meixonfrío)"
+ },
+ "latitude": 42.8980102517632,
+ "longitude": -8.52877289056778,
+ "lines": [
+ "1",
+ "P4",
+ "P6",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 74,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 5 (c. Mallou)"
+ },
+ "latitude": 42.8979090595066,
+ "longitude": -8.52840811014175,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 75,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 6 (Gramalleira)"
+ },
+ "latitude": 42.9013455734857,
+ "longitude": -8.52240264415741,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 76,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 7 (FORD)"
+ },
+ "latitude": 42.9030185697163,
+ "longitude": -8.5195380449295,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 77,
+ "name": {
+ "original": "Avda. Cruceiro da Coruña 8 (c. Costa Vella)"
+ },
+ "latitude": 42.9057406526939,
+ "longitude": -8.51486966013908,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 78,
+ "name": {
+ "original": "Avda. da Coruña (c. rúa Feáns)"
+ },
+ "latitude": 42.8762736834394,
+ "longitude": -8.55068653821945,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 79,
+ "name": {
+ "original": "Avda. das Burgas (Instituto Xelmírez)"
+ },
+ "latitude": 42.8781036197404,
+ "longitude": -8.55233877897263,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 80,
+ "name": {
+ "original": "Avda. das Ciencias (campo de hockey)"
+ },
+ "latitude": 42.8763601692984,
+ "longitude": -8.55469107627869,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 81,
+ "name": {
+ "original": "Avda. de Coimbra nº 28"
+ },
+ "latitude": 42.8870363105218,
+ "longitude": -8.54148387908936,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 82,
+ "name": {
+ "original": "Avda. de Coimbra nº 9"
+ },
+ "latitude": 42.8869950403372,
+ "longitude": -8.5414382815361,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 83,
+ "name": {
+ "original": "Avda. de Ferrol nº 19"
+ },
+ "latitude": 42.8707953435167,
+ "longitude": -8.55368793010712,
+ "lines": [
+ "12",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 84,
+ "name": {
+ "original": "Avda. de Ferrol nº 53 (Xosé Pasín)"
+ },
+ "latitude": 42.8677837202532,
+ "longitude": -8.55484932661057,
+ "lines": [
+ "12",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 85,
+ "name": {
+ "original": "Avda. de Ferrol (pza. Mercé)"
+ },
+ "latitude": 42.8657087206892,
+ "longitude": -8.55591416358948,
+ "lines": [
+ "12",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 86,
+ "name": {
+ "original": "Avda. de Lugo (c. Quiroga Palacios)"
+ },
+ "latitude": 42.8806253442159,
+ "longitude": -8.53325486183166,
+ "lines": [
+ "C11",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 87,
+ "name": {
+ "original": "Avda. Rodríguez de Viguri (c. Monte dos Postes)"
+ },
+ "latitude": 42.8860805,
+ "longitude": -8.5329345,
+ "lines": [
+ "9",
+ "C11",
+ "13",
+ "C2",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 88,
+ "name": {
+ "original": "Londres (centro saúde)"
+ },
+ "latitude": 42.881911,
+ "longitude": -8.5320754,
+ "lines": [
+ "9",
+ "C11",
+ "C4",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 89,
+ "name": {
+ "original": "Avda. de Lugo (xulgados)"
+ },
+ "latitude": 42.8839537447952,
+ "longitude": -8.53325217962265,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 90,
+ "name": {
+ "original": "Avda. de Lugo nº 123"
+ },
+ "latitude": 42.8742677671808,
+ "longitude": -8.53678464889526,
+ "lines": [
+ "C11",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 91,
+ "name": {
+ "original": "Avda. de Lugo nº 151"
+ },
+ "latitude": 42.8781891202706,
+ "longitude": -8.53401124477386,
+ "lines": [
+ "C11",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 92,
+ "name": {
+ "original": "Avda. de Lugo nº 22"
+ },
+ "latitude": 42.8803197159119,
+ "longitude": -8.53288605809212,
+ "lines": [
+ "13",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 93,
+ "name": {
+ "original": "Avda. de Lugo nº 263"
+ },
+ "latitude": 42.8836677865174,
+ "longitude": -8.53355795145035,
+ "lines": [
+ "C11",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 94,
+ "name": {
+ "original": "Avda. de San Marcos nº 18-20"
+ },
+ "latitude": 42.8924935578779,
+ "longitude": -8.4910637140274,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 95,
+ "name": {
+ "original": "Avda. de Vilagarcía nº 26"
+ },
+ "latitude": 42.8715541235912,
+ "longitude": -8.55205178260803,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 96,
+ "name": {
+ "original": "Avda. Lope Gómez de Marzoa 1"
+ },
+ "latitude": 42.8741193602028,
+ "longitude": -8.55511218309402,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 97,
+ "name": {
+ "original": "Avda. Lope Gómez de Marzoa 2"
+ },
+ "latitude": 42.8736819998146,
+ "longitude": -8.55872645974159,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 98,
+ "name": {
+ "original": "Avda. M. V. Míguez (c. hospital Clínico)"
+ },
+ "latitude": 42.8706734660549,
+ "longitude": -8.5674449801445,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 99,
+ "name": {
+ "original": "Avda. M. V. Míguez (c. hospital)"
+ },
+ "latitude": 42.8703559937947,
+ "longitude": -8.56822952628136,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 100,
+ "name": {
+ "original": "Avda. M. V. Míguez (c. igrexa Vidán)"
+ },
+ "latitude": 42.8694704046486,
+ "longitude": -8.57493907213211,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 101,
+ "name": {
+ "original": "Avda. M. V. Míguez nº 35"
+ },
+ "latitude": 42.8700227935981,
+ "longitude": -8.57227295637131,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 102,
+ "name": {
+ "original": "Avda. M. V. Míguez nº 42"
+ },
+ "latitude": 42.8699107435703,
+ "longitude": -8.57258945703506,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 103,
+ "name": {
+ "original": "Avda. M. V. Míguez nº 50"
+ },
+ "latitude": 42.8697161298807,
+ "longitude": -8.57449650764465,
+ "lines": [
+ "8",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 104,
+ "name": {
+ "original": "Avda. Mestre Mateo 1 (Gran Hotel)"
+ },
+ "latitude": 42.8728790177295,
+ "longitude": -8.55665177106857,
+ "lines": [
+ "15",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 105,
+ "name": {
+ "original": "Avda. Mestre Mateo 2 (nº 2)"
+ },
+ "latitude": 42.871909921398,
+ "longitude": -8.56343910098076,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 106,
+ "name": {
+ "original": "Avda. Mestre Mateo 3"
+ },
+ "latitude": 42.8717900118691,
+ "longitude": -8.5634645819664,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 107,
+ "name": {
+ "original": "Avda. Mestre Mateo 4 (Gran Hotel)"
+ },
+ "latitude": 42.872772869989,
+ "longitude": -8.5562601685524,
+ "lines": [
+ "15",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 108,
+ "name": {
+ "original": "Avda. Rodríguez Viguri nº 16"
+ },
+ "latitude": 42.8874047930891,
+ "longitude": -8.53243812918663,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 109,
+ "name": {
+ "original": "Avda. Santiago de Cuba (Lamas de Abade)"
+ },
+ "latitude": 42.8579634710868,
+ "longitude": -8.53495672345161,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 110,
+ "name": {
+ "original": "Avda. Santiago de Cuba (rúa Cantarrá)"
+ },
+ "latitude": 42.85779044769,
+ "longitude": -8.53489637374878,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 111,
+ "name": {
+ "original": "Avda. Teodomiro (Seminario Menor)"
+ },
+ "latitude": 42.8772859535135,
+ "longitude": -8.53742837905884,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 112,
+ "name": {
+ "original": "Avda. Xoán Carlos I"
+ },
+ "latitude": 42.876352,
+ "longitude": -8.547944,
+ "lines": [
+ "1",
+ "8",
+ "12",
+ "C2",
+ "P2",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 113,
+ "name": {
+ "original": "Avda. Xoán Carlos I - Igrexa do Pilar"
+ },
+ "latitude": 42.8763139780024,
+ "longitude": -8.54785412549973,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 114,
+ "name": {
+ "original": "Bálsoma"
+ },
+ "latitude": 42.9330707347107,
+ "longitude": -8.51512581110001,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 115,
+ "name": {
+ "original": "Bando (c. refuxio Animais) 1"
+ },
+ "latitude": 42.8873536969712,
+ "longitude": -8.48592460155487,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 116,
+ "name": {
+ "original": "Bando (c. refuxio Animais) 2"
+ },
+ "latitude": 42.8873851407411,
+ "longitude": -8.48603188991547,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 117,
+ "name": {
+ "original": "Bando (igrexa) 1"
+ },
+ "latitude": 42.88448438551,
+ "longitude": -8.48486244678497,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 118,
+ "name": {
+ "original": "Bando (igrexa) 2"
+ },
+ "latitude": 42.884654386107,
+ "longitude": -8.48481684923172,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 119,
+ "name": {
+ "original": "Bando de Arriba 1"
+ },
+ "latitude": 42.8840510292679,
+ "longitude": -8.47592264413834,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 120,
+ "name": {
+ "original": "Bando de Arriba 2"
+ },
+ "latitude": 42.8840058264007,
+ "longitude": -8.47605407238007,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 121,
+ "name": {
+ "original": "Bar de Abaixo 1"
+ },
+ "latitude": 42.8837857076173,
+ "longitude": -8.55905771255493,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 122,
+ "name": {
+ "original": "Bar de Abaixo 2"
+ },
+ "latitude": 42.8839281953123,
+ "longitude": -8.55785608291626,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 123,
+ "name": {
+ "original": "Bar de Arriba 1"
+ },
+ "latitude": 42.885855186231,
+ "longitude": -8.56329292058945,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 124,
+ "name": {
+ "original": "Bar de Arriba 2"
+ },
+ "latitude": 42.8858699258582,
+ "longitude": -8.56321111321449,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 125,
+ "name": {
+ "original": "Basquiños nº 28"
+ },
+ "latitude": 42.8869233087602,
+ "longitude": -8.5395111143589,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "9",
+ "C6",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 126,
+ "name": {
+ "original": "Benéfica de Conxo"
+ },
+ "latitude": 42.8629455504626,
+ "longitude": -8.5586205124855,
+ "lines": [
+ "12",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 127,
+ "name": {
+ "original": "Benéfica de Conxo (Televés)"
+ },
+ "latitude": 42.8629593125561,
+ "longitude": -8.55851590633392,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 128,
+ "name": {
+ "original": "Berlín (Centro Sociocultural)"
+ },
+ "latitude": 42.8840785440405,
+ "longitude": -8.53208810091019,
+ "lines": [
+ "9",
+ "C11",
+ "C2",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 130,
+ "name": {
+ "original": "Bernardo Barreiro (Instituto)"
+ },
+ "latitude": 42.8747326423581,
+ "longitude": -8.54063898324966,
+ "lines": [
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 131,
+ "name": {
+ "original": "Bornais (rotonda)"
+ },
+ "latitude": 42.8494808216099,
+ "longitude": -8.52612555027008,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 132,
+ "name": {
+ "original": "Bruxelas"
+ },
+ "latitude": 42.8841610882845,
+ "longitude": -8.5263803601265,
+ "lines": [
+ "C11",
+ "C2",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 135,
+ "name": {
+ "original": "Burgo das Nacións (Auditorio de Galicia)"
+ },
+ "latitude": 42.8903181844154,
+ "longitude": -8.54357868432999,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 136,
+ "name": {
+ "original": "Burgo das Nacións (colexio de Vite)"
+ },
+ "latitude": 42.890909689221,
+ "longitude": -8.54310125112534,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 137,
+ "name": {
+ "original": "Burgo das Nacións (Económicas)"
+ },
+ "latitude": 42.8882390294884,
+ "longitude": -8.54373693466187,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 138,
+ "name": {
+ "original": "Burgo das Nacións (fac. Económicas)"
+ },
+ "latitude": 42.888215446989,
+ "longitude": -8.54381740093231,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 139,
+ "name": {
+ "original": "N634 CRTVG rotonda 1"
+ },
+ "latitude": 42.8943408,
+ "longitude": -8.4755513,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 140,
+ "name": {
+ "original": "Camiño dos Vilares (Cañoteira)"
+ },
+ "latitude": 42.9048133308151,
+ "longitude": -8.53224366903305,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 141,
+ "name": {
+ "original": "Camiño dos Vilares (Follas Novas)"
+ },
+ "latitude": 42.8995114144713,
+ "longitude": -8.53360757231712,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 142,
+ "name": {
+ "original": "Camiño dos Vilares (rúa do Tambre)"
+ },
+ "latitude": 42.9064056832064,
+ "longitude": -8.52730304002762,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 143,
+ "name": {
+ "original": "Camiño dos Vilares (rúa dos Vilares)"
+ },
+ "latitude": 42.9058860366388,
+ "longitude": -8.52908402681351,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 144,
+ "name": {
+ "original": "Camiño dos Vilares nº 103"
+ },
+ "latitude": 42.8971800773728,
+ "longitude": -8.53400185704231,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 145,
+ "name": {
+ "original": "Camiño dos Vilares nº 133"
+ },
+ "latitude": 42.8990683394893,
+ "longitude": -8.53374838829041,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 146,
+ "name": {
+ "original": "Camiño dos Vilares nº 172"
+ },
+ "latitude": 42.9011618653201,
+ "longitude": -8.53328704833984,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 147,
+ "name": {
+ "original": "Camiño dos Vilares nº 27"
+ },
+ "latitude": 42.8941215988366,
+ "longitude": -8.53540331125259,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 148,
+ "name": {
+ "original": "Camiño dos Vilares nº 36"
+ },
+ "latitude": 42.894232622394,
+ "longitude": -8.53523835539818,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 149,
+ "name": {
+ "original": "Camiño dos Vilares nº 88"
+ },
+ "latitude": 42.8970130586894,
+ "longitude": -8.53399246931076,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 150,
+ "name": {
+ "original": "Camiño Francés (C. Comercial)"
+ },
+ "latitude": 42.8879432649888,
+ "longitude": -8.52611213922501,
+ "lines": [
+ "C11",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 151,
+ "name": {
+ "original": "Camiño Francés (c. Pena María)"
+ },
+ "latitude": 42.8875168113533,
+ "longitude": -8.52372094988823,
+ "lines": [
+ "C11",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 152,
+ "name": {
+ "original": "Camiño Francés (c. Valiño)"
+ },
+ "latitude": 42.8875354810442,
+ "longitude": -8.52418094873428,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 153,
+ "name": {
+ "original": "Camiño Francés (colexio Monte dos Postes)"
+ },
+ "latitude": 42.8878941345359,
+ "longitude": -8.52866023778915,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 154,
+ "name": {
+ "original": "Campo da Angustia"
+ },
+ "latitude": 42.8822065288528,
+ "longitude": -8.53629648685455,
+ "lines": [
+ "9",
+ "13",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 155,
+ "name": {
+ "original": "Campo de Conxo (psiquiátrico)"
+ },
+ "latitude": 42.8632443838012,
+ "longitude": -8.55610191822052,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 156,
+ "name": {
+ "original": "Campo de San Domingos (c. Mestre Mateo)"
+ },
+ "latitude": 42.8720023105483,
+ "longitude": -8.56447041034698,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 157,
+ "name": {
+ "original": "Campo de San Domingos (c. Mestre Mateo) 2"
+ },
+ "latitude": 42.8719944476473,
+ "longitude": -8.56455489993095,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 158,
+ "name": {
+ "original": "Campo de San Domingos (c. rúa Bidueiro)"
+ },
+ "latitude": 42.8749468965464,
+ "longitude": -8.56334924697876,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 159,
+ "name": {
+ "original": "Campo de San Domingos (c. rúa Bidueiro) 2"
+ },
+ "latitude": 42.8749921060507,
+ "longitude": -8.56342166662216,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 160,
+ "name": {
+ "original": "Campo de Sta. Isabel (campo de fútbol)"
+ },
+ "latitude": 42.8845747905101,
+ "longitude": -8.54854747653008,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 161,
+ "name": {
+ "original": "Campo de Sta. Isabel nº 8"
+ },
+ "latitude": 42.8848980855676,
+ "longitude": -8.55000391602516,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 162,
+ "name": {
+ "original": "Carme de Abaixo (c. Monte Pío)"
+ },
+ "latitude": 42.8827420980538,
+ "longitude": -8.55343043804169,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 163,
+ "name": {
+ "original": "Carme de abaixo 1"
+ },
+ "latitude": 42.8814527933126,
+ "longitude": -8.55217516422272,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 164,
+ "name": {
+ "original": "Carme de Abaixo 2"
+ },
+ "latitude": 42.8813879342831,
+ "longitude": -8.5520812869072,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 165,
+ "name": {
+ "original": "Carme de Abaixo nº 25"
+ },
+ "latitude": 42.8826831365346,
+ "longitude": -8.55337142944336,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 166,
+ "name": {
+ "original": "Casais"
+ },
+ "latitude": 42.906771103122,
+ "longitude": -8.45756828784943,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 167,
+ "name": {
+ "original": "Casal (viaducto)"
+ },
+ "latitude": 42.8603926290686,
+ "longitude": -8.58930230140686,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 168,
+ "name": {
+ "original": "Casal 1"
+ },
+ "latitude": 42.8625267881532,
+ "longitude": -8.58734428882599,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 169,
+ "name": {
+ "original": "Casal 2"
+ },
+ "latitude": 42.8634783378396,
+ "longitude": -8.58632504940033,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 170,
+ "name": {
+ "original": "Casal 3"
+ },
+ "latitude": 42.8604427644672,
+ "longitude": -8.58923524618149,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 171,
+ "name": {
+ "original": "Casal 4"
+ },
+ "latitude": 42.8626732569835,
+ "longitude": -8.58729600906372,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 172,
+ "name": {
+ "original": "Casal 5"
+ },
+ "latitude": 42.8635392837041,
+ "longitude": -8.58626335859299,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 173,
+ "name": {
+ "original": "Casal do Castiñeiriño (urbanización)"
+ },
+ "latitude": 42.8558429179484,
+ "longitude": -8.53962242603302,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 174,
+ "name": {
+ "original": "Casal do Castiñeiriño (viaducto)"
+ },
+ "latitude": 42.853155009742,
+ "longitude": -8.53883385658264,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 175,
+ "name": {
+ "original": "Casas do Rego 1"
+ },
+ "latitude": 42.8837129896323,
+ "longitude": -8.55439335107803,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 176,
+ "name": {
+ "original": "Casas do Rego 2"
+ },
+ "latitude": 42.8837729328423,
+ "longitude": -8.55440273880959,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 177,
+ "name": {
+ "original": "Casas Novas (Monte Pío)"
+ },
+ "latitude": 42.8866039548364,
+ "longitude": -8.55283498764038,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 178,
+ "name": {
+ "original": "Casas Novas nº 10"
+ },
+ "latitude": 42.8867149919266,
+ "longitude": -8.55286315083504,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 179,
+ "name": {
+ "original": "Casas Novas nº 53"
+ },
+ "latitude": 42.888727381721,
+ "longitude": -8.55373352766037,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 180,
+ "name": {
+ "original": "Casas Novas nº 55"
+ },
+ "latitude": 42.8891921479611,
+ "longitude": -8.55406075716019,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 181,
+ "name": {
+ "original": "Castiñeiriño nº 1"
+ },
+ "latitude": 42.8607514403378,
+ "longitude": -8.54057461023331,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 182,
+ "name": {
+ "original": "Castiñeiriño nº 12"
+ },
+ "latitude": 42.860791745035,
+ "longitude": -8.54083210229874,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 183,
+ "name": {
+ "original": "Castiñeiriño nº 50"
+ },
+ "latitude": 42.8585896937601,
+ "longitude": -8.5401776432991,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 184,
+ "name": {
+ "original": "Castiñeiriño nº 61"
+ },
+ "latitude": 42.858422570591,
+ "longitude": -8.54006364941597,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 185,
+ "name": {
+ "original": "Cemiterio de Boisaca"
+ },
+ "latitude": 42.9077180414256,
+ "longitude": -8.51602971553802,
+ "lines": [
+ "1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 186,
+ "name": {
+ "original": "Chan de Curros nº 2A"
+ },
+ "latitude": 42.8929612433255,
+ "longitude": -8.53734254837036,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 187,
+ "name": {
+ "original": "Rúa da Choupana"
+ },
+ "latitude": 42.8685592469491,
+ "longitude": -8.56068313121796,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 188,
+ "name": {
+ "original": "Cima da Eira"
+ },
+ "latitude": 42.8927332962395,
+ "longitude": -8.53771939873695,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 189,
+ "name": {
+ "original": "Cima da Vila"
+ },
+ "latitude": 42.8641113854984,
+ "longitude": -8.52390199899673,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 190,
+ "name": {
+ "original": "Codesedas 1"
+ },
+ "latitude": 42.8911425558358,
+ "longitude": -8.58148634433746,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 191,
+ "name": {
+ "original": "Codesedas 2"
+ },
+ "latitude": 42.8892864764111,
+ "longitude": -8.57999503612518,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 192,
+ "name": {
+ "original": "Codesedas 3"
+ },
+ "latitude": 42.8893405186873,
+ "longitude": -8.57990384101868,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 193,
+ "name": {
+ "original": "Codesedas 4"
+ },
+ "latitude": 42.8911062011901,
+ "longitude": -8.58134418725967,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 194,
+ "name": {
+ "original": "Colexiata de Sar"
+ },
+ "latitude": 42.8731954941683,
+ "longitude": -8.53696167469025,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 195,
+ "name": {
+ "original": "Colexiata de Sar (dir. centro)"
+ },
+ "latitude": 42.8731719059183,
+ "longitude": -8.53678196668625,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 196,
+ "name": {
+ "original": "R. Viguri acceso Concheiros"
+ },
+ "latitude": 42.8849383,
+ "longitude": -8.5338436,
+ "lines": [
+ "9",
+ "13",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 197,
+ "name": {
+ "original": "Avda. Lugo st. Fontiñas"
+ },
+ "latitude": 42.8838507,
+ "longitude": -8.5336569,
+ "lines": [
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 198,
+ "name": {
+ "original": "Correxíns 1"
+ },
+ "latitude": 42.8887431032578,
+ "longitude": -8.57762932777405,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 199,
+ "name": {
+ "original": "Correxíns 2"
+ },
+ "latitude": 42.8888325194222,
+ "longitude": -8.57743486762047,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 200,
+ "name": {
+ "original": "Os Vilares 45b"
+ },
+ "latitude": 42.9078234,
+ "longitude": -8.5318167,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 201,
+ "name": {
+ "original": "Costa de Aríns"
+ },
+ "latitude": 42.862075583331,
+ "longitude": -8.491171002388,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 202,
+ "name": {
+ "original": "Costa de Aríns (dir. Fornás)"
+ },
+ "latitude": 42.8620087378917,
+ "longitude": -8.49114418029785,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 203,
+ "name": {
+ "original": "Costa de San Marcos (desvío)"
+ },
+ "latitude": 42.8921594946725,
+ "longitude": -8.49770486354828,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 204,
+ "name": {
+ "original": "Costa de San Marcos (hotel Santiago Apóstol)"
+ },
+ "latitude": 42.8888246586657,
+ "longitude": -8.5024805366993,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 205,
+ "name": {
+ "original": "Costa de San Marcos 1"
+ },
+ "latitude": 42.8924709595417,
+ "longitude": -8.49384248256683,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 206,
+ "name": {
+ "original": "Costa de San Marcos 2"
+ },
+ "latitude": 42.8924277279189,
+ "longitude": -8.49157333374023,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 207,
+ "name": {
+ "original": "Costa de Sta. Isabel nº 16"
+ },
+ "latitude": 42.8860526969425,
+ "longitude": -8.55153009295464,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 208,
+ "name": {
+ "original": "Costa de Sta. Isabel nº 18"
+ },
+ "latitude": 42.8860821760989,
+ "longitude": -8.55147644877434,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 209,
+ "name": {
+ "original": "Neiro (dir.VM)"
+ },
+ "latitude": 42.8903831,
+ "longitude": -8.4596878,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 210,
+ "name": {
+ "original": "Neiro (dir.SM)"
+ },
+ "latitude": 42.8905276,
+ "longitude": -8.4594276,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 211,
+ "name": {
+ "original": "Xan Xordo 1"
+ },
+ "latitude": 42.899491,
+ "longitude": -8.4569322,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 212,
+ "name": {
+ "original": "Eslovenia (Decathlon)"
+ },
+ "latitude": 42.9028299546784,
+ "longitude": -8.5099732875824,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 214,
+ "name": {
+ "original": "Castela e León (Mercadona)"
+ },
+ "latitude": 42.9011841,
+ "longitude": -8.5078971,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 217,
+ "name": {
+ "original": "Coto da Nai"
+ },
+ "latitude": 42.861170214689,
+ "longitude": -8.50548326969147,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 218,
+ "name": {
+ "original": "Coto da Nai nº 12"
+ },
+ "latitude": 42.8610896057623,
+ "longitude": -8.50566029548645,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 219,
+ "name": {
+ "original": "Cruceiro de San Pedro"
+ },
+ "latitude": 42.8818222919379,
+ "longitude": -8.53502243757248,
+ "lines": [
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 220,
+ "name": {
+ "original": "Cruceiro de San Pedro 1"
+ },
+ "latitude": 42.8819068046104,
+ "longitude": -8.53498220443726,
+ "lines": [
+ "9",
+ "13",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 221,
+ "name": {
+ "original": "Cruceiro de Sar"
+ },
+ "latitude": 42.866490171157,
+ "longitude": -8.52983236312866,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 222,
+ "name": {
+ "original": "Cruceiro de Sar (dir. centro)"
+ },
+ "latitude": 42.8665511140481,
+ "longitude": -8.52978140115738,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 223,
+ "name": {
+ "original": "Cruceiro do Gaio"
+ },
+ "latitude": 42.8803737660437,
+ "longitude": -8.55014204978943,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 224,
+ "name": {
+ "original": "Cruceiro do Gaio (acceso Carme Abaixo)"
+ },
+ "latitude": 42.8804622116118,
+ "longitude": -8.55034857988358,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 225,
+ "name": {
+ "original": "Cruceiro do Gaio (dir. centro)"
+ },
+ "latitude": 42.8805339507017,
+ "longitude": -8.55039685964584,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 226,
+ "name": {
+ "original": "Curros Enríquez"
+ },
+ "latitude": 42.8746893983033,
+ "longitude": -8.542320728302,
+ "lines": [
+ "7",
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 227,
+ "name": {
+ "original": "Curros Enríquez nº 25"
+ },
+ "latitude": 42.875725281649,
+ "longitude": -8.54029566049576,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 228,
+ "name": {
+ "original": "Ensinanza"
+ },
+ "latitude": 42.8789635334699,
+ "longitude": -8.5410962998867,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "C11",
+ "13",
+ "15",
+ "C6",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "P6",
+ "P7",
+ "P8",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 229,
+ "name": {
+ "original": "Pza. Camilo D. Baliño"
+ },
+ "latitude": 42.8871090245894,
+ "longitude": -8.53414535522461,
+ "lines": [
+ "C2",
+ "C4",
+ "P2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 230,
+ "name": {
+ "original": "Pza. Camilo D. Baliño"
+ },
+ "latitude": 42.8872465915099,
+ "longitude": -8.53412926197052,
+ "lines": [
+ "C2",
+ "C4",
+ "P1",
+ "P2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 231,
+ "name": {
+ "original": "Estrada de Brins 1"
+ },
+ "latitude": 42.8987510133215,
+ "longitude": -8.58805775642395,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 232,
+ "name": {
+ "original": "Estrada de Brins 2"
+ },
+ "latitude": 42.8987863810248,
+ "longitude": -8.58825087547302,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 233,
+ "name": {
+ "original": "Feáns 1"
+ },
+ "latitude": 42.8922862423958,
+ "longitude": -8.6126697063446,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 234,
+ "name": {
+ "original": "Feáns 2"
+ },
+ "latitude": 42.890631623715,
+ "longitude": -8.61012160778046,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 235,
+ "name": {
+ "original": "Feáns 3"
+ },
+ "latitude": 42.8906827171175,
+ "longitude": -8.61017525196075,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 236,
+ "name": {
+ "original": "Feáns 4"
+ },
+ "latitude": 42.892368775657,
+ "longitude": -8.61277163028717,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 237,
+ "name": {
+ "original": "Federico García Lorca nº 14"
+ },
+ "latitude": 42.8912015092697,
+ "longitude": -8.53803589940071,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 238,
+ "name": {
+ "original": "Federico García Lorca nº 20"
+ },
+ "latitude": 42.8915709495057,
+ "longitude": -8.53631928563118,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 239,
+ "name": {
+ "original": "Federico García Lorca nº 21"
+ },
+ "latitude": 42.8915925656212,
+ "longitude": -8.53636890649796,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 240,
+ "name": {
+ "original": "Federico García Lorca nº 8"
+ },
+ "latitude": 42.8912427766399,
+ "longitude": -8.53810161352158,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 241,
+ "name": {
+ "original": "Figueiras (dir. Folgoso)"
+ },
+ "latitude": 42.8947857721832,
+ "longitude": -8.58299911022186,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 242,
+ "name": {
+ "original": "Figueiras (dir. Santiago)"
+ },
+ "latitude": 42.8948810745766,
+ "longitude": -8.58303129673004,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 243,
+ "name": {
+ "original": "Figueiras (igrexa) 1"
+ },
+ "latitude": 42.8980829528935,
+ "longitude": -8.58542382717133,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 244,
+ "name": {
+ "original": "Figueiras (igrexa) 2"
+ },
+ "latitude": 42.898204776217,
+ "longitude": -8.58542919158936,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 245,
+ "name": {
+ "original": "Folgoso"
+ },
+ "latitude": 42.8962791535838,
+ "longitude": -8.58963489532471,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 246,
+ "name": {
+ "original": "Torrente (c. Volta do Castro)"
+ },
+ "latitude": 42.8608035415268,
+ "longitude": -8.5658960044384,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 247,
+ "name": {
+ "original": "Fonte de San Antonio nº 3"
+ },
+ "latitude": 42.8776250111364,
+ "longitude": -8.54257687926292,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "13",
+ "15",
+ "C5",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "P6",
+ "P7",
+ "P8",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 249,
+ "name": {
+ "original": "Formarís"
+ },
+ "latitude": 42.9195388112461,
+ "longitude": -8.49164038896561,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 250,
+ "name": {
+ "original": "Formarís 2"
+ },
+ "latitude": 42.9195997017388,
+ "longitude": -8.49129438400269,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 251,
+ "name": {
+ "original": "Fornás"
+ },
+ "latitude": 42.8576439672762,
+ "longitude": -8.48847806453705,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 252,
+ "name": {
+ "original": "Meixonfrío (rotonda)"
+ },
+ "latitude": 42.8992707200313,
+ "longitude": -8.52577552199364,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 253,
+ "name": {
+ "original": "Frades (desvío Lamas entrada)"
+ },
+ "latitude": 42.9404904265803,
+ "longitude": -8.44278931617737,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 254,
+ "name": {
+ "original": "Frades (desvío Lamas saída)"
+ },
+ "latitude": 42.9405218432503,
+ "longitude": -8.44270884990692,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 255,
+ "name": {
+ "original": "Frades 1"
+ },
+ "latitude": 42.9377198059551,
+ "longitude": -8.44230115413666,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 256,
+ "name": {
+ "original": "Frades 2"
+ },
+ "latitude": 42.9378906415916,
+ "longitude": -8.44226896762848,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 257,
+ "name": {
+ "original": "Fraíz de Arriba"
+ },
+ "latitude": 42.8949901317739,
+ "longitude": -8.6154967546463,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 258,
+ "name": {
+ "original": "Fraíz de Arriba 2"
+ },
+ "latitude": 42.8950176416671,
+ "longitude": -8.61548602581024,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 263,
+ "name": {
+ "original": "Frei Rosendo Salvado"
+ },
+ "latitude": 42.873635806514,
+ "longitude": -8.55026543140411,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 264,
+ "name": {
+ "original": "Galeras (c. Domingo García Sabell)"
+ },
+ "latitude": 42.8826497249821,
+ "longitude": -8.54875266551971,
+ "lines": [
+ "9",
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 265,
+ "name": {
+ "original": "Galeras nº 16A"
+ },
+ "latitude": 42.880762925595,
+ "longitude": -8.54931056499481,
+ "lines": [
+ "9",
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 266,
+ "name": {
+ "original": "Galeras nº 38"
+ },
+ "latitude": 42.8826005903131,
+ "longitude": -8.54855552315712,
+ "lines": [
+ "9",
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 267,
+ "name": {
+ "original": "Galeras nº 5"
+ },
+ "latitude": 42.8814419834791,
+ "longitude": -8.54928910732269,
+ "lines": [
+ "9",
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 268,
+ "name": {
+ "original": "Garabal"
+ },
+ "latitude": 42.9173447491528,
+ "longitude": -8.51259380578995,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 269,
+ "name": {
+ "original": "García Prieto nº 18-22 (Doutor Maceira)"
+ },
+ "latitude": 42.8692836528179,
+ "longitude": -8.5532882809639,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 270,
+ "name": {
+ "original": "García Prieto nº 64"
+ },
+ "latitude": 42.8674328133373,
+ "longitude": -8.55422303080559,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 271,
+ "name": {
+ "original": "Grandeira"
+ },
+ "latitude": 42.8589858721714,
+ "longitude": -8.51852685213089,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 272,
+ "name": {
+ "original": "Grandeira - A Devesa"
+ },
+ "latitude": 42.8591077727096,
+ "longitude": -8.51865023374557,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 275,
+ "name": {
+ "original": "Gumersindo Busto Villanueva"
+ },
+ "latitude": 42.8940007499586,
+ "longitude": -8.54529529809952,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 276,
+ "name": {
+ "original": "Hórreo (Parlamento de Galicia)"
+ },
+ "latitude": 42.8726804819922,
+ "longitude": -8.54472666978836,
+ "lines": [
+ "6",
+ "12",
+ "C6",
+ "P3",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 277,
+ "name": {
+ "original": "Hórreo nº 23"
+ },
+ "latitude": 42.8753380559439,
+ "longitude": -8.54416072368622,
+ "lines": [
+ "6",
+ "7",
+ "12",
+ "C6",
+ "P3",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 278,
+ "name": {
+ "original": "Hospital Clínico"
+ },
+ "latitude": 42.8692620288852,
+ "longitude": -8.56517851352692,
+ "lines": [
+ "1",
+ "12",
+ "C2",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 279,
+ "name": {
+ "original": "Lavacolla"
+ },
+ "latitude": 42.8991999,
+ "longitude": -8.4444594,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 280,
+ "name": {
+ "original": "Hospital Provincial"
+ },
+ "latitude": 42.8603149682728,
+ "longitude": -8.551145195961,
+ "lines": [
+ "12",
+ "C2",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 281,
+ "name": {
+ "original": "N634 C. Lorenzo 1"
+ },
+ "latitude": 42.9011148,
+ "longitude": -8.4251011,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 282,
+ "name": {
+ "original": "Hotel Santiago Apóstol"
+ },
+ "latitude": 42.88880500677,
+ "longitude": -8.50286543369293,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 283,
+ "name": {
+ "original": "Ildefonso Sánchez Mera 1"
+ },
+ "latitude": 42.8646323670563,
+ "longitude": -8.56017619371414,
+ "lines": [
+ "12",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 284,
+ "name": {
+ "original": "Ildefonso Sánchez Mera 2"
+ },
+ "latitude": 42.8645556945746,
+ "longitude": -8.55978727340698,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 285,
+ "name": {
+ "original": "J. M. Suárez Núñez (fac. Física)"
+ },
+ "latitude": 42.8749567247023,
+ "longitude": -8.5594841837883,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 286,
+ "name": {
+ "original": "Lamas de Abade 1 (CIFP Compostela)"
+ },
+ "latitude": 42.8596897461557,
+ "longitude": -8.53559106588364,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 287,
+ "name": {
+ "original": "Lamas de Abade 2 (CIFP Compostela)"
+ },
+ "latitude": 42.8597192379072,
+ "longitude": -8.53569835424423,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 288,
+ "name": {
+ "original": "Lamas de Laraño"
+ },
+ "latitude": 42.8733674915522,
+ "longitude": -8.59328269958496,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 289,
+ "name": {
+ "original": "Lamas de Laraño 2"
+ },
+ "latitude": 42.8736269609844,
+ "longitude": -8.59426438808441,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 290,
+ "name": {
+ "original": "Lamas do Carballal"
+ },
+ "latitude": 42.9384718719319,
+ "longitude": -8.43036532402039,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 291,
+ "name": {
+ "original": "Laraño 1 (igrexa)"
+ },
+ "latitude": 42.8658296249934,
+ "longitude": -8.58379036188126,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 292,
+ "name": {
+ "original": "Laraño 2 (igrexa)"
+ },
+ "latitude": 42.8658866366969,
+ "longitude": -8.58369648456573,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 293,
+ "name": {
+ "original": "Lisboa (Área Central)"
+ },
+ "latitude": 42.8829268437822,
+ "longitude": -8.52954804897308,
+ "lines": [
+ "9",
+ "C11",
+ "C2",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 295,
+ "name": {
+ "original": "Lobío"
+ },
+ "latitude": 42.873806819837,
+ "longitude": -8.49924176931381,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 296,
+ "name": {
+ "original": "Londres (EGAP)"
+ },
+ "latitude": 42.881165840726,
+ "longitude": -8.52926641702652,
+ "lines": [
+ "9",
+ "C11",
+ "C2",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 297,
+ "name": {
+ "original": "Londres (Instituto)"
+ },
+ "latitude": 42.8810105713042,
+ "longitude": -8.5291363298893,
+ "lines": [
+ "9",
+ "C11",
+ "C4",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 298,
+ "name": {
+ "original": "Lugar da Lagoa (camping)"
+ },
+ "latitude": 42.8923137534952,
+ "longitude": -8.47645103931427,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 299,
+ "name": {
+ "original": "Lugar da Lagoa (camping) 2"
+ },
+ "latitude": 42.8922312201604,
+ "longitude": -8.4765100479126,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 300,
+ "name": {
+ "original": "Madrid nº 17"
+ },
+ "latitude": 42.8853422450116,
+ "longitude": -8.52621674537659,
+ "lines": [
+ "C11",
+ "C2",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 301,
+ "name": {
+ "original": "Mallou nº 38"
+ },
+ "latitude": 42.8952504927714,
+ "longitude": -8.52819889783859,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 302,
+ "name": {
+ "original": "Rúa de Mallou"
+ },
+ "latitude": 42.8969934094027,
+ "longitude": -8.52820426225662,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 303,
+ "name": {
+ "original": "Marrozos 1 (Pajuela)"
+ },
+ "latitude": 42.8362009927925,
+ "longitude": -8.51159870624542,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 304,
+ "name": {
+ "original": "Marrozos 2"
+ },
+ "latitude": 42.8399851252228,
+ "longitude": -8.51373374462128,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 305,
+ "name": {
+ "original": "Marrozos 3"
+ },
+ "latitude": 42.8398356524544,
+ "longitude": -8.51377665996552,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 306,
+ "name": {
+ "original": "Marrozos 4 (Pajuela)"
+ },
+ "latitude": 42.8357250096241,
+ "longitude": -8.51305782794952,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 307,
+ "name": {
+ "original": "Marzo de Arriba 1"
+ },
+ "latitude": 42.9393604,
+ "longitude": -8.5415885,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 308,
+ "name": {
+ "original": "Marzo de Arriba 2"
+ },
+ "latitude": 42.9398660169391,
+ "longitude": -8.54310393333435,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 309,
+ "name": {
+ "original": "Marzo de Arriba 3"
+ },
+ "latitude": 42.9398267456808,
+ "longitude": -8.54294836521149,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 310,
+ "name": {
+ "original": "Marzo de Arriba 4"
+ },
+ "latitude": 42.9396324,
+ "longitude": -8.5416609,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 311,
+ "name": {
+ "original": "Monte da Vila (c. Queiroal)"
+ },
+ "latitude": 42.9099045881962,
+ "longitude": -8.54698240756989,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 312,
+ "name": {
+ "original": "Monte da Vila (Queiroal)"
+ },
+ "latitude": 42.9100371929855,
+ "longitude": -8.54676514863968,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 313,
+ "name": {
+ "original": "Monte da Vila 1"
+ },
+ "latitude": 42.9154963336167,
+ "longitude": -8.54924350976944,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 314,
+ "name": {
+ "original": "Monte da Vila 2"
+ },
+ "latitude": 42.9128287031436,
+ "longitude": -8.54834765195847,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 315,
+ "name": {
+ "original": "Monte da Vila 3"
+ },
+ "latitude": 42.912720659712,
+ "longitude": -8.54825913906097,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 316,
+ "name": {
+ "original": "Monte da Vila 4"
+ },
+ "latitude": 42.9154020452593,
+ "longitude": -8.54907721281052,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 317,
+ "name": {
+ "original": "Miramontes 1"
+ },
+ "latitude": 42.9398719076257,
+ "longitude": -8.56202960014343,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 318,
+ "name": {
+ "original": "Miramontes 2"
+ },
+ "latitude": 42.9379259868365,
+ "longitude": -8.56172382831573,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 319,
+ "name": {
+ "original": "N634 C. Lorenzo"
+ },
+ "latitude": 42.9011392,
+ "longitude": -8.4250824,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 320,
+ "name": {
+ "original": "Monte do Gozo 1"
+ },
+ "latitude": 42.8798509518736,
+ "longitude": -8.50153774023056,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 321,
+ "name": {
+ "original": "AEROPORTO"
+ },
+ "latitude": 42.8919182,
+ "longitude": -8.4216896,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 322,
+ "name": {
+ "original": "Moscova"
+ },
+ "latitude": 42.8855260003065,
+ "longitude": -8.52433383464813,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 323,
+ "name": {
+ "original": "Xan Xordo"
+ },
+ "latitude": 42.8995235,
+ "longitude": -8.4568453,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 324,
+ "name": {
+ "original": "Multiusos Fontes do Sar T"
+ },
+ "latitude": 42.8755483768059,
+ "longitude": -8.52996110916138,
+ "lines": [
+ "9",
+ "C11",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 325,
+ "name": {
+ "original": "N-525 (cruce estrada San Xulián 1)"
+ },
+ "latitude": 42.8434150325534,
+ "longitude": -8.52147459983826,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 326,
+ "name": {
+ "original": "N-525 (cruce estrada San Xulián 2)"
+ },
+ "latitude": 42.8424838236769,
+ "longitude": -8.51917862892151,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 327,
+ "name": {
+ "original": "N-525 (El Aparcadero)"
+ },
+ "latitude": 42.8308272839275,
+ "longitude": -8.50070357322693,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 328,
+ "name": {
+ "original": "N-525 (km. 334)"
+ },
+ "latitude": 42.8311144705237,
+ "longitude": -8.50253820419312,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 329,
+ "name": {
+ "original": "O Bargo 1"
+ },
+ "latitude": 42.9291312680886,
+ "longitude": -8.5544416308403,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 330,
+ "name": {
+ "original": "O Bargo 2"
+ },
+ "latitude": 42.9267676635648,
+ "longitude": -8.55668663978577,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 331,
+ "name": {
+ "original": "O Bargo 3"
+ },
+ "latitude": 42.9268383668025,
+ "longitude": -8.55665981769562,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 332,
+ "name": {
+ "original": "O Bargo 4"
+ },
+ "latitude": 42.9291234124698,
+ "longitude": -8.55436116456985,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 333,
+ "name": {
+ "original": "O Barral"
+ },
+ "latitude": 42.9204305563203,
+ "longitude": -8.50842028856277,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 334,
+ "name": {
+ "original": "O Carballal - San Xulián"
+ },
+ "latitude": 42.9306346187067,
+ "longitude": -8.44040751457214,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 337,
+ "name": {
+ "original": "Vía Marconi"
+ },
+ "latitude": 42.914196,
+ "longitude": -8.5290645,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 338,
+ "name": {
+ "original": "Ponte do Romaño nº 52"
+ },
+ "latitude": 42.9060788,
+ "longitude": -8.5444828,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 339,
+ "name": {
+ "original": "Os Tilos (clínica Concheiros)"
+ },
+ "latitude": 42.8432183687011,
+ "longitude": -8.53507876396179,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 340,
+ "name": {
+ "original": "Os Tilos (Hotel Los Tilos)"
+ },
+ "latitude": 42.8463049356685,
+ "longitude": -8.54007840156555,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 341,
+ "name": {
+ "original": "Os Tilos (rotonda c. Cobas)"
+ },
+ "latitude": 42.840850486775,
+ "longitude": -8.53440284729004,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 342,
+ "name": {
+ "original": "Os Tilos (rúa Ameneiro 1)"
+ },
+ "latitude": 42.8463364003549,
+ "longitude": -8.54190766811371,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 343,
+ "name": {
+ "original": "Os Tilos (rúa Ameneiro 2)"
+ },
+ "latitude": 42.8437847589009,
+ "longitude": -8.54246556758881,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 344,
+ "name": {
+ "original": "Os Tilos (rúa Ameneiro 3 - Piscina)"
+ },
+ "latitude": 42.843223285305,
+ "longitude": -8.53980213403702,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 345,
+ "name": {
+ "original": "Os Tilos (rúa Carballo - Hotel)"
+ },
+ "latitude": 42.8462243073367,
+ "longitude": -8.53974312543869,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 346,
+ "name": {
+ "original": "Os Tilos (rúa Carballo c. rúa Sabugueiro)"
+ },
+ "latitude": 42.8414640994407,
+ "longitude": -8.5317850112915,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 347,
+ "name": {
+ "original": "Os Tilos (rúa Carballo c. rúa Texo)"
+ },
+ "latitude": 42.8415899679522,
+ "longitude": -8.53289544582367,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 348,
+ "name": {
+ "original": "Os Tilos (rúa Carballo nº 15)"
+ },
+ "latitude": 42.8450247026518,
+ "longitude": -8.53752493858337,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 349,
+ "name": {
+ "original": "Os Tilos (rúa Carballo) T"
+ },
+ "latitude": 42.8449539055818,
+ "longitude": -8.53755041956902,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 350,
+ "name": {
+ "original": "Os Tilos (rúa Castiñeiro - Centro comercial)"
+ },
+ "latitude": 42.8450089699766,
+ "longitude": -8.53991746902466,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 351,
+ "name": {
+ "original": "Os Tilos (rúa Vidueiro - Uceira)"
+ },
+ "latitude": 42.8399497238103,
+ "longitude": -8.53148460388184,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 352,
+ "name": {
+ "original": "Os Tilos (rúa Vidueiro 2)"
+ },
+ "latitude": 42.8400991963027,
+ "longitude": -8.53300809860229,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 353,
+ "name": {
+ "original": "Os Tilos (rúa Vidueiro c. Cerdeira)"
+ },
+ "latitude": 42.8436156290377,
+ "longitude": -8.53629648685455,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 354,
+ "name": {
+ "original": "Os Tilos (saída urbanización)"
+ },
+ "latitude": 42.8466372806084,
+ "longitude": -8.54196131229401,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 357,
+ "name": {
+ "original": "Outeiro do Castiñeiriño"
+ },
+ "latitude": 42.8500599361494,
+ "longitude": -8.54078382253647,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 358,
+ "name": {
+ "original": "Outeiro do Castiñeiriño nº 57"
+ },
+ "latitude": 42.8494493585253,
+ "longitude": -8.54085892438889,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 359,
+ "name": {
+ "original": "Outeiro do Castiñeiriño nº 70"
+ },
+ "latitude": 42.8479528770527,
+ "longitude": -8.5411325097084,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 360,
+ "name": {
+ "original": "París (Área Central)"
+ },
+ "latitude": 42.8819932825741,
+ "longitude": -8.52663516998291,
+ "lines": [
+ "C11",
+ "C4",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 361,
+ "name": {
+ "original": "París (c. Bruxelas)"
+ },
+ "latitude": 42.8837188856884,
+ "longitude": -8.52561324834824,
+ "lines": [
+ "C11",
+ "C4",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 362,
+ "name": {
+ "original": "Os Vilares 65b"
+ },
+ "latitude": 42.9090612,
+ "longitude": -8.5334771,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 363,
+ "name": {
+ "original": "París (c. Moscova)"
+ },
+ "latitude": 42.8853127655015,
+ "longitude": -8.52468252182007,
+ "lines": [
+ "C11",
+ "C4",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 364,
+ "name": {
+ "original": "París (Hotel Área Central)"
+ },
+ "latitude": 42.8820286598879,
+ "longitude": -8.52670222520828,
+ "lines": [
+ "C11",
+ "C2",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 365,
+ "name": {
+ "original": "París (parque)"
+ },
+ "latitude": 42.8862639639189,
+ "longitude": -8.52419167757034,
+ "lines": [
+ "C11",
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 366,
+ "name": {
+ "original": "Pastoriza nº 103A"
+ },
+ "latitude": 42.8877791691232,
+ "longitude": -8.53788435459137,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 367,
+ "name": {
+ "original": "Pastoriza nº 22"
+ },
+ "latitude": 42.8878695692948,
+ "longitude": -8.53741630911827,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "9",
+ "C6",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 368,
+ "name": {
+ "original": "Costa Aríns (c. Rego Miguel)"
+ },
+ "latitude": 42.8627178,
+ "longitude": -8.4929845,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 369,
+ "name": {
+ "original": "Paxonal (rot. rúa Canfranc)"
+ },
+ "latitude": 42.8658394546012,
+ "longitude": -8.54351833462715,
+ "lines": [
+ "6",
+ "12",
+ "C6",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 370,
+ "name": {
+ "original": "Paxonal nº 29-31"
+ },
+ "latitude": 42.8643128977544,
+ "longitude": -8.54273244738579,
+ "lines": [
+ "6",
+ "12",
+ "C6",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 371,
+ "name": {
+ "original": "Paxonal nº 63"
+ },
+ "latitude": 42.8624353678347,
+ "longitude": -8.54145169258118,
+ "lines": [
+ "6",
+ "12",
+ "C6",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 372,
+ "name": {
+ "original": "Peregrina 1"
+ },
+ "latitude": 42.9212869337141,
+ "longitude": -8.55317026376724,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 373,
+ "name": {
+ "original": "Peregrina 2"
+ },
+ "latitude": 42.9211572993685,
+ "longitude": -8.55308175086975,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 374,
+ "name": {
+ "original": "Picaños nº 55"
+ },
+ "latitude": 42.8692177980902,
+ "longitude": -8.53618651628494,
+ "lines": [
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 375,
+ "name": {
+ "original": "Picaños nº 59"
+ },
+ "latitude": 42.8691519432923,
+ "longitude": -8.53681415319443,
+ "lines": [
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 376,
+ "name": {
+ "original": "Picaños nº 7"
+ },
+ "latitude": 42.869305276743,
+ "longitude": -8.53386640548706,
+ "lines": [
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 377,
+ "name": {
+ "original": "Picaños nº 8"
+ },
+ "latitude": 42.8693799775169,
+ "longitude": -8.53398576378822,
+ "lines": [
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 378,
+ "name": {
+ "original": "Piñeiro (rúa do Padronés nº 2)"
+ },
+ "latitude": 42.8499527659564,
+ "longitude": -8.52495610713959,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 379,
+ "name": {
+ "original": "Piñeiro (rúa do Padronés nº 25)"
+ },
+ "latitude": 42.848843691022,
+ "longitude": -8.52467447519302,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 380,
+ "name": {
+ "original": "Piñeiro da Enfesta 1"
+ },
+ "latitude": 42.9355067543553,
+ "longitude": -8.45330893993378,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 381,
+ "name": {
+ "original": "Piñeiro da Enfesta 2"
+ },
+ "latitude": 42.935011899639,
+ "longitude": -8.4587699174881,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 382,
+ "name": {
+ "original": "Piñeiro da Enfesta 3"
+ },
+ "latitude": 42.9346466471787,
+ "longitude": -8.46262693405151,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 383,
+ "name": {
+ "original": "Piscinas Fontes do Sar"
+ },
+ "latitude": 42.8775906140712,
+ "longitude": -8.5285422205925,
+ "lines": [
+ "9",
+ "C11",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 384,
+ "name": {
+ "original": "Ponte da Asén"
+ },
+ "latitude": 42.8849393571552,
+ "longitude": -8.54998379945755,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 385,
+ "name": {
+ "original": "Ponte de San Lázaro"
+ },
+ "latitude": 42.8866137811356,
+ "longitude": -8.50848734378815,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 386,
+ "name": {
+ "original": "Ponte de Sar nº 55"
+ },
+ "latitude": 42.8705132557995,
+ "longitude": -8.53400856256485,
+ "lines": [
+ "7",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 387,
+ "name": {
+ "original": "Ponte de Sar nº 22"
+ },
+ "latitude": 42.8716622391638,
+ "longitude": -8.5352236032486,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 388,
+ "name": {
+ "original": "Ponte de Sar nº 41"
+ },
+ "latitude": 42.8717389028187,
+ "longitude": -8.53525578975677,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 389,
+ "name": {
+ "original": "Ponte de Sar nº 46"
+ },
+ "latitude": 42.8705083413679,
+ "longitude": -8.53404343128204,
+ "lines": [
+ "7",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 390,
+ "name": {
+ "original": "Ponte do Romaño (c. rúa Romaño)"
+ },
+ "latitude": 42.9045972156611,
+ "longitude": -8.54521885514259,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 391,
+ "name": {
+ "original": "Ponte do Romaño (sanatorio)"
+ },
+ "latitude": 42.9024193220275,
+ "longitude": -8.54612544178963,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 392,
+ "name": {
+ "original": "Ponte do Romaño 1 (c. rúa Romaño)"
+ },
+ "latitude": 42.9043280530009,
+ "longitude": -8.54542806744576,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 393,
+ "name": {
+ "original": "Ponte do Romaño 2"
+ },
+ "latitude": 42.9025558724231,
+ "longitude": -8.54616835713387,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 394,
+ "name": {
+ "original": "Ponte Marzán"
+ },
+ "latitude": 42.863370207932,
+ "longitude": -8.5210508108139,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 395,
+ "name": {
+ "original": "Ponte Marzán (dir. Aríns)"
+ },
+ "latitude": 42.863061545154,
+ "longitude": -8.52110981941223,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 396,
+ "name": {
+ "original": "Ponte San Lázaro"
+ },
+ "latitude": 42.8865371359601,
+ "longitude": -8.50895941257477,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 397,
+ "name": {
+ "original": "Porta do Camiño"
+ },
+ "latitude": 42.8818950121514,
+ "longitude": -8.53975385427475,
+ "lines": [
+ "C11",
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 398,
+ "name": {
+ "original": "Porto de Amio nº 8"
+ },
+ "latitude": 42.8909489916649,
+ "longitude": -8.51298540830612,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 399,
+ "name": {
+ "original": "Porto do Medio"
+ },
+ "latitude": 42.8944517213941,
+ "longitude": -8.51784020662308,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 400,
+ "name": {
+ "original": "Pousada 1"
+ },
+ "latitude": 42.8805221579803,
+ "longitude": -8.48345696926117,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 401,
+ "name": {
+ "original": "Pousada 2"
+ },
+ "latitude": 42.8805899660975,
+ "longitude": -8.48354011774063,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 402,
+ "name": {
+ "original": "Poza de Bar (colexio Pío XII)"
+ },
+ "latitude": 42.8796819207807,
+ "longitude": -8.55218589305878,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 403,
+ "name": {
+ "original": "Poza Real Abaixo"
+ },
+ "latitude": 42.8596582882718,
+ "longitude": -8.56955587863922,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 404,
+ "name": {
+ "original": "Poza Real Abaixo (Sta. Apolonia)"
+ },
+ "latitude": 42.8602087989256,
+ "longitude": -8.56697022914886,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 405,
+ "name": {
+ "original": "Poza Real de Abaixo"
+ },
+ "latitude": 42.8596769663923,
+ "longitude": -8.5694432258606,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 406,
+ "name": {
+ "original": "Poza Real de Abaixo (Sta. Apolonia)"
+ },
+ "latitude": 42.8601802904587,
+ "longitude": -8.56705605983734,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 407,
+ "name": {
+ "original": "Poza Real de Arriba"
+ },
+ "latitude": 42.8579280799769,
+ "longitude": -8.57079237699509,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 408,
+ "name": {
+ "original": "Poza Real de Arriba T"
+ },
+ "latitude": 42.8581040522398,
+ "longitude": -8.57077896595001,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 409,
+ "name": {
+ "original": "Praza de Galicia"
+ },
+ "latitude": 42.8761734383148,
+ "longitude": -8.54421705007553,
+ "lines": [
+ "C11",
+ "13",
+ "15",
+ "P6",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 410,
+ "name": {
+ "original": "Praza de Galicia nº 3"
+ },
+ "latitude": 42.876415205691,
+ "longitude": -8.54457378387451,
+ "lines": [
+ "5",
+ "6",
+ "7",
+ "12",
+ "13",
+ "15",
+ "C5",
+ "P3",
+ "P4",
+ "P6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 411,
+ "name": {
+ "original": "CDC 1"
+ },
+ "latitude": 42.8709921,
+ "longitude": -8.5230802,
+ "lines": [
+ "9"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 412,
+ "name": {
+ "original": "Psiquiátrico de Conxo"
+ },
+ "latitude": 42.8631952336804,
+ "longitude": -8.55606704950333,
+ "lines": [
+ "12",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 413,
+ "name": {
+ "original": "Quintáns"
+ },
+ "latitude": 42.9221560660313,
+ "longitude": -8.43628227710724,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 414,
+ "name": {
+ "original": "Quintáns de Villestro"
+ },
+ "latitude": 42.8823500028928,
+ "longitude": -8.60682785511017,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 415,
+ "name": {
+ "original": "Quintáns de Villestro 2"
+ },
+ "latitude": 42.8825150958959,
+ "longitude": -8.60679030418396,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 416,
+ "name": {
+ "original": "Quiroga Palacios nº 10"
+ },
+ "latitude": 42.8779778256415,
+ "longitude": -8.53529065847397,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 417,
+ "name": {
+ "original": "Quiroga Palacios nº 54"
+ },
+ "latitude": 42.879615094407,
+ "longitude": -8.53352710604668,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 420,
+ "name": {
+ "original": "Raiola (IES Lamas de Abade)"
+ },
+ "latitude": 42.8627096283842,
+ "longitude": -8.53654325008392,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 421,
+ "name": {
+ "original": "Ramón Baltar 1"
+ },
+ "latitude": 42.8632699418485,
+ "longitude": -8.55514705181122,
+ "lines": [
+ "12",
+ "C2",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 422,
+ "name": {
+ "original": "Ramón Baltar 2"
+ },
+ "latitude": 42.8623459134135,
+ "longitude": -8.55326414108276,
+ "lines": [
+ "12",
+ "C2",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 423,
+ "name": {
+ "original": "Ramón Baltar 3"
+ },
+ "latitude": 42.8624029283343,
+ "longitude": -8.55315417051315,
+ "lines": [
+ "12",
+ "C2",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 424,
+ "name": {
+ "original": "Ramón Baltar 4"
+ },
+ "latitude": 42.8632109617233,
+ "longitude": -8.55504512786865,
+ "lines": [
+ "12",
+ "C2",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 425,
+ "name": {
+ "original": "Rebordaos"
+ },
+ "latitude": 42.9208283018883,
+ "longitude": -8.53107824921608,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 426,
+ "name": {
+ "original": "Reboredo"
+ },
+ "latitude": 42.9091050243838,
+ "longitude": -8.47331821918488,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 427,
+ "name": {
+ "original": "Reborido"
+ },
+ "latitude": 42.9057691401155,
+ "longitude": -8.61726701259613,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 428,
+ "name": {
+ "original": "Mourentán Correos"
+ },
+ "latitude": 42.9007945,
+ "longitude": -8.4304579,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 429,
+ "name": {
+ "original": "Recinto Feiral de Amio"
+ },
+ "latitude": 42.9017994383715,
+ "longitude": -8.51267963647842,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 430,
+ "name": {
+ "original": "Rúa de Amio nº 114"
+ },
+ "latitude": 42.8997396,
+ "longitude": -8.51166,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 431,
+ "name": {
+ "original": "Rep. Arxentina nº 26"
+ },
+ "latitude": 42.8728986746984,
+ "longitude": -8.54786485433578,
+ "lines": [
+ "15",
+ "C4",
+ "P6",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 432,
+ "name": {
+ "original": "Rep. Arxentina nº 43"
+ },
+ "latitude": 42.8718892812498,
+ "longitude": -8.5507133603096,
+ "lines": [
+ "15",
+ "C4",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 433,
+ "name": {
+ "original": "República do Salvador"
+ },
+ "latitude": 42.8745282156502,
+ "longitude": -8.54692339897156,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 434,
+ "name": {
+ "original": "Requesende 1"
+ },
+ "latitude": 42.9165501926268,
+ "longitude": -8.43435645103455,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 435,
+ "name": {
+ "original": "Requesende 2"
+ },
+ "latitude": 42.912817898809,
+ "longitude": -8.43335330486298,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 436,
+ "name": {
+ "original": "Requesende 3"
+ },
+ "latitude": 42.9131341703664,
+ "longitude": -8.43347400426865,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 437,
+ "name": {
+ "original": "Restollal (Centro comercial)"
+ },
+ "latitude": 42.8621493098346,
+ "longitude": -8.54171723127365,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 439,
+ "name": {
+ "original": "Roberto Vidal Bolaño"
+ },
+ "latitude": 42.8949537793963,
+ "longitude": -8.5469126701355,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 441,
+ "name": {
+ "original": "Rocha Vella"
+ },
+ "latitude": 42.8599551714127,
+ "longitude": -8.57653766870499,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 442,
+ "name": {
+ "original": "Avda. Barcelona nº 23"
+ },
+ "latitude": 42.8711108477636,
+ "longitude": -8.5602942109108,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 443,
+ "name": {
+ "original": "Roma 1"
+ },
+ "latitude": 42.8860635059681,
+ "longitude": -8.52162212133408,
+ "lines": [
+ "C11",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 444,
+ "name": {
+ "original": "Roma 2"
+ },
+ "latitude": 42.8863032693231,
+ "longitude": -8.5216811299324,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 445,
+ "name": {
+ "original": "Romaño"
+ },
+ "latitude": 42.9057190415377,
+ "longitude": -8.54469984769821,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 446,
+ "name": {
+ "original": "Peregrina 3"
+ },
+ "latitude": 42.9224156,
+ "longitude": -8.5538677,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 447,
+ "name": {
+ "original": "Rosalía de Castro (hotel Peregrino)"
+ },
+ "latitude": 42.8718430866073,
+ "longitude": -8.55578005313873,
+ "lines": [
+ "1",
+ "C2",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 448,
+ "name": {
+ "original": "Rosalía de Castro nº 126"
+ },
+ "latitude": 42.8724996370025,
+ "longitude": -8.55437457561493,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 449,
+ "name": {
+ "original": "Rosalía de Castro nº 158"
+ },
+ "latitude": 42.8717674059482,
+ "longitude": -8.55613946914673,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 450,
+ "name": {
+ "original": "Rosalía de Castro nº 87"
+ },
+ "latitude": 42.873331126431,
+ "longitude": -8.55310052633286,
+ "lines": [
+ "1",
+ "12",
+ "C2",
+ "P2",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 451,
+ "name": {
+ "original": "Rosalía de Castro nº 96"
+ },
+ "latitude": 42.8736476005515,
+ "longitude": -8.55279207229614,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 452,
+ "name": {
+ "original": "Rotonda da Cantaleta"
+ },
+ "latitude": 42.8669246336791,
+ "longitude": -8.57162654399872,
+ "lines": [
+ "12",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 453,
+ "name": {
+ "original": "Roxos (almacén)"
+ },
+ "latitude": 42.8760211047255,
+ "longitude": -8.61200451850891,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 454,
+ "name": {
+ "original": "Roxos (igrexa)"
+ },
+ "latitude": 42.8767405090804,
+ "longitude": -8.6089950799942,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 455,
+ "name": {
+ "original": "Roxos (rúa de Muros - Invernadoiro)"
+ },
+ "latitude": 42.8757773702005,
+ "longitude": -8.60429048538208,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 456,
+ "name": {
+ "original": "Roxos (rúa de Muros nº 113)"
+ },
+ "latitude": 42.8758953063812,
+ "longitude": -8.61210107803345,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 457,
+ "name": {
+ "original": "Roxos (rúa de Muros nº 19)"
+ },
+ "latitude": 42.8737095192113,
+ "longitude": -8.59866857528687,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 458,
+ "name": {
+ "original": "Roxos (rúa de Muros nº 19A)"
+ },
+ "latitude": 42.8736387550236,
+ "longitude": -8.59900116920471,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 459,
+ "name": {
+ "original": "Roxos (rúa de Muros nº 57)"
+ },
+ "latitude": 42.8760840038015,
+ "longitude": -8.60525608062744,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 460,
+ "name": {
+ "original": "Roxos (rúa de Muros nº 57C)"
+ },
+ "latitude": 42.8760368295005,
+ "longitude": -8.60549211502075,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 461,
+ "name": {
+ "original": "Ulpiano Villanueva"
+ },
+ "latitude": 42.8928212,
+ "longitude": -8.5430896,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 462,
+ "name": {
+ "original": "Curros Enríquez (c. Castrón Douro)"
+ },
+ "latitude": 42.8758274931048,
+ "longitude": -8.54026615619659,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 463,
+ "name": {
+ "original": "Rúa da Choupana nº 22"
+ },
+ "latitude": 42.8680727009214,
+ "longitude": -8.56163531541824,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 464,
+ "name": {
+ "original": "Rúa da Estrada (fr. nº 28)"
+ },
+ "latitude": 42.8650137620885,
+ "longitude": -8.54052633047104,
+ "lines": [
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 465,
+ "name": {
+ "original": "Rúa da Estrada (fr. nº 74)"
+ },
+ "latitude": 42.8629484994829,
+ "longitude": -8.54081466794014,
+ "lines": [
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 466,
+ "name": {
+ "original": "Rúa da Estrada nº 28"
+ },
+ "latitude": 42.8650353875094,
+ "longitude": -8.54057997465134,
+ "lines": [
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 467,
+ "name": {
+ "original": "Rúa da Estrada nº 4"
+ },
+ "latitude": 42.8667752260979,
+ "longitude": -8.54011595249176,
+ "lines": [
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 468,
+ "name": {
+ "original": "Rúa da Estrada nº 76"
+ },
+ "latitude": 42.8631500155348,
+ "longitude": -8.54083746671677,
+ "lines": [
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 469,
+ "name": {
+ "original": "Rúa da Mariñeira"
+ },
+ "latitude": 42.8928963963954,
+ "longitude": -8.5101529955864,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 470,
+ "name": {
+ "original": "Rúa da Mira 1"
+ },
+ "latitude": 42.8941736718574,
+ "longitude": -8.51474091410637,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 471,
+ "name": {
+ "original": "Rúa da Mira 2"
+ },
+ "latitude": 42.8934623309409,
+ "longitude": -8.51231753826141,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 472,
+ "name": {
+ "original": "Rúa da Mira 3"
+ },
+ "latitude": 42.8932589488114,
+ "longitude": -8.51010873913765,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 473,
+ "name": {
+ "original": "Rúa da Muiña (Centro Sociocultural)"
+ },
+ "latitude": 42.8897836635656,
+ "longitude": -8.51528137922287,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 474,
+ "name": {
+ "original": "Rúa da Muiña nº 19"
+ },
+ "latitude": 42.8877830995682,
+ "longitude": -8.51663321256638,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 475,
+ "name": {
+ "original": "Rúa da Muiña nº 4"
+ },
+ "latitude": 42.886767071201,
+ "longitude": -8.51697117090225,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 476,
+ "name": {
+ "original": "Rúa da Muiña nº 40"
+ },
+ "latitude": 42.8884591323817,
+ "longitude": -8.51600557565689,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 477,
+ "name": {
+ "original": "Rúa da Ponte Vella"
+ },
+ "latitude": 42.8668853159297,
+ "longitude": -8.57562571763992,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 478,
+ "name": {
+ "original": "Rúa da Ponte Vella (Vidán)"
+ },
+ "latitude": 42.8669541219748,
+ "longitude": -8.57560962438583,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 479,
+ "name": {
+ "original": "Rúa da Rosa"
+ },
+ "latitude": 42.8730303762288,
+ "longitude": -8.54639500379562,
+ "lines": [
+ "6",
+ "12",
+ "15",
+ "C4",
+ "C5",
+ "P3",
+ "P6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 480,
+ "name": {
+ "original": "Rúa da Torreira 1"
+ },
+ "latitude": 42.900751221559,
+ "longitude": -8.54691535234451,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 481,
+ "name": {
+ "original": "Rúa da Torreira 2 (Viqueira)"
+ },
+ "latitude": 42.8990369016756,
+ "longitude": -8.54706823825836,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 482,
+ "name": {
+ "original": "Rúa da Torreira 3"
+ },
+ "latitude": 42.8971790949113,
+ "longitude": -8.54723319411278,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 483,
+ "name": {
+ "original": "Rúa da Torreira nº 2"
+ },
+ "latitude": 42.8972144635162,
+ "longitude": -8.54710981249809,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 484,
+ "name": {
+ "original": "Rúa da Torreira nº 31"
+ },
+ "latitude": 42.8993335954043,
+ "longitude": -8.54693815112114,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 485,
+ "name": {
+ "original": "Rúa da Torreira nº 53"
+ },
+ "latitude": 42.9006146671665,
+ "longitude": -8.54682683944702,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 486,
+ "name": {
+ "original": "Rúa das Cancelas (c. Camping)"
+ },
+ "latitude": 42.8908625262553,
+ "longitude": -8.52732181549072,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 487,
+ "name": {
+ "original": "Rúa das Cancelas (campo de fútbol)"
+ },
+ "latitude": 42.8911219221206,
+ "longitude": -8.52680683135986,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 488,
+ "name": {
+ "original": "Rúa das Cancelas (costa 1)"
+ },
+ "latitude": 42.8902042060933,
+ "longitude": -8.53102058172226,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 489,
+ "name": {
+ "original": "Rúa das Cancelas (costa)"
+ },
+ "latitude": 42.8903063935642,
+ "longitude": -8.53104203939438,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 490,
+ "name": {
+ "original": "Rúa das Cancelas nº 47"
+ },
+ "latitude": 42.8899860745794,
+ "longitude": -8.5297679901123,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 491,
+ "name": {
+ "original": "Rúa das Cancelas nº 54"
+ },
+ "latitude": 42.8899782139699,
+ "longitude": -8.52959632873535,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 492,
+ "name": {
+ "original": "Rúa das Fontes do Sar"
+ },
+ "latitude": 42.8798470209232,
+ "longitude": -8.52924227714539,
+ "lines": [
+ "9",
+ "C11",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 493,
+ "name": {
+ "original": "Rúa das Fontes do Sar (piscinas)"
+ },
+ "latitude": 42.8775178887844,
+ "longitude": -8.52857172489166,
+ "lines": [
+ "9",
+ "C11",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 494,
+ "name": {
+ "original": "Rúa das Fontes do Sar nº 4"
+ },
+ "latitude": 42.8798254006916,
+ "longitude": -8.52943539619446,
+ "lines": [
+ "9",
+ "C11",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 495,
+ "name": {
+ "original": "Rúa das Fontiñas (CEIP Monte dos Postes 1)"
+ },
+ "latitude": 42.8868053936578,
+ "longitude": -8.52655336260796,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 496,
+ "name": {
+ "original": "Rúa das Fontiñas (CEIP Monte dos Postes 2)"
+ },
+ "latitude": 42.8867316966043,
+ "longitude": -8.52653056383133,
+ "lines": [
+ "6",
+ "C11",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 497,
+ "name": {
+ "original": "San Pedro (igrexa)"
+ },
+ "latitude": 42.88120220123036,
+ "longitude": -8.537885695695877,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 498,
+ "name": {
+ "original": "Calzada de San Pedro (Don Bosco)"
+ },
+ "latitude": 42.880141841507445,
+ "longitude": -8.537350594997406,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 499,
+ "name": {
+ "original": "Rúa de Belvís (convento)"
+ },
+ "latitude": 42.8783670003044,
+ "longitude": -8.537628203630447,
+ "lines": [
+ "13"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 500,
+ "name": {
+ "original": "Romaño T"
+ },
+ "latitude": 42.9084413,
+ "longitude": -8.5458093,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 501,
+ "name": {
+ "original": "Rúa das Mulas (c. rúa do Tambre)"
+ },
+ "latitude": 42.9047583197569,
+ "longitude": -8.52722257375717,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 502,
+ "name": {
+ "original": "Coto dos Olmos"
+ },
+ "latitude": 42.8857317,
+ "longitude": -8.4806001,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 503,
+ "name": {
+ "original": "TVG (dir. Vilamaior)"
+ },
+ "latitude": 42.8915889,
+ "longitude": -8.4712096,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 504,
+ "name": {
+ "original": "TVG (dir. Santiago)"
+ },
+ "latitude": 42.8915094,
+ "longitude": -8.4704747,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 505,
+ "name": {
+ "original": "Aldea de Abaixo 2"
+ },
+ "latitude": 42.9235371,
+ "longitude": -8.4649203,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 506,
+ "name": {
+ "original": "Rúa de Amio"
+ },
+ "latitude": 42.8935016317581,
+ "longitude": -8.5086777806282,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 507,
+ "name": {
+ "original": "Rúa de Amio nº 48"
+ },
+ "latitude": 42.8933955194941,
+ "longitude": -8.50862681865692,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 508,
+ "name": {
+ "original": "N634 H. Garcas 1"
+ },
+ "latitude": 42.9000728,
+ "longitude": -8.4371288,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 509,
+ "name": {
+ "original": "Rúa de Boiro"
+ },
+ "latitude": 42.8937502088471,
+ "longitude": -8.54542806744576,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 510,
+ "name": {
+ "original": "Rúa de Boisaca"
+ },
+ "latitude": 42.9064420288326,
+ "longitude": -8.51497560739517,
+ "lines": [
+ "1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 511,
+ "name": {
+ "original": "Rúa de San Pedro nº 58"
+ },
+ "latitude": 42.8813191443288,
+ "longitude": -8.53779315948486,
+ "lines": [
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 512,
+ "name": {
+ "original": "Rúa de Sandino nº 57"
+ },
+ "latitude": 42.865493451464,
+ "longitude": -8.52696776390076,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 513,
+ "name": {
+ "original": "Rúa de Sandino nº 134 (Cima da Vila)"
+ },
+ "latitude": 42.8641703647634,
+ "longitude": -8.52420508861542,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 514,
+ "name": {
+ "original": "Rúa de Sandino nº 62A"
+ },
+ "latitude": 42.8654678943372,
+ "longitude": -8.52710455656052,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 515,
+ "name": {
+ "original": "Rúa de Sar de Afora nº 18"
+ },
+ "latitude": 42.8747424705482,
+ "longitude": -8.53887408971786,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 516,
+ "name": {
+ "original": "Rúa de Sar de Afora nº 90"
+ },
+ "latitude": 42.8747975083836,
+ "longitude": -8.53894919157028,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 517,
+ "name": {
+ "original": "Rúa de Senande"
+ },
+ "latitude": 42.87659014247,
+ "longitude": -8.5018327832222,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 518,
+ "name": {
+ "original": "Rúa do Avío nº 20"
+ },
+ "latitude": 42.8945961494574,
+ "longitude": -8.54735121130943,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 519,
+ "name": {
+ "original": "Rúa do Avío nº 23"
+ },
+ "latitude": 42.8951276811171,
+ "longitude": -8.54741960763931,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 520,
+ "name": {
+ "original": "Rúa do Ceo (c. rúa Pequena)"
+ },
+ "latitude": 42.8925957415558,
+ "longitude": -8.52915644645691,
+ "lines": [
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 521,
+ "name": {
+ "original": "Rúa do Churruchao"
+ },
+ "latitude": 42.859456760823,
+ "longitude": -8.57346788048744,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 522,
+ "name": {
+ "original": "Rúa do Churruchao (Rocha Vella)"
+ },
+ "latitude": 42.859548185552,
+ "longitude": -8.57371598482132,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 523,
+ "name": {
+ "original": "Rúa do Cruceiro de Sar (c. Picaños)"
+ },
+ "latitude": 42.8695627974506,
+ "longitude": -8.53311002254486,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 524,
+ "name": {
+ "original": "Rúa do Cruceiro de Sar (fr. nº 38)"
+ },
+ "latitude": 42.868208344442,
+ "longitude": -8.53240728378296,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 525,
+ "name": {
+ "original": "Rúa do Cruceiro de Sar nº 38"
+ },
+ "latitude": 42.8680333839032,
+ "longitude": -8.53228390216827,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 526,
+ "name": {
+ "original": "Rúa do Cruceiro de Sar nº 4 (c. Picaños)"
+ },
+ "latitude": 42.8692541656351,
+ "longitude": -8.53323072195053,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 527,
+ "name": {
+ "original": "Rúa do Cubelo (praza)"
+ },
+ "latitude": 42.8894554811899,
+ "longitude": -8.51588487625122,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 528,
+ "name": {
+ "original": "Rúa do Cubelo nº 67"
+ },
+ "latitude": 42.8914098109515,
+ "longitude": -8.51842895150185,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 529,
+ "name": {
+ "original": "Rúa do Nabal"
+ },
+ "latitude": 42.8793468054426,
+ "longitude": -8.60757887363434,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 530,
+ "name": {
+ "original": "Rúa do Nabal 2"
+ },
+ "latitude": 42.8795325440806,
+ "longitude": -8.60755205154419,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 531,
+ "name": {
+ "original": "Rúa do Río nº 60"
+ },
+ "latitude": 42.9010223646363,
+ "longitude": -8.53274926543236,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 532,
+ "name": {
+ "original": "Rúa do Tambre (c. Cañoteira)"
+ },
+ "latitude": 42.9030981415123,
+ "longitude": -8.52768927812576,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 533,
+ "name": {
+ "original": "Avda. Rodríguez Viguri"
+ },
+ "latitude": 42.8878404,
+ "longitude": -8.5328595,
+ "lines": [
+ "6",
+ "9",
+ "C6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 534,
+ "name": {
+ "original": "Rúa do Tambre nº 175"
+ },
+ "latitude": 42.909294,
+ "longitude": -8.528107,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 535,
+ "name": {
+ "original": "Avda. Rodríguez de Viguri (c. Concheiros)"
+ },
+ "latitude": 42.8851615,
+ "longitude": -8.5337035,
+ "lines": [
+ "9",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 536,
+ "name": {
+ "original": "Rúa do Tambre nº 61"
+ },
+ "latitude": 42.9006608402683,
+ "longitude": -8.52884531021118,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 538,
+ "name": {
+ "original": "Garabal (cruce)"
+ },
+ "latitude": 42.9164167,
+ "longitude": -8.5154668,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 539,
+ "name": {
+ "original": "Rúa San Martiño"
+ },
+ "latitude": 42.8630812052495,
+ "longitude": -8.50446671247482,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 540,
+ "name": {
+ "original": "Rúa San Martiño (c. Agra das Lamas)"
+ },
+ "latitude": 42.876382773537,
+ "longitude": -8.49799990653992,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 541,
+ "name": {
+ "original": "Rúa San Martiño 1"
+ },
+ "latitude": 42.863091035295,
+ "longitude": -8.50438892841339,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 542,
+ "name": {
+ "original": "Rúa Volta do Castro (centro comercial)"
+ },
+ "latitude": 42.8659849326138,
+ "longitude": -8.56477349996567,
+ "lines": [
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 543,
+ "name": {
+ "original": "Rúa Volta do Castro nº 35"
+ },
+ "latitude": 42.8659888644473,
+ "longitude": -8.56465011835098,
+ "lines": [
+ "12",
+ "C4",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 544,
+ "name": {
+ "original": "Salgueiriños (aparcadoiro)"
+ },
+ "latitude": 42.8935841633929,
+ "longitude": -8.53251188993454,
+ "lines": [
+ "1",
+ "P4",
+ "P6",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 545,
+ "name": {
+ "original": "Cruceiro da Coruña nº 24"
+ },
+ "latitude": 42.8938022821815,
+ "longitude": -8.53197276592255,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 546,
+ "name": {
+ "original": "Cruceiro da Coruña nº 52"
+ },
+ "latitude": 42.8956562607381,
+ "longitude": -8.53063032031059,
+ "lines": [
+ "1",
+ "P4",
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 547,
+ "name": {
+ "original": "Salvadas (SGAE)"
+ },
+ "latitude": 42.8869066041344,
+ "longitude": -8.54755908250809,
+ "lines": [
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 548,
+ "name": {
+ "original": "Salvadas nº 17"
+ },
+ "latitude": 42.886767071201,
+ "longitude": -8.54772001504898,
+ "lines": [
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 549,
+ "name": {
+ "original": "Salvadas nº 47"
+ },
+ "latitude": 42.8887755289148,
+ "longitude": -8.54692071676254,
+ "lines": [
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 550,
+ "name": {
+ "original": "Vista Alegre nº 61"
+ },
+ "latitude": 42.8892393122042,
+ "longitude": -8.54693681001663,
+ "lines": [
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 551,
+ "name": {
+ "original": "San Caetano (igrexa)"
+ },
+ "latitude": 42.8901138093433,
+ "longitude": -8.534936606884,
+ "lines": [
+ "1",
+ "C2",
+ "P4",
+ "P6",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 552,
+ "name": {
+ "original": "San Caetano (parque)"
+ },
+ "latitude": 42.8901668683213,
+ "longitude": -8.5350438952446,
+ "lines": [
+ "1",
+ "6",
+ "P4",
+ "P6",
+ "6A",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 553,
+ "name": {
+ "original": "San Clemente (Alameda)"
+ },
+ "latitude": 42.8774520428427,
+ "longitude": -8.54674369096756,
+ "lines": [
+ "9",
+ "C4",
+ "P1",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 554,
+ "name": {
+ "original": "San Clemente (IES Rosalía de Castro)"
+ },
+ "latitude": 42.8774962677367,
+ "longitude": -8.54650095105171,
+ "lines": [
+ "8",
+ "9",
+ "C2",
+ "P1",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 555,
+ "name": {
+ "original": "San Cristovo (igrexa)"
+ },
+ "latitude": 42.9321055297788,
+ "longitude": -8.46337258815765,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 557,
+ "name": {
+ "original": "San Domingos de Bonaval"
+ },
+ "latitude": 42.8821269300976,
+ "longitude": -8.53940784931183,
+ "lines": [
+ "9",
+ "13",
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 558,
+ "name": {
+ "original": "San Lázaro (igrexa)"
+ },
+ "latitude": 42.8867464360221,
+ "longitude": -8.52019250392914,
+ "lines": [
+ "6",
+ "C5",
+ "C6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 559,
+ "name": {
+ "original": "San Lázaro (Museo Pedagóxico)"
+ },
+ "latitude": 42.8864624559539,
+ "longitude": -8.51433724164963,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 560,
+ "name": {
+ "original": "San Lázaro (Palacio de Congresos)"
+ },
+ "latitude": 42.8864310117137,
+ "longitude": -8.51342797279358,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 561,
+ "name": {
+ "original": "San Lázaro nº 61"
+ },
+ "latitude": 42.8866678257534,
+ "longitude": -8.51889163255692,
+ "lines": [
+ "6",
+ "C5",
+ "C6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 562,
+ "name": {
+ "original": "San Lázaro nº 82"
+ },
+ "latitude": 42.8863740189875,
+ "longitude": -8.51568102836609,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 563,
+ "name": {
+ "original": "San Lourenzo (c. Campus - J.M. Suárez Núñez)"
+ },
+ "latitude": 42.8778628417486,
+ "longitude": -8.5604926943779,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 564,
+ "name": {
+ "original": "San Lourenzo (c. J.M. Suárez Núñez- Campus)"
+ },
+ "latitude": 42.8780230329253,
+ "longitude": -8.56035456061363,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 565,
+ "name": {
+ "original": "San Lourenzo (carballeira)"
+ },
+ "latitude": 42.8783709313491,
+ "longitude": -8.55578273534775,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 566,
+ "name": {
+ "original": "San Lourenzo (dir. Vidán)"
+ },
+ "latitude": 42.8785674832637,
+ "longitude": -8.55530261993408,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 567,
+ "name": {
+ "original": "San Lourenzo (estrada dir. Vidán)"
+ },
+ "latitude": 42.8763365822579,
+ "longitude": -8.56273502111435,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 568,
+ "name": {
+ "original": "San Lourenzo (estrada)"
+ },
+ "latitude": 42.8764338787416,
+ "longitude": -8.56251507997513,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 569,
+ "name": {
+ "original": "San Marcos"
+ },
+ "latitude": 42.8922852598564,
+ "longitude": -8.48859876394272,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 570,
+ "name": {
+ "original": "San Marcos T"
+ },
+ "latitude": 42.8923343868116,
+ "longitude": -8.48865509033203,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 571,
+ "name": {
+ "original": "Mourentán Correos 1"
+ },
+ "latitude": 42.9006616,
+ "longitude": -8.4307792,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 572,
+ "name": {
+ "original": "San Roque (La Salle)"
+ },
+ "latitude": 42.884222996395,
+ "longitude": -8.54158043861389,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "9",
+ "15",
+ "C6",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 573,
+ "name": {
+ "original": "San Roque nº 21"
+ },
+ "latitude": 42.8839832249546,
+ "longitude": -8.54174539446831,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "15",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 574,
+ "name": {
+ "original": "San Silvestre - A Gracia"
+ },
+ "latitude": 42.9280442373054,
+ "longitude": -8.52313220500946,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 575,
+ "name": {
+ "original": "Sánchez Freire"
+ },
+ "latitude": 42.8644141451275,
+ "longitude": -8.55569154024124,
+ "lines": [
+ "C2",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 576,
+ "name": {
+ "original": "Santa Clara"
+ },
+ "latitude": 42.8851791248794,
+ "longitude": -8.54117810726166,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "8",
+ "15",
+ "P1",
+ "P2",
+ "P4",
+ "P6",
+ "P7",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 577,
+ "name": {
+ "original": "Santa Isabel"
+ },
+ "latitude": 42.8854798158721,
+ "longitude": -8.54770794510841,
+ "lines": [
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 578,
+ "name": {
+ "original": "Santa Lucía (hotel)"
+ },
+ "latitude": 42.8523193158303,
+ "longitude": -8.52696776390076,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 579,
+ "name": {
+ "original": "Santa Lucía (Piñeiro do Eixo)"
+ },
+ "latitude": 42.8460669834593,
+ "longitude": -8.52492928504944,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 580,
+ "name": {
+ "original": "Santa Lucía (Pontillón 1)"
+ },
+ "latitude": 42.8544055799786,
+ "longitude": -8.52990210056305,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 581,
+ "name": {
+ "original": "Santa Lucía (Pontillón 2)"
+ },
+ "latitude": 42.8532523427683,
+ "longitude": -8.52873265743256,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 582,
+ "name": {
+ "original": "Santa Lucía nº 106"
+ },
+ "latitude": 42.8458526290315,
+ "longitude": -8.52505534887314,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 583,
+ "name": {
+ "original": "Santa Lucía nº 34"
+ },
+ "latitude": 42.8521915028234,
+ "longitude": -8.52691411972046,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 584,
+ "name": {
+ "original": "Santa María de Grixoa (Ponte Vilar)"
+ },
+ "latitude": 42.9510730103562,
+ "longitude": -8.55587124824524,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 585,
+ "name": {
+ "original": "Santa María de Grixoa (Valiña)"
+ },
+ "latitude": 42.951159391309,
+ "longitude": -8.5531085729599,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 586,
+ "name": {
+ "original": "Santa Marta de Arriba nº 10"
+ },
+ "latitude": 42.8707009867931,
+ "longitude": -8.55776488780975,
+ "lines": [
+ "1",
+ "12",
+ "C4",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 587,
+ "name": {
+ "original": "Sta. Marta (colexio Divino Maestro)"
+ },
+ "latitude": 42.8706439795361,
+ "longitude": -8.55769246816635,
+ "lines": [
+ "1",
+ "C2",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 588,
+ "name": {
+ "original": "Santasmariñas nº 49"
+ },
+ "latitude": 42.8670091667557,
+ "longitude": -8.53991210460663,
+ "lines": [
+ "C5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 589,
+ "name": {
+ "original": "Santiago de Chile (c. Frei R. Salvado)"
+ },
+ "latitude": 42.8726962076185,
+ "longitude": -8.55087429285049,
+ "lines": [
+ "15",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 590,
+ "name": {
+ "original": "Santiago de Chile nº 31"
+ },
+ "latitude": 42.8708307272508,
+ "longitude": -8.54956269264221,
+ "lines": [
+ "15",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 591,
+ "name": {
+ "original": "S. León Caracas (E. Intermodal)"
+ },
+ "latitude": 42.8709860222886,
+ "longitude": -8.54623541235924,
+ "lines": [
+ "6",
+ "12",
+ "15",
+ "C4",
+ "C5",
+ "P3",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 592,
+ "name": {
+ "original": "Sanxuás 1"
+ },
+ "latitude": 42.8733959939296,
+ "longitude": -8.50578635931015,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 593,
+ "name": {
+ "original": "Sanxuás 2"
+ },
+ "latitude": 42.8702763797519,
+ "longitude": -8.50775510072708,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 594,
+ "name": {
+ "original": "Sarela (c. Pedroso) 1"
+ },
+ "latitude": 42.8834889390857,
+ "longitude": -8.56927692890167,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 595,
+ "name": {
+ "original": "Sarela (c. Pedroso) 2"
+ },
+ "latitude": 42.8835705014403,
+ "longitude": -8.56917634606361,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 596,
+ "name": {
+ "original": "Sarela de Arriba"
+ },
+ "latitude": 42.9179084950357,
+ "longitude": -8.5518479347229,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 597,
+ "name": {
+ "original": "Sarela de Arriba (dir. Grixoa)"
+ },
+ "latitude": 42.917987065481,
+ "longitude": -8.55188012123108,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 598,
+ "name": {
+ "original": "Senra nº 13"
+ },
+ "latitude": 42.8768191319988,
+ "longitude": -8.54556083679199,
+ "lines": [
+ "1",
+ "8",
+ "9",
+ "12",
+ "P1",
+ "P2",
+ "P7",
+ "P8",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 599,
+ "name": {
+ "original": "Senra nº 14"
+ },
+ "latitude": 42.8768338737848,
+ "longitude": -8.54497477412224,
+ "lines": [
+ "1",
+ "8",
+ "9",
+ "12",
+ "P1",
+ "P2",
+ "P7",
+ "P8",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 600,
+ "name": {
+ "original": "Sionlla (cruce)"
+ },
+ "latitude": 42.909674739219,
+ "longitude": -8.44940364360809,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 601,
+ "name": {
+ "original": "Sionlla de Abaixo"
+ },
+ "latitude": 42.9317127665751,
+ "longitude": -8.47518503665924,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 602,
+ "name": {
+ "original": "Sionlla de Arriba"
+ },
+ "latitude": 42.9153165963108,
+ "longitude": -8.48420262336731,
+ "lines": [
+ "P4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 603,
+ "name": {
+ "original": "N634 H. Garcas"
+ },
+ "latitude": 42.9001157,
+ "longitude": -8.4372467,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 604,
+ "name": {
+ "original": "Son de Abaixo 1"
+ },
+ "latitude": 42.9277476,
+ "longitude": -8.5332085,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 605,
+ "name": {
+ "original": "Son de Abaixo 2"
+ },
+ "latitude": 42.9255273977398,
+ "longitude": -8.53266477584839,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 606,
+ "name": {
+ "original": "Son de abaixo 3 (Escarabuña)"
+ },
+ "latitude": 42.9227678885465,
+ "longitude": -8.53193521499634,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 607,
+ "name": {
+ "original": "Son de Arriba"
+ },
+ "latitude": 42.9316892007032,
+ "longitude": -8.52934956550598,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 608,
+ "name": {
+ "original": "Sta. Isabel"
+ },
+ "latitude": 42.8851791248794,
+ "longitude": -8.54777231812477,
+ "lines": [
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 609,
+ "name": {
+ "original": "Sta. María da Peregrina"
+ },
+ "latitude": 42.9228641297374,
+ "longitude": -8.55396151542664,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 610,
+ "name": {
+ "original": "Sta. María de Grixoa (Ponte Vilar)"
+ },
+ "latitude": 42.9511358328794,
+ "longitude": -8.5560268163681,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 611,
+ "name": {
+ "original": "Sta. María de Grixoa (Valiña)"
+ },
+ "latitude": 42.951100495218,
+ "longitude": -8.5539186000824,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 612,
+ "name": {
+ "original": "Sta. María Villestro (rúa dos Príncipes)"
+ },
+ "latitude": 42.888344168022,
+ "longitude": -8.60659718513489,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 613,
+ "name": {
+ "original": "Sta. María Villestro (rúa dos Príncipes) 2"
+ },
+ "latitude": 42.8882734206172,
+ "longitude": -8.60647916793823,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 614,
+ "name": {
+ "original": "Rúa do Río nº 26"
+ },
+ "latitude": 42.9005940366205,
+ "longitude": -8.53039562702179,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 615,
+ "name": {
+ "original": "Sto. Ignacio do Monte"
+ },
+ "latitude": 42.8918775046173,
+ "longitude": -8.55618640780449,
+ "lines": [
+ "9",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 616,
+ "name": {
+ "original": "Susana (cabecera)"
+ },
+ "latitude": 42.8278166619322,
+ "longitude": -8.48694115877151,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 617,
+ "name": {
+ "original": "Susana (rúa de Sergude 1)"
+ },
+ "latitude": 42.827354384216,
+ "longitude": -8.48840832710266,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 618,
+ "name": {
+ "original": "Susana (rúa de Sergude 2)"
+ },
+ "latitude": 42.8273052055321,
+ "longitude": -8.48836809396744,
+ "lines": [
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 619,
+ "name": {
+ "original": "Os Vilares 76"
+ },
+ "latitude": 42.9101585,
+ "longitude": -8.5347385,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 620,
+ "name": {
+ "original": "Tanatorio de Boisaca"
+ },
+ "latitude": 42.9083712632082,
+ "longitude": -8.52146923542023,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 621,
+ "name": {
+ "original": "Queiroal (AC-404)"
+ },
+ "latitude": 42.9125605586423,
+ "longitude": -8.55194985866547,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 622,
+ "name": {
+ "original": "Teleclub"
+ },
+ "latitude": 42.8656408962198,
+ "longitude": -8.50326508283615,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 623,
+ "name": {
+ "original": "Teleclub T"
+ },
+ "latitude": 42.8656448280751,
+ "longitude": -8.50314438343048,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 624,
+ "name": {
+ "original": "Torrebranca"
+ },
+ "latitude": 42.8675202945198,
+ "longitude": -8.50897818803787,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 625,
+ "name": {
+ "original": "Torrebranca (rúa da Obrigada)"
+ },
+ "latitude": 42.8649980345049,
+ "longitude": -8.50873678922653,
+ "lines": [
+ "7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 626,
+ "name": {
+ "original": "Torrente (c. Travesa Benéfica Conxo)"
+ },
+ "latitude": 42.8628079293598,
+ "longitude": -8.56153339147568,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 627,
+ "name": {
+ "original": "Torrente (c. Travesa Benéfica)"
+ },
+ "latitude": 42.8627902351957,
+ "longitude": -8.56145560741425,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 628,
+ "name": {
+ "original": "Torrente nº 28"
+ },
+ "latitude": 42.8613963123363,
+ "longitude": -8.56348872184753,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 629,
+ "name": {
+ "original": "Torrente nº 31"
+ },
+ "latitude": 42.8613157037048,
+ "longitude": -8.56369525194168,
+ "lines": [
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 630,
+ "name": {
+ "original": "Tras Igrexa (centro sociocultural)"
+ },
+ "latitude": 42.8856046120302,
+ "longitude": -8.60588371753693,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 631,
+ "name": {
+ "original": "Tras Igrexa (centro sociocultural) 2"
+ },
+ "latitude": 42.8857618351771,
+ "longitude": -8.60583007335663,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 632,
+ "name": {
+ "original": "Urb. Brandía"
+ },
+ "latitude": 42.8720632479972,
+ "longitude": -8.5808801651001,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 633,
+ "name": {
+ "original": "Urb. Brandía 2"
+ },
+ "latitude": 42.8716445475376,
+ "longitude": -8.5805207490921,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 634,
+ "name": {
+ "original": "Bando de Arriba 3"
+ },
+ "latitude": 42.8831499136852,
+ "longitude": -8.47919225692749,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 635,
+ "name": {
+ "original": "Valiño nº 17"
+ },
+ "latitude": 42.8872249738713,
+ "longitude": -8.52445185184479,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 636,
+ "name": {
+ "original": "Valiño nº 2"
+ },
+ "latitude": 42.8872544524675,
+ "longitude": -8.52302759885788,
+ "lines": [
+ "6",
+ "C5",
+ "C6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 637,
+ "name": {
+ "original": "Valle Inclán (dársena autobuses)"
+ },
+ "latitude": 42.883258991626,
+ "longitude": -8.54026883840561,
+ "lines": [
+ "7",
+ "P3",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 638,
+ "name": {
+ "original": "Valle Inclán (dársena autobuses) T"
+ },
+ "latitude": 42.8830899698698,
+ "longitude": -8.54006230831146,
+ "lines": [
+ "7",
+ "P3",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 639,
+ "name": {
+ "original": "Valle Inclán (La Salle)"
+ },
+ "latitude": 42.8835803282227,
+ "longitude": -8.54145169258118,
+ "lines": [
+ "7",
+ "9",
+ "13",
+ "C5",
+ "P3",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 640,
+ "name": {
+ "original": "Vía Edison"
+ },
+ "latitude": 42.910678603235,
+ "longitude": -8.51299479603767,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 641,
+ "name": {
+ "original": "Vía Edison 1"
+ },
+ "latitude": 42.9100912170771,
+ "longitude": -8.51208284497261,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 642,
+ "name": {
+ "original": "Vía Edison 2"
+ },
+ "latitude": 42.9118101407235,
+ "longitude": -8.51445928215981,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 643,
+ "name": {
+ "original": "Vía Edison 3"
+ },
+ "latitude": 42.9127019976455,
+ "longitude": -8.5165835916996,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 644,
+ "name": {
+ "original": "Vía Edison 4"
+ },
+ "latitude": 42.9146811274252,
+ "longitude": -8.52140620350838,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 645,
+ "name": {
+ "original": "Vía Edison 5"
+ },
+ "latitude": 42.9157143748906,
+ "longitude": -8.52609738707542,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 646,
+ "name": {
+ "original": "Pardaces de Abaixo"
+ },
+ "latitude": 42.9115940500996,
+ "longitude": -8.55437994003296,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 647,
+ "name": {
+ "original": "Vía La Cierva"
+ },
+ "latitude": 42.9138,
+ "longitude": -8.5274258,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 648,
+ "name": {
+ "original": "Rúa de Amio (c. País Vasco)"
+ },
+ "latitude": 42.8946432,
+ "longitude": -8.508827,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 649,
+ "name": {
+ "original": "Rúa do Tambre nº 197"
+ },
+ "latitude": 42.9118738,
+ "longitude": -8.5285526,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 650,
+ "name": {
+ "original": "Manuel María nº 20"
+ },
+ "latitude": 42.8986555,
+ "longitude": -8.5305826,
+ "lines": [
+ "1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 651,
+ "name": {
+ "original": "Vía Pasteur 1"
+ },
+ "latitude": 42.9127442328405,
+ "longitude": -8.52377191185951,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 652,
+ "name": {
+ "original": "Vía Pasteur 2"
+ },
+ "latitude": 42.9117305801728,
+ "longitude": -8.52066859602928,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 653,
+ "name": {
+ "original": "Vía Pasteur 3"
+ },
+ "latitude": 42.9109084484686,
+ "longitude": -8.51872801780701,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 654,
+ "name": {
+ "original": "Vía Pasteur 4"
+ },
+ "latitude": 42.9101501523958,
+ "longitude": -8.51691752672195,
+ "lines": [
+ "P6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 655,
+ "name": {
+ "original": "Vicente Fraíz Antón (fac. Psicoloxía)"
+ },
+ "latitude": 42.8747346079963,
+ "longitude": -8.56279671192169,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 656,
+ "name": {
+ "original": "Vidán (rot. hospital Clínico)"
+ },
+ "latitude": 42.8712022552347,
+ "longitude": -8.56560230255127,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 657,
+ "name": {
+ "original": "Vilamaior"
+ },
+ "latitude": 42.8914726943398,
+ "longitude": -8.45229506492615,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 658,
+ "name": {
+ "original": "Pardaces de Arriba"
+ },
+ "latitude": 42.9128277209315,
+ "longitude": -8.56040954589844,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 659,
+ "name": {
+ "original": "Vilastrexe"
+ },
+ "latitude": 42.8755297034874,
+ "longitude": -8.61586153507233,
+ "lines": [
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 660,
+ "name": {
+ "original": "Virxe da Cerca (Praza de abastos 1)"
+ },
+ "latitude": 42.8804563152445,
+ "longitude": -8.54065373539925,
+ "lines": [
+ "4",
+ "5",
+ "7",
+ "8",
+ "9",
+ "13",
+ "P1",
+ "P2",
+ "P4",
+ "P7",
+ "P8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 661,
+ "name": {
+ "original": "Virxe da Cerca (Praza de abastos 2)"
+ },
+ "latitude": 42.8801192386458,
+ "longitude": -8.54079052805901,
+ "lines": [
+ "1",
+ "6",
+ "15",
+ "C5",
+ "P3",
+ "P6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 662,
+ "name": {
+ "original": "Virxe da Cerca nº 10"
+ },
+ "latitude": 42.8804523843327,
+ "longitude": -8.54050487279892,
+ "lines": [
+ "1",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "C11",
+ "13",
+ "15",
+ "C6",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "P6",
+ "P7",
+ "P8",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 663,
+ "name": {
+ "original": "Vista Alegre nº 110"
+ },
+ "latitude": 42.8929386451606,
+ "longitude": -8.54750946164131,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 664,
+ "name": {
+ "original": "Vista Alegre nº 153"
+ },
+ "latitude": 42.8924739071512,
+ "longitude": -8.54763552546501,
+ "lines": [
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 665,
+ "name": {
+ "original": "Vista Alegre nº 76"
+ },
+ "latitude": 42.8907387232986,
+ "longitude": -8.54708567261696,
+ "lines": [
+ "C2",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 666,
+ "name": {
+ "original": "Vista Alegre nº 99"
+ },
+ "latitude": 42.8905766000033,
+ "longitude": -8.54727476835251,
+ "lines": [
+ "C4",
+ "P7",
+ "4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 667,
+ "name": {
+ "original": "Vite de Arriba 1 nº 12"
+ },
+ "latitude": 42.8949596743779,
+ "longitude": -8.54435920715332,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 668,
+ "name": {
+ "original": "Vite de Arriba nº 12"
+ },
+ "latitude": 42.8948987595406,
+ "longitude": -8.54452550411224,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 669,
+ "name": {
+ "original": "Vite de Arriba nº 35"
+ },
+ "latitude": 42.8963479268562,
+ "longitude": -8.54296579957008,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 670,
+ "name": {
+ "original": "Os Vilares 65"
+ },
+ "latitude": 42.9089395,
+ "longitude": -8.5333976,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 671,
+ "name": {
+ "original": "Restollal (rot.Luís Iglesias)"
+ },
+ "latitude": 42.866037,
+ "longitude": -8.5443462,
+ "lines": [
+ "6",
+ "12",
+ "C5",
+ "P3"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 672,
+ "name": {
+ "original": "Lavacolla 1"
+ },
+ "latitude": 42.8991809,
+ "longitude": -8.4445197,
+ "lines": [
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 673,
+ "name": {
+ "original": "Xeneral Pardiñas nº 35"
+ },
+ "latitude": 42.8735237630455,
+ "longitude": -8.54645133018494,
+ "lines": [
+ "C11",
+ "13",
+ "15",
+ "P6",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 674,
+ "name": {
+ "original": "Xeneral Pardiñas nº 7"
+ },
+ "latitude": 42.875581792204,
+ "longitude": -8.54615092277527,
+ "lines": [
+ "C11",
+ "13",
+ "15",
+ "P6",
+ "5"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 675,
+ "name": {
+ "original": "Xulacasa 1"
+ },
+ "latitude": 42.8923884264172,
+ "longitude": -8.58290791511536,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 676,
+ "name": {
+ "original": "Xulacasa 2"
+ },
+ "latitude": 42.892007200552,
+ "longitude": -8.58251631259918,
+ "lines": [
+ "P1"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 678,
+ "name": {
+ "original": "Os Vilares 45"
+ },
+ "latitude": 42.9076629,
+ "longitude": -8.5328126,
+ "lines": [
+ "8"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 679,
+ "name": {
+ "original": "Pardaces (c. Aradas)"
+ },
+ "latitude": 42.9171650172382,
+ "longitude": -8.55981945991516,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 680,
+ "name": {
+ "original": "Bando de Arriba 4"
+ },
+ "latitude": 42.8831145370143,
+ "longitude": -8.47927272319794,
+ "lines": [
+ "6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 681,
+ "name": {
+ "original": "Hospital Gil Casares"
+ },
+ "latitude": 42.8685335,
+ "longitude": -8.563408,
+ "lines": [
+ "C2",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 682,
+ "name": {
+ "original": "Bálsoma 2"
+ },
+ "latitude": 42.9301279,
+ "longitude": -8.5193463,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 683,
+ "name": {
+ "original": "Cidade da Cultura"
+ },
+ "latitude": 42.8688128391159,
+ "longitude": -8.52568298578262,
+ "lines": [
+ "9",
+ "C11"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 684,
+ "name": {
+ "original": "Feliciano Barrera Fernández (aparcadoiro)"
+ },
+ "latitude": 42.865883687817,
+ "longitude": -8.56027945876122,
+ "lines": [
+ "1",
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 685,
+ "name": {
+ "original": "Feliciano Barrera Fernández"
+ },
+ "latitude": 42.8659161254884,
+ "longitude": -8.56036394834518,
+ "lines": [
+ "1",
+ "12",
+ "C4"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 686,
+ "name": {
+ "original": "Avda. da Liberdade"
+ },
+ "latitude": 42.867332553852,
+ "longitude": -8.56112837791443,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 687,
+ "name": {
+ "original": "Casal do Castiñeiriño"
+ },
+ "latitude": 42.8565645237132,
+ "longitude": -8.53944808244705,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 688,
+ "name": {
+ "original": "Rúa de Amio nº 51"
+ },
+ "latitude": 42.8948851,
+ "longitude": -8.5094659,
+ "lines": [
+ "C5",
+ "C6"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 689,
+ "name": {
+ "original": "Castiñeiriño (c. Peleteiro)"
+ },
+ "latitude": 42.8528698919136,
+ "longitude": -8.53884726762772,
+ "lines": [
+ "6",
+ "12"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 690,
+ "name": {
+ "original": "O Barral 2"
+ },
+ "latitude": 42.9226922703624,
+ "longitude": -8.5075056552887,
+ "lines": [
+ "1",
+ "P2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 691,
+ "name": {
+ "original": "Hórreo (E. Intermodal)"
+ },
+ "latitude": 42.8706512,
+ "longitude": -8.5461194,
+ "lines": [
+ "6",
+ "12",
+ "C4",
+ "C6",
+ "P3",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 692,
+ "name": {
+ "original": "Avda. Barcelona nº 5"
+ },
+ "latitude": 42.8718263778983,
+ "longitude": -8.55781048536301,
+ "lines": [
+ "15"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 693,
+ "name": {
+ "original": "Pardaces de Arriba 2"
+ },
+ "latitude": 42.9157683940058,
+ "longitude": -8.56022447347641,
+ "lines": [
+ "P7"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 694,
+ "name": {
+ "original": "Hórreo (E. Intermodal)"
+ },
+ "latitude": 42.8702804,
+ "longitude": -8.5469266,
+ "lines": [
+ "C2"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 695,
+ "name": {
+ "original": "Monte dos Postes nº 8"
+ },
+ "latitude": 42.8869489,
+ "longitude": -8.5305313,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ },
+ {
+ "stopId": 696,
+ "name": {
+ "original": "Monte dos Postes nº 47"
+ },
+ "latitude": 42.88725,
+ "longitude": -8.5300852,
+ "lines": [
+ "6",
+ "6A"
+ ],
+ "hide": false
+ }
+] \ No newline at end of file
diff --git a/src/frontend/public/stops.json b/src/frontend/public/stops/vigo.json
index 9ab70f0..9ab70f0 100644
--- a/src/frontend/public/stops.json
+++ b/src/frontend/public/stops/vigo.json