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