1
- import { pairwise } from 'itertools-ts/lib/single' ;
2
1
import type { XPathNode } from '../../adapter/interface/XPathNode.ts' ;
3
2
import { EvaluationContext } from '../../context/EvaluationContext.ts' ;
4
- import { JRCompatibleGeoValueError } from '../../error/JRCompatibleGeoValueError.ts' ;
5
3
import type { EvaluableArgument } from '../../evaluator/functions/FunctionImplementation.ts' ;
6
4
import { NumberFunction } from '../../evaluator/functions/NumberFunction.ts' ;
7
- import type { GeopointCoordinates } from '../../lib/geo/Geopoint.ts' ;
8
- import { geopointCodec } from '../../lib/geo/geopointCodec.ts' ;
9
-
10
- const evaluatePoints = < T extends XPathNode > (
11
- context : EvaluationContext < T > ,
12
- expression : EvaluableArgument
13
- ) : GeopointCoordinates [ ] => {
14
- const results = expression . evaluate ( context ) ;
15
-
16
- const stringResults = [ ...results ] . map ( ( result ) => result . toString ( ) ) ;
17
- const geopointStrings = stringResults . flatMap ( ( result ) => {
18
- const string = result . toString ( ) . trim ( ) ;
19
-
20
- return string . split ( / \s * ; \s * / ) ;
21
- } ) ;
22
-
23
- return geopointStrings . map ( ( string ) => {
24
- return geopointCodec . decodeValue ( string ) ;
25
- } ) ;
26
- } ;
27
-
28
- interface Line {
29
- readonly start : GeopointCoordinates ;
30
- readonly end : GeopointCoordinates ;
31
- }
32
-
33
- const evaluateLines = < T extends XPathNode > (
34
- context : EvaluationContext < T > ,
35
- expression : readonly EvaluableArgument [ ]
36
- ) : Line [ ] => {
37
- const points = expression . flatMap ( ( el ) => evaluatePoints ( context , el ) ) ;
38
- if ( points . length < 2 ) {
39
- throw new JRCompatibleGeoValueError ( ) ;
40
- }
41
-
42
- return Array . from ( pairwise ( points ) ) . map ( ( line ) => {
43
- const [ start , end ] = line ;
44
-
45
- return {
46
- start,
47
- end,
48
- } ;
49
- } ) ;
50
- } ;
5
+ import { Geotrace } from '../../lib/geo/Geotrace.ts' ;
6
+ import type { GeotraceLine } from '../../lib/geo/GeotraceLine.ts' ;
51
7
52
8
const EARTH_EQUATORIAL_RADIUS_METERS = 6_378_100 ;
53
9
const PRECISION = 100 ;
@@ -70,7 +26,7 @@ const toAbsolutePrecision = (value: number, precision: number) => {
70
26
return Math . abs ( toPrecision ( value , precision ) ) ;
71
27
} ;
72
28
73
- const geodesicArea = ( lines : readonly Line [ ] ) : number => {
29
+ const geodesicArea = ( lines : readonly GeotraceLine [ ] ) : number => {
74
30
const [ firstLine , ...rest ] = lines ;
75
31
const lastLine = rest [ rest . length - 1 ] ;
76
32
@@ -81,7 +37,7 @@ const geodesicArea = (lines: readonly Line[]): number => {
81
37
const { start } = firstLine ;
82
38
const { end } = lastLine ;
83
39
84
- let shape : readonly Line [ ] ;
40
+ let shape : readonly GeotraceLine [ ] ;
85
41
86
42
if ( start . latitude === end . latitude && start . longitude === end . longitude ) {
87
43
shape = lines ;
@@ -101,19 +57,24 @@ const geodesicArea = (lines: readonly Line[]): number => {
101
57
return ( total * EARTH_EQUATORIAL_RADIUS_METERS * EARTH_EQUATORIAL_RADIUS_METERS ) / 2 ;
102
58
} ;
103
59
104
- export const area = new NumberFunction (
105
- 'area' ,
106
- [ { arityType : 'required' } ] ,
107
- ( context , [ expression ] ) => {
108
- const lines = evaluateLines ( context , [ expression ! ] ) ;
60
+ const evaluateArgumentValues = < T extends XPathNode > (
61
+ context : EvaluationContext < T > ,
62
+ args : readonly EvaluableArgument [ ]
63
+ ) : readonly string [ ] => {
64
+ const evaluations = args . flatMap ( ( arg ) => [ ... arg . evaluate ( context ) ] ) ;
109
65
110
- const areaResult = geodesicArea ( lines ) ;
66
+ return evaluations . map ( ( evaluation ) => evaluation . toString ( ) ) ;
67
+ } ;
111
68
112
- return toAbsolutePrecision ( areaResult , PRECISION ) ;
113
- }
114
- ) ;
69
+ export const area = new NumberFunction ( 'area' , [ { arityType : 'required' } ] , ( context , args ) => {
70
+ const values = evaluateArgumentValues ( context , args ) ;
71
+ const { lines } = Geotrace . fromEncodedValues ( values ) ;
72
+ const areaResult = geodesicArea ( lines ) ;
73
+
74
+ return toAbsolutePrecision ( areaResult , PRECISION ) ;
75
+ } ) ;
115
76
116
- const geodesicDistance = ( line : Line ) : number => {
77
+ const geodesicDistance = ( line : GeotraceLine ) : number => {
117
78
const { start, end } = line ;
118
79
const deltaLambda = toRadians ( start . longitude - end . longitude ) ;
119
80
const phi0 = toRadians ( start . latitude ) ;
@@ -140,7 +101,8 @@ export const distance = new NumberFunction(
140
101
'distance' ,
141
102
[ { arityType : 'required' } , { arityType : 'variadic' } ] ,
142
103
( context , args ) => {
143
- const lines = evaluateLines ( context , args ) ;
104
+ const values = evaluateArgumentValues ( context , args ) ;
105
+ const { lines } = Geotrace . fromEncodedValues ( values ) ;
144
106
const distances = lines . map ( geodesicDistance ) ;
145
107
146
108
return toAbsolutePrecision ( sum ( distances ) , PRECISION ) ;
0 commit comments