utils.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { getCenter } from 'ol/extent';
  2. import { Geometry, LineString, Point } from 'ol/geom';
  3. import { toLonLat } from 'ol/proj';
  4. import { getArea, getLength } from 'ol/sphere';
  5. import { ArrayVector, Field, FieldType } from '@grafana/data';
  6. import { SpatialCalculation, SpatialCalculationOption } from './models.gen';
  7. /** Will return a field with a single row */
  8. export function toLineString(field: Field<Geometry | undefined>): LineString {
  9. const coords: number[][] = [];
  10. for (const geo of field.values.toArray()) {
  11. if (geo) {
  12. coords.push(getCenterPoint(geo));
  13. }
  14. }
  15. return new LineString(coords);
  16. }
  17. /** Will return a field with a single row */
  18. export function calculateBearings(values: Array<Geometry | undefined>): number[] {
  19. const bearing = new Array(values.length);
  20. if (values.length > 1) {
  21. let prev: number[] | undefined = getCenterPointWGS84(values[0]);
  22. for (let i = 1; i < values.length; i++) {
  23. let next: number[] | undefined = getCenterPointWGS84(values[i]);
  24. if (prev && next) {
  25. let degrees = (Math.atan2(next[0] - prev[0], next[1] - prev[1]) * 180) / Math.PI;
  26. if (degrees < 0.0) {
  27. degrees += 360.0;
  28. }
  29. bearing[i - 1] = bearing[i] = degrees;
  30. }
  31. }
  32. } else {
  33. bearing.fill(0);
  34. }
  35. return bearing;
  36. }
  37. export function getCenterPoint(geo: Geometry): number[] {
  38. if (geo instanceof Point) {
  39. return (geo as Point).getCoordinates();
  40. }
  41. return getCenter(geo.getExtent());
  42. }
  43. export function getCenterPointWGS84(geo?: Geometry): number[] | undefined {
  44. if (!geo) {
  45. return undefined;
  46. }
  47. return toLonLat(getCenterPoint(geo));
  48. }
  49. /** Will return a new field with calculated values */
  50. export function doGeomeryCalculation(field: Field<Geometry | undefined>, options: SpatialCalculationOption): Field {
  51. const values = field.values.toArray();
  52. const buffer = new Array(field.values.length);
  53. const op = options.calc ?? SpatialCalculation.Heading;
  54. const name = options.field ?? op;
  55. switch (op) {
  56. case SpatialCalculation.Area: {
  57. for (let i = 0; i < values.length; i++) {
  58. const geo = values[i];
  59. if (geo) {
  60. buffer[i] = getArea(geo);
  61. }
  62. }
  63. return {
  64. name,
  65. type: FieldType.number,
  66. config: {
  67. unit: 'areaM2',
  68. },
  69. values: new ArrayVector(buffer),
  70. };
  71. }
  72. case SpatialCalculation.Distance: {
  73. for (let i = 0; i < values.length; i++) {
  74. const geo = values[i];
  75. if (geo) {
  76. buffer[i] = getLength(geo);
  77. }
  78. }
  79. return {
  80. name,
  81. type: FieldType.number,
  82. config: {
  83. unit: 'lengthm',
  84. },
  85. values: new ArrayVector(buffer),
  86. };
  87. }
  88. // Use heading as default
  89. case SpatialCalculation.Heading:
  90. default: {
  91. return {
  92. name,
  93. type: FieldType.number,
  94. config: {
  95. unit: 'degree',
  96. },
  97. values: new ArrayVector(calculateBearings(values)),
  98. };
  99. }
  100. }
  101. }