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 Const from "../base/constants.js"; 33 import Type from "../utils/type.js"; 34 35 /** 36 * A 3D polyhedron is a basic geometric element. 37 * @class Creates a new 3D point object. Do not use this constructor to create a 3D point. Use {@link JXG.View3D#create} with 38 * type {@link Polyhedron3D} instead. 39 * 40 * @augments JXG.GeometryElement3D 41 * @augments JXG.GeometryElement 42 * @param {JXG.View3D} view The 3D view the polyhedron is drawn on. 43 * @param {Object} polyhedron Defining data for the polyhedron, i.e. vertice coordinates and faces, which are lists of vertex numbers or keys. The structure of this object is 44 * <pre>polyhedron = { 45 * view: view, 46 * vertices: {}, 47 * coords: {}, 48 * coords2D: {}, 49 * zIndex: {}, 50 * faces: [] 51 * };</pre> 52 * @param {Array} faces List of face3d objects. These have been already generated in `createPolyhedron3D`. 53 * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#polyhedron3d} and {@link JXG.Options#elements}, 54 * and optionally a name and an id. 55 */ 56 JXG.Polyhedron3D = function (view, polyhedron, faces, attributes) { 57 var e, 58 genericMethods, 59 generateMethod, 60 that = this; 61 62 this.constructor(view.board, attributes, Const.OBJECT_TYPE_POLYHEDRON3D, Const.OBJECT_CLASS_3D); 63 this.constructor3D(view, 'polyhedron3d'); 64 65 this.board.finalizeAdding(this); 66 67 this.elType = 'polyhedron3d'; 68 69 /** 70 * List of Face3D objects. 71 * @name Polyhedron3D#faces 72 * @type Array 73 */ 74 this.faces = faces; 75 76 /** 77 * Number of faces 78 * @name Polyhedron3D#numberFaces 79 * @type Number 80 */ 81 this.numberFaces = faces.length; 82 83 /** 84 * Contains the defining data of the polyhedron: 85 * Definitions of vertices and a list of vertices for each face. This is pretty much the input given 86 * in the construction of the polyhedron plus internal data. 87 * @name Polyhedron3D#def 88 * @type Object 89 * @example 90 * polyhedron = { 91 * view: view, 92 * vertices: {}, 93 * coords: {}, 94 * coords2D: {}, 95 * zIndex: {}, 96 * faces: [] 97 * }; 98 */ 99 this.def = polyhedron; 100 101 // Simultaneous methods for all faces 102 genericMethods = [ 103 "setAttribute", 104 "setParents", 105 "prepareUpdate", 106 "updateRenderer", 107 "update", 108 "fullUpdate", 109 "highlight", 110 "noHighlight" 111 ]; 112 113 /** 114 * Generate methods like `updateRenderer` or `setAttribute` which call simultaneously 115 * the method with the same name for each face3d element of the polyhedron. 116 * @param {String} what Method name 117 * @returns {Function} Function consisting of a loop that calls the method for each face. 118 */ 119 generateMethod = function (what) { 120 return function () { 121 var i; 122 123 for (i in that.faces) { 124 if (that.faces.hasOwnProperty(i)) { 125 if (Type.exists(that.faces[i][what])) { 126 that.faces[i][what].apply(that.faces[i], arguments); 127 } 128 } 129 } 130 return that; 131 }; 132 }; 133 134 for (e = 0; e < genericMethods.length; e++) { 135 this[genericMethods[e]] = generateMethod(genericMethods[e]); 136 } 137 }; 138 139 JXG.Polyhedron3D.prototype = new JXG.GeometryElement(); 140 141 Type.copyPrototypeMethods(JXG.Polyhedron3D, JXG.GeometryElement3D, 'constructor3D'); 142 Type.copyMethodMap(JXG.Polyhedron3D, { 143 setAttribute: "setAttribute", 144 setParents: "setParents", 145 addTransform: "addTransform", 146 removeTransform: "removeTransform", 147 clearTransforms: "clearTransforms" 148 }); 149 150 JXG.extend( 151 JXG.Polyhedron3D.prototype, 152 /** @lends JXG.Polyhedron3D.prototype */ { 153 154 // Already documented in element3d.js 155 addTransform: function (el, transform) { 156 if (this.faces.length > 0 && el.faces.length > 0) { 157 this.faces[0].addTransform(el.faces[0], transform); 158 } else { 159 throw new Error("Adding transformation failed. At least one of the two polyhedra has no faces."); 160 } 161 return this; 162 }, 163 164 // Already documented in element3d.js 165 removeTransform: function (transform) { 166 if (this.faces.length > 0) { 167 this.faces[0].removeTransform(transform); 168 } else { 169 throw new Error("Removing transformation failed. The polyhedron has no faces."); 170 } 171 return this; 172 }, 173 174 // Already documented in element3d.js 175 clearTransforms: function () { 176 if (this.faces.length > 0) { 177 this.faces[0].clearTransforms(); 178 } else { 179 throw new Error("Removing transformation failed. The polyhedron has no faces."); 180 } 181 return this; 182 }, 183 184 /** 185 * Output polyhedron in ASCII STL format. 186 * Normals are ignored and output as 0 0 0. 187 * 188 * @param {String} name Set name of the model, overwrites property name 189 * @returns String 190 */ 191 toSTL: function(name) { 192 var i, j, v, f, c, le, 193 txt = 'solid '; 194 195 if (name === undefined) { 196 name = this.name; 197 } 198 199 txt += name + '\n'; 200 201 for (i = 0; i < this.def.faces.length; i++) { 202 txt += ' facet normal 0 0 0\n outer loop\n'; 203 f = this.def.faces[i]; 204 le = f.length; 205 v = this.def.coords; 206 for (j = 0; j < le; j++) { 207 c = v[f[j]]; 208 txt += ' vertex ' + c[1] + ' ' + c[2] + ' ' + c[3] + '\n'; 209 } 210 txt += ' endloop\n endfacet\n'; 211 } 212 txt += 'endsolid ' + name + '\n'; 213 214 return txt; 215 } 216 } 217 ); 218 219 /** 220 * @class A polyhedron in a 3D view consists of faces. 221 * @pseudo 222 * @description Create a polyhedron in a 3D view consisting of faces. Faces can 223 * be 0-, 1- or 2-dimensional. 224 * 225 * @name Polyhedron3D 226 * @augments JXG.GeometryElement3D 227 * @constructor 228 * @type Object 229 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 230 * @param {} TODO 231 * 232 * @example 233 * var box = [-4, 4]; 234 * var view = board.create( 235 * 'view3d', 236 * [[-5, -3], [8, 8], 237 * [box, box, box]], 238 * { 239 * projection: 'parallel', 240 * trackball: { enabled: false }, 241 * depthOrder: { 242 * enabled: true 243 * }, 244 * xPlaneRear: { visible: false }, 245 * yPlaneRear: { visible: false }, 246 * zPlaneRear: { fillOpacity: 0.2 } 247 * } 248 * ); 249 * var cube = view.create('polyhedron3d', [ 250 * [ 251 * [-3, -3, -3], 252 * [3, -3, -3], 253 * [3, 3, -3], 254 * [-3, 3, -3], 255 * 256 * [-3, -3, 3], 257 * [3, -3, 3], 258 * [3, 3, 3], 259 * [-3, 3, 3] 260 * ], 261 * [ 262 * [0, 1, 2, 3], 263 * [0, 1, 5, 4], 264 * [[1, 2, 6, 5], { fillColor: 'black', fillOpacity: 0.5, strokeWidth: 5 }], 265 * [2, 3, 7, 6], 266 * [3, 0, 4, 7], 267 * [4, 5, 6, 7] 268 * ] 269 * ], { 270 * fillColorArray: ['blue', 'red', 'yellow'] 271 * }); 272 * 273 * </pre><div id="JXG2ab3325b-4171-4a00-9896-a1b886969e18" class="jxgbox" style="width: 300px; height: 300px;"></div> 274 * <script type="text/javascript"> 275 * (function() { 276 * var board = JXG.JSXGraph.initBoard('JXG2ab3325b-4171-4a00-9896-a1b886969e18', 277 * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); 278 * var box = [-4, 4]; 279 * var view = board.create( 280 * 'view3d', 281 * [[-5, -3], [8, 8], 282 * [box, box, box]], 283 * { 284 * projection: 'parallel', 285 * trackball: { enabled: false }, 286 * depthOrder: { 287 * enabled: true 288 * }, 289 * xPlaneRear: { visible: false }, 290 * yPlaneRear: { visible: false }, 291 * zPlaneRear: { fillOpacity: 0.2 } 292 * } 293 * ); 294 * var cube = view.create('polyhedron3d', [ 295 * [ 296 * [-3, -3, -3], 297 * [3, -3, -3], 298 * [3, 3, -3], 299 * [-3, 3, -3], 300 * 301 * [-3, -3, 3], 302 * [3, -3, 3], 303 * [3, 3, 3], 304 * [-3, 3, 3] 305 * ], 306 * [ 307 * [0, 1, 2, 3], 308 * [0, 1, 5, 4], 309 * [[1, 2, 6, 5], { fillColor: 'black', fillOpacity: 0.5, strokeWidth: 5 }], 310 * [2, 3, 7, 6], 311 * [3, 0, 4, 7], 312 * [4, 5, 6, 7] 313 * ] 314 * ], { 315 * fillColorArray: ['blue', 'red', 'yellow'] 316 * }); 317 * 318 * })(); 319 * 320 * </script><pre> 321 * 322 * @example 323 * var box = [-4, 4]; 324 * var view = board.create( 325 * 'view3d', 326 * [[-5, -3], [8, 8], 327 * [box, box, box]], 328 * { 329 * projection: 'parallel', 330 * trackball: { enabled: false }, 331 * depthOrder: { 332 * enabled: true 333 * }, 334 * xPlaneRear: { visible: false }, 335 * yPlaneRear: { visible: false }, 336 * zPlaneRear: { fillOpacity: 0.2 } 337 * } 338 * ); 339 * var aa = view.create('point3d', [-3, -3, -3], { name: 'A', layer: 12}); 340 * var bb = view.create('point3d', [() => aa.X(), () => aa.Y(), 3], { name: 'B', fixed: true, layer: 12}); 341 * var cube = view.create('polyhedron3d', [ 342 * { 343 * a: 'A', 344 * b: [3, -3, -3], 345 * c: [3, 3, -3], 346 * d: [-3, 3, -3], 347 * 348 * e: bb, 349 * f: [3, -3, 3], 350 * g: [3, 3, 3], 351 * h: [-3, 3, 3] 352 * }, 353 * [ 354 * ['a', 'b', 'c', 'd'], 355 * ['a', 'b', 'f', 'e'], 356 * ['b', 'c', 'g', 'f'], 357 * ['c', 'd', 'h', 'g'], 358 * ['d', 'a', 'e', 'h'], 359 * ['e', 'f', 'g', 'h'], 360 * 361 * ['a', 'g'], // Edge 362 * ['f'] // Vertex 363 * ] 364 * ], { 365 * fillColorArray: ['blue', 'red', 'yellow'], 366 * fillOpacity: 0.4, 367 * layer: 12 368 * }); 369 * cube.faces[6].setAttribute({ strokeWidth: 5 }); 370 * cube.faces[7].setAttribute({ strokeWidth: 10 }); 371 * 372 * </pre><div id="JXG1e862f44-3e38-424b-98d5-f972338a8b7f" class="jxgbox" style="width: 300px; height: 300px;"></div> 373 * <script type="text/javascript"> 374 * (function() { 375 * var board = JXG.JSXGraph.initBoard('JXG1e862f44-3e38-424b-98d5-f972338a8b7f', 376 * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); 377 * var box = [-4, 4]; 378 * var view = board.create( 379 * 'view3d', 380 * [[-5, -3], [8, 8], 381 * [box, box, box]], 382 * { 383 * projection: 'parallel', 384 * trackball: { enabled: false }, 385 * depthOrder: { 386 * enabled: true 387 * }, 388 * xPlaneRear: { visible: false }, 389 * yPlaneRear: { visible: false }, 390 * zPlaneRear: { fillOpacity: 0.2 } 391 * } 392 * ); 393 * var aa = view.create('point3d', [-3, -3, -3], { name: 'A', layer: 12}); 394 * var bb = view.create('point3d', [() => aa.X(), () => aa.Y(), 3], { name: 'B', fixed: true, layer: 12}); 395 * var cube = view.create('polyhedron3d', [ 396 * { 397 * a: 'A', 398 * b: [3, -3, -3], 399 * c: [3, 3, -3], 400 * d: [-3, 3, -3], 401 * 402 * e: bb, 403 * f: [3, -3, 3], 404 * g: [3, 3, 3], 405 * h: [-3, 3, 3] 406 * }, 407 * [ 408 * ['a', 'b', 'c', 'd'], 409 * ['a', 'b', 'f', 'e'], 410 * ['b', 'c', 'g', 'f'], 411 * ['c', 'd', 'h', 'g'], 412 * ['d', 'a', 'e', 'h'], 413 * ['e', 'f', 'g', 'h'], 414 * 415 * ['a', 'g'], // Edge 416 * ['f'] // Vertex 417 * ] 418 * ], { 419 * fillColorArray: ['blue', 'red', 'yellow'], 420 * fillOpacity: 0.4, 421 * layer: 12 422 * }); 423 * cube.faces[6].setAttribute({ strokeWidth: 5 }); 424 * cube.faces[7].setAttribute({ strokeWidth: 10 }); 425 * 426 * })(); 427 * 428 * </script><pre> 429 * 430 * @example 431 * var box = [-4, 4]; 432 * var view = board.create( 433 * 'view3d', 434 * [[-5, -3], [8, 8], 435 * [box, box, box]], 436 * { 437 * projection: 'parallel', 438 * trackball: { enabled: false }, 439 * depthOrder: { 440 * enabled: true 441 * }, 442 * xPlaneRear: { visible: false }, 443 * yPlaneRear: { visible: false }, 444 * zPlaneRear: { fillOpacity: 0.2 } 445 * } 446 * ); 447 * var s = board.create('slider', [[-4, -6], [4, -6], [0, 2, 4]], { name: 's' }); 448 * var cube = view.create('polyhedron3d', [ 449 * [ 450 * () => { let f = s.Value(); return [-f, -f, -f]; }, 451 * () => { let f = s.Value(); return [f, -f, -f]; }, 452 * () => { let f = s.Value(); return [f, f, -f]; }, 453 * () => { let f = s.Value(); return [-f, f, -f]; }, 454 * 455 * () => { let f = s.Value(); return [-f, -f, f]; }, 456 * () => { let f = s.Value(); return [f, -f, f]; }, 457 * () => { let f = s.Value(); return [f, f, f]; }, 458 * // () => { let f = s.Value(); return [-f, f, f]; } 459 * [ () => -s.Value(), () => s.Value(), () => s.Value() ] 460 * ], 461 * [ 462 * [0, 1, 2, 3], 463 * [0, 1, 5, 4], 464 * [1, 2, 6, 5], 465 * [2, 3, 7, 6], 466 * [3, 0, 4, 7], 467 * [4, 5, 6, 7], 468 * ] 469 * ], { 470 * strokeWidth: 3, 471 * fillOpacity: 0.6, 472 * fillColorArray: ['blue', 'red', 'yellow'], 473 * shader: { 474 * enabled:false 475 * } 476 * }); 477 * 478 * </pre><div id="JXG6f27584b-b648-4743-a864-a6c559ead00e" class="jxgbox" style="width: 300px; height: 300px;"></div> 479 * <script type="text/javascript"> 480 * (function() { 481 * var board = JXG.JSXGraph.initBoard('JXG6f27584b-b648-4743-a864-a6c559ead00e', 482 * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); 483 * var box = [-4, 4]; 484 * var view = board.create( 485 * 'view3d', 486 * [[-5, -3], [8, 8], 487 * [box, box, box]], 488 * { 489 * projection: 'parallel', 490 * trackball: { enabled: false }, 491 * depthOrder: { 492 * enabled: true 493 * }, 494 * xPlaneRear: { visible: false }, 495 * yPlaneRear: { visible: false }, 496 * zPlaneRear: { fillOpacity: 0.2 } 497 * } 498 * ); 499 * var s = board.create('slider', [[-4, -6], [4, -6], [0, 2, 4]], { name: 's' }); 500 * var cube = view.create('polyhedron3d', [ 501 * [ 502 * () => { let f = s.Value(); return [-f, -f, -f]; }, 503 * () => { let f = s.Value(); return [f, -f, -f]; }, 504 * () => { let f = s.Value(); return [f, f, -f]; }, 505 * () => { let f = s.Value(); return [-f, f, -f]; }, 506 * 507 * () => { let f = s.Value(); return [-f, -f, f]; }, 508 * () => { let f = s.Value(); return [f, -f, f]; }, 509 * () => { let f = s.Value(); return [f, f, f]; }, 510 * // () => { let f = s.Value(); return [-f, f, f]; } 511 * [ () => -s.Value(), () => s.Value(), () => s.Value() ] 512 * ], 513 * [ 514 * [0, 1, 2, 3], 515 * [0, 1, 5, 4], 516 * [1, 2, 6, 5], 517 * [2, 3, 7, 6], 518 * [3, 0, 4, 7], 519 * [4, 5, 6, 7], 520 * ] 521 * ], { 522 * strokeWidth: 3, 523 * fillOpacity: 0.6, 524 * fillColorArray: ['blue', 'red', 'yellow'], 525 * shader: { 526 * enabled:false 527 * } 528 * }); 529 * 530 * })(); 531 * 532 * </script><pre> 533 * 534 * @example 535 * var box = [-4, 4]; 536 * var view = board.create( 537 * 'view3d', 538 * [[-5, -3], [8, 8], 539 * [box, box, box]], 540 * { 541 * projection: 'parallel', 542 * trackball: { enabled: false }, 543 * depthOrder: { 544 * enabled: true 545 * }, 546 * xPlaneRear: { visible: false }, 547 * yPlaneRear: { visible: false }, 548 * zPlaneRear: { fillOpacity: 0.2 } 549 * } 550 * ); 551 * let rho = 1.6180339887; 552 * let vertexList = [ 553 * [0, -1, -rho], [0, +1, -rho], [0, -1, rho], [0, +1, rho], 554 * [1, rho, 0], [-1, rho, 0], [1, -rho, 0], [-1, -rho, 0], 555 * [-rho, 0, 1], [-rho, 0, -1], [rho, 0, 1], [rho, 0, -1] 556 * ]; 557 * let faceArray = [ 558 * [4, 1, 11], 559 * [11, 1, 0], 560 * [6, 11, 0], 561 * [0, 1, 9], 562 * [11, 10, 4], 563 * [9, 1, 5], 564 * [8, 9, 5], 565 * [5, 3, 8], 566 * [6, 10, 11], 567 * [2, 3, 10], 568 * [2, 10, 6], 569 * [8, 3, 2], 570 * [3, 4, 10], 571 * [7, 8, 2], 572 * [9, 8, 7], 573 * [0, 9, 7], 574 * [4, 3, 5], 575 * [5, 1, 4], 576 * [0, 7, 6], 577 * [7, 2, 6] 578 * ]; 579 * var ico = view.create('polyhedron3d', [vertexList, faceArray], { 580 * fillColorArray: [], 581 * fillOpacity: 1, 582 * strokeWidth: 0.1, 583 * layer: 12, 584 * shader: { 585 * enabled: true, 586 * type: 'angle', 587 * hue: 60, 588 * saturation: 90, 589 * minlightness: 60, 590 * maxLightness: 80 591 * } 592 * }); 593 * 594 * </pre><div id="JXGfea93484-96e9-4eb5-9e45-bb53d612aead" class="jxgbox" style="width: 300px; height: 300px;"></div> 595 * <script type="text/javascript"> 596 * (function() { 597 * var board = JXG.JSXGraph.initBoard('JXGfea93484-96e9-4eb5-9e45-bb53d612aead', 598 * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); 599 * var box = [-4, 4]; 600 * var view = board.create( 601 * 'view3d', 602 * [[-5, -3], [8, 8], 603 * [box, box, box]], 604 * { 605 * projection: 'parallel', 606 * trackball: { enabled: false }, 607 * depthOrder: { 608 * enabled: true 609 * }, 610 * xPlaneRear: { visible: false }, 611 * yPlaneRear: { visible: false }, 612 * zPlaneRear: { fillOpacity: 0.2 } 613 * } 614 * ); 615 * let rho = 1.6180339887; 616 * let vertexList = [ 617 * [0, -1, -rho], [0, +1, -rho], [0, -1, rho], [0, +1, rho], 618 * [1, rho, 0], [-1, rho, 0], [1, -rho, 0], [-1, -rho, 0], 619 * [-rho, 0, 1], [-rho, 0, -1], [rho, 0, 1], [rho, 0, -1] 620 * ]; 621 * let faceArray = [ 622 * [4, 1, 11], 623 * [11, 1, 0], 624 * [6, 11, 0], 625 * [0, 1, 9], 626 * [11, 10, 4], 627 * [9, 1, 5], 628 * [8, 9, 5], 629 * [5, 3, 8], 630 * [6, 10, 11], 631 * [2, 3, 10], 632 * [2, 10, 6], 633 * [8, 3, 2], 634 * [3, 4, 10], 635 * [7, 8, 2], 636 * [9, 8, 7], 637 * [0, 9, 7], 638 * [4, 3, 5], 639 * [5, 1, 4], 640 * [0, 7, 6], 641 * [7, 2, 6] 642 * ]; 643 * var ico = view.create('polyhedron3d', [vertexList, faceArray], { 644 * fillColorArray: [], 645 * fillOpacity: 1, 646 * strokeWidth: 0.1, 647 * layer: 12, 648 * shader: { 649 * enabled: true, 650 * type: 'angle', 651 * hue: 60, 652 * saturation: 90, 653 * minlightness: 60, 654 * maxLightness: 80 655 * } 656 * }); 657 * 658 * })(); 659 * 660 * </script><pre> 661 * 662 */ 663 JXG.createPolyhedron3D = function (board, parents, attributes) { 664 var view = parents[0], 665 i, le, 666 face, f, 667 el, 668 attr, attr_polyhedron, 669 faceList = [], 670 base = null, 671 transform = null, 672 673 polyhedron = { 674 view: view, 675 vertices: {}, 676 coords: {}, 677 coords2D: {}, 678 zIndex: {}, 679 faces: [] 680 }; 681 682 if (Type.exists(parents[1].type) && parents[1].type === Const.OBJECT_TYPE_POLYHEDRON3D) { 683 // Polyhedron from baseElement and transformations 684 base = parents[1]; 685 transform = parents[2]; 686 polyhedron.vertices = base.def.vertices; 687 polyhedron.faces = base.def.faces; 688 } else { 689 // Copy vertices into a dict 690 if (Type.isArray(parents[1])) { 691 le = parents[1].length; 692 for (i = 0; i < le; i++) { 693 polyhedron.vertices[i] = parents[1][i]; 694 } 695 } else if (Type.isObject(parents[1])) { 696 for (i in parents[1]) { 697 if (parents[1].hasOwnProperty(i)) { 698 polyhedron.vertices[i] = parents[1][i]; 699 } 700 } 701 } 702 polyhedron.faces = parents[2]; 703 } 704 705 attr_polyhedron = Type.copyAttributes(attributes, board.options, 'polyhedron3d'); 706 707 console.time('polyhedron'); 708 709 view.board.suspendUpdate(); 710 // Create face3d elements 711 le = polyhedron.faces.length; 712 for (i = 0; i < le; i++) { 713 attr = Type.copyAttributes(attributes, board.options, 'face3d'); 714 if (attr_polyhedron.fillcolorarray.length > 0) { 715 attr.fillcolor = attr_polyhedron.fillcolorarray[i % attr_polyhedron.fillcolorarray.length]; 716 } 717 f = polyhedron.faces[i]; 718 719 if (Type.isArray(f) && f.length === 2 && Type.isObject(f[1]) && Type.isArray(f[0])) { 720 // Handle case that face is of type [[points], {attr}] 721 Type.mergeAttr(attr, f[1]); 722 // Normalize face array, i.e. don't store attributes of that face in polyhedron 723 polyhedron.faces[i] = f[0]; 724 } 725 726 face = view.create('face3d', [polyhedron, i], attr); 727 faceList.push(face); 728 } 729 el = new JXG.Polyhedron3D(view, polyhedron, faceList, attr_polyhedron); 730 el.setParents(el); // Sets el as parent to all faces. 731 for (i = 0; i < le; i++) { 732 el.inherits.push(el.faces[i]); 733 // el.addChild(el.faces[i]); // This takes very long time. We avoid it with 734 // a special treatment in removeObject 735 } 736 if (base !== null) { 737 el.addTransform(base, transform); 738 el.addParents(base); 739 } 740 view.board.unsuspendUpdate(); 741 742 console.timeEnd('polyhedron'); 743 744 return el; 745 }; 746 747 JXG.registerElement("polyhedron3d", JXG.createPolyhedron3D); 748