diff --git a/README.md b/README.md
index 10ce689..ce04131 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,6 @@ LGAV 21L BIBE2F SID (Cycle 2507, ID 10657)
The leg terminates upon reaching `Distance`.
This intercept point then becomes the origin fix of the succeeding leg.
-This new origin is an implicit overfly.
## Course to Fix (CF)
@@ -320,7 +319,6 @@ LGAV 03R BIBE2T SID (Cycle 2507, ID 10659)
The leg terminates upon reaching `Distance`.
This intercept point then becomes the origin fix of the succeeding leg.
-This new origin is an implicit overfly.
## Track from Fix to Manual Termination (FM)
@@ -626,7 +624,6 @@ LFRK 31 NEVI4Y SID (Cycle 2507, ID 10482)
The leg terminates upon reaching `Distance`.
This intercept point then becomes the origin fix of the succeeding leg.
-This new origin is an implicit overfly.
## Heading to Intercept (VI)
@@ -700,4 +697,9 @@ LIMC 35R MMP8G SID (Cycle 2507, ID 11909)
### Notes
The leg terminates at the intercept point.
-This intercept point then becomes the origin fix of the succeeding leg.
\ No newline at end of file
+This intercept point then becomes the origin fix of the succeeding leg.
+
+
+# Other Fields
+
+- `Vnav`: Angle from IAF to MAP. Useful for RNAV.
\ No newline at end of file
diff --git a/browser/src/App.tsx b/browser/src/App.tsx
index ebdb5a6..254f6e6 100644
--- a/browser/src/App.tsx
+++ b/browser/src/App.tsx
@@ -24,7 +24,7 @@ function App() {
return (
<>
- {transitions.length === 0 ? (
+ {!user ? (
{!initialized &&
Loading...
}
@@ -38,7 +38,27 @@ function App() {
>
)}
- {user && (
+
+ ) : (
+
+ {selectedAirport && selectedRunway && selectedTerminal ? (
+
{
+ setSelectedTerminal(undefined);
+ setSelectedChart(undefined);
+ setTransitions([]);
+ setSelectedTransition(undefined);
+ }}
+ />
+ ) : (
{
- const _transitions = selectedTransitions.map((transition) => ({
- name: transition,
- data: parser.parse(selectedRunway!, transition),
- }));
+ let _transitions = selectedTransitions
+ .map((transition) => ({
+ name: transition,
+ data: parser.parse(selectedRunway!, transition),
+ }))
+ .filter(
+ (transition) =>
+ !transition.name.startsWith('RW') || transition.name === `RW${selectedRunway?.Ident}`
+ );
+
+ if (_transitions.length > 1)
+ _transitions = _transitions.filter((transition) => transition.name !== 'ALL');
setTransitions(_transitions);
setSelectedTransition(_transitions[0]);
setSelectedChart(undefined);
}}
/>
)}
-
- ) : (
-
- {transitions.length > 0 && selectedAirport && selectedTerminal ? (
- <>
- {
- setSelectedTerminal(undefined);
- setTransitions([]);
- }}
- />
-
- >
- ) : (
- Error
- )}
+
)}
>
diff --git a/browser/src/components/Loader.tsx b/browser/src/components/Loader.tsx
new file mode 100644
index 0000000..3ff532c
--- /dev/null
+++ b/browser/src/components/Loader.tsx
@@ -0,0 +1,22 @@
+import type { FC } from 'react';
+
+interface LoaderProps {
+ size?: 0.5 | 1 | 2 | 3;
+}
+
+export const Loader: FC = ({ size = 2 }) => {
+ const variants = {
+ 0.5: 'size-6 border-1 after:top-1 after:left-0.5 after:size-1.5 after:border-1',
+ 1: 'size-12 border-2 after:top-2 after:left-1 after:size-3 after:border-2',
+ 2: 'size-24 border-4 after:top-3 after:left-2 after:size-6 after:border-4',
+ 3: 'size-36 border-6 after:top-4 after:left-3 after:size-9 after:border-6',
+ };
+
+ return (
+
+
+
+ );
+};
diff --git a/browser/src/components/Map.tsx b/browser/src/components/Map.tsx
index 218b3a9..cea15a7 100644
--- a/browser/src/components/Map.tsx
+++ b/browser/src/components/Map.tsx
@@ -1,22 +1,26 @@
import { default as L } from 'leaflet';
import 'leaflet-svg-shape-markers';
-import { createRef, type FC } from 'react';
+import { createRef, Fragment, useEffect, type FC } from 'react';
import { GeoJSON, ImageOverlay, MapContainer, TileLayer } from 'react-leaflet';
interface MapProps {
- airport: Airport;
+ airport: Airport | undefined;
chart: Chart | undefined;
- procedure: Procedure | undefined;
+ procedures: Procedure[];
}
-export const Map: FC = ({ airport, chart, procedure }) => {
+export const Map: FC = ({ airport, chart, procedures }) => {
const mapRef = createRef();
const imageRef = createRef();
+ useEffect(() => {
+ if (airport) mapRef.current?.flyTo([airport?.Latitude, airport?.Longitude], 10, { animate: false });
+ }, [airport]);
+
return (
{
@@ -46,15 +50,15 @@ export const Map: FC = ({ airport, chart, procedure }) => {
/>
)}
- {procedure && (
- <>
+ {procedures.map((procedure) => (
+
({
- color: '#ff00ff',
+ color: properties.isMAP ? '#00ffff' : '#ff00ff',
stroke: true,
- weight: 5,
+ weight: properties.isMAP ? 2.5 : 5,
opacity: 1,
dashArray: properties.isManual ? '20, 20' : undefined,
})}
@@ -71,12 +75,22 @@ export const Map: FC = ({ airport, chart, procedure }) => {
weight: 3,
}}
pointToLayer={({ properties }, latlng) => {
- if (properties.isFlyOver)
+ if (properties.isIntersection) return L.circleMarker(latlng, { radius: 6 });
+ else if (properties.IsMAP)
+ return L.shapeMarker(latlng, {
+ shape: 'square',
+ radius: 6,
+ });
+ else if (properties.IsFAF)
+ return L.shapeMarker(latlng, {
+ shape: 'diamond',
+ radius: 6,
+ });
+ else if (properties.isFlyOver)
return L.shapeMarker(latlng, {
shape: 'triangle',
radius: 6,
});
- if (properties.isIntersection) return L.circleMarker(latlng, { radius: 6 });
return L.shapeMarker(latlng, {
shape: 'star-4',
@@ -98,8 +112,8 @@ export const Map: FC = ({ airport, chart, procedure }) => {
}}
filter={(feature) => feature.geometry.type === 'Point'}
/>
- >
- )}
+
+ ))}
);
};
diff --git a/browser/src/components/ProcedureSelect.tsx b/browser/src/components/ProcedureSelect.tsx
index f840689..8742f95 100644
--- a/browser/src/components/ProcedureSelect.tsx
+++ b/browser/src/components/ProcedureSelect.tsx
@@ -1,5 +1,6 @@
import { createRef, useMemo, useState, type Dispatch, type FC, type SetStateAction } from 'react';
import Parser from '../parser/parser';
+import { Loader } from './Loader';
const parser = await Parser.instance();
@@ -24,26 +25,32 @@ export const ProcedureSelect: FC = ({
}) => {
const inputRef = createRef();
const [error, setError] = useState();
+ const [inFlight, setInFlight] = useState();
const runways = useMemo(
() => parser.runways.filter(({ AirportID }) => AirportID === selectedAirport?.ID),
[selectedAirport]
);
- const terminals = useMemo(
- () =>
- parser.terminals.filter(
- ({ AirportID, RwyID }) => AirportID === selectedAirport?.ID && (!RwyID || RwyID === selectedRunway?.ID)
- ),
- [selectedAirport, selectedRunway]
- );
+ const terminals = useMemo(() => {
+ const _terminals = parser.terminals.filter(
+ ({ AirportID, RwyID }) => AirportID === selectedAirport?.ID && (!RwyID || RwyID === selectedRunway?.ID)
+ );
+
+ return {
+ star: _terminals.filter((terminal) => terminal.Proc === 1),
+ sid: _terminals.filter((terminal) => terminal.Proc === 2),
+ iap: _terminals.filter((terminal) => terminal.Proc === 3),
+ };
+ }, [selectedAirport, selectedRunway]);
return (
-
+
{selectedAirport && (
{
setError(undefined);
+ setInFlight(undefined);
if (selectedTerminal) {
setSelectedTerminal(undefined);
@@ -58,68 +65,126 @@ export const ProcedureSelect: FC = ({
)}
- {!selectedAirport && (
-
-
Enter Airport ICAO
- {
- if (e.target.value.length <= 4) e.target.value = e.target.value.toUpperCase();
- else e.target.value = e.target.value.slice(0, 4);
- }}
- >
- {
- const airport = parser.airports.find(({ ICAO }) => ICAO === inputRef.current?.value.toUpperCase());
- if (!airport) {
- setError('Airport not found');
- return;
- }
- setSelectedAirport(airport);
- setError(undefined);
- }}
- >
- Select Airport
-
- {error && {error} }
-
- )}
- {selectedAirport && !selectedRunway && (
-
-
Select Runway
- {runways.map((runway) => (
+
+ {!selectedAirport && (
+
+
Enter Airport ICAO
+ {
+ if (e.target.value.length <= 4) e.target.value = e.target.value.toUpperCase();
+ else e.target.value = e.target.value.slice(0, 4);
+ }}
+ >
setSelectedRunway(runway)}
- >
- Runway {runway.Ident}
-
- ))}
-
- )}
- {selectedAirport && selectedRunway && !selectedTerminal && (
-
-
Select Procedure
- {terminals.map((terminal) => (
- {
- parser.loadTerminal(terminal.ID).then(() => {
- setSelectedTerminal(terminal);
- const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
- handleSelection(Array.from(transitions));
- });
+ const airport = parser.airports.find(({ ICAO }) => ICAO === inputRef.current?.value.toUpperCase());
+ if (!airport) {
+ setError('Airport not found');
+ return;
+ }
+ setSelectedAirport(airport);
+ setError(undefined);
}}
>
- {terminal.FullName}
+ Select Airport
- ))}
-
- )}
+ {error &&
{error} }
+
+ )}
+
+ {selectedAirport && !selectedRunway && (
+
+
Select Runway
+ {runways.map((runway) => (
+ setSelectedRunway(runway)}
+ >
+ Runway {runway.Ident}
+
+ ))}
+
+ )}
+
+ {selectedAirport && selectedRunway && !selectedTerminal && (
+
+
Select Procedure
+
+
+
Arrivals
+ {terminals.star.map((terminal) => (
+
{
+ setInFlight(terminal.ID);
+ parser.loadTerminal(terminal.ID).then(() => {
+ setSelectedTerminal(terminal);
+ const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
+ handleSelection(Array.from(transitions));
+ setInFlight(undefined);
+ });
+ }}
+ disabled={!!inFlight}
+ >
+
+ {terminal.FullName}
+ {inFlight === terminal.ID && }
+
+
+ ))}
+
+
+
Departures
+ {terminals.sid.map((terminal) => (
+
{
+ parser.loadTerminal(terminal.ID).then(() => {
+ setSelectedTerminal(terminal);
+ const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
+ handleSelection(Array.from(transitions));
+ });
+ }}
+ disabled={!!inFlight}
+ >
+
+ {terminal.FullName}
+ {inFlight === terminal.ID && }
+
+
+ ))}
+
+
+
Approaches
+ {terminals.iap.map((terminal) => (
+
{
+ parser.loadTerminal(terminal.ID).then(() => {
+ setSelectedTerminal(terminal);
+ const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
+ handleSelection(Array.from(transitions));
+ });
+ }}
+ disabled={!!inFlight}
+ >
+
+ {terminal.FullName}
+ {inFlight === terminal.ID && }
+
+
+ ))}
+
+
+ )}
+
);
};
diff --git a/browser/src/components/Sidebar.tsx b/browser/src/components/Sidebar.tsx
index d544896..eba86b6 100644
--- a/browser/src/components/Sidebar.tsx
+++ b/browser/src/components/Sidebar.tsx
@@ -1,11 +1,13 @@
import BrowserImageManipulation from 'browser-image-manipulation';
import L from 'leaflet';
import type { Chart as NGChart } from 'navigraph/charts';
-import { useEffect, useState, type Dispatch, type FC, type SetStateAction } from 'react';
+import { useCallback, useEffect, useState, type Dispatch, type FC, type SetStateAction } from 'react';
import { charts } from '../lib/navigraph';
+import { Loader } from './Loader';
interface SidebarProps {
airport: Airport;
+ runway: Runway;
terminal: Terminal;
transitions: Procedure[];
transition: Procedure | undefined;
@@ -17,6 +19,7 @@ interface SidebarProps {
export const Sidebar: FC
= ({
airport,
+ runway,
terminal,
transitions,
transition,
@@ -25,14 +28,83 @@ export const Sidebar: FC = ({
setChart,
backAction,
}) => {
- const [chartIndex, setChartIndex] = useState([]);
+ const [inFlight, setInFlight] = useState(false);
+ const [chartIndex, setChartIndex] = useState<{
+ sid: NGChart[];
+ star: NGChart[];
+ iap: NGChart[];
+ }>({ star: [], sid: [], iap: [] });
useEffect(() => {
+ setInFlight(true);
(async () => {
- setChartIndex((await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' })) ?? []);
+ const _chartIndex = await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' });
+
+ const newChartIndex = {
+ star:
+ _chartIndex?.filter(
+ (_chart) =>
+ _chart.category === 'ARR' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
+ ) ?? [],
+ sid:
+ _chartIndex?.filter(
+ (_chart) =>
+ _chart.category === 'DEP' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
+ ) ?? [],
+ iap:
+ _chartIndex?.filter(
+ (_chart) =>
+ _chart.category === 'APP' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
+ ) ?? [],
+ };
+
+ _chartIndex?.filter((_chart) => ['ARR', 'DEP', 'APP'].includes(_chart.category));
+ setChartIndex(newChartIndex);
+ setInFlight(false);
})();
}, [airport.ICAO]);
+ useEffect(() => {
+ if (terminal) {
+ const star = chartIndex.star.find((_chart) => _chart.procedures.includes(terminal.FullName));
+ const sid = chartIndex.sid.find((_chart) => _chart.procedures.includes(terminal.FullName));
+ const iap = chartIndex.iap.find((_chart) => _chart.procedures.includes(terminal.FullName));
+ if (star) findChart(star);
+ if (sid) findChart(sid);
+ if (iap) findChart(iap);
+ }
+ }, [terminal, chartIndex]);
+
+ const findChart = useCallback(
+ async (_chart: NGChart) => {
+ if (chart?.index_number === _chart.index_number) return;
+ if (!_chart.bounding_boxes) return;
+
+ const planView = _chart.bounding_boxes.planview;
+
+ const chartImage = await charts.getChartImage({ chart: _chart, theme: 'light' });
+ if (!chartImage) return;
+ // Crop
+ const dataURL = await new BrowserImageManipulation()
+ .loadBlob(chartImage)
+ .crop(
+ planView.pixels.x2 - planView.pixels.x1,
+ planView.pixels.y1 - planView.pixels.y2,
+ planView.pixels.x1,
+ planView.pixels.y2
+ )
+ .saveAsImage();
+
+ const bounds = new L.LatLngBounds(
+ [planView.latlng.lat1, planView.latlng.lng1],
+ [planView.latlng.lat2, planView.latlng.lng2]
+ );
+
+ setChart({ data: dataURL, index_number: _chart.index_number, bounds });
+ },
+ [chart]
+ );
+
return (
= ({
setTransition(_procedure);
}}
>
- {_procedure.name ? _procedure.name : 'ZZZZ'}
+ {_procedure.name ? _procedure.name : 'NONE'}
))}
-
Charts
- {chartIndex
- .filter((_chart) => _chart.is_georeferenced)
- .map((_chart) => (
-
{
- if (chart?.index_number === _chart.index_number) return;
- if (!_chart.bounding_boxes) return;
+ Charts
+ {inFlight && }
- const planView = _chart.bounding_boxes.planview;
+
+
Arrivals
+ {chartIndex.star
+ .filter((_chart) => _chart.is_georeferenced)
+ .map((_chart) => (
+
findChart(_chart)}
+ >
+ {_chart.index_number}
+
+ {_chart.name}
+
+ ))}
+
- const chartImage = await charts.getChartImage({ chart: _chart, theme: 'light' });
- if (!chartImage) return;
- // Crop
- const dataURL = await new BrowserImageManipulation()
- .loadBlob(chartImage)
- .crop(
- planView.pixels.x2 - planView.pixels.x1,
- planView.pixels.y1 - planView.pixels.y2,
- planView.pixels.x1,
- planView.pixels.y2
- )
- .saveAsImage();
+
+
Departures
+ {chartIndex.sid
+ .filter((_chart) => _chart.is_georeferenced)
+ .map((_chart) => (
+
findChart(_chart)}
+ >
+ {_chart.index_number}
+
+ {_chart.name}
+
+ ))}
+
- const bounds = new L.LatLngBounds(
- [planView.latlng.lat1, planView.latlng.lng1],
- [planView.latlng.lat2, planView.latlng.lng2]
- );
-
- setChart({ data: dataURL, index_number: _chart.index_number, bounds });
- }}
- >
- {_chart.index_number}
-
- {_chart.name}
-
- ))}
+
+
Approaches
+ {chartIndex.iap
+ .filter((_chart) => _chart.is_georeferenced)
+ .map((_chart) => (
+
findChart(_chart)}
+ >
+ {_chart.index_number}
+
+ {_chart.name}
+
+ ))}
+
diff --git a/browser/src/parser/parser.ts b/browser/src/parser/parser.ts
index 12f43d9..194d4c5 100644
--- a/browser/src/parser/parser.ts
+++ b/browser/src/parser/parser.ts
@@ -128,31 +128,32 @@ class Parser {
name: runway.Ident,
});
let lastCourse = runway.TrueHeading;
+ const legOptions = { isMAP: false };
const procedure = this._procedures.filter(
({ Transition }) => !Transition || Transition === transition || Transition === 'ALL'
);
// Main
for (let index = 0; index < procedure.length; index++) {
- //lastCourse = runway.TrueHeading;
const leg = procedure[index];
const previousFix = navFixes.at(-1)!;
+ legOptions.isMAP ||= previousFix.IsMAP ?? false;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
switch (leg.TrackCode) {
case 'AF': {
const [fixToAdd, lineToAdd] = TerminatorsAF(leg as AFTerminalEntry, previousFix, waypoint);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'CA': {
const [fixToAdd, lineToAdd] = TerminatorsCA(leg as CATerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'CD': {
const [fixToAdd, lineToAdd] = TerminatorsCD(leg as CDTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'CF': {
@@ -162,7 +163,7 @@ class Parser {
lastCourse,
waypoint
);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'CI': {
@@ -172,37 +173,37 @@ class Parser {
{ ...previousFix }, // COPY
lastCourse
);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'CR': {
const [fixToAdd, lineToAdd] = TerminatorsCR(leg as CRTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'DF': {
const [fixToAdd, lineToAdd] = TerminatorsDF(leg as DFTerminalEntry, previousFix, lastCourse, waypoint);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'FA': {
const [fixToAdd, lineToAdd] = TerminatorsFA(leg as FATerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'FC': {
const [fixToAdd, lineToAdd] = TerminatorsFC(leg as FCTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'FD': {
const [fixToAdd, lineToAdd] = TerminatorsFD(leg as FDTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'FM': {
const [fixToAdd, lineToAdd] = TerminatorsFM(leg as FMTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd, { isManual: true });
+ update(fixToAdd, lineToAdd, { isManual: true, ...legOptions });
// Make overfly
navFixes.at(-1)!.isFlyOver = true;
break;
@@ -231,7 +232,7 @@ class Parser {
lastCourse = (leg as RFTerminalEntry).Course?.toTrue(fixToAdd);
}
if (lineToAdd) {
- lineSegments.push({ line: lineToAdd });
+ lineSegments.push({ line: lineToAdd, ...legOptions });
}
break;
}
@@ -242,17 +243,17 @@ class Parser {
lastCourse,
waypoint
);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'VA': {
const [fixToAdd, lineToAdd] = TerminatorsVA(leg as VATerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'VD': {
const [fixToAdd, lineToAdd] = TerminatorsVD(leg as VDTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'VI': {
@@ -262,19 +263,19 @@ class Parser {
{ ...previousFix }, // COPY
lastCourse
);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
case 'VM': {
const [fixToAdd, lineToAdd] = TerminatorsVM(leg as VMTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd, { isManual: true });
+ update(fixToAdd, lineToAdd, { isManual: true, ...legOptions });
// Make overfly
navFixes.at(-1)!.isFlyOver = true;
break;
}
case 'VR': {
const [fixToAdd, lineToAdd] = TerminatorsVR(leg as VRTerminalEntry, previousFix, lastCourse);
- update(fixToAdd, lineToAdd);
+ update(fixToAdd, lineToAdd, legOptions);
break;
}
default:
diff --git a/browser/src/parser/pathGenerators/generateAFArc.ts b/browser/src/parser/pathGenerators/generateAFArc.ts
index 85c2211..cf92566 100644
--- a/browser/src/parser/pathGenerators/generateAFArc.ts
+++ b/browser/src/parser/pathGenerators/generateAFArc.ts
@@ -6,7 +6,7 @@ import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
* @param start Arc origin point
* @param center Arc center point
* @param radius Arc radius in nmi
- * @param turnDir
+ * @param turnDir Turn direction
* @returns Line segments
*/
export const generateAFArc = (
diff --git a/browser/src/parser/pathGenerators/generateTangentArc.ts b/browser/src/parser/pathGenerators/generateTangentArc.ts
index 3508dae..d49c0c7 100644
--- a/browser/src/parser/pathGenerators/generateTangentArc.ts
+++ b/browser/src/parser/pathGenerators/generateTangentArc.ts
@@ -56,14 +56,15 @@ export const generateTangentArc = (
}
// Generate arc
+ let arcRad = 0;
let arcCenter = computeIntersection(
start,
crsOrthogonalOnOrigin,
intcArcOnCrsIntoEndpoint,
crsOrthogonalOnEndpoint
);
- let arcRad = 0;
- if (arcCenter) arcRad = getPreciseDistance(arcCenter, start);
+ if (Math.abs(crsOrthogonalOnEndpoint - crsOrthogonalOnOrigin) <= 0.1 && arcCenter)
+ arcRad = getPreciseDistance(arcCenter, start);
else {
arcRad = getPreciseDistance(start, end) / 2;
arcCenter = computeDestinationPoint(start, arcRad, crsOrthogonalOnOrigin);
diff --git a/browser/src/parser/terminators/AF.ts b/browser/src/parser/terminators/AF.ts
index 5575793..21889a3 100644
--- a/browser/src/parser/terminators/AF.ts
+++ b/browser/src/parser/terminators/AF.ts
@@ -7,6 +7,11 @@ export const TerminatorsAF = (
previousFix: NavFix,
waypoint?: Waypoint
): [NavFix?, LineSegment[]?] => {
+ const navaid = {
+ latitude: leg.NavLat,
+ longitude: leg.NavLon,
+ };
+
const targetFix: NavFix = {
latitude: leg.WptLat,
longitude: leg.WptLon,
@@ -16,27 +21,13 @@ export const TerminatorsAF = (
speed: computeSpeed(leg, previousFix),
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
- const arcEndCrs = getGreatCircleBearing(
- {
- latitude: leg.NavLat,
- longitude: leg.NavLon,
- },
- {
- latitude: leg.WptLat,
- longitude: leg.WptLon,
- }
- );
+ const arcEndCrs = getGreatCircleBearing(navaid, targetFix);
- const line = generateAFArc(
- arcEndCrs,
- leg.Course.toTrue({ latitude: leg.NavLat, longitude: leg.NavLon }),
- previousFix,
- { latitude: leg.NavLat, longitude: leg.NavLon },
- leg.NavDist,
- leg.TurnDir
- );
+ const line = generateAFArc(arcEndCrs, leg.Course.toTrue(navaid), previousFix, navaid, leg.NavDist, leg.TurnDir);
return [targetFix, line];
};
diff --git a/browser/src/parser/terminators/CA.ts b/browser/src/parser/terminators/CA.ts
index 6b1510a..a9b4bd3 100644
--- a/browser/src/parser/terminators/CA.ts
+++ b/browser/src/parser/terminators/CA.ts
@@ -31,6 +31,8 @@ export const TerminatorsCA = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/CD.ts b/browser/src/parser/terminators/CD.ts
index 5056874..b33bef0 100644
--- a/browser/src/parser/terminators/CD.ts
+++ b/browser/src/parser/terminators/CD.ts
@@ -44,6 +44,8 @@ export const TerminatorsCD = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/CF.ts b/browser/src/parser/terminators/CF.ts
index b4900cb..68aab77 100644
--- a/browser/src/parser/terminators/CF.ts
+++ b/browser/src/parser/terminators/CF.ts
@@ -3,7 +3,6 @@ import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance';
import Parser from '../parser';
import { generateTangentArc } from '../pathGenerators/generateTangentArc';
-import { computeIntersection } from '../utils/computeIntersection';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
@@ -26,6 +25,8 @@ export const TerminatorsCF = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
const crsToIntercept = leg.Course.toTrue(targetFix);
@@ -38,74 +39,6 @@ export const TerminatorsCF = (
arc1 = [[previousFix.longitude, previousFix.latitude]];
}
- if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsToIntercept))) {
- const turnRate = computeTurnRate(speed, Parser.AC_BANK);
- let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
-
- // Turn Dir
- if (!leg.TurnDir || leg.TurnDir === 'E') {
- let prov = lastCourse - crsIntoEndpoint;
- prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
- leg.TurnDir = prov > 0 ? 'L' : 'R';
- }
-
- // Generate arc
- while (!updatedCrsToIntercept.equal(crsToIntercept)) {
- let time = 0;
- if (leg.TurnDir === 'R') {
- //const delta = (crsIntoEndpoint - lastCourse).normaliseDegrees();
- const increment = 0.1; //delta < 1 ? delta : 1;
- lastCourse = (lastCourse + increment).normaliseDegrees();
- time = increment / turnRate;
- } else {
- //const delta = (lastCourse - crsIntoEndpoint).normaliseDegrees();
- const increment = 0.1; //delta < 1 ? delta : 1;
- lastCourse = (lastCourse - increment).normaliseDegrees();
- time = increment / turnRate;
- }
-
- const arcFix = computeDestinationPoint(
- {
- latitude: arc2.at(-1)![1],
- longitude: arc2.at(-1)![0],
- },
- ((speed / 3600) * time).toMetre(),
- lastCourse
- );
-
- arc2.push([arcFix.longitude, arcFix.latitude]);
-
- // Update previousFix
- previousFix.latitude = arcFix.latitude;
- previousFix.longitude = arcFix.longitude;
- updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
-
- let interceptAngle = 0;
- if (leg.TurnDir === 'R') interceptAngle = lastCourse - crsToIntercept;
- else interceptAngle = crsToIntercept - lastCourse;
-
- if (interceptAngle > 0 && interceptAngle <= 45) {
- const interceptFix: NavFix = {
- ...computeIntersection(
- previousFix,
- leg.Course.toTrue(previousFix),
- targetFix,
- crsToIntercept.reciprocalCourse()
- )!,
- isFlyOver: leg.IsFlyOver,
- altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
- speed: speed,
- speedConstraint: leg.SpeedLimit,
- altitudeConstraint: leg.Alt,
- };
- if (interceptFix.latitude) arc2.push([interceptFix.longitude, interceptFix.latitude]);
-
- break;
- }
- }
- }
-
- // Decide on arc
let arc;
if (arc1 && arc1.length > 1) {
const endCrs = getGreatCircleBearing(
@@ -124,10 +57,61 @@ export const TerminatorsCF = (
);
if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1;
- else arc = arc2;
- } else {
- arc = arc2;
}
+
+ if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsToIntercept))) {
+ const turnRate = computeTurnRate(speed, Parser.AC_BANK);
+ let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
+
+ // Turn Dir
+ if (!leg.TurnDir || leg.TurnDir === 'E') {
+ let prov = lastCourse - crsIntoEndpoint;
+ prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
+ leg.TurnDir = prov > 0 ? 'L' : 'R';
+ }
+
+ // Generate arc
+ let lastDistance = getPreciseDistance(previousFix, targetFix);
+ while (!updatedCrsToIntercept.equal(crsToIntercept)) {
+ let interceptAngle = 0;
+ if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsToIntercept);
+ else interceptAngle = Math.abs(crsToIntercept - lastCourse);
+
+ let time = 0;
+ const increment = 0.1;
+ if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
+ if (leg.TurnDir === 'R') {
+ lastCourse = (lastCourse + increment).normaliseDegrees();
+ time = increment / turnRate;
+ } else {
+ lastCourse = (lastCourse - increment).normaliseDegrees();
+ time = increment / turnRate;
+ }
+ } else time = increment / turnRate;
+
+ const arcFix = computeDestinationPoint(
+ {
+ latitude: arc2.at(-1)![1],
+ longitude: arc2.at(-1)![0],
+ },
+ ((speed / 3600) * time).toMetre(),
+ lastCourse
+ );
+
+ arc2.push([arcFix.longitude, arcFix.latitude]);
+
+ // Update previousFix
+ previousFix.latitude = arcFix.latitude;
+ previousFix.longitude = arcFix.longitude;
+ updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
+
+ const newDistance = getPreciseDistance(previousFix, targetFix);
+ if (lastDistance <= newDistance && lastDistance < 25) break;
+ lastDistance = newDistance;
+ }
+ }
+
+ if (!arc) arc = arc2;
line.push(...arc);
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/CI.ts b/browser/src/parser/terminators/CI.ts
index a1bc65c..db07a76 100644
--- a/browser/src/parser/terminators/CI.ts
+++ b/browser/src/parser/terminators/CI.ts
@@ -68,6 +68,8 @@ export const TerminatorsCI = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([interceptFix.longitude, interceptFix.latitude]);
diff --git a/browser/src/parser/terminators/CR.ts b/browser/src/parser/terminators/CR.ts
index 7353cdd..3486961 100644
--- a/browser/src/parser/terminators/CR.ts
+++ b/browser/src/parser/terminators/CR.ts
@@ -27,6 +27,8 @@ export const TerminatorsCR = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([interceptFix.longitude, interceptFix.latitude]);
diff --git a/browser/src/parser/terminators/DF.ts b/browser/src/parser/terminators/DF.ts
index d2f6acc..47587ad 100644
--- a/browser/src/parser/terminators/DF.ts
+++ b/browser/src/parser/terminators/DF.ts
@@ -25,6 +25,8 @@ export const TerminatorsDF = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
let crsIntoEndpoint = getGreatCircleBearing(previousFix, targetFix);
diff --git a/browser/src/parser/terminators/FA.ts b/browser/src/parser/terminators/FA.ts
index fe87314..e9e2f47 100644
--- a/browser/src/parser/terminators/FA.ts
+++ b/browser/src/parser/terminators/FA.ts
@@ -35,6 +35,8 @@ export const TerminatorsFA = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/FC.ts b/browser/src/parser/terminators/FC.ts
index d499f32..87c8088 100644
--- a/browser/src/parser/terminators/FC.ts
+++ b/browser/src/parser/terminators/FC.ts
@@ -87,6 +87,8 @@ export const TerminatorsFC = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/FD.ts b/browser/src/parser/terminators/FD.ts
index c9cfe81..8b94420 100644
--- a/browser/src/parser/terminators/FD.ts
+++ b/browser/src/parser/terminators/FD.ts
@@ -48,6 +48,8 @@ export const TerminatorsFD = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/IF.ts b/browser/src/parser/terminators/IF.ts
index 18941af..66d8e74 100644
--- a/browser/src/parser/terminators/IF.ts
+++ b/browser/src/parser/terminators/IF.ts
@@ -10,6 +10,8 @@ export const TerminatorsIF = (leg: IFTerminalEntry, waypoint?: Waypoint): NavFix
speed: leg.SpeedLimit ? leg.SpeedLimit : Parser.AC_SPEED,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
return targetFix;
diff --git a/browser/src/parser/terminators/RF.ts b/browser/src/parser/terminators/RF.ts
index 8fa04c9..f29d3bb 100644
--- a/browser/src/parser/terminators/RF.ts
+++ b/browser/src/parser/terminators/RF.ts
@@ -17,6 +17,8 @@ export const TerminatorsRF = (
speed: computeSpeed(leg, previousFix),
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
const line = generateRFArc(
diff --git a/browser/src/parser/terminators/TF.ts b/browser/src/parser/terminators/TF.ts
index 4f169a4..118e8b8 100644
--- a/browser/src/parser/terminators/TF.ts
+++ b/browser/src/parser/terminators/TF.ts
@@ -3,7 +3,6 @@ import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance';
import Parser from '../parser';
import { generateTangentArc } from '../pathGenerators/generateTangentArc';
-import { computeIntersection } from '../utils/computeIntersection';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
@@ -25,6 +24,8 @@ export const TerminatorsTF = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
const crsIntoEndpoint = getGreatCircleBearing(previousFix, targetFix);
@@ -37,69 +38,6 @@ export const TerminatorsTF = (
arc1 = [[previousFix.longitude, previousFix.latitude]];
}
- if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint))) {
- const turnRate = computeTurnRate(speed, Parser.AC_BANK);
- let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
-
- // Turn Dir
- if (!leg.TurnDir || leg.TurnDir === 'E') {
- let prov = lastCourse - crsIntoEndpoint;
- prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
- leg.TurnDir = prov > 0 ? 'L' : 'R';
- }
-
- // Generate arc
- while (!updatedCrsToIntercept.equal(crsIntoEndpoint)) {
- let time = 0;
- if (leg.TurnDir === 'R') {
- //const delta = (crsIntoEndpoint - lastCourse).normaliseDegrees();
- const increment = 0.1; //delta < 1 ? delta : 1;
- lastCourse = (lastCourse + increment).normaliseDegrees();
- time = increment / turnRate;
- } else {
- //const delta = (lastCourse - crsIntoEndpoint).normaliseDegrees();
- const increment = 0.1; //delta < 1 ? delta : 1;
- lastCourse = (lastCourse - increment).normaliseDegrees();
- time = increment / turnRate;
- }
-
- const arcFix = computeDestinationPoint(
- {
- latitude: arc2.at(-1)![1],
- longitude: arc2.at(-1)![0],
- },
- ((speed / 3600) * time).toMetre(),
- lastCourse
- );
-
- arc2.push([arcFix.longitude, arcFix.latitude]);
-
- // Update previousFix
- previousFix.latitude = arcFix.latitude;
- previousFix.longitude = arcFix.longitude;
- updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
-
- let interceptAngle = 0;
- if (leg.TurnDir === 'R') interceptAngle = lastCourse - crsIntoEndpoint;
- else interceptAngle = crsIntoEndpoint - lastCourse;
-
- if (interceptAngle > 0 && interceptAngle <= 45) {
- const interceptFix: NavFix = {
- ...computeIntersection(previousFix, crsIntoEndpoint, targetFix, crsIntoEndpoint.reciprocalCourse())!,
- isFlyOver: leg.IsFlyOver,
- altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
- speed: speed,
- speedConstraint: leg.SpeedLimit,
- altitudeConstraint: leg.Alt,
- };
- if (interceptFix.latitude) line.push([interceptFix.longitude, interceptFix.latitude]);
-
- break;
- }
- }
- }
-
- // Decide on arc
let arc;
if (arc1 && arc1.length > 1) {
const endCrs = getGreatCircleBearing(
@@ -118,10 +56,61 @@ export const TerminatorsTF = (
);
if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1;
- else arc = arc2;
- } else {
- arc = arc2;
}
+
+ if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint))) {
+ const turnRate = computeTurnRate(speed, Parser.AC_BANK);
+ let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
+
+ // Turn Dir
+ if (!leg.TurnDir || leg.TurnDir === 'E') {
+ let prov = lastCourse - crsIntoEndpoint;
+ prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
+ leg.TurnDir = prov > 0 ? 'L' : 'R';
+ }
+
+ // Generate arc
+ let lastDistance = getPreciseDistance(previousFix, targetFix);
+ while (!updatedCrsToIntercept.equal(crsIntoEndpoint)) {
+ let interceptAngle = 0;
+ if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsIntoEndpoint);
+ else interceptAngle = Math.abs(crsIntoEndpoint - lastCourse);
+
+ let time = 0;
+ const increment = 0.1;
+ if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
+ if (leg.TurnDir === 'R') {
+ lastCourse = (lastCourse + increment).normaliseDegrees();
+ time = increment / turnRate;
+ } else {
+ lastCourse = (lastCourse - increment).normaliseDegrees();
+ time = increment / turnRate;
+ }
+ } else time = increment / turnRate;
+
+ const arcFix = computeDestinationPoint(
+ {
+ latitude: arc2.at(-1)![1],
+ longitude: arc2.at(-1)![0],
+ },
+ ((speed / 3600) * time).toMetre(),
+ lastCourse
+ );
+
+ arc2.push([arcFix.longitude, arcFix.latitude]);
+
+ // Update previousFix
+ previousFix.latitude = arcFix.latitude;
+ previousFix.longitude = arcFix.longitude;
+ updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
+
+ const newDistance = getPreciseDistance(previousFix, targetFix);
+ if (lastDistance <= newDistance && lastDistance < 25) break;
+ lastDistance = newDistance;
+ }
+ }
+
+ if (!arc) arc = arc2;
line.push(...arc);
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/VA.ts b/browser/src/parser/terminators/VA.ts
index 8254d50..2463009 100644
--- a/browser/src/parser/terminators/VA.ts
+++ b/browser/src/parser/terminators/VA.ts
@@ -32,6 +32,8 @@ export const TerminatorsVA = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/VD.ts b/browser/src/parser/terminators/VD.ts
index 3c45020..2a67b88 100644
--- a/browser/src/parser/terminators/VD.ts
+++ b/browser/src/parser/terminators/VD.ts
@@ -45,6 +45,8 @@ export const TerminatorsVD = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([targetFix.longitude, targetFix.latitude]);
diff --git a/browser/src/parser/terminators/VI.ts b/browser/src/parser/terminators/VI.ts
index c2c4c8b..466eb58 100644
--- a/browser/src/parser/terminators/VI.ts
+++ b/browser/src/parser/terminators/VI.ts
@@ -69,6 +69,8 @@ export const TerminatorsVI = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([interceptFix.longitude, interceptFix.latitude]);
diff --git a/browser/src/parser/terminators/VR.ts b/browser/src/parser/terminators/VR.ts
index 94f14a8..7694199 100644
--- a/browser/src/parser/terminators/VR.ts
+++ b/browser/src/parser/terminators/VR.ts
@@ -28,6 +28,8 @@ export const TerminatorsVR = (
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
+ IsFAF: leg.IsFAF,
+ IsMAP: leg.IsMAP,
};
line.push([interceptFix.longitude, interceptFix.latitude]);
diff --git a/browser/src/style.css b/browser/src/style.css
index d4b5078..73b707b 100644
--- a/browser/src/style.css
+++ b/browser/src/style.css
@@ -1 +1,15 @@
@import 'tailwindcss';
+
+@theme {
+ --animate-fade-in-scale: fade-in-scale 0.3s ease-out;
+ @keyframes fade-in-scale {
+ 0% {
+ opacity: 0;
+ transform: scale(0.95);
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
+ }
+}
diff --git a/browser/src/types/navdata.d.ts b/browser/src/types/navdata.d.ts
index e650321..290adab 100644
--- a/browser/src/types/navdata.d.ts
+++ b/browser/src/types/navdata.d.ts
@@ -85,9 +85,10 @@ export declare global {
speed?: number;
name?: string;
isFlyOver?: boolean;
- 'marker-color'?: string;
altitudeConstraint?: string;
speedConstraint?: number;
+ IsFAF?: boolean;
+ IsMAP?: boolean;
// For map
isIntersection?: boolean;
};