1 /*
  2     Copyright 2008-2024
  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 
 36 // -----------------------
 37 //  Lines
 38 // -----------------------
 39 
 40 /**
 41  * Constructor for 3D polygons.
 42  * @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.
 43  *
 44  * @augments JXG.GeometryElement3D
 45  * @augments JXG.GeometryElement
 46  * @param {View3D} view
 47  * @param {Point3D|Array} point
 48  * @param {Array} direction
 49  * @param {Array} range
 50  * @param {Object} attributes
 51  * @see JXG.Board#generateName
 52  */
 53 JXG.Polygon3D = function (view, vertices, attributes) {
 54     var i;
 55 
 56     this.constructor(view.board, attributes, Const.OBJECT_TYPE_POLYGON3D, Const.OBJECT_CLASS_3D);
 57     this.constructor3D(view, 'polygon3d');
 58 
 59     this.board.finalizeAdding(this);
 60 
 61     /**
 62      * References to the points defining the polygon. The last vertex is the same as the first vertex.
 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 );
 94 
 95 /**
 96  * @class A polygon is a sequence of points connected by lines, with the last point
 97  * connecting back to the first one. The points are given by:
 98  * <ul>
 99  *    <li> a list of Point3D objects,
100  *    <li> a list of coordinate arrays, or
101  *    <li> a function returning a list of coordinate arrays.
102  * </ul>
103  * Each two consecutive points of the list define a line.
104  * @pseudo
105  * @constructor
106  * @name Polygon
107  * @type JXG.Polygon
108  * @augments JXG.Polygon
109  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
110  * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be
111  * added to the array by the creator. Here, two points match if they have the same 'id' attribute.
112  */
113 JXG.createPolygon3D = function (board, parents, attributes) {
114     var view = parents[0],
115         el, i, le, obj,
116         points = [],
117         points2d = [],
118         attr,
119         attr_points,
120         is_transform = false;
121 
122     attr = Type.copyAttributes(attributes, board.options, 'polygon3d');
123     obj = board.select(parents[1]);
124     if (obj === null) {
125         // This is necessary if the original polygon is defined in another board.
126         obj = parents[1];
127     }
128     if (
129         Type.isObject(obj) &&
130         obj.type === Const.OBJECT_TYPE_POLYGON3D &&
131         Type.isTransformationOrArray(parents[2])
132     ) {
133         is_transform = true;
134         le = obj.vertices.length - 1;
135         attr_points = Type.copyAttributes(attributes, board.options, 'polygon3d', 'vertices');
136         for (i = 0; i < le; i++) {
137             if (attr_points.withlabel) {
138                 attr_points.name =
139                     obj.vertices[i].name === '' ? '' : obj.vertices[i].name + "'";
140             }
141             points.push(board.create('point3d', [obj.vertices[i], parents[2]], attr_points));
142         }
143     } else {
144         points = Type.providePoints3D(view, parents.slice(1), attributes, 'polygon3d', ['vertices']);
145         if (points === false) {
146             throw new Error(
147                 "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"
148             );
149         }
150     }
151 
152     el = new JXG.Polygon3D(view, points, attr);
153     el.isDraggable = true;
154 
155     attr = el.setAttr2D(attr);
156     for (i = 0; i < points.length; i++) {
157         points2d.push(points[i].element2D);
158     }
159     el.element2D = board.create('polygon', points2d, attr);
160     el.element2D.view = view;
161     el.addChild(el.element2D);
162     el.inherits.push(el.element2D);
163     el.element2D.setParents(el);
164 
165     // Put the points in their positions
166     if (is_transform) {
167       el.prepareUpdate().update().updateVisibility().updateRenderer();
168       le = obj.vertices.length - 1;
169       for (i = 0; i < le; i++) {
170           points[i].prepareUpdate().update().updateVisibility().updateRenderer();
171       }
172     }
173 
174     return el;
175 };
176 JXG.registerElement('polygon3d', JXG.createPolygon3D);