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