@eturnity/eturnity_maths 7.4.0 → 7.10.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": "7.4.0",
3
+ "version": "7.10.0",
4
4
  "author": "Eturnity Team",
5
5
  "main": "src/index.js",
6
6
  "private": false,
package/src/geometry.js CHANGED
@@ -98,7 +98,7 @@ export function getParallelLinePassingByPoint(A, B, C) {
98
98
  console.error("A == B Can't make a parallel line")
99
99
  return null
100
100
  }
101
- const D = new Point(C.x + B.x - A.x, C.y + B.y - A.y)
101
+ const D = new Point(C.x + B.x - A.x, C.y + B.y - A.y, C.z + B.z - A.z)
102
102
  return new Line(C, D, '')
103
103
  }
104
104
 
@@ -110,10 +110,15 @@ export function getDataAboutTwo3DLines(A,u,B,v){
110
110
  [u.z,v.z,w.z]
111
111
  ]
112
112
  let mInv=inverse3x3matrix(m)
113
+ if(!mInv){
114
+ return null
115
+ }
113
116
  let AB=substractVector(B,A)
114
117
  let [t1,t2,t3] = multiplyMatrices(mInv,[[AB.x],[AB.y],[AB.z]])
118
+ //M point on Au
115
119
  let M=addVector(A,multiplyVector(t1,u))
116
- let N=addVector(B,multiplyVector(t2,v))
120
+ //N point on Bv
121
+ let N=addVector(B,multiplyVector(-t2,v))
117
122
  let distance=get3DDistanceBetweenPoints(M,N)
118
123
  return {m,mInv,M,N,A,B,u,v,w,distance,t1,t2,t3}
119
124
 
@@ -140,11 +145,20 @@ export function get3DDistanceBetweenPoints(firstPoint, secondPoint) {
140
145
  )
141
146
  return distance
142
147
  }
143
-
148
+
149
+ export function getDegreeVectors(u,v){
150
+ return getDegree(u,{x:0,y:0,z:0},v)
151
+ }
152
+
144
153
  export function getDegree(H, I, J) {
145
- const a = getDistanceBetweenPoints(H, I)
146
- const b = getDistanceBetweenPoints(I, J)
147
- const c = getDistanceBetweenPoints(H, J)
154
+ let distanceFunction = get3DDistanceBetweenPoints
155
+ if(H.z==undefined || I.z==undefined || J.z==undefined || isNaN(H.z) || isNaN(I.z) || isNaN(J.z) ){
156
+ distanceFunction=getDistanceBetweenPoints
157
+ }
158
+ const a = distanceFunction(H, I)
159
+ const b = distanceFunction(I, J)
160
+ const c = distanceFunction(H, J)
161
+
148
162
 
149
163
  let angle = (Math.acos((a * a + b * b - c * c) / (2 * a * b)) * 180) / Math.PI
150
164
 
@@ -542,33 +556,65 @@ export function get3DDistanceBetweenPoints(firstPoint, secondPoint) {
542
556
  }
543
557
 
544
558
  export function getPointOnLine(M, A, B) {
559
+ function zValueNotDefined(P){
560
+ return P.z==undefined || isNaN(P.z)
561
+ }
545
562
  //Calcul of P, Projection of M on line AB
546
563
  if (isSamePoint3D(A, B)) {
547
564
  console.error("A and B don't make a line : A==B")
548
565
  return null
549
566
  }
550
567
  let P = {}
551
- const AM = {
552
- x: M.x - A.x,
553
- y: M.y - A.y
554
- }
555
- const AB = {
556
- x: B.x - A.x,
557
- y: B.y - A.y
558
- }
559
-
560
- const dot = AM.x * AB.x + AM.y * AB.y
561
- const distanceAB = getDistanceBetweenPoints(A, B)
562
- let param = -1
563
- if (distanceAB == 0) {
564
- //A et B sont confondu
565
- console.error("A and B don't make a line : A==B")
566
- P = M
567
- } else {
568
- // in case of 0 length line
569
- const distanceAP = dot / distanceAB
570
- P.x = A.x + (distanceAP * AB.x) / distanceAB
571
- P.y = A.y + (distanceAP * AB.y) / distanceAB
568
+ if(zValueNotDefined(M) || zValueNotDefined(A) || zValueNotDefined(B)){
569
+ const AM = {
570
+ x: M.x - A.x,
571
+ y: M.y - A.y
572
+ }
573
+ const AB = {
574
+ x: B.x - A.x,
575
+ y: B.y - A.y
576
+ }
577
+
578
+ const dot = AM.x * AB.x + AM.y * AB.y
579
+ const distanceAB = getDistanceBetweenPoints(A, B)
580
+ let param = -1
581
+ if (distanceAB == 0) {
582
+ //A et B sont confondu
583
+ console.error("A and B don't make a line : A==B")
584
+ P = M
585
+ } else {
586
+ // in case of 0 length line
587
+ const distanceAP = dot / distanceAB
588
+ P.x = A.x + (distanceAP * AB.x) / distanceAB
589
+ P.y = A.y + (distanceAP * AB.y) / distanceAB
590
+ }
591
+ }else{
592
+ //make 3D projection on line
593
+ const AM = {
594
+ x: M.x - A.x,
595
+ y: M.y - A.y,
596
+ z: M.z - A.z,
597
+ }
598
+ const AB = {
599
+ x: B.x - A.x,
600
+ y: B.y - A.y,
601
+ z: B.z - A.z
602
+ }
603
+
604
+ const dot = AM.x * AB.x + AM.y * AB.y + AM.z * AB.z
605
+ const distanceAB = get3DDistanceBetweenPoints(A, B)
606
+ let param = -1
607
+ if (distanceAB == 0) {
608
+ //A et B sont confondu
609
+ console.error("A and B don't make a line : A==B")
610
+ P = M
611
+ } else {
612
+ // in case of 0 length line
613
+ const distanceAP = dot / distanceAB
614
+ P.x = A.x + (distanceAP * AB.x) / distanceAB
615
+ P.y = A.y + (distanceAP * AB.y) / distanceAB
616
+ P.z = A.z + (distanceAP * AB.z) / distanceAB
617
+ }
572
618
  }
573
619
  //projection of the point to the line
574
620
  return P
@@ -584,10 +630,10 @@ export function get3DDistanceBetweenPoints(firstPoint, secondPoint) {
584
630
 
585
631
 
586
632
  export function normalizedVectorTowardInsideAngle(H, I, J) {
587
- const IH_angle = Math.atan2(H.y - I.y, H.x - I.x)
588
- const JI_angle = Math.atan2(J.y - I.y, J.x - I.x)
589
- const angle = (IH_angle + JI_angle) / 2
590
- return { x: Math.cos(angle), y: Math.sin(angle) }
633
+ const IH = normalizeVector(substractVector(H, I))
634
+ const IJ = normalizeVector(substractVector(J, I))
635
+ const res = normalizeVector(addVector(IH,IJ))
636
+ return res
591
637
  }
592
638
 
593
639
 
@@ -904,4 +950,40 @@ export function get3DDistanceBetweenPoints(firstPoint, secondPoint) {
904
950
  }
905
951
  return { x: handleX, y: handleY, z: outline[i].z }
906
952
  }
953
+ export function triangleArea(A,B,C){
954
+ var AB = substractVector(B,A)
955
+ var AC = substractVector(C,A)
956
+ const product = crossProduct(AB, AC)
957
+ let area = vectorLength(product)/2
958
+ return area
959
+ }
960
+ export function getIndexesOfBiggestTrangle(points){
961
+ return getIndexesOfBiggestTrangleWithFixedIndexes(points,[])
962
+ }
963
+ export function getIndexesOfBiggestTrangleWithFixedIndexes(points,fixedIndexes){
964
+ if(points.length<3){
965
+ throw new Error("not enough points to make a triangle")
966
+ return
967
+ }
968
+ let maxArea = -1
969
+ let maxTriangle = [ 0, 1, 2]
970
+ fixedIndexes=[...new Set(...fixedIndexes)].slice(0,3)
971
+ if(fixedIndexes.length==3){return fixedIndexes}
972
+ for (let i = 0; i < points.length - 2; i++) {
973
+ if(fixedIndexes.length==0 || fixedIndexes.includes(i)){
974
+ for (let j = i + 1; j < points.length - 1; j++) {
975
+ if(fixedIndexes.length<2 || fixedIndexes.includes(j)){
976
+ for (let k = j + 1; k < points.length; k++) {
977
+ const area = triangleArea(points[i], points[j], points[k]);
978
+ if (area > maxArea) {
979
+ maxArea = area;
980
+ maxTriangle = [i, j, k];
981
+ }
982
+ }
983
+ }
984
+ }
985
+ }
986
+ }
987
+ return maxTriangle
988
+ }
907
989
 
@@ -1,12 +1,13 @@
1
1
 
2
2
  import {
3
- getDistanceBetweenPoints,
4
3
  translate2D,
5
4
  verticalProjectionOnPlane,
6
- get3DDistanceBetweenPoints
5
+ get3DDistanceBetweenPoints,
6
+ getDistanceBetweenPoints,
7
7
  } from '../geometry'
8
8
  import { v4 as uuidv4 } from 'uuid'
9
9
  import {Point} from './Point'
10
+ import { addVector, multiplyVector, substractVector,vectorLength,crossProduct,dotProduct,normalizeVector } from '../vector'
10
11
 
11
12
 
12
13
 
@@ -30,6 +31,25 @@ export class Circle {
30
31
  circle.id = uuidv4()
31
32
  return circle
32
33
  }
34
+ getIntersections(object){
35
+ const intersections=[]
36
+ if(!object)return
37
+ if(object.type=="point"){
38
+ if(get3DDistanceBetweenPoints(object,this.center)==this.radius){
39
+ intersections.push({...object})
40
+ }
41
+ }else if(object.type=="line"){
42
+ let P=object.getProjectedPoint(this.center)
43
+ let distance = get3DDistanceBetweenPoints(P,this.center)
44
+ if(distance<=this.radius){
45
+ let A=addVector(P,multiplyVector(Math.sqrt(Math.pow(this.radius,2)-Math.pow(distance,2)),object.getDirectionVector()))
46
+ let B=addVector(P,multiplyVector(-Math.sqrt(Math.pow(this.radius,2)-Math.pow(distance,2)),object.getDirectionVector()))
47
+ intersections.push({...A})
48
+ intersections.push({...B})
49
+ }
50
+ }
51
+ return intersections
52
+ }
33
53
  getPxDistanceTo(point, canvasContext) {
34
54
  const toCanvasRef = canvasContext.toCanvasRef
35
55
  let pxCenter = toCanvasRef(this.center)
@@ -41,6 +61,20 @@ export class Circle {
41
61
  }
42
62
  return Math.abs(get3DDistanceBetweenPoints(point, pxCenter) - pxRadius)
43
63
  }
64
+ getDistanceToPoint(point) {
65
+ return get3DDistanceBetweenPoints(point, this.getProjectedPoint(point))
66
+ }
67
+ getHorizontalDistanceToPoint(point) {
68
+ return getDistanceBetweenPoints(point, this.getVerticalProjectedPoint(point))
69
+ }
70
+ isInPlane(plane){
71
+ if(!plane) return false
72
+ const {point,normalVector}=plane
73
+ const circleNormalVector=this.normalVector || {x:0,y:0,z:1}
74
+ if(vectorLength(crossProduct(circleNormalVector,normalVector))>0.1) return false
75
+ if(dotProduct(normalizeVector(substractVector(point,this.center)),normalVector)>0.1) return false
76
+ return true
77
+ }
44
78
  getProjectedPoint(point) {
45
79
  if(this.normalVector){
46
80
  point.z=verticalProjectionOnPlane(point,this.normalVector,this.center).z
@@ -54,9 +88,13 @@ export class Circle {
54
88
  }
55
89
  let x = this.center.x + (point.x - this.center.x) * (this.radius / distance)
56
90
  let y = this.center.y + (point.y - this.center.y) * (this.radius / distance)
57
- let P = new Point(x, y, 0, this.layer)
91
+ let z = this.center.z + (point.z - this.center.z) * (this.radius / distance)
92
+ let P = new Point(x, y, z, this.layer)
58
93
  return P
59
94
  }
95
+ getVerticalProjectedPoint(point) {
96
+ return this.getProjectedPoint(point)
97
+ }
60
98
  translate(vectorInMm) {
61
99
  this.center = translate2D(this.center, vectorInMm)
62
100
  }
@@ -6,9 +6,12 @@ import {
6
6
  isSamePoint3D,
7
7
  translate2D,
8
8
  midPoint,
9
+ getDataAboutTwo3DLines,
10
+ isPointBetweenSegment,
9
11
  } from '../geometry'
10
12
  import { v4 as uuidv4 } from 'uuid'
11
13
  import {Point} from './Point'
14
+ import { substractVector,normalizeVector, addVector, multiplyVector,dotProduct } from '../vector'
12
15
 
13
16
 
14
17
  export class Line {
@@ -35,6 +38,35 @@ export class Line {
35
38
  line.infiniteLine = this.infiniteLine
36
39
  return line
37
40
  }
41
+ getDirectionVector(){
42
+ return normalizeVector(substractVector(this.outline[1],this.outline[0]))
43
+ }
44
+ getIntersections(object){
45
+ const intersections=[]
46
+ if(!object)return
47
+ if(object.type=="point"){
48
+ if(isSamePoint3D(this.getProjectedPoint(object),object)){
49
+ intersections.push({...object})
50
+ }
51
+ }else if(object.type=="line"){
52
+ const data = getDataAboutTwo3DLines(this.outline[0],this.getDirectionVector(),object.outline[0],object.getDirectionVector())
53
+ if(!data){return []}
54
+ let {distance,N} = data
55
+ if(distance<0.1 && !!N){
56
+ intersections.push({...N})
57
+ }
58
+ }else if(object.type=="circle"){
59
+ let P=this.getProjectedPoint(object.center)
60
+ let distance = get3DDistanceBetweenPoints(P,object.center)
61
+ if(distance<=object.radius){
62
+ let A=addVector(P,multiplyVector(Math.sqrt(Math.pow(object.radius,2)-Math.pow(distance,2)),this.getDirectionVector()))
63
+ let B=addVector(P,multiplyVector(-Math.sqrt(Math.pow(object.radius,2)-Math.pow(distance,2)),this.getDirectionVector()))
64
+ intersections.push({...A})
65
+ intersections.push({...B})
66
+ }
67
+ }
68
+ return intersections
69
+ }
38
70
  pxLength(canvasContext) {
39
71
  return (
40
72
  getDistanceBetweenPoints(this.outline[0], this.outline[1]) /
@@ -69,8 +101,50 @@ export class Line {
69
101
  }
70
102
 
71
103
  let realityRefPoint = toRealityRef(point)
72
- let P = getPointOnLine(realityRefPoint, this.outline[0], this.outline[1])
73
- return getDistanceBetweenPoints(realityRefPoint, P) / canvasContext.mmPerPx
104
+ let A={x:this.outline[0].x,y:this.outline[0].y,z:0}
105
+ let B={x:this.outline[1].x,y:this.outline[1].y,z:0}
106
+ let M={x:realityRefPoint.x,y:realityRefPoint.y,z:0}
107
+ let P = getPointOnLine(M, A, B)
108
+ P.z = 0
109
+ if(!this.infiniteLine && !isPointBetweenSegment(P,A,B)){
110
+ return (Math.min(getDistanceBetweenPoints(M, A),getDistanceBetweenPoints(M, B))) / canvasContext.mmPerPx
111
+ }
112
+ return getDistanceBetweenPoints(M, P) / canvasContext.mmPerPx
113
+ }
114
+ isInPlane(plane){
115
+ if(!plane) return false
116
+ const {point,normalVector}=plane
117
+ if(dotProduct(this.getDirectionVector(),normalVector)>0.1) return false
118
+ if(dotProduct(normalizeVector(substractVector(point,this.outline[0])),normalVector)>0.1) return false
119
+ return true
120
+ }
121
+ includesPoint2D(point,tolerance){
122
+ const projection=this.getVerticalProjectedPoint(point)
123
+ return this.getHorizontalDistanceToPoint(point) < tolerance && isPointBetweenSegment( projection, this.outline[0], this.outline[1])
124
+ }
125
+ getDistanceToPoint(point) {
126
+ return get3DDistanceBetweenPoints(point, this.getProjectedPoint(point))
127
+ }
128
+ getHorizontalDistanceToPoint(point) {
129
+ return getDistanceBetweenPoints(point, this.getVerticalProjectedPoint(point))
130
+ }
131
+ getVerticalProjectedPoint(point){
132
+ if (this.outline.length == 0) {
133
+ return null
134
+ }
135
+ if (isSamePoint3D(this.outline[0], this.outline[1])) {
136
+ console.error("A == B Can't project point on Line")
137
+ return null
138
+ }
139
+ let A= {...this.outline[0],z:0}
140
+ let B= {...this.outline[1],z:0}
141
+ let P = getPointOnLine({...point,z:0}, A,B)
142
+ let AP = substractVector(P,A)
143
+ let AB = substractVector(B,A)
144
+ let k=dotProduct(AP,AB)/dotProduct(AB,AB)
145
+ let zP=this.outline[0].z+k*(this.outline[1].z-this.outline[0].z)
146
+ P.z=zP
147
+ return P
74
148
  }
75
149
  getProjectedPoint(point) {
76
150
  if (this.outline.length == 0) {
@@ -1,9 +1,12 @@
1
1
 
2
+ import { v4 as uuidv4 } from 'uuid'
2
3
  import {
3
4
  getDistanceBetweenPoints,
5
+ get3DDistanceBetweenPoints,
6
+ isSamePoint3D,
4
7
  translate2D,
5
8
  } from '../geometry'
6
- import { v4 as uuidv4 } from 'uuid'
9
+ import { substractVector,dotProduct } from '../vector'
7
10
 
8
11
  export class Point {
9
12
  constructor(x = 0, y = 0, z = 0, layer = null) {
@@ -19,6 +22,24 @@ export class Point {
19
22
  this.visible = true
20
23
  this.hasWarning = false
21
24
  }
25
+ getIntersections(object){
26
+ const intersections=[]
27
+ if(!object)return
28
+ if(object.type=="line"){
29
+ if(isSamePoint3D(object.getProjectedPoint(this),this)){
30
+ intersections.push({...this})
31
+ }
32
+ }else if(object.type=="point"){
33
+ if(isSamePoint3D(object,this)){
34
+ intersections.push({...object})
35
+ }
36
+ }else if(object.type=="circle"){
37
+ if(get3DDistanceBetweenPoints(this,object.center)==object.radius){
38
+ intersections.push({...this})
39
+ }
40
+ }
41
+ return intersections
42
+ }
22
43
  getPxDistanceTo(point, canvasContext) {
23
44
  const toRealityRef = canvasContext.toRealityRef
24
45
  const realityPoint = toRealityRef(point)
@@ -27,6 +48,21 @@ export class Point {
27
48
  getProjectedPoint(point) {
28
49
  return this
29
50
  }
51
+ getVerticalProjectedPoint(point) {
52
+ return this
53
+ }
54
+ getDistanceToPoint(point) {
55
+ return get3DDistanceBetweenPoints(point, this.getProjectedPoint(point))
56
+ }
57
+ getHorizontalDistanceToPoint(point) {
58
+ return getDistanceBetweenPoints(point, this.getVerticalProjectedPoint(point))
59
+ }
60
+ isInPlane(plane){
61
+ if(!plane) return false
62
+ const {point,normalVector}=plane
63
+ if(dotProduct(substractVector(point,this),normalVector)>0.1) return false
64
+ return true
65
+ }
30
66
  translate(vectorInMm) {
31
67
  let translatedPoint = translate2D({ x: this.x, y: this.y }, vectorInMm)
32
68
  this.x = translatedPoint.x
@@ -124,7 +124,10 @@ export class Polygon {
124
124
  x: p.x,
125
125
  y: p.y,
126
126
  z: p.z,
127
- }}),
127
+ selected:p.selected,
128
+ open:p.open,
129
+ }
130
+ }),
128
131
  holes: this.holes.map((p) => p.id),
129
132
  layer: this.layer,
130
133
  highlight: this.highlight,
@@ -37,7 +37,11 @@ export function getRoofMarginOutline(polygon){
37
37
  polygon.margins.outterOutline=polygon.flatOutline
38
38
  polygon.margins.innerOutline=[]
39
39
  const length=polygon.outline.length
40
+ polygon.margins.distances = polygon.margins.distances.slice(0, length)
40
41
  for(let index=0;index<length;index++){
42
+ if(polygon.margins.distances[index] == undefined){
43
+ polygon.margins.distances[index] = polygon.margins.sameMargin
44
+ }
41
45
  const B=polygon.margins.outterOutline[index]
42
46
  //A,B,C three consecutive points on the polygon.
43
47
  //n is a vector in the plan normal to AB of length margin[A] directed towards the inside
@@ -78,7 +82,11 @@ export function getObstacleMarginOutline(polygon){
78
82
  polygon.margins.innerOutline=polygon.flatOutline
79
83
  polygon.margins.outterOutline=[]
80
84
  const length=polygon.margins.innerOutline.length
85
+ polygon.margins.distances = polygon.margins.distances.slice(0, length)
81
86
  for(let index=0;index<length;index++){
87
+ if(polygon.margins.distances[index] == undefined){
88
+ polygon.margins.distances[index] = polygon.margins.sameMargin
89
+ }
82
90
  const B=polygon.margins.innerOutline[index]
83
91
  //A,B,C three consecutive points on the polygon.
84
92
  //n is a vector in the plan normal to AB of length margin[A] directed towards the inside
@@ -62,7 +62,7 @@ export function updateComputedGeometryPolygon(polygon) {
62
62
  if(!['roof','obstacle','moduleField'].includes(polygon.layer)){
63
63
  return polygon
64
64
  }
65
- if(isAlmostSamePoint2D(polygon.outline[0],polygon.outline[polygon.outline.length-1],10)){
65
+ if(polygon.outline.length > 0 && isAlmostSamePoint2D(polygon.outline[0],polygon.outline[polygon.outline.length-1],10)){
66
66
  polygon.outline.pop()
67
67
  }
68
68
  polygon.outline = calculateValidOutlineFromPolygon(polygon.outline)
@@ -125,10 +125,12 @@ export function calculateValidOutlineFromPolygon(outline){
125
125
  let v = normalizedVectorTowardInsideAngle(D,E,F)
126
126
 
127
127
  outline[coupleToSplit[0]] = {
128
+ ...outline[coupleToSplit[0]],
128
129
  ...addVector(multiplyVector(-mmTolerance,u),B),
129
130
  z:outline[coupleToSplit[0]].z
130
131
  }
131
132
  outline[coupleToSplit[1]] = {
133
+ ...outline[coupleToSplit[1]],
132
134
  ...addVector(multiplyVector(mmTolerance,v),E),
133
135
  z:outline[coupleToSplit[1]].z
134
136
  }
@@ -144,7 +146,7 @@ export function calculateBestFittingPlanePolygon(fullOutline) {
144
146
  return null
145
147
  }
146
148
  let isIncludingAllNodes=false
147
- let outline=fullOutline.filter(p=>!p.selected)
149
+ let outline=fullOutline
148
150
  if(outline.length<3){
149
151
  isIncludingAllNodes=true
150
152
  outline=fullOutline
package/src/vector.js CHANGED
@@ -25,6 +25,12 @@ export function addVector(u, v) {
25
25
  const result = u.x * v.x + u.y * v.y + u.z * v.z
26
26
  return result
27
27
  }
28
+ export function areCollinear(u,v){
29
+ return vectorLength(crossProduct(u,v)) == 0
30
+ }
31
+ export function areAlmostCollinear(u,v,tolerance){
32
+ return vectorLength(crossProduct(u,v)) < tolerance
33
+ }
28
34
  export function crossProduct(u, v) {
29
35
  const result = {}
30
36
  result.x = u.y * v.z - u.z * v.y