index.ts 45 KB

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