jsxgraph 1.4.2 → 1.4.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.
@@ -6,7 +6,7 @@
6
6
  } else {
7
7
  root.returnExports = factory();
8
8
  }
9
- }(this, function () {
9
+ }(typeof self !== 'undefined' ? self : this, function () {
10
10
  /**
11
11
  * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
12
12
  * Released under MIT license, http://github.com/requirejs/almond/LICENSE
@@ -842,7 +842,7 @@ define('base/constants',['jxg'], function (JXG) {
842
842
 
843
843
  var major = 1,
844
844
  minor = 4,
845
- patch = 2,
845
+ patch = 5,
846
846
  add = '', //'dev'
847
847
  version = major + '.' + minor + '.' + patch + (add ? '-' + add : ''),
848
848
  constants;
@@ -2026,7 +2026,7 @@ define('utils/type',[
2026
2026
  }
2027
2027
 
2028
2028
  // options from attributes
2029
- o = attributes;
2029
+ o = (typeof attributes === 'object') ? attributes : {};
2030
2030
  isAvail = true;
2031
2031
  for (i = 3; i < len; i++) {
2032
2032
  if (this.exists(o[arguments[i]])) {
@@ -2332,7 +2332,7 @@ define('utils/type',[
2332
2332
  return html_sanitize(str, function () { return undefined; }, function (id) { return id; });
2333
2333
  }
2334
2334
 
2335
- if (str) {
2335
+ if (str && typeof str === 'string') {
2336
2336
  str = str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
2337
2337
  }
2338
2338
 
@@ -3198,14 +3198,15 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) {
3198
3198
  * @param {String} inner_id id of the DOM element which is scaled and shifted
3199
3199
  * @param {Number} scale Scaling factor
3200
3200
  * @param {Number} vshift Vertical shift (in pixel)
3201
+ * @param {Object} doc document object or shadow root
3201
3202
  *
3202
3203
  * @private
3203
3204
  * @see JXG.Board#toFullscreen
3204
3205
  * @see JXG.Board#fullscreenListener
3205
3206
  *
3206
3207
  */
3207
- scaleJSXGraphDiv: function (wrap_id, inner_id, scale, vshift) {
3208
- var len = document.styleSheets.length, style,
3208
+ scaleJSXGraphDiv: function (wrap_id, inner_id, scale, vshift, doc) {
3209
+ var len = doc.styleSheets.length, style,
3209
3210
 
3210
3211
  pseudo_keys = [':fullscreen', ':-webkit-full-screen', ':-moz-full-screen', ':-ms-fullscreen'],
3211
3212
  len_pseudo = pseudo_keys.length, i,
@@ -3223,22 +3224,21 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) {
3223
3224
  // WebKit hack :(
3224
3225
  style.appendChild(document.createTextNode(''));
3225
3226
  // Add the <style> element to the page
3226
- document.body.appendChild(style);
3227
- len = document.styleSheets.length;
3227
+ doc.appendChild(style);
3228
+ len = doc.styleSheets.length;
3228
3229
  }
3229
3230
 
3230
3231
  // Remove a previously installed CSS rule.
3231
- if (document.styleSheets[len - 1].cssRules.length > 0 &&
3232
- regex.test(document.styleSheets[len - 1].cssRules[0].cssText) &&
3233
- document.styleSheets[len - 1].deleteRule) {
3234
-
3235
- document.styleSheets[len - 1].deleteRule(0);
3232
+ if (doc.styleSheets[len - 1].cssRules.length > 0 &&
3233
+ regex.test(doc.styleSheets[len - 1].cssRules[0].cssText) &&
3234
+ doc.styleSheets[len - 1].deleteRule) {
3235
+ doc.styleSheets[len - 1].deleteRule(0);
3236
3236
  }
3237
3237
 
3238
3238
  // Install a CSS rule to center the JSXGraph div at the first position of the list.
3239
3239
  for (i = 0; i < len_pseudo; i++) {
3240
3240
  try {
3241
- document.styleSheets[len - 1].insertRule('#' + wrap_id + pseudo_keys[i] + ' #' + inner_id + rule_inner, 0);
3241
+ doc.styleSheets[len - 1].insertRule('#' + wrap_id + pseudo_keys[i] + ' #' + inner_id + rule_inner, 0);
3242
3242
  break;
3243
3243
  } catch (err) {
3244
3244
  // console.log('JXG.scaleJSXGraphDiv: Could not add CSS rule "' + pseudo_keys[i] + '".');
@@ -3999,6 +3999,15 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) {
3999
3999
  return Math.sqrt(sum);
4000
4000
  },
4001
4001
 
4002
+ axpy: function (a, x, y) {
4003
+ var i, le = x.length,
4004
+ p = [];
4005
+ for (i = 0; i < le; i++) {
4006
+ p[i] = a * x[i] + y[i];
4007
+ }
4008
+ return p;
4009
+ },
4010
+
4002
4011
  /**
4003
4012
  * Compute the factorial of a positive integer. If a non-integer value
4004
4013
  * is given, the fraction will be ignored.
@@ -11749,43 +11758,43 @@ define('math/numerics',['jxg', 'utils/type', 'utils/env', 'math/math'], function
11749
11758
  */
11750
11759
  /*
11751
11760
  * jcobyla
11752
- *
11761
+ *
11753
11762
  * The MIT License
11754
11763
  *
11755
11764
  * Copyright (c) 2012 Anders Gustafsson, Cureos AB.
11756
11765
  *
11757
11766
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
11758
- * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
11759
- * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
11767
+ * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
11768
+ * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
11760
11769
  * subject to the following conditions:
11761
11770
  *
11762
11771
  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11763
11772
  *
11764
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11765
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
11766
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11773
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11774
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
11775
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11767
11776
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11768
- *
11777
+ *
11769
11778
  * Remarks:
11770
- *
11779
+ *
11771
11780
  * The original Fortran 77 version of this code was by Michael Powell (M.J.D.Powell @ damtp.cam.ac.uk)
11772
11781
  * The Fortran 90 version was by Alan Miller (Alan.Miller @ vic.cmis.csiro.au). Latest revision - 30 October 1998
11773
11782
  */
11774
11783
 
11775
11784
  /**
11776
11785
  * Constrained Optimization BY Linear Approximation in Java.
11777
- *
11786
+ *
11778
11787
  * COBYLA2 is an implementation of Powell's nonlinear derivative free constrained optimization that uses
11779
11788
  * a linear approximation approach. The algorithm is a sequential trust region algorithm that employs linear
11780
11789
  * approximations to the objective and constraint functions, where the approximations are formed by linear
11781
11790
  * interpolation at n + 1 points in the space of the variables and tries to maintain a regular shaped simplex
11782
11791
  * over iterations.
11783
- *
11792
+ *
11784
11793
  * It solves nonsmooth NLP with a moderate number of variables (about 100). Inequality constraints only.
11785
- *
11794
+ *
11786
11795
  * The initial point X is taken as one vertex of the initial simplex with zero being another, so, X should
11787
11796
  * not be entered as the zero vector.
11788
- *
11797
+ *
11789
11798
  * @author Anders Gustafsson, Cureos AB. Translation to Javascript by Reinhard Oldenburg, Goethe-University
11790
11799
  */
11791
11800
 
@@ -11798,7 +11807,7 @@ define('math/numerics',['jxg', 'utils/type', 'utils/env', 'math/math'], function
11798
11807
  utils/type
11799
11808
  */
11800
11809
 
11801
- define('math/nlp',['jxg'], function (JXG) {
11810
+ define('math/nlp',['jxg', 'utils/type'], function (JXG, Type) {
11802
11811
 
11803
11812
  "use strict";
11804
11813
 
@@ -11806,20 +11815,29 @@ define('math/nlp',['jxg'], function (JXG) {
11806
11815
  * The JXG.Math.Nlp namespace holds numerical algorithms for non-linear optimization.
11807
11816
  * @name JXG.Math.Nlp
11808
11817
  * @namespace
11809
- *
11818
+ *
11810
11819
  */
11811
- JXG.Math.Nlp = {
11820
+ JXG.Math.Nlp = {
11812
11821
 
11813
- arr: function(n) {
11814
- var a = new Array(n),
11815
- i;
11816
- for (i = 0; i <n ; i++) {
11817
- a[i] = 0.0;
11818
- }
11819
- return a;
11822
+ arr: function (n) {
11823
+ // Is 0 initialized
11824
+ return new Float64Array(n);
11825
+
11826
+ // var a = new Array(n),
11827
+ // i;
11828
+
11829
+ // if (Type.exists(a.fill)) {
11830
+ // a.fill(0.0, 0, n);
11831
+ // } else {
11832
+ // for (i = 0; i < n; i++) {
11833
+ // a[i] = 0.0;
11834
+ // }
11835
+ // }
11836
+
11837
+ // return a;
11820
11838
  },
11821
11839
 
11822
- arr2: function(n, m) {
11840
+ arr2: function (n, m) {
11823
11841
  var i = 0,
11824
11842
  a = new Array(n);
11825
11843
 
@@ -11830,7 +11848,7 @@ define('math/nlp',['jxg'], function (JXG) {
11830
11848
  return a;
11831
11849
  },
11832
11850
 
11833
- arraycopy: function(x, a, iox, b, n) {
11851
+ arraycopy: function (x, a, iox, b, n) {
11834
11852
  var i = 0;
11835
11853
  while (i < n) {
11836
11854
  iox[i + b] = x[i + a];
@@ -11860,7 +11878,7 @@ define('math/nlp',['jxg'], function (JXG) {
11860
11878
  * @param maxfun Maximum number of function evaluations before terminating.
11861
11879
  * @returns {Number} Exit status of the COBYLA2 optimization.
11862
11880
  */
11863
- FindMinimum: function(calcfc, n, m, x, rhobeg, rhoend, iprint, maxfun) {
11881
+ FindMinimum: function (calcfc, n, m, x, rhobeg, rhoend, iprint, maxfun) {
11864
11882
  // CobylaExitStatus FindMinimum(final Calcfc calcfc, int n, int m, double[] x, double rhobeg, double rhoend, int iprint, int maxfun)
11865
11883
  // This subroutine minimizes an objective function F(X) subject to M
11866
11884
  // inequality constraints on X, where X is a vector of variables that has
@@ -11924,16 +11942,16 @@ define('math/nlp',['jxg'], function (JXG) {
11924
11942
 
11925
11943
  // Internal representation of the objective and constraints calculation method,
11926
11944
  // accounting for that X and CON arrays in the cobylb method are base-1 arrays.
11927
- fcalcfc = function(n, m, thisx, con) { // int n, int m, double[] x, double[] con
11928
- var ix = that.arr(n),
11929
- ocon, f;
11930
-
11931
- that.arraycopy(thisx, 1, ix, 0, n);
11932
- ocon = that.arr(m);
11933
- f = calcfc(n, m, ix, ocon);
11934
- that.arraycopy(ocon, 0, con, 1, m);
11935
- return f;
11936
- };
11945
+ fcalcfc = function (n, m, thisx, con) { // int n, int m, double[] x, double[] con
11946
+ var ix = that.arr(n),
11947
+ ocon, f;
11948
+
11949
+ that.arraycopy(thisx, 1, ix, 0, n);
11950
+ ocon = that.arr(m);
11951
+ f = calcfc(n, m, ix, ocon);
11952
+ that.arraycopy(ocon, 0, con, 1, m);
11953
+ return f;
11954
+ };
11937
11955
 
11938
11956
  status = this.cobylb(fcalcfc, n, m, mpp, iox, rhobeg, rhoend, iprint, maxfun);
11939
11957
  this.arraycopy(iox, 1, x, 0, n);
@@ -11945,18 +11963,18 @@ define('math/nlp',['jxg'], function (JXG) {
11945
11963
  // double rhobeg, double rhoend, int iprint, int maxfun)
11946
11964
  /**
11947
11965
  * JavaScript implementation of the non-linear optimization method COBYLA.
11948
- * @param {Function} calcfc
11949
- * @param {Number} n
11950
- * @param {Number} m
11951
- * @param {Number} mpp
11952
- * @param {Number} x
11953
- * @param {Number} rhobeg
11954
- * @param {Number} rhoend
11955
- * @param {Number} iprint
11956
- * @param {Number} maxfun
11966
+ * @param {Function} calcfc
11967
+ * @param {Number} n
11968
+ * @param {Number} m
11969
+ * @param {Number} mpp
11970
+ * @param {Number} x
11971
+ * @param {Number} rhobeg
11972
+ * @param {Number} rhoend
11973
+ * @param {Number} iprint
11974
+ * @param {Number} maxfun
11957
11975
  * @returns {Number} Exit status of the COBYLA2 optimization
11958
11976
  */
11959
- cobylb: function (calcfc, n, m, mpp, x, rhobeg, rhoend, iprint, maxfun) {
11977
+ cobylb: function (calcfc, n, m, mpp, x, rhobeg, rhoend, iprint, maxfun) {
11960
11978
  // calcf ist funktion die aufgerufen wird wie calcfc(n, m, ix, ocon)
11961
11979
  // N.B. Arguments CON, SIM, SIMI, DATMAT, A, VSIG, VETA, SIGBAR, DX, W & IACT
11962
11980
  // have been removed.
@@ -12132,8 +12150,7 @@ define('math/nlp',['jxg'], function (JXG) {
12132
12150
  sim[i][np] += temp;
12133
12151
 
12134
12152
  tempa = 0.0;
12135
- for (k = 1; k <= n; ++k)
12136
- {
12153
+ for (k = 1; k <= n; ++k) {
12137
12154
  sim[i][k] -= temp;
12138
12155
  tempa -= simi[k][i];
12139
12156
  }
@@ -12144,13 +12161,17 @@ define('math/nlp',['jxg'], function (JXG) {
12144
12161
  // Make an error return if SIGI is a poor approximation to the inverse of
12145
12162
  // the leading N by N submatrix of SIG.
12146
12163
  error = 0.0;
12147
- for (i = 1; i <= n; ++i) {
12148
- for (j = 1; j <= n; ++j) {
12149
- temp = this.DOT_PRODUCT(
12150
- this.PART(this.ROW(simi, i), 1, n),
12151
- this.PART(this.COL(sim, j), 1, n)
12152
- ) - (i === j ? 1.0 : 0.0);
12153
- error = Math.max(error, Math.abs(temp));
12164
+ if (false) {
12165
+ for (i = 1; i <= n; ++i) {
12166
+ for (j = 1; j <= n; ++j) {
12167
+ temp = this.DOT_PRODUCT_ROW_COL(simi, i, sim, j, 1, n) - (i === j ? 1.0 : 0.0);
12168
+ // temp = this.DOT_PRODUCT(
12169
+ // this.PART(this.ROW(simi, i), 1, n),
12170
+ // this.PART(this.COL(sim, j), 1, n)
12171
+ // ) - (i === j ? 1.0 : 0.0);
12172
+
12173
+ error = Math.max(error, Math.abs(temp));
12174
+ }
12154
12175
  }
12155
12176
  }
12156
12177
  if (error > 0.1) {
@@ -12169,8 +12190,9 @@ define('math/nlp',['jxg'], function (JXG) {
12169
12190
  }
12170
12191
 
12171
12192
  for (i = 1; i <= n; ++i) {
12172
- a[i][k] = (k === mp ? -1.0 : 1.0) * this.DOT_PRODUCT(
12173
- this.PART(w, 1, n), this.PART(this.COL(simi, i), 1, n));
12193
+ a[i][k] = (k === mp ? -1.0 : 1.0) *
12194
+ this.DOT_PRODUCT_ROW_COL(w, -1, simi, i, 1, n);
12195
+ // this.DOT_PRODUCT(this.PART(w, 1, n), this.PART(this.COL(simi, i), 1, n));
12174
12196
  }
12175
12197
  }
12176
12198
 
@@ -12182,11 +12204,9 @@ define('math/nlp',['jxg'], function (JXG) {
12182
12204
 
12183
12205
  for (j = 1; j <= n; ++j) {
12184
12206
  wsig = 0.0;
12185
- for (k = 1; k <= n; ++k) {
12186
- wsig += simi[j][k] * simi[j][k];
12187
- }
12188
12207
  weta = 0.0;
12189
12208
  for (k = 1; k <= n; ++k) {
12209
+ wsig += simi[j][k] * simi[j][k];
12190
12210
  weta += sim[k][j] * sim[k][j];
12191
12211
  }
12192
12212
  vsig[j] = 1.0 / Math.sqrt(wsig);
@@ -12223,10 +12243,8 @@ define('math/nlp',['jxg'], function (JXG) {
12223
12243
  cvmaxm = 0.0;
12224
12244
  total = 0.0;
12225
12245
  for (k = 1; k <= mp; ++k) {
12226
- total = this.DOT_PRODUCT(
12227
- this.PART(this.COL(a, k), 1, n),
12228
- this.PART(dx, 1, n)
12229
- );
12246
+ // total = this.DOT_PRODUCT(this.PART(this.COL(a, k), 1, n), this.PART(dx, 1, n));
12247
+ total = this.DOT_PRODUCT_ROW_COL(dx, -1, a, k, 1, n);
12230
12248
  if (k < mp) {
12231
12249
  temp = datmat[k][np];
12232
12250
  cvmaxp = Math.max(cvmaxp, -total - temp);
@@ -12248,10 +12266,8 @@ define('math/nlp',['jxg'], function (JXG) {
12248
12266
 
12249
12267
  for (j = 1; j <= n; ++j) {
12250
12268
  if (j !== jdrop) {
12251
- temp = this.DOT_PRODUCT(
12252
- this.PART(this.ROW(simi, j), 1, n),
12253
- this.PART(dx, 1, n)
12254
- );
12269
+ // temp = this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n));
12270
+ temp = this.DOT_PRODUCT_ROW_COL(simi, j, dx, -1, 1, n);
12255
12271
  for (k = 1; k <= n; ++k) {
12256
12272
  simi[j][k] -= temp * simi[jdrop][k];
12257
12273
  }
@@ -12281,7 +12297,8 @@ define('math/nlp',['jxg'], function (JXG) {
12281
12297
  resnew = 0.0;
12282
12298
  con[mp] = 0.0;
12283
12299
  for (k = 1; k <= mp; ++k) {
12284
- total = con[k] - this.DOT_PRODUCT(this.PART(this.COL(a, k), 1, n), this.PART(dx, 1, n));
12300
+ //total = con[k] - this.DOT_PRODUCT(this.PART(this.COL(a, k), 1, n), this.PART(dx, 1, n));
12301
+ total = con[k] - this.DOT_PRODUCT_ROW_COL(dx, -1, a, k, 1, n);
12285
12302
  if (k < mp) { resnew = Math.max(resnew, total); }
12286
12303
  }
12287
12304
 
@@ -12329,7 +12346,8 @@ define('math/nlp',['jxg'], function (JXG) {
12329
12346
  ratio = trured <= 0.0 ? 1.0 : 0.0;
12330
12347
  jdrop = 0;
12331
12348
  for (j = 1; j <= n; ++j) {
12332
- temp = Math.abs(this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n)));
12349
+ // temp = Math.abs(this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n)));
12350
+ temp = Math.abs(this.DOT_PRODUCT_ROW_COL(simi, j, dx, -1, 1, n));
12333
12351
  if (temp > ratio) {
12334
12352
  jdrop = j;
12335
12353
  ratio = temp;
@@ -12369,7 +12387,8 @@ define('math/nlp',['jxg'], function (JXG) {
12369
12387
  for (k = 1; k <= n; ++k) { simi[jdrop][k] /= temp; }
12370
12388
  for (j = 1; j <= n; ++j) {
12371
12389
  if (j !== jdrop) {
12372
- temp = this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n));
12390
+ // temp = this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n));
12391
+ temp = this.DOT_PRODUCT_ROW_COL(simi, j, dx, -1, 1, n);
12373
12392
  for (k = 1; k <= n; ++k) {
12374
12393
  simi[j][k] -= temp * simi[jdrop][k];
12375
12394
  }
@@ -12422,7 +12441,7 @@ define('math/nlp',['jxg'], function (JXG) {
12422
12441
  }
12423
12442
  }
12424
12443
  if (iprint >= 2) {
12425
- console.log("Reduction in RHO to "+rho+" and PARMU = "+parmu);
12444
+ console.log("Reduction in RHO to " + rho + " and PARMU = " + parmu);
12426
12445
  }
12427
12446
  if (iprint === 2) {
12428
12447
  this.PrintIterationResult(nfvals, datmat[mp][np], datmat[mpp][np], this.COL(sim, np), n, iprint);
@@ -12458,7 +12477,7 @@ define('math/nlp',['jxg'], function (JXG) {
12458
12477
  return status;
12459
12478
  },
12460
12479
 
12461
- trstlp: function(n, m, a, b, rho, dx) { //(int n, int m, double[][] a, double[] b, double rho, double[] dx)
12480
+ trstlp: function (n, m, a, b, rho, dx) { //(int n, int m, double[][] a, double[] b, double rho, double[] dx)
12462
12481
  // N.B. Arguments Z, ZDOTA, VMULTC, SDIRN, DXNEW, VMULTD & IACT have been removed.
12463
12482
 
12464
12483
  // This subroutine calculates an N-component vector DX by applying the
@@ -12572,9 +12591,8 @@ define('math/nlp',['jxg'], function (JXG) {
12572
12591
 
12573
12592
  L_70:
12574
12593
  do {
12575
- optnew = (mcon === m) ? resmax : -this.DOT_PRODUCT(
12576
- this.PART(dx, 1, n), this.PART(this.COL(a, mcon), 1, n)
12577
- );
12594
+ // optnew = (mcon === m) ? resmax : -this.DOT_PRODUCT(this.PART(dx, 1, n), this.PART(this.COL(a, mcon), 1, n));
12595
+ optnew = (mcon === m) ? resmax : -this.DOT_PRODUCT_ROW_COL(dx, -1, a, mcon, 1, n);
12578
12596
 
12579
12597
  if (icount === 0 || optnew < optold) {
12580
12598
  optold = optnew;
@@ -12605,9 +12623,9 @@ define('math/nlp',['jxg'], function (JXG) {
12605
12623
  kp = k + 1;
12606
12624
  kk = iact[kp];
12607
12625
  sp = this.DOT_PRODUCT(
12608
- this.PART(this.COL(z, k), 1, n),
12609
- this.PART(this.COL(a, kk), 1, n)
12610
- );
12626
+ this.PART(this.COL(z, k), 1, n),
12627
+ this.PART(this.COL(a, kk), 1, n)
12628
+ );
12611
12629
  temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]);
12612
12630
  alpha = zdota[kp] / temp;
12613
12631
  beta = sp / temp;
@@ -12635,9 +12653,8 @@ define('math/nlp',['jxg'], function (JXG) {
12635
12653
  temp = 1.0 / zdota[nact];
12636
12654
  for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; }
12637
12655
  } else {
12638
- temp = this.DOT_PRODUCT(
12639
- this.PART(sdirn, 1, n), this.PART(this.COL(z, nact + 1), 1, n)
12640
- );
12656
+ // temp = this.DOT_PRODUCT(this.PART(sdirn, 1, n), this.PART(this.COL(z, nact + 1), 1, n));
12657
+ temp = this.DOT_PRODUCT_ROW_COL(sdirn, -1, z, nact + 1, 1, n);
12641
12658
  for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact + 1]; }
12642
12659
  }
12643
12660
  } else {
@@ -12646,34 +12663,34 @@ define('math/nlp',['jxg'], function (JXG) {
12646
12663
  tot = 0.0;
12647
12664
 
12648
12665
  // {
12649
- k = n;
12650
- while (k > nact) {
12651
- sp = 0.0;
12652
- spabs = 0.0;
12666
+ k = n;
12667
+ while (k > nact) {
12668
+ sp = 0.0;
12669
+ spabs = 0.0;
12670
+ for (i = 1; i <= n; ++i) {
12671
+ temp = z[i][k] * dxnew[i];
12672
+ sp += temp;
12673
+ spabs += Math.abs(temp);
12674
+ }
12675
+ acca = spabs + 0.1 * Math.abs(sp);
12676
+ accb = spabs + 0.2 * Math.abs(sp);
12677
+ if (spabs >= acca || acca >= accb) { sp = 0.0; }
12678
+ if (tot === 0.0) {
12679
+ tot = sp;
12680
+ } else {
12681
+ kp = k + 1;
12682
+ temp = Math.sqrt(sp * sp + tot * tot);
12683
+ alpha = sp / temp;
12684
+ beta = tot / temp;
12685
+ tot = temp;
12653
12686
  for (i = 1; i <= n; ++i) {
12654
- temp = z[i][k] * dxnew[i];
12655
- sp += temp;
12656
- spabs += Math.abs(temp);
12657
- }
12658
- acca = spabs + 0.1 * Math.abs(sp);
12659
- accb = spabs + 0.2 * Math.abs(sp);
12660
- if (spabs >= acca || acca >= accb) { sp = 0.0; }
12661
- if (tot === 0.0) {
12662
- tot = sp;
12663
- } else {
12664
- kp = k + 1;
12665
- temp = Math.sqrt(sp * sp + tot * tot);
12666
- alpha = sp / temp;
12667
- beta = tot / temp;
12668
- tot = temp;
12669
- for (i = 1; i <= n; ++i) {
12670
- temp = alpha * z[i][k] + beta * z[i][kp];
12671
- z[i][kp] = alpha * z[i][kp] - beta * z[i][k];
12672
- z[i][k] = temp;
12673
- }
12687
+ temp = alpha * z[i][k] + beta * z[i][kp];
12688
+ z[i][kp] = alpha * z[i][kp] - beta * z[i][k];
12689
+ z[i][k] = temp;
12674
12690
  }
12675
- --k;
12676
12691
  }
12692
+ --k;
12693
+ }
12677
12694
  // }
12678
12695
 
12679
12696
  if (tot === 0.0) {
@@ -12686,34 +12703,34 @@ define('math/nlp',['jxg'], function (JXG) {
12686
12703
 
12687
12704
  ratio = -1.0;
12688
12705
  //{
12689
- k = nact;
12690
- do {
12691
- zdotv = 0.0;
12692
- zdvabs = 0.0;
12706
+ k = nact;
12707
+ do {
12708
+ zdotv = 0.0;
12709
+ zdvabs = 0.0;
12693
12710
 
12694
- for (i = 1; i <= n; ++i) {
12695
- temp = z[i][k] * dxnew[i];
12696
- zdotv += temp;
12697
- zdvabs += Math.abs(temp);
12711
+ for (i = 1; i <= n; ++i) {
12712
+ temp = z[i][k] * dxnew[i];
12713
+ zdotv += temp;
12714
+ zdvabs += Math.abs(temp);
12715
+ }
12716
+ acca = zdvabs + 0.1 * Math.abs(zdotv);
12717
+ accb = zdvabs + 0.2 * Math.abs(zdotv);
12718
+ if (zdvabs < acca && acca < accb) {
12719
+ temp = zdotv / zdota[k];
12720
+ if (temp > 0.0 && iact[k] <= m) {
12721
+ tempa = vmultc[k] / temp;
12722
+ if (ratio < 0.0 || tempa < ratio) { ratio = tempa; }
12698
12723
  }
12699
- acca = zdvabs + 0.1 * Math.abs(zdotv);
12700
- accb = zdvabs + 0.2 * Math.abs(zdotv);
12701
- if (zdvabs < acca && acca < accb) {
12702
- temp = zdotv / zdota[k];
12703
- if (temp > 0.0 && iact[k] <= m) {
12704
- tempa = vmultc[k] / temp;
12705
- if (ratio < 0.0 || tempa < ratio) { ratio = tempa; }
12706
- }
12707
-
12708
- if (k >= 2) {
12709
- kw = iact[k];
12710
- for (i = 1; i <= n; ++i) { dxnew[i] -= temp * a[i][kw]; }
12711
- }
12712
- vmultd[k] = temp;
12713
- } else {
12714
- vmultd[k] = 0.0;
12724
+
12725
+ if (k >= 2) {
12726
+ kw = iact[k];
12727
+ for (i = 1; i <= n; ++i) { dxnew[i] -= temp * a[i][kw]; }
12715
12728
  }
12716
- } while (--k > 0);
12729
+ vmultd[k] = temp;
12730
+ } else {
12731
+ vmultd[k] = 0.0;
12732
+ }
12733
+ } while (--k > 0);
12717
12734
  //}
12718
12735
  if (ratio < 0.0) { break L_60; }
12719
12736
 
@@ -12732,9 +12749,9 @@ define('math/nlp',['jxg'], function (JXG) {
12732
12749
  kp = k + 1;
12733
12750
  kw = iact[kp];
12734
12751
  sp = this.DOT_PRODUCT(
12735
- this.PART(this.COL(z, k), 1, n),
12736
- this.PART(this.COL(a, kw), 1, n)
12737
- );
12752
+ this.PART(this.COL(z, k), 1, n),
12753
+ this.PART(this.COL(a, kw), 1, n)
12754
+ );
12738
12755
  temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]);
12739
12756
  alpha = zdota[kp] / temp;
12740
12757
  beta = sp / temp;
@@ -12753,9 +12770,9 @@ define('math/nlp',['jxg'], function (JXG) {
12753
12770
  vmultc[k] = vsave;
12754
12771
  }
12755
12772
  temp = this.DOT_PRODUCT(
12756
- this.PART(this.COL(z, nact), 1, n),
12757
- this.PART(this.COL(a, kk), 1, n)
12758
- );
12773
+ this.PART(this.COL(z, nact), 1, n),
12774
+ this.PART(this.COL(a, kk), 1, n)
12775
+ );
12759
12776
  if (temp === 0.0) { break L_60; }
12760
12777
  zdota[nact] = temp;
12761
12778
  vmultc[icon] = 0.0;
@@ -12778,9 +12795,9 @@ define('math/nlp',['jxg'], function (JXG) {
12778
12795
  if (mcon > m && kk !== mcon) {
12779
12796
  k = nact - 1;
12780
12797
  sp = this.DOT_PRODUCT(
12781
- this.PART(this.COL(z, k), 1, n),
12782
- this.PART(this.COL(a, kk), 1, n)
12783
- );
12798
+ this.PART(this.COL(z, k), 1, n),
12799
+ this.PART(this.COL(a, kk), 1, n)
12800
+ );
12784
12801
  temp = Math.sqrt(sp * sp + zdota[nact] * zdota[nact]);
12785
12802
  alpha = zdota[nact] / temp;
12786
12803
  beta = sp / temp;
@@ -12806,10 +12823,8 @@ define('math/nlp',['jxg'], function (JXG) {
12806
12823
  for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; }
12807
12824
  } else {
12808
12825
  kk = iact[nact];
12809
- temp = (this.DOT_PRODUCT(
12810
- this.PART(sdirn, 1, n),
12811
- this.PART(this.COL(a, kk), 1, n)
12812
- ) - 1.0) / zdota[nact];
12826
+ // temp = (this.DOT_PRODUCT(this.PART(sdirn, 1, n),this.PART(this.COL(a, kk), 1, n)) - 1.0) / zdota[nact];
12827
+ temp = (this.DOT_PRODUCT_ROW_COL(sdirn, -1, a, kk, 1, n) - 1.0) / zdota[nact];
12813
12828
  for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact]; }
12814
12829
  }
12815
12830
  }
@@ -12849,9 +12864,8 @@ define('math/nlp',['jxg'], function (JXG) {
12849
12864
  resmax = 0.0;
12850
12865
  for (k = 1; k <= nact; ++k) {
12851
12866
  kk = iact[k];
12852
- temp = b[kk] - this.DOT_PRODUCT(
12853
- this.PART(this.COL(a, kk), 1, n), this.PART(dxnew, 1, n)
12854
- );
12867
+ // temp = b[kk] - this.DOT_PRODUCT(this.PART(this.COL(a, kk), 1, n), this.PART(dxnew, 1, n));
12868
+ temp = b[kk] - this.DOT_PRODUCT_ROW_COL(dxnew, -1, a, kk, 1, n);
12855
12869
  resmax = Math.max(resmax, temp);
12856
12870
  }
12857
12871
  }
@@ -12861,25 +12875,25 @@ define('math/nlp',['jxg'], function (JXG) {
12861
12875
  // can be attributed to computer rounding errors. First calculate the new
12862
12876
  // Lagrange multipliers.
12863
12877
  //{
12864
- k = nact;
12865
- do {
12866
- zdotw = 0.0;
12867
- zdwabs = 0.0;
12868
- for (i = 1; i <= n; ++i) {
12869
- temp = z[i][k] * dxnew[i];
12870
- zdotw += temp;
12871
- zdwabs += Math.abs(temp);
12872
- }
12873
- acca = zdwabs + 0.1 * Math.abs(zdotw);
12874
- accb = zdwabs + 0.2 * Math.abs(zdotw);
12875
- if (zdwabs >= acca || acca >= accb) { zdotw = 0.0; }
12876
- vmultd[k] = zdotw / zdota[k];
12877
- if (k >= 2) {
12878
- kk = iact[k];
12879
- for (i = 1; i <= n; ++i) { dxnew[i] -= vmultd[k] * a[i][kk]; }
12880
- }
12881
- } while (k-- >= 2);
12882
- if (mcon > m) { vmultd[nact] = Math.max(0.0, vmultd[nact]); }
12878
+ k = nact;
12879
+ do {
12880
+ zdotw = 0.0;
12881
+ zdwabs = 0.0;
12882
+ for (i = 1; i <= n; ++i) {
12883
+ temp = z[i][k] * dxnew[i];
12884
+ zdotw += temp;
12885
+ zdwabs += Math.abs(temp);
12886
+ }
12887
+ acca = zdwabs + 0.1 * Math.abs(zdotw);
12888
+ accb = zdwabs + 0.2 * Math.abs(zdotw);
12889
+ if (zdwabs >= acca || acca >= accb) { zdotw = 0.0; }
12890
+ vmultd[k] = zdotw / zdota[k];
12891
+ if (k >= 2) {
12892
+ kk = iact[k];
12893
+ for (i = 1; i <= n; ++i) { dxnew[i] -= vmultd[k] * a[i][kk]; }
12894
+ }
12895
+ } while (k-- >= 2);
12896
+ if (mcon > m) { vmultd[nact] = Math.max(0.0, vmultd[nact]); }
12883
12897
  //}
12884
12898
 
12885
12899
  // Complete VMULTC by finding the new constraint residuals.
@@ -12944,12 +12958,12 @@ define('math/nlp',['jxg'], function (JXG) {
12944
12958
  return false;
12945
12959
  },
12946
12960
 
12947
- PrintIterationResult: function(nfvals, f, resmax, x, n, iprint) {
12948
- if (iprint > 1) { console.log("NFVALS = "+nfvals+" F = "+f+" MAXCV = "+resmax); }
12961
+ PrintIterationResult: function (nfvals, f, resmax, x, n, iprint) {
12962
+ if (iprint > 1) { console.log("NFVALS = " + nfvals + " F = " + f + " MAXCV = " + resmax); }
12949
12963
  if (iprint > 1) { console.log("X = " + this.PART(x, 1, n)); }
12950
12964
  },
12951
12965
 
12952
- ROW: function(src, rowidx) {
12966
+ ROW: function (src, rowidx) {
12953
12967
  return src[rowidx].slice();
12954
12968
  // var col,
12955
12969
  // cols = src[0].length,
@@ -12961,17 +12975,18 @@ define('math/nlp',['jxg'], function (JXG) {
12961
12975
  // return dest;
12962
12976
  },
12963
12977
 
12964
- COL: function(src, colidx) {
12978
+ COL: function (src, colidx) {
12965
12979
  var row,
12966
12980
  rows = src.length,
12967
- dest = this.arr(rows);
12981
+ dest = []; // this.arr(rows);
12982
+
12968
12983
  for (row = 0; row < rows; ++row) {
12969
12984
  dest[row] = src[row][colidx];
12970
12985
  }
12971
12986
  return dest;
12972
12987
  },
12973
12988
 
12974
- PART: function(src, from, to) {
12989
+ PART: function (src, from, to) {
12975
12990
  return src.slice(from, to + 1);
12976
12991
  // var srcidx,
12977
12992
  // dest = this.arr(to - from + 1),
@@ -12982,7 +12997,7 @@ define('math/nlp',['jxg'], function (JXG) {
12982
12997
  // return dest;
12983
12998
  },
12984
12999
 
12985
- FORMAT: function(x) {
13000
+ FORMAT: function (x) {
12986
13001
  return x.join(',');
12987
13002
  // var i, fmt = "";
12988
13003
  // for (i = 0; i < x.length; ++i) {
@@ -12991,12 +13006,38 @@ define('math/nlp',['jxg'], function (JXG) {
12991
13006
  // return fmt;
12992
13007
  },
12993
13008
 
12994
- DOT_PRODUCT: function(lhs, rhs) {
13009
+ DOT_PRODUCT: function (lhs, rhs) {
12995
13010
  var i, sum = 0.0,
12996
13011
  len = lhs.length;
12997
13012
  for (i = 0; i < len; ++i) {
12998
13013
  sum += lhs[i] * rhs[i];
12999
13014
  }
13015
+ return sum;
13016
+ },
13017
+
13018
+ DOT_PRODUCT_ROW_COL: function (lhs, row, rhs, col, start, end) {
13019
+ var i, sum = 0.0;
13020
+
13021
+ if (row === -1) {
13022
+ // lhs is vector
13023
+ for (i = start; i <= end; ++i) {
13024
+ sum += lhs[i] * rhs[i][col];
13025
+ }
13026
+ } else {
13027
+ // lhs is row of matrix
13028
+ if (col === -1) {
13029
+ // rhs is vector
13030
+ for (i = start; i <= end; ++i) {
13031
+ sum += lhs[row][i] * rhs[i];
13032
+ }
13033
+ } else {
13034
+ // rhs is column of matrix
13035
+ for (i = start; i <= end; ++i) {
13036
+ sum += lhs[row][i] * rhs[i][col];
13037
+ }
13038
+ }
13039
+ }
13040
+
13000
13041
  return sum;
13001
13042
  }
13002
13043
 
@@ -14728,6 +14769,30 @@ define('math/geometry',[
14728
14769
  return that.meetCurveLine(el1, el2, i, el1.board, alwaysintersect);
14729
14770
  };
14730
14771
 
14772
+ } else if (el1.type === Const.OBJECT_TYPE_POLYGON || el2.type === Const.OBJECT_TYPE_POLYGON) {
14773
+ // polygon - other
14774
+ // Uses the Greiner-Hormann clipping algorithm
14775
+ // Not implemented: polygon - point
14776
+
14777
+ if (el1.elementClass === Const.OBJECT_CLASS_LINE) {
14778
+ // line - path
14779
+ /** @ignore */
14780
+ func = function () {
14781
+ return that.meetPolygonLine(el2, el1, i, el1.board, alwaysintersect);
14782
+ };
14783
+ } else if (el2.elementClass === Const.OBJECT_CLASS_LINE) {
14784
+ // path - line
14785
+ func = function () {
14786
+ return that.meetPolygonLine(el1, el2, i, el1.board, alwaysintersect);
14787
+ };
14788
+ } else {
14789
+ // path - path
14790
+ /** @ignore */
14791
+ func = function () {
14792
+ return that.meetPathPath(el1, el2, i, el1.board);
14793
+ };
14794
+ }
14795
+
14731
14796
  } else if (el1.elementClass === Const.OBJECT_CLASS_LINE && el2.elementClass === Const.OBJECT_CLASS_LINE) {
14732
14797
  // line - line, lines may also be segments.
14733
14798
  /** @ignore */
@@ -15143,6 +15208,8 @@ define('math/geometry',[
15143
15208
  * @param {JXG.Line} li Line
15144
15209
  * @param {Number} nr Will return the nr-th intersection point.
15145
15210
  * @param {JXG.Board} board
15211
+ * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the
15212
+ * line defined by the segment
15146
15213
  * @returns {JXG.Coords} Coords object containing the intersection.
15147
15214
  */
15148
15215
  meetCurveLineContinuous: function (cu, li, nr, board, testSegment) {
@@ -15207,7 +15274,6 @@ define('math/geometry',[
15207
15274
  return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
15208
15275
  },
15209
15276
 
15210
-
15211
15277
  /**
15212
15278
  * Intersection of line and curve, discrete case.
15213
15279
  * Segments are treated as lines.
@@ -15394,6 +15460,87 @@ define('math/geometry',[
15394
15460
  return [c, t, u];
15395
15461
  },
15396
15462
 
15463
+ /**
15464
+ * Find the n-th intersection point of two pathes, usually given by polygons. Uses parts of the
15465
+ * Greiner-Hormann algorithm in JXG.Math.Clip.
15466
+ *
15467
+ * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path1
15468
+ * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path2
15469
+ * @param {Number} n
15470
+ * @param {JXG.Board} board
15471
+ *
15472
+ * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
15473
+ * the ideal point [0,0,0] is returned.
15474
+ *
15475
+ */
15476
+ meetPathPath: function(path1, path2, nr, board) {
15477
+ var S, C, len, intersections;
15478
+
15479
+ S = JXG.Math.Clip._getPath(path1, board);
15480
+ len = S.length;
15481
+ if (len > 0 && this.distance(S[0].coords.usrCoords, S[len - 1].coords.usrCoords, 3) < Mat.eps) {
15482
+ S.pop();
15483
+ }
15484
+
15485
+ C = JXG.Math.Clip._getPath(path2, board);
15486
+ len = C.length;
15487
+ if (len > 0 && this.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) {
15488
+ C.pop();
15489
+ }
15490
+
15491
+ // Handle cases where at least one of the paths is empty
15492
+ if (nr < 0 || JXG.Math.Clip.isEmptyCase(S, C, 'intersection')) {
15493
+ return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board));
15494
+ }
15495
+
15496
+ JXG.Math.Clip.makeDoublyLinkedList(S);
15497
+ JXG.Math.Clip.makeDoublyLinkedList(C);
15498
+
15499
+ intersections = JXG.Math.Clip.findIntersections(S, C, board)[0];
15500
+ if (nr < intersections.length) {
15501
+ return intersections[nr].coords;
15502
+ }
15503
+ return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board));
15504
+ },
15505
+
15506
+ /**
15507
+ * Find the n-th intersection point between a polygon and a line.
15508
+ * @param {JXG.Polygon} path
15509
+ * @param {JXG.Line} line
15510
+ * @param {Number} nr
15511
+ * @param {JXG.Board} board
15512
+ * @param {Boolean} alwaysIntersect If false just the segment between the two defining points of the line are tested for intersection.
15513
+ *
15514
+ * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
15515
+ * the ideal point [0,0,0] is returned.
15516
+ */
15517
+ meetPolygonLine: function(path, line, nr, board, alwaysIntersect) {
15518
+ var i, res, border,
15519
+ crds = [0,0,0],
15520
+ len = path.borders.length,
15521
+ intersections = [];
15522
+
15523
+ for (i = 0; i < len; i++) {
15524
+ border = path.borders[i];
15525
+ res = this.meetSegmentSegment(
15526
+ border.point1.coords.usrCoords,
15527
+ border.point2.coords.usrCoords,
15528
+ line.point1.coords.usrCoords,
15529
+ line.point2.coords.usrCoords);
15530
+
15531
+ if (
15532
+ (!alwaysIntersect || (res[2] >= 0 && res[2] < 1)) &&
15533
+ res[1] >= 0 && res[1] < 1) {
15534
+ intersections.push(res[0]);
15535
+ }
15536
+ }
15537
+
15538
+ if (nr >= 0 && nr < intersections.length) {
15539
+ crds = intersections[nr];
15540
+ }
15541
+ return (new Coords(Const.COORDS_BY_USER, crds, board));
15542
+ },
15543
+
15397
15544
  /****************************************/
15398
15545
  /**** BEZIER CURVE ALGORITHMS ****/
15399
15546
  /****************************************/
@@ -16334,7 +16481,86 @@ define('math/geometry',[
16334
16481
  };
16335
16482
 
16336
16483
  return [makeFct('X', 'cos'), makeFct('Y', 'sin'), 0, pi2];
16337
- }
16484
+ },
16485
+
16486
+
16487
+ meet3Planes: function (n1, d1, n2, d2, n3, d3) {
16488
+ var p = [0, 0, 0],
16489
+ n31, n12, n23, denom,
16490
+ i;
16491
+
16492
+ n31 = Mat.crossProduct(n3, n1);
16493
+ n12 = Mat.crossProduct(n1, n2);
16494
+ n23 = Mat.crossProduct(n2, n3);
16495
+ denom = Mat.innerProduct(n1, n23, 3);
16496
+ for (i = 0; i < 3; i++) {
16497
+ p[i] = (d1 * n23[i] + d2 * n31[i] + d3 * n12[i]) / denom;
16498
+ }
16499
+ return p;
16500
+ },
16501
+
16502
+
16503
+ meetPlanePlane: function (v11, v12, v21, v22) {
16504
+ var i, no1, no2,
16505
+ v = [0, 0, 0],
16506
+ w = [0, 0, 0];
16507
+
16508
+ for (i = 0; i < 3; i++) {
16509
+ v[i] = Type.evaluate(v11[i]);
16510
+ w[i] = Type.evaluate(v12[i]);
16511
+ }
16512
+ no1 = Mat.crossProduct(v, w);
16513
+
16514
+ for (i = 0; i < 3; i++) {
16515
+ v[i] = Type.evaluate(v21[i]);
16516
+ w[i] = Type.evaluate(v22[i]);
16517
+ }
16518
+ no2 = Mat.crossProduct(v, w);
16519
+
16520
+ return Mat.crossProduct(no1, no2);
16521
+ },
16522
+
16523
+ project3DTo3DPlane: function (point, normal, foot) {
16524
+ // TODO: homogeneous 3D coordinates
16525
+ var sol = [0, 0, 0],
16526
+ le, d1, d2, lbda;
16527
+
16528
+ foot = foot || [0, 0, 0];
16529
+
16530
+ le = Mat.norm(normal);
16531
+ d1 = Mat.innerProduct(point, normal, 3);
16532
+ d2 = Mat.innerProduct(foot, normal, 3);
16533
+ // (point - lbda * normal / le) * normal / le == foot * normal / le
16534
+ // => (point * normal - foot * normal) == lbda * le
16535
+ lbda = (d1 - d2) / le;
16536
+ sol = Mat.axpy(-lbda, normal, point);
16537
+
16538
+ return sol;
16539
+ },
16540
+
16541
+ getPlaneBounds: function (v1, v2, q, s, e) {
16542
+ var s1, s2, e1, e2, mat, rhs, sol;
16543
+
16544
+ if (v1[2] + v2[0] !== 0) {
16545
+ mat = [
16546
+ [v1[0], v2[0]],
16547
+ [v1[1], v2[1]]
16548
+ ];
16549
+ rhs = [s - q[0], s - q[1]];
16550
+
16551
+ sol = Numerics.Gauss(mat, rhs);
16552
+ s1 = sol[0];
16553
+ s2 = sol[1];
16554
+
16555
+ rhs = [e - q[0], e - q[1]];
16556
+ sol = Numerics.Gauss(mat, rhs);
16557
+ e1 = sol[0];
16558
+ e2 = sol[1];
16559
+ return [s1, e1, s2, e2];
16560
+ }
16561
+ return null;
16562
+ },
16563
+
16338
16564
  });
16339
16565
 
16340
16566
  return Mat.Geometry;
@@ -23140,7 +23366,6 @@ define('math/clip',[
23140
23366
 
23141
23367
  // Collect all points into clip array C
23142
23368
  C = this._getPath(clip, board);
23143
-
23144
23369
  len = C.length;
23145
23370
  if (len > 0 && Geometry.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) {
23146
23371
  C.pop();
@@ -25837,6 +26062,10 @@ define('options',[
25837
26062
  * visible: false // Initial visibility. Should be set to false always
25838
26063
  * }
25839
26064
  * </pre>
26065
+ * <p>
26066
+ * Board events triggered by selection manipulation:
26067
+ * 'startselecting', 'stopselecting', 'mousestartselecting', 'mousestopselecting',
26068
+ * 'pointerstartselecting', 'pointerstopselecting', 'touchstartselecting', 'touchstopselecting'.
25840
26069
  *
25841
26070
  * @example
25842
26071
  * board.on('stopselecting', function(){
@@ -25850,14 +26079,10 @@ define('options',[
25850
26079
  * });
25851
26080
  *
25852
26081
  * @name JXG.Board#selection
25853
- * @see JXG.Board#startselecting
25854
- * @see JXG.Board#stopselecting
25855
- * @see JXG.Board#mousestartselecting
25856
- * @see JXG.Board#pointerstartselecting
25857
- * @see JXG.Board#touchstartselecting
25858
- * @see JXG.Board#mousestopselecting
25859
- * @see JXG.Board#pointerstopselecting
25860
- * @see JXG.Board#touchstopselecting
26082
+ *
26083
+ * @see JXG.Board#startSelectionMode
26084
+ * @see JXG.Board#stopSelectionMode
26085
+ *
25861
26086
  * @type Object
25862
26087
  * @default
25863
26088
  */
@@ -26465,14 +26690,33 @@ define('options',[
26465
26690
  * <p>
26466
26691
  * In case the element is a polygon or line and it has the attribute "scalable:false",
26467
26692
  * moving the element with two fingers results in a rotation or translation.
26693
+ * <p>
26694
+ * If an element is set to be neither scalable nor rotatable, it can only be translated.
26468
26695
  *
26469
26696
  * @type Boolean
26470
26697
  * @default true
26471
26698
  * @name JXG.GeometryElement#scalable
26472
26699
  * @see JXG.Ticks#fixed
26700
+ * @see JXG.GeometryElement#rotatable
26473
26701
  */
26474
26702
  scalable: true,
26475
26703
 
26704
+ /**
26705
+ * Determines whether two-finger manipulation may rotate this object.
26706
+ * If set to false, the object can only be scaled and translated.
26707
+ * <p>
26708
+ * In case the element is a polygon or line and it has the attribute "rotatable:false",
26709
+ * moving the element with two fingers results in a rotation or translation.
26710
+ * <p>
26711
+ * If an element is set to be neither scalable nor rotatable, it can only be translated.
26712
+ *
26713
+ * @type Boolean
26714
+ * @default true
26715
+ * @name JXG.GeometryElement#rotatable
26716
+ * @see JXG.GeometryElement#scalable
26717
+ */
26718
+ rotatable: true,
26719
+
26476
26720
  /**
26477
26721
  * If the element is dragged it will be moved on mousedown or touchstart to the
26478
26722
  * top of its layer. Works only for SVG renderer and for simple elements
@@ -26544,6 +26788,7 @@ define('options',[
26544
26788
 
26545
26789
  /**
26546
26790
  * Controls if an element can get the focus with the tab key.
26791
+ * tabindex corresponds to the HTML attribute of the same name.
26547
26792
  * See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex">descriptiona at MDN</a>.
26548
26793
  * The additional value null completely disables focus of an element.
26549
26794
  * The value will be ignored if keyboard control of the board is not enabled or
@@ -26573,6 +26818,8 @@ define('options',[
26573
26818
  /**
26574
26819
  * A function that expects two {@link JXG.Coords}, the first one representing the coordinates of the
26575
26820
  * tick that is to be labeled, the second one the coordinates of the center (the tick with position 0).
26821
+ * The tird parameter is a null, number or a string. In the latter two cases, this value is taken.
26822
+ * Returns a string.
26576
26823
  *
26577
26824
  * @type function
26578
26825
  * @name Ticks#generateLabelText
@@ -26583,7 +26830,7 @@ define('options',[
26583
26830
  * A function that expects two {@link JXG.Coords}, the first one representing the coordinates of the
26584
26831
  * tick that is to be labeled, the second one the coordinates of the center (the tick with position 0).
26585
26832
  *
26586
- * @deprecated Use {@link JGX.Options@generateLabelValue}
26833
+ * @deprecated Use {@link JGX.Options@generateLabelText}
26587
26834
  * @type function
26588
26835
  * @name Ticks#generateLabelValue
26589
26836
  */
@@ -28559,7 +28806,6 @@ define('options',[
28559
28806
  */
28560
28807
  lastArrow: false,
28561
28808
 
28562
-
28563
28809
  /**
28564
28810
  * This number (pixel value) controls where infinite lines end at the canvas border. If zero, the line
28565
28811
  * ends exactly at the border, if negative there is a margin to the inside, if positive the line
@@ -28736,7 +28982,6 @@ define('options',[
28736
28982
  */
28737
28983
  lineCap: 'butt'
28738
28984
 
28739
-
28740
28985
  /**#@-*/
28741
28986
  },
28742
28987
 
@@ -30677,8 +30922,10 @@ define('options',[
30677
30922
  display: 'html',
30678
30923
 
30679
30924
  /**
30680
- * Anchor element {@link Point}, {@link Text} or {@link Image} of the text. If it exists, the coordinates of the text are relative
30681
- * to this anchor element.
30925
+ * Anchor element {@link Point}, {@link Text} or {@link Image} of the text.
30926
+ * If it exists, the coordinates of the text are relative
30927
+ * to this anchor element. In this case, only numbers are possible coordinates,
30928
+ * functions are not supported.
30682
30929
  *
30683
30930
  * @name anchor
30684
30931
  * @memberOf Text.prototype
@@ -35099,26 +35346,35 @@ define('base/element',[
35099
35346
  },
35100
35347
 
35101
35348
  /**
35102
- * Resolves property shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.
35103
- * Writes the expanded properties back to the given <tt>properties</tt>.
35104
- * @param {Object} properties
35105
- * @returns {Object} The given parameter with shortcuts expanded.
35349
+ * Resolves attribute shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.
35350
+ * Writes the expanded attributes back to the given <tt>attributes</tt>.
35351
+ * @param {Object} attributes object
35352
+ * @returns {Object} The given attributes object with shortcuts expanded.
35353
+ * @private
35106
35354
  */
35107
- resolveShortcuts: function (properties) {
35108
- var key, i;
35355
+ resolveShortcuts: function (attributes) {
35356
+ var key, i,
35357
+ j,
35358
+ subattr = ['traceattributes', 'traceAttributes'];
35109
35359
 
35110
35360
  for (key in Options.shortcuts) {
35111
35361
  if (Options.shortcuts.hasOwnProperty(key)) {
35112
- if (Type.exists(properties[key])) {
35113
- for (i = 0; i < Options.shortcuts[key].length; i++) {
35114
- if (!Type.exists(properties[Options.shortcuts[key][i]])) {
35115
- properties[Options.shortcuts[key][i]] = properties[key];
35362
+
35363
+ if (Type.exists(attributes[key])) {
35364
+ for (i = 0; i < Options.shortcuts[key].length; i++) {
35365
+ if (!Type.exists(attributes[Options.shortcuts[key][i]])) {
35366
+ attributes[Options.shortcuts[key][i]] = attributes[key];
35367
+ }
35368
+ }
35369
+ }
35370
+ for (j = 0; j < subattr.length; j++) {
35371
+ if (Type.isObject(attributes[subattr[j]])) {
35372
+ attributes[subattr[j]] = this.resolveShortcuts(attributes[subattr[j]]);
35373
+ }
35116
35374
  }
35117
35375
  }
35118
- }
35119
- }
35120
35376
  }
35121
- return properties;
35377
+ return attributes;
35122
35378
  },
35123
35379
 
35124
35380
  /**
@@ -36546,8 +36802,6 @@ define('base/coordselement',[
36546
36802
  * @private
36547
36803
  */
36548
36804
  updateCoords: function (fromParent) {
36549
- var i;
36550
-
36551
36805
  if (!this.needsUpdate) {
36552
36806
  return this;
36553
36807
  }
@@ -36674,7 +36928,6 @@ define('base/coordselement',[
36674
36928
  doRound = true;
36675
36929
  newPos = 0.0;
36676
36930
  } else {
36677
- //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToLine(this, slide, this.board).usrCoords, false);
36678
36931
  newCoords = Geometry.projectPointToLine(this, slide, this.board);
36679
36932
  p1c = p1c.usrCoords.slice(0);
36680
36933
  p2c = p2c.usrCoords.slice(0);
@@ -38181,7 +38434,7 @@ define('base/coordselement',[
38181
38434
  if (direction < 0) {
38182
38435
  alpha *= this.intervalCount / stepCount;
38183
38436
  } else {
38184
- alpha *= (stepCount - this.intervalCount);
38437
+ alpha *= (stepCount - this.intervalCount) / stepCount;
38185
38438
  }
38186
38439
  radius = this.slideObject.Radius();
38187
38440
 
@@ -38486,6 +38739,7 @@ define('base/text',[
38486
38739
 
38487
38740
  this.orgText = text;
38488
38741
  if (Type.isFunction(text)) {
38742
+ // <value> tags will not be evaluated.
38489
38743
  this.updateText = function () {
38490
38744
  resolvedText = text().toString();
38491
38745
  if (ev_p && !ev_um && !ev_uk) {
@@ -38506,14 +38760,20 @@ define('base/text',[
38506
38760
  // Convert via ASCIIMathML
38507
38761
  this.content = "'`" + text + "`'";
38508
38762
  } else if (ev_um || ev_uk) {
38509
- this.content = "'" + text + "'";
38763
+ if (ev_p) {
38764
+ this.content = this.generateTerm(text, true, true, true); // Replace value-tags
38765
+ this.content = this.content.replace(/\\/g, "\\\\");
38766
+ } else {
38767
+ this.content = "'" + text + "'";
38768
+ }
38510
38769
  } else {
38511
38770
  // Converts GEONExT syntax into JavaScript string
38512
38771
  // Short math is allowed
38513
38772
  // Avoid geonext2JS calls
38514
- this.content = this.generateTerm(text, true, true);
38773
+ this.content = this.generateTerm(text, true, true, false);
38515
38774
  }
38516
38775
  }
38776
+ // Convert JessieCode to JS function
38517
38777
  updateText = this.board.jc.snippet(this.content, true, '', false);
38518
38778
  this.updateText = function () {
38519
38779
  this.plaintext = updateText();
@@ -38869,30 +39129,43 @@ define('base/text',[
38869
39129
  /**
38870
39130
  * Converts the GEONExT syntax of the <value> terms into JavaScript.
38871
39131
  * Also, all Objects whose name appears in the term are searched and
38872
- * the text is added as child to these objects.
39132
+ * the text is added as child to these objects.
39133
+ * This method is called if the attribute parse==true is set.
38873
39134
  *
38874
39135
  * @param{String} contentStr String to be parsed
38875
39136
  * @param{Boolean} [expand] Optional flag if shortened math syntax is allowed (e.g. 3x instead of 3*x).
38876
39137
  * @param{Boolean} [avoidGeonext2JS] Optional flag if geonext2JS should be called. For backwards compatibility
38877
39138
  * this has to be set explicitely to true.
39139
+ * @param{Boolean} [outputTeX] Optional flag which has to be true if the resulting term will be sent to MathJax or KaTeX.
39140
+ * If true, "_" and "^" are NOT replaced by HTML tags sub and sup. Default: false, i.e. the replacement is done.
39141
+ * This flag allows the combination of &lt;value&gt; tag containing calculations with TeX output.
39142
+ *
38878
39143
  * @private
38879
39144
  * @see JXG.GeonextParser.geonext2JS
38880
39145
  */
38881
- generateTerm: function (contentStr, expand, avoidGeonext2JS) {
39146
+ generateTerm: function (contentStr, expand, avoidGeonext2JS, outputTeX) {
38882
39147
  var res, term, i, j,
38883
39148
  plaintext = '""';
38884
39149
 
38885
- // revert possible jc replacement
39150
+ outputTeX = outputTeX || false;
39151
+
39152
+ // Revert possible jc replacement
38886
39153
  contentStr = contentStr || '';
38887
39154
  contentStr = contentStr.replace(/\r/g, '');
38888
39155
  contentStr = contentStr.replace(/\n/g, '');
38889
39156
  contentStr = contentStr.replace(/"/g, '\'');
38890
39157
  contentStr = contentStr.replace(/'/g, "\\'");
38891
39158
 
38892
- contentStr = contentStr.replace(/&amp;arc;/g, '&ang;');
38893
- contentStr = contentStr.replace(/<arc\s*\/>/g, '&ang;');
38894
- contentStr = contentStr.replace(/&lt;arc\s*\/&gt;/g, '&ang;');
38895
- contentStr = contentStr.replace(/&lt;sqrt\s*\/&gt;/g, '&radic;');
39159
+ if (!outputTeX) {
39160
+ // Old GEONExT syntax, not (yet) supported as TeX output.
39161
+ // Otherwise, the else clause should be used.
39162
+ // That means, i.e. the <arc> tag and <sqrt> tag are not
39163
+ // converted into TeX syntax.
39164
+ contentStr = contentStr.replace(/&amp;arc;/g, '&ang;');
39165
+ contentStr = contentStr.replace(/<arc\s*\/>/g, '&ang;');
39166
+ contentStr = contentStr.replace(/&lt;arc\s*\/&gt;/g, '&ang;');
39167
+ contentStr = contentStr.replace(/&lt;sqrt\s*\/&gt;/g, '&radic;');
39168
+ }
38896
39169
 
38897
39170
  contentStr = contentStr.replace(/&lt;value&gt;/g, '<value>');
38898
39171
  contentStr = contentStr.replace(/&lt;\/value&gt;/g, '</value>');
@@ -38902,7 +39175,12 @@ define('base/text',[
38902
39175
  j = contentStr.indexOf('</value>');
38903
39176
  if (i >= 0) {
38904
39177
  while (i >= 0) {
38905
- plaintext += ' + "' + this.replaceSub(this.replaceSup(contentStr.slice(0, i))) + '"';
39178
+ if (!outputTeX) {
39179
+ plaintext += ' + "' + this.replaceSub(this.replaceSup(contentStr.slice(0, i))) + '"';
39180
+ // plaintext += ' + "' + this.replaceSub(contentStr.slice(0, i)) + '"';
39181
+ } else {
39182
+ plaintext += ' + "' + contentStr.slice(0, i) + '"';
39183
+ }
38906
39184
  term = contentStr.slice(i + 7, j);
38907
39185
  term = term.replace(/\s+/g, ''); // Remove all whitespace
38908
39186
  if (expand === true) {
@@ -38935,10 +39213,14 @@ define('base/text',[
38935
39213
  }
38936
39214
  }
38937
39215
 
38938
- plaintext += ' + "' + this.replaceSub(this.replaceSup(contentStr)) + '"';
38939
- plaintext = this.convertGeonextAndSketchometry2CSS(plaintext);
39216
+ if (!outputTeX) {
39217
+ plaintext += ' + "' + this.replaceSub(this.replaceSup(contentStr)) + '"';
39218
+ plaintext = this.convertGeonextAndSketchometry2CSS(plaintext);
39219
+ } else {
39220
+ plaintext += ' + "' + contentStr + '"';
39221
+ }
38940
39222
 
38941
- // This should replace &amp;pi; by &pi;
39223
+ // This should replace e.g. &amp;pi; by &pi;
38942
39224
  plaintext = plaintext.replace(/&amp;/g, '&');
38943
39225
  plaintext = plaintext.replace(/"/g, "'");
38944
39226
 
@@ -41095,7 +41377,7 @@ define('parser/jessiecode',[
41095
41377
  case 'node_str':
41096
41378
  //ret = node.value.replace(/\\'/, "'").replace(/\\"/, '"').replace(/\\\\/, '\\');
41097
41379
  /*jslint regexp:true*/
41098
- ret = node.value.replace(/\\(.)/, '$1');
41380
+ ret = node.value.replace(/\\(.)/g, '$1'); // Remove backslash, important in JessieCode tags
41099
41381
  /*jslint regexp:false*/
41100
41382
  break;
41101
41383
  }
@@ -44161,8 +44443,12 @@ define('base/board',[
44161
44443
  */
44162
44444
  getCoordsTopLeftCorner: function () {
44163
44445
  var cPos, doc, crect,
44164
- docElement = this.document.documentElement || this.document.body.parentNode,
44165
- docBody = this.document.body,
44446
+ // In ownerDoc we need the "real" document object.
44447
+ // The first version is used in the case of shadowDom,
44448
+ // the second case in the "normal" case.
44449
+ ownerDoc = this.document.ownerDocument || this.document,
44450
+ docElement = ownerDoc.documentElement || this.document.body.parentNode,
44451
+ docBody = ownerDoc.body,
44166
44452
  container = this.containerObj,
44167
44453
  // viewport, content,
44168
44454
  zoom, o;
@@ -44537,7 +44823,8 @@ define('base/board',[
44537
44823
  */
44538
44824
  twoFingerTouchObject: function (tar, drag, id) {
44539
44825
  var np, op, nd, od,
44540
- d, alpha,
44826
+ d,
44827
+ alpha = 0,
44541
44828
  S, t1, t3, t4, t5,
44542
44829
  ar, i, len,
44543
44830
  fixEl, moveEl, fix;
@@ -44571,7 +44858,9 @@ define('base/board',[
44571
44858
  return;
44572
44859
  }
44573
44860
 
44574
- alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
44861
+ if (Type.evaluate(drag.visProp.rotatable)) {
44862
+ alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
44863
+ }
44575
44864
 
44576
44865
  t1 = this.create('transform', [alpha, [fix[1], fix[2]]], {type: 'rotate'});
44577
44866
  t1.update();
@@ -45742,7 +46031,8 @@ define('base/board',[
45742
46031
  * @returns {Boolean}
45743
46032
  */
45744
46033
  pointerUpListener: function (evt) {
45745
- var i, j, found, touchTargets;
46034
+ var i, j, found, touchTargets,
46035
+ updateNeeded = false;
45746
46036
 
45747
46037
  this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);
45748
46038
  this.displayInfobox(false);
@@ -45762,10 +46052,14 @@ define('base/board',[
45762
46052
  }
45763
46053
  }
45764
46054
 
46055
+ this.originMoveEnd();
46056
+ this.update();
46057
+
45765
46058
  // selection
45766
46059
  if (this.selectingMode) {
45767
46060
  this._stopSelecting(evt);
45768
46061
  this.triggerEventHandlers(['touchstopselecting', 'pointerstopselecting', 'stopselecting'], [evt]);
46062
+ this.stopSelectionMode();
45769
46063
  } else {
45770
46064
  for (i = this.downObjects.length - 1; i > -1; i--) {
45771
46065
  found = false;
@@ -45776,32 +46070,38 @@ define('base/board',[
45776
46070
  }
45777
46071
  if (!found) {
45778
46072
  this.downObjects[i].triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);
45779
- this.downObjects[i].snapToGrid();
45780
- this.downObjects[i].snapToPoints();
46073
+ if (!Type.exists(this.downObjects[i].coords)) {
46074
+ // snapTo methods have to be called e.g. for line elements here.
46075
+ // For coordsElements there might be a conflict with
46076
+ // attractors, see commit from 2022.04.08, 11:12:18.
46077
+ this.downObjects[i].snapToGrid();
46078
+ this.downObjects[i].snapToPoints();
46079
+ updateNeeded = true;
46080
+ }
45781
46081
  this.downObjects.splice(i, 1);
45782
46082
  }
45783
46083
  }
45784
46084
  }
45785
46085
 
45786
- // this._pointerRemoveTouches(evt);
45787
- // if (this._board_touches.length === 0) {
45788
- if (this.hasPointerUp) {
45789
- if (window.navigator.msPointerEnabled) { // IE10-
45790
- Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);
45791
- } else {
45792
- Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);
45793
- Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);
45794
- }
45795
- this.hasPointerUp = false;
46086
+ if (this.hasPointerUp) {
46087
+ if (window.navigator.msPointerEnabled) { // IE10-
46088
+ Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);
46089
+ } else {
46090
+ Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);
46091
+ Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);
45796
46092
  }
46093
+ this.hasPointerUp = false;
46094
+ }
45797
46095
 
45798
- // this.dehighlightAll();
45799
- // this.updateQuality = this.BOARD_QUALITY_HIGH;
45800
- // this.mode = this.BOARD_MODE_NONE;
46096
+ // this.dehighlightAll();
46097
+ // this.updateQuality = this.BOARD_QUALITY_HIGH;
46098
+ // this.mode = this.BOARD_MODE_NONE;
45801
46099
 
45802
- this.originMoveEnd();
46100
+ // this.originMoveEnd();
46101
+ if (updateNeeded) {
45803
46102
  this.update();
45804
- // }
46103
+ }
46104
+
45805
46105
  // After one finger leaves the screen the gesture is stopped.
45806
46106
  this._pointerClearTouches();
45807
46107
  return true;
@@ -46135,7 +46435,8 @@ define('base/board',[
46135
46435
  eps = this.options.precision.touch,
46136
46436
  tmpTouches = [], found, foundNumber,
46137
46437
  evtTouches = evt && evt[JXG.touchProperty],
46138
- touchTargets;
46438
+ touchTargets,
46439
+ updateNeeded = false;
46139
46440
 
46140
46441
  this.triggerEventHandlers(['touchend', 'up'], [evt]);
46141
46442
  this.displayInfobox(false);
@@ -46144,6 +46445,7 @@ define('base/board',[
46144
46445
  if (this.selectingMode) {
46145
46446
  this._stopSelecting(evt);
46146
46447
  this.triggerEventHandlers(['touchstopselecting', 'stopselecting'], [evt]);
46448
+ this.stopSelectionMode();
46147
46449
  } else if (evtTouches && evtTouches.length > 0) {
46148
46450
  for (i = 0; i < this.touches.length; i++) {
46149
46451
  tmpTouches[i] = this.touches[i];
@@ -46235,8 +46537,14 @@ define('base/board',[
46235
46537
  }
46236
46538
  if (!found) {
46237
46539
  this.downObjects[i].triggerEventHandlers(['touchup', 'up'], [evt]);
46238
- this.downObjects[i].snapToGrid();
46239
- this.downObjects[i].snapToPoints();
46540
+ if (!Type.exists(this.downObjects[i].coords)) {
46541
+ // snapTo methods have to be called e.g. for line elements here.
46542
+ // For coordsElements there might be a conflict with
46543
+ // attractors, see commit from 2022.04.08, 11:12:18.
46544
+ this.downObjects[i].snapToGrid();
46545
+ this.downObjects[i].snapToPoints();
46546
+ updateNeeded = true;
46547
+ }
46240
46548
  this.downObjects.splice(i, 1);
46241
46549
  }
46242
46550
  }
@@ -46252,7 +46560,9 @@ define('base/board',[
46252
46560
  this.updateQuality = this.BOARD_QUALITY_HIGH;
46253
46561
 
46254
46562
  this.originMoveEnd();
46255
- this.update();
46563
+ if (updateNeeded) {
46564
+ this.update();
46565
+ }
46256
46566
  }
46257
46567
 
46258
46568
  return true;
@@ -46400,9 +46710,14 @@ define('base/board',[
46400
46710
  this.updateQuality = this.BOARD_QUALITY_HIGH;
46401
46711
 
46402
46712
  if (this.mouse && this.mouse.obj) {
46403
- // The parameter is needed for lines with snapToGrid enabled
46404
- this.mouse.obj.snapToGrid(this.mouse.targets[0]);
46405
- this.mouse.obj.snapToPoints();
46713
+ if (!Type.exists(this.mouse.obj.coords)) {
46714
+ // snapTo methods have to be called e.g. for line elements here.
46715
+ // For coordsElements there might be a conflict with
46716
+ // attractors, see commit from 2022.04.08, 11:12:18.
46717
+ // The parameter is needed for lines with snapToGrid enabled
46718
+ this.mouse.obj.snapToGrid(this.mouse.targets[0]);
46719
+ this.mouse.obj.snapToPoints();
46720
+ }
46406
46721
  }
46407
46722
 
46408
46723
  this.originMoveEnd();
@@ -46413,6 +46728,7 @@ define('base/board',[
46413
46728
  if (this.selectingMode) {
46414
46729
  this._stopSelecting(evt);
46415
46730
  this.triggerEventHandlers(['mousestopselecting', 'stopselecting'], [evt]);
46731
+ this.stopSelectionMode();
46416
46732
  } else {
46417
46733
  for (i = 0; i < this.downObjects.length; i++) {
46418
46734
  this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], [evt]);
@@ -46458,11 +46774,18 @@ define('base/board',[
46458
46774
  },
46459
46775
 
46460
46776
  /**
46461
- * Allow moving of JSXGraph elements with arrow keys
46462
- * and zooming of the construction with + / -.
46777
+ * Allow moving of JSXGraph elements with arrow keys.
46778
+ * The selection of the element is done with the tab key. For this,
46779
+ * the attribute "tabindex" of the element has to be set to some number (default=0).
46780
+ * tabindex corresponds to the HTML attribute of the same name.
46781
+ * <p>
46463
46782
  * Panning of the construction is done with arrow keys
46464
- * if the pan key (shift or ctrl) is pressed.
46465
- * The selection of the element is done with the tab key.
46783
+ * if the pan key (shift or ctrl - depending on the board attributes) is pressed.
46784
+ * <p>
46785
+ * Zooming is triggered with the keys +, o, -, if
46786
+ * the pan key (shift or ctrl - depending on the board attributes) is pressed.
46787
+ * <p>
46788
+ * Keyboard control (move, pan, and zoom) is disabled if an HTML element of type input or textarea has received focus.
46466
46789
  *
46467
46790
  * @param {Event} evt The browser's event object
46468
46791
  *
@@ -46473,7 +46796,7 @@ define('base/board',[
46473
46796
  */
46474
46797
  keyDownListener: function (evt) {
46475
46798
  var id_node = evt.target.id,
46476
- id, el, res,
46799
+ id, el, res, doc,
46477
46800
  sX = 0,
46478
46801
  sY = 0,
46479
46802
  // dx, dy are provided in screen units and
@@ -46488,6 +46811,15 @@ define('base/board',[
46488
46811
  return false;
46489
46812
  }
46490
46813
 
46814
+ // An element of type input or textarea has foxus, get out of here.
46815
+ doc = this.containerObj.shadowRoot || document;
46816
+ if (doc.activeElement) {
46817
+ el = doc.activeElement;
46818
+ if (el.tagName === 'INPUT' || el.tagName === 'textarea') {
46819
+ return false;
46820
+ }
46821
+ }
46822
+
46491
46823
  // Get the JSXGraph id from the id of the SVG node.
46492
46824
  id = id_node.replace(this.containerObj.id + '_', '');
46493
46825
  el = this.select(id);
@@ -46496,12 +46828,15 @@ define('base/board',[
46496
46828
  actPos = el.coords.usrCoords.slice(1);
46497
46829
  }
46498
46830
 
46499
- if (Type.evaluate(this.attr.keyboard.panshift) || Type.evaluate(this.attr.keyboard.panctrl)) {
46500
- doZoom = true;
46501
- }
46502
-
46503
46831
  if ((Type.evaluate(this.attr.keyboard.panshift) && evt.shiftKey) ||
46504
46832
  (Type.evaluate(this.attr.keyboard.panctrl) && evt.ctrlKey)) {
46833
+ // Pan key has been pressed
46834
+
46835
+ if (Type.evaluate(this.attr.zoom.enabled) === true) {
46836
+ doZoom = true;
46837
+ }
46838
+
46839
+ // Arrow keys
46505
46840
  if (evt.keyCode === 38) { // up
46506
46841
  this.clickUpArrow();
46507
46842
  } else if (evt.keyCode === 40) { // down
@@ -46510,10 +46845,20 @@ define('base/board',[
46510
46845
  this.clickLeftArrow();
46511
46846
  } else if (evt.keyCode === 39) { // right
46512
46847
  this.clickRightArrow();
46848
+
46849
+ // Zoom keys
46850
+ } else if (doZoom && evt.keyCode === 171) { // +
46851
+ this.zoomIn();
46852
+ } else if (doZoom && evt.keyCode === 173) { // -
46853
+ this.zoomOut();
46854
+ } else if (doZoom && evt.keyCode === 79) { // o
46855
+ this.zoom100();
46856
+
46513
46857
  } else {
46514
46858
  done = false;
46515
46859
  }
46516
46860
  } else {
46861
+
46517
46862
  // Adapt dx, dy to snapToGrid and attractToGrid
46518
46863
  // snapToGrid has priority.
46519
46864
  if (Type.exists(el.visProp)) {
@@ -46556,14 +46901,6 @@ define('base/board',[
46556
46901
  dir = [-dx, 0];
46557
46902
  } else if (evt.keyCode === 39) { // right
46558
46903
  dir = [dx, 0];
46559
- // } else if (evt.keyCode === 9) { // tab
46560
-
46561
- } else if (doZoom && evt.key === '+') { // +
46562
- this.zoomIn();
46563
- } else if (doZoom && evt.key === '-') { // -
46564
- this.zoomOut();
46565
- } else if (doZoom && evt.key === 'o') { // o
46566
- this.zoom100();
46567
46904
  } else {
46568
46905
  done = false;
46569
46906
  }
@@ -46593,15 +46930,16 @@ define('base/board',[
46593
46930
 
46594
46931
  this.update();
46595
46932
 
46596
- if (done) {
46933
+ if (done && Type.exists(evt.preventDefault)) {
46597
46934
  evt.preventDefault();
46598
46935
  }
46599
- return true;
46936
+ return done;
46600
46937
  },
46601
46938
 
46602
46939
  /**
46603
46940
  * Event listener for SVG elements getting focus.
46604
46941
  * This is needed for highlighting when using keyboard control.
46942
+ * Only elements having the attribute "tabindex" can receive focus.
46605
46943
  *
46606
46944
  * @see JXG.Board#keyFocusOutListener
46607
46945
  * @see JXG.Board#keyDownListener
@@ -46631,6 +46969,7 @@ define('base/board',[
46631
46969
  /**
46632
46970
  * Event listener for SVG elements losing focus.
46633
46971
  * This is needed for dehighlighting when using keyboard control.
46972
+ * Only elements having the attribute "tabindex" can receive focus.
46634
46973
  *
46635
46974
  * @see JXG.Board#keyFocusInListener
46636
46975
  * @see JXG.Board#keyDownListener
@@ -46681,8 +47020,8 @@ define('base/board',[
46681
47020
  }
46682
47021
 
46683
47022
  // If div is invisible - do nothing
46684
- if (w <= 0 || h <= 0) {
46685
- return;
47023
+ if (w <= 0 || h <= 0 || isNaN(w) || isNaN(h)) {
47024
+ return;
46686
47025
  }
46687
47026
 
46688
47027
  // If bounding box is not yet initialized, do it now.
@@ -48087,12 +48426,12 @@ define('base/board',[
48087
48426
  this.inUpdate = true;
48088
48427
 
48089
48428
  if (this.attr.minimizereflow === 'all' && this.containerObj && this.renderer.type !== 'vml') {
48090
- storeActiveEl = document.activeElement; // Store focus element
48429
+ storeActiveEl = this.document.activeElement; // Store focus element
48091
48430
  insert = this.renderer.removeToInsertLater(this.containerObj);
48092
48431
  }
48093
48432
 
48094
48433
  if (this.attr.minimizereflow === 'svg' && this.renderer.type === 'svg') {
48095
- storeActiveEl = document.activeElement;
48434
+ storeActiveEl = this.document.activeElement;
48096
48435
  insert = this.renderer.removeToInsertLater(this.renderer.svgRoot);
48097
48436
  }
48098
48437
 
@@ -48696,31 +49035,43 @@ define('base/board',[
48696
49035
  */
48697
49036
  updateCSSTransforms: function () {
48698
49037
  var obj = this.containerObj,
48699
- o = obj,
48700
- o2 = obj;
49038
+ o = obj;
49039
+ // o2 = obj;
48701
49040
 
48702
49041
  this.cssTransMat = Env.getCSSTransformMatrix(o);
48703
49042
 
49043
+ // Newer variant of walking up the tree.
49044
+ // We walk up all parent nodes and collect possible CSS transforms.
49045
+ // Works also for ShadowDOM
49046
+ o = o.parentNode === o.getRootNode() ? o.parentNode.host : o.parentNode;
49047
+ while (o) {
49048
+ this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
49049
+ o = o.parentNode === o.getRootNode() ? o.parentNode.host : o.parentNode;
49050
+ }
49051
+ this.cssTransMat = Mat.inverse(this.cssTransMat);
49052
+
48704
49053
  /*
48705
49054
  * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,
48706
49055
  * if not to the body. In IE and if we are in an position:absolute environment
48707
49056
  * offsetParent walks up the DOM hierarchy.
48708
49057
  * In order to walk up the DOM hierarchy also in Mozilla and Webkit
48709
49058
  * we need the parentNode steps.
49059
+ *
49060
+ * Seems to be outdated
48710
49061
  */
48711
- o = o.offsetParent;
48712
- while (o) {
48713
- this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
48714
-
48715
- o2 = o2.parentNode;
48716
- while (o2 !== o) {
48717
- this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
48718
- o2 = o2.parentNode;
48719
- }
49062
+ // o = o.offsetParent;
49063
+ // while (o) {
49064
+ // this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
49065
+
49066
+ // o2 = o2.parentNode;
49067
+ // while (o2 !== o) {
49068
+ // this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
49069
+ // o2 = o2.parentNode;
49070
+ // }
48720
49071
 
48721
- o = o.offsetParent;
48722
- }
48723
- this.cssTransMat = Mat.inverse(this.cssTransMat);
49072
+ // o = o.offsetParent;
49073
+ // }
49074
+ // this.cssTransMat = Mat.inverse(this.cssTransMat);
48724
49075
 
48725
49076
  return this;
48726
49077
  },
@@ -49281,16 +49632,17 @@ define('base/board',[
49281
49632
  *
49282
49633
  */
49283
49634
  toFullscreen: function (id) {
49284
- var wrap_id, wrap_node, inner_node;
49635
+ var wrap_id, wrap_node, inner_node,
49636
+ doc = this.document;
49285
49637
 
49286
49638
  id = id || this.container;
49287
49639
  this._fullscreen_inner_id = id;
49288
- inner_node = document.getElementById(id);
49640
+ inner_node = doc.getElementById(id);
49289
49641
  wrap_id = 'fullscreenwrap_' + id;
49290
49642
 
49291
49643
  // Wrap a div around the JSXGraph div.
49292
- if (this.document.getElementById(wrap_id)) {
49293
- wrap_node = this.document.getElementById(wrap_id);
49644
+ if (doc.getElementById(wrap_id)) {
49645
+ wrap_node = doc.getElementById(wrap_id);
49294
49646
  } else {
49295
49647
  wrap_node = document.createElement('div');
49296
49648
  wrap_node.classList.add('JXG_wrap_private');
@@ -49309,8 +49661,14 @@ define('base/board',[
49309
49661
  wrap_node.mozRequestFullScreen ||
49310
49662
  wrap_node.msRequestFullscreen;
49311
49663
 
49312
- if (wrap_node.requestFullscreen) {
49313
- wrap_node.requestFullscreen();
49664
+ if (doc.fullscreenElement === null) {
49665
+ // Start fullscreen mode
49666
+ if (wrap_node.requestFullscreen) {
49667
+ wrap_node.requestFullscreen();
49668
+ }
49669
+ } else {
49670
+ // Leave fullscreen mode (e.g. when clicking on the icon)
49671
+ document.exitFullscreen();
49314
49672
  }
49315
49673
 
49316
49674
  return this;
@@ -49324,23 +49682,24 @@ define('base/board',[
49324
49682
  * @param {Object} evt fullscreen event object (unused)
49325
49683
  */
49326
49684
  fullscreenListener: function (evt) {
49327
- var res, inner_id, inner_node;
49685
+ var res, inner_id, inner_node,
49686
+ doc = this.document;
49328
49687
 
49329
49688
  inner_id = this._fullscreen_inner_id;
49330
49689
  if (!Type.exists(inner_id)) {
49331
49690
  return;
49332
49691
  }
49333
49692
 
49334
- document.fullscreenElement = document.fullscreenElement ||
49335
- document.webkitFullscreenElement ||
49336
- document.mozFullscreenElement ||
49337
- document.msFullscreenElement;
49693
+ doc.fullscreenElement = doc.fullscreenElement ||
49694
+ doc.webkitFullscreenElement ||
49695
+ doc.mozFullscreenElement ||
49696
+ doc.msFullscreenElement;
49338
49697
 
49339
- inner_node = document.getElementById(inner_id);
49698
+ inner_node = doc.getElementById(inner_id);
49340
49699
  // If full screen mode is started we have to remove CSS margin around the JSXGraph div.
49341
49700
  // Otherwise, the positioning of the fullscreen div will be false.
49342
49701
  // When leaving the fullscreen mode, the margin is put back in.
49343
- if (document.fullscreenElement) {
49702
+ if (doc.fullscreenElement) {
49344
49703
  // Just entered fullscreen mode
49345
49704
 
49346
49705
  // Get the data computed in board.toFullscreen()
@@ -49352,7 +49711,7 @@ define('base/board',[
49352
49711
  // Further, the CSS margin has to be removed when in fullscreen mode,
49353
49712
  // and must be restored later.
49354
49713
  inner_node._cssFullscreenStore = {
49355
- id: document.fullscreenElement.id,
49714
+ id: doc.fullscreenElement.id,
49356
49715
  isFullscreen: true,
49357
49716
  margin: inner_node.style.margin,
49358
49717
  width: inner_node.style.width,
@@ -49366,18 +49725,18 @@ define('base/board',[
49366
49725
  // Do the shifting and scaling via CSS pseudo rules
49367
49726
  // We do this after fullscreen mode has been established to get the correct size
49368
49727
  // of the JSXGraph div.
49369
- Env.scaleJSXGraphDiv(document.fullscreenElement.id, inner_id, res.scale, res.vshift);
49728
+ Env.scaleJSXGraphDiv(doc.fullscreenElement.id, inner_id, res.scale, res.vshift, doc);
49370
49729
 
49371
- // Clear document.fullscreenElement, because Safari doesn't to it and
49730
+ // Clear this.document.fullscreenElement, because Safari doesn't to it and
49372
49731
  // when leaving full screen mode it is still set.
49373
- document.fullscreenElement = null;
49732
+ doc.fullscreenElement = null;
49374
49733
 
49375
49734
  } else if (Type.exists(inner_node._cssFullscreenStore)) {
49376
49735
  // Just left the fullscreen mode
49377
49736
 
49378
49737
  // Remove the CSS rules added in Env.scaleJSXGraphDiv
49379
49738
  try {
49380
- document.styleSheets[document.styleSheets.length - 1].deleteRule(0);
49739
+ doc.styleSheets[doc.styleSheets.length - 1].deleteRule(0);
49381
49740
  } catch (err) {
49382
49741
  console.log('JSXGraph: Could not remove CSS rules for full screen mode');
49383
49742
  }
@@ -49385,7 +49744,6 @@ define('base/board',[
49385
49744
  inner_node._cssFullscreenStore.isFullscreen = false;
49386
49745
  inner_node.style.margin = inner_node._cssFullscreenStore.margin;
49387
49746
  inner_node.style.width = inner_node._cssFullscreenStore.width;
49388
-
49389
49747
  }
49390
49748
 
49391
49749
  this.updateCSSTransforms();
@@ -51295,10 +51653,11 @@ define('renderer/svg',[
51295
51653
  * setTimeout(function() { console.log('done'); }, 400);
51296
51654
  */
51297
51655
  dumpToCanvas: function (canvasId, w, h, ignoreTexts) {
51298
- var svg, tmpImg, cv, ctx;
51656
+ var svg, tmpImg, cv, ctx,
51657
+ doc = this.container.ownerDocument;
51299
51658
 
51300
51659
  // Prepare the canvas element
51301
- cv = document.getElementById(canvasId);
51660
+ cv = doc.getElementById(canvasId);
51302
51661
 
51303
51662
  // Clear the canvas
51304
51663
  /* eslint-disable no-self-assign */
@@ -51434,7 +51793,8 @@ define('renderer/svg',[
51434
51793
  } else {
51435
51794
  // Debug: use canvas element 'jxgbox_canvas' from jsxdev/dump.html
51436
51795
  id = 'jxgbox_canvas';
51437
- canvas = document.getElementById(id);
51796
+ // canvas = document.getElementById(id);
51797
+ canvas = doc.getElementById(id);
51438
51798
  }
51439
51799
 
51440
51800
  if (newImg) {
@@ -51454,7 +51814,8 @@ define('renderer/svg',[
51454
51814
  }
51455
51815
 
51456
51816
  // Hide navigation bar in board
51457
- zbar = document.getElementById(this.container.id + '_navigationbar');
51817
+ // zbar = document.getElementById(this.container.id + '_navigationbar');
51818
+ zbar = doc.getElementById(this.container.id + '_navigationbar');
51458
51819
  if (Type.exists(zbar)) {
51459
51820
  zbarDisplay = zbar.style.display;
51460
51821
  zbar.style.display = 'none';
@@ -54990,6 +55351,7 @@ define('jsxgraph',[
54990
55351
  */
54991
55352
  _setARIA: function(container, attr) {
54992
55353
  var doc = attr.document || document,
55354
+ doc_glob,
54993
55355
  node_jsx, newNode, parent,
54994
55356
  id_label, id_description;
54995
55357
 
@@ -54998,18 +55360,19 @@ define('jsxgraph',[
54998
55360
  }
54999
55361
 
55000
55362
  node_jsx = doc.getElementById(container);
55363
+ doc_glob = node_jsx.ownerDocument; // This is the window.document element, needed below.
55001
55364
  parent = node_jsx.parentNode;
55002
55365
 
55003
55366
  id_label = container + '_ARIAlabel';
55004
55367
  id_description = container + '_ARIAdescription';
55005
55368
 
55006
- newNode = doc.createElement('div');
55369
+ newNode = doc_glob.createElement('div');
55007
55370
  newNode.innerHTML = attr.title;
55008
55371
  newNode.setAttribute('id', id_label);
55009
55372
  newNode.style.display = 'none';
55010
55373
  parent.insertBefore(newNode, node_jsx);
55011
55374
 
55012
- newNode = doc.createElement('div');
55375
+ newNode = doc_glob.createElement('div');
55013
55376
  newNode.innerHTML = attr.description;
55014
55377
  newNode.setAttribute('id', id_description);
55015
55378
  newNode.style.display = 'none';
@@ -55035,12 +55398,12 @@ define('jsxgraph',[
55035
55398
  }
55036
55399
 
55037
55400
  id = board.containerObj.getAttribute('aria-labelledby');
55038
- node = document.getElementById(id);
55401
+ node = doc.getElementById(id);
55039
55402
  if (node && node.parentNode) {
55040
55403
  node.parentNode.removeChild(node);
55041
55404
  }
55042
55405
  id = board.containerObj.getAttribute('aria-describedby');
55043
- node = document.getElementById(id);
55406
+ node = doc.getElementById(id);
55044
55407
  if (node && node.parentNode) {
55045
55408
  node.parentNode.removeChild(node);
55046
55409
  }
@@ -55306,7 +55669,8 @@ define('jsxgraph',[
55306
55669
  }
55307
55670
  };
55308
55671
 
55309
- // JessieScript/JessieCode startup: Search for script tags of type text/jessiescript and interprete them.
55672
+ // JessieScript/JessieCode startup:
55673
+ // Search for script tags of type text/jessiescript and interprete them.
55310
55674
  if (Env.isBrowser && typeof window === 'object' && typeof document === 'object') {
55311
55675
  Env.addEvent(window, 'load', function () {
55312
55676
  var type, i, j, div,
@@ -57018,7 +57382,7 @@ define('base/line',[
57018
57382
  if (this.parents.length < 3) { // Line through two points
57019
57383
  this.point1.handleSnapToGrid(true, true);
57020
57384
  this.point2.handleSnapToGrid(true, true);
57021
- } else if (Type.exists(pos)) { // Free line
57385
+ } else if (Type.exists(pos)) { // Free line
57022
57386
  sX = Type.evaluate(this.visProp.snapsizex);
57023
57387
  sY = Type.evaluate(this.visProp.snapsizey);
57024
57388
 
@@ -61697,8 +62061,35 @@ define('base/polygon',[
61697
62061
 
61698
62062
  /**
61699
62063
  * Add more points to the polygon. The new points will be inserted at the end.
61700
- * @param {JXG.Point} p Arbitrary number of points
62064
+ * The attributes of new border segments are set to the same values
62065
+ * as those used when the polygon was created.
62066
+ * If new vertices are supplied by coordinates, the default attributes of polygon
62067
+ * vertices are taken as their attributes. Therefore, the visual attributes of
62068
+ * new vertices and borders may have to be adapted afterwards.
62069
+ * @param {JXG.Point} p Arbitrary number of points or coordinate arrays
61701
62070
  * @returns {JXG.Polygon} Reference to the polygon
62071
+ * @example
62072
+ * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});
62073
+ * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});
62074
+ * var newPoint = board.create('point', [-1, -1]);
62075
+ * var newPoint2 = board.create('point', [-1, -2]);
62076
+ * pg.addPoints(newPoint, newPoint2, [1, -2]);
62077
+ *
62078
+ * </pre><div id="JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5" class="jxgbox" style="width: 300px; height: 300px;"></div>
62079
+ * <script type="text/javascript">
62080
+ * (function() {
62081
+ * var board = JXG.JSXGraph.initBoard('JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5',
62082
+ * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
62083
+ * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});
62084
+ * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});
62085
+ * var newPoint = board.create('point', [-1, -1]);
62086
+ * var newPoint2 = board.create('point', [-1, -2]);
62087
+ * pg.addPoints(newPoint, newPoint2, [1, -2]);
62088
+ *
62089
+ * })();
62090
+ *
62091
+ * </script><pre>
62092
+ *
61702
62093
  */
61703
62094
  addPoints: function (p) {
61704
62095
  var args = Array.prototype.slice.call(arguments);
@@ -61707,44 +62098,72 @@ define('base/polygon',[
61707
62098
  },
61708
62099
 
61709
62100
  /**
61710
- * Adds more points to the vertex list of the polygon, starting with index <tt><i</tt>
61711
- * @param {Number} idx The position where the new vertices are inserted, starting with 0.
61712
- * @param {JXG.Point} p Arbitrary number of points to insert.
62101
+ * Insert points to the vertex list of the polygon after index <tt><idx</tt>.
62102
+ * The attributes of new border segments are set to the same values
62103
+ * as those used when the polygon was created.
62104
+ * If new vertices are supplied by coordinates, the default attributes of polygon
62105
+ * vertices are taken as their attributes. Therefore, the visual attributes of
62106
+ * new vertices and borders may have to be adapted afterwards.
62107
+ *
62108
+ * @param {Number} idx The position after which the new vertices are inserted.
62109
+ * Setting idx to -1 inserts the new points at the front, i.e. at position 0.
62110
+ * @param {JXG.Point} p Arbitrary number of points or coordinate arrays to insert.
61713
62111
  * @returns {JXG.Polygon} Reference to the polygon object
62112
+ *
62113
+ * @example
62114
+ * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});
62115
+ * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});
62116
+ * var newPoint = board.create('point', [-1, -1]);
62117
+ * pg.insertPoints(0, newPoint, newPoint, [1, -2]);
62118
+ *
62119
+ * </pre><div id="JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca" class="jxgbox" style="width: 300px; height: 300px;"></div>
62120
+ * <script type="text/javascript">
62121
+ * (function() {
62122
+ * var board = JXG.JSXGraph.initBoard('JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca',
62123
+ * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
62124
+ * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});
62125
+ * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});
62126
+ * var newPoint = board.create('point', [-1, -1]);
62127
+ * pg.insertPoints(0, newPoint, newPoint, [1, -2]);
62128
+ *
62129
+ * })();
62130
+ *
62131
+ * </script><pre>
62132
+ *
61714
62133
  */
61715
62134
  insertPoints: function (idx, p) {
61716
- var i, npoints = [], tmp;
62135
+ var i, le;
61717
62136
 
61718
62137
  if (arguments.length === 0) {
61719
62138
  return this;
61720
62139
  }
61721
62140
 
61722
62141
 
61723
- if (idx < 0 || idx > this.vertices.length - 2) {
62142
+ if (idx < -1 || idx > this.vertices.length - 2) {
61724
62143
  return this;
61725
62144
  }
61726
62145
 
61727
- for (i = 1; i < arguments.length; i++) {
61728
- if (Type.isPoint(arguments[i])) {
61729
- npoints.push(arguments[i]);
61730
- }
62146
+ le = arguments.length - 1;
62147
+ for (i = 1; i < le + 1; i++) {
62148
+ this.vertices.splice(idx + i, 0,
62149
+ Type.providePoints(this.board, [arguments[i]], {}, 'polygon', ['vertices'])[0]
62150
+ );
62151
+ }
62152
+ if (idx === -1) {
62153
+ this.vertices[this.vertices.length - 1] = this.vertices[0];
61731
62154
  }
61732
-
61733
- tmp = this.vertices.slice(0, idx + 1).concat(npoints);
61734
- this.vertices = tmp.concat(this.vertices.slice(idx + 1));
61735
-
61736
62155
  if (this.withLines) {
61737
- tmp = this.borders.slice(0, idx);
61738
- this.board.removeObject(this.borders[idx]);
61739
-
61740
- for (i = 0; i < npoints.length; i++) {
61741
- tmp.push(this.board.create('segment', [this.vertices[idx + i], this.vertices[idx + i + 1]], this.attr_line));
62156
+ if (idx < 0) {
62157
+ this.borders[this.borders.length - 1].point2 = this.vertices[this.vertices.length - 1];
62158
+ } else {
62159
+ this.borders[idx].point2 = this.vertices[idx + 1];
62160
+ }
62161
+ for (i = idx + 1; i < idx + 1 + le; i++) {
62162
+ this.borders.splice(i, 0,
62163
+ this.board.create('segment', [this.vertices[i], this.vertices[i + 1]], this.attr_line)
62164
+ );
61742
62165
  }
61743
-
61744
- tmp.push(this.board.create('segment', [this.vertices[idx + npoints.length], this.vertices[idx + npoints.length + 1]], this.attr_line));
61745
- this.borders = tmp.concat(this.borders.slice(idx + 1));
61746
62166
  }
61747
-
61748
62167
  this.board.update();
61749
62168
 
61750
62169
  return this;
@@ -61759,7 +62178,7 @@ define('base/polygon',[
61759
62178
  var i, j, idx, nvertices = [], nborders = [],
61760
62179
  nidx = [], partition = [];
61761
62180
 
61762
- // partition:
62181
+ // Partition:
61763
62182
  // in order to keep the borders which could be recycled, we have to partition
61764
62183
  // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed,
61765
62184
  // the partitions are
@@ -61767,10 +62186,10 @@ define('base/polygon',[
61767
62186
  // this gives us the borders, that can be removed and the borders we have to create.
61768
62187
 
61769
62188
 
61770
- // remove the last vertex which is identical to the first
62189
+ // Remove the last vertex which is identical to the first
61771
62190
  this.vertices = this.vertices.slice(0, this.vertices.length - 1);
61772
62191
 
61773
- // collect all valid parameters as indices in nidx
62192
+ // Collect all valid parameters as indices in nidx
61774
62193
  for (i = 0; i < arguments.length; i++) {
61775
62194
  idx = arguments[i];
61776
62195
  if (Type.isPoint(idx)) {
@@ -61782,22 +62201,22 @@ define('base/polygon',[
61782
62201
  }
61783
62202
  }
61784
62203
 
61785
- // remove the polygon from each removed point's children
62204
+ // Remove the polygon from each removed point's children
61786
62205
  for (i = 0; i < nidx.length; i++) {
61787
62206
  this.vertices[nidx[i]].removeChild(this);
61788
62207
  }
61789
62208
 
61790
- // sort the elements to be eliminated
62209
+ // Sort the elements to be eliminated
61791
62210
  nidx = nidx.sort();
61792
62211
  nvertices = this.vertices.slice();
61793
62212
  nborders = this.borders.slice();
61794
62213
 
61795
- // initialize the partition
62214
+ // Initialize the partition
61796
62215
  if (this.withLines) {
61797
62216
  partition.push([nidx[nidx.length - 1]]);
61798
62217
  }
61799
62218
 
61800
- // run through all existing vertices and copy all remaining ones to nvertices
62219
+ // Run through all existing vertices and copy all remaining ones to nvertices,
61801
62220
  // compute the partition
61802
62221
  for (i = nidx.length - 1; i > -1; i--) {
61803
62222
  nvertices[nidx[i]] = -1;
@@ -61808,12 +62227,12 @@ define('base/polygon',[
61808
62227
  }
61809
62228
  }
61810
62229
 
61811
- // finalize the partition computation
62230
+ // Finalize the partition computation
61812
62231
  if (this.withLines) {
61813
62232
  partition[partition.length - 1][1] = nidx[0];
61814
62233
  }
61815
62234
 
61816
- // update vertices
62235
+ // Update vertices
61817
62236
  this.vertices = [];
61818
62237
  for (i = 0; i < nvertices.length; i++) {
61819
62238
  if (Type.isPoint(nvertices[i])) {
@@ -61824,7 +62243,7 @@ define('base/polygon',[
61824
62243
  this.vertices.push(this.vertices[0]);
61825
62244
  }
61826
62245
 
61827
- // delete obsolete and create missing borders
62246
+ // Delete obsolete and create missing borders
61828
62247
  if (this.withLines) {
61829
62248
  for (i = 0; i < partition.length; i++) {
61830
62249
  for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) {
@@ -68684,9 +69103,6 @@ define('element/composition',[
68684
69103
  b.addChild(t);
68685
69104
  }
68686
69105
 
68687
-
68688
-
68689
-
68690
69106
  t.elType = 'midpoint';
68691
69107
  t.setParents([a.id, b.id]);
68692
69108
 
@@ -68896,14 +69312,21 @@ define('element/composition',[
68896
69312
  };
68897
69313
 
68898
69314
  /**
68899
- * @class A parallel is a line through a given point with the same slope as a given line.
69315
+ * @class A parallel is a line through a given point with the same slope as a given line or
69316
+ * the line through two given point.
69317
+ * <p>
69318
+ * If original line is given as a JSXGraph line object, the resulting parallel line will be defined by the given point and an
69319
+ * infinitely far away point (an ideal point). That means, the line can not be shortened to a segment.
69320
+ * <p>
69321
+ * If the original line is given as two points, the resulting parallel line can be shortened to a a segment.
68900
69322
  * @pseudo
68901
69323
  * @name Parallel
68902
69324
  * @augments Line
68903
69325
  * @constructor
68904
69326
  * @type JXG.Line
68905
69327
  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
68906
- * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
69328
+ * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l. Alternative parameters are p1, p2, p: The
69329
+ * constructed line contains p and has the same slope as the line through p1 and p2.
68907
69330
  * @example
68908
69331
  * // Create a parallel
68909
69332
  * var p1 = board.create('point', [0.0, 2.0]);
@@ -68921,22 +69344,47 @@ define('element/composition',[
68921
69344
  * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
68922
69345
  * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
68923
69346
  * </script><pre>
69347
+ * @example
69348
+ * var p1, p2, p3, l1, pl1;
69349
+ *
69350
+ * p1 = board.create('point', [0.0, 2.0]);
69351
+ * p2 = board.create('point', [2.0, 1.0]);
69352
+ * l1 = board.create('line', [p1, p2]);
69353
+ *
69354
+ * p3 = board.create('point', [1.0, 3.0]);
69355
+ * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false});
69356
+ *
69357
+ * </pre><div id="JXGd643305d-20c3-4a88-91f9-8d0c4448594f" class="jxgbox" style="width: 300px; height: 300px;"></div>
69358
+ * <script type="text/javascript">
69359
+ * (function() {
69360
+ * var board = JXG.JSXGraph.initBoard('JXGd643305d-20c3-4a88-91f9-8d0c4448594f',
69361
+ * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
69362
+ * var p1, p2, p3, l1, pl1;
69363
+ *
69364
+ * p1 = board.create('point', [0.0, 2.0]);
69365
+ * p2 = board.create('point', [2.0, 1.0]);
69366
+ * l1 = board.create('line', [p1, p2]);
69367
+ *
69368
+ * p3 = board.create('point', [1.0, 3.0]);
69369
+ * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false});
69370
+ *
69371
+ * })();
69372
+ *
69373
+ * </script><pre>
69374
+ *
68924
69375
  */
68925
69376
  JXG.createParallel = function (board, parents, attributes) {
68926
- var p, pp, pl, li, i, attr;
69377
+ var p, pp, pl, li, i, attr, ty = 1;
68927
69378
 
68928
69379
  for (i = 0; i < parents.length; ++i) {
68929
69380
  parents[i] = board.select(parents[i]);
68930
69381
  }
68931
69382
  p = null;
68932
69383
  if (parents.length === 3) {
69384
+ // Line / segment through point parents[2] which is parallel to line through parents[0] and parents[1]
68933
69385
  parents = Type.providePoints(board, parents, attributes, 'point');
68934
- // line through point parents[2] which is parallel to line through parents[0] and parents[1]
68935
69386
  p = parents[2];
68936
- /** @ignore */
68937
- li = function () {
68938
- return Mat.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords);
68939
- };
69387
+ ty = 0;
68940
69388
  } else if (Type.isPointType(board, parents[0])) {
68941
69389
  // Parallel to line parents[1] through point parents[0]
68942
69390
  p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
@@ -68958,11 +69406,19 @@ define('element/composition',[
68958
69406
  }
68959
69407
 
68960
69408
  attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point');
68961
- pp = board.create('point', [
68962
- function () {
68963
- return Mat.crossProduct([1, 0, 0], li());
68964
- }
68965
- ], attr);
69409
+ if (ty === 1) {
69410
+ // Line is given by line element. The parallel line is
69411
+ // constructed as line through an ideal point.
69412
+ pp = board.create('point', [
69413
+ function () {
69414
+ return Mat.crossProduct([1, 0, 0], li());
69415
+ }
69416
+ ], attr);
69417
+ } else {
69418
+ // Line is given by two points. The parallel line is
69419
+ // constructed as line through two finite point.
69420
+ pp = board.create('parallelpoint', parents, attr);
69421
+ }
68966
69422
  pp.isDraggable = true;
68967
69423
 
68968
69424
  attr = Type.copyAttributes(attributes, board.options, 'parallel');
@@ -68996,31 +69452,33 @@ define('element/composition',[
68996
69452
  };
68997
69453
 
68998
69454
  /**
68999
- * @class An arrow parallel is a parallel segment with an arrow attached.
69455
+ * @class An arrow parallel is a segment with an arrow attached which is parallel through a given segment, given by its defining two points,
69456
+ * through a given point.
69457
+ * <p>
69000
69458
  * @pseudo
69001
69459
  * @constructor
69002
69460
  * @name Arrowparallel
69003
69461
  * @type Parallel
69004
69462
  * @augments Parallel
69005
69463
  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
69006
- * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l.
69464
+ * @param JXG.Point_JXG.Point_JXG.Point} p1, p2,p3 The constructed arrow contains p3 and has the same slope as the line through p1 and p2.
69007
69465
  * @example
69008
69466
  * // Create a parallel
69009
69467
  * var p1 = board.create('point', [0.0, 2.0]);
69010
69468
  * var p2 = board.create('point', [2.0, 1.0]);
69011
- * var l1 = board.create('line', [p1, p2]);
69469
+ * var l1 = board.create('segment', [p1, p2]);
69012
69470
  *
69013
69471
  * var p3 = board.create('point', [3.0, 3.0]);
69014
- * var pl1 = board.create('arrowparallel', [l1, p3]);
69472
+ * var pl1 = board.create('arrowparallel', [p1, p2, p3]);
69015
69473
  * </pre><div class="jxgbox" id="JXGeeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div>
69016
69474
  * <script type="text/javascript">
69017
69475
  * (function () {
69018
69476
  * var plex1_board = JXG.JSXGraph.initBoard('JXGeeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
69019
69477
  * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
69020
69478
  * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
69021
- * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
69479
+ * var plex1_l1 = plex1_board.create('segment', [plex1_p1, plex1_p2]);
69022
69480
  * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
69023
- * var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]);
69481
+ * var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_p1, plex1_p2, plex1_p3]);
69024
69482
  * })();
69025
69483
  * </script><pre>
69026
69484
  */
@@ -69467,7 +69925,7 @@ define('element/composition',[
69467
69925
  };
69468
69926
 
69469
69927
  /**
69470
- * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
69928
+ * @class Bisector lines are similar to {@link Bisector} but take two lines as parent elements. The resulting element is
69471
69929
  * a composition of two lines.
69472
69930
  * @pseudo
69473
69931
  * @constructor
@@ -72224,6 +72682,10 @@ define('element/slider',[
72224
72682
  p2.dump = false;
72225
72683
  l1.dump = false;
72226
72684
  l2.dump = false;
72685
+ if (withText) {
72686
+ t.dump = false;
72687
+ }
72688
+
72227
72689
 
72228
72690
  p3.elType = 'slider';
72229
72691
  p3.parents = parents;
@@ -72241,6 +72703,14 @@ define('element/slider',[
72241
72703
  p3.inherits.push(ti);
72242
72704
  }
72243
72705
 
72706
+ p3.getParents = function() {
72707
+ return [
72708
+ this.point1.coords.usrCoords.slice(1),
72709
+ this.point2.coords.usrCoords.slice(1),
72710
+ [this._smin, this.position * (this._smax - this._smin) + this._smin, this._smax]
72711
+ ];
72712
+ };
72713
+
72244
72714
  p3.baseline.on('up', function(evt) {
72245
72715
  var pos, c;
72246
72716
 
@@ -75969,7 +76439,7 @@ define('base/ticks',[
75969
76439
 
75970
76440
  // if value is Number
75971
76441
  if (Type.isNumber(value)) {
75972
- labelText = (Math.round(value * 1.e13) / 1.e13).toString();
76442
+ labelText = (Math.round(value * 1.e11) / 1.e11).toString();
75973
76443
  if (labelText.length > Type.evaluate(this.visProp.maxlabellength) ||
75974
76444
  labelText.indexOf('e') !== -1) {
75975
76445
 
@@ -76214,6 +76684,8 @@ define('base/ticks',[
76214
76684
  attr.id = this.id + ld.i + 'Label' + this.labelCounter;
76215
76685
 
76216
76686
  label = Text.createText(this.board, [ld.x, ld.y, ld.t], attr);
76687
+ this.addChild(label);
76688
+ label.setParents(this);
76217
76689
  label.isDraggable = false;
76218
76690
  label.dump = false;
76219
76691
  this.labels.push(label);
@@ -79755,7 +80227,13 @@ define('element/button',[
79755
80227
  * an SVG foreignObject container.
79756
80228
  * <p>
79757
80229
  * Instead of board.create('foreignobject') the shortcut board.create('fo') may be used.
79758
- *
80230
+ *
80231
+ * <p style="background-color:#dddddd; padding:10px"><b>NOTE:</b> In Safari up to version 15, a foreignObject does not obey the layer structure
80232
+ * if it contains &lt;video&gt; or &lt;iframe&gt; tags, as well as elements which are
80233
+ * positioned with <tt>position:absolute|relative|fixed</tt>. In this case, the foreignobject will be
80234
+ * "above" the JSXGraph construction.
80235
+ * </p>
80236
+ *
79759
80237
  * @pseudo
79760
80238
  * @description
79761
80239
  * @name ForeignObject
@@ -79893,6 +80371,2040 @@ define('element/button',[
79893
80371
  };
79894
80372
  });
79895
80373
 
80374
+ /*global JXG:true, define: true*/
80375
+
80376
+ define('options3d',[
80377
+ 'jxg', 'options'
80378
+ ], function (JXG, Options) {
80379
+
80380
+ "use strict";
80381
+
80382
+ JXG.extend(Options, {
80383
+
80384
+ infobox: {
80385
+ strokeColor: 'black'
80386
+ },
80387
+
80388
+ axes3d: {
80389
+ /**#@+
80390
+ * @visprop
80391
+ */
80392
+
80393
+ /**
80394
+ * Position of the main axes in a View3D element. Possible values are
80395
+ * 'center' and 'border'.
80396
+ *
80397
+ * @type String
80398
+ * @name View3D#axesPosition
80399
+ * @default 'center'
80400
+ */
80401
+ axesPosition: 'center', // Possible values: 'center', otherwise: border
80402
+
80403
+ // Main axes
80404
+
80405
+ /**
80406
+ * Attributes of the 3D x-axis.
80407
+ *
80408
+ * @type Line3D
80409
+ * @name View3D#xAxis
80410
+ */
80411
+ xAxis: { visible: true, point2: {name: 'x'}},
80412
+
80413
+ /**
80414
+ * Attributes of the 3D y-axis.
80415
+ *
80416
+ * @type Line3D
80417
+ * @name View3D#yAxis
80418
+ */
80419
+ yAxis: { visible: true, point2: {name: 'y'}},
80420
+
80421
+ /**
80422
+ * Attributes of the 3D z-axis.
80423
+ *
80424
+ * @type Line3D
80425
+ * @name View3D#zAxis
80426
+ */
80427
+ zAxis: { visible: true, point2: {name: 'z'}},
80428
+
80429
+ // Planes
80430
+ /**
80431
+ * Attributes of the 3D plane orthogonal to the x-axis at the "rear" of the cube.
80432
+ * @type Plane3D
80433
+ * @name View3D#xPlaneRear
80434
+ */
80435
+ xPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },
80436
+ /**
80437
+ * Attributes of the 3D plane orthogonal to the y-axis at the "rear" of the cube.
80438
+ * @type Plane3D
80439
+ * @name View3D#yPlaneRear
80440
+ */
80441
+ yPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },
80442
+ /**
80443
+ * Attributes of the 3D plane orthogonal to the z-axis at the "rear" of the cube.
80444
+ * @type Plane3D
80445
+ * @name View3D#zPlaneRear
80446
+ */
80447
+ zPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },
80448
+
80449
+ /**
80450
+ * Attributes of the 3D plane orthogonal to the x-axis at the "front" of the cube.
80451
+ * @type Plane3D
80452
+ * @name View3D#xPlaneFront
80453
+ */
80454
+ xPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },
80455
+ /**
80456
+ * Attributes of the 3D plane orthogonal to the y-axis at the "front" of the cube.
80457
+ * @type Plane3D
80458
+ * @name View3D#yPlaneFront
80459
+ */
80460
+ yPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },
80461
+ /**
80462
+ * Attributes of the 3D plane orthogonal to the z-axis at the "front" of the cube.
80463
+ * @type Plane3D
80464
+ * @name View3D#zPlaneFront
80465
+ */
80466
+ zPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },
80467
+
80468
+ // Axes on the planes
80469
+ /**
80470
+ * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the "rear" of the cube.
80471
+ * @type Plane3D
80472
+ * @name View3D#xPlaneRearYAxis
80473
+ */
80474
+ xPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80475
+ /**
80476
+ * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the "rear" of the cube.
80477
+ * @type Plane3D
80478
+ * @name View3D#xPlaneRearZAxis
80479
+ */
80480
+ xPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80481
+ /**
80482
+ * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the "front" of the cube.
80483
+ * @type Plane3D
80484
+ * @name View3D#xPlaneFrontYAxis
80485
+ */
80486
+ xPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80487
+ /**
80488
+ * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the "front" of the cube.
80489
+ * @type Plane3D
80490
+ * @name View3D#xPlaneFrontZAxis
80491
+ */
80492
+ xPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80493
+
80494
+ /**
80495
+ * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the "rear" of the cube.
80496
+ * @type Plane3D
80497
+ * @name View3D#yPlaneRearXAxis
80498
+ */
80499
+ yPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80500
+ /**
80501
+ * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the "rear" of the cube.
80502
+ * @type Plane3D
80503
+ * @name View3D#yPlaneRearZAxis
80504
+ */
80505
+ yPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80506
+ /**
80507
+ * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the "front" of the cube.
80508
+ * @type Plane3D
80509
+ * @name View3D#yPlaneFrontXAxis
80510
+ */
80511
+ yPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80512
+ /**
80513
+ * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the "front" of the cube.
80514
+ * @type Plane3D
80515
+ * @name View3D#yPlaneFrontZAxis
80516
+ */
80517
+ yPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80518
+
80519
+ /**
80520
+ * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the "rear" of the cube.
80521
+ * @type Plane3D
80522
+ * @name View3D#zPlaneRearXAxis
80523
+ */
80524
+ zPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80525
+ /**
80526
+ * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the "rear" of the cube.
80527
+ * @type Plane3D
80528
+ * @name View3D#zPlaneRearYAxis
80529
+ */
80530
+ zPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80531
+ /**
80532
+ * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the "front" of the cube.
80533
+ * @type Plane3D
80534
+ * @name View3D#zPlaneFrontXAxis
80535
+ */
80536
+ zPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},
80537
+ /**
80538
+ * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the "front" of the cube.
80539
+ * @type Plane3D
80540
+ * @name View3D#zPlaneFrontYAxis
80541
+ */
80542
+ zPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}
80543
+
80544
+ /**#@-*/
80545
+ },
80546
+
80547
+ axis3d: {
80548
+ highlight: false,
80549
+ strokecolor: 'black',
80550
+ strokeWidth: 1,
80551
+ tabindex: null,
80552
+
80553
+ point1: { visible: false, name: '' },
80554
+ point2: { visible: false, name: '', label: { visible: true } }
80555
+ },
80556
+
80557
+ mesh3d: {
80558
+ strokeWidth: 1,
80559
+ strokeColor: '#9a9a9a',
80560
+ strokeOpacity: 0.6,
80561
+ highlight: false,
80562
+ fillColor: '#9a9a9a',
80563
+ fillOpacity: 0.1,
80564
+ tabindex: null,
80565
+
80566
+ visible: 'inherit'
80567
+ },
80568
+
80569
+ line3d: {
80570
+ strokeWidth: 1,
80571
+ strokeColor: 'black',
80572
+ fixed: true,
80573
+ tabindex: null,
80574
+
80575
+ gradient: 'linear',
80576
+ gradientSecondColor: '#ffffff',
80577
+
80578
+ point1: {visible: false, name: ''},
80579
+ point2: {visible: false, name: ''}
80580
+ },
80581
+
80582
+ plane3d: {
80583
+ strokeWidth: 0,
80584
+ strokeColor: 'black',
80585
+ strokeOpacity: 1,
80586
+ highlight: false,
80587
+ tabindex: null,
80588
+
80589
+ gradient: 'linear',
80590
+ gradientSecondColor: '#ffffff',
80591
+ gradientAngle: Math.PI,
80592
+ fillColor: '#a7a7a7',
80593
+ fillOpacity: 0.6
80594
+ },
80595
+
80596
+ point3d: {
80597
+ strokeWidth: 0,
80598
+ gradient: 'radial',
80599
+ gradientSecondColor: '#555555',
80600
+ fillColor: 'yellow',
80601
+ highlightStrokeColor: '#555555'
80602
+ },
80603
+
80604
+ surface3d: {
80605
+ /**#@+
80606
+ * @visprop
80607
+ */
80608
+
80609
+ highlight: false,
80610
+ tabindex: -1,
80611
+ strokeWidth: 1,
80612
+
80613
+ /**
80614
+ * Number of intervals the mesh is divided into in direction of parameter u.
80615
+ * @type Number
80616
+ * @name Surface3D#stepsU
80617
+ */
80618
+ stepsU: 30,
80619
+
80620
+ /**
80621
+ * Number of intervals the mesh is divided into in direction of parameter v.
80622
+ * @type Number
80623
+ * @name Surface3D#stepsV
80624
+ */
80625
+ stepsV: 30
80626
+
80627
+ /**#@-*/
80628
+ },
80629
+
80630
+ view3d: {
80631
+ needsRegularUpdate: true
80632
+ }
80633
+
80634
+ });
80635
+
80636
+ return JXG.Options;
80637
+ });
80638
+
80639
+
80640
+ /*
80641
+ Copyright 2008-2022
80642
+ Matthias Ehmann,
80643
+ Carsten Miller,
80644
+ Andreas Walter,
80645
+ Alfred Wassermann
80646
+
80647
+ This file is part of JSXGraph.
80648
+
80649
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
80650
+
80651
+ You can redistribute it and/or modify it under the terms of the
80652
+
80653
+ * GNU Lesser General Public License as published by
80654
+ the Free Software Foundation, either version 3 of the License, or
80655
+ (at your option) any later version
80656
+ OR
80657
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
80658
+
80659
+ JSXGraph is distributed in the hope that it will be useful,
80660
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
80661
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80662
+ GNU Lesser General Public License for more details.
80663
+
80664
+ You should have received a copy of the GNU Lesser General Public License and
80665
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
80666
+ and <http://opensource.org/licenses/MIT/>.
80667
+ */
80668
+ /*global JXG:true, define: true*/
80669
+
80670
+ define('3d/threed',['jxg'
80671
+ ], function (JXG) {
80672
+ "use strict";
80673
+
80674
+ JXG.ThreeD = {};
80675
+
80676
+ return JXG.ThreeD;
80677
+ });
80678
+
80679
+ /*
80680
+ Copyright 2008-2022
80681
+ Matthias Ehmann,
80682
+ Carsten Miller,
80683
+ Andreas Walter,
80684
+ Alfred Wassermann
80685
+
80686
+ This file is part of JSXGraph.
80687
+
80688
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
80689
+
80690
+ You can redistribute it and/or modify it under the terms of the
80691
+
80692
+ * GNU Lesser General Public License as published by
80693
+ the Free Software Foundation, either version 3 of the License, or
80694
+ (at your option) any later version
80695
+ OR
80696
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
80697
+
80698
+ JSXGraph is distributed in the hope that it will be useful,
80699
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
80700
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80701
+ GNU Lesser General Public License for more details.
80702
+
80703
+ You should have received a copy of the GNU Lesser General Public License and
80704
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
80705
+ and <http://opensource.org/licenses/MIT/>.
80706
+ */
80707
+ /*global JXG:true, define: true*/
80708
+
80709
+ define('3d/view3d',['jxg', 'options', 'base/constants', 'utils/type', 'math/math', 'base/element', '3d/threed',
80710
+ ], function (JXG, Options, Const, Type, Mat, GeometryElement, ThreeD) {
80711
+ "use strict";
80712
+
80713
+ ThreeD.View3D = function (board, parents, attributes) {
80714
+ var bbox3d, coords, size;
80715
+ this.constructor(board, attributes, Const.OBJECT_TYPE_VIEW3D, Const.OBJECT_CLASS_CURVE);
80716
+
80717
+ bbox3d = parents[2]; // [[x1, x2], [y1,y2], [z1,z2]]
80718
+ coords = parents[0]; // llft corner
80719
+ size = parents[1]; // [w, h]
80720
+
80721
+ /**
80722
+ * "Namespace" for all 3D handling
80723
+ */
80724
+ this.D3 = {};
80725
+
80726
+ /**
80727
+ * An associative array containing all geometric objects belonging to the view.
80728
+ * Key is the id of the object and value is a reference to the object.
80729
+ * @type Object
80730
+ */
80731
+ this.D3.objects = {};
80732
+
80733
+ /**
80734
+ * An array containing all geometric objects in this view in the order of construction.
80735
+ * @type Array
80736
+ */
80737
+ this.D3.objectsList = [];
80738
+
80739
+ /**
80740
+ * @type {Object} contains the axes of the view or null
80741
+ * @default null
80742
+ */
80743
+ this.D3.defaultAxes = null;
80744
+
80745
+ /**
80746
+ * 3D-to-2D transformation matrix
80747
+ * @type {Array} 3 x 4 mattrix
80748
+ */
80749
+ this.D3.matrix = [
80750
+ [1, 0, 0, 0],
80751
+ [0, 1, 0, 0],
80752
+ [0, 0, 1, 0]
80753
+ ];
80754
+
80755
+ // Bounding box (cube) [[x1, x2], [y1,y2], [z1,z2]]:
80756
+ this.D3.bbox3d = bbox3d;
80757
+ this.D3.coords = coords;
80758
+ this.D3.size = size;
80759
+
80760
+ /**
80761
+ * Distance of the view to the origin. In other words, its
80762
+ * the radius of the sphere where the camera sits.
80763
+ */
80764
+ this.D3.r = -1;
80765
+
80766
+ this.timeoutAzimuth = null;
80767
+
80768
+ this.id = this.board.setId(this, 'V');
80769
+ this.board.finalizeAdding(this);
80770
+ this.elType = 'view3d';
80771
+ this.methodMap = Type.deepCopy(this.methodMap, {
80772
+ });
80773
+ };
80774
+ ThreeD.View3D.prototype = new GeometryElement();
80775
+
80776
+ JXG.extend(ThreeD.View3D.prototype, /** @lends ThreeD.View3D.prototype */ {
80777
+ create: function (elementType, parents, attributes) {
80778
+ var prefix = [],
80779
+ is3D = false,
80780
+ el;
80781
+
80782
+ if (elementType.indexOf('3d') > 0) {
80783
+ is3D = true;
80784
+ prefix.push(this);
80785
+ }
80786
+ el = this.board.create(elementType, prefix.concat(parents), attributes);
80787
+ if (true || is3D) {
80788
+ this.add(el);
80789
+ }
80790
+ return el;
80791
+ },
80792
+
80793
+ add: function (el) {
80794
+ this.D3.objects[el.id] = el;
80795
+ this.D3.objectsList.push(el);
80796
+ },
80797
+
80798
+ /**
80799
+ * Update 3D-to-2D transformation matrix with the actual
80800
+ * elevation and azimuth angles.
80801
+ *
80802
+ * @private
80803
+ */
80804
+ update: function () {
80805
+ var D3 = this.D3,
80806
+ e, r, a, f, mat;
80807
+
80808
+ if (!Type.exists(D3.el_slide) ||
80809
+ !Type.exists(D3.az_slide) ||
80810
+ !this.needsUpdate) {
80811
+ return this;
80812
+ }
80813
+
80814
+ e = D3.el_slide.Value();
80815
+ r = D3.r;
80816
+ a = D3.az_slide.Value();
80817
+ f = r * Math.sin(e);
80818
+ mat = [[1, 0, 0,], [0, 1, 0], [0, 0, 1]];
80819
+
80820
+ D3.matrix = [
80821
+ [1, 0, 0, 0],
80822
+ [0, 1, 0, 0],
80823
+ [0, 0, 1, 0]
80824
+ ];
80825
+
80826
+ D3.matrix[1][1] = r * Math.cos(a);
80827
+ D3.matrix[1][2] = -r * Math.sin(a);
80828
+ D3.matrix[2][1] = f * Math.sin(a);
80829
+ D3.matrix[2][2] = f * Math.cos(a);
80830
+ D3.matrix[2][3] = Math.cos(e);
80831
+
80832
+ if (true) {
80833
+ mat[1][1] = D3.size[0] / (D3.bbox3d[0][1] - D3.bbox3d[0][0]); // w / d_x
80834
+ mat[2][2] = D3.size[1] / (D3.bbox3d[1][1] - D3.bbox3d[1][0]); // h / d_y
80835
+ mat[1][0] = D3.coords[0] - mat[1][1] * D3.bbox3d[0][0]; // llft_x
80836
+ mat[2][0] = D3.coords[1] - mat[2][2] * D3.bbox3d[1][0]; // llft_y
80837
+
80838
+ D3.matrix = Mat.matMatMult(mat, D3.matrix);
80839
+ }
80840
+
80841
+ return this;
80842
+ },
80843
+
80844
+ updateRenderer: function () {
80845
+ this.needsUpdate = false;
80846
+ return this;
80847
+ },
80848
+
80849
+ /**
80850
+ * Project 3D coordinates to 2D board coordinates
80851
+ * The 3D coordinates are provides as three numbers x, y, z or one array of length 3.
80852
+ *
80853
+ * @param {Number|Array} x
80854
+ * @param {[Number]} y
80855
+ * @param {[Number]} z
80856
+ * @returns {Array} Array of length 3 containing the projection on to the board
80857
+ * in homogeneous user coordinates.
80858
+ */
80859
+ project3DTo2D: function (x, y, z) {
80860
+ var vec;
80861
+ if (arguments.length === 3) {
80862
+ vec = [1, x, y, z];
80863
+ } else {
80864
+ // Argument is an array
80865
+ if (x.length === 3) {
80866
+ vec = [1].concat(x);
80867
+ } else {
80868
+ vec = x;
80869
+ }
80870
+ }
80871
+ return Mat.matVecMult(this.D3.matrix, vec);
80872
+ },
80873
+
80874
+ /**
80875
+ * Project a 2D coordinate to the plane through the origin
80876
+ * defined by its normal vector `normal`.
80877
+ *
80878
+ * @param {JXG.Point} point
80879
+ * @param {Array} normal
80880
+ * @returns Array of length 4 containing the projected
80881
+ * point in homogeneous coordinates.
80882
+ */
80883
+ project2DTo3DPlane: function (point, normal, foot) {
80884
+ var mat, rhs, d, le,
80885
+ n = normal.slice(1),
80886
+ sol = [1, 0, 0, 0];
80887
+
80888
+ foot = foot || [1, 0, 0, 0];
80889
+ le = Mat.norm(n, 3);
80890
+ d = Mat.innerProduct(foot.slice(1), n, 3) / le;
80891
+
80892
+ mat = this.D3.matrix.slice(0, 3); // True copy
80893
+ mat.push([0].concat(n));
80894
+
80895
+ // 2D coordinates of point:
80896
+ rhs = point.coords.usrCoords.concat([d]);
80897
+ try {
80898
+ // Prevent singularity in case elevation angle is zero
80899
+ if (mat[2][3] === 1.0) {
80900
+ mat[2][1] = mat[2][2] = Mat.eps * 0.001;
80901
+ }
80902
+ sol = Mat.Numerics.Gauss(mat, rhs);
80903
+ } catch (err) {
80904
+ sol = [0, NaN, NaN, NaN];
80905
+ }
80906
+
80907
+ return sol;
80908
+ },
80909
+
80910
+ project3DToCube: function (c3d) {
80911
+ var cube = this.D3.bbox3d;
80912
+ if (c3d[1] < cube[0][0]) { c3d[1] = cube[0][0]; }
80913
+ if (c3d[1] > cube[0][1]) { c3d[1] = cube[0][1]; }
80914
+ if (c3d[2] < cube[1][0]) { c3d[2] = cube[1][0]; }
80915
+ if (c3d[2] > cube[1][1]) { c3d[2] = cube[1][1]; }
80916
+ if (c3d[3] < cube[2][0]) { c3d[3] = cube[2][0]; }
80917
+ if (c3d[3] > cube[2][1]) { c3d[3] = cube[2][1]; }
80918
+
80919
+ return c3d;
80920
+ },
80921
+
80922
+ intersectionLineCube: function (p, d, r) {
80923
+ var rnew, i, r0, r1;
80924
+
80925
+ rnew = r;
80926
+ for (i = 0; i < 3; i++) {
80927
+ if (d[i] !== 0) {
80928
+ r0 = (this.D3.bbox3d[i][0] - p[i]) / d[i];
80929
+ r1 = (this.D3.bbox3d[i][1] - p[i]) / d[i];
80930
+ if (r < 0) {
80931
+ rnew = Math.max(rnew, Math.min(r0, r1));
80932
+ } else {
80933
+ rnew = Math.min(rnew, Math.max(r0, r1));
80934
+ }
80935
+ }
80936
+ }
80937
+ return rnew;
80938
+ },
80939
+
80940
+ isInCube: function (q) {
80941
+ return q[0] > this.D3.bbox3d[0][0] - Mat.eps && q[0] < this.D3.bbox3d[0][1] + Mat.eps &&
80942
+ q[1] > this.D3.bbox3d[1][0] - Mat.eps && q[1] < this.D3.bbox3d[1][1] + Mat.eps &&
80943
+ q[2] > this.D3.bbox3d[2][0] - Mat.eps && q[2] < this.D3.bbox3d[2][1] + Mat.eps;
80944
+ },
80945
+
80946
+ /**
80947
+ *
80948
+ * @param {*} plane1
80949
+ * @param {*} plane2
80950
+ * @param {*} d
80951
+ * @returns Array of length 2 containing the coordinates of the defining points of
80952
+ * of the intersection segment.
80953
+ */
80954
+ intersectionPlanePlane: function(plane1, plane2, d) {
80955
+ var ret = [[], []],
80956
+ p, dir, r, q;
80957
+
80958
+ d = d || plane2.D3.d;
80959
+
80960
+ p = Mat.Geometry.meet3Planes(plane1.D3.normal, plane1.D3.d, plane2.D3.normal, d,
80961
+ Mat.crossProduct(plane1.D3.normal, plane2.D3.normal), 0);
80962
+ dir = Mat.Geometry.meetPlanePlane(plane1.D3.dir1, plane1.D3.dir2, plane2.D3.dir1, plane2.D3.dir2);
80963
+ r = this.intersectionLineCube(p, dir, Infinity);
80964
+ q = Mat.axpy(r, dir, p);
80965
+ if (this.isInCube(q)) {
80966
+ ret[0] = q;
80967
+ }
80968
+ r = this.intersectionLineCube(p, dir, -Infinity);
80969
+ q = Mat.axpy(r, dir, p);
80970
+ if (this.isInCube(q) ) {
80971
+ ret[1] = q;
80972
+ }
80973
+ return ret;
80974
+ },
80975
+
80976
+ getMesh: function (X, Y, Z, interval_u, interval_v) {
80977
+ var i_u, i_v, u, v, c2d,
80978
+ delta_u, delta_v,
80979
+ p = [0, 0, 0],
80980
+ steps_u = interval_u[2],
80981
+ steps_v = interval_v[2],
80982
+
80983
+ dataX = [],
80984
+ dataY = [];
80985
+
80986
+ delta_u = (Type.evaluate(interval_u[1]) - Type.evaluate(interval_u[0])) / (steps_u);
80987
+ delta_v = (Type.evaluate(interval_v[1]) - Type.evaluate(interval_v[0])) / (steps_v);
80988
+
80989
+ for (i_u = 0; i_u <= steps_u; i_u++) {
80990
+ u = interval_u[0] + delta_u * i_u;
80991
+ for (i_v = 0; i_v <= steps_v; i_v++) {
80992
+ v = interval_v[0] + delta_v * i_v;
80993
+ p[0] = X(u, v);
80994
+ p[1] = Y(u, v);
80995
+ p[2] = Z(u, v);
80996
+ c2d = this.project3DTo2D(p);
80997
+ dataX.push(c2d[1]);
80998
+ dataY.push(c2d[2]);
80999
+ }
81000
+ dataX.push(NaN);
81001
+ dataY.push(NaN);
81002
+ }
81003
+
81004
+ for (i_v = 0; i_v <= steps_v; i_v++) {
81005
+ v = interval_v[0] + delta_v * i_v;
81006
+ for (i_u = 0; i_u <= steps_u; i_u++) {
81007
+ u = interval_u[0] + delta_u * i_u;
81008
+ p[0] = X(u, v);
81009
+ p[1] = Y(u, v);
81010
+ p[2] = Z(u, v);
81011
+ c2d = this.project3DTo2D(p);
81012
+ dataX.push(c2d[1]);
81013
+ dataY.push(c2d[2]);
81014
+ }
81015
+ dataX.push(NaN);
81016
+ dataY.push(NaN);
81017
+ }
81018
+
81019
+ return [dataX, dataY];
81020
+ },
81021
+
81022
+ animateAzimuth: function () {
81023
+ var s = this.D3.az_slide._smin,
81024
+ e = this.D3.az_slide._smax,
81025
+ sdiff = e - s,
81026
+ newVal = this.D3.az_slide.Value() + 0.1;
81027
+
81028
+ this.D3.az_slide.position = ((newVal - s) / sdiff);
81029
+ if (this.D3.az_slide.position > 1) {
81030
+ this.D3.az_slide.position = 0.0;
81031
+ }
81032
+ this.board.update();
81033
+
81034
+ this.timeoutAzimuth = setTimeout(function () { this.animateAzimuth(); }.bind(this), 200);
81035
+ },
81036
+
81037
+ stopAzimuth: function () {
81038
+ clearTimeout(this.timeoutAzimuth);
81039
+ this.timeoutAzimuth = null;
81040
+ }
81041
+ });
81042
+
81043
+ /**
81044
+ * @class This element creates a 3D view.
81045
+ * @pseudo
81046
+ * @description A View3D element provides the container and the methods to create and display 3D elements.
81047
+ * It is contained in a JSXGraph board.
81048
+ * @name View3D
81049
+ * @augments JXG.View3D
81050
+ * @constructor
81051
+ * @type Object
81052
+ * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
81053
+ * @param {Array_Array_Array} lower,dim,cube Here, lower is an array of the form [x, y] and
81054
+ * dim is an array of the form [w, h].
81055
+ * The arrays [x, y] and [w, h] define the 2D frame into which the 3D cube is
81056
+ * (roughly) projected.
81057
+ * cube is an array of the form [[x1, x2], [y1, y2], [z1, z2]]
81058
+ * which determines the coordinate ranges of the 3D cube.
81059
+ *
81060
+ * @example
81061
+ * var bound = [-5, 5];
81062
+ * var view = board.create('view3d',
81063
+ * [[-6, -3],
81064
+ * [8, 8],
81065
+ * [bound, bound, bound]],
81066
+ * {
81067
+ * // Main axes
81068
+ * axesPosition: 'center',
81069
+ * xAxis: { strokeColor: 'blue', strokeWidth: 3},
81070
+ *
81071
+ * // Planes
81072
+ * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}},
81073
+ * yPlaneFront: { visible: true, fillColor: 'blue'},
81074
+ *
81075
+ * // Axes on planes
81076
+ * xPlaneRearYAxis: {strokeColor: 'red'},
81077
+ * xPlaneRearZAxis: {strokeColor: 'red'},
81078
+ *
81079
+ * yPlaneFrontXAxis: {strokeColor: 'blue'},
81080
+ * yPlaneFrontZAxis: {strokeColor: 'blue'},
81081
+ *
81082
+ * zPlaneFrontXAxis: {visible: false},
81083
+ * zPlaneFrontYAxis: {visible: false}
81084
+ * });
81085
+ *
81086
+ * </pre><div id="JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7" class="jxgbox" style="width: 500px; height: 500px;"></div>
81087
+ * <script type="text/javascript">
81088
+ * (function() {
81089
+ * var board = JXG.JSXGraph.initBoard('JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7',
81090
+ * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});
81091
+ * var bound = [-5, 5];
81092
+ * var view = board.create('view3d',
81093
+ * [[-6, -3], [8, 8],
81094
+ * [bound, bound, bound]],
81095
+ * {
81096
+ * // Main axes
81097
+ * axesPosition: 'center',
81098
+ * xAxis: { strokeColor: 'blue', strokeWidth: 3},
81099
+ *
81100
+ * // Planes
81101
+ * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}},
81102
+ * yPlaneFront: { visible: true, fillColor: 'blue'},
81103
+ *
81104
+ * // Axes on planes
81105
+ * xPlaneRearYAxis: {strokeColor: 'red'},
81106
+ * xPlaneRearZAxis: {strokeColor: 'red'},
81107
+ *
81108
+ * yPlaneFrontXAxis: {strokeColor: 'blue'},
81109
+ * yPlaneFrontZAxis: {strokeColor: 'blue'},
81110
+ *
81111
+ * zPlaneFrontXAxis: {visible: false},
81112
+ * zPlaneFrontYAxis: {visible: false}
81113
+ * });
81114
+ *
81115
+ * })();
81116
+ *
81117
+ * </script><pre>
81118
+ *
81119
+ */
81120
+ ThreeD.createView3D = function (board, parents, attributes) {
81121
+ var view, frame, attr,
81122
+ x, y, w, h,
81123
+ coords = parents[0], // llft corner
81124
+ size = parents[1]; // [w, h]
81125
+
81126
+ attr = Type.copyAttributes(attributes, board.options, 'view3d');
81127
+ view = new ThreeD.View3D(board, parents, attr);
81128
+ view.defaultAxes = view.create('axes3d', parents, attributes);
81129
+
81130
+ x = coords[0];
81131
+ y = coords[1];
81132
+ w = size[0];
81133
+ h = size[1];
81134
+
81135
+ /*
81136
+ * Frame around the view object
81137
+ */
81138
+ if (false) {
81139
+ frame = board.create('polygon', [
81140
+ [coords[0], coords[1] + size[1]], // ulft
81141
+ [coords[0], coords[1]], // llft
81142
+ [coords[0] + size[0], coords[1]], // lrt
81143
+ [coords[0] + size[0], coords[1] + size[1]], // urt
81144
+ ], {
81145
+ fillColor: 'none',
81146
+ highlightFillColor: 'none',
81147
+ highlight: false,
81148
+ vertices: {
81149
+ fixed: true,
81150
+ visible: false
81151
+ },
81152
+ borders: {
81153
+ strokeColor: 'black',
81154
+ highlight: false,
81155
+ strokeWidth: 0.5,
81156
+ dash: 4
81157
+ }
81158
+ });
81159
+ //view.add(frame);
81160
+ }
81161
+
81162
+ /**
81163
+ * Slider to adapt azimuth angle
81164
+ */
81165
+ view.D3.az_slide = board.create('slider', [[x - 1, y - 2], [x + w + 1, y - 2], [0, 1.0, 2 * Math.PI]], {
81166
+ style: 6, name: 'az',
81167
+ point1: { frozen: true },
81168
+ point2: { frozen: true }
81169
+ });
81170
+
81171
+ /**
81172
+ * Slider to adapt elevation angle
81173
+ */
81174
+ view.D3.el_slide = board.create('slider', [[x - 1, y], [x - 1, y + h], [0, 0.30, Math.PI / 2]], {
81175
+ style: 6, name: 'el',
81176
+ point1: { frozen: true },
81177
+ point2: { frozen: true }
81178
+ });
81179
+
81180
+ view.board.highlightInfobox = function (x, y, el) {
81181
+ var d;
81182
+
81183
+ if (Type.exists(el.D3)) {
81184
+ d = Type.evaluate(el.visProp.infoboxdigits);
81185
+ if (d === 'auto') {
81186
+ view.board.highlightCustomInfobox('(' +
81187
+ Type.autoDigits(el.D3.X()) + ' | ' +
81188
+ Type.autoDigits(el.D3.Y()) + ' | ' +
81189
+ Type.autoDigits(el.D3.Z()) + ')', el);
81190
+ } else {
81191
+ view.board.highlightCustomInfobox('(' +
81192
+ Type.toFixed(el.D3.X(), d) + ' | ' +
81193
+ Type.toFixed(el.D3.Y(), d) + ' | ' +
81194
+ Type.toFixed(el.D3.Z(), d) + ')', el);
81195
+ }
81196
+ } else {
81197
+ view.board.highlightCustomInfobox('(' + x + ', ' + y + ')', el);
81198
+ }
81199
+ };
81200
+
81201
+ return view;
81202
+ };
81203
+ JXG.registerElement('view3d', ThreeD.createView3D);
81204
+
81205
+ return ThreeD.View3D;
81206
+ });
81207
+
81208
+
81209
+ /*
81210
+ Copyright 2008-2022
81211
+ Matthias Ehmann,
81212
+ Carsten Miller,
81213
+ Andreas Walter,
81214
+ Alfred Wassermann
81215
+
81216
+ This file is part of JSXGraph.
81217
+
81218
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
81219
+
81220
+ You can redistribute it and/or modify it under the terms of the
81221
+
81222
+ * GNU Lesser General Public License as published by
81223
+ the Free Software Foundation, either version 3 of the License, or
81224
+ (at your option) any later version
81225
+ OR
81226
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
81227
+
81228
+ JSXGraph is distributed in the hope that it will be useful,
81229
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
81230
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81231
+ GNU Lesser General Public License for more details.
81232
+
81233
+ You should have received a copy of the GNU Lesser General Public License and
81234
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
81235
+ and <http://opensource.org/licenses/MIT/>.
81236
+ */
81237
+ /*global JXG:true, define: true*/
81238
+
81239
+ /**
81240
+ * Create axes and rear and front walls of the
81241
+ * view3d bounding box bbox3d.
81242
+ */
81243
+ define('3d/box3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d'
81244
+ ], function (JXG, Type, Mat, Geometry, ThreeD) {
81245
+ "use strict";
81246
+
81247
+ ThreeD.createAxes = function (board, parents, attributes) {
81248
+ var view = parents[0],
81249
+ i, j, k, i1, i2,
81250
+ attr,
81251
+ pos,
81252
+ directions = ['x', 'y', 'z'],
81253
+ suffixAxis = 'Axis',
81254
+ dir, dir1,
81255
+ sides = ['Rear', 'Front'],
81256
+ rear = [0, 0, 0], // x, y, z
81257
+ front = [0, 0, 0], // x, y, z
81258
+ from, to,
81259
+ vec1, vec2, range1, range2,
81260
+ na, na_parent,
81261
+ ticks_attr,
81262
+ axes = {};
81263
+
81264
+ if (Type.exists(view.D3)) {
81265
+ for (i = 0; i < directions.length; i++) {
81266
+ rear[i] = view.D3.bbox3d[i][0];
81267
+ front[i] = view.D3.bbox3d[i][1];
81268
+ }
81269
+ } else {
81270
+ for (i = 0; i < directions.length; i++) {
81271
+ rear[i] = parents[1][i];
81272
+ front[i] = parents[2][1];
81273
+ }
81274
+ }
81275
+
81276
+ // Main 3D axes
81277
+ attr = Type.copyAttributes(attributes, board.options, 'axes3d');
81278
+ pos = attr.axesposition;
81279
+ for (i = 0; i < directions.length; i++) {
81280
+ // Run through ['x', 'y', 'z']
81281
+ dir = directions[i];
81282
+ na = dir + suffixAxis;
81283
+
81284
+ if (pos === 'center') { // Axes centered
81285
+ from = [0, 0, 0];
81286
+ to = [0, 0, 0];
81287
+ to[i] = front[i];
81288
+ axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]);
81289
+ } else {
81290
+ na += 'Border'; // Axes bordered
81291
+ from = rear.slice();
81292
+ to = front.slice();
81293
+ if (i === 2) {
81294
+ from[1] = front[1];
81295
+ to[0] = rear[0];
81296
+ } else {
81297
+ from[i] = front[i];
81298
+ to[2] = rear[2];
81299
+ }
81300
+ to[i] = front[i];
81301
+ attr[na.toLowerCase()].lastArrow = false;
81302
+ axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]);
81303
+
81304
+ // TODO
81305
+ ticks_attr = {
81306
+ visible: true, // Für z-Ticks wird path nicht berechnet
81307
+ minorTicks: 0,
81308
+ tickEndings: [0, 1],
81309
+ drawLabels: false
81310
+ };
81311
+ if (i === 2) {
81312
+ ticks_attr.tickEndings = [1, 0];
81313
+ }
81314
+ axes[na + 'Ticks'] = view.create('ticks', [axes[na], 1], ticks_attr);
81315
+ }
81316
+ }
81317
+
81318
+ // Origin (2D point)
81319
+ axes.O = board.create('intersection', [
81320
+ axes[directions[0] + suffixAxis],
81321
+ axes[directions[1] + suffixAxis]
81322
+ ], {
81323
+ name: '', visible: false, withLabel: false
81324
+ });
81325
+
81326
+ // Front and rear planes
81327
+ for (i = 0; i < directions.length; i++) {
81328
+ // Run through ['x', 'y', 'z']
81329
+ i1 = (i + 1) % 3;
81330
+ i2 = (i + 2) % 3;
81331
+
81332
+ dir = directions[i];
81333
+ for (j = 0; j < sides.length; j++) {
81334
+ // Run through ['Rear', 'Front']
81335
+
81336
+ from = [0, 0, 0];
81337
+ from[i] = (j === 0) ? rear[i] : front[i];
81338
+ vec1 = [0, 0, 0];
81339
+ vec2 = [0, 0, 0];
81340
+ vec1[i1] = 1;
81341
+ vec2[i2] = 1;
81342
+ range1 = [rear[i1], front[i1]];
81343
+ range2 = [rear[i2], front[i2]];
81344
+ na = dir + 'Plane' + sides[j];
81345
+
81346
+ attr = Type.copyAttributes(attributes, board.options, 'axes3d', na);
81347
+ axes[na] =
81348
+ view.create('plane3d', [from, vec1, vec2, range1, range2], attr);
81349
+ axes[na].D3.elType = 'axisplane3d';
81350
+ }
81351
+ }
81352
+
81353
+ // Axes on front and rear planes
81354
+ for (i = 0; i < directions.length; i++) {
81355
+ // Run through ['x', 'y', 'z']
81356
+ dir = directions[i];
81357
+ for (j = 0; j < sides.length; j++) {
81358
+ for (k = 1; k <= 2; k++) {
81359
+ i1 = (i + k) % 3;
81360
+ dir1 = directions[i1];
81361
+ na = dir + 'Plane' + sides[j] + dir1.toUpperCase() + 'Axis';
81362
+ na_parent = dir + 'Plane' + sides[j];
81363
+
81364
+ from = [0, 0, 0];
81365
+ to = [0, 0, 0];
81366
+ from[i] = to[i] = (j === 0) ? rear[i] : front[i];
81367
+
81368
+ from[i1] = rear[i1];
81369
+ to[i1] = front[i1];
81370
+
81371
+ attr = Type.copyAttributes(attributes, board.options, 'axes3d', na);
81372
+ axes[na] = view.create('axis3d', [from, to], attr);
81373
+ axes[na_parent].addChild(axes[na]);
81374
+ axes[na_parent].inherits.push(axes[na]);
81375
+ }
81376
+ }
81377
+ }
81378
+
81379
+ return axes;
81380
+ };
81381
+ JXG.registerElement('axes3d', ThreeD.createAxes);
81382
+
81383
+ ThreeD.createAxis = function (board, parents, attributes) {
81384
+ var view = parents[0],
81385
+ attr,
81386
+ start = parents[1],
81387
+ end = parents[2],
81388
+ el_start, el_end, el;
81389
+
81390
+ // Use 2D points to create axis
81391
+ attr = Type.copyAttributes(attributes.point1, board.options, 'axis3d', 'point1');
81392
+ el_start = board.create('point', [
81393
+ (function (xx, yy, zz) {
81394
+ return function () { return view.project3DTo2D(xx, yy, zz)[1]; };
81395
+ })(start[0], start[1], start[2]),
81396
+ (function (xx, yy, zz) {
81397
+ return function () { return view.project3DTo2D(xx, yy, zz)[2]; };
81398
+ })(start[0], start[1], start[2])
81399
+ ], attr);
81400
+
81401
+ attr = Type.copyAttributes(attributes.point2, board.options, 'axis3d', 'point2');
81402
+ el_end = board.create('point', [
81403
+ (function (xx, yy, zz) {
81404
+ return function () { return view.project3DTo2D(xx, yy, zz)[1]; };
81405
+ })(end[0], end[1], end[2]),
81406
+ (function (xx, yy, zz) {
81407
+ return function () { return view.project3DTo2D(xx, yy, zz)[2]; };
81408
+ })(end[0], end[1], end[2])
81409
+ ], attr);
81410
+
81411
+ attr = Type.copyAttributes(attributes, board.options, 'axis3d');
81412
+ el = board.create('arrow', [el_start, el_end], attr);
81413
+
81414
+ return el;
81415
+ };
81416
+ JXG.registerElement('axis3d', ThreeD.createAxis);
81417
+
81418
+ ThreeD.createMesh = function (board, parents, attr) {
81419
+ var view = parents[0],
81420
+ point = parents[1],
81421
+ vec1 = parents[2],
81422
+ range1 = parents[3],
81423
+ vec2 = parents[4],
81424
+ range2 = parents[5],
81425
+ el;
81426
+
81427
+ el = board.create('curve', [[], []], attr);
81428
+ el.updateDataArray = function () {
81429
+ var s1 = range1[0],
81430
+ e1 = range1[1],
81431
+ s2 = range2[0],
81432
+ e2 = range2[1],
81433
+ l1, l2, res, i, sol,
81434
+ v1 = [0, 0, 0],
81435
+ v2 = [0, 0, 0],
81436
+ step = 1,
81437
+ q = [0, 0, 0];
81438
+
81439
+ this.dataX = [];
81440
+ this.dataY = [];
81441
+
81442
+ for (i = 0; i < 3; i++) {
81443
+ q[i] = Type.evaluate(point[i]);
81444
+ v1[i] = Type.evaluate(vec1[i]);
81445
+ v2[i] = Type.evaluate(vec2[i]);
81446
+ }
81447
+ l1 = JXG.Math.norm(v1, 3);
81448
+ l2 = JXG.Math.norm(v2, 3);
81449
+ for (i = 0; i < 3; i++) {
81450
+ v1[i] /= l1;
81451
+ v2[i] /= l2;
81452
+ }
81453
+ if (false) {
81454
+ sol = Mat.Geometry.getPlaneBounds(v1, v2, q, s1, e1);
81455
+ if (sol !== null) {
81456
+ s1 = sol[0];
81457
+ e1 = sol[1];
81458
+ s2 = sol[2];
81459
+ e2 = sol[3];
81460
+ }
81461
+ }
81462
+
81463
+ res = view.getMesh(
81464
+ function(u, v) { return q[0] + u * v1[0] + v * v2[0]; },
81465
+ function(u, v) { return q[1] + u * v1[1] + v * v2[1]; },
81466
+ function(u, v) { return q[2] + u * v1[2] + v * v2[2]; },
81467
+ [Math.ceil(s1), Math.floor(e1), (Math.ceil(e1) - Math.floor(s1)) / step],
81468
+ [Math.ceil(s2), Math.floor(e2), (Math.ceil(e2) - Math.floor(s2)) / step]);
81469
+ this.dataX = res[0];
81470
+ this.dataY = res[1];
81471
+ };
81472
+ return el;
81473
+ };
81474
+ JXG.registerElement('mesh3d', ThreeD.createMesh);
81475
+
81476
+ });
81477
+ /*
81478
+ Copyright 2008-2022
81479
+ Matthias Ehmann,
81480
+ Carsten Miller,
81481
+ Andreas Walter,
81482
+ Alfred Wassermann
81483
+
81484
+ This file is part of JSXGraph.
81485
+
81486
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
81487
+
81488
+ You can redistribute it and/or modify it under the terms of the
81489
+
81490
+ * GNU Lesser General Public License as published by
81491
+ the Free Software Foundation, either version 3 of the License, or
81492
+ (at your option) any later version
81493
+ OR
81494
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
81495
+
81496
+ JSXGraph is distributed in the hope that it will be useful,
81497
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
81498
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81499
+ GNU Lesser General Public License for more details.
81500
+
81501
+ You should have received a copy of the GNU Lesser General Public License and
81502
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
81503
+ and <http://opensource.org/licenses/MIT/>.
81504
+ */
81505
+ /*global JXG:true, define: true*/
81506
+
81507
+ define('3d/curve3d',['jxg', 'utils/type', '3d/view3d'
81508
+ ], function (JXG, Type, ThreeD) {
81509
+ "use strict";
81510
+
81511
+ ThreeD.createCurve = function (board, parents, attr) {
81512
+ var view = parents[0],
81513
+ D3, el;
81514
+
81515
+ D3 = {
81516
+ elType: 'curve3D',
81517
+ X: parents[1],
81518
+ Y: parents[2],
81519
+ Z: parents[3],
81520
+ };
81521
+ D3.F = [D3.X, D3.Y, D3.Z];
81522
+
81523
+ el = board.create('curve', [[], []], attr);
81524
+ el.D3 = D3;
81525
+
81526
+ if (Type.isFunction(el.D3.X)) {
81527
+ // 3D curve given as t -> [X(t), Y(t), Z(t)]
81528
+
81529
+ el.D3.range = parents[4];
81530
+ el.updateDataArray = function () {
81531
+ var steps = Type.evaluate(this.visProp.numberpointshigh),
81532
+ s = Type.evaluate(this.D3.range[0]),
81533
+ e = Type.evaluate(this.D3.range[1]),
81534
+ delta = (e - s) / (steps - 1),
81535
+ c2d, t, i,
81536
+ p = [0, 0, 0];
81537
+
81538
+ this.dataX = [];
81539
+ this.dataY = [];
81540
+
81541
+ for (t = s; t <= e; t += delta) {
81542
+ for (i = 0; i < 3; i++) {
81543
+ p[i] = this.D3.F[i](t);
81544
+ }
81545
+ c2d = view.project3DTo2D(p);
81546
+ this.dataX.push(c2d[1]);
81547
+ this.dataY.push(c2d[2]);
81548
+ }
81549
+ };
81550
+ } else if (Type.isArray(el.D3.X)) {
81551
+ // 3D curve given as array of 3D points
81552
+
81553
+ el.updateDataArray = function () {
81554
+ var i,
81555
+ le = this.D3.X.length,
81556
+ c2d;
81557
+
81558
+ this.dataX = [];
81559
+ this.dataY = [];
81560
+
81561
+ for (i = 0; i < le; i++) {
81562
+ c2d = view.project3DTo2D([this.D3.X[i], this.D3.Y[i], this.D3.Z[i]]);
81563
+ this.dataX.push(c2d[1]);
81564
+ this.dataY.push(c2d[2]);
81565
+ }
81566
+ };
81567
+ }
81568
+
81569
+ return el;
81570
+ };
81571
+ JXG.registerElement('curve3d', ThreeD.createCurve);
81572
+
81573
+ });
81574
+ /*
81575
+ Copyright 2008-2022
81576
+ Matthias Ehmann,
81577
+ Carsten Miller,
81578
+ Andreas Walter,
81579
+ Alfred Wassermann
81580
+
81581
+ This file is part of JSXGraph.
81582
+
81583
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
81584
+
81585
+ You can redistribute it and/or modify it under the terms of the
81586
+
81587
+ * GNU Lesser General Public License as published by
81588
+ the Free Software Foundation, either version 3 of the License, or
81589
+ (at your option) any later version
81590
+ OR
81591
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
81592
+
81593
+ JSXGraph is distributed in the hope that it will be useful,
81594
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
81595
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81596
+ GNU Lesser General Public License for more details.
81597
+
81598
+ You should have received a copy of the GNU Lesser General Public License and
81599
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
81600
+ and <http://opensource.org/licenses/MIT/>.
81601
+ */
81602
+ /*global JXG:true, define: true*/
81603
+
81604
+ /**
81605
+ * Create linear spaces of dimension at least one,
81606
+ * i.e. lines and planes.
81607
+ */
81608
+ define('3d/linspace3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d'
81609
+ ], function (JXG, Type, Mat, Geometry, ThreeD) {
81610
+ "use strict";
81611
+
81612
+ /**
81613
+ * @class This element is used to provide a constructor for a 3D line.
81614
+ * @pseudo
81615
+ * @description There are two possibilities to create a Line3D object.
81616
+ * <p>
81617
+ * First: the line in 3D is defined by two points in 3D (Point3D).
81618
+ * The points can be either existing points or coordinate arrays of
81619
+ * the form [x, y, z].
81620
+ * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])
81621
+ * a direction given as array [x, y, z] and an optional range
81622
+ * given as array [s, e]. The default value for the range is [-Infinity, Infinity].
81623
+ * <p>
81624
+ * All numbers can also be provided as functions returning a number.
81625
+ *
81626
+ * @name Line3D
81627
+ * @augments JXG.Curve
81628
+ * @constructor
81629
+ * @type JXG.Curve
81630
+ * @throws {Exception} If the element cannot be constructed with the given parent
81631
+ * objects an exception is thrown.
81632
+ * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given
81633
+ * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the
81634
+ * line will determine the radius), or another {@link JXG.Circle}.
81635
+ *
81636
+ */
81637
+ ThreeD.createLine = function (board, parents, attributes) {
81638
+ var view = parents[0],
81639
+ attr, D3, point, point1, point2,
81640
+ el;
81641
+
81642
+ // Range
81643
+ D3 = {
81644
+ elType: 'line3d',
81645
+ range: parents[3] || [-Infinity, Infinity]
81646
+ };
81647
+
81648
+ // Point
81649
+ if (Type.isPoint(parents[1])) {
81650
+ point = parents[1];
81651
+ } else {
81652
+ point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });
81653
+ }
81654
+ D3.point = point;
81655
+
81656
+ // Direction
81657
+ if (Type.isPoint(parents[2]) && Type.exists(parents[2].D3)) {
81658
+ // Line defined by two points
81659
+
81660
+ point1 = point;
81661
+ point2 = parents[2];
81662
+ D3.direction = function () {
81663
+ return [
81664
+ point2.D3.X() - point.D3.X(),
81665
+ point2.D3.Y() - point.D3.Y(),
81666
+ point2.D3.Z() - point.D3.Z()
81667
+ ];
81668
+ };
81669
+ D3.range = [0, 1];
81670
+ } else {
81671
+ // Line defined by point, direction and range
81672
+
81673
+ // Directions are handled as arrays of length 4,
81674
+ // i.e. with homogeneous coordinates.
81675
+ if (Type.isFunction(parents[2])) {
81676
+ D3.direction = parents[2];
81677
+ } else if (parents[2].length === 3) {
81678
+ D3.direction = [1].concat(parents[2]);
81679
+ } else if (parents[2].length === 4) {
81680
+ D3.direction = parents[2];
81681
+ } else {
81682
+ // Throw error
81683
+ }
81684
+
81685
+ // Direction given as array
81686
+ D3.getPointCoords = function (r) {
81687
+ var p = [],
81688
+ d = [],
81689
+ i;
81690
+
81691
+ p.push(point.D3.X());
81692
+ p.push(point.D3.Y());
81693
+ p.push(point.D3.Z());
81694
+
81695
+ if (Type.isFunction(D3.direction)) {
81696
+ d = D3.direction();
81697
+ } else {
81698
+ for (i = 1; i < 4; i++) {
81699
+ d.push(Type.evaluate(D3.direction[i]));
81700
+ }
81701
+ }
81702
+ if (Math.abs(r) === Infinity) {
81703
+ r = view.intersectionLineCube(p, d, r);
81704
+ }
81705
+ return [
81706
+ p[0] + d[0] * r,
81707
+ p[1] + d[1] * r,
81708
+ p[2] + d[2] * r
81709
+ ];
81710
+
81711
+ };
81712
+
81713
+ attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point1');
81714
+ point1 = view.create('point3d', [
81715
+ function () {
81716
+ return D3.getPointCoords(Type.evaluate(D3.range[0]));
81717
+ }
81718
+ ], attr);
81719
+ attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point2');
81720
+ point2 = view.create('point3d', [
81721
+ function () {
81722
+ return D3.getPointCoords(Type.evaluate(D3.range[1]));
81723
+ }
81724
+ ], attr);
81725
+ }
81726
+
81727
+ attr = Type.copyAttributes(attributes, board.options, 'line3d');
81728
+ el = view.create('segment', [point1, point2], attr);
81729
+ el.point1 = point1;
81730
+ el.point2 = point2;
81731
+ point1.addChild(el);
81732
+ point2.addChild(el);
81733
+ el.D3 = D3;
81734
+
81735
+ return el;
81736
+ };
81737
+ JXG.registerElement('line3d', ThreeD.createLine);
81738
+
81739
+ ThreeD.createPlane = function (board, parents, attributes) {
81740
+ var view = parents[0],
81741
+ attr, D3,
81742
+ point,
81743
+ vec1 = parents[2],
81744
+ vec2 = parents[3],
81745
+ el, grid, update;
81746
+
81747
+ // D3: {
81748
+ // point,
81749
+ // vec1,
81750
+ // vec2,
81751
+ // poin1,
81752
+ // point2,
81753
+ // normal array of len 3
81754
+ // d
81755
+ // }
81756
+ D3 = {
81757
+ elType: 'plane3d',
81758
+ dir1: [],
81759
+ dir2: [],
81760
+ range1: parents[4],
81761
+ range2: parents[5],
81762
+ vec1: vec1,
81763
+ vec2: vec2
81764
+ };
81765
+
81766
+ if (Type.isPoint(parents[1])) {
81767
+ point = parents[1];
81768
+ } else {
81769
+ point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });
81770
+ }
81771
+ D3.point = point;
81772
+
81773
+ D3.updateNormal = function () {
81774
+ var i;
81775
+ for (i = 0; i < 3; i++) {
81776
+ D3.dir1[i] = Type.evaluate(D3.vec1[i]);
81777
+ D3.dir2[i] = Type.evaluate(D3.vec2[i]);
81778
+ }
81779
+ D3.normal = Mat.crossProduct(D3.dir1, D3.dir2);
81780
+ D3.d = Mat.innerProduct(D3.point.D3.coords.slice(1), D3.normal, 3);
81781
+ };
81782
+ D3.updateNormal();
81783
+
81784
+ attr = Type.copyAttributes(attributes, board.options, 'plane3d');
81785
+ el = board.create('curve', [[], []], attr);
81786
+ el.D3 = D3;
81787
+
81788
+ el.updateDataArray = function () {
81789
+ var s1, e1, s2, e2,
81790
+ c2d, l1, l2,
81791
+ planes = ['xPlaneRear', 'yPlaneRear', 'zPlaneRear'],
81792
+ points = [],
81793
+ v1 = [0, 0, 0],
81794
+ v2 = [0, 0, 0],
81795
+ q = [0, 0, 0],
81796
+ p = [0, 0, 0], d, i, j, a, b, first, pos, pos_akt;
81797
+
81798
+ this.dataX = [];
81799
+ this.dataY = [];
81800
+
81801
+ this.D3.updateNormal();
81802
+
81803
+ // Infinite plane
81804
+ if (this.D3.elType !== 'axisplane3d' && view.defaultAxes &&
81805
+ (!D3.range1 || !D3.range2)
81806
+ ) {
81807
+
81808
+ // Start with the rear plane.
81809
+ // Determine the intersections with the view bbox3d
81810
+ // For each face of the bbox3d we determine two points
81811
+ // which are the ends of the intersection line.
81812
+ // We start with the three rear planes.
81813
+ for (j = 0; j < planes.length; j++) {
81814
+ p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]]);
81815
+
81816
+ if (p[0].length === 3 && p[1].length === 3) {
81817
+ // This test is necessary to filter out intersection lines which are
81818
+ // identical to intersections of axis planes (they would occur twice).
81819
+ for (i = 0; i < points.length; i++) {
81820
+ if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||
81821
+ (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {
81822
+ break;
81823
+ }
81824
+ }
81825
+ if (i === points.length) {
81826
+ points.push(p.slice());
81827
+ }
81828
+ }
81829
+
81830
+ // Point on the front plane of the bbox3d
81831
+ p = [0, 0, 0];
81832
+ p[j] = view.D3.bbox3d[j][1];
81833
+
81834
+ // d is the rhs of the Hesse normal form of the front plane.
81835
+ d = Mat.innerProduct(p, view.defaultAxes[planes[j]].D3.normal, 3);
81836
+ p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]], d);
81837
+
81838
+ if (p[0].length === 3 && p[1].length === 3) {
81839
+ // Do the same test as above
81840
+ for (i = 0; i < points.length; i++) {
81841
+ if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||
81842
+ (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {
81843
+ break;
81844
+ }
81845
+ }
81846
+ if (i === points.length) {
81847
+ points.push(p.slice());
81848
+ }
81849
+ }
81850
+ }
81851
+
81852
+ // Concatenate the intersection points to a polygon.
81853
+ // If all wents well, each intersection should appear
81854
+ // twice in the list.
81855
+ first = 0;
81856
+ pos = first;
81857
+ i = 0;
81858
+ do {
81859
+ p = points[pos][i];
81860
+ if (p.length === 3) {
81861
+ c2d = view.project3DTo2D(p);
81862
+ this.dataX.push(c2d[1]);
81863
+ this.dataY.push(c2d[2]);
81864
+ }
81865
+ i = (i + 1) % 2;
81866
+ p = points[pos][i];
81867
+
81868
+ pos_akt = pos;
81869
+ for (j = 0; j < points.length; j++) {
81870
+ if (j !== pos && Geometry.distance(p, points[j][0]) < Mat.eps) {
81871
+ pos = j;
81872
+ i = 0;
81873
+ break;
81874
+ }
81875
+ if (j !== pos && Geometry.distance(p, points[j][1]) < Mat.eps) {
81876
+ pos = j;
81877
+ i = 1;
81878
+ break;
81879
+ }
81880
+ }
81881
+ if (pos === pos_akt) {
81882
+ console.log("Error: update plane3d: did not find next", pos);
81883
+ break;
81884
+ }
81885
+ } while (pos !== first);
81886
+ c2d = view.project3DTo2D(points[first][0]);
81887
+ this.dataX.push(c2d[1]);
81888
+ this.dataY.push(c2d[2]);
81889
+
81890
+ } else {
81891
+ // 3D bounded flat
81892
+ s1 = Type.evaluate(this.D3.range1[0]);
81893
+ e1 = Type.evaluate(this.D3.range1[1]);
81894
+ s2 = Type.evaluate(this.D3.range2[0]);
81895
+ e2 = Type.evaluate(this.D3.range2[1]);
81896
+
81897
+ q = this.D3.point.D3.coords.slice(1);
81898
+
81899
+ v1 = this.D3.dir1.slice();
81900
+ v2 = this.D3.dir2.slice();
81901
+ l1 = Mat.norm(v1, 3);
81902
+ l2 = Mat.norm(v2, 3);
81903
+ for (i = 0; i < 3; i++) {
81904
+ v1[i] /= l1;
81905
+ v2[i] /= l2;
81906
+ }
81907
+
81908
+ for (j = 0; j < 4; j++) {
81909
+ switch (j) {
81910
+ case 0: a = s1; b = s2; break;
81911
+ case 1: a = e1; b = s2; break;
81912
+ case 2: a = e1; b = e2; break;
81913
+ case 3: a = s1; b = e2;
81914
+ }
81915
+ for (i = 0; i < 3; i++) {
81916
+ p[i] = q[i] + a * v1[i] + b * v2[i];
81917
+ }
81918
+ c2d = view.project3DTo2D(p);
81919
+ this.dataX.push(c2d[1]);
81920
+ this.dataY.push(c2d[2]);
81921
+ }
81922
+ // Close the curve
81923
+ this.dataX.push(this.dataX[0]);
81924
+ this.dataY.push(this.dataY[0]);
81925
+ }
81926
+ };
81927
+
81928
+ attr = Type.copyAttributes(attributes.mesh3d, board.options, 'mesh3d');
81929
+
81930
+ if (D3.range1 && D3.range2) {
81931
+ grid = view.create('mesh3d', [point.D3.coords.slice(1), vec1, D3.range1, vec2, D3.range2], attr);
81932
+ el.grid = grid;
81933
+ el.inherits.push(grid);
81934
+ }
81935
+
81936
+ // update = el.update;
81937
+ // el.update = function () {
81938
+ // if (el.needsUpdate) {
81939
+ // update.apply(el);
81940
+ // }
81941
+ // return this;
81942
+ // };
81943
+
81944
+ return el;
81945
+ };
81946
+ JXG.registerElement('plane3d', ThreeD.createPlane);
81947
+
81948
+ });
81949
+ /*
81950
+ Copyright 2008-2022
81951
+ Matthias Ehmann,
81952
+ Carsten Miller,
81953
+ Andreas Walter,
81954
+ Alfred Wassermann
81955
+
81956
+ This file is part of JSXGraph.
81957
+
81958
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
81959
+
81960
+ You can redistribute it and/or modify it under the terms of the
81961
+
81962
+ * GNU Lesser General Public License as published by
81963
+ the Free Software Foundation, either version 3 of the License, or
81964
+ (at your option) any later version
81965
+ OR
81966
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
81967
+
81968
+ JSXGraph is distributed in the hope that it will be useful,
81969
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
81970
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81971
+ GNU Lesser General Public License for more details.
81972
+
81973
+ You should have received a copy of the GNU Lesser General Public License and
81974
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
81975
+ and <http://opensource.org/licenses/MIT/>.
81976
+ */
81977
+ /*global JXG:true, define: true*/
81978
+
81979
+ define('3d/point3d',['jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type', '3d/view3d'
81980
+ ], function (JXG, Const, Mat, Geometry, Type, ThreeD) {
81981
+ "use strict";
81982
+
81983
+ /**
81984
+ * @class This element is used to provide a constructor for a 3D Point.
81985
+ * @pseudo
81986
+ * @description There are two possibilities to create a Line3D object.
81987
+ * <p>
81988
+ * First: the line in 3D is defined by two points in 3D (Point3D).
81989
+ * The points can be either existing points or coordinate arrays of
81990
+ * the form [x, y, z].
81991
+ * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])
81992
+ * a direction given as array [x, y, z] and an optional range
81993
+ * given as array [s, e]. The default value for the range is [-Infinity, Infinity].
81994
+ * <p>
81995
+ * All numbers can also be provided as functions returning a number.
81996
+ *
81997
+ * @name Point3D
81998
+ * @augments JXG.Point
81999
+ * @constructor
82000
+ * @type JXG.Point
82001
+ * @throws {Exception} If the element cannot be constructed with the given parent
82002
+ * objects an exception is thrown.
82003
+ * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given
82004
+ * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the
82005
+ * line will determine the radius), or another {@link JXG.Circle}.
82006
+ *
82007
+ */
82008
+ ThreeD.createPoint = function (board, parents, attributes) {
82009
+ var view = parents[0],
82010
+ attr, update2D, D3,
82011
+ i, c2d,
82012
+ el;
82013
+
82014
+ attr = Type.copyAttributes(attributes, board.options, 'point3d');
82015
+
82016
+ D3 = {
82017
+ elType: 'point3d',
82018
+ coords: [1, 0, 0, 0],
82019
+ X: function () { return this.coords[1]; },
82020
+ Y: function () { return this.coords[2]; },
82021
+ Z: function () { return this.coords[3]; }
82022
+ };
82023
+
82024
+ // If the last element of partents is a 3D object, the point is a glider
82025
+ // on that element.
82026
+ if (parents.length > 2 && Type.exists(parents[parents.length - 1].D3)) {
82027
+ D3.slide = parents.pop();
82028
+ } else {
82029
+ D3.slide = null;
82030
+ }
82031
+
82032
+ if (parents.length === 2) {
82033
+ D3.F = parents[1]; // (Array [x, y, z] | function) returning [x, y, z]
82034
+ D3.coords = [1].concat(Type.evaluate(D3.F));
82035
+ } else if (parents.length === 4) {
82036
+ D3.F = parents.slice(1); // 3 numbers | functions
82037
+ for (i = 0; i < 3; i++) {
82038
+ D3.coords[i + 1] = Type.evaluate(D3.F[i]);
82039
+ }
82040
+ } else {
82041
+ // Throw error
82042
+ }
82043
+
82044
+ /**
82045
+ * Update the 4D coords array
82046
+ * @returns Object
82047
+ */
82048
+ D3.updateCoords = function () {
82049
+ var res, i;
82050
+ if (Type.isFunction(this.F)) {
82051
+ res = Type.evaluate(this.F);
82052
+ this.coords = [1, res[0], res[1], res[2]];
82053
+ } else {
82054
+ this.coords[0] = 1;
82055
+ for (i = 0; i < 3; i++) {
82056
+ if (Type.isFunction(this.F[i])) {
82057
+ this.coords[i + 1] = Type.evaluate(this.F[i]);
82058
+ }
82059
+ }
82060
+ }
82061
+ return this;
82062
+ };
82063
+ D3.updateCoords();
82064
+
82065
+ c2d = view.project3DTo2D(D3.coords);
82066
+ el = board.create('point', c2d, attr);
82067
+ el.D3 = D3;
82068
+ el.D3.c2d = el.coords.usrCoords.slice(); // Copy of the coordinates to detect dragging
82069
+ update2D = el.update;
82070
+
82071
+ if (el.D3.slide) {
82072
+ el._minFunc = function (n, m, x, con) {
82073
+ var surface = el.D3.slide.D3,
82074
+ c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])],
82075
+ c2d = view.project3DTo2D(c3d);
82076
+
82077
+ con[0] = el.X() - c2d[1];
82078
+ con[1] = el.Y() - c2d[2];
82079
+
82080
+ return con[0] * con[0] + con[1] * con[1];
82081
+ };
82082
+
82083
+ el.projectCoords2Surface = function () {
82084
+ var n = 2, // # of variables
82085
+ m = 2, // number of constraints
82086
+ x = [0, 0],
82087
+ // Various Cobyla constants, see Cobyla docs in Cobyja.js
82088
+ rhobeg = 5.0,
82089
+ rhoend = 1.0e-6,
82090
+ iprint = 0,
82091
+ maxfun = 200,
82092
+ surface = this.D3.slide.D3,
82093
+ r, c3d, c2d;
82094
+
82095
+ if (Type.exists(this.D3.params)) {
82096
+ x = this.D3.params.slice();
82097
+ }
82098
+ r = Mat.Nlp.FindMinimum(this._minFunc, n, m, x, rhobeg, rhoend, iprint, maxfun);
82099
+
82100
+ c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])];
82101
+ c2d = view.project3DTo2D(c3d);
82102
+ this.D3.params = x;
82103
+ this.D3.coords = c3d;
82104
+ this.coords.setCoordinates(Const.COORDS_BY_USER, c2d);
82105
+ this.D3.c2d = c2d;
82106
+ };
82107
+ }
82108
+
82109
+ el.update = function (drag) {
82110
+ var c3d, foot;
82111
+ if (!this.needsUpdate) {
82112
+ return this;
82113
+ }
82114
+
82115
+ // Update is called in from two methods:
82116
+ // Once in setToPositionDirectly and
82117
+ // once in the subsequent board.update
82118
+ if (this.draggable() &&
82119
+ Geometry.distance(this.D3.c2d, this.coords.usrCoords) !== 0) {
82120
+
82121
+ if (this.D3.slide) {
82122
+ this.projectCoords2Surface();
82123
+ } else {
82124
+ // Drag the point in its xy plane
82125
+ foot = [1, 0, 0, this.D3.coords[3]];
82126
+ c3d = view.project2DTo3DPlane(el, [1, 0, 0, 1], foot);
82127
+ if (c3d[0] !== 0) {
82128
+ this.D3.coords = view.project3DToCube(c3d);
82129
+ }
82130
+ }
82131
+ } else {
82132
+ this.D3.updateCoords();
82133
+ // Update 2D point from its 3D view
82134
+ el.coords.setCoordinates(Const.COORDS_BY_USER,
82135
+ view.project3DTo2D([1, this.D3.X(), this.D3.Y(), this.D3.Z()])
82136
+ );
82137
+ }
82138
+ this.D3.c2d = el.coords.usrCoords.slice();
82139
+
82140
+ update2D.apply(this, [drag]);
82141
+ return this;
82142
+ };
82143
+
82144
+ el.normalizeCoords3D = function () {
82145
+ if (Math.abs(el.D3.coords[0]) > Mat.eps) {
82146
+ el.D3.coords[1] /= el.D3.coords[0];
82147
+ el.D3.coords[2] /= el.D3.coords[0];
82148
+ el.D3.coords[3] /= el.D3.coords[0];
82149
+ el.D3.coords[0] = 1.0;
82150
+ }
82151
+ return this;
82152
+ };
82153
+
82154
+ el.setPosition3D = function (coords, noevent) {
82155
+ var c = el.D3.coords,
82156
+ oc = el.D3.coords.slice(); // Copy of original values
82157
+
82158
+ if (coords.length === 3) { // Euclidean coordinates
82159
+ c[0] = 1.0;
82160
+ c[1] = coords[0];
82161
+ c[2] = coords[1];
82162
+ c[3] = coords[2];
82163
+ } else { // Homogeneous coordinates (normalized)
82164
+ c[0] = coords[0];
82165
+ c[1] = coords[1];
82166
+ c[2] = coords[2];
82167
+ el.normalizeCoords3D();
82168
+ }
82169
+
82170
+ // console.log(el.emitter, !noevent, oc[0] !== c[0] || oc[1] !== c[1] || oc[2] !== c[2] || oc[3] !== c[3]);
82171
+ // Not yet working
82172
+ if (el.emitter && !noevent &&
82173
+ (oc[0] !== c[0] || oc[1] !== c[1] || oc[2] !== c[2] || oc[3] !== c[3])) {
82174
+ this.triggerEventHandlers(['update3D'], [oc]);
82175
+ }
82176
+ return this;
82177
+ };
82178
+
82179
+ // Not yet working
82180
+ el.__evt__update3D = function (oc) { };
82181
+
82182
+ return el;
82183
+ };
82184
+ JXG.registerElement('point3d', ThreeD.createPoint);
82185
+
82186
+ });
82187
+ /*
82188
+ Copyright 2008-2022
82189
+ Matthias Ehmann,
82190
+ Carsten Miller,
82191
+ Andreas Walter,
82192
+ Alfred Wassermann
82193
+
82194
+ This file is part of JSXGraph.
82195
+
82196
+ JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
82197
+
82198
+ You can redistribute it and/or modify it under the terms of the
82199
+
82200
+ * GNU Lesser General Public License as published by
82201
+ the Free Software Foundation, either version 3 of the License, or
82202
+ (at your option) any later version
82203
+ OR
82204
+ * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
82205
+
82206
+ JSXGraph is distributed in the hope that it will be useful,
82207
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
82208
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82209
+ GNU Lesser General Public License for more details.
82210
+
82211
+ You should have received a copy of the GNU Lesser General Public License and
82212
+ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
82213
+ and <http://opensource.org/licenses/MIT/>.
82214
+ */
82215
+ /*global JXG:true, define: true*/
82216
+
82217
+ define('3d/surface3d',['jxg', 'utils/type', '3d/view3d'
82218
+ ], function (JXG, Type, ThreeD) {
82219
+ "use strict";
82220
+
82221
+
82222
+ /**
82223
+ * @class This element creates a 3D parametric surface.
82224
+ * @pseudo
82225
+ * @description A 3D parametric surface is defined by a function
82226
+ * <i>F: R<sup>2</sup> &rarr; R<sup>3</sup></i>.
82227
+ *
82228
+ * @name ParametricSurface3D
82229
+ * @augments Curve
82230
+ * @constructor
82231
+ * @type Object
82232
+ * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
82233
+ * @param {Function_Function_Function_Array_Array} F<sub>X</sub>,F<sub>Y</sub>,F<sub>Z</sub>,rangeX,rangeY
82234
+ * F<sub>X</sub>(u,v), F<sub>Y</sub>(u,v), F<sub>Z</sub>(u,v) are functions returning a number, rangeU is the array containing
82235
+ * lower and upper bound for the range of parameter u, rangeV is the array containing
82236
+ * lower and upper bound for the range of parameter v. rangeU and rangeV may also be functions returning an array of length two.
82237
+ * @example
82238
+ * var view = board.create('view3d',
82239
+ * [[-6, -3], [8, 8],
82240
+ * [[-5, 5], [-5, 5], [-5, 5]]]);
82241
+ *
82242
+ * // Sphere
82243
+ * var c = view.create('parametricsurface3d', [
82244
+ * (u, v) => 2 * Math.sin(u) * Math.cos(v),
82245
+ * (u, v) => 2 * Math.sin(u) * Math.sin(v),
82246
+ * (u, v) => 2 * Math.cos(u),
82247
+ * [0, 2 * Math.PI],
82248
+ * [0, Math.PI]
82249
+ * ], {
82250
+ * strokeColor: '#ff0000',
82251
+ * stepsU: 30,
82252
+ * stepsV: 30
82253
+ * });
82254
+ *
82255
+ * </pre><div id="JXG52da0ecc-1ba9-4d41-850c-36e5120025a5" class="jxgbox" style="width: 500px; height: 500px;"></div>
82256
+ * <script type="text/javascript">
82257
+ * (function() {
82258
+ * var board = JXG.JSXGraph.initBoard('JXG52da0ecc-1ba9-4d41-850c-36e5120025a5',
82259
+ * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});
82260
+ * var view = board.create('view3d',
82261
+ * [[-6, -3], [8, 8],
82262
+ * [[-5, 5], [-5, 5], [-5, 5]]]);
82263
+ *
82264
+ * // Sphere
82265
+ * var c = view.create('parametricsurface3d', [
82266
+ * (u, v) => 2 * Math.sin(u) * Math.cos(v),
82267
+ * (u, v) => 2 * Math.sin(u) * Math.sin(v),
82268
+ * (u, v) => 2 * Math.cos(u),
82269
+ * [0, 2 * Math.PI],
82270
+ * [0, Math.PI]
82271
+ * ], {
82272
+ * strokeColor: '#ff0000',
82273
+ * stepsU: 20,
82274
+ * stepsV: 20
82275
+ * });
82276
+ *
82277
+ * })();
82278
+ *
82279
+ * </script><pre>
82280
+ *
82281
+ */
82282
+ ThreeD.createParametricSurface = function (board, parents, attributes) {
82283
+ var view = parents[0],
82284
+ attr,
82285
+ X = parents[1],
82286
+ Y = parents[2],
82287
+ Z = parents[3],
82288
+ range_u = parents[4],
82289
+ range_v = parents[5],
82290
+ D3, el;
82291
+
82292
+ D3 = {
82293
+ elType: 'surface3d',
82294
+ X: X,
82295
+ Y: Y,
82296
+ Z: Z,
82297
+ range_u: range_u,
82298
+ range_v: range_v
82299
+ };
82300
+ attr = Type.copyAttributes(attributes, board.options, 'surface3d');
82301
+ el = board.create('curve', [[], []], attr);
82302
+ el.updateDataArray = function () {
82303
+ var steps_u = Type.evaluate(this.visProp.stepsu),
82304
+ steps_v = Type.evaluate(this.visProp.stepsv),
82305
+ r_u = Type.evaluate(this.D3.range_u), // Type.evaluate(range_u),
82306
+ r_v = Type.evaluate(this.D3.range_v), // Type.evaluate(range_v),
82307
+ res = view.getMesh(this.D3.X, this.D3.Y, this.D3.Z,
82308
+ r_u.concat([steps_u]),
82309
+ r_v.concat([steps_v]));
82310
+ this.dataX = res[0];
82311
+ this.dataY = res[1];
82312
+ };
82313
+ el.D3 = D3;
82314
+
82315
+ return el;
82316
+ };
82317
+ JXG.registerElement('parametricsurface3d', ThreeD.createParametricSurface);
82318
+
82319
+ /**
82320
+ * @class This element creates a 3D function graph.
82321
+ * @pseudo
82322
+ * @description A 3D function graph is defined by a function
82323
+ * <i>F: R<sup>2</sup> &rarr; R</i>.
82324
+ *
82325
+ * @name Functiongraph3D
82326
+ * @augments ParametricSurface3D
82327
+ * @constructor
82328
+ * @type Object
82329
+ * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
82330
+ * @param {Function_Array_Array} F,rangeX,rangeY F(x,y) is a function returning a number, rangeX is the array containing
82331
+ * lower and upper bound for the range of x, rangeY is the array containing
82332
+ * lower and upper bound for the range of y.
82333
+ * @example
82334
+ * var box = [-5, 5];
82335
+ * var view = board.create('view3d',
82336
+ * [
82337
+ * [-6, -3], [8, 8],
82338
+ * [box, box, box]
82339
+ * ],
82340
+ * {
82341
+ * xPlaneRear: {visible: false},
82342
+ * yPlaneRear: {visible: false},
82343
+ * });
82344
+ *
82345
+ * // Function F to be plotted
82346
+ * var F = (x, y) => Math.sin(x * y / 4);
82347
+ *
82348
+ * // 3D surface
82349
+ * var c = view.create('functiongraph3d', [
82350
+ * F,
82351
+ * box, // () => [-s.Value()*5, s.Value() * 5],
82352
+ * box, // () => [-s.Value()*5, s.Value() * 5],
82353
+ * ], {
82354
+ * strokeWidth: 0.5,
82355
+ * stepsU: 70,
82356
+ * stepsV: 70
82357
+ * });
82358
+ *
82359
+ * </pre><div id="JXG87646dd4-9fe5-4c21-8734-089abc612515" class="jxgbox" style="width: 500px; height: 500px;"></div>
82360
+ * <script type="text/javascript">
82361
+ * (function() {
82362
+ * var board = JXG.JSXGraph.initBoard('JXG87646dd4-9fe5-4c21-8734-089abc612515',
82363
+ * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});
82364
+ * var box = [-5, 5];
82365
+ * var view = board.create('view3d',
82366
+ * [
82367
+ * [-6, -3], [8, 8],
82368
+ * [box, box, box]
82369
+ * ],
82370
+ * {
82371
+ * xPlaneRear: {visible: false},
82372
+ * yPlaneRear: {visible: false},
82373
+ * });
82374
+ *
82375
+ * // Function F to be plotted
82376
+ * var F = (x, y) => Math.sin(x * y / 4);
82377
+ *
82378
+ * // 3D surface
82379
+ * var c = view.create('functiongraph3d', [
82380
+ * F,
82381
+ * box, // () => [-s.Value()*5, s.Value() * 5],
82382
+ * box, // () => [-s.Value()*5, s.Value() * 5],
82383
+ * ], {
82384
+ * strokeWidth: 0.5,
82385
+ * stepsU: 70,
82386
+ * stepsV: 70
82387
+ * });
82388
+ *
82389
+ * })();
82390
+ *
82391
+ * </script><pre>
82392
+ *
82393
+ */
82394
+ ThreeD.createFunctiongraph = function (board, parents, attributes) {
82395
+ var view = parents[0],
82396
+ X = function(u, v) { return u; },
82397
+ Y = function(u, v) { return v; },
82398
+ Z = parents[1],
82399
+ range_u = parents[2],
82400
+ range_v = parents[3];
82401
+
82402
+ return view.create('parametricsurface3d', [X, Y, Z, range_u, range_v], attributes);
82403
+ };
82404
+ JXG.registerElement('functiongraph3d', ThreeD.createFunctiongraph);
82405
+
82406
+ });
82407
+
79896
82408
  /*global define: true*/
79897
82409
  define('../build/core.deps.js',[
79898
82410
  'jxg',
@@ -79965,7 +82477,15 @@ define('../build/core.deps.js',[
79965
82477
  'element/checkbox',
79966
82478
  'element/input',
79967
82479
  'element/button',
79968
- 'base/foreignobject'
82480
+ 'base/foreignobject',
82481
+ 'options3d',
82482
+ '3d/box3d',
82483
+ '3d/curve3d',
82484
+ '3d/linspace3d',
82485
+ '3d/point3d',
82486
+ '3d/surface3d',
82487
+ '3d/threed',
82488
+ '3d/view3d'
79969
82489
  ], function (JXG, Env) {
79970
82490
  "use strict";
79971
82491