index.ts 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  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: number;
  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: number;
  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: number;
  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: number;
  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: number;
  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: number;
  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. }
  425. return line;
  426. } else {
  427. const ai = <AirspaceInfoPolygonLocal> airspace;
  428. let points = [];
  429. for (let obj of ai.polygonPoints) {
  430. points.push({ addr: obj.addr, lat: latLngDegreesToDecimal(obj.lat), lng: latLngDegreesToDecimal(obj.lng) })
  431. }
  432. const polygon = <AirspaceInfoPolygonServer>{
  433. airspace_name: ai.name,
  434. airspace_id: ai.airspaceId,
  435. airspace_type: Global.airspaceType.polygon,
  436. note: ai.note,
  437. altitude: parseInt(ai.height),
  438. unit: Global.heightStandards.get(ai.heightStandard),
  439. points
  440. };
  441. return polygon;
  442. }
  443. }
  444. function getCircleRegions(circle: Circle): CoordinateShort[] {
  445. let lat, lng;
  446. if((circle.coordinate as any).latitude) {
  447. let coord = <CoordinateLong> circle.coordinate;
  448. lat = coord.latitude;
  449. lng = coord.longitude;
  450. } else {
  451. let coord = <CoordinateShort> circle.coordinate;
  452. lat = coord.lat;
  453. lng = coord.lng;
  454. }
  455. let latlon = new LatLon(lat, lng)
  456. let d1 = latlon.destinationPoint(circle.radius, 0)
  457. let d2 = latlon.destinationPoint(circle.radius, 90)
  458. let d3 = latlon.destinationPoint(circle.radius, 180)
  459. let d4 = latlon.destinationPoint(circle.radius, 270)
  460. 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 }]
  461. }
  462. function getDefaultStyle(): ShapeStyle {
  463. let imageName = 'BA_oval'
  464. let lineWidth = Global.amapLineWidth
  465. let strokeColor = Global.amapStrokeColor
  466. let fillColor = Global.amapFillColor
  467. return {imageName, lineWidth, strokeColor, fillColor}
  468. }
  469. function getCirclesAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: (styleName: string) => ShapeStyle | null, currentAirspaceIndex: number | undefined): CirclesAndMarkers {
  470. let circles: Circle[] = [];
  471. let markers: Marker[] = [];
  472. if (!Array.isArray(airspaceInfos)) {
  473. return {circles, markers};
  474. }
  475. let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle()
  476. //通过该方法获取样式
  477. let circleStyle = setStyle('circle');
  478. if(circleStyle) {
  479. lineWidth = circleStyle.lineWidth
  480. strokeColor = circleStyle.strokeColor
  481. fillColor = circleStyle.fillColor
  482. imageName = circleStyle.imageName
  483. }
  484. for (let i = 0; i < airspaceInfos.length; i++) {
  485. let tmpCircle = airspaceInfos[i]
  486. let airspaceTypeFix, radiusFix
  487. if ((tmpCircle as any).airspaceType) {
  488. airspaceTypeFix = 'airspaceType';
  489. radiusFix = 'radius'
  490. } else {
  491. airspaceTypeFix = 'airspace_type';
  492. radiusFix = 'radius_of_flying'
  493. }
  494. if ((tmpCircle as any)[airspaceTypeFix] == Global.airspaceType.circle && currentAirspaceIndex != i) {
  495. let coordinate = {latitude: 0, longitude: 0};
  496. if ((tmpCircle as any).center_point_of_flying) {
  497. let ai = <AirspaceInfoCircleServer>tmpCircle;
  498. coordinate.latitude = ai.center_point_of_flying.lat;
  499. coordinate.longitude = ai.center_point_of_flying.lng;
  500. } else {
  501. let ai = <AirspaceInfoCircleLocal>tmpCircle;
  502. coordinate.latitude = latLngDegreesToDecimal(ai.lat);
  503. coordinate.longitude = latLngDegreesToDecimal(ai.lng);
  504. }
  505. let radius = (tmpCircle as any)[radiusFix];
  506. if(radius) {
  507. let circle = <Circle>{lineWidth, strokeColor, fillColor, radius, coordinate}
  508. circles.push(circle);
  509. } else {
  510. // 这里的经纬度必定是数值, 所以最后一个参数是 2
  511. markers.push(addOvalPointConfig(coordinate.latitude, coordinate.longitude, imageName, 2));
  512. }
  513. }
  514. }
  515. return {circles, markers};
  516. }
  517. function getCircleAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: (styleName: string)=> ShapeStyle | null, currentAirspaceIndex: () => number | undefined) {
  518. return createSelector(
  519. airspaceInfos,
  520. () => setStyle,
  521. currentAirspaceIndex,
  522. getCirclesAndMarkers
  523. );
  524. }
  525. function getLatLng(latlng: number | string, dataType: number): number {
  526. if(dataType == 1) { // 驼峰模式,新建计划的时候的格式
  527. return latLngDegreesToDecimal(<string>latlng)
  528. } else {
  529. return <number>latlng
  530. }
  531. }
  532. function drawLineConfig(lat: number | string, lng: number | string, dataType: number) {
  533. return {
  534. latitude: getLatLng(lat, dataType),
  535. longitude: getLatLng(lng, dataType)
  536. };
  537. }
  538. function addOvalPointConfig(lat: number | string, lng: number | string, imageName: string, dataType: number) {
  539. return {
  540. coordinate: {
  541. latitude: getLatLng(lat, dataType),
  542. longitude: getLatLng(lng, dataType)
  543. },
  544. imageName: imageName
  545. };
  546. }
  547. function pointCompare(point1: AirRoutePoint | undefined, point2: AirRoutePoint | undefined) {
  548. if (!point1 || !point2) {
  549. return false
  550. }
  551. const pointId1 = point1.point_id;
  552. const pointId2 = point2.point_id;
  553. if(pointId1 == pointId2) {
  554. return true;
  555. }
  556. let [point1Lat, point1lng] = getFixedLatLng(point1)
  557. let [point2lat, point2lng] = getFixedLatLng(point2)
  558. if(myRound(point1Lat) == myRound(point2lat)
  559. && myRound(point1lng) == myRound(point2lng)) {
  560. return true
  561. } else {
  562. return false
  563. }
  564. }
  565. function getCrossPoint(points1: AirRoutePoint[], points2: AirRoutePoint[]) {
  566. for(let point1 of points1) {
  567. for(let point2 of points2) {
  568. if (pointCompare(point1, point2))
  569. return point1
  570. }
  571. }
  572. return undefined
  573. }
  574. function getAirwayPoints(airway: PassingPointAirline, pointBefore: PassingPoint, pointAfter: PassingPoint) {
  575. let found = 0
  576. let points = []
  577. let pointTypeFix, pointsFix, airRoutePoint
  578. if ('points' in airway) {
  579. pointTypeFix = 'point_type';
  580. pointsFix = 'points'
  581. airRoutePoint = airway['points']
  582. } else {
  583. pointTypeFix = 'pointType'
  584. pointsFix = 'airlines'
  585. airRoutePoint = airway['airlines']
  586. }
  587. let crossPointBefore, crossPointAfter;
  588. // 如果前后是其他航线,那么找到交叉点作为前后的点
  589. if ( (pointBefore as any)[pointTypeFix] == Global.pointTypes.line ) {
  590. crossPointBefore = getCrossPoint(airRoutePoint, <AirRoutePoint[]>(pointBefore as any)[pointsFix])
  591. }
  592. if((pointAfter as any)[pointTypeFix] == Global.pointTypes.line) {
  593. crossPointAfter = getCrossPoint(airRoutePoint, <AirRoutePoint[]>(pointAfter as any)[pointsFix])
  594. }
  595. for (let point of airRoutePoint) {
  596. if (pointCompare(crossPointBefore, point) || pointCompare(crossPointAfter, point)) {
  597. found++
  598. points.push(Object.assign({}, point))
  599. continue
  600. }
  601. if (found == 1) {
  602. points.push(Object.assign({}, point))
  603. }
  604. }
  605. if (!(points.length > 0 && found == 2)) {
  606. // 如果两个点不全在航线上面,那么画全部航线
  607. points = airRoutePoint
  608. }
  609. return points;
  610. }
  611. function getLinesRouter(lineProps: AirspaceInfoLine, lineAndMarkerStyle: ShapeStyle | null) {
  612. let coordinates: Coordinate[] = new Array();
  613. let markers: Marker[] = new Array();
  614. let lines: Line[] = []
  615. let {imageName, lineWidth, strokeColor} = getDefaultStyle()
  616. if (lineAndMarkerStyle) {
  617. imageName = lineAndMarkerStyle.imageName
  618. lineWidth = lineAndMarkerStyle.lineWidth
  619. strokeColor = lineAndMarkerStyle.strokeColor
  620. }
  621. let startPoint, passPoints, endPoint, pointTypeFix, dataType, airlineWidth
  622. if ((lineProps as any).start_point) {
  623. let ll = <AirspaceInfoLineServer>lineProps;
  624. dataType = 2 // 下划线模式
  625. startPoint = ll['start_point']
  626. passPoints = ll['passing_points']
  627. endPoint = ll['end_point']
  628. pointTypeFix = 'point_type';
  629. airlineWidth = parseInt(ll['airline_width'] + '', 10)
  630. } else {
  631. let ll = <AirspaceInfoLineLocal>lineProps;
  632. dataType = 1 // 驼峰模式
  633. startPoint = ll['dep']
  634. passPoints = ll['passPoints']
  635. endPoint = ll['arrive']
  636. pointTypeFix = 'pointType'
  637. airlineWidth = parseInt(ll['airlineWidth'] + '', 10)
  638. }
  639. if (startPoint) {
  640. coordinates.push(drawLineConfig(startPoint.lat, startPoint.lng, dataType));
  641. markers.push(addOvalPointConfig(startPoint.lat, startPoint.lng, imageName, dataType));
  642. }
  643. if (Array.isArray(passPoints)) {
  644. for (let i = 0; i < passPoints.length; i++) {
  645. let obj = passPoints[i]
  646. if (!isObject(obj)) { // 所有的 points/airway 都必须是 obj
  647. continue;
  648. }
  649. let pointType = (obj as any)[pointTypeFix]
  650. if ( pointType == Global.pointTypes.point
  651. || pointType == Global.pointTypes.nav) {
  652. let pp = <PassingPointNav | PassingPointNormal>obj
  653. coordinates.push(drawLineConfig(pp.lat, pp.lng, dataType));
  654. markers.push(addOvalPointConfig(pp.lat, pp.lng, imageName, dataType));
  655. } else {
  656. // 遇到一个航线,不需要和前前面的点连起来
  657. let pp = <PassingPointAirline>obj
  658. if (coordinates.length > 1) {
  659. lines.push({lineWidth, strokeColor, coordinates})
  660. }
  661. coordinates = []
  662. const pointBefore = i == 0 ? startPoint : passPoints[i - 1]
  663. const pointAfter = i == passPoints.length - 1 ? (endPoint ? endPoint : passPoints[passPoints.length - 1]) : passPoints[i + 1]
  664. lines.push({lineWidth, strokeColor, coordinates: getAirwayPoints(pp, <PassingPoint>pointBefore, <PassingPoint>pointAfter)})
  665. }
  666. }
  667. }
  668. if (endPoint) {
  669. coordinates.push(drawLineConfig(endPoint.lat, endPoint.lng, dataType));
  670. markers.push(addOvalPointConfig(endPoint.lat, endPoint.lng, imageName, dataType));
  671. }
  672. if (coordinates.length > 1) {
  673. lines.push({lineWidth, strokeColor, coordinates});
  674. }
  675. if(airlineWidth > 0) {
  676. // 有宽度的空域,需要线周围多画宽度的多边形
  677. let polygons = processAirlineWidth(lines, airlineWidth)
  678. return { lines, markers, polygons };
  679. } else {
  680. return { lines, markers, polygons: [] };
  681. }
  682. }
  683. function getFixedLatLng(point: {lat?: string | number, lng?: string | number, latitude?: string | number, longitude?: string | number}): [number, number] {
  684. let pp = <any> point;
  685. let lat = pp.latitude ? pp.latitude : pp.lat
  686. let lng = pp.longitude ? pp.longitude : pp.lng
  687. // 复制计划的数据,有的点是度数模式如 38°35′17″
  688. if(isSafeString(lat)) {
  689. lat = latLngDegreesToDecimal(<string>lat);
  690. lng = latLngDegreesToDecimal(<string>lng);
  691. }
  692. return [lat, lng]
  693. }
  694. function processAirlineWidth(lines: Line[], airlineWidth: number) {
  695. let polygons: Polygon[] = []
  696. let {strokeColor, fillColor} = getDefaultStyle()
  697. for(let line of lines) {
  698. let points = line.coordinates
  699. for(let i=0; i<points.length-1; i++) {
  700. let [lat1, lng1] = getFixedLatLng(points[i])
  701. let [lat2, lng2] = getFixedLatLng(points[i+1])
  702. let point1: LatLon.Spherical = new LatLon(lat1, lng1)
  703. let point2: LatLon.Spherical = new LatLon(lat2, lng2)
  704. let coordinates = getCirclePoints(point1, point2, airlineWidth)
  705. polygons.push({lineWidth: 1, strokeColor, fillColor, coordinates})
  706. }
  707. }
  708. return polygons
  709. }
  710. function getCirclePoints(point1: LatLon.Spherical, point2: LatLon.Spherical, width: number) {
  711. let percision = 10 // 半圆处理为多边形的时候,半圆上取几个点
  712. let step = 180/percision
  713. let bearing = (360 + point1.bearingTo(point2) - 90) % 360 // 取正值
  714. let points = []
  715. for(let diff = 0; diff <= 180; diff += step) {
  716. let point = point2.destinationPoint(width, bearing + diff)
  717. points.push({lat: point.lat, lng: point.lon})
  718. }
  719. for(let diff = 180; diff <= 360; diff += step) {
  720. let point = point1.destinationPoint(width, bearing + diff)
  721. points.push({lat: point.lat, lng: point.lon})
  722. }
  723. return points
  724. }
  725. function myRound(num: number, digits?: number) {
  726. if(digits == null)
  727. digits = 6 // 比较的精度,经纬度会被经过度分秒方式到浮点方式的转化
  728. return Math.round(num * Math.pow(10, digits)) / Math.pow(10, digits)
  729. }
  730. function getLinesPolygonsAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: number | undefined): LinesPolygonsAndMarkers {
  731. let retLines: Line[] = [];
  732. let retMarkers: Marker[] = [];
  733. let retPolygons: Polygon[] = [];
  734. if (!Array.isArray(airspaceInfos)) {
  735. return { lines: retLines, markers: retMarkers, polygons: retPolygons };
  736. }
  737. let lineStyle = setStyle('line');
  738. for (let i = 0; i < airspaceInfos.length; i++) {
  739. let tmpLine = airspaceInfos[i]
  740. let airspaceTypeFix;
  741. if ((tmpLine as any).airspaceType)
  742. airspaceTypeFix = 'airspaceType';
  743. else
  744. airspaceTypeFix = 'airspace_type';
  745. if ((tmpLine as any)[airspaceTypeFix] == Global.airspaceType.line && currentAirspaceIndex != i) {
  746. let lineProps = <AirspaceInfoLine>tmpLine;
  747. let { lines, markers, polygons } = getLinesRouter(lineProps, lineStyle);
  748. retMarkers.push(...markers);
  749. retLines.push(...lines);
  750. retPolygons.push(...polygons)
  751. }
  752. }
  753. return { lines: retLines, markers: retMarkers, polygons: retPolygons };
  754. }
  755. function getLinePolygonsAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) {
  756. return createSelector(
  757. airspaceInfos,
  758. () => setStyle,
  759. currentAirspaceIndex,
  760. getLinesPolygonsAndMarkers
  761. );
  762. }
  763. function getPolygon(polygonProps: AirspaceInfoPolygon, polygonAndMarkerStyle: ShapeStyle | null) {
  764. let coordinates: Coordinate[] = new Array();
  765. let markers: Marker[] = new Array();
  766. let {imageName, lineWidth, strokeColor, fillColor} = getDefaultStyle()
  767. if (polygonAndMarkerStyle) {
  768. imageName = polygonAndMarkerStyle.imageName
  769. lineWidth = polygonAndMarkerStyle.lineWidth
  770. strokeColor = polygonAndMarkerStyle.strokeColor
  771. fillColor = polygonAndMarkerStyle.fillColor
  772. }
  773. let pointsFix, dataType;
  774. if ((polygonProps as any).points) {
  775. pointsFix = 'points';
  776. dataType = 2
  777. } else {
  778. pointsFix = 'polygonPoints';
  779. dataType = 1 // 驼峰模式
  780. }
  781. if (Array.isArray((polygonProps as any)[pointsFix])) {
  782. for (let obj of (polygonProps as any)[pointsFix]) {
  783. if (!obj) {
  784. continue
  785. }
  786. coordinates.push(drawLineConfig(obj.lat, obj.lng, dataType));
  787. markers.push(addOvalPointConfig(obj.lat, obj.lng, imageName, dataType));
  788. }
  789. }
  790. let polygon = <Polygon>{lineWidth, strokeColor, fillColor, coordinates};
  791. return { markers, polygon };
  792. }
  793. function getPolygonsAndMarkers(airspaceInfos: AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: number | undefined): PolygonsAndMarkers {
  794. let markers: Marker[] = [];
  795. let polygons: Polygon[] = [];
  796. if (!Array.isArray(airspaceInfos)) {
  797. return { markers, polygons };
  798. }
  799. let polygonAndMarkerStyle = setStyle('polygon');
  800. for (let i = 0; i < airspaceInfos.length; i++) {
  801. let polygon = <AirspaceInfoPolygon>airspaceInfos[i]
  802. let airspaceTypeFix;
  803. if ((polygon as any).airspaceType)
  804. airspaceTypeFix = 'airspaceType';
  805. else
  806. airspaceTypeFix = 'airspace_type';
  807. if ((polygon as any)[airspaceTypeFix] == Global.airspaceType.polygon && currentAirspaceIndex != i) {
  808. let retObj = getPolygon(polygon, polygonAndMarkerStyle);
  809. markers.push(...retObj.markers);
  810. polygons.push(retObj.polygon);
  811. }
  812. }
  813. return { markers, polygons };
  814. }
  815. function getPolygonAndMarkerSelector(airspaceInfos: () => AirspaceInfo[], setStyle: FnSetStyle, currentAirspaceIndex: () => number | undefined) {
  816. return createSelector(
  817. airspaceInfos,
  818. () => setStyle,
  819. currentAirspaceIndex,
  820. getPolygonsAndMarkers
  821. );
  822. }
  823. function getMarkers(circlesAndMarkers: CirclesAndMarkers, polygonAndMarkers: PolygonsAndMarkers, lineAndMarkers: LinesAndMarkes) {
  824. let markers: Marker[] = [];
  825. if (circlesAndMarkers) {
  826. markers = [...circlesAndMarkers.markers]
  827. }
  828. if (polygonAndMarkers) {
  829. markers = [...markers, ...polygonAndMarkers.markers]
  830. }
  831. if (lineAndMarkers) {
  832. markers = [...markers, ...lineAndMarkers.markers]
  833. }
  834. return markers
  835. }
  836. function getMarkerSelector(
  837. circlesAndMarkers: OutputSelector<any, any, (...params: any[]) => CirclesAndMarkers>,
  838. polygonAndMarkers: OutputSelector<any, any, (...params: any[]) => PolygonsAndMarkers>,
  839. lineAndMarkers: OutputSelector<any, any, (...params: any[]) => LinesAndMarkes>) {
  840. return createSelector(
  841. circlesAndMarkers,
  842. polygonAndMarkers,
  843. lineAndMarkers,
  844. getMarkers
  845. )
  846. }
  847. function getRegionPoints(circles: Circle[], lineAndMarkers: LinesAndMarkes, polygonAndMarkers: PolygonsAndMarkers) {
  848. let regionPoints: Coordinate[] = new Array();
  849. for (let i = 0; i < circles.length; i++) {
  850. regionPoints.push(...getCircleRegions(circles[i]));
  851. }
  852. let lines = lineAndMarkers.lines;
  853. for (let i = 0; i < lines.length; i++) {
  854. regionPoints.push(...lines[i].coordinates);
  855. }
  856. let polygons = polygonAndMarkers.polygons;
  857. for (let i = 0; i < polygons.length; i++) {
  858. regionPoints.push(...polygons[i].coordinates);
  859. }
  860. return regionPoints;
  861. }
  862. function getRegionPointsSelector(
  863. circles: OutputSelector<any, any, (...params: any[])=>Circle[]>,
  864. lineAndMarkers: OutputSelector<any, any, (...params: any[])=>LinesAndMarkes>,
  865. polygonAndMarkers: OutputSelector<any, any, (...params: any[])=>PolygonsAndMarkers>) {
  866. return createSelector(
  867. circles,
  868. lineAndMarkers,
  869. polygonAndMarkers,
  870. getRegionPoints
  871. );
  872. }
  873. function getCircles(circlesAndMarkers: CirclesAndMarkers) {
  874. return circlesAndMarkers.circles;
  875. }
  876. function getCircleSelector(circlesAndMarkers: OutputSelector<any, any, (...params: any[])=> CirclesAndMarkers>) {
  877. return createSelector(
  878. circlesAndMarkers,
  879. getCircles
  880. );
  881. }
  882. function getLines(lineAndMarker: LinesAndMarkes) {
  883. return lineAndMarker.lines;
  884. }
  885. function getLineSelector(lineAndMarker: OutputSelector<any, any, (...params: any[])=>LinesAndMarkes>) {
  886. return createSelector(
  887. lineAndMarker,
  888. getLines
  889. );
  890. }
  891. function getPolygons(polygonAndMarkers: PolygonsAndMarkers, linePolygonsAndMarkers: LinesPolygonsAndMarkers) {
  892. return [...polygonAndMarkers.polygons, ...linePolygonsAndMarkers.polygons];
  893. }
  894. function getPolygonSelector(
  895. polygonAndMarkers: OutputSelector<any, any, (...params: any[]) => PolygonsAndMarkers>,
  896. linePolygonsAndMarkers: OutputSelector<any, any, (...params: any[]) => LinesPolygonsAndMarkers>) {
  897. return createSelector(
  898. polygonAndMarkers,
  899. linePolygonsAndMarkers,
  900. getPolygons
  901. );
  902. }
  903. export type FnSetStyle = (styleName: string) => null | ShapeStyle
  904. let setStyle: (style: undefined | ShapeStyles) => FnSetStyle = (styles) => {
  905. if (!styles)
  906. return () => null
  907. else
  908. return (shapeName: string): ShapeStyle => styles[shapeName]
  909. }
  910. //获取selector
  911. export function getShapesSelector(airspaceInfos: () => AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: () => number | undefined) {
  912. currentAirspaceIndex = currentAirspaceIndex ? currentAirspaceIndex : () => -1;
  913. let circlesAndMarkers = getCircleAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  914. let circles = getCircleSelector(circlesAndMarkers);
  915. let linePolygonsAndMarkers = getLinePolygonsAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  916. let lines = getLineSelector(linePolygonsAndMarkers);
  917. let polygonAndMarkers = getPolygonAndMarkerSelector(airspaceInfos, setStyle(style), currentAirspaceIndex);
  918. let polygons = getPolygonSelector(polygonAndMarkers, linePolygonsAndMarkers);
  919. let markers = getMarkerSelector(circlesAndMarkers, polygonAndMarkers, linePolygonsAndMarkers);
  920. let regionPoints = getRegionPointsSelector(circles, linePolygonsAndMarkers, polygonAndMarkers);
  921. return {
  922. markers,
  923. circles,
  924. lines,
  925. polygons,
  926. regionPoints
  927. }
  928. }
  929. //获取数组
  930. export function getShapes(airspaceInfos: AirspaceInfo[], style?: ShapeStyles, currentAirspaceIndex?: number) {
  931. let {markers, polygons, circles, lines, regionPoints} =
  932. getShapesSelector(()=>airspaceInfos, style, ()=>currentAirspaceIndex)
  933. return {
  934. markers: markers(airspaceInfos),
  935. circles: circles(airspaceInfos),
  936. lines: lines(airspaceInfos),
  937. polygons: polygons(airspaceInfos),
  938. regionPoints: regionPoints(airspaceInfos)
  939. }
  940. }
  941. // 总共 5 种格式, http://git.corp.brilliantaero.com/BA/Coco/issues/99#note_6358
  942. // 1. 全输出格式
  943. // 2. 简化格式
  944. // 3. 传真格式
  945. // 4. 用户端用的简化格式
  946. // 5. 极简格式
  947. function getHeight(height: number | string, unit: string | number, type: number) {
  948. let shortNum
  949. const num = +height; // to number
  950. if(num >= 100) {
  951. shortNum = parseInt(num/100 + '').toString()
  952. if(shortNum.length <2) {
  953. shortNum = '0' + shortNum
  954. }
  955. }
  956. let heightStandard = Global.heightStandardsById.get(unit)
  957. if(!heightStandard) {
  958. heightStandard = unit
  959. }
  960. // 这里统一使用数字判断
  961. let standardUnit = Global.heightStandards.get(heightStandard)
  962. let heightDesc
  963. switch(standardUnit) {
  964. case 1:
  965. heightDesc = ['H*真', '真高*米']
  966. break;
  967. case 2:
  968. heightDesc = ['H*标(含以下)', '标高*米(含以下)']
  969. break;
  970. case 3:
  971. heightDesc = ['H*真(含以下)', '真高*米(含以下)']
  972. break;
  973. default:
  974. heightDesc = ['H*标', '标高*米']
  975. }
  976. if(shortNum && (type == 1 || type == 2)) {
  977. // H02真,H02真(含以下)
  978. return heightDesc[0].replace('*', shortNum)
  979. } else {
  980. // 真高200米,真高200米(含以下)
  981. return heightDesc[1].replace('*', height + '')
  982. }
  983. }
  984. function getAirspaceName(airspaceInfo: AirspaceInfo) {
  985. if((airspaceInfo as any).airspace_name) {
  986. const ai = <AirspaceInfoServer> airspaceInfo;
  987. return ai.airspace_name
  988. } else {
  989. const ai = <AirspaceInfoLocal> airspaceInfo;
  990. return ai.name
  991. }
  992. }
  993. export function circleContent(airspaceInfo: AirspaceInfoCircle, type=3) {
  994. if(type == 5)
  995. return getAirspaceName(airspaceInfo)
  996. if('airspace_name' in airspaceInfo) {
  997. const lat = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lat);
  998. const lng = latLngDecimalToDegrees(airspaceInfo.center_point_of_flying.lng);
  999. let content = [];
  1000. let loc = `以${airspaceInfo.center_loc}`
  1001. if(type == 1 || type == 3)
  1002. loc += `(E${lng}, N${lat})`;
  1003. content.push(`${loc}为中心`)
  1004. content.push(`半径${airspaceInfo.radius_of_flying}米`);
  1005. content.push(getHeight(airspaceInfo.altitude, airspaceInfo.unit, type))
  1006. if (airspaceInfo.note)
  1007. content.push(`备注:${airspaceInfo.note}`)
  1008. return content.join(',');
  1009. } else {
  1010. let content = []
  1011. let loc = `以${airspaceInfo.addr}`
  1012. if(type == 1 || type == 3)
  1013. loc += `(E${airspaceInfo.lng}, N${airspaceInfo.lat})`;
  1014. content.push(`${loc}为中心`)
  1015. content.push(`半径${airspaceInfo.radius}米`);
  1016. content.push(getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type))
  1017. if (airspaceInfo.note)
  1018. content.push(`备注:${airspaceInfo.note}`)
  1019. return content.join(',');
  1020. }
  1021. }
  1022. function flyingCenter(item: CoordinateShort | {} = {}): string{
  1023. if(item == {}){
  1024. return "";
  1025. }
  1026. const pp = <CoordinateShort> item;
  1027. return (
  1028. "(E" + latLngDecimalToDegrees(pp.lng) +
  1029. ', ' +
  1030. "N" + latLngDecimalToDegrees(pp.lat) + ")"
  1031. );
  1032. }
  1033. export function lineContent(airspaceInfo: AirspaceInfoLine, type=3): string {
  1034. if(type == 5)
  1035. return getAirspaceName(airspaceInfo)
  1036. if('airspace_name' in airspaceInfo) {
  1037. let content = [];
  1038. content.push(`${airspaceInfo.start_loc}`)
  1039. if(type == 1 || type == 3)
  1040. content.push(`${flyingCenter(airspaceInfo.start_point)}`)
  1041. content.push(` - `)
  1042. content.push(getHeight(airspaceInfo.start_point.altitude, airspaceInfo.start_point.unit, type))
  1043. const passing_points = airspaceInfo.passing_points;
  1044. if(Array.isArray(passing_points)) {
  1045. for(let i = 0; i < passing_points.length; i++) {
  1046. const obj = passing_points[i];
  1047. if (obj.point_type == Global.pointTypes.point) {
  1048. let pp = <PassingPointNormalServer>obj;
  1049. const lat = latLngDecimalToDegrees(pp.lat)
  1050. const lng = latLngDecimalToDegrees(pp.lng)
  1051. content.push(` - ${pp.point_name}`)
  1052. if(type == 1 || type == 3)
  1053. content.push(`(E${lng}, N${lat})`)
  1054. } else if (obj.point_type == Global.pointTypes.nav) {
  1055. let pp = <PassingPointNavServer>obj;
  1056. const lat = latLngDecimalToDegrees(pp.lat)
  1057. const lng = latLngDecimalToDegrees(pp.lng)
  1058. content.push(` - ${pp.point_code}`)
  1059. if(type == 1 || type == 3)
  1060. content.push(`(E${lng}, N${lat})`)
  1061. } else {
  1062. let pp = <PassingPointAirlineServer>obj;
  1063. content.push(` - ${pp.air_route_code}`)
  1064. }
  1065. if(obj.altitude) {
  1066. content.push(` - ${getHeight(obj.altitude, obj.unit, type)}`)
  1067. }
  1068. }
  1069. }
  1070. content.push(` - ${airspaceInfo.end_loc}`)
  1071. if(type == 1 || type == 3)
  1072. content.push(`${flyingCenter(airspaceInfo.end_point)}`)
  1073. if(isSafeString(airspaceInfo.airline_width)) {
  1074. content.push(`,宽度:${airspaceInfo.airline_width}米`)
  1075. }
  1076. if(isSafeString(airspaceInfo.note)) {
  1077. content.push(`,备注: ${airspaceInfo.note}`)
  1078. }
  1079. let result = content.join("")
  1080. return result;
  1081. } else {
  1082. let content = [];
  1083. content.push(`${airspaceInfo.dep.addr}`)
  1084. if(type == 1 || type == 3)
  1085. content.push(`(E${airspaceInfo.dep.lng}, N${airspaceInfo.dep.lat})`)
  1086. content.push(` - ${getHeight(airspaceInfo.dep.height, airspaceInfo.dep.heightStandard, type)}`);
  1087. if (Array.isArray(airspaceInfo.passPoints)) {
  1088. let length = airspaceInfo.passPoints.length;
  1089. for (let i = 0; i < length; i++) {
  1090. let obj = airspaceInfo.passPoints[i];
  1091. if (obj.pointType == Global.pointTypes.point) {
  1092. let pp = <PassingPointNormalLocal>obj;
  1093. content.push(` - ${pp.addr}`)
  1094. if(type == 1 || type == 3)
  1095. content.push(`(E${pp.lng}, N${pp.lat})`);
  1096. } else if (obj.pointType == Global.pointTypes.nav) {
  1097. let pp = <PassingPointNavLocal>obj;
  1098. content.push(` - ${pp.pointCode}`)
  1099. if(type == 1 || type == 3)
  1100. content.push(`(E${pp.lng}, N${pp.lat})`);
  1101. } else {
  1102. let pp = <PassingPointAirlineLocal>obj;
  1103. content.push(` - ${pp.airlineCode}`);
  1104. }
  1105. if(obj.height) {
  1106. content.push(` - ${getHeight(obj.height, obj.heightStandard, type)}`)
  1107. }
  1108. }
  1109. }
  1110. content.push(` - ${airspaceInfo.arrive.addr}`)
  1111. if(type == 1 || type == 3)
  1112. content.push(`(E${airspaceInfo.arrive.lng}, N${airspaceInfo.arrive.lat})`);
  1113. if(airspaceInfo.airlineWidth) {
  1114. content.push(`,宽度:${airspaceInfo.airlineWidth}米`)
  1115. }
  1116. if (airspaceInfo.note)
  1117. content.push(`,备注:${airspaceInfo.note}`)
  1118. return content.join('');
  1119. }
  1120. }
  1121. export function polygonContent(airspaceInfo: AirspaceInfoPolygon, type=3): string {
  1122. if(type == 5)
  1123. return getAirspaceName(airspaceInfo)
  1124. if('airspace_name' in airspaceInfo) {
  1125. let res = []
  1126. let points = airspaceInfo.points
  1127. for (let i = 0; i < points.length; i++) {
  1128. let c = `${points[i].addr ? points[i].addr : ''}`
  1129. if(type == 1 || type == 3)
  1130. c += `(E${latLngDecimalToDegrees(points[i].lng)}, N${latLngDecimalToDegrees(points[i].lat)})`;
  1131. res.push(c)
  1132. }
  1133. let content = [res.join('、')]
  1134. content.push(`${airspaceInfo.points.length}点连线范围内`)
  1135. content.push(`,${getHeight(airspaceInfo.altitude, airspaceInfo.unit, type)}`)
  1136. if(isSafeString(airspaceInfo.note)) {
  1137. content.push(`,备注:${airspaceInfo.note}`)
  1138. }
  1139. return content.join('');
  1140. } else {
  1141. let content = [];
  1142. let length = airspaceInfo.polygonPoints.length;
  1143. for (let i = 0; i < length; i++) {
  1144. let obj = airspaceInfo.polygonPoints[i];
  1145. let c = `${obj.addr ? obj.addr : ''}`
  1146. if(type == 1 || type == 3)
  1147. c += `(E${obj.lng}, N${obj.lat})`
  1148. content.push(c)
  1149. }
  1150. let cc = content.join('、') + `${length}点连线范围内`
  1151. cc += `,${getHeight(airspaceInfo.height, airspaceInfo.heightStandard, type)}`
  1152. if (airspaceInfo.note)
  1153. cc = `${content},备注:${airspaceInfo.note}`
  1154. return cc;
  1155. }
  1156. }
  1157. export {latLngDegreesToDecimal, latLngDecimalToDegrees}