1 /*
  2     Copyright 2005-2026
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  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 
 30 /*global JXG: true, define: true*/
 31 /*jslint nomen: true, plusplus: true*/
 32 /*eslint no-loss-of-precision: off */
 33 
 34 /**
 35  * @fileoverview In this file the namespace JXG.Math.Tiling is defined, which holds numerical
 36  * algorithms for creating meshes for surface3d elements.
 37  */
 38 import Mat from "./math.js";
 39 
 40 /**
 41  * The JXG.Math.Tiling namespace.
 42  * @name JXG.Math.Tiling
 43  * @exports Mat.Numerics as JXG.Math.Tiling
 44  * @namespace
 45  */
 46 Mat.Tiling = {
 47     /**
 48      * Triangulate (partition it into triangles) a given two dimensional domain.
 49      * The number of triangles the original rectangle is divided into depends on the parameters stepsU and stepsV.
 50      * Input are the ranges of u and v, as well as stepsU and stepsV which are static.
 51      * If the optional parameter stepsV is not given or is equal to 0, the rectangle is partitioned into
 52      * nearly equilateral triangles.
 53      * Otherwise, the shape of the triangles depends on the ratio of stepsU / stepsV.
 54      * @name triangulation
 55      * @param {JXG.ParametricSurface3D|JXG.Plane3D} el element which is displayed using a polyhedron3d.
 56      * From this element its function F is used.
 57      * @param {Array} rg_u Begin and end of first direction (numbers or functions)
 58      * @param {Array} rg_v Begin and end of second direction (numbers or functions)
 59      * @param {Number} stepsU Immutable
 60      * @param {Number} [stepsV=0] Immutable
 61      * @returns [coords,faces]
 62      * @memberof JXG.Math.Tiling
 63      *
 64      * @example
 65      * var rg = board.create('slider', [[-7, -7], [3, -7], [1, 4, 5]], { name: 'rg' }); // range
 66      *
 67      * var box = [-5, 5];
 68      * var view = board.create('view3d',
 69      *     [[-5, -3], [8, 8],
 70      *     [box, box, box]],
 71      *     {
 72      *         projection: 'central',
 73      *         xPlaneRear: { visible: false },
 74      *         yPlaneRear: { visible: false },
 75      *         zPlaneRear: { visible: false }
 76      *     });
 77      *
 78      * var range = [() => -rg.Value(), () => rg.Value()],
 79      *     stepsU = 25,
 80      *     // stepsV = 25,
 81      *     F = (x, y) => [x, y, 3 * Math.sin(Math.sqrt(x ** 2 + y ** 2))];
 82      *
 83      * view.setView(0, Math.PI / 2); // Set view from above
 84      *
 85      * var el = { F: F }; // Fake surface3d element
 86      *
 87      * // stepsV not supplied -> approx. equilater triangles
 88      * var surface = JXG.Math.Tiling.triangulation(el, range, range, stepsU);
 89      * var pol = view.create('polyhedron3d', surface, {
 90      *     shader: {
 91      *         enabled: true,
 92      *         light: {
 93      *             dir: 0
 94      *         }
 95      *     },
 96      *     fillColorArray: ['white'],
 97      *     fillOpacity: 0.9,
 98      *     strokeWidth: 0.2
 99      * });
100      *
101      * </pre><div id="JXG37cb3ef3-a818-4114-97b6-954d0189e0fb" class="jxgbox" style="width: 300px; height: 300px;"></div>
102      * <script type="text/javascript">
103      *     (function() {
104      *         var board = JXG.JSXGraph.initBoard('JXG37cb3ef3-a818-4114-97b6-954d0189e0fb',
105      *             {boundingbox: [-8, 8, 8,-8], axis: false, pan: { enabled: false }, showcopyright: false, shownavigation: false});
106      *     var rg = board.create('slider', [[-7, -7], [3, -7], [1, 4, 5]], { name: 'rg' });
107      *
108      *     var box = [-5, 5];
109      *     var view = board.create('view3d',
110      *         [[-5, -3], [8, 8],
111      *         [box, box, box]],
112      *         {
113      *             projection: 'central',
114      *             xPlaneRear: { visible: false },
115      *             yPlaneRear: { visible: false },
116      *             zPlaneRear: { visible: false }
117      *         });
118      *
119      *     var range = [() => -rg.Value(), () => rg.Value()],
120      *         stepsU = 25,
121      *         stepsV = 25,
122      *         F = (x, y) => [x, y, 3 * Math.sin(Math.sqrt(x ** 2 + y ** 2))];
123      *     view.setView(0, Math.PI / 2);
124      *
125      *     var el = { F: F }; // Fake surface3d element
126      *
127      *     var surface = JXG.Math.Tiling.triangulation(el, range, range, stepsU);
128      *     var pol = view.create('polyhedron3d', surface, {
129      *         shader: {
130      *             enabled: true,
131      *             light: {
132      *                 dir: 0
133      *             }
134      *         },
135      *         fillColorArray: ['white'],
136      *         fillOpacity: 0.9,
137      *         strokeWidth: 0.2
138      *     });
139      *
140      *     })();
141      *
142      * </script><pre>
143      *
144      */
145     triangulation: function (el, rg_u, rg_v, stepsU, stepsV) {
146         var i, j, le,
147             up,
148             ru, rv, du, dv,
149             vertices = [],
150             faces = [];
151 
152         if (stepsV === undefined || stepsV === 0) {
153             // Approximate equilateral triangles
154             ru = JXG.evaluate(rg_u);
155             rv = JXG.evaluate(rg_v);
156             du = (ru[1] - ru[0]) / stepsU;
157             dv = du * Math.sqrt(3) / 2;
158             stepsV = Math.round(Math.abs(rv[1] - rv[0]) / dv);
159         }
160         for (j = 0; j <= stepsV; j++) {
161             up = (j % 2 === 0) ? stepsU : stepsU + 1;
162             for (i = 0; i <= up; i++) {
163                 // Generate vertices
164                 vertices.push(
165                     (function (ii, jj, up) {
166                         var s = ii;
167                         if (jj % 2 === 1) {
168                             s = (ii === up) ? (ii - 1) : ((ii > 0) ? (ii - 0.5) : s);
169                         }
170 
171                         return function () {
172                             var ru = JXG.evaluate(rg_u),
173                                 rv = JXG.evaluate(rg_v),
174                                 u = ru[0] + s * (ru[1] - ru[0]) / stepsU,
175                                 v = rv[0] + jj * (rv[1] - rv[0]) / stepsV,
176                                 val = el.F(u, v);
177                             // return [u, v, val];
178                             return (val.length === 4) ? val.slice(1) : val;
179                         };
180                     })(i, j, up)
181                 );
182 
183                 // Generate faces
184                 if (j > 0) {
185                     le = vertices.length - 1;
186                     if (j % 2 === 1) {
187                         if (i > 0) {
188                             faces.push([le - 1, le, le - 2 - stepsU]);
189                             if (i < up) {
190                                 faces.push([le, le - 1 - stepsU, le - 2 - stepsU]);
191                             } else {
192                                 faces.push([le - 1, le, le - 2 - stepsU]);
193                             }
194                         }
195                     } else {
196                         if (i > 0) {
197                             faces.push([le, le - 2 - stepsU, le - 1]);
198                         }
199                         faces.push([le, le - 1 - stepsU, le - 2 - stepsU]);
200                     }
201                 }
202             }
203         }
204         return [vertices, faces];
205     },
206 
207     /**
208      * Rectangulate (partition it into rectangles) a given two dimensional domain.
209      * The number of rectangles the original rectangle is divided into depends on the parameters stepsU and stepsV.
210      * Input are the ranges of u and v, as well as stepsU and stepsV which are static.
211      * @name rectangulation
212      * @param {JXG.ParametricSurface3D|JXG.Plane3D} el element which is displayed using a polyhedron3d.
213      * From this element its function F is used.
214      * @param {Array} rg_u Begin and end of first direction (numbers or functions)
215      * @param {Array} rg_v Begin and end of second direction (numbers or functions)
216      * @param {Number} stepsU Immutable
217      * @param {Number} stepsV Immutable
218      * @returns [coords,faces]
219      * @memberof JXG.Math.Tiling
220      *
221      * @example
222      * var rg = board.create('slider', [[-7, -7], [3, -7], [1, 4, 5]], { name: 'rg' });
223      *
224      * var box = [-5, 5];
225      * var view = board.create('view3d',
226      *     [[-5, -3], [8, 8],
227      *     [box, box, box]],
228      *     {
229      *         projection: 'central',
230      *         // axesPosition: 'center',
231      *         xPlaneRear: { visible: false },
232      *         yPlaneRear: { visible: false },
233      *         zPlaneRear: { visible: false }
234      *     });
235      *
236      * var range = [() => -rg.Value(), () => rg.Value()],
237      *     stepsU = 15,
238      *     stepsV = 5,
239      *     F = (x, y) => [x, y, 3 * Math.sin(Math.sqrt(x ** 2 + y ** 2))];
240      *
241      * view.setView(0, Math.PI / 2);  // Set view from above
242      *
243      * var el = { F: F }; // Fake surface3d element
244      *
245      * var surface = JXG.Math.Tiling.rectangulation(el, range, range, stepsU, stepsV);
246      * var pol = view.create('polyhedron3d', surface, {
247      *     shader: {
248      *         enabled: true,
249      *         light: {
250      *             dir: 0
251      *         }
252      *     },
253      *     fillColorArray: ['white'],
254      *     fillOpacity: 0.9,
255      *     strokeWidth: 0.2
256      * });
257      *
258      * </pre><div id="JXG8c99ffea-7edc-494a-b416-34d9c154d310" class="jxgbox" style="width: 300px; height: 300px;"></div>
259      * <script type="text/javascript">
260      *     (function() {
261      *         var board = JXG.JSXGraph.initBoard('JXG8c99ffea-7edc-494a-b416-34d9c154d310',
262      *             {boundingbox: [-8, 8, 8,-8], axis: false, pan: { enabled: false }, showcopyright: false, shownavigation: false});
263      *     var rg = board.create('slider', [[-7, -7], [3, -7], [1, 4, 5]], { name: 'rg' });
264      *
265      *     var box = [-5, 5];
266      *     var view = board.create('view3d',
267      *         [[-5, -3], [8, 8],
268      *         [box, box, box]],
269      *         {
270      *             projection: 'central',
271      *             // axesPosition: 'center',
272      *             xPlaneRear: { visible: false },
273      *             yPlaneRear: { visible: false },
274      *             zPlaneRear: { visible: false }
275      *         });
276      *
277      *     var range = [() => -rg.Value(), () => rg.Value()],
278      *         stepsU = 15,
279      *         stepsV = 5,
280      *         F = (x, y) => [x, y, 3 * Math.sin(Math.sqrt(x ** 2 + y ** 2))];
281      *
282      *     view.setView(0, Math.PI / 2);
283      *
284      *     var el = { F: F }; // Fake surface3d element
285      *
286      *     var surface = JXG.Math.Tiling.rectangulation(el, range, range, stepsU, stepsV);
287      *     var pol = view.create('polyhedron3d', surface, {
288      *         shader: {
289      *             enabled: true,
290      *             light: {
291      *                 dir: 0
292      *             }
293      *         },
294      *         fillColorArray: ['white'],
295      *         fillOpacity: 0.9,
296      *         strokeWidth: 0.2
297      *     });
298      *
299      *     })();
300      *
301      * </script><pre>
302      *
303      */
304     rectangulation: function (el, rg_u, rg_v, stepsU, stepsV) {
305         var vertices = [],
306             faces = [],
307             i, j, le;
308 
309         for (j = 0; j <= stepsV; j++) {
310             for (i = 0; i <= stepsU; i++) {
311                 vertices.push(
312                     (function (ii, jj) {
313                         return function () {
314                             var ru = JXG.evaluate(rg_u),
315                                 rv = JXG.evaluate(rg_v),
316                                 u = ru[0] + ii * (ru[1] - ru[0]) / stepsU,
317                                 v = rv[0] + jj * (rv[1] - rv[0]) / stepsV,
318                                 val = el.F(u, v);
319                             return (val.length === 4) ? val.slice(1) : val;
320                         };
321                     })(i, j)
322                 );
323                 if (i > 0 && j > 0) {
324                     le = vertices.length - 1;
325                     faces.push(
326                         // [le - 1 - stepsU - 1, le - 1 - stepsU, le, le - 1]
327                         [le - 1, le, le - 1 - stepsU, le - 1 - stepsU - 1]
328                     );
329                 }
330             }
331         }
332         return [vertices, faces];
333     }
334 
335     // triangulation_old: function (p1, p2, p3, p4, stepsU, stepsV) {
336     //     // Vectors used for checking if the given coordinates create a rectangle
337     //     var vec1 = [p2[0] - p1[0], p2[1] - p1[1]],
338     //         vec2 = [p3[0] - p2[0], p3[1] - p2[1]],
339     //         vec3 = [p4[0] - p3[0], p4[1] - p3[1]],
340     //         vec4 = [p1[0] - p4[0], p1[1] - p4[1]],
341 
342     //         coords = [],
343     //         faces = [],
344     //         width, height,
345     //         wSide, hSide,
346     //         triangleWidth, triangleHeight,
347     //         s1, s2,
348     //         i, j,
349     //         numRows,
350     //         widthX, widthY, heightX, heightY,
351     //         oddPoints,
352     //         evenPoints;
353 
354     //     // Check if the given coordinates create a rectangle, otherwise an exception is thrown
355     //     if (
356     //         vec1[0] * vec4[0] + vec1[1] * vec4[1] !== 0 ||
357     //         vec2[0] * vec1[0] + vec2[1] * vec1[1] !== 0 ||
358     //         vec3[0] * vec2[0] + vec3[1] * vec2[1] !== 0 ||
359     //         vec4[0] * vec3[0] + vec4[1] * vec3[1] !== 0
360     //     ) {
361     //         throw new Error(" the board created is not rectangle  ");
362     //     }
363 
364     //     // Set initial values for wSide, hSide
365     //     wSide = [0, 0];
366     //     hSide = [0, 0];
367 
368     //     // Check for longer side of rectangle:
369     //     // longer side is appointed height, shorter side is appointed width
370     //     s1 = Math.sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]));
371     //     s2 = Math.sqrt((p3[0] - p2[0]) * (p3[0] - p2[0]) + (p3[1] - p2[1]) * (p3[1] - p2[1]));
372     //     if (s1 <= s2) {
373     //         width = s1;
374     //         height = s2;
375     //         // Determine start and end points of the width-side and height-side
376     //         wSide = [p1, p2];
377     //         hSide = [p2, p3];
378     //     } else {
379     //         width = s2;
380     //         height = s1;
381     //         // Determine start and end points of the width-side and height-side
382     //         wSide = [p2, p3];
383     //         hSide = [p1, p2];
384     //     }
385     //     // Calculate height and width of the triangles and number of rows
386     //     triangleWidth = width / stepsU;
387 
388     //     if (stepsV === undefined || stepsV === 0) {
389     //         // Equilateral triangles, depending on parameter "stepsU"
390     //         triangleHeight = (triangleWidth * Math.sqrt(3)) / 2;
391     //         numRows = Math.round(height / triangleHeight);
392     //     } else {
393     //         // Two parameters stepsU, stepsV
394     //         numRows = stepsV;
395     //         triangleHeight = height / numRows;
396     //     }
397 
398     //     // Calculate values of "shifting vectors"
399     //     widthX = (wSide[1][0] - wSide[0][0]) / stepsU;
400     //     widthY = (wSide[1][1] - wSide[0][1]) / stepsU;
401     //     heightX = (hSide[1][0] - hSide[0][0]) / numRows;
402     //     heightY = (hSide[1][1] - hSide[0][1]) / numRows;
403 
404     //     oddPoints = [];
405     //     evenPoints = [];
406 
407     //     // Push coordinates of the base point (p1)
408     //     coords.push([p1[0], p1[1]]);
409     //     evenPoints.push(coords.length - 1);
410 
411     //     // Calculate point coordinates of layer 0 and store indices in evenPoints
412     //     for (i = 1; i <= stepsU; i++) {
413     //         coords.push([p1[0] + i * widthX, p1[1] + i * widthY]); // Points first line
414     //         evenPoints.push(coords.length - 1);
415     //     }
416 
417     //     for (i = 1; i <= numRows; i++) {
418     //         if (i % 2 === 0) {
419     //             // Points and faces of layers with an even index
420 
421     //             evenPoints = [];
422     //             // Calculate first point coordinates within the layer
423     //             coords.push([
424     //                 p1[0] + i * heightX,
425     //                 p1[1] + i * heightY
426     //             ]);
427     //             // evenPoints stores index of the first point of the layer
428     //             evenPoints.push(coords.length - 1);
429     //             // Calculate all other point coordinates within the layer
430     //             for (j = 1; j <= stepsU; j++) {
431     //                 coords.push([
432     //                     coords[evenPoints[0]][0] + j * widthX,
433     //                     coords[evenPoints[0]][1] + j * widthY
434     //                 ]);
435     //                 //evenPoints stores index of the most recently calculated point of the layer
436     //                 evenPoints.push(coords.length - 1);
437     //             }
438     //             // Connect the faces of the row by grouping indices of points
439     //             faces.push([evenPoints[0], oddPoints[0], oddPoints[1]]);
440     //             for (j = 1; j <= stepsU; j++) {
441     //                 faces.push([evenPoints[j - 1], oddPoints[j], evenPoints[j]]);
442     //                 faces.push([evenPoints[j], oddPoints[j], oddPoints[j + 1]]);
443     //             }
444     //         } else {
445     //             // Points and faces of layers with an odd index
446 
447     //             oddPoints = [];
448     //             // Calculate first point coordinates within the layer
449     //             coords.push([
450     //                 p1[0] + i * heightX,
451     //                 p1[1] + i * heightY
452     //             ]);
453     //             // oddPoints stores index of the first point of the layer
454     //             oddPoints.push(coords.length - 1);
455     //             // Calculate all other point coordinates within the layer except for the last point
456     //             for (j = 1; j <= stepsU; j++) {
457     //                 coords.push([
458     //                     coords[oddPoints[0]][0] + j * widthX - widthX / 2,
459     //                     coords[oddPoints[0]][1] + j * widthY - widthY / 2
460     //                 ]);
461     //                 // oddPoints stores index of the most recently calculated point of the layer
462     //                 oddPoints.push(coords.length - 1);
463     //             }
464     //             // Calculate last point coordinates within the layer
465     //             coords.push([
466     //                 coords[oddPoints[0]][0] + stepsU * widthX,
467     //                 coords[oddPoints[0]][1] + stepsU * widthY
468     //             ]);
469     //             // oddPoints stores index of last point within the layer
470     //             oddPoints.push(coords.length - 1);
471     //             // Connect the faces of the row by grouping indices of points
472     //             faces.push([oddPoints[0], evenPoints[0], oddPoints[1]]);
473     //             for (j = 1; j <= stepsU; j++) {
474     //                 faces.push([oddPoints[j], evenPoints[j - 1], evenPoints[j]]);
475     //                 faces.push([oddPoints[j], evenPoints[j], oddPoints[j + 1]]);
476     //             }
477     //         }
478     //     }
479 
480     //     return [coords, faces];
481     // },
482 
483     // rectangulation_old: function (p1, p2, p3, p4, stepsU, stepsV) {
484     //     // Vectors used for checking if the given coordinates create a rectangle
485     //     var vec1 = [p2[0] - p1[0], p2[1] - p1[1]],
486     //         vec2 = [p3[0] - p2[0], p3[1] - p2[1]],
487     //         vec3 = [p4[0] - p3[0], p4[1] - p3[1]],
488     //         vec4 = [p1[0] - p4[0], p1[1] - p4[1]],
489 
490     //         coords = [],
491     //         faces = [],
492     //         wSide, hSide,
493     //         s1, s2,
494     //         i, j,
495     //         widthX, widthY,
496     //         heightX, heightY,
497     //         startPointLayer;
498 
499     //     // Check if the given coordinates create a rectangle, otherwise an exception is thrown
500     //     if (
501     //         vec1[0] * vec4[0] + vec1[1] * vec4[1] !== 0 ||
502     //         vec2[0] * vec1[0] + vec2[1] * vec1[1] !== 0 ||
503     //         vec3[0] * vec2[0] + vec3[1] * vec2[1] !== 0 ||
504     //         vec4[0] * vec3[0] + vec4[1] * vec3[1] !== 0
505     //     ) {
506     //         throw new Error("rectangulation_old: area is not rectangle  ");
507     //         // console.log("rectangulation_old: area is not rectangle  ");
508     //     }
509 
510     //     // Set initial values for wSide, hSide
511     //     wSide = [0, 0];
512     //     hSide = [0, 0];
513 
514     //     // Check for longer side of rectangle:
515     //     // longer side is appointed height, shorter side is appointed width
516     //     // s1 = Math.sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]));
517     //     // s2 = Math.sqrt((p3[0] - p2[0]) * (p3[0] - p2[0]) + (p3[1] - p2[1]) * (p3[1] - p2[1]));
518     //     s1 = Mat.hypot(vec1[0], vec1[1]);
519     //     s2 = Mat.hypot(vec2[0], vec2[1]);
520 
521     //     if (s1 <= s2) {
522     //         // Determine start and end points of the width-side and height-side
523     //         wSide = [p1, p2];
524     //         hSide = [p2, p3];
525     //     } else {
526     //         // Determine start and end points of the width-side and height-side
527     //         wSide = [p2, p3];
528     //         hSide = [p1, p2];
529     //     }
530 
531     //     // Calculate values of "shifting vectors"
532     //     widthX = (wSide[1][0] - wSide[0][0]) / stepsV;
533     //     widthY = (wSide[1][1] - wSide[0][1]) / stepsV;
534     //     heightX = (hSide[1][0] - hSide[0][0]) / stepsU;
535     //     heightY = (hSide[1][1] - hSide[0][1]) / stepsU;
536 
537     //     // Initialize startPointLayer that stores coordinates of the first point of the current layer
538     //     startPointLayer = [];
539 
540     //     // Push coordinates of base point (p1)
541     //     coords.push([p1[0], p1[1]]);
542     //     startPointLayer = coords[0];
543 
544     //     // Calculate point coordinates of layer 0
545     //     for (j = 1; j <= stepsV; j++) {
546     //         coords.push([startPointLayer[0] + j * widthX, startPointLayer[1] + j * widthY]);
547     //     }
548 
549     //     for (i = 1; i <= stepsU; i++) {
550     //         startPointLayer = [];
551 
552     //         // Calculate point coordinates of first point of layer
553     //         coords.push([
554     //             p1[0] + i * heightX,
555     //             p1[1] + i * heightY
556     //         ]);
557     //         startPointLayer = coords[coords.length - 1];
558 
559     //         // Calculating remaining point coordinates of layer
560     //         for (j = 1; j <= stepsV; j++) {
561     //             coords.push([
562     //                 startPointLayer[0] + j * widthX,
563     //                 startPointLayer[1] + j * widthY
564     //             ]);
565     //         }
566 
567     //         // Connect rectangles by grouping indices of points
568     //         for (
569     //             j = coords.length - stepsV - 1;
570     //             j < coords.length - 1;
571     //             j++
572     //         ) {
573     //             faces.push([j, j - stepsV - 1, j - stepsV, j + 1]);
574     //         }
575     //     }
576 
577     //     return [coords, faces];
578     // },
579 
580     // /**
581     //  * This function creates an array of dynamic 3-dimensional points
582     //  * based on an array of pairs of two coordinates.
583     //  * It uses a mathematical function to assign a third coordinate (the z-coordinate)
584     //  * to each pair of two coordinates.
585     //  * The 3-dimensional points are not stored directly.
586     //  * Instead the array stores JavaScript functions that utilize the mentioned mathematical function
587     //  * to return an array of three coordinates.
588     //  * This allows the recognition and proper visualization of changes to the underlying
589     //  * mathematical function.
590     //  * @name mapMeshTo3D
591     //  * @param {Array} surface
592     //  * @param {Parametricsurface3d} el
593     //  * @returns {Array} dynamicPoints array of [x, y, z] coordinates
594     //  *
595     //  * @private
596     //  * @memberof JXG.Math.Tiling
597     //  */
598     // mapMeshTo3D: function (surface, el) {
599     //     var dynamicPoints = [], i;
600 
601     //     for (i = 0; i < surface[0].length; i++) {
602     //         dynamicPoints.push(
603     //             (function (u, v) {
604     //                 return function(x, y) { return el.F(u, v); };
605     //             })(surface[0][i][0], surface[0][i][1])
606     //         ); // Capture values explicitly
607     //         // dynamicPoints.push(
608     //         //     (function (u, v) {
609     //         //         return function(x, y) { return el.F(Type.evaluate(u), Type.evaluate(v)); };
610     //         //     })(surface[0][i][0], surface[0][i][1])
611     //         // ); // Capture values explicitly
612     //     }
613 
614     //     return dynamicPoints;
615     // }
616 };
617 
618 export default Mat.Tiling;
619