import { createSelector, OutputSelector } from 'reselect'; import Global from './Common'; import { Marker, Circle, Line, Polygon} from 'react-native-amap-kit'; import { latLngDegreesToDecimal, latLngDecimalToDegrees, isObject, isSafeString, hasPoint, isNumber } from './Utils' export { Marker, Circle, Line, Polygon }; let LatLon = require('geodesy').LatLonSpherical; declare namespace LatLon { export interface Spherical { lat: number; lon: number; bearingTo: (point: LatLon.Spherical) => number; destinationPoint: (distance: number, bearing: number, radius?: number) => LatLon.Spherical } } export interface CoordinateShort { lat: number; lng: number; } export interface CoordinateLong { latitude: number; longitude: number; } // Server export interface LatLngAddrServer extends CoordinateShort { addr: string; } export interface LatLngPointServer extends LatLngAddrServer { altitude: number; unit: 0 | 1 | 2 | 3; } export interface StartPointServer extends CoordinateShort { altitude: number; unit: 0 | 1 | 2 | 3; } export interface AirRoutePoint extends CoordinateShort { point_id: number; point_name: string; point_code: string; } // Passpoints export interface PassingPointNavServer extends CoordinateShort { point_type: 1; altitude: number; unit: 0 | 1 | 2 | 3; point_id: number; point_code: string; point_name: string; } export interface PassingPointAirlineServer { point_type: 2; altitude: number; unit: 0 | 1 | 2 | 3; airway?: number; air_route_code: string; points: Array; } export interface PassingPointNormalServer extends CoordinateShort{ point_type: 3; altitude: number; unit: 0 | 1 | 2 | 3; point_name: string; } // Airspace export interface AirspaceInfoCircleServer { airspace_name: string; airspace_type: 1; airspace_id: string; note: string; center_loc: string; center_point_of_flying: CoordinateShort; radius_of_flying: number; altitude: number; unit: number; free_draw?: boolean; } export interface AirspaceInfoLineServer { airspace_name: string; airspace_type: 2; airspace_id: string; note: string; start_loc: string; start_point: StartPointServer; end_loc: string; end_point: CoordinateShort; passing_points: Array; airline_width?: number; free_draw?: boolean; } export interface AirspaceInfoPolygonServer { airspace_name: string; airspace_type: 3; airspace_id: string; note: string; points: Array; altitude: number; unit: number; free_draw?: boolean; } // Local export interface CoordinateShort { lat: number; lng: number; } export interface LatLngAddrLocal extends CoordinateShort { addr: string; } export interface LatLngPointLocal extends LatLngAddrLocal{ height: string; heightStandard: string; } // Passpoint export interface PassingPointNavLocal extends CoordinateShort { pointType: 1; height: string; heightStandard: string; pointId: number; pointCode: string; pointName: string; } export interface PassingPointAirlineLocal { pointType: 2; height: string; heightStandard: string; airRouteId: number; airlineCode: string; airlines: Array; } export interface PassingPointNormalLocal extends CoordinateShort { pointType: 3; height: string; heightStandard: string; addr: string; } // Airspace export interface AirspaceInfoCircleLocal { airspaceType: 1; airspaceId: string; name: string; note: string; addr: string; lat: number; lng: number; radius: number; height: string; heightStandard: string; isDraw?: boolean; } export interface AirspaceInfoLineLocal { airspaceType: 2; airspaceId: string; name: string; note: string; dep: LatLngPointLocal; arrive: LatLngAddrLocal; passPoints: Array; airlineWidth?: number; isDraw?: boolean; } export interface AirspaceInfoPolygonLocal { airspaceType: 3; airspaceId: string; name: string; note: string; polygonPoints: Array; height: string; heightStandard: string; isDraw?: boolean; } declare type AirspaceInfoCircle = AirspaceInfoCircleLocal | AirspaceInfoCircleServer; declare type AirspaceInfoLine = AirspaceInfoLineLocal | AirspaceInfoLineServer; declare type AirspaceInfoPolygon = AirspaceInfoPolygonLocal | AirspaceInfoPolygonServer; declare type AirspaceInfoLocal = AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal; declare type AirspaceInfoServer = AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer; declare type AirspaceInfo = AirspaceInfoLocal | AirspaceInfoServer declare type PassingPointNav = PassingPointNavLocal | PassingPointNavServer declare type PassingPointNormal = PassingPointNormalLocal | PassingPointNormalServer declare type PassingPointAirline = PassingPointAirlineLocal | PassingPointAirlineServer declare type PassingPointLocal = PassingPointNavLocal | PassingPointNormalLocal | PassingPointAirlineLocal declare type PassingPointServer = PassingPointNavServer | PassingPointNormalServer | PassingPointAirlineServer declare type PassingPoint = PassingPointLocal | PassingPointServer // shapes export type Coordinate = CoordinateLong | CoordinateShort export interface CirclesAndMarkers { circles: Circle[]; markers: Marker[]; } export interface LinesAndMarkes { lines: Line[]; markers: Marker[]; } export interface LinesPolygonsAndMarkers { polygons: Polygon[]; markers: Marker[]; lines: Line[]; } export interface PolygonsAndMarkers { polygons: Polygon[]; markers: Marker[]; } export interface ShapeStyle { imageName: string; lineWidth: number; strokeColor: string; fillColor: string; } export interface ShapeStyles { [styleName: string]: ShapeStyle } export function convertAirspaceInfoServerToLocal(airspaceInfo : AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer) : AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal | null { const airspaceType = airspaceInfo.airspace_type if (airspaceType == Global.airspaceType.circle) { const ai: AirspaceInfoCircleServer = airspaceInfo return { airspaceType, airspaceId: ai.airspace_id, name: ai.airspace_name, note: ai.note, addr: ai.center_loc, lat: ai.center_point_of_flying.lat, lng: ai.center_point_of_flying.lng, radius: ai.radius_of_flying, height: ai.altitude + "", heightStandard: Global.heightStandardsById.get(ai.unit), isDraw: ai.free_draw? ai.free_draw: false }; } if (airspaceType == Global.airspaceType.line) { const ai: AirspaceInfoLineServer = airspaceInfo let dep = { addr: ai.start_loc, lat: ai.start_point.lat, lng: ai.start_point.lng, height: ai.start_point.altitude + "", heightStandard: Global.heightStandardsById.get(ai.start_point.unit) } let arrive = { addr: ai.end_loc, lat: ai.end_point.lat, lng: ai.end_point.lng } let passPoints: (PassingPointNavLocal | PassingPointAirlineLocal | PassingPointNormalLocal)[] = [] if(Array.isArray(ai.passing_points)) { for(let obj of ai.passing_points) { let point: PassingPointNavLocal | PassingPointAirlineLocal | PassingPointNormalLocal; if (obj.point_type == Global.pointTypes.point) { const pp = obj; const lat = pp.lat const lng = pp.lng point = { pointType: pp.point_type, addr: pp.point_name, lat, lng } } else if (obj.point_type == Global.pointTypes.nav) { const pp = obj; const lat = pp.lat const lng = pp.lng point = { pointType: pp.point_type, pointId: pp.point_id, pointCode: pp.point_code, pointName: pp.point_name, lat, lng } } else { const pp = obj; point = { pointType: pp.point_type, airRouteId: pp.airway, airlineCode: pp.air_route_code, airlines: pp.points } } if(isNumber(obj.altitude) && isNumber(obj.unit)) { point.height = obj.altitude + ""; point.heightStandard = Global.heightStandardsById.get(obj.unit); } else { point.height = "" point.heightStandard = [...Global.heightStandards.keys()][0]; } passPoints.push(point) } } return { ...{ airspaceType, airspaceId: ai.airspace_id, name: ai.airspace_name, note: ai.note, dep, arrive, passPoints, isDraw: ai.free_draw? ai.free_draw: false }, ...(ai.airline_width ? {airlineWidth: ai.airline_width} : {})} } if (airspaceType == Global.airspaceType.polygon) { const ai = airspaceInfo; if(Array.isArray(ai.points)) { let polygonPoints = new Array(); let defaultPointName = 'A' for(let obj of ai.points) { let addr = obj.addr if(!addr) { addr = defaultPointName defaultPointName = String.fromCharCode(defaultPointName.charCodeAt(0) + 1) } polygonPoints.push({addr, lat: obj.lat, lng: obj.lng}) } return { airspaceType, airspaceId: ai.airspace_id, name: ai.airspace_name, note: ai.note, height: ai.altitude + '', heightStandard: Global.heightStandardsById.get(ai.unit), polygonPoints, isDraw: ai.free_draw? ai.free_draw: false }; } } return null; } export function convertAirspaceInfoLocalToServer(airspace : AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal) : AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer { if (airspace.airspaceType == Global.airspaceType.circle) { const ai = airspace; const circle = { airspace_name: ai.name, airspace_id: ai.airspaceId, airspace_type: Global.airspaceType.circle, note: isSafeString(ai.note) ? ai.note : null, radius_of_flying: parseInt(ai.radius + ''), center_point_of_flying: { lng: ai.lng, lat: ai.lat }, center_loc: ai.addr, altitude: parseInt(ai.height), unit: Global.heightStandards.get(ai.heightStandard), free_draw: ai.isDraw? ai.isDraw: false }; return circle } else if (airspace.airspaceType == Global.airspaceType.line) { const ai = airspace; let line = { airspace_name: ai.name, airspace_id: ai.airspaceId, airspace_type: Global.airspaceType.line, note: ai.note, start_loc: ai.dep.addr, start_point: { lng: ai.dep.lng, lat: ai.dep.lat, altitude: parseInt(ai.dep.height), unit: Global.heightStandards.get(ai.dep.heightStandard) }, end_loc: ai.arrive.addr, end_point: { lng: ai.arrive.lng, lat: ai.arrive.lat }, free_draw: ai.isDraw? ai.isDraw: false } if(ai.airlineWidth) { line['airline_width'] = ai.airlineWidth } if (Array.isArray(ai.passPoints) && ai.passPoints.length > 0) { let passing_points = []; for (let obj of ai.passPoints) { let retObj: PassingPointNormalServer | PassingPointNavServer | PassingPointAirlineServer; if (obj.pointType == Global.pointTypes.point && hasPoint(obj)) { const pp = obj; retObj = { point_type: Global.pointTypes.point, point_name: pp.addr, lat: pp.lat, lng: pp.lng }; } else if (obj.pointType == Global.pointTypes.nav) { const pp = obj; retObj = { point_type: Global.pointTypes.nav, point_name: pp.pointName, point_id: pp.pointId, point_code: pp.pointCode, lat: pp.lat, lng: pp.lng }; } else { const pp = obj; retObj = { point_type: Global.pointTypes.line, airway: pp.airRouteId, air_route_code: pp.airlineCode, points: pp.airlines }; } if (isSafeString(obj.height) && isSafeString(obj.heightStandard)) { retObj.altitude = parseInt(obj.height); // @ts-ignore retObj.unit = Global.heightStandards.get(obj.heightStandard); } passing_points.push(retObj) } line.passing_points = passing_points; } else { line.passing_points = []; } return line; } else { const ai = airspace; const polygon = { airspace_name: ai.name, airspace_id: ai.airspaceId, airspace_type: Global.airspaceType.polygon, note: ai.note, altitude: parseInt(ai.height), unit: Global.heightStandards.get(ai.heightStandard), points: ai.polygonPoints, free_draw: ai.isDraw? ai.isDraw: false }; return polygon; } } function getCircleRegions(circle: Circle): CoordinateShort[] { let lat, lng; if((circle.coordinate as any).latitude) { let coord = circle.coordinate; lat = coord.latitude; lng = coord.longitude; } else { let coord = circle.coordinate; lat = coord.lat; lng = coord.lng; } let latlon = new LatLon(lat, lng) let d1 = latlon.destinationPoint(circle.radius, 0) let d2 = latlon.destinationPoint(circle.radius, 90) let d3 = latlon.destinationPoint(circle.radius, 180) let d4 = latlon.destinationPoint(circle.radius, 270) return [{ lat: d1.lat, lng: d1.lon }, { lat: d2.lat, lng: d2.lon }, { lat: d3.lat, lng: d3.lon }, { lat: d4.lat, lng: d4.lon }] } function getDefaultStyle(): ShapeStyle { let imageName = 'BA_oval' let lineWidth = Global.amapLineWidth let strokeColor = Global.amapStrokeColor let fillColor = Global.amapFillColor return {imageName, lineWidth, strokeColor, fillColor} } function getCirclesAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: (styleName: string) => ShapeStyle | null, currentAirspaceIndex: number | undefined): CirclesAndMarkers { let circles: Circle[] = []; let markers: Marker[] = []; if (!Array.isArray(airspaceInfos)) { return {circles, markers}; } let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle() //通过该方法获取样式 let circleStyle = setStyle('circle'); if(circleStyle) { lineWidth = circleStyle.lineWidth strokeColor = circleStyle.strokeColor fillColor = circleStyle.fillColor imageName = circleStyle.imageName } for (let i = 0; i < airspaceInfos.length; i++) { let tmpCircle = airspaceInfos[i] let airspaceTypeFix, radiusFix if ((tmpCircle as any).airspaceType) { airspaceTypeFix = 'airspaceType'; radiusFix = 'radius' } else { airspaceTypeFix = 'airspace_type'; radiusFix = 'radius_of_flying' } if ((tmpCircle as any)[airspaceTypeFix] == Global.airspaceType.circle && currentAirspaceIndex != i) { let coordinate = {latitude: 0, longitude: 0}; if ((tmpCircle as any).center_point_of_flying) { let ai = tmpCircle; coordinate.latitude = ai.center_point_of_flying.lat; coordinate.longitude = ai.center_point_of_flying.lng; } else { let ai = tmpCircle; coordinate.latitude = ai.lat; coordinate.longitude = ai.lng; } let radius = (tmpCircle as any)[radiusFix]; if(radius) { let circle = {lineWidth, strokeColor, fillColor, radius, coordinate} circles.push(circle); } else { markers.push(addOvalPointConfig(coordinate.latitude, coordinate.longitude, imageName)); } } } return {circles, markers}; } function getCircleAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: (styleName: string)=> ShapeStyle | null, currentAirspaceIndex: () => number | undefined) { return createSelector( airspaceInfos, () => setStyle, currentAirspaceIndex, getCirclesAndMarkers ); } function drawLineConfig(lat: number, lng: number) { return { latitude: lat, longitude: lng }; } function addOvalPointConfig(lat: number, lng: number, imageName: string) { return { coordinate: { latitude: lat, longitude: lng }, imageName: imageName }; } function pointCompare(point1: AirRoutePoint | undefined, point2: AirRoutePoint | undefined) { if (!point1 || !point2) { return false } const pointId1 = point1.point_id; const pointId2 = point2.point_id; if(pointId1 == pointId2) { return true; } let [point1Lat, point1lng] = getFixedLatLng(point1) let [point2lat, point2lng] = getFixedLatLng(point2) if(myRound(point1Lat) == myRound(point2lat) && myRound(point1lng) == myRound(point2lng)) { return true } else { return false } } function getCrossPoint(points1: AirRoutePoint[], points2: AirRoutePoint[]) { for(let point1 of points1) { for(let point2 of points2) { if (pointCompare(point1, point2)) return point1 } } return undefined } function getAirwayPoints(airway: PassingPointAirline, pointBefore: PassingPoint, pointAfter: PassingPoint) { let found = 0 let points = [] let pointTypeFix, pointsFix, airRoutePoint if ('points' in airway) { pointTypeFix = 'point_type'; pointsFix = 'points' airRoutePoint = airway['points'] } else { pointTypeFix = 'pointType' pointsFix = 'airlines' airRoutePoint = airway['airlines'] } let crossPointBefore, crossPointAfter; // 如果前后是其他航线,那么找到交叉点作为前后的点 if ( (pointBefore as any)[pointTypeFix] == Global.pointTypes.line ) { crossPointBefore = getCrossPoint(airRoutePoint, (pointBefore as any)[pointsFix]) } if((pointAfter as any)[pointTypeFix] == Global.pointTypes.line) { crossPointAfter = getCrossPoint(airRoutePoint, (pointAfter as any)[pointsFix]) } for (let point of airRoutePoint) { if (pointCompare(crossPointBefore, point) || pointCompare(crossPointAfter, point)) { found++ points.push(Object.assign({}, point)) continue } if (found == 1) { points.push(Object.assign({}, point)) } } if (!(points.length > 0 && found == 2)) { // 如果两个点不全在航线上面,那么画全部航线 points = airRoutePoint } return points; } function getLinesRouter(lineProps: AirspaceInfoLine, lineAndMarkerStyle: ShapeStyle | null) { let coordinates: Coordinate[] = new Array(); let markers: Marker[] = new Array(); let lines: Line[] = [] let {imageName, lineWidth, strokeColor} = getDefaultStyle() if (lineAndMarkerStyle) { imageName = lineAndMarkerStyle.imageName lineWidth = lineAndMarkerStyle.lineWidth strokeColor = lineAndMarkerStyle.strokeColor } let startPoint, passPoints, endPoint, pointTypeFix, airlineWidth if ((lineProps as any).start_point) { let ll = lineProps; startPoint = ll['start_point'] passPoints = ll['passing_points'] endPoint = ll['end_point'] pointTypeFix = 'point_type'; airlineWidth = parseInt(ll['airline_width'] + '', 10) } else { let ll = lineProps; startPoint = ll['dep'] passPoints = ll['passPoints'] endPoint = ll['arrive'] pointTypeFix = 'pointType' airlineWidth = parseInt(ll['airlineWidth'] + '', 10) } if (startPoint) { coordinates.push(drawLineConfig(startPoint.lat, startPoint.lng)); markers.push(addOvalPointConfig(startPoint.lat, startPoint.lng, imageName)); } if (Array.isArray(passPoints)) { for (let i = 0; i < passPoints.length; i++) { let obj = passPoints[i] if (!isObject(obj)) { // 所有的 points/airway 都必须是 obj continue; } let pointType = (obj as any)[pointTypeFix] if ( pointType == Global.pointTypes.point || pointType == Global.pointTypes.nav) { let pp = obj coordinates.push(drawLineConfig(pp.lat, pp.lng)); markers.push(addOvalPointConfig(pp.lat, pp.lng, imageName)); } else { // 遇到一个航线,不需要和前前面的点连起来 let pp = obj if (coordinates.length > 1) { lines.push({lineWidth, strokeColor, coordinates}) } coordinates = [] const pointBefore = i == 0 ? startPoint : passPoints[i - 1] const pointAfter = i == passPoints.length - 1 ? (endPoint ? endPoint : passPoints[passPoints.length - 1]) : passPoints[i + 1] lines.push({lineWidth, strokeColor, coordinates: getAirwayPoints(pp, pointBefore, pointAfter)}) } } } if (endPoint) { coordinates.push(drawLineConfig(endPoint.lat, endPoint.lng)); markers.push(addOvalPointConfig(endPoint.lat, endPoint.lng, imageName)); } if (coordinates.length > 1) { lines.push({lineWidth, strokeColor, coordinates}); } if(airlineWidth > 0) { // 有宽度的空域,需要线周围多画宽度的多边形 let polygons = processAirlineWidth(lines, airlineWidth) return { lines, markers, polygons }; } else { return { lines, markers, polygons: [] }; } } function getFixedLatLng(point: {lat?: string | number, lng?: string | number, latitude?: string | number, longitude?: string | number}): [number, number] { let pp = point; let lat = pp.latitude ? pp.latitude : pp.lat let lng = pp.longitude ? pp.longitude : pp.lng return [lat, lng] } function processAirlineWidth(lines: Line[], airlineWidth: number) { let polygons: Polygon[] = [] let {strokeColor, fillColor} = getDefaultStyle() for(let line of lines) { let points = line.coordinates for(let i=0; itmpLine; let { lines, markers, polygons } = getLinesRouter(lineProps, lineStyle); retMarkers.push(...markers); retLines.push(...lines); retPolygons.push(...polygons) } } return { lines: retLines, markers: retMarkers, polygons: retPolygons }; } function getLinePolygonsAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) { return createSelector( airspaceInfos, () => setStyle, currentAirspaceIndex, getLinesPolygonsAndMarkers ); } function getPolygon(polygonProps: AirspaceInfoPolygon, polygonAndMarkerStyle: ShapeStyle | null) { let coordinates: Coordinate[] = new Array(); let markers: Marker[] = new Array(); let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle() if (polygonAndMarkerStyle) { imageName = polygonAndMarkerStyle.imageName lineWidth = polygonAndMarkerStyle.lineWidth strokeColor = polygonAndMarkerStyle.strokeColor fillColor = polygonAndMarkerStyle.fillColor } let pointsFix; if ((polygonProps as any).points) { pointsFix = 'points'; } else { pointsFix = 'polygonPoints'; } if (Array.isArray((polygonProps as any)[pointsFix])) { for (let obj of (polygonProps as any)[pointsFix]) { if (!obj) { continue } coordinates.push(drawLineConfig(obj.lat, obj.lng)); markers.push(addOvalPointConfig(obj.lat, obj.lng, imageName)); } } let polygon = {lineWidth, strokeColor, fillColor, coordinates}; return { markers, polygon }; } function getPolygonsAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: number | undefined): PolygonsAndMarkers { let markers: Marker[] = []; let polygons: Polygon[] = []; if (!Array.isArray(airspaceInfos)) { return { markers, polygons }; } let polygonAndMarkerStyle = setStyle('polygon'); for (let i = 0; i < airspaceInfos.length; i++) { let polygon = airspaceInfos[i] let airspaceTypeFix; if ((polygon as any).airspaceType) airspaceTypeFix = 'airspaceType'; else airspaceTypeFix = 'airspace_type'; if ((polygon as any)[airspaceTypeFix] == Global.airspaceType.polygon && currentAirspaceIndex != i) { let retObj = getPolygon(polygon, polygonAndMarkerStyle); markers.push(...retObj.markers); polygons.push(retObj.polygon); } } return { markers, polygons }; } function getPolygonAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) { return createSelector( airspaceInfos, () => setStyle, currentAirspaceIndex, getPolygonsAndMarkers ); } function getMarkers(circlesAndMarkers: CirclesAndMarkers, polygonAndMarkers: PolygonsAndMarkers, lineAndMarkers: LinesAndMarkes) { let markers: Marker[] = []; if (circlesAndMarkers) { markers = [...circlesAndMarkers.markers] } if (polygonAndMarkers) { markers = [...markers, ...polygonAndMarkers.markers] } if (lineAndMarkers) { markers = [...markers, ...lineAndMarkers.markers] } return markers } function getMarkerSelector( circlesAndMarkers: OutputSelector CirclesAndMarkers>, polygonAndMarkers: OutputSelector PolygonsAndMarkers>, lineAndMarkers: OutputSelector LinesAndMarkes>) { return createSelector( circlesAndMarkers, polygonAndMarkers, lineAndMarkers, getMarkers ) } function getRegionPoints(circles: Circle[], lineAndMarkers: LinesAndMarkes, polygonAndMarkers: PolygonsAndMarkers) { let regionPoints: Coordinate[] = new Array(); for (let i = 0; i < circles.length; i++) { regionPoints.push(...getCircleRegions(circles[i])); } let lines = lineAndMarkers.lines; for (let i = 0; i < lines.length; i++) { regionPoints.push(...lines[i].coordinates); } let polygons = polygonAndMarkers.polygons; for (let i = 0; i < polygons.length; i++) { regionPoints.push(...polygons[i].coordinates); } return regionPoints; } function getRegionPointsSelector( circles: OutputSelectorCircle[]>, lineAndMarkers: OutputSelectorLinesAndMarkes>, polygonAndMarkers: OutputSelectorPolygonsAndMarkers>) { return createSelector( circles, lineAndMarkers, polygonAndMarkers, getRegionPoints ); } function getCircles(circlesAndMarkers: CirclesAndMarkers) { return circlesAndMarkers.circles; } function getCircleSelector(circlesAndMarkers: OutputSelector CirclesAndMarkers>) { return createSelector( circlesAndMarkers, getCircles ); } function getLines(lineAndMarker: LinesAndMarkes) { return lineAndMarker.lines; } function getLineSelector(lineAndMarker: OutputSelectorLinesAndMarkes>) { return createSelector( lineAndMarker, getLines ); } function getPolygons(polygonAndMarkers: PolygonsAndMarkers, linePolygonsAndMarkers: LinesPolygonsAndMarkers) { return [...polygonAndMarkers.polygons, ...linePolygonsAndMarkers.polygons]; } function getPolygonSelector( polygonAndMarkers: OutputSelector PolygonsAndMarkers>, linePolygonsAndMarkers: OutputSelector LinesPolygonsAndMarkers>) { return createSelector( polygonAndMarkers, linePolygonsAndMarkers, getPolygons ); } export type FnSetStyle = (styleName: string) => null | ShapeStyle let setStyle: (style: undefined | ShapeStyles) => FnSetStyle = (styles) => { if (!styles) return () => null else return (shapeName: string): ShapeStyle => styles[shapeName] } //获取selector export function getShapesSelector(airspaceInfos: () => AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: () => number | undefined) { currentAirspaceIndex = currentAirspaceIndex ? currentAirspaceIndex : () => -1; let circlesAndMarkers = getCircleAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex); let circles = getCircleSelector(circlesAndMarkers); let linePolygonsAndMarkers = getLinePolygonsAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex); let lines = getLineSelector(linePolygonsAndMarkers); let polygonAndMarkers = getPolygonAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex); let polygons = getPolygonSelector(polygonAndMarkers, linePolygonsAndMarkers); let markers = getMarkerSelector(circlesAndMarkers, polygonAndMarkers, linePolygonsAndMarkers); let regionPoints = getRegionPointsSelector(circles, linePolygonsAndMarkers, polygonAndMarkers); return { markers, circles, lines, polygons, regionPoints } } //获取数组 export function getShapes(airspaceInfos: AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: number) { let {markers, polygons, circles, lines, regionPoints} = getShapesSelector(()=>airspaceInfos, style, ()=>currentAirspaceIndex) return { markers: markers(airspaceInfos), circles: circles(airspaceInfos), lines: lines(airspaceInfos), polygons: polygons(airspaceInfos), regionPoints: regionPoints(airspaceInfos) } } // 总共 5 种格式, http://git.corp.brilliantaero.com/BA/Coco/issues/99#note_6358 // 1. 全输出格式 // 2. 简化格式 // 3. 传真格式 // 4. 用户端用的简化格式 // 5. 极简格式 function getHeight(height: number | string, unit: string | number, type: number) { let shortNum const num = +height; // to number if(num >= 100) { shortNum = parseInt(num/100 + '').toString() if(shortNum.length <2) { shortNum = '0' + shortNum } } let heightStandard = Global.heightStandardsById.get(unit) if(!heightStandard) { heightStandard = unit } // 这里统一使用数字判断 let standardUnit = Global.heightStandards.get(heightStandard) let heightDesc switch(standardUnit) { case 1: heightDesc = ['H*真', '真高*米'] break; case 2: heightDesc = ['H*标(含以下)', '标高*米(含以下)'] break; case 3: heightDesc = ['H*真(含以下)', '真高*米(含以下)'] break; default: heightDesc = ['H*标', '标高*米'] } if(shortNum && (type == 1 || type == 2)) { // H02真,H02真(含以下) return heightDesc[0].replace('*', shortNum) } else { // 真高200米,真高200米(含以下) return heightDesc[1].replace('*', height + '') } } function getAirspaceName(airspaceInfo: AirspaceInfo) { if((airspaceInfo as any).airspace_name) { const ai = airspaceInfo; return ai.airspace_name } else { const ai = airspaceInfo; return ai.name } } export function circleContent(airspaceInfo: AirspaceInfoCircle, type=3) { if(type == 5) return getAirspaceName(airspaceInfo) if('airspace_name' in airspaceInfo) { const lat = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lat); const lng = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lng); let content = []; let loc = `以${airspaceInfo.center_loc}` if(type == 1 || type == 3) loc += `(E${lng}, N${lat})`; content.push(`${loc}为中心`) content.push(`半径${airspaceInfo.radius_of_flying}米`); content.push(getHeight(airspaceInfo.altitude, airspaceInfo.unit, type)) if (airspaceInfo.note) content.push(`备注:${airspaceInfo.note}`) return content.join(','); } else { let content = [] let loc = `以${airspaceInfo.addr}` if(type == 1 || type == 3) loc += `(E${latLngDecimalToDegrees(airspaceInfo.lng)}, N${latLngDecimalToDegrees(airspaceInfo.lat)})`; content.push(`${loc}为中心`) content.push(`半径${airspaceInfo.radius}米`); content.push(getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type)) if (airspaceInfo.note) content.push(`备注:${airspaceInfo.note}`) return content.join(','); } } function flyingCenter(item: CoordinateShort | {} = {}): string{ if(item == {}){ return ""; } const pp = item; return ( "(E" + latLngDecimalToDegrees(pp.lng) + ', ' + "N" + latLngDecimalToDegrees(pp.lat) + ")" ); } export function lineContent(airspaceInfo: AirspaceInfoLine, type=3): string { if(type == 5) return getAirspaceName(airspaceInfo) if('airspace_name' in airspaceInfo) { let content = []; content.push(`${airspaceInfo.start_loc}`) if(type == 1 || type == 3) content.push(`${flyingCenter(airspaceInfo.start_point)}`) content.push(` - `) content.push(getHeight(airspaceInfo.start_point.altitude, airspaceInfo.start_point.unit, type)) const passing_points = airspaceInfo.passing_points; if(Array.isArray(passing_points)) { for(let i = 0; i < passing_points.length; i++) { const obj = passing_points[i]; if (obj.point_type == Global.pointTypes.point) { let pp = obj; const lat = latLngDecimalToDegrees(pp.lat) const lng = latLngDecimalToDegrees(pp.lng) content.push(` - ${pp.point_name}`) if(type == 1 || type == 3) content.push(`(E${lng}, N${lat})`) } else if (obj.point_type == Global.pointTypes.nav) { let pp = obj; const lat = latLngDecimalToDegrees(pp.lat) const lng = latLngDecimalToDegrees(pp.lng) content.push(` - ${pp.point_code}`) if(type == 1 || type == 3) content.push(`(E${lng}, N${lat})`) } else { let pp = obj; content.push(` - ${pp.air_route_code}`) } if(obj.altitude) { content.push(` - ${getHeight(obj.altitude, obj.unit, type)}`) } } } content.push(` - ${airspaceInfo.end_loc}`) if(type == 1 || type == 3) content.push(`${flyingCenter(airspaceInfo.end_point)}`) if(isSafeString(airspaceInfo.airline_width)) { content.push(`,宽度:${airspaceInfo.airline_width}米`) } if(isSafeString(airspaceInfo.note)) { content.push(`,备注: ${airspaceInfo.note}`) } let result = content.join("") return result; } else { let content = []; content.push(`${airspaceInfo.dep.addr}`) if(type == 1 || type == 3) content.push(`(E${latLngDecimalToDegrees(airspaceInfo.dep.lng)}, N${latLngDecimalToDegrees(airspaceInfo.dep.lat)})`) content.push(` - ${getHeight(airspaceInfo.dep.height, airspaceInfo.dep.heightStandard, type)}`); if (Array.isArray(airspaceInfo.passPoints)) { let length = airspaceInfo.passPoints.length; for (let i = 0; i < length; i++) { let obj = airspaceInfo.passPoints[i]; if (obj.pointType == Global.pointTypes.point) { let pp = obj; content.push(` - ${pp.addr}`) if(type == 1 || type == 3) content.push(`(E${latLngDecimalToDegrees(pp.lng)}, N${latLngDecimalToDegrees(pp.lat)})`); } else if (obj.pointType == Global.pointTypes.nav) { let pp = obj; content.push(` - ${pp.pointCode}`) if(type == 1 || type == 3) content.push(`(E${latLngDecimalToDegrees(pp.lng)}, N${latLngDecimalToDegrees(pp.lat)})`); } else { let pp = obj; content.push(` - ${pp.airlineCode}`); } if(obj.height) { content.push(` - ${getHeight(obj.height, obj.heightStandard, type)}`) } } } content.push(` - ${airspaceInfo.arrive.addr}`) if(type == 1 || type == 3) content.push(`(E${latLngDecimalToDegrees(airspaceInfo.arrive.lng)}, N${latLngDecimalToDegrees(airspaceInfo.arrive.lat)})`); if(airspaceInfo.airlineWidth) { content.push(`,宽度:${airspaceInfo.airlineWidth}米`) } if (airspaceInfo.note) content.push(`,备注:${airspaceInfo.note}`) return content.join(''); } } export function polygonContent(airspaceInfo: AirspaceInfoPolygon, type=3): string { if(type == 5) return getAirspaceName(airspaceInfo) if('airspace_name' in airspaceInfo) { let res = [] let points = airspaceInfo.points for (let i = 0; i < points.length; i++) { let c = `${points[i].addr ? points[i].addr : ''}` if(type == 1 || type == 3) c += `(E${latLngDecimalToDegrees(points[i].lng)}, N${latLngDecimalToDegrees(points[i].lat)})`; res.push(c) } let content = [res.join('、')] content.push(`${airspaceInfo.points.length}点连线范围内`) content.push(`,${getHeight(airspaceInfo.altitude, airspaceInfo.unit, type)}`) if(isSafeString(airspaceInfo.note)) { content.push(`,备注:${airspaceInfo.note}`) } return content.join(''); } else { let content = []; let length = airspaceInfo.polygonPoints.length; for (let i = 0; i < length; i++) { let obj = airspaceInfo.polygonPoints[i]; let c = `${obj.addr ? obj.addr : ''}` if(type == 1 || type == 3) c += `(E${latLngDecimalToDegrees(obj.lng)}, N${latLngDecimalToDegrees(obj.lat)})` content.push(c) } let cc = content.join('、') + `${length}点连线范围内` cc += `,${getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type)}` if (airspaceInfo.note) cc += `,备注:${airspaceInfo.note}` return cc; } } export {latLngDegreesToDecimal, latLngDecimalToDegrees}