@eturnity/eturnity_maths 8.10.1 → 8.16.1-SLD.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_maths",
3
- "version": "8.10.1",
3
+ "version": "8.16.1-SLD.0",
4
4
  "author": "Eturnity Team",
5
5
  "main": "src/index.js",
6
6
  "private": false,
package/src/geometry.js CHANGED
@@ -413,6 +413,45 @@ export function getPointInsideOutline(vs, firstLevelHoles = []) {
413
413
  }
414
414
  return result
415
415
  }
416
+ export function distanceTo2DPolyline(point, polyline) {
417
+ let minDistance = Infinity
418
+ if (polyline.length < 2) {
419
+ throw new Error('not enough points in polyline')
420
+ }
421
+ for (let i = 0; i < polyline.length - 1; i++) {
422
+ let A = polyline[i]
423
+ let B = polyline[i + 1]
424
+ const distance = distanceTo2DSegment(point, A, B)
425
+ if (distance < minDistance) {
426
+ minDistance = distance
427
+ }
428
+ }
429
+ return minDistance
430
+ }
431
+ export function distanceTo2DSegment(point, A, B) {
432
+ const vectorAB = { x: B.x - A.x, y: B.y - A.y }
433
+ const vectorAP = { x: point.x - A.x, y: point.y - A.y }
434
+ const lengthABSquared = vectorAB.x * vectorAB.x + vectorAB.y * vectorAB.y
435
+ if (lengthABSquared === 0) {
436
+ return Math.sqrt(vectorAP.x * vectorAP.x + vectorAP.y * vectorAP.y)
437
+ }
438
+ const t =
439
+ (vectorAP.x * vectorAB.x + vectorAP.y * vectorAB.y) / lengthABSquared
440
+ if (t < 0) {
441
+ return Math.sqrt(vectorAP.x * vectorAP.x + vectorAP.y * vectorAP.y)
442
+ }
443
+ if (t > 1) {
444
+ const vectorBP = { x: point.x - B.x, y: point.y - B.y }
445
+ return Math.sqrt(vectorBP.x * vectorBP.x + vectorBP.y * vectorBP.y)
446
+ }
447
+ const projection = {
448
+ x: A.x + t * vectorAB.x,
449
+ y: A.y + t * vectorAB.y,
450
+ }
451
+ const dx = point.x - projection.x
452
+ const dy = point.y - projection.y
453
+ return Math.sqrt(dx * dx + dy * dy)
454
+ }
416
455
 
417
456
  export function distanceToEdge2D(M, A, B) {
418
457
  const pA = { x: A.x, y: A.y, z: 0 }
@@ -734,6 +773,18 @@ export function get3pointNotAlignedFromOutline(outline) {
734
773
  }
735
774
  return [A, B, C]
736
775
  }
776
+ export function getNormalVectorFromFlatOutline(outline) {
777
+ const ABC = get3pointNotAlignedFromOutline(outline)
778
+ if (!ABC) {
779
+ return null
780
+ }
781
+ let normalVector = getNormalVectorFrom3Points(...ABC)
782
+ if (normalVector.z < 0) {
783
+ normalVector = multiplyVector(-1, normalVector)
784
+ }
785
+ normalVector = normalizeVector(normalVector)
786
+ return normalVector
787
+ }
737
788
  export function getNormalVectortoEdgeTowardPolygon(k, outline) {
738
789
  const A = outline[k]
739
790
  const B = outline[(k + 1) % outline.length]
package/src/index.js CHANGED
@@ -9,6 +9,7 @@ export * from './objects'
9
9
  export * from './splitMergePolygons'
10
10
  export * from './miscellaneous'
11
11
  export * from './stats'
12
+ export * from './irradiance'
12
13
  export * from './spherical'
13
14
  export * from './SHPSolver'
14
15
  export * from './panelFunctions'
@@ -0,0 +1,77 @@
1
+ import { dotProduct, inclineWithNormalVector, normalizeVector } from './index'
2
+ export function ineichenDiffuseIrradiance(dni, dhi, plane_theta, cosAOI) {
3
+ //compute of Ineichen diffuse
4
+ const F = 1.0 - Math.pow(dhi / Math.max(dni * cosAOI + dhi, 1e-6), 2.0)
5
+ const diffusion_Ineichen =
6
+ dhi *
7
+ ((1.0 + Math.cos(plane_theta)) / 2.0) *
8
+ (1.0 + F * Math.pow(Math.sin(plane_theta / 2.0), 3.0)) *
9
+ (1.0 + F * Math.pow(cosAOI, 2.0) * Math.pow(Math.cos(plane_theta), 3.0))
10
+ return diffusion_Ineichen
11
+ }
12
+ export function getOptimizedGHI({ dataGrids, lat, lng }) {
13
+ // Compute normal vector for max DNI
14
+ let optimized_panel_tilt
15
+ if (Math.abs(lat) < 25) optimized_panel_tilt = Math.abs(lat) * 0.87
16
+ else if (Math.abs(lat) < 50) optimized_panel_tilt = Math.abs(lat) * 0.76 + 3.1
17
+ else optimized_panel_tilt = Math.abs(lat) * 0.76 + 3.1
18
+
19
+ const phi = 180
20
+ const theta = optimized_panel_tilt
21
+ const phiRad = (phi * Math.PI) / 180
22
+ const thetaRad = (theta * Math.PI) / 180
23
+ const optimizedNormalVector = {
24
+ x: Math.sin(thetaRad) * Math.sin(phiRad),
25
+ y: Math.sin(thetaRad) * Math.cos(phiRad),
26
+ z: Math.cos(thetaRad),
27
+ }
28
+ let { ghi } = getGHI({
29
+ dataGrids: dataGrids,
30
+ normalVector: optimizedNormalVector,
31
+ })
32
+ return ghi
33
+ }
34
+ export function getGHI({ dataGrids, normalVector }) {
35
+ // Compute highest GHI
36
+ normalVector = normalizeVector(normalVector)
37
+ let GHISum = 0
38
+ let DHISum = 0
39
+ let DNISum = 0
40
+ const resolution = {
41
+ x: 1 / dataGrids.dni_grid[0].length,
42
+ y: 1 / dataGrids.dni_grid.length,
43
+ }
44
+ for (let i = 0; i < dataGrids.dni_grid.length; i++) {
45
+ for (let j = 0; j < dataGrids.dni_grid[0].length; j++) {
46
+ const phi = j * resolution.x
47
+ const theta = i * resolution.y
48
+ const phiRad = phi * Math.PI * 2
49
+ const thetaRad = (theta * Math.PI) / 2
50
+ const sunDir = {
51
+ x: Math.sin(thetaRad) * Math.sin(phiRad),
52
+ y: Math.sin(thetaRad) * Math.cos(phiRad),
53
+ z: Math.cos(thetaRad),
54
+ }
55
+ const cosAngle = Math.max(dotProduct(normalVector, sunDir), 0)
56
+ const dni = dataGrids.dni_grid[i][j]
57
+ const dhi = dataGrids.dhi_grid[i][j]
58
+ const plane_theta = inclineWithNormalVector(normalVector)
59
+ const ineichen_dhi = ineichenDiffuseIrradiance(
60
+ dni,
61
+ dhi,
62
+ plane_theta,
63
+ cosAngle
64
+ )
65
+ const ghi = dni * cosAngle + ineichen_dhi
66
+ DHISum += ineichen_dhi
67
+ DNISum += dni
68
+ GHISum += ghi
69
+ }
70
+ }
71
+
72
+ return {
73
+ dhi: DHISum,
74
+ dni: DNISum,
75
+ ghi: GHISum,
76
+ }
77
+ }
@@ -332,6 +332,8 @@ export class Polygon {
332
332
  row_spacing_mm: this.data.row_spacing_mm,
333
333
  is_row_spacing_automatic: this.data.is_row_spacing_automatic,
334
334
  offset_percent: this.data.offset_percent,
335
+ fitting_panel_area_m2: this.data.fitting_panel_area_m2,
336
+ has_fitting_panels: this.data.has_fitting_panels,
335
337
  panel_orientation: this.data.panel_orientation,
336
338
  panel_direction_degrees: this.data.panel_direction_degrees,
337
339
  component_id_pv_module: this.data.component_id_pv_module,
@@ -0,0 +1,51 @@
1
+ import { distanceTo2DSegment } from '../../index'
2
+
3
+ describe('distanceTo2DSegment function', () => {
4
+ test('top middle', () => {
5
+ const A = { x: 0, y: 0, z: 0 }
6
+ const B = { x: 10, y: 0, z: 0 }
7
+ const point = { x: 5, y: 10, z: 0 }
8
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(10, 4)
9
+ })
10
+ test('bottom', () => {
11
+ const A = { x: 0, y: 0, z: 0 }
12
+ const B = { x: 10, y: 0, z: 0 }
13
+ const point = { x: 5, y: -10, z: 0 }
14
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(10, 4)
15
+ })
16
+ test('diagonal', () => {
17
+ const A = { x: 0, y: 0, z: 0 }
18
+ const B = { x: 10, y: 0, z: 0 }
19
+ const point = { x: -3, y: 4, z: 0 }
20
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(5, 4)
21
+ })
22
+ test('point aligned with A and B', () => {
23
+ const A = { x: 0, y: 0, z: 0 }
24
+ const B = { x: 10, y: 0, z: 0 }
25
+ const point = { x: -10, y: 0, z: 0 }
26
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(10, 4)
27
+ })
28
+ test('point aligned with A and B right', () => {
29
+ const A = { x: 0, y: 0, z: 0 }
30
+ const B = { x: 10, y: 0, z: 0 }
31
+ const point = { x: 20, y: 0, z: 0 }
32
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(10, 4)
33
+ })
34
+ test('AB in diagonal', () => {
35
+ const A = { x: 0, y: 10, z: 0 }
36
+ const B = { x: 10, y: 0, z: 0 }
37
+ const point = { x: 0, y: 0, z: 0 }
38
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(7.07106, 4)
39
+ })
40
+ test('point and A and A', () => {
41
+ const A = { x: 0, y: 10, z: 0 }
42
+ const point = { x: 0, y: 0, z: 0 }
43
+ expect(distanceTo2DSegment(point, A, A)).toBeCloseTo(10, 4)
44
+ })
45
+ test('point vertical to B', () => {
46
+ const A = { x: 0, y: 0, z: 0 }
47
+ const B = { x: 10, y: 0, z: 0 }
48
+ const point = { x: 10, y: 10, z: 0 }
49
+ expect(distanceTo2DSegment(point, A, B)).toBeCloseTo(10, 4)
50
+ })
51
+ })