1 /*
  2     Copyright 2008-2023
  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";
 32 import Type from "../utils/type";
 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  * @param {string} elType
 39  * @borrows JXG.EventEmitter#on as this.on
 40  * @borrows JXG.EventEmitter#off as this.off
 41  * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers
 42  * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers
 43  */
 44 JXG.GeometryElement3D = function (view, elType) {
 45     this.elType = elType;
 46     this.id = this.board.setId(this, elType);
 47 
 48     /**
 49      * Pointer to the view3D in which the element is constructed
 50      * @type JXG.View3D
 51      * @private
 52      */
 53     this.view = view;
 54 
 55     /**
 56      * Link to the 2D element(s) used to visualize the 3D element
 57      * in a view. In case, there are several 2D elements, it is an array.
 58      *
 59      * @type 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.view.objects[this.id] = this;
 76 
 77     if (this.name !== "") {
 78         this.view.elementsByName[this.name] = this;
 79     }
 80 };
 81 
 82 JXG.extend(JXG.GeometryElement3D.prototype, {
 83 
 84     setAttr2D: function(attr3D) {
 85         var attr2D = attr3D;
 86 
 87         attr2D.name = this.name;
 88 
 89         return attr2D;
 90     },
 91 
 92     // Documented in element.js
 93     setAttribute: function(attr) {
 94         var i, key, value, arg, pair,
 95         attributes = {};
 96 
 97         // Normalize the user input
 98         for (i = 0; i < arguments.length; i++) {
 99             arg = arguments[i];
100             if (Type.isString(arg)) {
101                 // pairRaw is string of the form 'key:value'
102                 pair = arg.split(":");
103                 attributes[Type.trim(pair[0])] = Type.trim(pair[1]);
104             } else if (!Type.isArray(arg)) {
105                 // pairRaw consists of objects of the form {key1:value1,key2:value2,...}
106                 JXG.extend(attributes, arg);
107             } else {
108                 // pairRaw consists of array [key,value]
109                 attributes[arg[0]] = arg[1];
110             }
111         }
112 
113         for (i in attributes) {
114             if (attributes.hasOwnProperty(i)) {
115                 key = i.replace(/\s+/g, "").toLowerCase();
116                 value = attributes[i];
117                 switch (key) {
118                     case "numberpointshigh":
119                     case "stepsu":
120                     case "stepsv":
121                         if (Type.exists(this.visProp[key]) &&
122                         (!JXG.Validator[key] ||
123                             (JXG.Validator[key] && JXG.Validator[key](value)) ||
124                             (JXG.Validator[key] &&
125                                 Type.isFunction(value) &&
126                                 JXG.Validator[key](value())))
127                         ) {
128                             value =
129                                 value.toLowerCase && value.toLowerCase() === "false"
130                                     ? false
131                                     : value;
132                             this._set(key, value);
133                         }
134                     break;
135                     default:
136                         if (Type.exists(this.element2D)) {
137                             this.element2D.setAttribute(attributes);
138                         }
139                 }
140             }
141         }
142     },
143 
144     // Documented in element.js
145     getAttribute: function(key) {
146         var result;
147         key = key.toLowerCase();
148 
149         switch (key) {
150             case "numberpointshigh":
151             case "stepsu":
152             case "stepsv":
153                 result = this.visProp[key];
154                 break;
155             default:
156                 if (Type.exists(this.element2D)) {
157                     result = this.element2D.getAttribute(key);
158                 }
159                 break;
160         }
161 
162         return result;
163     },
164 
165     // Documented in element.js
166     getAttributes: function() {
167         var attr = {},
168             i, key,
169             attr3D = ['numberpointshigh', 'stepsu', 'stepsv'],
170             le = attr3D.length;
171 
172         if (Type.exists(this.element2D)) {
173             attr = Type.merge(this.element2D.getAttributes());
174         }
175 
176         for (i = 0; i < le; i++) {
177             key = attr3D[i];
178             if (Type.exists(this.visProp[key])) {
179                 attr[key] = this.visProp[key];
180             }
181         }
182 
183         return attr;
184     }
185 
186 });
187 
188 export default JXG.GeometryElement3D;
189