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