index.ts 45 KB

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