pimath 0.0.33 → 0.0.36

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.
Files changed (165) hide show
  1. package/dist/pi.js +6468 -1
  2. package/dist/pi.js.map +1 -1
  3. package/dist/pi.min.js +2 -0
  4. package/dist/pi.min.js.map +1 -0
  5. package/docs/assets/search.js +1 -1
  6. package/docs/classes/algebra.Equation.html +9 -9
  7. package/docs/classes/algebra.LinearSystem.html +1 -1
  8. package/docs/classes/algebra.Logicalset.html +2 -2
  9. package/docs/classes/algebra.Monom.html +37 -37
  10. package/docs/classes/algebra.Polynom.html +10 -10
  11. package/docs/classes/algebra.PolynomExpFactor.html +1 -1
  12. package/docs/classes/algebra.PolynomExpProduct.html +1 -1
  13. package/docs/classes/algebra.Rational.html +2 -2
  14. package/docs/classes/coefficients.Fraction.html +4 -4
  15. package/docs/classes/coefficients.Nthroot.html +1 -1
  16. package/docs/classes/geometry.Circle.html +2 -2
  17. package/docs/classes/geometry.Line.html +2 -2
  18. package/docs/classes/geometry.Point.html +1 -1
  19. package/docs/classes/geometry.Triangle.html +5 -5
  20. package/docs/classes/geometry.Vector.html +1 -1
  21. package/docs/classes/numeric.Numeric.html +5 -5
  22. package/docs/classes/shutingyard.Shutingyard.html +4 -4
  23. package/docs/enums/geometry.LinePropriety.html +1 -0
  24. package/docs/enums/shutingyard.ShutingyardMode.html +1 -1
  25. package/docs/enums/shutingyard.ShutingyardType.html +1 -1
  26. package/docs/interfaces/geometry.remarquableLines.html +1 -1
  27. package/docs/modules/algebra.html +1 -1
  28. package/docs/modules/coefficients.html +1 -1
  29. package/docs/modules/geometry.html +1 -1
  30. package/docs/modules/random.Random.html +1 -1
  31. package/docs/modules/random.html +1 -1
  32. package/docs/modules/shutingyard.html +1 -1
  33. package/esm/main.d.ts +41 -1
  34. package/esm/main.js +34 -20
  35. package/esm/main.js.map +1 -1
  36. package/esm/maths/algebra/equation.d.ts +63 -18
  37. package/esm/maths/algebra/equation.js +599 -503
  38. package/esm/maths/algebra/equation.js.map +1 -1
  39. package/esm/maths/algebra/linearSystem.d.ts +1 -1
  40. package/esm/maths/algebra/linearSystem.js +157 -104
  41. package/esm/maths/algebra/linearSystem.js.map +1 -1
  42. package/esm/maths/algebra/logicalset.d.ts +11 -0
  43. package/esm/maths/algebra/logicalset.js +18 -6
  44. package/esm/maths/algebra/logicalset.js.map +1 -1
  45. package/esm/maths/algebra/monom.d.ts +142 -1
  46. package/esm/maths/algebra/monom.js +633 -405
  47. package/esm/maths/algebra/monom.js.map +1 -1
  48. package/esm/maths/algebra/polynom.d.ts +52 -3
  49. package/esm/maths/algebra/polynom.js +1003 -720
  50. package/esm/maths/algebra/polynom.js.map +1 -1
  51. package/esm/maths/algebra/rational.d.ts +13 -1
  52. package/esm/maths/algebra/rational.js +98 -83
  53. package/esm/maths/algebra/rational.js.map +1 -1
  54. package/esm/maths/coefficients/fraction.d.ts +18 -0
  55. package/esm/maths/coefficients/fraction.js +390 -332
  56. package/esm/maths/coefficients/fraction.js.map +1 -1
  57. package/esm/maths/coefficients/nthroot.d.ts +3 -0
  58. package/esm/maths/coefficients/nthroot.js +48 -33
  59. package/esm/maths/coefficients/nthroot.js.map +1 -1
  60. package/esm/maths/expressions/numexp.js +13 -5
  61. package/esm/maths/expressions/numexp.js.map +1 -1
  62. package/esm/maths/expressions/polynomexp.bkp.d.ts +2 -2
  63. package/esm/maths/expressions/polynomexp.bkp.js +95 -95
  64. package/esm/maths/expressions/polynomexp.bkp.js.map +1 -1
  65. package/esm/maths/expressions/polynomexp.d.ts +2 -2
  66. package/esm/maths/expressions/polynomexp.js +27 -14
  67. package/esm/maths/expressions/polynomexp.js.map +1 -1
  68. package/esm/maths/geometry/circle.d.ts +20 -8
  69. package/esm/maths/geometry/circle.js +148 -50
  70. package/esm/maths/geometry/circle.js.map +1 -1
  71. package/esm/maths/geometry/line.d.ts +11 -4
  72. package/esm/maths/geometry/line.js +251 -193
  73. package/esm/maths/geometry/line.js.map +1 -1
  74. package/esm/maths/geometry/point.d.ts +13 -1
  75. package/esm/maths/geometry/point.js +124 -76
  76. package/esm/maths/geometry/point.js.map +1 -1
  77. package/esm/maths/geometry/triangle.d.ts +23 -1
  78. package/esm/maths/geometry/triangle.js +197 -158
  79. package/esm/maths/geometry/triangle.js.map +1 -1
  80. package/esm/maths/geometry/vector.d.ts +5 -1
  81. package/esm/maths/geometry/vector.js +139 -115
  82. package/esm/maths/geometry/vector.js.map +1 -1
  83. package/esm/maths/numeric.d.ts +17 -0
  84. package/esm/maths/numeric.js +40 -0
  85. package/esm/maths/numeric.js.map +1 -1
  86. package/esm/maths/{random/index.d.ts → randomization/random.d.ts} +3 -2
  87. package/esm/maths/{random/index.js → randomization/random.js} +6 -2
  88. package/esm/maths/randomization/random.js.map +1 -0
  89. package/esm/maths/{random → randomization}/randomCore.d.ts +0 -0
  90. package/esm/maths/randomization/randomCore.js +22 -0
  91. package/esm/maths/randomization/randomCore.js.map +1 -0
  92. package/esm/maths/{random → randomization}/rndFraction.d.ts +4 -1
  93. package/esm/maths/randomization/rndFraction.js +40 -0
  94. package/esm/maths/randomization/rndFraction.js.map +1 -0
  95. package/esm/maths/randomization/rndHelpers.d.ts +25 -0
  96. package/esm/maths/{random → randomization}/rndHelpers.js +20 -0
  97. package/esm/maths/randomization/rndHelpers.js.map +1 -0
  98. package/esm/maths/{random → randomization}/rndMonom.d.ts +4 -1
  99. package/esm/maths/randomization/rndMonom.js +53 -0
  100. package/esm/maths/randomization/rndMonom.js.map +1 -0
  101. package/esm/maths/{random → randomization}/rndPolynom.d.ts +4 -1
  102. package/esm/maths/randomization/rndPolynom.js +75 -0
  103. package/esm/maths/randomization/rndPolynom.js.map +1 -0
  104. package/esm/maths/{random → randomization}/rndTypes.d.ts +0 -0
  105. package/esm/maths/{random → randomization}/rndTypes.js +0 -0
  106. package/esm/maths/randomization/rndTypes.js.map +1 -0
  107. package/esm/maths/shutingyard.d.ts +21 -0
  108. package/esm/maths/shutingyard.js +86 -9
  109. package/esm/maths/shutingyard.js.map +1 -1
  110. package/package.json +2 -2
  111. package/public/index.html +47 -0
  112. package/src/main.ts +17 -15
  113. package/src/maths/algebra/equation.ts +144 -129
  114. package/src/maths/algebra/linearSystem.ts +2 -2
  115. package/src/maths/algebra/monom.ts +1 -1
  116. package/src/maths/algebra/polynom.ts +136 -136
  117. package/src/maths/algebra/rational.ts +1 -1
  118. package/src/maths/expressions/numexp.ts +1 -1
  119. package/src/maths/expressions/polynomexp.bkp.ts +2 -2
  120. package/src/maths/expressions/polynomexp.ts +2 -2
  121. package/src/maths/geometry/circle.ts +172 -77
  122. package/src/maths/geometry/line.ts +4 -3
  123. package/src/maths/geometry/point.ts +26 -3
  124. package/src/maths/geometry/triangle.ts +1 -1
  125. package/src/maths/geometry/vector.ts +1 -1
  126. package/src/maths/numeric.ts +15 -0
  127. package/src/maths/{random/index.ts → randomization/random.ts} +3 -2
  128. package/src/maths/{random → randomization}/randomCore.ts +0 -0
  129. package/src/maths/{random → randomization}/rndFraction.ts +2 -2
  130. package/src/maths/{random → randomization}/rndHelpers.ts +0 -0
  131. package/src/maths/{random → randomization}/rndMonom.ts +2 -2
  132. package/src/maths/{random → randomization}/rndPolynom.ts +3 -3
  133. package/src/maths/{random → randomization}/rndTypes.ts +0 -0
  134. package/tests/algebra/monom.test.ts +1 -1
  135. package/tests/algebra/polynom.test.ts +8 -9
  136. package/tests/geometry/circle.test.ts +33 -0
  137. package/tsconfig.json +2 -2
  138. package/webpack-production-min.config.js +26 -0
  139. package/webpack-production.config.js +1 -1
  140. package/dev/pi.js +0 -5392
  141. package/dev/pi.js.map +0 -1
  142. package/esm/maths/algebra/index.d.ts +0 -7
  143. package/esm/maths/algebra/index.js +0 -20
  144. package/esm/maths/algebra/index.js.map +0 -1
  145. package/esm/maths/coefficients/index.d.ts +0 -2
  146. package/esm/maths/coefficients/index.js +0 -15
  147. package/esm/maths/coefficients/index.js.map +0 -1
  148. package/esm/maths/geometry/index.d.ts +0 -5
  149. package/esm/maths/geometry/index.js +0 -18
  150. package/esm/maths/geometry/index.js.map +0 -1
  151. package/esm/maths/random/index.js.map +0 -1
  152. package/esm/maths/random/randomCore.js +0 -22
  153. package/esm/maths/random/randomCore.js.map +0 -1
  154. package/esm/maths/random/rndFraction.js +0 -37
  155. package/esm/maths/random/rndFraction.js.map +0 -1
  156. package/esm/maths/random/rndHelpers.d.ts +0 -8
  157. package/esm/maths/random/rndHelpers.js.map +0 -1
  158. package/esm/maths/random/rndMonom.js +0 -46
  159. package/esm/maths/random/rndMonom.js.map +0 -1
  160. package/esm/maths/random/rndPolynom.js +0 -63
  161. package/esm/maths/random/rndPolynom.js.map +0 -1
  162. package/esm/maths/random/rndTypes.js.map +0 -1
  163. package/src/maths/algebra/index.ts +0 -7
  164. package/src/maths/coefficients/index.ts +0 -2
  165. package/src/maths/geometry/index.ts +0 -5
@@ -5,10 +5,10 @@
5
5
  import {literalType, Monom} from './monom';
6
6
  import {Shutingyard, ShutingyardType, Token} from '../shutingyard';
7
7
  import {Numeric} from '../numeric';
8
- import {Fraction} from "../coefficients";
9
- import {log} from "util";
8
+ import {Fraction} from "../coefficients/fraction";
9
+
10
+ export type PolynomParsingType = string | Polynom | number | Fraction | Monom
10
11
 
11
- export type PolynomParsingType = string|Polynom|number|Fraction|Monom
12
12
  /**
13
13
  * Polynom class can handle polynoms, reorder, resolve, ...
14
14
  * ```
@@ -120,6 +120,82 @@ export class Polynom {
120
120
  return this.variables.length;
121
121
  }
122
122
 
123
+ static addToken = (stack: Polynom[], element: Token): void => {
124
+
125
+ switch (element.tokenType) {
126
+ case ShutingyardType.COEFFICIENT:
127
+ stack.push(new Polynom(element.token))
128
+ break
129
+
130
+ case ShutingyardType.VARIABLE:
131
+ stack.push(new Polynom().add(new Monom(element.token)))
132
+ break
133
+
134
+ case ShutingyardType.CONSTANT:
135
+ // TODO: add constant support to Polynom parsing.
136
+ console.log('Actually, not supported - will be added later !')
137
+ break
138
+
139
+ case ShutingyardType.OPERATION:
140
+ if (stack.length >= 2) {
141
+ const b = stack.pop(),
142
+ a = stack.pop()
143
+
144
+ if (element.token === '+') {
145
+ stack.push(a.add(b))
146
+ } else if (element.token === '-') {
147
+ stack.push(a.subtract(b))
148
+ } else if (element.token === '*') {
149
+ stack.push(a.multiply(b))
150
+ } else if (element.token === '/') {
151
+ if (b.degree().isStrictlyPositive()) {
152
+ console.log('divide by a polynom -> should create a rational polynom !')
153
+ } else {
154
+ stack.push(a.divide(b.monoms[0].coefficient))
155
+
156
+ }
157
+ } else if (element.token === '^') {
158
+ if (b.degree().isStrictlyPositive()) {
159
+ console.error('Cannot elevate a polynom with another polynom !')
160
+ } else {
161
+ if (b.monoms[0].coefficient.isRelative()) {
162
+ // Integer power
163
+ stack.push(a.pow(b.monoms[0].coefficient.value))
164
+ } else {
165
+ // Only allow power if the previous polynom is only a monom, without coefficient.
166
+ if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {
167
+ for (let letter in a.monoms[0].literal) {
168
+ a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient)
169
+ }
170
+ stack.push(a)
171
+ } else {
172
+ console.error('Cannot have power with fraction')
173
+ }
174
+ }
175
+ }
176
+ }
177
+ } else {
178
+ console.log('Stack size: ', stack.length)
179
+ if (element.token === '-') {
180
+ stack.push(stack.pop().opposed())
181
+ } else {
182
+ console.log('While parsing, cannot apply ', element.token, 'to', stack[0].tex)
183
+ }
184
+ }
185
+ break
186
+
187
+ case ShutingyardType.MONOM:
188
+ // Should never appear.
189
+ console.error('The monom token should not appear here')
190
+ break;
191
+
192
+ case ShutingyardType.FUNCTION:
193
+ // Should never appear.
194
+ console.log('The function token should not appear here - might be introduced later.')
195
+ break;
196
+ }
197
+ }
198
+
123
199
  // ------------------------------------------
124
200
  /**
125
201
  * Parse a string to a polynom.
@@ -131,12 +207,12 @@ export class Polynom {
131
207
  this._monoms = []
132
208
  this._factors = []
133
209
 
134
- if(typeof inputStr === 'string') {
210
+ if (typeof inputStr === 'string') {
135
211
  return this._parseString(inputStr, ...values)
136
- }else if(typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof Monom){
212
+ } else if (typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof Monom) {
137
213
  this._monoms.push(new Monom(inputStr))
138
- }else if(inputStr instanceof Polynom){
139
- for(const m of inputStr.monoms){
214
+ } else if (inputStr instanceof Polynom) {
215
+ for (const m of inputStr.monoms) {
140
216
  this._monoms.push(m.clone())
141
217
  }
142
218
  }
@@ -144,59 +220,6 @@ export class Polynom {
144
220
  return this
145
221
  };
146
222
 
147
- private _parseString(inputStr: string, ...values:unknown[]): Polynom{
148
- if (values === undefined || values.length === 0) {
149
- inputStr = '' + inputStr;
150
- this._rawString = inputStr;
151
-
152
- // Parse the polynom using the shutting yard algorithm
153
- if (inputStr !== '' && !isNaN(Number(inputStr))) {
154
- this.empty();
155
- // It's a simple number.
156
- let m = new Monom(inputStr);
157
- // m.coefficient = new Fraction(inputStr);
158
- // m.literalStr = '';
159
- this.add(m);
160
- return this;
161
- }
162
-
163
- // Parse the string.
164
- return this.shutingYardToReducedPolynom(inputStr);
165
- } else if (/^[a-z]/.test(inputStr)) {
166
- // We assume the inputStr contains only letters.
167
- this.empty();
168
-
169
- let fractions = values.map(x => new Fraction(x));
170
- // Multiple setLetter version
171
- if (inputStr.length > 1) {
172
- // TODO: check that the number of values given correspond to the letters (+1 eventually)
173
- let letters = inputStr.split(''),
174
- i = 0;
175
- for (let F of fractions) {
176
- let m = new Monom();
177
- m.coefficient = F.clone();
178
- m.literalStr = letters[i] || '';
179
- this.add(m);
180
- i++;
181
- }
182
- }
183
- // Single setLetter version
184
- else {
185
- let n = fractions.length - 1;
186
- for (let F of fractions) {
187
- let m = new Monom()
188
- m.coefficient = F.clone();
189
- m.literalStr = `${inputStr}^${n}`
190
- this.add(m);
191
- n--;
192
- }
193
- }
194
- return this;
195
- } else {
196
- return this.zero();
197
- }
198
- }
199
-
200
223
 
201
224
  // ------------------------------------------
202
225
  // Creation / parsing functions
@@ -972,6 +995,59 @@ export class Polynom {
972
995
  return M;
973
996
  }
974
997
 
998
+ private _parseString(inputStr: string, ...values: unknown[]): Polynom {
999
+ if (values === undefined || values.length === 0) {
1000
+ inputStr = '' + inputStr;
1001
+ this._rawString = inputStr;
1002
+
1003
+ // Parse the polynom using the shutting yard algorithm
1004
+ if (inputStr !== '' && !isNaN(Number(inputStr))) {
1005
+ this.empty();
1006
+ // It's a simple number.
1007
+ let m = new Monom(inputStr);
1008
+ // m.coefficient = new Fraction(inputStr);
1009
+ // m.literalStr = '';
1010
+ this.add(m);
1011
+ return this;
1012
+ }
1013
+
1014
+ // Parse the string.
1015
+ return this.shutingYardToReducedPolynom(inputStr);
1016
+ } else if (/^[a-z]/.test(inputStr)) {
1017
+ // We assume the inputStr contains only letters.
1018
+ this.empty();
1019
+
1020
+ let fractions = values.map(x => new Fraction(x));
1021
+ // Multiple setLetter version
1022
+ if (inputStr.length > 1) {
1023
+ // TODO: check that the number of values given correspond to the letters (+1 eventually)
1024
+ let letters = inputStr.split(''),
1025
+ i = 0;
1026
+ for (let F of fractions) {
1027
+ let m = new Monom();
1028
+ m.coefficient = F.clone();
1029
+ m.literalStr = letters[i] || '';
1030
+ this.add(m);
1031
+ i++;
1032
+ }
1033
+ }
1034
+ // Single setLetter version
1035
+ else {
1036
+ let n = fractions.length - 1;
1037
+ for (let F of fractions) {
1038
+ let m = new Monom()
1039
+ m.coefficient = F.clone();
1040
+ m.literalStr = `${inputStr}^${n}`
1041
+ this.add(m);
1042
+ n--;
1043
+ }
1044
+ }
1045
+ return this;
1046
+ } else {
1047
+ return this.zero();
1048
+ }
1049
+ }
1050
+
975
1051
  private genDisplay = (output?: string, forceSign?: boolean, wrapParentheses?: boolean): string => {
976
1052
  let P: string = '';
977
1053
 
@@ -997,82 +1073,6 @@ export class Polynom {
997
1073
  return P;
998
1074
  };
999
1075
 
1000
-
1001
- static addToken = (stack: Polynom[], element: Token): void => {
1002
-
1003
- switch(element.tokenType){
1004
- case ShutingyardType.COEFFICIENT:
1005
- stack.push(new Polynom( element.token ))
1006
- break
1007
-
1008
- case ShutingyardType.VARIABLE:
1009
- stack.push(new Polynom().add(new Monom(element.token)))
1010
- break
1011
-
1012
- case ShutingyardType.CONSTANT:
1013
- // TODO: add constant support to Polynom parsing.
1014
- console.log('Actually, not supported - will be added later !')
1015
- break
1016
-
1017
- case ShutingyardType.OPERATION:
1018
- if(stack.length>=2){
1019
- const b = stack.pop(),
1020
- a = stack.pop()
1021
-
1022
- if(element.token === '+'){
1023
- stack.push(a.add(b))
1024
- }else if(element.token === '-'){
1025
- stack.push(a.subtract(b))
1026
- }else if(element.token === '*'){
1027
- stack.push(a.multiply(b))
1028
- }else if(element.token === '/'){
1029
- if(b.degree().isStrictlyPositive()){
1030
- console.log('divide by a polynom -> should create a rational polynom !')
1031
- }else {
1032
- stack.push(a.divide(b.monoms[0].coefficient))
1033
-
1034
- }
1035
- }else if(element.token === '^'){
1036
- if(b.degree().isStrictlyPositive()) {
1037
- console.error('Cannot elevate a polynom with another polynom !')
1038
- }else {
1039
- if(b.monoms[0].coefficient.isRelative()) {
1040
- // Integer power
1041
- stack.push(a.pow(b.monoms[0].coefficient.value))
1042
- }else{
1043
- // Only allow power if the previous polynom is only a monom, without coefficient.
1044
- if(a.monoms.length===1 && a.monoms[0].coefficient.isOne()){
1045
- for (let letter in a.monoms[0].literal) {
1046
- a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient)
1047
- }
1048
- stack.push(a)
1049
- }else {
1050
- console.error('Cannot have power with fraction')
1051
- }
1052
- }
1053
- }
1054
- }
1055
- }else{
1056
- console.log('Stack size: ', stack.length)
1057
- if(element.token === '-'){
1058
- stack.push(stack.pop().opposed())
1059
- }else{
1060
- console.log('While parsing, cannot apply ', element.token, 'to', stack[0].tex)
1061
- }
1062
- }
1063
- break
1064
-
1065
- case ShutingyardType.MONOM:
1066
- // Should never appear.
1067
- console.error('The monom token should not appear here')
1068
- break;
1069
-
1070
- case ShutingyardType.FUNCTION:
1071
- // Should never appear.
1072
- console.log('The function token should not appear here - might be introduced later.')
1073
- break;
1074
- }
1075
- }
1076
1076
  /**
1077
1077
  * Main parse using a shutting yard class
1078
1078
  * @param inputStr
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import {Polynom} from "./polynom";
7
- import {Fraction} from "../coefficients";
7
+ import {Fraction} from "../coefficients/fraction";
8
8
 
9
9
  /**
10
10
  * Rational class can handle rational polynoms
@@ -1,5 +1,5 @@
1
1
  import {Shutingyard, ShutingyardMode, ShutingyardType, tokenConstant} from "../shutingyard";
2
- import {Fraction} from "../coefficients";
2
+ import {Fraction} from "../coefficients/fraction";
3
3
 
4
4
  export class NumExp {
5
5
  private _rpn: { token: string, tokenType: string }[]
@@ -1,5 +1,5 @@
1
- import {Polynom} from "../algebra";
2
- import {Fraction} from "../coefficients";
1
+ import {Polynom} from "../algebra/polynom";
2
+ import {Fraction} from "../coefficients/fraction";
3
3
 
4
4
  type Factor = {
5
5
  polynom: Polynom,
@@ -1,5 +1,5 @@
1
- import {Polynom, PolynomParsingType} from "../algebra";
2
- import {Fraction, FractionParsingType} from "../coefficients";
1
+ import {Polynom, PolynomParsingType} from "../algebra/polynom";
2
+ import {Fraction, FractionParsingType} from "../coefficients/fraction";
3
3
 
4
4
  type PolynomExpMathFunctionType = { name: string; fn: Function, tex: string }
5
5
 
@@ -1,16 +1,14 @@
1
1
  import {Point} from "./point";
2
- import {Fraction} from "../coefficients";
3
- import {Equation, Monom, Polynom} from "../algebra";
4
- import {Line} from "./line";
2
+ import {Line, LinePropriety} from "./line";
5
3
  import {Vector} from "./vector";
6
4
  import {Triangle} from "./triangle";
5
+ import {Numeric} from "../numeric";
6
+ import {Fraction} from "../coefficients/fraction";
7
+ import {Equation} from "../algebra/equation";
8
+ import {Polynom} from "../algebra/polynom";
9
+ import {Monom} from "../algebra/monom";
7
10
 
8
11
  export class Circle {
9
- private _center: Point;
10
- private _squareRadius: Fraction;
11
- private _cartesian: Equation;
12
- private _exists: boolean;
13
-
14
12
  constructor(...values: unknown[]) {
15
13
  this._exists = false
16
14
 
@@ -19,30 +17,42 @@ export class Circle {
19
17
  }
20
18
  }
21
19
 
20
+ private _center: Point;
22
21
 
23
22
  get center(): Point {
24
23
  return this._center;
25
24
  }
26
25
 
27
-
28
- get exists(): boolean {
29
- return this._exists;
30
- }
26
+ private _squareRadius: Fraction;
31
27
 
32
28
  get squareRadius(): Fraction {
33
29
  return this._squareRadius
34
30
  }
35
31
 
36
- get radius(): { tex: string, display: string } {
32
+ private _cartesian: Equation;
33
+
34
+ get cartesian(): Equation {
35
+ return this._cartesian
36
+ }
37
+
38
+ private _exists: boolean;
39
+
40
+ get exists(): boolean {
41
+ return this._exists;
42
+ }
43
+
44
+ get radius(): { tex: string, display: string, value: number } {
37
45
  if (this._squareRadius.isSquare()) {
38
46
  return {
39
47
  tex: this._squareRadius.clone().sqrt().tex,
40
48
  display: this._squareRadius.clone().sqrt().display,
49
+ value: this._squareRadius.clone().sqrt().value
41
50
  }
42
51
  } else {
43
52
  return {
44
53
  tex: `\\sqrt{${this._squareRadius.tex}}`,
45
- display: `sqrt(${this._squareRadius.display})`
54
+ display: `sqrt(${this._squareRadius.display})`,
55
+ value: this._squareRadius.clone().sqrt().value
46
56
  }
47
57
  }
48
58
  return this._squareRadius
@@ -72,14 +82,100 @@ export class Circle {
72
82
  return this._cartesian.tex
73
83
  }
74
84
 
75
-
76
85
  // TODO: reformat code for better display.
77
86
  get display(): string {
78
87
  return this._cartesian.display
79
88
  }
80
89
 
81
- get cartesian(): Equation {
82
- return this._cartesian
90
+ /**
91
+ * Get the relative position between circle and line. It corresponds to the number of intersection.
92
+ * @param {Line} L
93
+ * @returns {number}
94
+ */
95
+ relativePosition = (L: Line): number => {
96
+ let distance = L.distanceTo(this.center), radius = Math.sqrt(this._squareRadius.value)
97
+
98
+ if (distance.value - radius > 0.0000000001) {
99
+ return 0 // external
100
+ } else if (Math.abs(distance.value - radius) < 0.0000000001) {
101
+ return 1 // tangent
102
+ } else {
103
+ return 2 // external
104
+ }
105
+ }
106
+
107
+ lineIntersection = (L: Line): Point[] => {
108
+ let intersectionPoints: Point[] = [], solX: Fraction
109
+
110
+ if (this._cartesian === null) {
111
+ return []
112
+ }
113
+ const equX = this._cartesian.clone(), lineX = L.equation.clone().isolate('x'),
114
+ lineY = L.equation.clone().isolate('y')
115
+
116
+ if (lineX instanceof Equation && lineY instanceof Equation) {
117
+ equX.replaceBy('y', lineY.right).simplify()
118
+ equX.solve()
119
+
120
+ for (let x of equX.solutions) {
121
+ if (x.exact === false && isNaN(x.value)) {
122
+ continue
123
+ }
124
+
125
+ solX = new Fraction(x.exact === false ? x.value : x.exact)
126
+ intersectionPoints.push(new Point(solX.clone(), lineY.right.evaluate(solX)))
127
+ }
128
+ }
129
+
130
+ return intersectionPoints
131
+ }
132
+
133
+ tangents = (P: Point | Fraction): Line[] => {
134
+ if (P instanceof Fraction) {
135
+ return this._tangentsWithSlope(P)
136
+ } else if (this.isPointOnCircle(P)) {
137
+ return this._tangentsThroughOnePointOnTheCircle(P)
138
+ } else if (this.center.distanceTo(P).value > this.radius.value) {
139
+ //TODO: Must check it's outside the circle
140
+ return this._tangentsThroughOnePointOutsideTheCircle(P)
141
+ } else {
142
+ console.log('No tangents as the point is inside !')
143
+ }
144
+ return []
145
+ }
146
+
147
+ isPointOnCircle = (P: Point): Boolean => {
148
+ return this._cartesian.test({x: P.x, y: P.y})
149
+ }
150
+
151
+ getPointsOnCircle = (numberIsInteger?: boolean): Point[] => {
152
+ if (numberIsInteger === undefined) {
153
+ numberIsInteger = false
154
+ }
155
+
156
+ // It means searching for pythagorician triples that make a perfect square.
157
+ // (x-4)^2 + (y+3)^2 = 15
158
+
159
+ let triplets = Numeric.pythagoricianTripletsWithTarget(this._squareRadius.value, true)
160
+
161
+ let points: Point[] = [], pt
162
+ triplets.forEach(triplet => {
163
+ // Allow positive / negative values
164
+ // x-a = t => x = a + t
165
+ // x-a = -t => x = a - t
166
+
167
+ for (let k of [[1, 1], [-1, 1], [-1, -1], [1, -1]]) {
168
+ pt = new Point(
169
+ this.center.x.clone().add(k[0] * triplet[0]),
170
+ this.center.y.clone().add(k[1] * triplet[1])
171
+ )
172
+ // Check if the point is not already in points.
173
+ if (!pt.isInListOfPoints(points)) {
174
+ points.push(pt)
175
+ }
176
+ }
177
+ })
178
+ return points
83
179
  }
84
180
 
85
181
  clone(): Circle {
@@ -89,6 +185,59 @@ export class Circle {
89
185
  return this
90
186
  }
91
187
 
188
+ private _tangentsThroughOnePointOnTheCircle = (P: Point): Line[] => {
189
+ let CT = new Vector(this._center, P)
190
+ return [new Line(P, CT, LinePropriety.Perpendicular)]
191
+ }
192
+
193
+ private _tangentsThroughOnePointOutsideTheCircle = (P: Point): Line[] => {
194
+ // y = mx + h
195
+ // px, py => h = -m px + py => mx - y -m.px + py = 0 =>
196
+ // Centre: cx, cy, radius: r
197
+ // (m.cx - cy -m.px + py)^2 = r^2 * (m^2 + 1)
198
+ // (m(cx-py) - (cy - py))^2 = r^2 * (m^2 + 1)
199
+
200
+ let cx_px = this.center.x.clone().subtract(P.x), cy_py = this.center.y.clone().subtract(P.y),
201
+ polyLeft = new Polynom('x'), polyRight = new Polynom('x^2+1')
202
+
203
+ polyLeft.multiply(cx_px).subtract(cy_py).pow(2)
204
+ polyRight.multiply(this.squareRadius)
205
+
206
+ let equ = new Equation(polyLeft, polyRight)
207
+ equ.moveLeft().simplify().solve()
208
+
209
+ return equ.solutions.map(sol => {
210
+ // h = -m px + py
211
+ let h, equ = new Equation('y', 'x')
212
+
213
+ if (sol.exact instanceof Fraction) {
214
+ h = P.x.clone().opposed().multiply(sol.exact).add(P.y)
215
+ equ.right.multiply(sol.exact).add(h)
216
+ } else {
217
+ h = P.x.clone().opposed().multiply(sol.value).add(P.y)
218
+ equ.right.multiply(sol.value).add(h)
219
+ }
220
+
221
+ return new Line(equ)
222
+ })
223
+
224
+ }
225
+
226
+ private _tangentsWithSlope = (slope: Fraction): Line[] => {
227
+ // d(C;t)=r => ac1+bc2 + x = +- sqrt(a^2 + b^2)*r
228
+ // x = -ac1-bc2 +- sqrt(a^2 + b^2)*r
229
+ // y = a/bx + h => ax-by + H = 0
230
+
231
+ const a = slope.numerator, b = -slope.denominator, c1 = this._center.x.clone(), c2 = this._center.y.clone(),
232
+ r = this._squareRadius
233
+
234
+ let sq = this._squareRadius.clone().multiply(slope.numerator ** 2 + slope.denominator ** 2),
235
+ x1 = c1.clone().multiply(a).opposed().subtract(c2.clone().multiply(b)).add(sq.clone().sqrt()),
236
+ x2 = c1.clone().multiply(a).opposed().subtract(c2.clone().multiply(b)).subtract(sq.clone().sqrt())
237
+
238
+ return [new Line(a, b, x1), new Line(a, b, x2)]
239
+ }
240
+
92
241
  private _reset(): Circle {
93
242
  this._center = null
94
243
  this._squareRadius = null
@@ -128,7 +277,7 @@ export class Circle {
128
277
  }
129
278
 
130
279
  // Calculate once the different values.
131
- if(this._exists) {
280
+ if (this._exists) {
132
281
  this._calculateCartesian()
133
282
 
134
283
  // If the square radius is zero or positive, the circle exists.
@@ -141,10 +290,7 @@ export class Circle {
141
290
  }
142
291
 
143
292
  private _calculateCartesian() {
144
- this._cartesian = (new Equation(
145
- new Polynom(`(x-(${this._center.x.display}))^2+(y-(${this._center.y.display}))^2`),
146
- new Polynom(`${this._squareRadius.display}`)
147
- )).moveLeft()
293
+ this._cartesian = (new Equation(new Polynom(`(x-(${this._center.x.display}))^2+(y-(${this._center.y.display}))^2`), new Polynom(`${this._squareRadius.display}`))).moveLeft()
148
294
  }
149
295
 
150
296
  private _parseCopyCircle(circle: Circle): Circle {
@@ -183,9 +329,7 @@ export class Circle {
183
329
 
184
330
  if (equ.degree('x').value === 2 && equ.degree('y').value === 2) {
185
331
  // Both must be of degree 2.
186
- let x2 = equ.left.monomByDegree(2, 'x'),
187
- y2 = equ.left.monomByDegree(2, 'y'),
188
- x1: Monom, y1: Monom, c: Monom
332
+ let x2 = equ.left.monomByDegree(2, 'x'), y2 = equ.left.monomByDegree(2, 'y'), x1: Monom, y1: Monom, c: Monom
189
333
 
190
334
  // Both square monoms must have the same coefficient.
191
335
  if (x2.coefficient.isEqual(y2.coefficient)) {
@@ -196,10 +340,7 @@ export class Circle {
196
340
 
197
341
  c = equ.left.monomByDegree(0)
198
342
 
199
- this._center = new Point(
200
- x1.coefficient.clone().divide(2).opposed(),
201
- y1.coefficient.clone().divide(2).opposed()
202
- )
343
+ this._center = new Point(x1.coefficient.clone().divide(2).opposed(), y1.coefficient.clone().divide(2).opposed())
203
344
 
204
345
  this._squareRadius = c.coefficient.clone().opposed()
205
346
  .add(this._center.x.clone().pow(2))
@@ -207,7 +348,7 @@ export class Circle {
207
348
 
208
349
  this._calculateCartesian()
209
350
  this._exists = true
210
- }else{
351
+ } else {
211
352
  // The circle is not a valid circle
212
353
  this._center = null
213
354
  this._squareRadius = null
@@ -218,57 +359,11 @@ export class Circle {
218
359
  }
219
360
 
220
361
  private _parseThroughtThreePoints(A: Point, B: Point, C: Point): Circle {
221
- let T = new Triangle(A, B, C),
222
- mAB = T.remarquables.mediators.AB.clone(),
362
+ let T = new Triangle(A, B, C), mAB = T.remarquables.mediators.AB.clone(),
223
363
  mAC = T.remarquables.mediators.AC.clone()
224
364
  this.parse(mAB.intersection(mAC).point, A)
225
365
 
226
366
  return this
227
367
  }
228
368
 
229
- /**
230
- * Get the relative position between circle and line. It corresponds to the number of intersection.
231
- * @param {Line} L
232
- * @returns {number}
233
- */
234
- relativePosition = (L: Line): number => {
235
- let distance = L.distanceTo(this.center),
236
- radius = Math.sqrt(this._squareRadius.value)
237
-
238
- if (distance.value - radius > 0.0000000001) {
239
- return 0 // external
240
- } else if (Math.abs(distance.value - radius) < 0.0000000001) {
241
- return 1 // tangent
242
- } else {
243
- return 2 // external
244
- }
245
- }
246
-
247
- lineIntersection = (L: Line): Point[] => {
248
- let intersectionPoints: Point[] = [], solX: Fraction
249
-
250
- if(this._cartesian===null){return []}
251
- const equX = this._cartesian.clone(),
252
- lineX = L.equation.clone().isolate('x'),
253
- lineY = L.equation.clone().isolate('y')
254
-
255
- if (lineX instanceof Equation && lineY instanceof Equation) {
256
- equX.replaceBy('y', lineY.right).simplify()
257
- equX.solve()
258
-
259
- for(let x of equX.solutions){
260
- if(x.exact===false && isNaN(x.value)){continue}
261
-
262
- solX = new Fraction(x.exact===false?x.value:x.exact)
263
- intersectionPoints.push(
264
- new Point(
265
- solX.clone(),
266
- lineY.right.evaluate(solX)
267
- )
268
- )
269
- }
270
- }
271
-
272
- return intersectionPoints
273
- }
274
369
  }