1 /* 2 Copyright 2008-2025 3 Matthias Ehmann, 4 Aaron Fenyes, 5 Carsten Miller, 6 Andreas Walter, 7 Alfred Wassermann 8 9 This file is part of JSXGraph. 10 11 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 12 13 You can redistribute it and/or modify it under the terms of the 14 15 * GNU Lesser General Public License as published by 16 the Free Software Foundation, either version 3 of the License, or 17 (at your option) any later version 18 OR 19 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 20 21 JSXGraph is distributed in the hope that it will be useful, 22 but WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 GNU Lesser General Public License for more details. 25 26 You should have received a copy of the GNU Lesser General Public License and 27 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 28 and <https://opensource.org/licenses/MIT/>. 29 */ 30 /*global JXG:true, define: true*/ 31 32 import JXG from '../jxg.js'; 33 import Const from '../base/constants.js'; 34 import Type from '../utils/type.js'; 35 import Mat from '../math/math.js'; 36 37 /** 38 * Constructor for 3D polygons. 39 * @class Creates a new 3D polygon object. Do not use this constructor to create a 3D polygon. Use {@link JXG.View3D#create} with type {@link Polygon3D} instead. 40 * 41 * @augments JXG.GeometryElement3D 42 * @augments JXG.GeometryElement 43 * @param {View3D} view 44 * @param {Point3D|Array} point 45 * @param {Array} direction 46 * @param {Array} range 47 * @param {Object} attributes 48 * @see JXG.Board#generateName 49 */ 50 JXG.Polygon3D = function (view, vertices, attributes) { 51 var i; 52 53 this.constructor(view.board, attributes, Const.OBJECT_TYPE_POLYGON3D, Const.OBJECT_CLASS_3D); 54 this.constructor3D(view, 'polygon3d'); 55 56 this.board.finalizeAdding(this); 57 58 /** 59 * References to the points defining the polygon. 60 * Compared to the 2D {@link JXG.Polygon#vertices}, it contains one point less, i.e. for a quadrangle 61 * 'vertices' contains four points. In a 2D quadrangle, 'vertices' will contain five points, the last one being 62 * a copy of the first one. 63 * @type Array 64 */ 65 this.vertices = []; 66 for (i = 0; i < vertices.length; i++) { 67 this.vertices[i] = this.board.select(vertices[i]); 68 69 // The _is_new flag is replaced by _is_new_pol. 70 // Otherwise, the polygon would disappear if the last border element 71 // is removed (and the point has been provided by coordinates) 72 if (this.vertices[i]._is_new) { 73 delete this.vertices[i]._is_new; 74 this.vertices[i]._is_new_pol = true; 75 } 76 } 77 }; 78 JXG.Polygon3D.prototype = new JXG.GeometryElement(); 79 Type.copyPrototypeMethods(JXG.Polygon3D, JXG.GeometryElement3D, 'constructor3D'); 80 81 JXG.extend( 82 JXG.Polygon3D.prototype, 83 /** @lends JXG.Polygon3D.prototype */ { 84 update: function () { 85 return this; 86 }, 87 88 updateRenderer: function () { 89 this.needsUpdate = false; 90 return this; 91 }, 92 93 updateZIndex: function() { 94 var i, 95 le = this.vertices.length, // - 1, 96 c3d = [1, 0, 0, 0]; 97 98 if (le <= 0) { 99 return [NaN, NaN, NaN, NaN]; 100 } 101 for (i = 0; i < le; i++) { 102 c3d[1] += this.vertices[i].coords[1]; 103 c3d[2] += this.vertices[i].coords[2]; 104 c3d[3] += this.vertices[i].coords[3]; 105 } 106 c3d[1] /= le; 107 c3d[2] /= le; 108 c3d[3] /= le; 109 110 // this.zIndex = Mat.matVecMult(this.view.matrix3DRotShift, c3d)[3]; 111 this.zIndex = Mat.innerProduct(this.view.matrix3DRotShift[3], c3d); 112 113 return this; 114 } 115 } 116 ); 117 118 /** 119 * @class A polygon is a sequence of points connected by lines, with the last point 120 * connecting back to the first one. The points are given by: 121 * <ul> 122 * <li> a list of Point3D objects, 123 * <li> a list of coordinate arrays, or 124 * <li> a function returning a list of coordinate arrays. 125 * </ul> 126 * Each two consecutive points of the list define a line. 127 * <p> 128 * JSXGraph does not require and does not check planarity of the polygon. 129 * 130 * @pseudo 131 * @constructor 132 * @name Polygon3D 133 * @type JXG.Polygon3D 134 * @augments JXG.Polygon3D 135 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 136 * @param {Array} vertices The polygon's vertices. 137 */ 138 JXG.createPolygon3D = function (board, parents, attributes) { 139 var view = parents[0], 140 el, i, le, obj, 141 points = [], 142 points2d = [], 143 attr, 144 attr_points, 145 is_transform = false; 146 147 attr = Type.copyAttributes(attributes, board.options, 'polygon3d'); 148 obj = board.select(parents[1]); 149 if (obj === null) { 150 // This is necessary if the original polygon is defined in another board. 151 obj = parents[1]; 152 } 153 // TODO: Number of points? Is the last point equal to the first point? 154 if ( 155 Type.isObject(obj) && 156 obj.type === Const.OBJECT_TYPE_POLYGON3D && 157 Type.isTransformationOrArray(parents[2]) 158 ) { 159 is_transform = true; 160 le = obj.vertices.length - 1; 161 attr_points = Type.copyAttributes(attributes, board.options, 'polygon3d', 'vertices'); 162 for (i = 0; i < le; i++) { 163 if (attr_points.withlabel) { 164 attr_points.name = 165 obj.vertices[i].name === '' ? '' : obj.vertices[i].name + "'"; 166 } 167 points.push(board.create('point3d', [obj.vertices[i], parents[2]], attr_points)); 168 } 169 } else if (Type.isArray(parents[1]) && parents[1].every((x) => Type.isPoint3D(x))) { 170 // array of points [A, B, C] 171 // TODO mixing points and coords arrays 172 points = parents[1]; 173 } else { 174 points = Type.providePoints3D(view, parents.slice(1), attributes, 'polygon3d', ['vertices']); 175 if (points === false) { 176 throw new Error( 177 "JSXGraph: Can't create polygon3d with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon3d and a transformation can be supplied" 178 ); 179 } 180 } 181 182 el = new JXG.Polygon3D(view, points, attr); 183 el.isDraggable = true; 184 185 attr = el.setAttr2D(attr); 186 for (i = 0; i < points.length; i++) { 187 points2d.push(points[i].element2D); 188 } 189 el.element2D = board.create('polygon', points2d, attr); 190 el.element2D.view = view; 191 el.addChild(el.element2D); 192 el.inherits.push(el.element2D); 193 el.element2D.setParents(el); 194 195 // Put the points in their positions 196 if (is_transform) { 197 el.prepareUpdate().update().updateVisibility().updateRenderer(); 198 le = obj.vertices.length - 1; 199 for (i = 0; i < le; i++) { 200 points[i].prepareUpdate().update().updateVisibility().updateRenderer(); 201 } 202 } 203 204 return el; 205 }; 206 JXG.registerElement('polygon3d', JXG.createPolygon3D);