geogrid 0.0.3 → 0.0.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geogrid",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Regular and irregular geoJSON grids ",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -36,10 +36,15 @@
36
36
  },
37
37
  "homepage": "https://github.com/neocarto/geogrid#readme",
38
38
  "dependencies": {
39
+ "@turf/area": "^7.2.0",
39
40
  "@turf/bbox": "^7.2.0",
41
+ "@turf/boolean-intersects": "^7.2.0",
40
42
  "@turf/boolean-point-in-polygon": "^7.1.0",
43
+ "@turf/boolean-within": "^7.2.0",
41
44
  "@turf/helpers": "^7.1.0",
42
45
  "@turf/intersect": "^7.1.0",
46
+ "@turf/length": "^7.2.0",
47
+ "@turf/line-split": "^7.2.0",
43
48
  "d3-array": "^3.2.4",
44
49
  "d3-delaunay": "^6.0.4",
45
50
  "d3-geo": "^3.1.1",
@@ -47,7 +52,6 @@
47
52
  "docs": "^0.3.2-canary.0",
48
53
  "documentation": "^14.0.3",
49
54
  "geojson2h3": "^1.2.0",
50
- "geotoolbox": "^3.0.3",
51
55
  "h3-js": "^4.1.0",
52
56
  "rbush": "^4.0.1",
53
57
  "rollup": "^4.10.0"
@@ -2,12 +2,12 @@ import { geoProject } from "d3-geo-projection";
2
2
  const d3 = Object.assign({}, { geoProject });
3
3
 
4
4
  /**
5
- * @function tool/project
6
- * @description The function `tool.project` use geoproject from d3-geo-projection to project a geoJSON. It returns a GeoJSON FeatureCollection with coordinates in the page map.
5
+ * @function project
6
+ * @description The function `project` use geoproject from d3-geo-projection to project a geoJSON. It returns a GeoJSON FeatureCollection with coordinates in the page map.
7
7
  * @property {object} data - a GeoJSON FeatureCollection
8
8
  * @property {function} options.projection - projection definition. See [d3-geo](https://github.com/d3/d3-geo) & [d3-geo-projection](https://github.com/d3/d3-geo-projection)
9
9
  * @example
10
- * let newGeoJSON = geoviz.tool.project(world, { projection: d3.geoOrthographic()})
10
+ * let newGeoJSON = project(world, { projection: d3.geoOrthographic()})
11
11
  */
12
12
  export function project(data, { projection = null } = {}) {
13
13
  return projection == null ? data : d3.geoProject(data, projection);
package/src/index.js CHANGED
@@ -1,9 +1,11 @@
1
- export { square } from "./grid/square.js";
2
- export { triangle } from "./grid/triangle.js";
3
- export { dot } from "./grid/dot.js";
4
- export { random } from "./grid/random.js";
5
- export { diamond } from "./grid/diamond.js";
1
+ // export { square } from "./grid/square.js";
2
+ // export { triangle } from "./grid/triangle.js";
3
+ // export { dot } from "./grid/dot.js";
4
+ //export { random } from "./grid/random.js";
5
+ // export { diamond } from "./grid/diamond.js";
6
6
  export { hexbin } from "./grid/hexbin.js";
7
- export { h3 } from "./grid/h3.js";
7
+ // export { h3 } from "./grid/h3.js";
8
8
  export { pointstogrid } from "./operator/pointstogrid.js";
9
- export { polygonstogrid } from "./operator/polygonstogrid.js";
9
+ // export { polygonstogrid } from "./operator/polygonstogrid.js";
10
+ // export { linestogrid } from "./operator/linestogrid.js";
11
+ // export { project } from "./helpers/project.js";
@@ -0,0 +1,129 @@
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
+ * @property {boolean} [sum=true] - Compute sum of weighted lengths
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 linestogrid(opts = {}) {
24
+ const {
25
+ grid,
26
+ lines,
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
+ const gridFeatures = grid.features;
38
+ const lineFeatures = lines.features;
39
+ const hasVar = varField !== undefined && varField !== null;
40
+
41
+ const gridbyindex = new Map(gridFeatures.map((d, i) => [i, d]));
42
+
43
+ // ---- 1. Spatial index RBush ----
44
+ const tree = new RBush();
45
+ const items = gridFeatures.map((g, i) => {
46
+ const [minX, minY, maxX, maxY] = bbox(g);
47
+ return { minX, minY, maxX, maxY, i };
48
+ });
49
+ tree.load(items);
50
+
51
+ // ---- 2. Prepare stats storage per cell ----
52
+ const gridStats = new Map();
53
+ gridFeatures.forEach((g, i) => {
54
+ gridStats.set(i, { countSet: new Set(), valuesList: [], numericList: [] });
55
+ });
56
+
57
+ // ---- 3. Loop over lines ----
58
+ lineFeatures.forEach((line, i) => {
59
+ const totalLen = turfLength(line);
60
+ if (totalLen === 0) return;
61
+
62
+ const val = hasVar ? parseFloat(line.properties?.[varField]) || 0 : 1;
63
+ const [minX, minY, maxX, maxY] = bbox(line);
64
+ const candidates = tree.search({ minX, minY, maxX, maxY });
65
+
66
+ for (const cand of candidates) {
67
+ const g = gridbyindex.get(cand.i);
68
+ if (!booleanIntersects(g, line)) continue;
69
+
70
+ const split = lineSplit(line, g);
71
+ if (!split || split.features.length === 0) continue;
72
+
73
+ let lenInside = 0;
74
+ split.features.forEach((seg) => {
75
+ const segLen = turfLength(seg);
76
+ if (segLen > 0 && booleanIntersects(g, seg)) {
77
+ lenInside += segLen;
78
+ }
79
+ });
80
+
81
+ if (lenInside > 0) {
82
+ const stats = gridStats.get(cand.i);
83
+ stats.countSet.add(i); // unique line IDs
84
+
85
+ if (includeValues)
86
+ stats.valuesList.push(hasVar ? line.properties[varField] : i);
87
+
88
+ if (hasVar) stats.numericList.push(val * (lenInside / totalLen));
89
+ }
90
+ }
91
+ });
92
+
93
+ // ---- 4. Build final GeoJSON ----
94
+ const result = {
95
+ type: "FeatureCollection",
96
+ features: gridFeatures
97
+ .map((g, i) => {
98
+ const stats = gridStats.get(i);
99
+ const numericValues = stats.numericList;
100
+ const values = stats.valuesList;
101
+ const count = stats.countSet.size;
102
+
103
+ if (count === 0) return null;
104
+
105
+ const cellProps = { count };
106
+
107
+ if (hasVar && numericValues.length > 0) {
108
+ if (calcSum) cellProps.sum = sum(numericValues);
109
+ if (calcMean) cellProps.mean = mean(numericValues);
110
+ if (calcMedian) cellProps.median = median(numericValues);
111
+ if (calcMin) cellProps.min = min(numericValues);
112
+ if (calcMax) cellProps.max = max(numericValues);
113
+ }
114
+
115
+ if (includeValues) cellProps.values = values;
116
+
117
+ return {
118
+ type: g.type,
119
+ properties: { ...g.properties, ...cellProps },
120
+ geometry: g.geometry,
121
+ };
122
+ })
123
+ .filter((f) => f !== null),
124
+ };
125
+
126
+ const t1 = performance.now();
127
+ console.log(`Execution time: ${(t1 - t0).toFixed(2)} ms`);
128
+ return result;
129
+ }
@@ -1,72 +1,113 @@
1
1
  import RBush from "rbush";
2
2
  import { bbox } from "@turf/bbox";
3
3
  import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
4
- import { geoPath } from "d3-geo";
5
- import { groups } from "d3-array";
6
- const d3 = Object.assign({}, { geoPath, groups });
4
+ import { min, max, median, mean, sum } from "d3-array";
7
5
 
8
6
  /**
9
- * @function op.pointstogrid
10
- * @description The `op.pointstogrid()` function allows to count dots in polygons (e.g. grid cells)
11
- * @property {object} [points] - dots geoJSON
12
- * @property {object} [grid] - grid
13
- * @property {string} [var = undefined] - field (absolute quantitative data only)
7
+ * @function pointstogrid
8
+ * @description Assigns points to grid cells and computes statistics per cell.
9
+ * @param {object} opts
10
+ * @property {object} [points] - GeoJSON points
11
+ * @property {object} [grid] - GeoJSON grid (polygons)
12
+ * @property {string} [var] - Field for weighting points (optional)
13
+ * @property {boolean} [values=false] - Include array of raw values/IDs
14
+ * @property {boolean} [sum=true] - Compute sum
15
+ * @property {boolean} [median=false] - Compute median
16
+ * @property {boolean} [min=false] - Compute minimum
17
+ * @property {boolean} [max=false] - Compute maximum
18
+ * @property {boolean} [mean=false] - Compute mean
14
19
  */
15
- export function pointstogrid(
16
- opts = {
17
- points: undefined,
18
- grid: undefined,
19
- var: undefined,
20
- }
21
- ) {
20
+ export function pointstogrid(opts = {}) {
21
+ const {
22
+ points,
23
+ grid,
24
+ var: varField,
25
+ values: includeValues = false,
26
+ sum: calcSum = true,
27
+ median: calcMedian = false,
28
+ min: calcMin = false,
29
+ max: calcMax = false,
30
+ mean: calcMean = false,
31
+ } = opts;
32
+
22
33
  const t0 = performance.now();
34
+ const gridFeatures = grid.features;
35
+ const pointFeatures = points.features;
36
+ const hasVar = varField !== undefined && varField !== null;
23
37
 
24
- const polys = opts.grid.features;
25
- const points = opts.points.features;
26
- const count = new Array(polys.length).fill(0);
38
+ const gridbyindex = new Map(gridFeatures.map((d, i) => [i, d]));
27
39
 
28
- // ---- 1. Construire l’index spatial des polygones ----
40
+ // ---- 1. Spatial index for polygons ----
29
41
  const tree = new RBush();
30
- const items = polys.map((p, i) => {
31
- const [minX, minY, maxX, maxY] = bbox(p);
42
+ const items = gridFeatures.map((g, i) => {
43
+ const [minX, minY, maxX, maxY] = bbox(g);
32
44
  return { minX, minY, maxX, maxY, i };
33
45
  });
34
46
  tree.load(items);
35
47
 
36
- // ---- 2. Boucle sur les points ----
37
- points.forEach((pt) => {
38
- const [x, y] = pt.geometry.coordinates;
48
+ // ---- 2. Prepare stats storage per cell ----
49
+ const gridStats = new Map();
50
+ gridFeatures.forEach((g, i) => {
51
+ gridStats.set(i, { countSet: new Set(), valuesList: [], numericList: [] });
52
+ });
53
+
54
+ // ---- 3. Loop over points ----
55
+ pointFeatures.forEach((pt, i) => {
56
+ const x = pt.geometry.coordinates[0];
57
+ const y = pt.geometry.coordinates[1];
39
58
 
40
- // Trouver les polygones candidats dont la bbox contient le point
41
- const candidates = tree.search({
42
- minX: x,
43
- minY: y,
44
- maxX: x,
45
- maxY: y,
46
- });
59
+ const candidates = tree.search({ minX: x, minY: y, maxX: x, maxY: y });
47
60
 
48
- // Tester seulement ces candidats
49
61
  for (const cand of candidates) {
50
- const poly = polys[cand.i];
51
- if (booleanPointInPolygon(pt, poly)) {
52
- const value =
53
- opts.var === undefined ? 1 : parseFloat(pt.properties[opts.var]) || 0;
54
- count[cand.i] += value;
55
- break; // Si un point ne doit appartenir qu'à une cellule
56
- }
62
+ const poly = gridbyindex.get(cand.i);
63
+ if (!booleanPointInPolygon(pt, poly)) continue;
64
+
65
+ const stats = gridStats.get(cand.i);
66
+ stats.countSet.add(i);
67
+
68
+ const val = hasVar ? pt.properties[varField] : 1;
69
+
70
+ if (includeValues)
71
+ stats.valuesList.push(hasVar ? pt.properties[varField] : i);
72
+ if (hasVar) stats.numericList.push(parseFloat(val) || 0);
73
+ break; // point counted once per cell
57
74
  }
58
75
  });
59
76
 
60
- // ---- 3. Reconstituer la grille ----
61
- const output = polys
62
- .map((d, i) => ({
63
- type: d.type,
64
- geometry: d.geometry,
65
- properties: { ...d.properties, count: count[i] },
66
- }))
67
- .filter((d) => d.properties.count !== 0);
77
+ // ---- 4. Build final GeoJSON ----
78
+ const result = {
79
+ type: "FeatureCollection",
80
+ features: gridFeatures
81
+ .map((g, i) => {
82
+ const stats = gridStats.get(i);
83
+ const numericValues = stats.numericList;
84
+ const values = stats.valuesList;
85
+ const count = stats.countSet.size;
86
+
87
+ if (count === 0) return null;
88
+
89
+ const cellProps = { count };
90
+
91
+ if (hasVar && numericValues.length > 0) {
92
+ if (calcSum) cellProps.sum = sum(numericValues);
93
+ if (calcMean) cellProps.mean = mean(numericValues);
94
+ if (calcMedian) cellProps.median = median(numericValues);
95
+ if (calcMin) cellProps.min = min(numericValues);
96
+ if (calcMax) cellProps.max = max(numericValues);
97
+ }
98
+
99
+ if (includeValues) cellProps.values = values;
100
+
101
+ return {
102
+ type: g.type,
103
+ properties: { ...g.properties, ...cellProps },
104
+ geometry: g.geometry,
105
+ };
106
+ })
107
+ .filter((f) => f !== null),
108
+ };
68
109
 
69
110
  const t1 = performance.now();
70
- console.log(`Temps d'exécution: ${(t1 - t0).toFixed(2)} ms`);
71
- return { type: "FeatureCollection", features: output };
111
+ console.log(`Execution time: ${(t1 - t0).toFixed(2)} ms`);
112
+ return result;
72
113
  }
@@ -1,90 +1,126 @@
1
1
  import { featureCollection } from "@turf/helpers";
2
2
  import { bbox } from "@turf/bbox";
3
3
  import { intersect } from "@turf/intersect";
4
+ import area from "@turf/area";
4
5
  import RBush from "rbush";
5
- import { geoPath } from "d3-geo";
6
- import { groups } from "d3-array";
7
-
8
- const d3 = Object.assign({}, { geoPath, groups });
6
+ import { min, max, median, mean, sum } from "d3-array";
9
7
 
10
8
  /**
11
- * @function op.pointstogrid
12
- * @description Count points (optionally weighted) within polygons (e.g. grid cells)
13
- * @property {object} [points] - points geoJSON
14
- * @property {object} [grid] - grid geoJSON
15
- * @property {string} [var = undefined] - field for point weight
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
16
22
  */
17
- export function polygonstogrid(
18
- opts = { grid: undefined, polygons: undefined, var: undefined }
19
- ) {
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
+
20
36
  const t0 = performance.now();
21
37
 
22
- const grid = opts.grid.features;
23
- const polys = opts.polygons.features;
24
- const gridbyindex = new Map(grid.map((d, i) => [i, d]));
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]));
25
43
 
26
- // ---- 1. Créer l’index spatial RBush ----
44
+ // ---- 1. Spatial index RBush ----
27
45
  const tree = new RBush();
28
- const items = grid.map((g, i) => {
46
+ const items = gridFeatures.map((g, i) => {
29
47
  const [minX, minY, maxX, maxY] = bbox(g);
30
48
  return { minX, minY, maxX, maxY, i };
31
49
  });
32
50
  tree.load(items);
33
51
 
34
- const arr = [];
35
- const path = d3.geoPath();
52
+ // ---- 2. Prepare stats storage per cell ----
53
+ const gridStats = new Map();
54
+ gridFeatures.forEach((g, i) => {
55
+ gridStats.set(i, { countSet: new Set(), valuesList: [], numericList: [] });
56
+ });
36
57
 
37
- // ---- 2. Boucle sur les polygones ----
58
+ // ---- 3. Loop over polygons ----
38
59
  polys.forEach((p, i) => {
39
- const area = path.area(p);
40
- const [minX, minY, maxX, maxY] = bbox(p);
60
+ const polygonArea = area(p);
61
+ const val = hasVar ? parseFloat(p.properties?.[varField]) || 0 : 1;
41
62
 
42
- // 3. Chercher uniquement les cellules qui peuvent intersecter
63
+ const [minX, minY, maxX, maxY] = bbox(p);
43
64
  const candidates = tree.search({ minX, minY, maxX, maxY });
44
65
 
45
- // 4. Tester seulement les candidats
46
66
  for (const cand of candidates) {
47
67
  const g = gridbyindex.get(cand.i);
48
68
  const f = intersect(featureCollection([p, g]));
49
- if (f) {
50
- const areapiece = path.area(f);
51
- arr.push([i, cand.i, areapiece / area]);
69
+ if (!f) continue;
70
+
71
+ const areapiece = area(f);
72
+ const fraction = areapiece / polygonArea;
73
+
74
+ const stats = gridStats.get(cand.i);
75
+ stats.countSet.add(i);
76
+
77
+ if (includeValues) {
78
+ stats.valuesList.push(hasVar ? p.properties[varField] : 1);
79
+ }
80
+
81
+ if (hasVar) {
82
+ stats.numericList.push(val * fraction);
52
83
  }
53
84
  }
54
85
  });
55
86
 
56
- // ---- 5. Calcul des valeurs ----
57
- const accessor = new Map(
58
- polys.map((d, i) => [
59
- i,
60
- opts.var ? parseFloat(d.properties[opts.var]) || 0 : 1,
61
- ])
62
- );
63
-
64
- const datagrid = d3.groups(arr, (d) => d[1]);
65
-
66
- function getsum(cell) {
67
- let sum = 0;
68
- cell[1].forEach((d) => {
69
- sum += accessor.get(d[0]) * d[2];
70
- });
71
- return sum === 0 ? undefined : sum;
72
- }
73
-
74
- // ---- 6. Assemblage du résultat ----
87
+ // ---- 4. Build final GeoJSON ----
75
88
  const result = {
76
89
  type: "FeatureCollection",
77
- features: datagrid.map(([key, vals]) => {
78
- const tmp = gridbyindex.get(key);
79
- return {
80
- type: tmp.type,
81
- properties: { ...tmp.properties, sum: getsum([key, vals]) },
82
- geometry: tmp.geometry,
83
- };
84
- }),
90
+ features: gridFeatures
91
+ .map((g, i) => {
92
+ const stats = gridStats.get(i);
93
+ const numericValues = stats.numericList;
94
+ const values = stats.valuesList;
95
+ const count = stats.countSet.size;
96
+
97
+ if (count === 0) return null;
98
+
99
+ const cellProps = { count };
100
+
101
+ if (hasVar && numericValues.length > 0) {
102
+ if (calcSum) cellProps.sum = sum(numericValues);
103
+ if (calcMean) cellProps.mean = mean(numericValues);
104
+ if (calcMedian) cellProps.median = median(numericValues);
105
+ if (calcMin) cellProps.min = min(numericValues);
106
+ if (calcMax) cellProps.max = max(numericValues);
107
+ }
108
+
109
+ if (includeValues) {
110
+ cellProps.values = values;
111
+ }
112
+
113
+ return {
114
+ type: g.type,
115
+ properties: { ...g.properties, ...cellProps },
116
+ geometry: g.geometry,
117
+ };
118
+ })
119
+ .filter((f) => f !== null),
85
120
  };
86
121
 
87
122
  const t1 = performance.now();
88
- console.log(`Temps d'exécution: ${(t1 - t0).toFixed(2)} ms`);
123
+ console.log(`Optimized execution time: ${(t1 - t0).toFixed(2)} ms`);
124
+
89
125
  return result;
90
126
  }
@@ -0,0 +1,100 @@
1
+ import { featureCollection } from "@turf/helpers";
2
+ import { bbox } from "@turf/bbox";
3
+ import { intersect } from "@turf/intersect";
4
+ import RBush from "rbush";
5
+ import { geoPath } from "d3-geo";
6
+ import { groups } from "d3-array";
7
+
8
+ const d3 = Object.assign({}, { geoPath, groups });
9
+
10
+ /**
11
+ * @function polygonstogrid
12
+ * @description Répartit des polygones (optionnellement pondérés) sur une grille polygonale.
13
+ * @property {object} [polygons] - GeoJSON de polygones
14
+ * @property {object} [grid] - GeoJSON de grille
15
+ * @property {string} [var] - Champ de pondération (facultatif)
16
+ */
17
+ export function polygonstogrid(
18
+ opts = { grid: undefined, polygons: undefined, var: undefined }
19
+ ) {
20
+ const t0 = performance.now();
21
+
22
+ const grid = opts.grid.features;
23
+ const polys = opts.polygons.features;
24
+ const gridbyindex = new Map(grid.map((d, i) => [i, d]));
25
+
26
+ // ---- 1. Créer l’index spatial RBush ----
27
+ const tree = new RBush();
28
+ const items = grid.map((g, i) => {
29
+ const [minX, minY, maxX, maxY] = bbox(g);
30
+ return { minX, minY, maxX, maxY, i };
31
+ });
32
+ tree.load(items);
33
+
34
+ const arr = [];
35
+ const path = d3.geoPath();
36
+
37
+ // ---- 2. Boucle sur les polygones ----
38
+ polys.forEach((p, i) => {
39
+ const area = path.area(p);
40
+ const [minX, minY, maxX, maxY] = bbox(p);
41
+
42
+ // 3. Chercher uniquement les cellules qui peuvent intersecter
43
+ const candidates = tree.search({ minX, minY, maxX, maxY });
44
+
45
+ // 4. Tester seulement les candidats
46
+ for (const cand of candidates) {
47
+ const g = gridbyindex.get(cand.i);
48
+ const f = intersect(featureCollection([p, g]));
49
+ if (f) {
50
+ const areapiece = path.area(f);
51
+ arr.push([i, cand.i, areapiece / area]);
52
+ }
53
+ }
54
+ });
55
+
56
+ // ---- 5. Calcul des valeurs ----
57
+ const hasVar = opts.var !== undefined && opts.var !== null;
58
+
59
+ const accessor = new Map(
60
+ polys.map((d, i) => [
61
+ i,
62
+ hasVar ? parseFloat(d.properties[opts.var]) || 0 : 1,
63
+ ])
64
+ );
65
+
66
+ const datagrid = d3.groups(arr, (d) => d[1]);
67
+
68
+ function getsum(cell) {
69
+ const vals = cell[1];
70
+ if (hasVar) {
71
+ // Cas pondéré
72
+ let sum = 0;
73
+ vals.forEach((d) => {
74
+ sum += accessor.get(d[0]) * d[2];
75
+ });
76
+ return sum === 0 ? undefined : sum;
77
+ } else {
78
+ // Cas non pondéré : juste compter le nombre de polygones intersectés
79
+ const uniquePolygons = new Set(vals.map((d) => d[0]));
80
+ return uniquePolygons.size;
81
+ }
82
+ }
83
+
84
+ // ---- 6. Assemblage du résultat ----
85
+ const result = {
86
+ type: "FeatureCollection",
87
+ features: datagrid.map(([key, vals]) => {
88
+ const tmp = gridbyindex.get(key);
89
+ return {
90
+ type: tmp.type,
91
+ properties: { ...tmp.properties, sum: getsum([key, vals]) },
92
+ geometry: tmp.geometry,
93
+ };
94
+ }),
95
+ };
96
+
97
+ const t1 = performance.now();
98
+ console.log(`Temps d'exécution: ${(t1 - t0).toFixed(2)} ms`);
99
+ return result;
100
+ }