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 this._set(key, value); 143 if (Type.exists(this.element2D)) { 144 this.element2D.setAttribute(attributes); 145 } 146 } 147 } 148 } 149 }, 150 151 // Documented in element.js 152 getAttribute: function(key) { 153 var result; 154 key = key.toLowerCase(); 155 156 switch (key) { 157 case "numberpointshigh": 158 case "stepsu": 159 case "stepsv": 160 result = this.visProp[key]; 161 break; 162 default: 163 if (Type.exists(this.element2D)) { 164 result = this.element2D.getAttribute(key); 165 } 166 break; 167 } 168 169 return result; 170 }, 171 172 // Documented in element.js 173 getAttributes: function() { 174 var attr = {}, 175 i, key, 176 attr3D = ['numberpointshigh', 'stepsu', 'stepsv'], 177 le = attr3D.length; 178 179 if (Type.exists(this.element2D)) { 180 attr = Type.merge(this.element2D.getAttributes()); 181 } 182 183 for (i = 0; i < le; i++) { 184 key = attr3D[i]; 185 if (Type.exists(this.visProp[key])) { 186 attr[key] = this.visProp[key]; 187 } 188 } 189 190 return attr; 191 }, 192 193 // /** 194 // * Add transformations to this element. 195 // * @param {JXG.GeometryElement} el 196 // * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} 197 // * or an array of {@link JXG.Transformation}s. 198 // * @returns {JXG.CoordsElement} Reference to itself. 199 // */ 200 addTransformGeneric: function (el, transform) { 201 var i, 202 list = Type.isArray(transform) ? transform : [transform], 203 len = list.length; 204 205 // There is only one baseElement possible 206 if (this.transformations.length === 0) { 207 this.baseElement = el; 208 } 209 210 for (i = 0; i < len; i++) { 211 this.transformations.push(list[i]); 212 } 213 214 return this; 215 }, 216 217 removeTransformGeneric: function (transform) { 218 var i, 219 list = Type.isArray(transform) ? transform : [transform], 220 len = list.length; 221 222 for (i = 0; i < len; i++) { 223 Type.removeElementFromArray(this.transformations, list[i]); 224 } 225 226 if (this.transformations.length === 0) { 227 this.baseElement = null; 228 } 229 230 return this; 231 }, 232 233 clearTransforms: function () { 234 this.transformations = []; 235 this.baseElement = null; 236 237 return this; 238 }, 239 240 /** 241 * Set position of the 2D element. This is a 242 * callback function, executed in {@link JXG.GeometryElement#setPosition}. 243 * @param {JXG.Transform} t transformation 244 * @private 245 * @see JXG.GeometryElement#setPosition 246 */ 247 setPosition2D: function(t) { 248 /* stub */ 249 }, 250 251 /** 252 * Project a 3D point to this element and update point.position. This function computes the 253 * preimage (u,v) of a 3D position (1, X, Y, Z) 254 * @param {Array} p 3D position of the point (array of length 4, homogeneous coordinates) 255 * @param {Array} params Changed in place to the new parameters of the point in terms of the elements functions X, Y, Z. 256 * For example for a surface, params will contain values (u,v) such that the new 3D position is 257 * p = [X(u, v), Z(u, v), Z(u, v)]. 258 * @returns {Array} 3D coordinates of the projected point with homogeneous coordinates of the form [1, x, y, z]. 259 */ 260 projectCoords: function(p, params) { 261 /* stub */ 262 }, 263 264 /** 265 * 266 * @param {*} pScr 267 * @param {*} params 268 * @returns 269 */ 270 // TODO check if Geometry.projectScreenCoordsToParametric has range or (range_u and range_v) - depending on the dimension given in params 271 projectScreenCoords: function (pScr, params, cyclic) { 272 return Geometry.projectScreenCoordsToParametric(pScr, this, params, cyclic); 273 }, 274 275 // Documented in element.js 276 remove: function() {} 277 278 }); 279 280 export default JXG.GeometryElement3D; 281