1 /* 2 Copyright 2008-2022 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 <http://www.gnu.org/licenses/> 27 and <http://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 define(['jxg', 'utils/type', 'math/math', 'math/geometry'], function (JXG, Type, Mat, Geometry) { 36 "use strict"; 37 38 JXG.createAxes3D = function (board, parents, attributes) { 39 var view = parents[0], 40 i, j, k, i1, i2, 41 attr, 42 pos, 43 directions = ['x', 'y', 'z'], 44 suffixAxis = 'Axis', 45 dir, dir1, 46 sides = ['Rear', 'Front'], 47 rear = [0, 0, 0], // x, y, z 48 front = [0, 0, 0], // x, y, z 49 from, to, 50 vec1, vec2, range1, range2, 51 na, na_parent, 52 ticks_attr, 53 axes = {}; 54 55 if (Type.exists(view.bbox3D)) { 56 for (i = 0; i < directions.length; i++) { 57 rear[i] = view.bbox3D[i][0]; 58 front[i] = view.bbox3D[i][1]; 59 } 60 } else { 61 for (i = 0; i < directions.length; i++) { 62 rear[i] = parents[1][i]; 63 front[i] = parents[2][1]; 64 } 65 } 66 67 // Main 3D axes 68 attr = Type.copyAttributes(attributes, board.options, 'axes3d'); 69 pos = attr.axesposition; 70 for (i = 0; i < directions.length; i++) { 71 // Run through ['x', 'y', 'z'] 72 dir = directions[i]; 73 na = dir + suffixAxis; 74 75 if (pos === 'center') { // Axes centered 76 from = [0, 0, 0]; 77 to = [0, 0, 0]; 78 to[i] = front[i]; 79 axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]); 80 } else { 81 na += 'Border'; // Axes bordered 82 from = rear.slice(); 83 to = front.slice(); 84 if (i === 2) { 85 from[1] = front[1]; 86 to[0] = rear[0]; 87 } else { 88 from[i] = front[i]; 89 to[2] = rear[2]; 90 } 91 to[i] = front[i]; 92 attr[na.toLowerCase()].lastArrow = false; 93 axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]); 94 95 // TODO 96 ticks_attr = { 97 visible: true, // Für z-Ticks wird path nicht berechnet 98 minorTicks: 0, 99 tickEndings: [0, 1], 100 drawLabels: false 101 }; 102 if (i === 2) { 103 ticks_attr.tickEndings = [1, 0]; 104 } 105 axes[na + 'Ticks'] = view.create('ticks', [axes[na], 1], ticks_attr); 106 } 107 } 108 109 // Origin (2D point) 110 axes.O = view.create('intersection', [ 111 axes[directions[0] + suffixAxis], 112 axes[directions[1] + suffixAxis] 113 ], { 114 name: '', visible: false, withLabel: false 115 }); 116 117 // Front and rear planes 118 for (i = 0; i < directions.length; i++) { 119 // Run through ['x', 'y', 'z'] 120 i1 = (i + 1) % 3; 121 i2 = (i + 2) % 3; 122 123 dir = directions[i]; 124 for (j = 0; j < sides.length; j++) { 125 // Run through ['Rear', 'Front'] 126 127 from = [0, 0, 0]; 128 from[i] = (j === 0) ? rear[i] : front[i]; 129 vec1 = [0, 0, 0]; 130 vec2 = [0, 0, 0]; 131 vec1[i1] = 1; 132 vec2[i2] = 1; 133 range1 = [rear[i1], front[i1]]; 134 range2 = [rear[i2], front[i2]]; 135 na = dir + 'Plane' + sides[j]; 136 137 attr = Type.copyAttributes(attributes, board.options, 'axes3d', na); 138 axes[na] = view.create('plane3d', [from, vec1, vec2, range1, range2], attr); 139 axes[na].elType = 'axisplane3d'; 140 } 141 } 142 143 // Axes on front and rear planes 144 for (i = 0; i < directions.length; i++) { 145 // Run through ['x', 'y', 'z'] 146 dir = directions[i]; 147 for (j = 0; j < sides.length; j++) { 148 for (k = 1; k <= 2; k++) { 149 i1 = (i + k) % 3; 150 dir1 = directions[i1]; 151 na = dir + 'Plane' + sides[j] + dir1.toUpperCase() + 'Axis'; 152 na_parent = dir + 'Plane' + sides[j]; 153 154 from = [0, 0, 0]; 155 to = [0, 0, 0]; 156 from[i] = to[i] = (j === 0) ? rear[i] : front[i]; 157 158 from[i1] = rear[i1]; 159 to[i1] = front[i1]; 160 161 attr = Type.copyAttributes(attributes, board.options, 'axes3d', na); 162 axes[na] = view.create('axis3d', [from, to], attr); 163 axes[na_parent].addChild(axes[na]); 164 axes[na_parent].element2D.inherits.push(axes[na]); // TODO: Access of element2D is not nice 165 } 166 } 167 } 168 169 return axes; 170 }; 171 JXG.registerElement('axes3d', JXG.createAxes3D); 172 173 JXG.createAxis3D = function (board, parents, attributes) { 174 var view = parents[0], 175 attr, 176 start = parents[1], 177 end = parents[2], 178 el_start, el_end, el; 179 180 // Use 2D points to create axis 181 attr = Type.copyAttributes(attributes.point1, board.options, 'axis3d', 'point1'); 182 el_start = view.create('point', [ 183 (function (xx, yy, zz) { 184 return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; 185 })(start[0], start[1], start[2]), 186 (function (xx, yy, zz) { 187 return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; 188 })(start[0], start[1], start[2]) 189 ], attr); 190 191 attr = Type.copyAttributes(attributes.point2, board.options, 'axis3d', 'point2'); 192 el_end = view.create('point', [ 193 (function (xx, yy, zz) { 194 return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; 195 })(end[0], end[1], end[2]), 196 (function (xx, yy, zz) { 197 return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; 198 })(end[0], end[1], end[2]) 199 ], attr); 200 201 attr = Type.copyAttributes(attributes, board.options, 'axis3d'); 202 el = view.create('arrow', [el_start, el_end], attr); 203 204 return el; 205 }; 206 JXG.registerElement('axis3d', JXG.createAxis3D); 207 208 JXG.createMesh3D = function (board, parents, attr) { 209 var view = parents[0], 210 point = parents[1], 211 dir1 = parents[2], 212 range1 = parents[3], 213 dir2 = parents[4], 214 range2 = parents[5], 215 el; 216 217 el = view.create('curve', [[], []], attr); 218 el.updateDataArray = function () { 219 var s1 = range1[0], 220 e1 = range1[1], 221 s2 = range2[0], 222 e2 = range2[1], 223 l1, l2, res, i, sol, 224 v1 = [0, 0, 0], 225 v2 = [0, 0, 0], 226 step = 1, 227 q = [0, 0, 0]; 228 229 this.dataX = []; 230 this.dataY = []; 231 232 if (Type.isFunction(point)) { 233 q = point().slice(1); 234 } else { 235 for (i = 0; i < 3; i++) { 236 q[i] = Type.evaluate(point[i]); 237 } 238 } 239 for (i = 0; i < 3; i++) { 240 v1[i] = Type.evaluate(dir1[i]); 241 v2[i] = Type.evaluate(dir2[i]); 242 } 243 l1 = JXG.Math.norm(v1, 3); 244 l2 = JXG.Math.norm(v2, 3); 245 for (i = 0; i < 3; i++) { 246 v1[i] /= l1; 247 v2[i] /= l2; 248 } 249 250 // sol = Mat.Geometry.getPlaneBounds(v1, v2, q, s1, e1); 251 // if (sol !== null) { 252 // s1 = sol[0]; 253 // e1 = sol[1]; 254 // s2 = sol[2]; 255 // e2 = sol[3]; 256 // } 257 258 res = view.getMesh( 259 [ 260 function(u, v) { return q[0] + u * v1[0] + v * v2[0]; }, 261 function(u, v) { return q[1] + u * v1[1] + v * v2[1]; }, 262 function(u, v) { return q[2] + u * v1[2] + v * v2[2]; } 263 ], 264 [Math.ceil(s1), Math.floor(e1), (Math.ceil(e1) - Math.floor(s1)) / step], 265 [Math.ceil(s2), Math.floor(e2), (Math.ceil(e2) - Math.floor(s2)) / step]); 266 this.dataX = res[0]; 267 this.dataY = res[1]; 268 }; 269 return el; 270 }; 271 JXG.registerElement('mesh3d', JXG.createMesh3D); 272 273 });