      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  utils/type
     39  base/element
     40   elements:
     41    point
     42    segment
     43    ticks
     44  */
     45
     46 /**
     47  * @fileoverview Geometry objects for measurements are defined in this file. This file stores all
     48  * style and functional properties that are required to use a tape measure on
     49  * a board.
     50  */
     51
     52 define([
     53     'jxg', 'utils/type', 'base/element'
     54 ], function (JXG, Type, GeometryElement) {
     55
     56     "use strict";
     57
     58     /**
     59      * @class A tape measure can be used to measure distances between points.
     60      * @pseudo
     61      * @description
     62      * @name Tapemeasure
     63      * @augments Segment
     64      * @constructor
     65      * @type JXG.Segment
     66      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
     67      * @param {Array_Array} start,end, The two arrays give the initial position where the tape measure
     68      * is drawn on the board.
     69      * @example
     70      * // Create a tape measure
     71      * var p1 = board.create('point', [0,0]);
     72      * var p2 = board.create('point', [1,1]);
     73      * var p3 = board.create('point', [3,1]);
     74      * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'});
     75      * </pre><div class="jxgbox" id="JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01" style="width: 200px; height: 200px;"></div>
     76      * <script type="text/javascript">
     77      *   (function () {
     78      *     var board = JXG.JSXGraph.initBoard('JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
     79      *     var p1 = board.create('point', [0,0]);
     80      *     var p2 = board.create('point', [1,1]);
     81      *     var p3 = board.create('point', [3,1]);
     82      *     var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'} );
     83      *   })();
     84      * </script><pre>
     85      */
     86     JXG.createTapemeasure = function (board, parents, attributes) {
     87         var pos0, pos1,
     88             attr, withTicks, withText, digits,
     89             li, p1, p2, n, ti;
     90
     91         pos0 = parents[0];
     92         pos1 = parents[1];
     93
     94         // start point
     95         attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point1');
     96         p1 = board.create('point', pos0,  attr);
     97
     98         // end point
     99         attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point2');
    100         p2 = board.create('point', pos1,  attr);
    101
    102         p1.setAttribute({ignoredSnapToPoints: [p2]});
    103         p2.setAttribute({ignoredSnapToPoints: [p1]});
    104
    105         // tape measure line
    106         attr = Type.copyAttributes(attributes, board.options, 'tapemeasure');
    107         withTicks = attr.withticks;
    108         withText = attr.withlabel;
    109         digits = attr.digits;
    110
    111         if (digits === 2 && attr.precision !== 2) {
    112             // Backward compatibility
    113             digits = attr.precision;
    114         }
    115
    116         // Below, we will replace the label by the measurement function.
    117         if (withText) {
    118             attr.withlabel = true;
    119         }
    120         li = board.create('segment', [p1, p2], attr);
    121         // p1, p2 are already added to li.inherits
    122
    123         if (withText) {
    124             if (attributes.name && attributes.name !== '') {
    125                 n = attributes.name + ' = ';
    126             } else {
    127                 n = '';
    128             }
    129             li.label.setText(function () {
    130                 return n + Type.toFixed(p1.Dist(p2), digits);
    131             });
    132         }
    133
    134         if (withTicks) {
    135             attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'ticks');
    136             //ticks  = 2;
    137             ti = board.create('ticks', [li, 0.1], attr);
    138             li.inherits.push(ti);
    139         }
    140
    141         // override the segments's remove method to ensure the removal of all elements
    142         /** @ignore */
    143         li.remove = function () {
    144             if (withTicks) {
    145                 li.removeTicks(ti);
    146             }
    147
    148             board.removeObject(p2);
    149             board.removeObject(p1);
    150
    151             GeometryElement.prototype.remove.call(this);
    152         };
    153
    154         /**
    155          * Returns the length of the tape measure.
    156          * @name Value
    157          * @memberOf Tapemeasure.prototype
    158          * @function
    159          * @returns {Number} length of tape measure.
    160          */
    161         li.Value = function () {
    162             return p1.Dist(p2);
    163         };
    164
    165         p1.dump = false;
    166         p2.dump = false;
    167
    168         li.elType = 'tapemeasure';
    169         li.getParents = function() {
    170             return [[p1.X(), p1.Y()], [p2.X(), p2.Y()]];
    171         };
    172
    173         li.subs = {
    174             point1: p1,
    175             point2: p2
    176         };
    177
    178         if (withTicks) {
    179             ti.dump = false;
    180         }
    181
    182         li.methodMap = JXG.deepCopy(li.methodMap, {
    183             Value: 'Value'
    184         });
    185
    186         li.prepareUpdate().update();
    187         if (!board.isSuspendedUpdate) {
    188             li.updateVisibility().updateRenderer();
    189             // The point updates are necessary in case of snapToGrid==true
    190             li.point1.updateVisibility().updateRenderer();
    191             li.point2.updateVisibility().updateRenderer();
    192         }
    193
    194         return li;
    195     };
    196
    197     JXG.registerElement('tapemeasure', JXG.createTapemeasure);
    198
    199     return {
    200         createTapemeasure: JXG.createTapemeasure
    201     };
    202 });
    203