@eturnity/eturnity_maths 9.19.0 → 9.25.0-EPDM-19998.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.
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_maths",
3
- "version": "9.19.0",
3
+ "version": "9.25.0-EPDM-19998.0",
4
4
  "author": "Eturnity Team",
5
5
  "main": "src/index.js",
6
6
  "private": false,
7
+ "scripts": {
8
+ "test": "jest",
9
+ "prepare": "husky",
10
+ "lint": "eslint --fix --debug --ext .js,.vue .",
11
+ "merge-remote-master": "node scripts/merge-master.js"
12
+ },
7
13
  "repository": {
8
14
  "type": "git",
9
15
  "url": "git+ssh://git@bitbucket.org/eturnitydevs/eturnity_maths.git"
@@ -22,8 +28,8 @@
22
28
  "uuid": "9.0.0"
23
29
  },
24
30
  "devDependencies": {
25
- "@babel/core": "7.21.4",
26
- "@babel/preset-env": "7.21.4",
31
+ "@babel/core": "7.22.0",
32
+ "@babel/preset-env": "7.22.0",
27
33
  "babel-jest": "29.5.0",
28
34
  "husky": "^9.1.5",
29
35
  "@vue/eslint-config-standard": "8.0.1",
@@ -34,13 +40,8 @@
34
40
  "eslint-plugin-prettier": "4.2.1",
35
41
  "eslint-plugin-vue": "9.14.1",
36
42
  "jest": "29.5.0",
37
- "prettier": "^2.8.4",
38
- "prettier-plugin-vue": "^1.1.6"
43
+ "prettier": "2.8.4",
44
+ "prettier-plugin-vue": "1.1.6"
39
45
  },
40
- "description": "",
41
- "scripts": {
42
- "test": "jest",
43
- "lint": "eslint --fix --debug --ext .js,.vue .",
44
- "merge-remote-master": "node scripts/merge-master.js"
45
- }
46
- }
46
+ "description": ""
47
+ }
package/src/config.js CHANGED
@@ -32,11 +32,6 @@ export const layerColors = {
32
32
  strokeColor: '#ffffff',
33
33
  strokeWidth: 1,
34
34
  },
35
- user_deactivated_panel: {
36
- fillColor: 'rgba(115, 115, 229, 0.1)',
37
- strokeColor: 'white',
38
- strokeWidth: 4,
39
- },
40
35
  selectedPanel: {
41
36
  fillColor: '#0068DE80',
42
37
  strokeColor: theme.colors.blue,
package/src/geometry.js CHANGED
@@ -887,6 +887,45 @@ export function verticalProjectionOnPlane(p, n, o) {
887
887
  const projectedPoint = { ...p, z: projectedHeight }
888
888
  return projectedPoint
889
889
  }
890
+
891
+ // 2D convex hull (Andrew's monotone chain). Input/output: array of [x, y].
892
+ // Returns the hull in counter-clockwise order; passes through collinear points
893
+ // only at the endpoints. Used to grow a module-field outline so it encloses
894
+ // newly added panels.
895
+ export function convexHull2D(points) {
896
+ const pts = points
897
+ .map((p) => [p[0], p[1]])
898
+ .sort((a, b) => a[0] - b[0] || a[1] - b[1])
899
+ if (pts.length < 3) {
900
+ return pts
901
+ }
902
+ const cross = (o, a, b) =>
903
+ (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
904
+ const lower = []
905
+ for (const p of pts) {
906
+ while (
907
+ lower.length >= 2 &&
908
+ cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0
909
+ ) {
910
+ lower.pop()
911
+ }
912
+ lower.push(p)
913
+ }
914
+ const upper = []
915
+ for (let i = pts.length - 1; i >= 0; i--) {
916
+ const p = pts[i]
917
+ while (
918
+ upper.length >= 2 &&
919
+ cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0
920
+ ) {
921
+ upper.pop()
922
+ }
923
+ upper.push(p)
924
+ }
925
+ lower.pop()
926
+ upper.pop()
927
+ return lower.concat(upper)
928
+ }
890
929
  export function projectionOnPlaneFollowingVector(p, n, o, v) {
891
930
  // if p belongs to (n,o) plane return p
892
931
  const opn = dotProduct(substractVector(p, o), n)
@@ -50,6 +50,11 @@ export class Polygon {
50
50
  this.isParallel = true
51
51
  } else if (this.layer == 'roof') {
52
52
  this.moduleFields = []
53
+ } else if (['moduleField', 'tmpModuleField'].includes(this.layer)) {
54
+ // Transient validation state — never serialized / sent to BE.
55
+ this.warnings = []
56
+ this.hasWarnings = false
57
+ this.hasError = false
53
58
  }
54
59
  }
55
60
 
@@ -60,7 +65,6 @@ export class Polygon {
60
65
  })
61
66
  if (['tmpModuleField', 'moduleField'].includes(this.layer)) {
62
67
  polygon.panels = []
63
- polygon.userDeactivatedPanels = []
64
68
  polygon.data?.moduleGrids?.forEach((grid) => {
65
69
  grid.project_variant_module_grid_3d_id = null
66
70
  })
@@ -394,10 +398,7 @@ export class Polygon {
394
398
  extraSerialization.needsOptimisation = this.needsOptimisation
395
399
  extraSerialization.priority = this.priority
396
400
  } else if (this.layer == 'panel') {
397
- extraSerialization.row_index = this.row_index
398
- extraSerialization.col_index = this.col_index
399
- extraSerialization.moduleField = { id: this.moduleField.id }
400
- } else if (this.layer == 'user_deactivated_panel') {
401
+ extraSerialization.gridIndex = this.gridIndex
401
402
  extraSerialization.row_index = this.row_index
402
403
  extraSerialization.col_index = this.col_index
403
404
  extraSerialization.moduleField = { id: this.moduleField.id }
@@ -442,9 +443,6 @@ export class Polygon {
442
443
  if (!this.panels) {
443
444
  this.panels = []
444
445
  }
445
- if (!this.userDeactivatedPanels) {
446
- this.userDeactivatedPanels = []
447
- }
448
446
  return {
449
447
  module_field_uuid: this.id,
450
448
  roof_uuid: this.roof ? this.roof.id : null,
@@ -472,7 +470,7 @@ export class Polygon {
472
470
  yearly_yield_kwh_kwp: this.data.yearly_yield_kwh_kwp,
473
471
  yearly_yield_kwh_kwp_2: this.data.yearly_yield_kwh_kwp_2,
474
472
  }
475
- } else if (['panel', 'user_deactivated_panel'].includes(this.layer)) {
473
+ } else if (this.layer == 'panel') {
476
474
  return {
477
475
  id: this.id,
478
476
  row_index: this.row_index,
@@ -67,7 +67,6 @@ export function updateOutlineFromInclineDirection(
67
67
  export function updateComputedGeometryPolygon(polygon) {
68
68
  if (
69
69
  ![
70
- 'user_deactivated_panel',
71
70
  'panel',
72
71
  'roof',
73
72
  'obstacle',
@@ -36,15 +36,10 @@ export function hydratePolygon(serializedPolygon) {
36
36
  polygon.pvData = serializedPolygon.pvData
37
37
  polygon.mountingData = serializedPolygon.mountingData
38
38
  polygon.panels = []
39
- polygon.userDeactivatedPanels = []
40
39
  } else if (layer == 'panel') {
41
40
  polygon.row_index = serializedPolygon.row_index
42
41
  polygon.col_index = serializedPolygon.col_index
43
42
  polygon.moduleField = serializedPolygon.moduleField
44
- } else if (layer == 'user_deactivated_panel') {
45
- polygon.row_index = serializedPolygon.row_index
46
- polygon.col_index = serializedPolygon.col_index
47
- polygon.moduleField = serializedPolygon.moduleField
48
43
  } else if (layer == 'roof_plan_item') {
49
44
  polygon.shape = 'polygon'
50
45
  polygon.colorIndex = serializedPolygon.colorIndex
@@ -1,3 +1,37 @@
1
+ // Normalise a grid vector that may be stored as a [x,y,z] array (backend
2
+ // format) or a {x,y,z} object. Used internally by canonicalGridCoords.
3
+ function _normalizeVec(v) {
4
+ if (Array.isArray(v)) return { x: v[0] ?? 0, y: v[1] ?? 0, z: v[2] ?? 0 }
5
+ return { x: v?.x ?? 0, y: v?.y ?? 0, z: v?.z ?? 0 }
6
+ }
7
+
8
+ /**
9
+ * Return the canonical (row, col) position of `module` in firstGrid's
10
+ * coordinate system. Modules on firstGrid map 1-to-1; modules on other grids
11
+ * get their origin-offset projected onto firstGrid's row/column axes so that
12
+ * all panels of a multi-grid module field share one comparable coordinate space.
13
+ *
14
+ * Grid vectors may be stored as [x,y,z] arrays or {x,y,z} objects — both
15
+ * forms are normalised internally.
16
+ */
17
+ export function canonicalGridCoords(module, grid, firstGrid) {
18
+ if (grid === firstGrid)
19
+ return { row: module.row_index, col: module.col_index }
20
+ const rowVec = _normalizeVec(firstGrid.grid_row_vector)
21
+ const colVec = _normalizeVec(firstGrid.grid_column_vector)
22
+ const rowLen2 = rowVec.x * rowVec.x + rowVec.y * rowVec.y + rowVec.z * rowVec.z
23
+ const colLen2 = colVec.x * colVec.x + colVec.y * colVec.y + colVec.z * colVec.z
24
+ const originA = _normalizeVec(grid.grid_origin)
25
+ const originB = _normalizeVec(firstGrid.grid_origin)
26
+ const dx = originA.x - originB.x
27
+ const dy = originA.y - originB.y
28
+ const dz = originA.z - originB.z
29
+ return {
30
+ row: (dx * rowVec.x + dy * rowVec.y + dz * rowVec.z) / rowLen2 + module.row_index,
31
+ col: (dx * colVec.x + dy * colVec.y + dz * colVec.z) / colLen2 + module.col_index,
32
+ }
33
+ }
34
+
1
35
  export function arePanelsAdjacent(panelA, panelB) {
2
36
  const areSameModuleField = panelA.moduleField.id == panelB.moduleField.id
3
37
  const areVerticalyAdjacent =
package/src/plane.js CHANGED
@@ -42,7 +42,7 @@ export function getPlaneFromPolygon(polygon) {
42
42
  const origin = pointProjectionOnPlane(
43
43
  { x: 0, y: 0, z: 0 },
44
44
  polygon.normalVector,
45
- polygon.outline[0]
45
+ polygon.flatOutline?.[0] || polygon.outline[0]
46
46
  )
47
47
  const normalVector = polygon.normalVector
48
48
  const { edgeDirectionVector } = getLongestEdgeData(polygon.outline)
@@ -74,3 +74,17 @@ export function getPlaneFromPolygon(polygon) {
74
74
  upVector,
75
75
  })
76
76
  }
77
+
78
+ export function isOnSamePlane(polygon0, polygon1) {
79
+ const plane0 = getPlaneFromPolygon(polygon0)
80
+ const plane1 = getPlaneFromPolygon(polygon1)
81
+ if (polygon0.outline.length < polygon1.outline.length) {
82
+ return (polygon0.flatOutline || polygon0.outline).every((p) =>
83
+ plane1.isPointOnPlane(p)
84
+ )
85
+ } else {
86
+ return (polygon1.flatOutline || polygon1.outline).every((p) =>
87
+ plane0.isPointOnPlane(p)
88
+ )
89
+ }
90
+ }