      1 /*
      2  Copyright 2008-2024
      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.js";
     36 import Symbolic from "../math/symbolic.js";
     37 import Type from "../utils/type.js";
     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