geogrid 1.1.0 → 1.2.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.
@@ -1,124 +0,0 @@
1
- import { bbox } from "@turf/bbox";
2
- import { lineSplit } from "@turf/line-split";
3
- import { length as turfLength } from "@turf/length";
4
- import { booleanIntersects } from "@turf/boolean-intersects";
5
- import RBush from "rbush";
6
- import { min, max, median, mean, sum } from "d3-array";
7
-
8
- /**
9
- * @function linestogrid
10
- * @description Assigns lines to a grid and computes statistics per cell.
11
- * Supports weighted lengths or simple counts.
12
- * @param {object} opts
13
- * @property {object} [grid] - GeoJSON grid
14
- * @property {object} [lines] - GeoJSON lines (LineString or MultiLineString)
15
- * @property {string} [var] - Field for weighting length (optional)
16
- * @property {boolean} [values=false] - Include array of raw values/IDs
17
- */
18
- export function linestogrid(opts = {}) {
19
- const {
20
- grid,
21
- lines,
22
- var: varField,
23
- values: includeValues = false,
24
- sum: calcSum = true,
25
- median: calcMedian = false,
26
- min: calcMin = false,
27
- max: calcMax = false,
28
- mean: calcMean = false,
29
- } = opts;
30
-
31
- const t0 = performance.now();
32
- const gridFeatures = grid.features;
33
- const lineFeatures = lines.features;
34
- const hasVar = varField !== undefined && varField !== null;
35
-
36
- const gridbyindex = new Map(gridFeatures.map((d, i) => [i, d]));
37
-
38
- // ---- 1. Spatial index RBush ----
39
- const tree = new RBush();
40
- const items = gridFeatures.map((g, i) => {
41
- const [minX, minY, maxX, maxY] = bbox(g);
42
- return { minX, minY, maxX, maxY, i };
43
- });
44
- tree.load(items);
45
-
46
- // ---- 2. Prepare stats storage per cell ----
47
- const gridStats = new Map();
48
- gridFeatures.forEach((g, i) => {
49
- gridStats.set(i, { countSet: new Set(), valuesList: [], numericList: [] });
50
- });
51
-
52
- // ---- 3. Loop over lines ----
53
- lineFeatures.forEach((line, i) => {
54
- const totalLen = turfLength(line);
55
- if (totalLen === 0) return;
56
-
57
- const val = hasVar ? parseFloat(line.properties?.[varField]) || 0 : 1;
58
- const [minX, minY, maxX, maxY] = bbox(line);
59
- const candidates = tree.search({ minX, minY, maxX, maxY });
60
-
61
- for (const cand of candidates) {
62
- const g = gridbyindex.get(cand.i);
63
- if (!booleanIntersects(g, line)) continue;
64
-
65
- const split = lineSplit(line, g);
66
- if (!split || split.features.length === 0) continue;
67
-
68
- let lenInside = 0;
69
- split.features.forEach((seg) => {
70
- const segLen = turfLength(seg);
71
- if (segLen > 0 && booleanIntersects(g, seg)) {
72
- lenInside += segLen;
73
- }
74
- });
75
-
76
- if (lenInside > 0) {
77
- const stats = gridStats.get(cand.i);
78
- stats.countSet.add(i); // unique line IDs
79
-
80
- if (includeValues)
81
- stats.valuesList.push(hasVar ? line.properties[varField] : i);
82
-
83
- if (hasVar) stats.numericList.push(val * (lenInside / totalLen));
84
- }
85
- }
86
- });
87
-
88
- // ---- 4. Build final GeoJSON ----
89
- const result = {
90
- type: "FeatureCollection",
91
- features: gridFeatures
92
- .map((g, i) => {
93
- const stats = gridStats.get(i);
94
- const numericValues = stats.numericList;
95
- const values = stats.valuesList;
96
- const count = stats.countSet.size;
97
-
98
- if (count === 0) return null;
99
-
100
- const cellProps = { count };
101
-
102
- if (hasVar && numericValues.length > 0) {
103
- if (calcSum) cellProps.sum = sum(numericValues);
104
- if (calcMean) cellProps.mean = mean(numericValues);
105
- if (calcMedian) cellProps.median = median(numericValues);
106
- if (calcMin) cellProps.min = min(numericValues);
107
- if (calcMax) cellProps.max = max(numericValues);
108
- }
109
-
110
- if (includeValues) cellProps.values = values;
111
-
112
- return {
113
- type: g.type,
114
- properties: { ...g.properties, ...cellProps },
115
- geometry: g.geometry,
116
- };
117
- })
118
- .filter((f) => f !== null),
119
- };
120
-
121
- const t1 = performance.now();
122
- console.log(`Execution time: ${(t1 - t0).toFixed(2)} ms`);
123
- return result;
124
- }
@@ -1,144 +0,0 @@
1
- import { featureCollection } from "@turf/helpers";
2
- import { bbox } from "@turf/bbox";
3
- import { intersect } from "@turf/intersect";
4
- import area from "@turf/area";
5
- import RBush from "rbush";
6
- import { min, max, median, mean, sum } from "d3-array";
7
-
8
- /**
9
- * @function polygonstogrid
10
- * @description Assign polygons to a grid and compute statistics per cell.
11
- * Optimized and removes cells with count = 0
12
- * @param {object} opts
13
- * @property {object} [grid] - GeoJSON grid
14
- * @property {object} [polygons] - GeoJSON polygons to assign
15
- * @property {string} [var] - Field for weighting (optional)
16
- * @property {boolean} [values=false] - Include array of raw values
17
- * @property {boolean} [sum=true] - Compute sum
18
- * @property {boolean} [median=false] - Compute median
19
- * @property {boolean} [min=false] - Compute minimum
20
- * @property {boolean} [max=false] - Compute maximum
21
- * @property {boolean} [mean=false] - Compute mean
22
- */
23
- export function polygonstogrid(opts = {}) {
24
- const {
25
- grid,
26
- polygons,
27
- var: varField,
28
- values: includeValues = false,
29
- sum: calcSum = true,
30
- median: calcMedian = false,
31
- min: calcMin = false,
32
- max: calcMax = false,
33
- mean: calcMean = false,
34
- } = opts;
35
-
36
- const t0 = performance.now();
37
-
38
- const gridFeatures = grid.features;
39
- const polys = polygons.features;
40
- const hasVar = varField !== undefined && varField !== null;
41
-
42
- const gridbyindex = new Map(gridFeatures.map((d, i) => [i, d]));
43
-
44
- // ---- 1. Spatial index ----
45
- const tree = new RBush();
46
- const items = gridFeatures.map((g, i) => {
47
- const [minX, minY, maxX, maxY] = bbox(g);
48
- return { minX, minY, maxX, maxY, i };
49
- });
50
- tree.load(items);
51
-
52
- // ---- 2. Stockage pour chaque carré ----
53
- const gridStats = new Map();
54
- gridFeatures.forEach((_, i) => {
55
- gridStats.set(i, { numericList: [], valuesList: [], countSet: new Set() });
56
- });
57
-
58
- // ---- 3. Boucle sur les polygones ----
59
- for (let i = 0; i < polys.length; i++) {
60
- const p = polys[i];
61
- if (!p.geometry || !["Polygon", "MultiPolygon"].includes(p.geometry.type))
62
- continue;
63
-
64
- const val = hasVar ? parseFloat(p.properties?.[varField]) || 0 : 1;
65
-
66
- // 3a. Récupérer tous les carrés intersectant ce polygone
67
- const [minX, minY, maxX, maxY] = bbox(p);
68
- const candidates = tree.search({ minX, minY, maxX, maxY });
69
-
70
- // 3b. Calculer toutes les intersections et leur aire
71
- const pieces = [];
72
- for (const cand of candidates) {
73
- const g = gridbyindex.get(cand.i);
74
- if (!g.geometry || !["Polygon", "MultiPolygon"].includes(g.geometry.type))
75
- continue;
76
-
77
- let f;
78
- try {
79
- f = intersect(featureCollection([p, g]));
80
- } catch (e) {
81
- continue;
82
- }
83
- if (!f) continue;
84
-
85
- const areapiece = area(f);
86
- if (areapiece <= 0) continue;
87
-
88
- pieces.push({ index: cand.i, area: areapiece });
89
- }
90
-
91
- // 3c. Somme totale des aires des morceaux pour ce polygone
92
- const totalPieceArea = sum(pieces.map((d) => d.area));
93
- if (totalPieceArea === 0) continue;
94
-
95
- // 3d. Calculer la valeur proportionnelle de chaque morceau
96
- for (const piece of pieces) {
97
- const fraction = piece.area / totalPieceArea;
98
- const pieceValue = val * fraction;
99
-
100
- const stats = gridStats.get(piece.index);
101
- stats.numericList.push(pieceValue);
102
- if (includeValues) stats.valuesList.push(pieceValue);
103
- stats.countSet.add(i);
104
- }
105
- }
106
-
107
- // ---- 4. Construire le GeoJSON final ----
108
- const result = {
109
- type: "FeatureCollection",
110
- features: gridFeatures
111
- .map((g, i) => {
112
- const stats = gridStats.get(i);
113
- const numericValues = stats.numericList;
114
- const values = stats.valuesList;
115
- const count = stats.countSet.size;
116
-
117
- if (count === 0) return null;
118
-
119
- const cellProps = { count };
120
-
121
- if (hasVar && numericValues.length > 0) {
122
- if (calcSum) cellProps.sum = sum(numericValues);
123
- if (calcMean) cellProps.mean = mean(numericValues);
124
- if (calcMedian) cellProps.median = median(numericValues);
125
- if (calcMin) cellProps.min = min(numericValues);
126
- if (calcMax) cellProps.max = max(numericValues);
127
- }
128
-
129
- if (includeValues) cellProps.values = values;
130
-
131
- return {
132
- type: g.type,
133
- properties: { ...g.properties, ...cellProps },
134
- geometry: g.geometry,
135
- };
136
- })
137
- .filter((f) => f !== null),
138
- };
139
-
140
- const t1 = performance.now();
141
- console.log(`Execution time: ${(t1 - t0).toFixed(2)} ms`);
142
-
143
- return result;
144
- }