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