@team-geospan/structuresio 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GEOSPAN StructuresIO
2
2
 
3
- JavaScript utilities for working with the [StructuresJSON]() format.
3
+ JavaScript utilities for working with the [StructuresJSON](https://github.com/team-geospan/structures-json) format.
4
4
 
5
5
  ## Installation
6
6
 
package/lib/geojson.js CHANGED
@@ -22,56 +22,65 @@
22
22
  import { isCollection } from "./helpers";
23
23
 
24
24
  /**
25
- * toCoordinateArray converts the surface topology to a GeoJSON style
26
- * Polygon geometry coordinates array.
27
- *
28
- * This is written to be as clear and testable as possible.
29
- * There are likely more efficient ways to loop through this loop,
30
- * but this version works and is relatively easy to read.
31
- *
25
+ * simplifyRing converts a single surface ring and coverts it to a list
26
+ * of points.
32
27
  */
33
- export const toCoordinateArray = (surface, edges, points) => {
34
- // the "edges" array is structued similar to a simple features polygon.
35
- // [outer ring, inner ring, inner ring]
36
- // And each ring is composed of [edgeId, edgeId, edgeId]
37
- // edges contains points [pointId, pointId]
38
- const coords = surface.edges.map((edgeIds) => {
39
- const edgePoints = [];
40
- edgeIds.forEach((edgeId, edgeIdx) => {
41
- const edge = edges[edgeId];
42
- // copy the points to ensure the origin edge is not mutated.
43
- const nextPoints = [...edge.points];
44
- if (edgeIdx === 0) {
45
- // determine whether to start the line with the first segment reversed
46
- const testPoints = edges[edgeIds[1]].points;
47
- if (nextPoints[0] === testPoints[0]) {
48
- // flip it
49
- nextPoints.reverse();
50
- }
51
- } else {
52
- // keep the line contiguous, flip the next set of points
53
- // when the lastPoint in the line does not match the
54
- // first point of the next edge.
55
- const lastPoint = edgePoints[edgePoints.length - 1];
56
- if (nextPoints[0] !== lastPoint) {
57
- nextPoints.reverse();
58
- }
28
+ export const simplifyRing = (ringEdges) => {
29
+ if (ringEdges.length === 0) {
30
+ return [];
31
+ }
32
+
33
+ let edges = structuredClone(ringEdges);
34
+ const sortedList = [];
35
+
36
+ sortedList.push(edges.shift());
37
+
38
+ // ensure the iterations of the while loop do not exceed
39
+ // O(n^2), the input edge structure is likely degenerate.
40
+ let maxIter = edges.length * edges.length;
41
+ while (maxIter > 0 && edges.length > 0) {
42
+ for (let i = 0, len = edges.length; i < len; i++) {
43
+ const edge = edges[i];
44
+ const len = sortedList.length - 1;
45
+ if (sortedList[len][1] === edge[0]) {
46
+ sortedList.push(edge);
47
+ edges = edges.slice(0, i).concat(edges.slice(i + 1));
48
+ break;
49
+ } else if (sortedList[len][1] === edge[edge.length - 1]) {
50
+ sortedList.push(edge.reverse());
51
+ edges = edges.slice(0, i).concat(edges.slice(i + 1));
52
+ break;
59
53
  }
60
- // use slice(1) to prevent duplicate points.
61
- nextPoints.slice(1).forEach((p) => edgePoints.push(p));
62
- });
63
- // ensure the polygon is closed.
64
- if (edgePoints[0] !== edgePoints[edgePoints.length - 1]) {
65
- edgePoints.push(edgePoints[0]);
66
54
  }
67
- // convert all the point ids into [x, y, z] coordinates.
68
- return edgePoints.map((ptId) => points[ptId].coordinates);
55
+ maxIter--;
56
+ }
57
+
58
+ // flatten the list
59
+ const asPoints = sortedList.map((edge) => edge[0]);
60
+ // ensure the polygon is closed
61
+ asPoints.push(sortedList[0][0]);
62
+ return asPoints;
63
+ };
64
+
65
+ // surfaceRings returns a list of point ids based on the surfaces edges
66
+ const surfaceRings = (surfaceId, { surfaces, edges }) => {
67
+ return surfaces[surfaceId].edges.map((ring) => {
68
+ return ring.map((edgeId) => {
69
+ return edges[edgeId].points;
70
+ });
69
71
  });
70
- return coords;
71
72
  };
72
73
 
73
74
  const structureToPolygonFeature = ({ surfaces, points, edges }) => {
74
75
  const features = Object.keys(surfaces).map((surfaceId) => {
76
+ const rings = surfaceRings(surfaceId, { surfaces, edges }).map((ring) =>
77
+ simplifyRing(ring),
78
+ );
79
+ // convert all the rings into coordinates
80
+ const coordinates = rings.map((ring) =>
81
+ ring.map((pointId) => points[pointId].coordinates),
82
+ );
83
+
75
84
  return {
76
85
  type: "Feature",
77
86
  properties: {
@@ -81,7 +90,7 @@ const structureToPolygonFeature = ({ surfaces, points, edges }) => {
81
90
  },
82
91
  geometry: {
83
92
  type: "Polygon",
84
- coordinates: toCoordinateArray(surfaces[surfaceId], edges, points),
93
+ coordinates,
85
94
  },
86
95
  };
87
96
  });
@@ -94,10 +103,9 @@ const structureToPolygonFeature = ({ surfaces, points, edges }) => {
94
103
  */
95
104
  export const toPolygonGeoJSON = (collection) => {
96
105
  // handle either a collection or single structure
97
- const allFeatures =
98
- collection.kind === "StructureCollection"
99
- ? collection.structures.map(structureToPolygonFeature)
100
- : [structureToPolygonFeature(collection)];
106
+ const allFeatures = isCollection(collection)
107
+ ? collection.structures.map(structureToPolygonFeature)
108
+ : [structureToPolygonFeature(collection)];
101
109
 
102
110
  return {
103
111
  type: "FeatureCollection",
package/lib/summary.js CHANGED
@@ -49,3 +49,21 @@ export const summarizeSurfaceMaterials = (collection, flatten = false) => {
49
49
 
50
50
  return summary;
51
51
  };
52
+
53
+ export const summarizeEdges = (collection, flatten = false) => {
54
+ const summary = {};
55
+ collection.structures.forEach((structure) => {
56
+ Object.values(structure.edges).forEach((edge) => {
57
+ const kind = edge.kind || "";
58
+ summary[kind] =
59
+ (summary[kind] || 0) +
60
+ ((edge.properties && edge.properties.length) || 0);
61
+ });
62
+ });
63
+
64
+ if (flatten) {
65
+ return Object.keys(summary).map((key) => [key, summary[key]]);
66
+ }
67
+
68
+ return summary;
69
+ };
package/lib/units.js CHANGED
@@ -1,3 +1,5 @@
1
+ /* v8 ignore start */
2
+
1
3
  /**
2
4
  * Copyright GEOSPAN Corp
3
5
  *
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "@team-geospan/structuresio",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Collection of utilities for working with StructuresJSON",
5
5
  "type": "module",
6
+ "exports": {
7
+ "./*": "./lib/*"
8
+ },
6
9
  "files": [
7
10
  "./lib"
8
11
  ],
9
12
  "scripts": {
10
13
  "lint": "eslint --report-unused-disable-directives --max-warnings 0 ./tests ./lib --ext .js",
11
14
  "lint:fix": "npm run lint -- --fix",
12
- "test": "vitest ./tests"
15
+ "test": "vitest ./tests",
16
+ "coverage": "vitest ./tests --coverage"
13
17
  },
14
18
  "eslintConfig": {
15
19
  "env": {
@@ -29,6 +33,7 @@
29
33
  }
30
34
  },
31
35
  "devDependencies": {
36
+ "@vitest/coverage-v8": "^3.1.1",
32
37
  "eslint": "^8.57.0",
33
38
  "eslint-config-prettier": "^10.0.1",
34
39
  "eslint-plugin-prettier": "^5.2.3",