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, na, 52 ticks_attr, 53 axes = {}; 54 55 if (Type.exists(view.D3)) { 56 for (i = 0; i < directions.length; i++) { 57 rear[i] = view.D3.bbox3d[i][0]; 58 front[i] = view.D3.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 // Axes 68 attr = Type.copyAttributes(attributes, board.options, 'axes3d'); 69 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 // 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 axes[na] = 139 view.create('plane3d', [from, vec1, vec2, range1, range2], attr[na.toLowerCase()]); 140 axes[na].D3.elType = 'axisplane3d'; 141 } 142 } 143 144 // Axes on planes 145 for (i = 0; i < directions.length; i++) { 146 // Run through ['x', 'y', 'z'] 147 dir = directions[i]; 148 for (j = 0; j < sides.length; j++) { 149 for (k = 1; k <= 2; k++) { 150 i1 = (i + k) % 3; 151 dir1 = directions[i1]; 152 na = dir + 'Plane' + sides[j] + dir1.toUpperCase() + 'Axis'; 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 axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]); 162 } 163 } 164 } 165 // axes.Y2Dxy = view.create('axis3d', [[0, sy, sz], [0, ey, sz]], attr); 166 167 return axes; 168 }; 169 JXG.registerElement('axes3d', ThreeD.createAxes); 170 171 ThreeD.createAxis = function (board, parents, attributes) { 172 var view = parents[0], 173 attr, 174 start = parents[1], 175 end = parents[2], 176 el_start, el_end, el; 177 178 // Use 2D points to create axis 179 attr = Type.copyAttributes(attributes.point1, board.options, 'axis3d', 'point1'); 180 el_start = board.create('point', [ 181 (function (xx, yy, zz) { 182 return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; 183 })(start[0], start[1], start[2]), 184 (function (xx, yy, zz) { 185 return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; 186 })(start[0], start[1], start[2]) 187 ], attr); 188 189 attr = Type.copyAttributes(attributes.point2, board.options, 'axis3d', 'point2'); 190 el_end = board.create('point', [ 191 (function (xx, yy, zz) { 192 return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; 193 })(end[0], end[1], end[2]), 194 (function (xx, yy, zz) { 195 return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; 196 })(end[0], end[1], end[2]) 197 ], attr); 198 199 attr = Type.copyAttributes(attributes, board.options, 'axis3d'); 200 el = board.create('arrow', [el_start, el_end], attr); 201 202 return el; 203 }; 204 JXG.registerElement('axis3d', ThreeD.createAxis); 205 206 ThreeD.createMesh = function (board, parents, attr) { 207 var view = parents[0], 208 point = parents[1], 209 vec1 = parents[2], 210 range1 = parents[3], 211 vec2 = parents[4], 212 range2 = parents[5], 213 el; 214 215 el = board.create('curve', [[], []], attr); 216 el.updateDataArray = function () { 217 var s1 = range1[0], 218 e1 = range1[1], 219 s2 = range2[0], 220 e2 = range2[1], 221 l1, l2, res, i, sol, 222 v1 = [0, 0, 0], 223 v2 = [0, 0, 0], 224 step = 1, 225 q = [0, 0, 0]; 226 227 this.dataX = []; 228 this.dataY = []; 229 230 for (i = 0; i < 3; i++) { 231 q[i] = Type.evaluate(point[i]); 232 v1[i] = Type.evaluate(vec1[i]); 233 v2[i] = Type.evaluate(vec2[i]); 234 } 235 l1 = JXG.Math.norm(v1, 3); 236 l2 = JXG.Math.norm(v2, 3); 237 for (i = 0; i < 3; i++) { 238 v1[i] /= l1; 239 v2[i] /= l2; 240 } 241 if (false) { 242 sol = Mat.Geometry.getPlaneBounds(v1, v2, q, s1, e1); 243 if (sol !== null) { 244 s1 = sol[0]; 245 e1 = sol[1]; 246 s2 = sol[2]; 247 e2 = sol[3]; 248 } 249 } 250 251 res = view.getMesh( 252 function(u, v) { return q[0] + u * v1[0] + v * v2[0]; }, 253 function(u, v) { return q[1] + u * v1[1] + v * v2[1]; }, 254 function(u, v) { return q[2] + u * v1[2] + v * v2[2]; }, 255 [Math.ceil(s1), Math.floor(e1), (Math.ceil(e1) - Math.floor(s1)) / step], 256 [Math.ceil(s2), Math.floor(e2), (Math.ceil(e2) - Math.floor(s2)) / step]); 257 this.dataX = res[0]; 258 this.dataY = res[1]; 259 }; 260 return el; 261 }; 262 JXG.registerElement('mesh3d', ThreeD.createMesh); 263 264 });