index.ts 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. import { createSelector, OutputSelector } from 'reselect';
  2. import Global from './Common';
  3. import { Marker, Circle, Line, Polygon} from 'react-native-amap-kit';
  4. import {
  5. latLngDegreesToDecimal,
  6. latLngDecimalToDegrees,
  7. isObject,
  8. isSafeString,
  9. hasPoint,
  10. isNumber
  11. } from './Utils'
  12. export { Marker, Circle, Line, Polygon };
  13. let LatLon = require('geodesy').LatLonSpherical;
  14. declare namespace LatLon {
  15. export interface Spherical {
  16. lat: number;
  17. lon: number;
  18. bearingTo: (point: LatLon.Spherical) => number;
  19. destinationPoint: (distance: number, bearing: number, radius?: number) => LatLon.Spherical
  20. }
  21. }
  22. export interface CoordinateShort {
  23. lat: number;
  24. lng: number;
  25. }
  26. export interface CoordinateLong {
  27. latitude: number;
  28. longitude: number;
  29. }
  30. // Server
  31. export interface LatLngAddrServer extends CoordinateShort {
  32. addr: string;
  33. }
  34. export interface LatLngPointServer extends LatLngAddrServer {
  35. altitude: number;
  36. unit: 0 | 1 | 2 | 3;
  37. }
  38. export interface StartPointServer extends CoordinateShort {
  39. altitude: number;
  40. unit: 0 | 1 | 2 | 3;
  41. }
  42. export interface AirRoutePoint extends CoordinateShort {
  43. point_id: number;
  44. point_name: string;
  45. point_code: string;
  46. }
  47. // Passpoints
  48. export interface PassingPointNavServer extends CoordinateShort {
  49. point_type: 1;
  50. altitude: number;
  51. unit: 0 | 1 | 2 | 3;
  52. point_id: number;
  53. point_code: string;
  54. point_name: string;
  55. }
  56. export interface PassingPointAirlineServer {
  57. point_type: 2;
  58. altitude: number;
  59. unit: 0 | 1 | 2 | 3;
  60. airway?: number;
  61. air_route_code: string;
  62. points: Array<AirRoutePoint>;
  63. }
  64. export interface PassingPointNormalServer extends CoordinateShort{
  65. point_type: 3;
  66. altitude: number;
  67. unit: 0 | 1 | 2 | 3;
  68. point_name: string;
  69. }
  70. // Airspace
  71. export interface AirspaceInfoCircleServer {
  72. airspace_name: string;
  73. airspace_type: 1;
  74. airspace_id: string;
  75. note: string;
  76. center_loc: string;
  77. center_point_of_flying: CoordinateShort;
  78. radius_of_flying: number;
  79. altitude: number;
  80. unit: number;
  81. }
  82. export interface AirspaceInfoLineServer {
  83. airspace_name: string;
  84. airspace_type: 2;
  85. airspace_id: string;
  86. note: string;
  87. start_loc: string;
  88. start_point: StartPointServer;
  89. end_loc: string;
  90. end_point: CoordinateShort;
  91. passing_points: Array<PassingPointServer>;
  92. airline_width?: number;
  93. }
  94. export interface AirspaceInfoPolygonServer {
  95. airspace_name: string;
  96. airspace_type: 3;
  97. airspace_id: string;
  98. note: string;
  99. points: Array<LatLngAddrServer>;
  100. altitude: number;
  101. unit: number;
  102. }
  103. // Local
  104. export interface CoordinateShortString {
  105. lat: string;
  106. lng: string;
  107. }
  108. export interface LatLngAddrLocal extends CoordinateShortString {
  109. addr: string;
  110. }
  111. export interface LatLngPointLocal extends LatLngAddrLocal{
  112. height: string;
  113. heightStandard: string;
  114. }
  115. // Passpoint
  116. export interface PassingPointNavLocal extends CoordinateShortString {
  117. pointType: 1;
  118. height: string;
  119. heightStandard: string;
  120. pointId: number;
  121. pointCode: string;
  122. pointName: string;
  123. }
  124. export interface PassingPointAirlineLocal {
  125. pointType: 2;
  126. height: string;
  127. heightStandard: string;
  128. airRouteId: number;
  129. airlineCode: string;
  130. airlines: Array<AirRoutePoint>;
  131. }
  132. export interface PassingPointNormalLocal extends CoordinateShortString {
  133. pointType: 3;
  134. height: string;
  135. heightStandard: string;
  136. addr: string;
  137. }
  138. // Airspace
  139. export interface AirspaceInfoCircleLocal {
  140. airspaceType: 1;
  141. airspaceId: string;
  142. name: string;
  143. note: string;
  144. addr: string;
  145. lat: string;
  146. lng: string;
  147. radius: number;
  148. height: string;
  149. heightStandard: string;
  150. }
  151. export interface AirspaceInfoLineLocal {
  152. airspaceType: 2;
  153. airspaceId: string;
  154. name: string;
  155. note: string;
  156. dep: LatLngPointLocal;
  157. arrive: LatLngAddrLocal;
  158. passPoints: Array<PassingPointLocal>;
  159. airlineWidth?: number;
  160. }
  161. export interface AirspaceInfoPolygonLocal {
  162. airspaceType: 3;
  163. airspaceId: string;
  164. name: string;
  165. note: string;
  166. polygonPoints: Array<LatLngAddrLocal>;
  167. height: string;
  168. heightStandard: string;
  169. }
  170. declare type AirspaceInfoCircle = AirspaceInfoCircleLocal | AirspaceInfoCircleServer;
  171. declare type AirspaceInfoLine = AirspaceInfoLineLocal | AirspaceInfoLineServer;
  172. declare type AirspaceInfoPolygon = AirspaceInfoPolygonLocal | AirspaceInfoPolygonServer;
  173. declare type AirspaceInfoLocal = AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal;
  174. declare type AirspaceInfoServer = AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer;
  175. declare type AirspaceInfo = AirspaceInfoLocal | AirspaceInfoServer
  176. declare type PassingPointNav = PassingPointNavLocal | PassingPointNavServer
  177. declare type PassingPointNormal = PassingPointNormalLocal | PassingPointNormalServer
  178. declare type PassingPointAirline = PassingPointAirlineLocal | PassingPointAirlineServer
  179. declare type PassingPointLocal = PassingPointNavLocal | PassingPointNormalLocal | PassingPointAirlineLocal
  180. declare type PassingPointServer = PassingPointNavServer | PassingPointNormalServer | PassingPointAirlineServer
  181. declare type PassingPoint = PassingPointLocal | PassingPointServer
  182. // shapes
  183. export type Coordinate = CoordinateLong | CoordinateShort
  184. export interface CirclesAndMarkers {
  185. circles: Circle[];
  186. markers: Marker[];
  187. }
  188. export interface LinesAndMarkes {
  189. lines: Line[];
  190. markers: Marker[];
  191. }
  192. export interface LinesPolygonsAndMarkers {
  193. polygons: Polygon[];
  194. markers: Marker[];
  195. lines: Line[];
  196. }
  197. export interface PolygonsAndMarkers {
  198. polygons: Polygon[];
  199. markers: Marker[];
  200. }
  201. export interface ShapeStyle {
  202. imageName: string;
  203. lineWidth: number;
  204. strokeColor: string;
  205. fillColor: string;
  206. }
  207. export interface ShapeStyles {
  208. [styleName: string]: ShapeStyle
  209. }
  210. export function convertAirspaceInfoServerToLocal(airspaceInfo
  211. : AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer)
  212. : AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal | null {
  213. const airspaceType = airspaceInfo.airspace_type
  214. if (airspaceType == Global.airspaceType.circle) {
  215. const ai: AirspaceInfoCircleServer = <AirspaceInfoCircleServer> airspaceInfo
  216. return <AirspaceInfoCircleLocal>{
  217. airspaceType,
  218. airspaceId: ai.airspace_id,
  219. name: ai.airspace_name,
  220. note: ai.note,
  221. addr: ai.center_loc,
  222. lat: latLngDecimalToDegrees(ai.center_point_of_flying.lat),
  223. lng: latLngDecimalToDegrees(ai.center_point_of_flying.lng),
  224. radius: ai.radius_of_flying,
  225. height: ai.altitude + "",
  226. heightStandard: Global.heightStandardsById.get(ai.unit)
  227. };
  228. }
  229. if (airspaceType == Global.airspaceType.line) {
  230. const ai: AirspaceInfoLineServer = <AirspaceInfoLineServer> airspaceInfo
  231. let dep = {
  232. addr: ai.start_loc,
  233. lat: latLngDecimalToDegrees(ai.start_point.lat),
  234. lng: latLngDecimalToDegrees(ai.start_point.lng),
  235. height: ai.start_point.altitude + "",
  236. heightStandard: Global.heightStandardsById.get(ai.start_point.unit)
  237. }
  238. let arrive = {
  239. addr: ai.end_loc,
  240. lat: latLngDecimalToDegrees(ai.end_point.lat),
  241. lng: latLngDecimalToDegrees(ai.end_point.lng)
  242. }
  243. let passPoints: (PassingPointNavLocal | PassingPointAirlineLocal | PassingPointNormalLocal)[] = []
  244. if(Array.isArray(ai.passing_points)) {
  245. for(let obj of ai.passing_points) {
  246. let point: PassingPointNavLocal | PassingPointAirlineLocal | PassingPointNormalLocal;
  247. if (obj.point_type == Global.pointTypes.point) {
  248. const pp = <PassingPointNormalServer>obj;
  249. const lat = latLngDecimalToDegrees(pp.lat)
  250. const lng = latLngDecimalToDegrees(pp.lng)
  251. point = <PassingPointNormalLocal>{
  252. pointType: pp.point_type,
  253. addr: pp.point_name,
  254. lat, lng
  255. }
  256. } else if (obj.point_type == Global.pointTypes.nav) {
  257. const pp = <PassingPointNavServer>obj;
  258. const lat = latLngDecimalToDegrees(pp.lat)
  259. const lng = latLngDecimalToDegrees(pp.lng)
  260. point = <PassingPointNavLocal>{
  261. pointType: pp.point_type,
  262. pointId: pp.point_id,
  263. pointCode: pp.point_code,
  264. pointName: pp.point_name,
  265. lat, lng
  266. }
  267. } else {
  268. const pp = <PassingPointAirlineServer>obj;
  269. point = <PassingPointAirlineLocal>{
  270. pointType: pp.point_type,
  271. airRouteId: pp.airway,
  272. airlineCode: pp.air_route_code,
  273. airlines: pp.points
  274. }
  275. }
  276. if(isNumber(obj.altitude) && isNumber(obj.unit)) {
  277. point.height = obj.altitude + "";
  278. point.heightStandard = Global.heightStandardsById.get(obj.unit);
  279. } else {
  280. point.height = ""
  281. point.heightStandard = [...Global.heightStandards.keys()][0];
  282. }
  283. passPoints.push(point)
  284. }
  285. }
  286. return <AirspaceInfoLineLocal>{ ...{
  287. airspaceType,
  288. airspaceId: ai.airspace_id,
  289. name: ai.airspace_name,
  290. note: ai.note,
  291. dep,
  292. arrive,
  293. passPoints
  294. }, ...(ai.airline_width ? {airlineWidth: ai.airline_width} : {})}
  295. }
  296. if (airspaceType == Global.airspaceType.polygon) {
  297. const ai = <AirspaceInfoPolygonServer>airspaceInfo;
  298. if(Array.isArray(ai.points)) {
  299. let polygonPoints = new Array();
  300. let defaultPointName = 'A'
  301. for(let obj of ai.points) {
  302. let addr = obj.addr
  303. if(!addr) {
  304. addr = defaultPointName
  305. defaultPointName = String.fromCharCode(defaultPointName.charCodeAt(0) + 1)
  306. }
  307. polygonPoints.push({addr, lat: latLngDecimalToDegrees(obj.lat), lng: latLngDecimalToDegrees(obj.lng)})
  308. }
  309. return <AirspaceInfoPolygonLocal>{
  310. airspaceType,
  311. airspaceId: ai.airspace_id,
  312. name: ai.airspace_name,
  313. note: ai.note,
  314. height: ai.altitude + '',
  315. heightStandard: Global.heightStandardsById.get(ai.unit),
  316. polygonPoints
  317. };
  318. }
  319. }
  320. return null;
  321. }
  322. export function convertAirspaceInfoLocalToServer(airspace
  323. : AirspaceInfoCircleLocal | AirspaceInfoLineLocal | AirspaceInfoPolygonLocal)
  324. : AirspaceInfoCircleServer | AirspaceInfoLineServer | AirspaceInfoPolygonServer {
  325. if (airspace.airspaceType == Global.airspaceType.circle) {
  326. const ai = <AirspaceInfoCircleLocal> airspace;
  327. const circle = <AirspaceInfoCircleServer>{
  328. airspace_name: ai.name,
  329. airspace_id: ai.airspaceId,
  330. airspace_type: Global.airspaceType.circle,
  331. note: isSafeString(ai.note) ? ai.note : null,
  332. radius_of_flying: parseInt(ai.radius + ''),
  333. center_point_of_flying: {
  334. lng: latLngDegreesToDecimal(ai.lng),
  335. lat: latLngDegreesToDecimal(ai.lat)
  336. },
  337. center_loc: ai.addr,
  338. altitude: parseInt(ai.height),
  339. unit: Global.heightStandards.get(ai.heightStandard)
  340. };
  341. return circle
  342. } else if (airspace.airspaceType == Global.airspaceType.line) {
  343. const ai = <AirspaceInfoLineLocal> airspace;
  344. let line = <AirspaceInfoLineServer>{
  345. airspace_name: ai.name,
  346. airspace_id: ai.airspaceId,
  347. airspace_type: Global.airspaceType.line,
  348. note: ai.note,
  349. start_loc: ai.dep.addr,
  350. start_point: {
  351. lng: latLngDegreesToDecimal(ai.dep.lng),
  352. lat: latLngDegreesToDecimal(ai.dep.lat),
  353. altitude: parseInt(ai.dep.height),
  354. unit: Global.heightStandards.get(ai.dep.heightStandard)
  355. },
  356. end_loc: ai.arrive.addr,
  357. end_point: {
  358. lng: latLngDegreesToDecimal(ai.arrive.lng),
  359. lat: latLngDegreesToDecimal(ai.arrive.lat)
  360. }
  361. }
  362. if(ai.airlineWidth) {
  363. line['airline_width'] = ai.airlineWidth
  364. }
  365. if (Array.isArray(ai.passPoints) && ai.passPoints.length > 0) {
  366. let passing_points = [];
  367. for (let obj of ai.passPoints) {
  368. let retObj: PassingPointNormalServer | PassingPointNavServer | PassingPointAirlineServer;
  369. if (obj.pointType == Global.pointTypes.point && hasPoint(<PassingPointNormalLocal>obj)) {
  370. const pp = <PassingPointNormalLocal>obj;
  371. retObj = <PassingPointNormalServer>{
  372. point_type: Global.pointTypes.point,
  373. point_name: pp.addr,
  374. lat: latLngDegreesToDecimal(pp.lat),
  375. lng: latLngDegreesToDecimal(pp.lng)
  376. };
  377. } else if (obj.pointType == Global.pointTypes.nav) {
  378. const pp = <PassingPointNavLocal>obj;
  379. retObj = <PassingPointNavServer>{
  380. point_type: Global.pointTypes.nav,
  381. point_name: pp.pointName,
  382. point_id: pp.pointId,
  383. point_code: pp.pointCode,
  384. lat: latLngDegreesToDecimal(pp.lat),
  385. lng: latLngDegreesToDecimal(pp.lng)
  386. };
  387. } else {
  388. const pp = <PassingPointAirlineLocal>obj;
  389. retObj = <PassingPointAirlineServer>{
  390. point_type: Global.pointTypes.line,
  391. airway: pp.airRouteId,
  392. air_route_code: pp.airlineCode,
  393. points: pp.airlines
  394. };
  395. }
  396. if (isSafeString(obj.height) && isSafeString(obj.heightStandard)) {
  397. retObj.altitude = parseInt(obj.height);
  398. // @ts-ignore
  399. retObj.unit = Global.heightStandards.get(obj.heightStandard);
  400. }
  401. passing_points.push(retObj)
  402. }
  403. line.passing_points = passing_points;
  404. } else {
  405. line.passing_points = [];
  406. }
  407. return line;
  408. } else {
  409. const ai = <AirspaceInfoPolygonLocal> airspace;
  410. let points = [];
  411. for (let obj of ai.polygonPoints) {
  412. points.push({ addr: obj.addr, lat: latLngDegreesToDecimal(obj.lat), lng: latLngDegreesToDecimal(obj.lng) })
  413. }
  414. const polygon = <AirspaceInfoPolygonServer>{
  415. airspace_name: ai.name,
  416. airspace_id: ai.airspaceId,
  417. airspace_type: Global.airspaceType.polygon,
  418. note: ai.note,
  419. altitude: parseInt(ai.height),
  420. unit: Global.heightStandards.get(ai.heightStandard),
  421. points
  422. };
  423. return polygon;
  424. }
  425. }
  426. function getCircleRegions(circle: Circle): CoordinateShort[] {
  427. let lat, lng;
  428. if((circle.coordinate as any).latitude) {
  429. let coord = <CoordinateLong> circle.coordinate;
  430. lat = coord.latitude;
  431. lng = coord.longitude;
  432. } else {
  433. let coord = <CoordinateShort> circle.coordinate;
  434. lat = coord.lat;
  435. lng = coord.lng;
  436. }
  437. let latlon = new LatLon(lat, lng)
  438. let d1 = latlon.destinationPoint(circle.radius, 0)
  439. let d2 = latlon.destinationPoint(circle.radius, 90)
  440. let d3 = latlon.destinationPoint(circle.radius, 180)
  441. let d4 = latlon.destinationPoint(circle.radius, 270)
  442. 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 }]
  443. }
  444. function getDefaultStyle(): ShapeStyle {
  445. let imageName = 'BA_oval'
  446. let lineWidth = Global.amapLineWidth
  447. let strokeColor = Global.amapStrokeColor
  448. let fillColor = Global.amapFillColor
  449. return {imageName, lineWidth, strokeColor, fillColor}
  450. }
  451. function getCirclesAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: (styleName: string) => ShapeStyle | null, currentAirspaceIndex: number | undefined): CirclesAndMarkers {
  452. let circles: Circle[] = [];
  453. let markers: Marker[] = [];
  454. if (!Array.isArray(airspaceInfos)) {
  455. return {circles, markers};
  456. }
  457. let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle()
  458. //通过该方法获取样式
  459. let circleStyle = setStyle('circle');
  460. if(circleStyle) {
  461. lineWidth = circleStyle.lineWidth
  462. strokeColor = circleStyle.strokeColor
  463. fillColor = circleStyle.fillColor
  464. imageName = circleStyle.imageName
  465. }
  466. for (let i = 0; i < airspaceInfos.length; i++) {
  467. let tmpCircle = airspaceInfos[i]
  468. let airspaceTypeFix, radiusFix
  469. if ((tmpCircle as any).airspaceType) {
  470. airspaceTypeFix = 'airspaceType';
  471. radiusFix = 'radius'
  472. } else {
  473. airspaceTypeFix = 'airspace_type';
  474. radiusFix = 'radius_of_flying'
  475. }
  476. if ((tmpCircle as any)[airspaceTypeFix] == Global.airspaceType.circle && currentAirspaceIndex != i) {
  477. let coordinate = {latitude: 0, longitude: 0};
  478. if ((tmpCircle as any).center_point_of_flying) {
  479. let ai = <AirspaceInfoCircleServer>tmpCircle;
  480. coordinate.latitude = ai.center_point_of_flying.lat;
  481. coordinate.longitude = ai.center_point_of_flying.lng;
  482. } else {
  483. let ai = <AirspaceInfoCircleLocal>tmpCircle;
  484. coordinate.latitude = latLngDegreesToDecimal(ai.lat);
  485. coordinate.longitude = latLngDegreesToDecimal(ai.lng);
  486. }
  487. let radius = (tmpCircle as any)[radiusFix];
  488. if(radius) {
  489. let circle = <Circle>{lineWidth, strokeColor, fillColor, radius, coordinate}
  490. circles.push(circle);
  491. } else {
  492. // 这里的经纬度必定是数值, 所以最后一个参数是 2
  493. markers.push(addOvalPointConfig(coordinate.latitude, coordinate.longitude, imageName, 2));
  494. }
  495. }
  496. }
  497. return {circles, markers};
  498. }
  499. function getCircleAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: (styleName: string)=> ShapeStyle | null, currentAirspaceIndex: () => number | undefined) {
  500. return createSelector(
  501. airspaceInfos,
  502. () => setStyle,
  503. currentAirspaceIndex,
  504. getCirclesAndMarkers
  505. );
  506. }
  507. function getLatLng(latlng: number | string, dataType: number): number {
  508. if(dataType == 1) { // 驼峰模式,新建计划的时候的格式
  509. return latLngDegreesToDecimal(<string>latlng)
  510. } else {
  511. return <number>latlng
  512. }
  513. }
  514. function drawLineConfig(lat: number | string, lng: number | string, dataType: number) {
  515. return {
  516. latitude: getLatLng(lat, dataType),
  517. longitude: getLatLng(lng, dataType)
  518. };
  519. }
  520. function addOvalPointConfig(lat: number | string, lng: number | string, imageName: string, dataType: number) {
  521. return {
  522. coordinate: {
  523. latitude: getLatLng(lat, dataType),
  524. longitude: getLatLng(lng, dataType)
  525. },
  526. imageName: imageName
  527. };
  528. }
  529. function pointCompare(point1: AirRoutePoint | undefined, point2: AirRoutePoint | undefined) {
  530. if (!point1 || !point2) {
  531. return false
  532. }
  533. const pointId1 = point1.point_id;
  534. const pointId2 = point2.point_id;
  535. if(pointId1 == pointId2) {
  536. return true;
  537. }
  538. let [point1Lat, point1lng] = getFixedLatLng(point1)
  539. let [point2lat, point2lng] = getFixedLatLng(point2)
  540. if(myRound(point1Lat) == myRound(point2lat)
  541. && myRound(point1lng) == myRound(point2lng)) {
  542. return true
  543. } else {
  544. return false
  545. }
  546. }
  547. function getCrossPoint(points1: AirRoutePoint[], points2: AirRoutePoint[]) {
  548. for(let point1 of points1) {
  549. for(let point2 of points2) {
  550. if (pointCompare(point1, point2))
  551. return point1
  552. }
  553. }
  554. return undefined
  555. }
  556. function getAirwayPoints(airway: PassingPointAirline, pointBefore: PassingPoint, pointAfter: PassingPoint) {
  557. let found = 0
  558. let points = []
  559. let pointTypeFix, pointsFix, airRoutePoint
  560. if ('points' in airway) {
  561. pointTypeFix = 'point_type';
  562. pointsFix = 'points'
  563. airRoutePoint = airway['points']
  564. } else {
  565. pointTypeFix = 'pointType'
  566. pointsFix = 'airlines'
  567. airRoutePoint = airway['airlines']
  568. }
  569. let crossPointBefore, crossPointAfter;
  570. // 如果前后是其他航线,那么找到交叉点作为前后的点
  571. if ( (pointBefore as any)[pointTypeFix] == Global.pointTypes.line ) {
  572. crossPointBefore = getCrossPoint(airRoutePoint, <AirRoutePoint[]>(pointBefore as any)[pointsFix])
  573. }
  574. if((pointAfter as any)[pointTypeFix] == Global.pointTypes.line) {
  575. crossPointAfter = getCrossPoint(airRoutePoint, <AirRoutePoint[]>(pointAfter as any)[pointsFix])
  576. }
  577. for (let point of airRoutePoint) {
  578. if (pointCompare(crossPointBefore, point) || pointCompare(crossPointAfter, point)) {
  579. found++
  580. points.push(Object.assign({}, point))
  581. continue
  582. }
  583. if (found == 1) {
  584. points.push(Object.assign({}, point))
  585. }
  586. }
  587. if (!(points.length > 0 && found == 2)) {
  588. // 如果两个点不全在航线上面,那么画全部航线
  589. points = airRoutePoint
  590. }
  591. return points;
  592. }
  593. function getLinesRouter(lineProps: AirspaceInfoLine, lineAndMarkerStyle: ShapeStyle | null) {
  594. let coordinates: Coordinate[] = new Array();
  595. let markers: Marker[] = new Array();
  596. let lines: Line[] = []
  597. let {imageName, lineWidth, strokeColor} = getDefaultStyle()
  598. if (lineAndMarkerStyle) {
  599. imageName = lineAndMarkerStyle.imageName
  600. lineWidth = lineAndMarkerStyle.lineWidth
  601. strokeColor = lineAndMarkerStyle.strokeColor
  602. }
  603. let startPoint, passPoints, endPoint, pointTypeFix, dataType, airlineWidth
  604. if ((lineProps as any).start_point) {
  605. let ll = <AirspaceInfoLineServer>lineProps;
  606. dataType = 2 // 下划线模式
  607. startPoint = ll['start_point']
  608. passPoints = ll['passing_points']
  609. endPoint = ll['end_point']
  610. pointTypeFix = 'point_type';
  611. airlineWidth = parseInt(ll['airline_width'] + '', 10)
  612. } else {
  613. let ll = <AirspaceInfoLineLocal>lineProps;
  614. dataType = 1 // 驼峰模式
  615. startPoint = ll['dep']
  616. passPoints = ll['passPoints']
  617. endPoint = ll['arrive']
  618. pointTypeFix = 'pointType'
  619. airlineWidth = parseInt(ll['airlineWidth'] + '', 10)
  620. }
  621. if (startPoint) {
  622. coordinates.push(drawLineConfig(startPoint.lat, startPoint.lng, dataType));
  623. markers.push(addOvalPointConfig(startPoint.lat, startPoint.lng, imageName, dataType));
  624. }
  625. if (Array.isArray(passPoints)) {
  626. for (let i = 0; i < passPoints.length; i++) {
  627. let obj = passPoints[i]
  628. if (!isObject(obj)) { // 所有的 points/airway 都必须是 obj
  629. continue;
  630. }
  631. let pointType = (obj as any)[pointTypeFix]
  632. if ( pointType == Global.pointTypes.point
  633. || pointType == Global.pointTypes.nav) {
  634. let pp = <PassingPointNav | PassingPointNormal>obj
  635. coordinates.push(drawLineConfig(pp.lat, pp.lng, dataType));
  636. markers.push(addOvalPointConfig(pp.lat, pp.lng, imageName, dataType));
  637. } else {
  638. // 遇到一个航线,不需要和前前面的点连起来
  639. let pp = <PassingPointAirline>obj
  640. if (coordinates.length > 1) {
  641. lines.push({lineWidth, strokeColor, coordinates})
  642. }
  643. coordinates = []
  644. const pointBefore = i == 0 ? startPoint : passPoints[i - 1]
  645. const pointAfter = i == passPoints.length - 1 ? (endPoint ? endPoint : passPoints[passPoints.length - 1]) : passPoints[i + 1]
  646. lines.push({lineWidth, strokeColor, coordinates: getAirwayPoints(pp, <PassingPoint>pointBefore, <PassingPoint>pointAfter)})
  647. }
  648. }
  649. }
  650. if (endPoint) {
  651. coordinates.push(drawLineConfig(endPoint.lat, endPoint.lng, dataType));
  652. markers.push(addOvalPointConfig(endPoint.lat, endPoint.lng, imageName, dataType));
  653. }
  654. if (coordinates.length > 1) {
  655. lines.push({lineWidth, strokeColor, coordinates});
  656. }
  657. if(airlineWidth > 0) {
  658. // 有宽度的空域,需要线周围多画宽度的多边形
  659. let polygons = processAirlineWidth(lines, airlineWidth)
  660. return { lines, markers, polygons };
  661. } else {
  662. return { lines, markers, polygons: [] };
  663. }
  664. }
  665. function getFixedLatLng(point: {lat?: string | number, lng?: string | number, latitude?: string | number, longitude?: string | number}): [number, number] {
  666. let pp = <any> point;
  667. let lat = pp.latitude ? pp.latitude : pp.lat
  668. let lng = pp.longitude ? pp.longitude : pp.lng
  669. // 复制计划的数据,有的点是度数模式如 38°35′17″
  670. if(isSafeString(lat)) {
  671. lat = latLngDegreesToDecimal(<string>lat);
  672. lng = latLngDegreesToDecimal(<string>lng);
  673. }
  674. return [lat, lng]
  675. }
  676. function processAirlineWidth(lines: Line[], airlineWidth: number) {
  677. let polygons: Polygon[] = []
  678. let {strokeColor, fillColor} = getDefaultStyle()
  679. for(let line of lines) {
  680. let points = line.coordinates
  681. for(let i=0; i<points.length-1; i++) {
  682. let [lat1, lng1] = getFixedLatLng(points[i])
  683. let [lat2, lng2] = getFixedLatLng(points[i+1])
  684. let point1: LatLon.Spherical = new LatLon(lat1, lng1)
  685. let point2: LatLon.Spherical = new LatLon(lat2, lng2)
  686. let coordinates = getCirclePoints(point1, point2, airlineWidth)
  687. polygons.push({lineWidth: 1, strokeColor, fillColor, coordinates})
  688. }
  689. }
  690. return polygons
  691. }
  692. function getCirclePoints(point1: LatLon.Spherical, point2: LatLon.Spherical, width: number) {
  693. let percision = 10 // 半圆处理为多边形的时候,半圆上取几个点
  694. let step = 180/percision
  695. let bearing = (360 + point1.bearingTo(point2) - 90) % 360 // 取正值
  696. let points = []
  697. for(let diff = 0; diff <= 180; diff += step) {
  698. let point = point2.destinationPoint(width, bearing + diff)
  699. points.push({lat: point.lat, lng: point.lon})
  700. }
  701. for(let diff = 180; diff <= 360; diff += step) {
  702. let point = point1.destinationPoint(width, bearing + diff)
  703. points.push({lat: point.lat, lng: point.lon})
  704. }
  705. return points
  706. }
  707. function myRound(num: number, digits?: number) {
  708. if(digits == null)
  709. digits = 6 // 比较的精度,经纬度会被经过度分秒方式到浮点方式的转化
  710. return Math.round(num * Math.pow(10, digits)) / Math.pow(10, digits)
  711. }
  712. function getLinesPolygonsAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: number | undefined): LinesPolygonsAndMarkers {
  713. let retLines: Line[] = [];
  714. let retMarkers: Marker[] = [];
  715. let retPolygons: Polygon[] = [];
  716. if (!Array.isArray(airspaceInfos)) {
  717. return { lines: retLines, markers: retMarkers, polygons: retPolygons };
  718. }
  719. let lineStyle = setStyle('line');
  720. for (let i = 0; i < airspaceInfos.length; i++) {
  721. let tmpLine = airspaceInfos[i]
  722. let airspaceTypeFix;
  723. if ((tmpLine as any).airspaceType)
  724. airspaceTypeFix = 'airspaceType';
  725. else
  726. airspaceTypeFix = 'airspace_type';
  727. if ((tmpLine as any)[airspaceTypeFix] == Global.airspaceType.line && currentAirspaceIndex != i) {
  728. let lineProps = <AirspaceInfoLine>tmpLine;
  729. let { lines, markers, polygons } = getLinesRouter(lineProps, lineStyle);
  730. retMarkers.push(...markers);
  731. retLines.push(...lines);
  732. retPolygons.push(...polygons)
  733. }
  734. }
  735. return { lines: retLines, markers: retMarkers, polygons: retPolygons };
  736. }
  737. function getLinePolygonsAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) {
  738. return createSelector(
  739. airspaceInfos,
  740. () => setStyle,
  741. currentAirspaceIndex,
  742. getLinesPolygonsAndMarkers
  743. );
  744. }
  745. function getPolygon(polygonProps: AirspaceInfoPolygon, polygonAndMarkerStyle: ShapeStyle | null) {
  746. let coordinates: Coordinate[] = new Array();
  747. let markers: Marker[] = new Array();
  748. let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle()
  749. if (polygonAndMarkerStyle) {
  750. imageName = polygonAndMarkerStyle.imageName
  751. lineWidth = polygonAndMarkerStyle.lineWidth
  752. strokeColor = polygonAndMarkerStyle.strokeColor
  753. fillColor = polygonAndMarkerStyle.fillColor
  754. }
  755. let pointsFix, dataType;
  756. if ((polygonProps as any).points) {
  757. pointsFix = 'points';
  758. dataType = 2
  759. } else {
  760. pointsFix = 'polygonPoints';
  761. dataType = 1 // 驼峰模式
  762. }
  763. if (Array.isArray((polygonProps as any)[pointsFix])) {
  764. for (let obj of (polygonProps as any)[pointsFix]) {
  765. if (!obj) {
  766. continue
  767. }
  768. coordinates.push(drawLineConfig(obj.lat, obj.lng, dataType));
  769. markers.push(addOvalPointConfig(obj.lat, obj.lng, imageName, dataType));
  770. }
  771. }
  772. let polygon = <Polygon>{lineWidth, strokeColor, fillColor, coordinates};
  773. return { markers, polygon };
  774. }
  775. function getPolygonsAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: number | undefined): PolygonsAndMarkers {
  776. let markers: Marker[] = [];
  777. let polygons: Polygon[] = [];
  778. if (!Array.isArray(airspaceInfos)) {
  779. return { markers, polygons };
  780. }
  781. let polygonAndMarkerStyle = setStyle('polygon');
  782. for (let i = 0; i < airspaceInfos.length; i++) {
  783. let polygon = <AirspaceInfoPolygon>airspaceInfos[i]
  784. let airspaceTypeFix;
  785. if ((polygon as any).airspaceType)
  786. airspaceTypeFix = 'airspaceType';
  787. else
  788. airspaceTypeFix = 'airspace_type';
  789. if ((polygon as any)[airspaceTypeFix] == Global.airspaceType.polygon && currentAirspaceIndex != i) {
  790. let retObj = getPolygon(polygon, polygonAndMarkerStyle);
  791. markers.push(...retObj.markers);
  792. polygons.push(retObj.polygon);
  793. }
  794. }
  795. return { markers, polygons };
  796. }
  797. function getPolygonAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) {
  798. return createSelector(
  799. airspaceInfos,
  800. () => setStyle,
  801. currentAirspaceIndex,
  802. getPolygonsAndMarkers
  803. );
  804. }
  805. function getMarkers(circlesAndMarkers: CirclesAndMarkers, polygonAndMarkers: PolygonsAndMarkers, lineAndMarkers: LinesAndMarkes) {
  806. let markers: Marker[] = [];
  807. if (circlesAndMarkers) {
  808. markers = [...circlesAndMarkers.markers]
  809. }
  810. if (polygonAndMarkers) {
  811. markers = [...markers, ...polygonAndMarkers.markers]
  812. }
  813. if (lineAndMarkers) {
  814. markers = [...markers, ...lineAndMarkers.markers]
  815. }
  816. return markers
  817. }
  818. function getMarkerSelector(
  819. circlesAndMarkers: OutputSelector<any, any, (...params: any[]) => CirclesAndMarkers>,
  820. polygonAndMarkers: OutputSelector<any, any, (...params: any[]) => PolygonsAndMarkers>,
  821. lineAndMarkers: OutputSelector<any, any, (...params: any[]) => LinesAndMarkes>) {
  822. return createSelector(
  823. circlesAndMarkers,
  824. polygonAndMarkers,
  825. lineAndMarkers,
  826. getMarkers
  827. )
  828. }
  829. function getRegionPoints(circles: Circle[], lineAndMarkers: LinesAndMarkes, polygonAndMarkers: PolygonsAndMarkers) {
  830. let regionPoints: Coordinate[] = new Array();
  831. for (let i = 0; i < circles.length; i++) {
  832. regionPoints.push(...getCircleRegions(circles[i]));
  833. }
  834. let lines = lineAndMarkers.lines;
  835. for (let i = 0; i < lines.length; i++) {
  836. regionPoints.push(...lines[i].coordinates);
  837. }
  838. let polygons = polygonAndMarkers.polygons;
  839. for (let i = 0; i < polygons.length; i++) {
  840. regionPoints.push(...polygons[i].coordinates);
  841. }
  842. return regionPoints;
  843. }
  844. function getRegionPointsSelector(
  845. circles: OutputSelector<any, any, (...params: any[])=>Circle[]>,
  846. lineAndMarkers: OutputSelector<any, any, (...params: any[])=>LinesAndMarkes>,
  847. polygonAndMarkers: OutputSelector<any, any, (...params: any[])=>PolygonsAndMarkers>) {
  848. return createSelector(
  849. circles,
  850. lineAndMarkers,
  851. polygonAndMarkers,
  852. getRegionPoints
  853. );
  854. }
  855. function getCircles(circlesAndMarkers: CirclesAndMarkers) {
  856. return circlesAndMarkers.circles;
  857. }
  858. function getCircleSelector(circlesAndMarkers: OutputSelector<any, any, (...params: any[])=> CirclesAndMarkers>) {
  859. return createSelector(
  860. circlesAndMarkers,
  861. getCircles
  862. );
  863. }
  864. function getLines(lineAndMarker: LinesAndMarkes) {
  865. return lineAndMarker.lines;
  866. }
  867. function getLineSelector(lineAndMarker: OutputSelector<any, any, (...params: any[])=>LinesAndMarkes>) {
  868. return createSelector(
  869. lineAndMarker,
  870. getLines
  871. );
  872. }
  873. function getPolygons(polygonAndMarkers: PolygonsAndMarkers, linePolygonsAndMarkers: LinesPolygonsAndMarkers) {
  874. return [...polygonAndMarkers.polygons, ...linePolygonsAndMarkers.polygons];
  875. }
  876. function getPolygonSelector(
  877. polygonAndMarkers: OutputSelector<any, any, (...params: any[]) => PolygonsAndMarkers>,
  878. linePolygonsAndMarkers: OutputSelector<any, any, (...params: any[]) => LinesPolygonsAndMarkers>) {
  879. return createSelector(
  880. polygonAndMarkers,
  881. linePolygonsAndMarkers,
  882. getPolygons
  883. );
  884. }
  885. export type FnSetStyle = (styleName: string) => null | ShapeStyle
  886. let setStyle: (style: undefined | ShapeStyles) => FnSetStyle = (styles) => {
  887. if (!styles)
  888. return () => null
  889. else
  890. return (shapeName: string): ShapeStyle => styles[shapeName]
  891. }
  892. //获取selector
  893. export function getShapesSelector(airspaceInfos: () => AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: () => number | undefined) {
  894. currentAirspaceIndex = currentAirspaceIndex ? currentAirspaceIndex : () => -1;
  895. let circlesAndMarkers = getCircleAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  896. let circles = getCircleSelector(circlesAndMarkers);
  897. let linePolygonsAndMarkers = getLinePolygonsAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  898. let lines = getLineSelector(linePolygonsAndMarkers);
  899. let polygonAndMarkers = getPolygonAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  900. let polygons = getPolygonSelector(polygonAndMarkers, linePolygonsAndMarkers);
  901. let markers = getMarkerSelector(circlesAndMarkers, polygonAndMarkers, linePolygonsAndMarkers);
  902. let regionPoints = getRegionPointsSelector(circles, linePolygonsAndMarkers, polygonAndMarkers);
  903. return {
  904. markers,
  905. circles,
  906. lines,
  907. polygons,
  908. regionPoints
  909. }
  910. }
  911. //获取数组
  912. export function getShapes(airspaceInfos: AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: number) {
  913. let {markers, polygons, circles, lines, regionPoints} =
  914. getShapesSelector(()=>airspaceInfos, style, ()=>currentAirspaceIndex)
  915. return {
  916. markers: markers(airspaceInfos),
  917. circles: circles(airspaceInfos),
  918. lines: lines(airspaceInfos),
  919. polygons: polygons(airspaceInfos),
  920. regionPoints: regionPoints(airspaceInfos)
  921. }
  922. }
  923. // 总共 5 种格式, http://git.corp.brilliantaero.com/BA/Coco/issues/99#note_6358
  924. // 1. 全输出格式
  925. // 2. 简化格式
  926. // 3. 传真格式
  927. // 4. 用户端用的简化格式
  928. // 5. 极简格式
  929. function getHeight(height: number | string, unit: string | number, type: number) {
  930. let shortNum
  931. const num = +height; // to number
  932. if(num >= 100) {
  933. shortNum = parseInt(num/100 + '').toString()
  934. if(shortNum.length <2) {
  935. shortNum = '0' + shortNum
  936. }
  937. }
  938. let heightStandard = Global.heightStandardsById.get(unit)
  939. if(!heightStandard) {
  940. heightStandard = unit
  941. }
  942. // 这里统一使用数字判断
  943. let standardUnit = Global.heightStandards.get(heightStandard)
  944. let heightDesc
  945. switch(standardUnit) {
  946. case 1:
  947. heightDesc = ['H*真', '真高*米']
  948. break;
  949. case 2:
  950. heightDesc = ['H*标(含以下)', '标高*米(含以下)']
  951. break;
  952. case 3:
  953. heightDesc = ['H*真(含以下)', '真高*米(含以下)']
  954. break;
  955. default:
  956. heightDesc = ['H*标', '标高*米']
  957. }
  958. if(shortNum && (type == 1 || type == 2)) {
  959. // H02真,H02真(含以下)
  960. return heightDesc[0].replace('*', shortNum)
  961. } else {
  962. // 真高200米,真高200米(含以下)
  963. return heightDesc[1].replace('*', height + '')
  964. }
  965. }
  966. function getAirspaceName(airspaceInfo: AirspaceInfo) {
  967. if((airspaceInfo as any).airspace_name) {
  968. const ai = <AirspaceInfoServer> airspaceInfo;
  969. return ai.airspace_name
  970. } else {
  971. const ai = <AirspaceInfoLocal> airspaceInfo;
  972. return ai.name
  973. }
  974. }
  975. export function circleContent(airspaceInfo: AirspaceInfoCircle, type=3) {
  976. if(type == 5)
  977. return getAirspaceName(airspaceInfo)
  978. if('airspace_name' in airspaceInfo) {
  979. const lat = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lat);
  980. const lng = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lng);
  981. let content = [];
  982. let loc = `以${airspaceInfo.center_loc}`
  983. if(type == 1 || type == 3)
  984. loc += `(E${lng}, N${lat})`;
  985. content.push(`${loc}为中心`)
  986. content.push(`半径${airspaceInfo.radius_of_flying}米`);
  987. content.push(getHeight(airspaceInfo.altitude, airspaceInfo.unit, type))
  988. if (airspaceInfo.note)
  989. content.push(`备注:${airspaceInfo.note}`)
  990. return content.join(',');
  991. } else {
  992. let content = []
  993. let loc = `以${airspaceInfo.addr}`
  994. if(type == 1 || type == 3)
  995. loc += `(E${airspaceInfo.lng}, N${airspaceInfo.lat})`;
  996. content.push(`${loc}为中心`)
  997. content.push(`半径${airspaceInfo.radius}米`);
  998. content.push(getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type))
  999. if (airspaceInfo.note)
  1000. content.push(`备注:${airspaceInfo.note}`)
  1001. return content.join(',');
  1002. }
  1003. }
  1004. function flyingCenter(item: CoordinateShort | {} = {}): string{
  1005. if(item == {}){
  1006. return "";
  1007. }
  1008. const pp = <CoordinateShort> item;
  1009. return (
  1010. "(E" + latLngDecimalToDegrees(pp.lng) +
  1011. ', ' +
  1012. "N" + latLngDecimalToDegrees(pp.lat) + ")"
  1013. );
  1014. }
  1015. export function lineContent(airspaceInfo: AirspaceInfoLine, type=3): string {
  1016. if(type == 5)
  1017. return getAirspaceName(airspaceInfo)
  1018. if('airspace_name' in airspaceInfo) {
  1019. let content = [];
  1020. content.push(`${airspaceInfo.start_loc}`)
  1021. if(type == 1 || type == 3)
  1022. content.push(`${flyingCenter(airspaceInfo.start_point)}`)
  1023. content.push(` - `)
  1024. content.push(getHeight(airspaceInfo.start_point.altitude, airspaceInfo.start_point.unit, type))
  1025. const passing_points = airspaceInfo.passing_points;
  1026. if(Array.isArray(passing_points)) {
  1027. for(let i = 0; i < passing_points.length; i++) {
  1028. const obj = passing_points[i];
  1029. if (obj.point_type == Global.pointTypes.point) {
  1030. let pp = <PassingPointNormalServer>obj;
  1031. const lat = latLngDecimalToDegrees(pp.lat)
  1032. const lng = latLngDecimalToDegrees(pp.lng)
  1033. content.push(` - ${pp.point_name}`)
  1034. if(type == 1 || type == 3)
  1035. content.push(`(E${lng}, N${lat})`)
  1036. } else if (obj.point_type == Global.pointTypes.nav) {
  1037. let pp = <PassingPointNavServer>obj;
  1038. const lat = latLngDecimalToDegrees(pp.lat)
  1039. const lng = latLngDecimalToDegrees(pp.lng)
  1040. content.push(` - ${pp.point_code}`)
  1041. if(type == 1 || type == 3)
  1042. content.push(`(E${lng}, N${lat})`)
  1043. } else {
  1044. let pp = <PassingPointAirlineServer>obj;
  1045. content.push(` - ${pp.air_route_code}`)
  1046. }
  1047. if(obj.altitude) {
  1048. content.push(` - ${getHeight(obj.altitude, obj.unit, type)}`)
  1049. }
  1050. }
  1051. }
  1052. content.push(` - ${airspaceInfo.end_loc}`)
  1053. if(type == 1 || type == 3)
  1054. content.push(`${flyingCenter(airspaceInfo.end_point)}`)
  1055. if(isSafeString(airspaceInfo.airline_width)) {
  1056. content.push(`,宽度:${airspaceInfo.airline_width}米`)
  1057. }
  1058. if(isSafeString(airspaceInfo.note)) {
  1059. content.push(`,备注: ${airspaceInfo.note}`)
  1060. }
  1061. let result = content.join("")
  1062. return result;
  1063. } else {
  1064. let content = [];
  1065. content.push(`${airspaceInfo.dep.addr}`)
  1066. if(type == 1 || type == 3)
  1067. content.push(`(E${airspaceInfo.dep.lng}, N${airspaceInfo.dep.lat})`)
  1068. content.push(` - ${getHeight(airspaceInfo.dep.height, airspaceInfo.dep.heightStandard, type)}`);
  1069. if (Array.isArray(airspaceInfo.passPoints)) {
  1070. let length = airspaceInfo.passPoints.length;
  1071. for (let i = 0; i < length; i++) {
  1072. let obj = airspaceInfo.passPoints[i];
  1073. if (obj.pointType == Global.pointTypes.point) {
  1074. let pp = <PassingPointNormalLocal>obj;
  1075. content.push(` - ${pp.addr}`)
  1076. if(type == 1 || type == 3)
  1077. content.push(`(E${pp.lng}, N${pp.lat})`);
  1078. } else if (obj.pointType == Global.pointTypes.nav) {
  1079. let pp = <PassingPointNavLocal>obj;
  1080. content.push(` - ${pp.pointCode}`)
  1081. if(type == 1 || type == 3)
  1082. content.push(`(E${pp.lng}, N${pp.lat})`);
  1083. } else {
  1084. let pp = <PassingPointAirlineLocal>obj;
  1085. content.push(` - ${pp.airlineCode}`);
  1086. }
  1087. if(obj.height) {
  1088. content.push(` - ${getHeight(obj.height, obj.heightStandard, type)}`)
  1089. }
  1090. }
  1091. }
  1092. content.push(` - ${airspaceInfo.arrive.addr}`)
  1093. if(type == 1 || type == 3)
  1094. content.push(`(E${airspaceInfo.arrive.lng}, N${airspaceInfo.arrive.lat})`);
  1095. if(airspaceInfo.airlineWidth) {
  1096. content.push(`,宽度:${airspaceInfo.airlineWidth}米`)
  1097. }
  1098. if (airspaceInfo.note)
  1099. content.push(`,备注:${airspaceInfo.note}`)
  1100. return content.join('');
  1101. }
  1102. }
  1103. export function polygonContent(airspaceInfo: AirspaceInfoPolygon, type=3): string {
  1104. if(type == 5)
  1105. return getAirspaceName(airspaceInfo)
  1106. if('airspace_name' in airspaceInfo) {
  1107. let res = []
  1108. let points = airspaceInfo.points
  1109. for (let i = 0; i < points.length; i++) {
  1110. let c = `${points[i].addr ? points[i].addr : ''}`
  1111. if(type == 1 || type == 3)
  1112. c += `(E${latLngDecimalToDegrees(points[i].lng)}, N${latLngDecimalToDegrees(points[i].lat)})`;
  1113. res.push(c)
  1114. }
  1115. let content = [res.join('、')]
  1116. content.push(`${airspaceInfo.points.length}点连线范围内`)
  1117. content.push(`,${getHeight(airspaceInfo.altitude, airspaceInfo.unit, type)}`)
  1118. if(isSafeString(airspaceInfo.note)) {
  1119. content.push(`,备注:${airspaceInfo.note}`)
  1120. }
  1121. return content.join('');
  1122. } else {
  1123. let content = [];
  1124. let length = airspaceInfo.polygonPoints.length;
  1125. for (let i = 0; i < length; i++) {
  1126. let obj = airspaceInfo.polygonPoints[i];
  1127. let c = `${obj.addr ? obj.addr : ''}`
  1128. if(type == 1 || type == 3)
  1129. c += `(E${obj.lng}, N${obj.lat})`
  1130. content.push(c)
  1131. }
  1132. let cc = content.join('、') + `${length}点连线范围内`
  1133. cc += `,${getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type)}`
  1134. if (airspaceInfo.note)
  1135. cc += `,备注:${airspaceInfo.note}`
  1136. return cc;
  1137. }
  1138. }
  1139. export {latLngDegreesToDecimal, latLngDecimalToDegrees}