1 /*
  2     Copyright 2008-2021
  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  see define call
 38  */
 39 
 40 /**
 41  * @fileoverview Example file for a triangle implemented as a extension to JSXGraph.
 42  */
 43 
 44 define([
 45     'jxg', 'options', 'utils/type', 'base/constants', 'base/line', 'base/polygon', 'base/point', 'base/element'
 46 ], function (JXG, Options, Type, Const, Line, Polygon, Point, GeometryElement) {
 47 
 48     "use strict";
 49 
 50     var priv = {
 51             removeSlopeTriangle: function () {
 52                 Polygon.Polygon.prototype.remove.call(this);
 53 
 54                 this.board.removeObject(this.toppoint);
 55                 this.board.removeObject(this.glider);
 56 
 57                 this.board.removeObject(this.baseline);
 58                 this.board.removeObject(this.basepoint);
 59 
 60                 this.board.removeObject(this.label);
 61 
 62                 if (this._isPrivateTangent) {
 63                     this.board.removeObject(this.tangent);
 64                 }
 65             },
 66             Value: function () {
 67                 return this.tangent.getSlope();
 68             }
 69         };
 70 
 71     /**
 72      * @class Slope triangle for a point on a line.
 73      * @pseudo
 74      * @name Slopetriangle
 75      * @augments JXG.Line
 76      * @constructor
 77      * @type JXG.Polygon
 78      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 79      * Parameter options:
 80      * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle.
 81      * @param {JXG.Line_JXG.Point} li, p A line and a point on that line.
 82      *  The user has to take care that the point is a member of the line.
 83      * @example
 84      * // Create a slopetriangle on a tangent
 85      * var f = board.create('plot', ['sin(x)']),
 86      *     g = board.create('glider', [1, 2, f]),
 87      *     t = board.create('tangent', [g]),
 88      *
 89      *     st = board.create('slopetriangle', [t]);
 90      *
 91      * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div>
 92      * <script type="text/javascript">
 93      * (function () {
 94      *   var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
 95      *     f = board.create('plot', ['sin(x)']),
 96      *     g = board.create('glider', [1, 2, f]),
 97      *     t = board.create('tangent', [g]),
 98      *
 99      *     st = board.create('slopetriangle', [t]);
100      * })();
101      * </script><pre>
102      *
103      * @example
104      * // Create a on a line and a point on that line
105      * var p1 = board.create('point', [-2, 3]),
106      *     p2 = board.create('point', [2, -3]),
107      *     li = board.create('line', [p1, p2]),
108      *     p = board.create('glider', [0, 0, li]),
109      *
110      *     st = board.create('slopetriangle', [li, p]);
111      *
112      * </pre><div class="jxgbox" id="JXGb52f451c-22cf-4677-852a-0bb9d764ee95" style="width: 300px; height: 300px;"></div>
113      * <script type="text/javascript">
114      * (function () {
115      *   var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
116      *     p1 = board.create('point', [-2, 3]),
117      *     p2 = board.create('point', [2, -3]),
118      *     li = board.create('line', [p1, p2]),
119      *     p = board.create('glider', [0, 0, li]),
120      *
121      *     st = board.create('slopetriangle', [li, p]);
122      * })();
123      * </script><pre>
124      */
125     JXG.createSlopeTriangle = function (board, parents, attributes) {
126         var el, tangent, tglide, glider, toppoint, baseline, basepoint, label, attr,
127             isPrivateTangent = false;
128 
129         if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) {
130             tangent = parents[0];
131             tglide = tangent.glider;
132         } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) {
133             tglide = parents[0];
134             attr = Type.copyAttributes(attributes, board.options,  'slopetriangle', 'tangent');
135             tangent = board.create('tangent', [tglide], attr);
136             isPrivateTangent = true;
137         } else if (parents.length === 2 &&
138                 parents[0].elementClass === Const.OBJECT_CLASS_LINE && Type.isPoint(parents[1])) {
139             tangent = parents[0];
140             tglide = parents[1];
141         } else {
142             throw new Error("JSXGraph: Can't create slope triangle with parent types '" + (typeof parents[0]) + "'.");
143         }
144 
145         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'basepoint');
146         basepoint = board.create('point', [function () {
147             return [tglide.X() + 1,  tglide.Y()];
148         }], attr);
149 
150         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'baseline');
151         baseline = board.create('line', [tglide, basepoint], attr);
152 
153         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'glider');
154         glider = board.create('glider', [tglide.X() + 1, tglide.Y(), baseline], attr);
155 
156         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'toppoint');
157         toppoint = board.create('point', [function () {
158             return [glider.X(), glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()];
159         }], attr);
160 
161         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle');
162         attr.borders = Type.copyAttributes(attr.borders, board.options, 'slopetriangle', 'borders');
163         el = board.create('polygon', [tglide, glider, toppoint], attr);
164 
165         /**
166          * Returns the value of the slope triangle, that is the slope of the tangent.
167          * @name Value
168          * @memberOf Slopetriangle.prototype
169          * @function
170          * @returns {Number} slope of the tangent.
171          */
172         el.Value = priv.Value;
173         el.tangent = tangent;
174         el._isPrivateTangent = isPrivateTangent;
175 
176         //el.borders[0].setArrow(false, {type: 2, size: 10});
177         //el.borders[1].setArrow(false, {type: 2, size: 10});
178         el.borders[2].setArrow(false, false);
179 
180         attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'label');
181         label = board.create('text', [
182             function () { return glider.X() + 0.1; },
183             function () { return (glider.Y() + toppoint.Y()) * 0.5; },
184             function () { return ''; }
185         ], attr);
186 
187         label._setText(function () {
188             return Type.toFixed(el.Value(), Type.evaluate(label.visProp.digits));
189         });
190         label.fullUpdate();
191 
192         el.glider = glider;
193         el.basepoint = basepoint;
194         el.baseline = baseline;
195         el.toppoint = toppoint;
196         el.label = label;
197 
198         el.subs = {
199             glider: glider,
200             basePoint: basepoint,
201             baseLine: baseline,
202             topPoint: toppoint,
203             label: label
204         };
205         el.inherits.push(glider, basepoint, baseline, toppoint, label);
206 
207         el.methodMap = JXG.deepCopy(el.methodMap, {
208             tangent: 'tangent',
209             glider: 'glider',
210             basepoint: 'basepoint',
211             baseline: 'baseline',
212             toppoint: 'toppoint',
213             label: 'label',
214             Value: 'Value',
215             V: 'Value'
216         });
217 
218         el.remove = priv.removeSlopeTriangle;
219 
220         return el;
221     };
222 
223     JXG.registerElement('slopetriangle', JXG.createSlopeTriangle);
224 
225     return {
226         createSlopeTriangle: JXG.createSlopeTriangle
227     };
228 });
229