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             return n + Type.toFixed(p1.Dist(p2), digits);
116         });
117     }
118 
119     if (withTicks) {
120         attr = Type.copyAttributes(attributes, board.options, "tapemeasure", "ticks");
121         //ticks  = 2;
122         ti = board.create("ticks", [li, 0.1], attr);
123         li.inherits.push(ti);
124     }
125 
126     // override the segments's remove method to ensure the removal of all elements
127     /** @ignore */
128     li.remove = function () {
129         if (withTicks) {
130             li.removeTicks(ti);
131         }
132 
133         board.removeObject(p2);
134         board.removeObject(p1);
135 
136         GeometryElement.prototype.remove.call(this);
137     };
138 
139     /**
140      * Returns the length of the tape measure.
141      * @name Value
142      * @memberOf Tapemeasure.prototype
143      * @function
144      * @returns {Number} length of tape measure.
145      */
146     li.Value = function () {
147         return p1.Dist(p2);
148     };
149 
150     p1.dump = false;
151     p2.dump = false;
152 
153     li.elType = "tapemeasure";
154     li.getParents = function () {
155         return [
156             [p1.X(), p1.Y()],
157             [p2.X(), p2.Y()]
158         ];
159     };
160 
161     li.subs = {
162         point1: p1,
163         point2: p2
164     };
165 
166     if (withTicks) {
167         ti.dump = false;
168     }
169 
170     li.methodMap = JXG.deepCopy(li.methodMap, {
171         Value: "Value"
172     });
173 
174     li.prepareUpdate().update();
175     if (!board.isSuspendedUpdate) {
176         li.updateVisibility().updateRenderer();
177         // The point updates are necessary in case of snapToGrid==true
178         li.point1.updateVisibility().updateRenderer();
179         li.point2.updateVisibility().updateRenderer();
180     }
181 
182     return li;
183 };
184 
185 JXG.registerElement("tapemeasure", JXG.createTapemeasure);
186 
187 // export default {
188 //     createTapemeasure: JXG.createTapemeasure
189 // };
190