@dra2020/baseclient 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/all/all.d.ts +18 -0
  4. package/dist/baseclient.js +9567 -0
  5. package/dist/baseclient.js.map +1 -0
  6. package/dist/context/all.d.ts +1 -0
  7. package/dist/context/context.d.ts +13 -0
  8. package/dist/filterexpr/all.d.ts +1 -0
  9. package/dist/filterexpr/filterexpr.d.ts +64 -0
  10. package/dist/fsm/all.d.ts +1 -0
  11. package/dist/fsm/fsm.d.ts +118 -0
  12. package/dist/logabstract/all.d.ts +1 -0
  13. package/dist/logabstract/log.d.ts +26 -0
  14. package/dist/logclient/all.d.ts +1 -0
  15. package/dist/logclient/log.d.ts +6 -0
  16. package/dist/ot-editutil/all.d.ts +2 -0
  17. package/dist/ot-editutil/oteditutil.d.ts +14 -0
  18. package/dist/ot-editutil/otmaputil.d.ts +21 -0
  19. package/dist/ot-js/all.d.ts +9 -0
  20. package/dist/ot-js/otarray.d.ts +111 -0
  21. package/dist/ot-js/otclientengine.d.ts +38 -0
  22. package/dist/ot-js/otcomposite.d.ts +37 -0
  23. package/dist/ot-js/otcounter.d.ts +17 -0
  24. package/dist/ot-js/otengine.d.ts +22 -0
  25. package/dist/ot-js/otmap.d.ts +19 -0
  26. package/dist/ot-js/otserverengine.d.ts +38 -0
  27. package/dist/ot-js/otsession.d.ts +111 -0
  28. package/dist/ot-js/ottypes.d.ts +29 -0
  29. package/dist/poly/all.d.ts +15 -0
  30. package/dist/poly/blend.d.ts +1 -0
  31. package/dist/poly/boundbox.d.ts +16 -0
  32. package/dist/poly/cartesian.d.ts +5 -0
  33. package/dist/poly/graham-scan.d.ts +8 -0
  34. package/dist/poly/hash.d.ts +1 -0
  35. package/dist/poly/matrix.d.ts +24 -0
  36. package/dist/poly/minbound.d.ts +1 -0
  37. package/dist/poly/poly.d.ts +52 -0
  38. package/dist/poly/polybin.d.ts +5 -0
  39. package/dist/poly/polylabel.d.ts +7 -0
  40. package/dist/poly/polypack.d.ts +30 -0
  41. package/dist/poly/polyround.d.ts +1 -0
  42. package/dist/poly/polysimplify.d.ts +1 -0
  43. package/dist/poly/quad.d.ts +48 -0
  44. package/dist/poly/selfintersect.d.ts +1 -0
  45. package/dist/poly/shamos.d.ts +1 -0
  46. package/dist/poly/simplify.d.ts +2 -0
  47. package/dist/poly/topo.d.ts +46 -0
  48. package/dist/poly/union.d.ts +48 -0
  49. package/dist/util/all.d.ts +5 -0
  50. package/dist/util/bintrie.d.ts +93 -0
  51. package/dist/util/countedhash.d.ts +19 -0
  52. package/dist/util/gradient.d.ts +15 -0
  53. package/dist/util/indexedarray.d.ts +15 -0
  54. package/dist/util/util.d.ts +68 -0
  55. package/docs/context.md +2 -0
  56. package/docs/fsm.md +243 -0
  57. package/docs/logabstract.md +2 -0
  58. package/docs/logclient.md +2 -0
  59. package/docs/ot-editutil.md +2 -0
  60. package/docs/ot-js.md +95 -0
  61. package/docs/poly.md +103 -0
  62. package/docs/util.md +2 -0
  63. package/lib/all/all.ts +19 -0
  64. package/lib/context/all.ts +1 -0
  65. package/lib/context/context.ts +82 -0
  66. package/lib/filterexpr/all.ts +1 -0
  67. package/lib/filterexpr/filterexpr.ts +625 -0
  68. package/lib/fsm/all.ts +1 -0
  69. package/lib/fsm/fsm.ts +549 -0
  70. package/lib/logabstract/all.ts +1 -0
  71. package/lib/logabstract/log.ts +55 -0
  72. package/lib/logclient/all.ts +1 -0
  73. package/lib/logclient/log.ts +105 -0
  74. package/lib/ot-editutil/all.ts +2 -0
  75. package/lib/ot-editutil/oteditutil.ts +180 -0
  76. package/lib/ot-editutil/otmaputil.ts +209 -0
  77. package/lib/ot-js/all.ts +9 -0
  78. package/lib/ot-js/otarray.ts +1168 -0
  79. package/lib/ot-js/otclientengine.ts +327 -0
  80. package/lib/ot-js/otcomposite.ts +247 -0
  81. package/lib/ot-js/otcounter.ts +145 -0
  82. package/lib/ot-js/otengine.ts +71 -0
  83. package/lib/ot-js/otmap.ts +144 -0
  84. package/lib/ot-js/otserverengine.ts +329 -0
  85. package/lib/ot-js/otsession.ts +199 -0
  86. package/lib/ot-js/ottypes.ts +98 -0
  87. package/lib/poly/all.ts +15 -0
  88. package/lib/poly/blend.ts +27 -0
  89. package/lib/poly/boundbox.ts +102 -0
  90. package/lib/poly/cartesian.ts +130 -0
  91. package/lib/poly/graham-scan.ts +401 -0
  92. package/lib/poly/hash.ts +15 -0
  93. package/lib/poly/matrix.ts +309 -0
  94. package/lib/poly/minbound.ts +211 -0
  95. package/lib/poly/poly.ts +767 -0
  96. package/lib/poly/polybin.ts +218 -0
  97. package/lib/poly/polylabel.ts +204 -0
  98. package/lib/poly/polypack.ts +458 -0
  99. package/lib/poly/polyround.ts +30 -0
  100. package/lib/poly/polysimplify.ts +24 -0
  101. package/lib/poly/quad.ts +272 -0
  102. package/lib/poly/selfintersect.ts +87 -0
  103. package/lib/poly/shamos.ts +297 -0
  104. package/lib/poly/simplify.ts +119 -0
  105. package/lib/poly/topo.ts +525 -0
  106. package/lib/poly/union.ts +371 -0
  107. package/lib/util/all.ts +5 -0
  108. package/lib/util/bintrie.ts +603 -0
  109. package/lib/util/countedhash.ts +83 -0
  110. package/lib/util/gradient.ts +108 -0
  111. package/lib/util/indexedarray.ts +80 -0
  112. package/lib/util/util.ts +695 -0
  113. package/package.json +52 -0
@@ -0,0 +1,199 @@
1
+ // Errors
2
+ export const ESuccess: number = 0; // Generic success
3
+ export const EFail: number = 1; // Generic failure
4
+ export const EFull: number = 2; // Too many clients attached to this session; try later
5
+ export const ERetry: number = 3; // Try request again
6
+ export const ENoSession: number = 4; // No record of such session
7
+ export const EClockSeen: number = 5;
8
+ export const EClockFailure: number = 6;
9
+ export const EClockReset: number = 7;
10
+ export const ENoUser: number = 8; // No user specified (internal error since all authorized reqs have user)
11
+ export const EBadRequest: number = 9; // Badly formed request
12
+ export const ELoadFailed: number = 10; // Session exists in index, but load of state failed ((temp?) internal error)
13
+ export const ENoPerm: number = 11; // No permissions (readonly)
14
+ export const ENoAccess: number = 12; // No access (no read)
15
+ export const EMaintenance: number = 13; // Server under maintenance
16
+ export const EClockAnomaly: number = 14; // Typically server restart and client is ahead
17
+
18
+ // Filters
19
+ export const FilterMyMaps: number = 0;
20
+ export const FilterSharedWithMe: number = 1;
21
+ export const FilterMyPublic: number = 2;
22
+ export const FilterRecent: number = 3;
23
+ export const FilterTrash: number = 4;
24
+ export const FilterPublic: number = 5;
25
+ export const FilterOfficial: number = 6;
26
+ export const FilterCount: number = 7;
27
+ export type Filter = number;
28
+
29
+ // Permissions
30
+ export const PermNone: number = 0; // No permissions
31
+ export const PermRead: number = 1; // Can view
32
+ export const PermWrite: number = 2; // Can modify
33
+ export const PermOwner: number = 4; // Can change deleted, published, access permissions
34
+ export const PermAdmin: number = 8; // Can administer site
35
+ export const PermEdit: number = (PermWrite|PermOwner);
36
+ export const PermAll: number = (PermRead|PermWrite|PermOwner|PermAdmin);
37
+ export type Permission = number;
38
+
39
+ // Server State
40
+ export const ServerStateRunning: number = 0;
41
+ export const ServerStateMaintenance: number = 1;
42
+ export type ServerState = number;
43
+
44
+ // Maps Access Tokens (IDs) to SessionID
45
+ export interface AccessSessionMap
46
+ {
47
+ [key: string]: string;
48
+ }
49
+
50
+ // Maps Access ID to { list of users, permission } (stored with session)
51
+ export interface AccessMap
52
+ {
53
+ [key: string]: Access;
54
+ }
55
+
56
+ export interface Access
57
+ {
58
+ userIDs: string[]; // empty implies "anyone"
59
+ perm: Permission;
60
+ }
61
+
62
+ export interface Revision
63
+ {
64
+ id: string;
65
+ modifyTime: any; // JSON date
66
+ label?: string; // optional label
67
+ }
68
+
69
+ export type RevisionList = Revision[];
70
+
71
+ export interface SessionUser
72
+ {
73
+ id: string;
74
+ name: string;
75
+ }
76
+
77
+ export interface ActiveUser
78
+ {
79
+ id: string;
80
+ name: string;
81
+ active: number;
82
+ }
83
+
84
+ export interface SessionUserIndex
85
+ {
86
+ [key: string]: SessionUser;
87
+ }
88
+
89
+ export interface SessionUserList
90
+ {
91
+ [key: string]: number;
92
+ }
93
+
94
+ export interface SessionProps
95
+ {
96
+ id: string;
97
+ name: string;
98
+ type: string;
99
+ description: string;
100
+ labels: string[];
101
+ createdBy: string;
102
+ lastActive: any; // JSON date (should be string)
103
+ createTime: any; // JSON date (should be string)
104
+ modifyTime: any; // JSON date (should be string)
105
+ clientCount: number;
106
+ maxClients: number;
107
+ requestCount: number;
108
+ deleted: boolean;
109
+ published?: string;
110
+ official: boolean;
111
+ loadFailed: boolean;
112
+ accessMap: AccessMap;
113
+ revisions: RevisionList;
114
+ xprops?: { [prop: string]: string };
115
+ }
116
+
117
+ // True to add, False to remove
118
+ export type LabelUpdate = { [name: string]: boolean|null }
119
+
120
+ export interface SessionUpdateProps
121
+ {
122
+ id: string;
123
+ deleted?: boolean;
124
+ published?: boolean;
125
+ official?: boolean;
126
+ name?: string;
127
+ description?: string;
128
+ labelupdate?: LabelUpdate;
129
+ access?: Access;
130
+ accessUpdate?: AccessMap;
131
+ restore?: string; // Revision ID
132
+ revision?: Revision; // If ID is empty, snap a new revision, otherwise label it.
133
+ }
134
+
135
+ export interface SessionsIndex
136
+ {
137
+ [key: string]: SessionProps;
138
+ }
139
+
140
+ // The semantics here are:
141
+ // if aid is provided, only look through that access token.
142
+ // if aid is missing, look for that user in any access token (but ignore anonymous tokens).
143
+ // in either case, return the full set of permissions a user has.
144
+ //
145
+ export function accessFindUser(a: Access, uid: string): Permission
146
+ {
147
+ if (a === undefined) return PermNone;
148
+ if (a.userIDs.length == 0)
149
+ return a.perm;
150
+ for (let i: number = 0; i < a.userIDs.length; i++)
151
+ if (a.userIDs[i] === uid) return a.perm;
152
+ return PermNone;
153
+ }
154
+
155
+ export function accessMapFindUser(accessMap: AccessMap, uid: string, aid?: string): Permission
156
+ {
157
+ if (aid !== undefined)
158
+ return accessFindUser(accessMap[aid], uid);
159
+ else
160
+ {
161
+ let perm: Permission = PermNone;
162
+ for (var aid1 in accessMap) if (accessMap.hasOwnProperty(aid1))
163
+ {
164
+ let a = accessMap[aid1];
165
+ for (let i: number = 0; i < a.userIDs.length; i++)
166
+ if (a.userIDs[i] === uid)
167
+ {
168
+ perm |= a.perm;
169
+ break;
170
+ }
171
+ }
172
+ return perm;
173
+ }
174
+ }
175
+
176
+ export function SessionFilterFunction(p: SessionProps, uid: string, f: number): boolean
177
+ {
178
+ if (f === FilterPublic) return p.published !== undefined;
179
+
180
+ if (f === FilterSharedWithMe)
181
+ {
182
+ if (p.createdBy === uid) return false;
183
+ return true;
184
+ }
185
+
186
+ // All other filters require ownership of this session
187
+ if (p.createdBy !== uid) return false;
188
+
189
+ if (f === FilterTrash) return p.deleted;
190
+
191
+ if (f === FilterRecent && !p.deleted && p.modifyTime)
192
+ {
193
+ let d = new Date();
194
+ let interval = d.getTime() - new Date(p.modifyTime).getTime();
195
+ return interval < (1000 * 60 * 60 * 24 * 7); // one week
196
+ }
197
+
198
+ return !p.deleted;
199
+ }
@@ -0,0 +1,98 @@
1
+
2
+ // Resource data type that supports basic OT inteface.
3
+ export interface IOTResource
4
+ {
5
+ resourceName: string;
6
+ underlyingType: string;
7
+ edits: any[];
8
+
9
+ // Normally defined by base class
10
+ length: number;
11
+ empty(): void;
12
+ isEmpty(): boolean;
13
+
14
+ // Copy an instance
15
+ copy(): IOTResource;
16
+
17
+ // Test whether two operations are effectively equivalent
18
+ effectivelyEqual(rhs: IOTResource): boolean;
19
+
20
+ // Core OT algorithm for this type
21
+ transform(rhs: IOTResource, bPriorIsService: boolean): void; // throws on error
22
+
23
+ // compose two edit actions
24
+ compose(rhs: IOTResource): void; // throws on error
25
+
26
+ // apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
27
+ apply(startValue: any): any;
28
+
29
+ // return a collapsed, minimal version of the operation, suitable for constructing from scratch from empty initial value
30
+ minimize(): void;
31
+ }
32
+
33
+ // Useful base class
34
+ export class OTResourceBase implements IOTResource
35
+ {
36
+ resourceName: string;
37
+ underlyingType: string;
38
+ edits: any[];
39
+
40
+ constructor(rname: string, utype: string)
41
+ {
42
+ this.resourceName = rname;
43
+ this.underlyingType = utype;
44
+ this.edits = [];
45
+ }
46
+
47
+ get length(): number
48
+ {
49
+ return this.edits.length;
50
+ }
51
+
52
+ // Set an existing instance of the operation to be empty
53
+ empty(): void
54
+ {
55
+ this.edits = [];
56
+ }
57
+
58
+ // Test
59
+ isEmpty(): boolean
60
+ {
61
+ return this.edits.length == 0;
62
+ }
63
+
64
+ // Copy an instance
65
+ copy(): OTResourceBase
66
+ {
67
+ throw "OTResourceBase.copy must be overridden in subclass";
68
+ }
69
+
70
+ // Test whether two operations are effectively equivalent
71
+ effectivelyEqual(rhs: OTResourceBase): boolean
72
+ {
73
+ throw "OTResourceBase.effectivelyEqual must be overridden in subclass";
74
+ }
75
+
76
+ // Core OT algorithm for this type
77
+ transform(rhs: OTResourceBase, bPriorIsService: boolean): void
78
+ {
79
+ throw "OTResourceBase.transform must be overridden in subclass";
80
+ }
81
+
82
+ // compose two edit actions
83
+ compose(rhs: OTResourceBase): void
84
+ {
85
+ throw "OTResourceBase.compose must be overridden in subclass";
86
+ }
87
+
88
+ // apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
89
+ apply(startValue: any): any
90
+ {
91
+ throw "OTResourceBase.apply must be overridden in subclass";
92
+ }
93
+
94
+ minimize(): void
95
+ {
96
+ // Default implementation does nothing.
97
+ }
98
+ }
@@ -0,0 +1,15 @@
1
+ export * from './poly';
2
+ export * from './union';
3
+ export * from './quad';
4
+ export * from './polylabel';
5
+ export * from './polysimplify';
6
+ export * from './polypack';
7
+ export * from './polybin';
8
+ export * from './boundbox';
9
+ export * from './blend';
10
+ export * from './cartesian';
11
+ export * from './minbound';
12
+ export * from './polyround';
13
+ export * from './topo';
14
+ export * from './selfintersect';
15
+ export * from './shamos';
@@ -0,0 +1,27 @@
1
+ import * as Util from '../util/all';
2
+ import * as PP from './polypack';
3
+
4
+ // Takes array of polygon or multi-polygon coordinate structures and returns a single multi-polygon
5
+ // structure. The coordinates may be passed in using packed format.
6
+
7
+ export function blend(polys: any[]): any
8
+ {
9
+ if (polys == null || polys.length == 0) return null;
10
+
11
+ let result: any[] = [];
12
+
13
+ for (let i: number = 0; i < polys.length; i++)
14
+ {
15
+ let p = PP.polyUnpack(polys[i]);
16
+ let d = Util.depthof(p);
17
+ if (d === 4)
18
+ result.push(p);
19
+ else if (d === 5)
20
+ for (let j: number = 0; j < p.length; j++)
21
+ result.push(p[j]);
22
+ else if (p.length === undefined || p.length > 0)
23
+ throw new Error('blend expects polygon or multi-polygon coordinates');
24
+ }
25
+
26
+ return result;
27
+ }
@@ -0,0 +1,102 @@
1
+ import * as Util from '../util/all';
2
+
3
+ import * as P from './poly';
4
+ import * as PP from './polypack';
5
+
6
+ // Note, in Geo format so top > bottom
7
+ export interface BoundBox
8
+ {
9
+ left?: number;
10
+ top?: number;
11
+ right?: number;
12
+ bottom?: number;
13
+ }
14
+
15
+ export function boundboxWidth(bb: BoundBox): number { return Math.abs(bb.right - bb.left); }
16
+ export function boundboxHeight(bb: BoundBox): number { return Math.abs(bb.bottom - bb.top); }
17
+
18
+ export function boundboxCX(bb: BoundBox): number { return bb.left + (bb.right - bb.left) / 2; }
19
+ export function boundboxCY(bb: BoundBox): number { return bb.top + (bb.bottom - bb.top) / 2; }
20
+
21
+ export function clipLon(lon: number): number { return lon <= 0 ? lon : -179; }
22
+
23
+ export function boundboxExtend(bbox: BoundBox, x: number, y: number): void
24
+ {
25
+ x = clipLon(x);
26
+ if (bbox.left === undefined || x < bbox.left)
27
+ bbox.left = x;
28
+ if (bbox.right === undefined || x > bbox.right)
29
+ bbox.right = x;
30
+ if (bbox.top === undefined || y > bbox.top)
31
+ bbox.top = y;
32
+ if (bbox.bottom === undefined || y < bbox.bottom)
33
+ bbox.bottom = y;
34
+ }
35
+
36
+ function boundboxExtendPacked(pp: PP.PolyPack, bbox: BoundBox): void
37
+ {
38
+ let buffer = pp.buffer as Float64Array;
39
+ let offset = pp.buffer[pp.offset+1] + pp.offset;
40
+ let end = pp.offset + pp.length;
41
+ for (; offset < end; offset += 2)
42
+ boundboxExtend(bbox, buffer[offset], buffer[offset+1]);
43
+ }
44
+
45
+ export function boundbox(poly: any, bbox?: BoundBox): BoundBox
46
+ {
47
+ let i: number;
48
+
49
+ if (bbox === undefined)
50
+ bbox = { };
51
+
52
+ if (poly)
53
+ {
54
+ // Collection
55
+ if (poly.features)
56
+ {
57
+ for (i = 0; i < poly.features.length; i++)
58
+ boundbox(poly.features[i], bbox);
59
+ }
60
+
61
+ // feature
62
+ else if (poly.geometry)
63
+ {
64
+ if (poly.geometry.packed)
65
+ boundboxExtendPacked(poly.geometry.packed as PP.PolyPack, bbox);
66
+ else if (poly.geometry.coordinates)
67
+ boundbox(poly.geometry.coordinates, bbox);
68
+ }
69
+
70
+ // raw packed buffer
71
+ else if (poly.offset !== undefined)
72
+ boundboxExtendPacked(poly as PP.PolyPack, bbox);
73
+
74
+ // array of other things (like raw coordinates, or other aggregates)
75
+ else if (Array.isArray(poly) && typeof poly[0] !== 'number')
76
+ {
77
+ for (i = 0; i < poly.length; i++)
78
+ boundbox(poly[i], bbox);
79
+ }
80
+
81
+ // single point
82
+ else
83
+ boundboxExtend(bbox, poly[0], poly[1]);
84
+ }
85
+
86
+ return bbox;
87
+ }
88
+
89
+ export function boundboxPoly(bb: BoundBox): any
90
+ {
91
+ return [ [ [bb.left, bb.top], [bb.left, bb.bottom], [bb.right, bb.bottom], [bb.right, bb.top], [bb.left, bb.top] ] ];
92
+ }
93
+
94
+ export function boundboxArea(poly: any): number
95
+ {
96
+ return P.polyArea(boundboxPoly(boundbox(poly)));
97
+ }
98
+
99
+ export function boundboxIntersects(bb1: BoundBox, bb2: BoundBox): boolean
100
+ {
101
+ return !(bb1.left > bb2.right || bb1.right < bb2.left || bb1.top < bb2.bottom || bb1.bottom > bb2.top);
102
+ }
@@ -0,0 +1,130 @@
1
+ //
2
+ // GEO-FEATURES UTILITIES
3
+ //
4
+
5
+ import * as GeoJSON from 'geojson';
6
+ import * as P from './poly';
7
+ import * as PP from './polypack';
8
+
9
+
10
+ // HELPER
11
+
12
+ function bufferToRing(b: Float64Array, s: number, nPoints: number): any
13
+ {
14
+ let r: any = [];
15
+ let e = s + nPoints * 2;
16
+ for (; s < e; s += 2)
17
+ r.push([ b[s], b[s+1] ]);
18
+ return r;
19
+ }
20
+
21
+ export function polyParts(poly: any): GeoJSON.FeatureCollection
22
+ {
23
+ let pp = P.polyNormalize(poly);
24
+
25
+ let parts: GeoJSON.FeatureCollection = { type: 'FeatureCollection', features: [] };
26
+ let af: any = parts.features;
27
+ let f: any;
28
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
29
+ let r = bufferToRing(b, iOffset, nPoints);
30
+ if (iRing == 0)
31
+ {
32
+ f = { type: 'Feature',
33
+ properties: { id: String(iPoly+1) },
34
+ geometry: { type: 'Polygon', coordinates: [ r ] } };
35
+ af.push(f);
36
+ }
37
+ else
38
+ f.geometry.coordinates.push(r);
39
+ });
40
+ return parts;
41
+ }
42
+
43
+ // CARTESIAN ("FLAT") AREA, PERIMETER, AND DIAMETER
44
+
45
+ export function polyAreaFlat(poly: any): number
46
+ {
47
+ let pp = P.polyNormalize(poly);
48
+
49
+ let a: number = 0;
50
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
51
+ a += polySimpleAreaFlat(b, iOffset, nPoints) * (iRing == 0 ? 1 : -1);
52
+ });
53
+ return a;
54
+ }
55
+
56
+ // Algorithm for the area of a simple/single planar polygon:
57
+ // https://algorithmtutor.com/Computational-Geometry/Area-of-a-polygon-given-a-set-of-points/
58
+ // https://mathopenref.com/coordpolygonarea2.html
59
+ //
60
+ // function polygonArea(X, Y, numPoints)
61
+ // {
62
+ // area = 0; // Accumulates area in the loop
63
+ // j = numPoints-1; // The last vertex is the 'previous' one to the first
64
+
65
+ // for (i=0; i<numPoints; i++)
66
+ // { area = area + (X[j]+X[i]) * (Y[j]-Y[i]);
67
+ // j = i; //j is previous vertex to i
68
+ // }
69
+ // return area/2;
70
+ // }
71
+
72
+ // Reimplemented to use polygons vs. X & Y vectors
73
+ function polySimpleAreaFlat(b: Float64Array, i: number, nPoints: number): number
74
+ {
75
+ let a = 0;
76
+ let e = i + nPoints * 2;
77
+ let j = e - 2; // The last vertex is the 'previous' one to the first
78
+
79
+ for (; i < e; i += 2)
80
+ {
81
+ a += (b[j] + b[i]) * (b[j+1] - b[i+1]);
82
+ j = i;
83
+ }
84
+ return Math.abs(a / 2);
85
+ }
86
+
87
+ // You would need to divide by Poly.EARTH_RADIUS to go from the returned units of meters to Lat/Lon “units.”
88
+ // NOTE - No conversion of degrees to radians!
89
+
90
+ export function polyPerimeterFlat(poly: any): number
91
+ {
92
+ let pp = P.polyNormalize(poly);
93
+
94
+ let perimeter: number = 0;
95
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
96
+ // Ignore holes so only look at first ring
97
+ if (iRing == 0)
98
+ {
99
+ let s = iOffset;
100
+ let e = s + (nPoints-1) * 2; // index *at* last point since we look at next point in each iteration
101
+ for (; s < e; s += 2)
102
+ perimeter += _distance(b[s], b[s+1], b[s+2], b[s+3]);
103
+ s = iOffset;
104
+ if (nPoints > 2 && (b[s] != b[e] || b[s+1] != b[e+1]))
105
+ perimeter += _distance(b[s], b[s+1], b[e], b[e+1]);
106
+ }
107
+ });
108
+
109
+ return perimeter;
110
+ }
111
+
112
+ function _distance(x1: number, y1: number, x2: number, y2: number): number
113
+ {
114
+ const dLat = y2 - y1;
115
+ const dLon = x2 - x1;
116
+ let d: number;
117
+
118
+ d = Math.sqrt((dLat * dLat) + (dLon * dLon));
119
+
120
+ return d;
121
+ }
122
+
123
+ // The polyCircle code is already just treating the coordinate system as Cartesian.
124
+ // So just compute circle and return diameter.
125
+
126
+ export function polyDiameterFlat(poly: any): number
127
+ {
128
+ let circle = P.polyToCircle(poly);
129
+ return circle ? circle.r * 2 : 0;
130
+ }