1 /*
  2     Copyright 2008-2022
  3         Matthias Ehmann,
  4         Carsten Miller,
  5         Andreas Walter,
  6         Alfred Wassermann
  7 
  8     This file is part of JSXGraph.
  9 
 10     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 11 
 12     You can redistribute it and/or modify it under the terms of the
 13 
 14       * GNU Lesser General Public License as published by
 15         the Free Software Foundation, either version 3 of the License, or
 16         (at your option) any later version
 17       OR
 18       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 19 
 20     JSXGraph is distributed in the hope that it will be useful,
 21     but WITHOUT ANY WARRANTY; without even the implied warranty of
 22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 23     GNU Lesser General Public License for more details.
 24 
 25     You should have received a copy of the GNU Lesser General Public License and
 26     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 27     and <http://opensource.org/licenses/MIT/>.
 28  */
 29 /*global JXG:true, define: true*/
 30 
 31 define(['jxg', 'base/constants', 'utils/type'], function (JXG, Const, Type) {
 32     "use strict";
 33 
 34     /**
 35      * Constructor for 3D curves.
 36      * @class Creates a new 3D curve object. Do not use this constructor to create a 3D curve. Use {@link JXG.Board#create} with type {@link Curve3D} instead.
 37      *
 38      * @augments JXG.GeometryElement3D
 39      * @augments JXG.GeometryElement
 40      * @param {View3D} view
 41      * @param {Function} F
 42      * @param {Function} X
 43      * @param {Function} Y
 44      * @param {Function} Z
 45      * @param {Array} range
 46      * @param {Object} attributes
 47      * @see JXG.Board#generateName
 48      */
 49      JXG.Curve3D = function (view, F, X, Y, Z, range, attributes) {
 50         this.constructor(view.board, attributes, Const.OBJECT_TYPE_CURVE3D, Const.OBJECT_CLASS_3D);
 51         this.constructor3D(view, 'surface3d');
 52 
 53         this.id = this.view.board.setId(this, 'S3D');
 54         this.board.finalizeAdding(this);
 55 
 56         this.F = F;
 57 
 58         /**
 59          * Function which maps u to x; i.e. it defines the x-coordinate of the curve
 60          * @function
 61          * @returns Number
 62          */
 63         this.X = X;
 64 
 65         /**
 66          * Function which maps u to y; i.e. it defines the y-coordinate of the curve
 67          * @function
 68          * @returns Number
 69          */
 70         this.Y = Y;
 71 
 72         /**
 73          * Function which maps u to z; i.e. it defines the x-coordinate of the curve
 74          * @function
 75          * @returns Number
 76          */
 77         this.Z = Z;
 78 
 79         if (this.F !== null) {
 80             this.X = function(u) { return this.F(u)[0]; };
 81             this.Y = function(u) { return this.F(u)[1]; };
 82             this.Z = function(u) { return this.F(u)[2]; };
 83         }
 84 
 85         this.range = range;
 86 
 87         this.methodMap = Type.deepCopy(this.methodMap, {
 88             // TODO
 89         });
 90     };
 91     JXG.Curve3D.prototype = new JXG.GeometryElement();
 92     Type.copyPrototypeMethods(JXG.Curve3D, JXG.GeometryElement3D, 'constructor3D');
 93 
 94     JXG.extend(JXG.Curve3D.prototype, /** @lends JXG.Curve3D.prototype */ {
 95 
 96         updateDataArray: function () {
 97             var steps = Type.evaluate(this.visProp.numberpointshigh),
 98                 r, s, e, delta,
 99                 c2d, u,
100                 dataX, dataY,
101                 p = [0, 0, 0];
102 
103             dataX = [];
104             dataY = [];
105 
106             if (Type.isArray(this.X)) {
107                 steps = this.X.length;
108                 for (u = 0; u < steps; u++) {
109                     p = [this.X[u], this.Y[u], this.Z[u]];
110                     c2d = this.view.project3DTo2D(p);
111                     dataX.push(c2d[1]);
112                     dataY.push(c2d[2]);
113                 }
114             } else {
115                 r = Type.evaluate(this.range);
116                 s = r[0];
117                 e = r[1];
118                 delta = (e - s) / (steps - 1);
119                 for (u = s; u <= e; u += delta) {
120                     if (this.F !== null){
121                         p = this.F(u);
122                     } else {
123                         p = [this.X(u), this.Y(u), this.Z(u)];
124                     }
125                     c2d = this.view.project3DTo2D(p);
126                     dataX.push(c2d[1]);
127                     dataY.push(c2d[2]);
128                 }
129             }
130             return {'X': dataX, 'Y': dataY};
131         },
132 
133         update: function () { return this; },
134 
135         updateRenderer: function () {
136             this.needsUpdate = false;
137             return this;
138         }
139     });
140 
141     /**
142      * @class This element creates a 3D parametric curves.
143      * @pseudo
144      * @description A 3D parametric curve is defined by a function
145      *    <i>F: R<sup>1</sup> → R<sup>3</sup></i>.
146      *
147      * @name Curve3D
148      * @augments Curve
149      * @constructor
150      * @type Object
151      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
152      * @param {Function_Function_Function_Array,Function} F<sub>X</sub>,F<sub>Y</sub>,F<sub>Z</sub>,range
153      * F<sub>X</sub>(u), F<sub>Y</sub>(u), F<sub>Z</sub>(u) are functions returning a number, range is the array containing
154      * lower and upper bound for the range of the parameter u. range may also be a function returning an array of length two.
155      * @param {Function_Array,Function} F,range Alternatively: F<sub>[X,Y,Z]</sub>(u) a function returning an array [x,y,z] of
156      * numbers, range as above.
157      * @param {Array_Array_Array} X,Y,Z Three arrays containing the coordinate points which define the curve.
158      */
159     JXG.createCurve3D = function (board, parents, attributes) {
160         var view = parents[0],
161             F, X, Y, Z, range,
162             attr, el;
163 
164         if (parents.length === 3) {
165             F = parents[1];
166             range = parents[2];
167             X = null;
168             Y = null;
169             Z = null;
170         } else {
171             X = parents[1];
172             Y = parents[2];
173             Z = parents[3];
174             range = parents[4];
175             F = null;
176         }
177         // TODO Throw error
178 
179         attr = Type.copyAttributes(attributes, board.options, 'curve3d');
180         el = new JXG.Curve3D(view, F, X, Y, Z, range, attr);
181 
182         el.element2D = board.create('curve', [[], []], attr);
183         el.element2D.updateDataArray = function() {
184             var ret = el.updateDataArray();
185             this.dataX = ret.X;
186             this.dataY = ret.Y;
187         };
188         el.addChild(el.element2D);
189         el.inherits.push(el.element2D);
190         el.element2D.setParents(el);
191 
192         el.element2D.prepareUpdate().update();
193         if (!board.isSuspendedUpdate) {
194             el.element2D.updateVisibility().updateRenderer();
195         }
196 
197         return el;
198     };
199     JXG.registerElement('curve3d', JXG.createCurve3D);
200 
201 });