1 /*
  2  Copyright 2008-2022
  3  Matthias Ehmann,
  4  Michael Gerhaeuser,
  5  Carsten Miller,
  6  Bianca Valentin,
  7  Alfred Wassermann,
  8  Peter Wilfahrt
  9 
 10  This file is part of JSXGraph.
 11 
 12  JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14  You can redistribute it and/or modify it under the terms of the
 15 
 16  * GNU Lesser General Public License as published by
 17  the Free Software Foundation, either version 3 of the License, or
 18  (at your option) any later version
 19  OR
 20  * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22  JSXGraph is distributed in the hope that it will be useful,
 23  but WITHOUT ANY WARRANTY; without even the implied warranty of
 24  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25  GNU Lesser General Public License for more details.
 26 
 27  You should have received a copy of the GNU Lesser General Public License and
 28  the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 29  and <http://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 
 33 /*global JXG: true, define: true*/
 34 /*jslint nomen: true, plusplus: true*/
 35 
 36 /* depends:
 37  jxg
 38  math/math
 39  math/geometry
 40  math/numerics
 41  math/statistics
 42  math/symbolic
 43  base/composition
 44  base/coords
 45  base/constants
 46  utils/type
 47  elements:
 48  line
 49  circle
 50  transform
 51  point
 52  glider
 53  text
 54  curve
 55  */
 56 
 57 define([
 58     'jxg', 'math/symbolic', 'utils/type'
 59 ], function (JXG, Symbolic, Type) {
 60 
 61     "use strict";
 62 
 63     /**
 64      * @class This element is used to visualize the locus of a given dependent point.
 65      * @pseudo
 66      * @description The locus element is used to visualize the curve a given point describes.
 67      * @constructor
 68      * @name Locus
 69      * @type JXG.Curve
 70      * @augments JXG.Curve
 71      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 72      * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.
 73      * @example
 74      *  // This examples needs JXG.Server up and running, otherwise it won't work.
 75      *  p1 = board.create('point', [0, 0]);
 76      *  p2 = board.create('point', [6, -1]);
 77      *  c1 = board.create('circle', [p1, 2]);
 78      *  c2 = board.create('circle', [p2, 1.5]);
 79      *  g1 = board.create('glider', [6, 3, c1]);
 80      *  c3 = board.create('circle', [g1, 4]);
 81      *  g2 = board.create('intersection', [c2,c3,0]);
 82      *  m1 = board.create('midpoint', [g1,g2]);
 83      *  loc = board.create('locus', [m1], {strokeColor: 'red'});
 84      * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
 85      * <script type="text/javascript">
 86      *  lcex_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
 87      *  lcex_p1 = lcex_board.create('point', [0, 0]);
 88      *  lcex_p2 = lcex_board.create('point', [6, -1]);
 89      *  lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);
 90      *  lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);
 91      *  lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);
 92      *  lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);
 93      *  lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);
 94      *  lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);
 95      *  lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});
 96      * </script><pre>
 97      */
 98     JXG.createLocus = function (board, parents, attributes) {
 99         var c, p;
100 
101         if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) {
102             p = parents[0];
103         } else {
104             throw new Error("JSXGraph: Can't create locus with parent of type other than point." +
105                 "\nPossible parent types: [point]");
106         }
107 
108         c = board.create('curve', [[null], [null]], attributes);
109         c.dontCallServer = false;
110 
111         c.elType = 'locus';
112         c.setParents([p.id]);
113 
114         /**
115          * Should be documented in JXG.Curve
116          * @ignore
117          */
118         c.updateDataArray = function () {
119             var spe, cb, data;
120 
121             if (c.board.mode > 0) {
122                 return;
123             }
124 
125             spe = Symbolic.generatePolynomials(board, p, true).join('|');
126             if (spe === c.spe) {
127                 return;
128             }
129 
130             c.spe = spe;
131 
132             cb = function (x, y, eq, t) {
133                 c.dataX = x;
134                 c.dataY = y;
135 
136                 /**
137                  * The implicit definition of the locus.
138                  * @memberOf Locus.prototype
139                  * @name eq
140                  * @type String
141                  */
142                 c.eq = eq;
143 
144                 /**
145                  * The time it took to calculate the locus
146                  * @memberOf Locus.prototype
147                  * @name ctime
148                  * @type Number
149                  */
150                 c.ctime = t;
151 
152                 // convert equation and use it to build a generatePolynomial-method
153                 c.generatePolynomial = (function (equations) {
154                     return function (point) {
155                         var i,
156                             x = '(' + point.symbolic.x + ')',
157                             y = '(' + point.symbolic.y + ')',
158                             res = [];
159 
160                         for (i = 0; i < equations.length; i++) {
161                             res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y);
162                         }
163 
164                         return res;
165                     };
166                 }(eq));
167             };
168             data = Symbolic.geometricLocusByGroebnerBase(board, p, cb);
169 
170             cb(data.datax, data.datay, data.polynomial, data.exectime);
171         };
172         return c;
173     };
174 
175     JXG.registerElement('locus', JXG.createLocus);
176 
177     return {
178         createLocus: JXG.createLocus
179     };
180 });
181