1 /*
  2  Copyright 2008-2023
  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 <https://www.gnu.org/licenses/>
 29  and <https://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 /*global JXG: true, define: true*/
 33 /*jslint nomen: true, plusplus: true*/
 34 
 35 import JXG from "../jxg";
 36 import Symbolic from "../math/symbolic";
 37 import Type from "../utils/type";
 38 
 39 /**
 40  * @class This element is used to visualize the locus of a given dependent point.
 41  * @pseudo
 42  * @description The locus element is used to visualize the curve a given point describes.
 43  * @constructor
 44  * @name Locus
 45  * @type JXG.Curve
 46  * @augments JXG.Curve
 47  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 48  * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.
 49  * @example
 50  *  // This examples needs JXG.Server up and running, otherwise it won't work.
 51  *  p1 = board.create('point', [0, 0]);
 52  *  p2 = board.create('point', [6, -1]);
 53  *  c1 = board.create('circle', [p1, 2]);
 54  *  c2 = board.create('circle', [p2, 1.5]);
 55  *  g1 = board.create('glider', [6, 3, c1]);
 56  *  c3 = board.create('circle', [g1, 4]);
 57  *  g2 = board.create('intersection', [c2,c3,0]);
 58  *  m1 = board.create('midpoint', [g1,g2]);
 59  *  loc = board.create('locus', [m1], {strokeColor: 'red'});
 60  * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
 61  * <script type="text/javascript">
 62  *  lcex_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
 63  *  lcex_p1 = lcex_board.create('point', [0, 0]);
 64  *  lcex_p2 = lcex_board.create('point', [6, -1]);
 65  *  lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);
 66  *  lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);
 67  *  lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);
 68  *  lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);
 69  *  lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);
 70  *  lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);
 71  *  lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});
 72  * </script><pre>
 73  */
 74 JXG.createLocus = function (board, parents, attributes) {
 75     var c, p;
 76 
 77     if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) {
 78         p = parents[0];
 79     } else {
 80         throw new Error(
 81             "JSXGraph: Can't create locus with parent of type other than point." +
 82                 "\nPossible parent types: [point]"
 83         );
 84     }
 85 
 86     c = board.create("curve", [[null], [null]], attributes);
 87     c.dontCallServer = false;
 88 
 89     c.elType = "locus";
 90     c.setParents([p.id]);
 91 
 92     /**
 93      * Should be documented in JXG.Curve
 94      * @ignore
 95      */
 96     c.updateDataArray = function () {
 97         var spe, cb, data;
 98 
 99         if (c.board.mode > 0) {
100             return;
101         }
102 
103         spe = Symbolic.generatePolynomials(board, p, true).join("|");
104         if (spe === c.spe) {
105             return;
106         }
107 
108         c.spe = spe;
109 
110         cb = function (x, y, eq, t) {
111             c.dataX = x;
112             c.dataY = y;
113 
114             /**
115              * The implicit definition of the locus.
116              * @memberOf Locus.prototype
117              * @name eq
118              * @type String
119              */
120             c.eq = eq;
121 
122             /**
123              * The time it took to calculate the locus
124              * @memberOf Locus.prototype
125              * @name ctime
126              * @type Number
127              */
128             c.ctime = t;
129 
130             // convert equation and use it to build a generatePolynomial-method
131             c.generatePolynomial = (function (equations) {
132                 return function (point) {
133                     var i,
134                         x = "(" + point.symbolic.x + ")",
135                         y = "(" + point.symbolic.y + ")",
136                         res = [];
137 
138                     for (i = 0; i < equations.length; i++) {
139                         res[i] = equations[i]
140                             .replace(/\*\*/g, "^")
141                             .replace(/x/g, x)
142                             .replace(/y/g, y);
143                     }
144 
145                     return res;
146                 };
147             })(eq);
148         };
149         data = Symbolic.geometricLocusByGroebnerBase(board, p, cb);
150 
151         cb(data.datax, data.datay, data.polynomial, data.exectime);
152     };
153     return c;
154 };
155 
156 JXG.registerElement("locus", JXG.createLocus);
157 
158 // export default {
159 //     createLocus: JXG.createLocus
160 // };
161