      1 /*
      2     Copyright 2008-2025
      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 <https://www.gnu.org/licenses/>
     27     and <https://opensource.org/licenses/MIT/>.
     28  */
     29 /*global JXG:true, define: true*/
     30
     31 import JXG from "../jxg.js";
     32 import Type from "../utils/type.js";
     33
     34 /**
     35  * Constructs a new GeometryElement3D object.
     36  * @class This is the basic class for 3D geometry elements like Point3D and Line3D.
     37  * @constructor
     38  * @augments JXG.GeometryElement
     39  *
     40  * @param {string} elType
     41  */
     42 JXG.GeometryElement3D = function (view, elType) {
     43     this.elType = elType;
     44
     45     /**
     46      * Pointer to the view3D in which the element is constructed
     47      * @type JXG.View3D
     48      * @private
     49      */
     50     this.view = view;
     51
     52     this.id = this.view.board.setId(this, elType);
     53
     54     /**
     55      * Link to the 2D element(s) used to visualize the 3D element
     56      * in a view. In case, there are several 2D elements, it is an array.
     57      *
     58      * @type Array
     59      * @description JXG.GeometryElement,Array
     60      * @private
     61      *
     62      * @example
     63      *   p.element2D;
     64      */
     65     this.element2D = null;
     66
     67     /**
     68      * If this property exists (and is true) the element is a 3D element.
     69      *
     70      * @type Boolean
     71      * @private
     72      */
     73     this.is3D = true;
     74
     75     this.zIndex = 0.0;
     76
     77     this.view.objects[this.id] = this;
     78
     79     if (this.name !== "") {
     80         this.view.elementsByName[this.name] = this;
     81     }
     82 };
     83
     84 JXG.extend(JXG.GeometryElement3D.prototype, {
     85
     86     setAttr2D: function(attr3D) {
     87         var attr2D = attr3D;
     88
     89         attr2D.name = this.name;
     90         attr2D.element3d = this;
     91         attr2D.id = null; // The 2D element's id may not be controlled by the user.
     92
     93         return attr2D;
     94     },
     95
     96     // Documented in element.js
     97     setAttribute: function(attr) {
     98         var i, key, value, arg, pair,
     99         attributes = {};
    100
    101         // Normalize the user input
    102         for (i = 0; i < arguments.length; i++) {
    103             arg = arguments[i];
    104             if (Type.isString(arg)) {
    105                 // pairRaw is string of the form 'key:value'
    106                 pair = arg.split(":");
    107                 attributes[Type.trim(pair[0])] = Type.trim(pair[1]);
    108             } else if (!Type.isArray(arg)) {
    109                 // pairRaw consists of objects of the form {key1:value1,key2:value2,...}
    110                 JXG.extend(attributes, arg);
    111             } else {
    112                 // pairRaw consists of array [key,value]
    113                 attributes[arg[0]] = arg[1];
    114             }
    115         }
    116
    117         for (i in attributes) {
    118             if (attributes.hasOwnProperty(i)) {
    119                 key = i.replace(/\s+/g, "").toLowerCase();
    120                 value = attributes[i];
    121                 switch (key) {
    122                     case "numberpointshigh":
    123                     case "stepsu":
    124                     case "stepsv":
    125                         if (Type.exists(this.visProp[key]) &&
    126                         (!JXG.Validator[key] ||
    127                             (JXG.Validator[key] && JXG.Validator[key](value)) ||
    128                             (JXG.Validator[key] &&
    129                                 Type.isFunction(value) &&
    130                                 JXG.Validator[key](value())))
    131                         ) {
    132                             value =
    133                                 value.toLowerCase && value.toLowerCase() === "false"
    134                                     ? false
    135                                     : value;
    136                             this._set(key, value);
    137                         }
    138                     break;
    139                     default:
    140                         if (Type.exists(this.element2D)) {
    141                             this.element2D.setAttribute(attributes);
    142                         }
    143                 }
    144             }
    145         }
    146     },
    147
    148     // Documented in element.js
    149     getAttribute: function(key) {
    150         var result;
    151         key = key.toLowerCase();
    152
    153         switch (key) {
    154             case "numberpointshigh":
    155             case "stepsu":
    156             case "stepsv":
    157                 result = this.visProp[key];
    158                 break;
    159             default:
    160                 if (Type.exists(this.element2D)) {
    161                     result = this.element2D.getAttribute(key);
    162                 }
    163                 break;
    164         }
    165
    166         return result;
    167     },
    168
    169     // Documented in element.js
    170     getAttributes: function() {
    171         var attr = {},
    172             i, key,
    173             attr3D = ['numberpointshigh', 'stepsu', 'stepsv'],
    174             le = attr3D.length;
    175
    176         if (Type.exists(this.element2D)) {
    177             attr = Type.merge(this.element2D.getAttributes());
    178         }
    179
    180         for (i = 0; i < le; i++) {
    181             key = attr3D[i];
    182             if (Type.exists(this.visProp[key])) {
    183                 attr[key] = this.visProp[key];
    184             }
    185         }
    186
    187         return attr;
    188     },
    189
    190     // /**
    191     //  * Add transformations to this element.
    192     //  * @param {JXG.GeometryElement} el
    193     //  * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation}
    194     //  * or an array of {@link JXG.Transformation}s.
    195     //  * @returns {JXG.CoordsElement} Reference to itself.
    196     //  */
    197     addTransformGeneric: function (el, transform) {
    198         var i,
    199             list = Type.isArray(transform) ? transform : [transform],
    200             len = list.length;
    201
    202         // There is only one baseElement possible
    203         if (this.transformations.length === 0) {
    204             this.baseElement = el;
    205         }
    206
    207         for (i = 0; i < len; i++) {
    208             this.transformations.push(list[i]);
    209         }
    210
    211         return this;
    212     },
    213
    214     /**
    215      * Set position of the 2D element. This is a
    216      * callback function, executed in {@link JXG.GeometryElement#setPosition}.
    217      * @param {JXG.Transform} t transformation
    218      * @private
    219      * @see JXG.GeometryElement#setPosition
    220      */
    221     setPosition2D: function(t) {
    222         /* stub */
    223     },
    224
    225     /**
    226      * Project a 3D point to this element and update point.position.
    227      * @param {Array} p 3D position of the point (array of length 3)
    228      * @param {Array} params Changed in place to the new of the point in terms of the elements functions X, Y, Z.
    229      * For example for a surface, params will contain values (u,v) such that the new 3D position
    230      * p = [X(u, v), Z(u, v), Z(u, v)].
    231      * @returns {Array} 3D coordinates of the projected point with homogeneous coordinates of the form [1, x, y, z].
    232      */
    233     projectCoords: function(p, params) {
    234         /* stub */
    235     },
    236
    237     // Documented in element.js
    238     remove: function() {}
    239
    240 });
    241
    242 export default JXG.GeometryElement3D;
    243