jsxgraph 1.4.1 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/distrib/geogebra.min.js +1 -1
- package/distrib/geonext.min.js +1 -1
- package/distrib/index.d.ts +5252 -4826
- package/distrib/intergeo.min.js +1 -1
- package/distrib/jsxgraph.css +6 -2
- package/distrib/jsxgraphcore.js +4 -4
- package/distrib/jsxgraphsrc.js +2617 -151
- package/distrib/sketch.min.js +2 -2
- package/package.json +1 -1
- package/src/3d/box3d.js +268 -0
- package/src/3d/curve3d.js +97 -0
- package/src/3d/linspace3d.js +375 -0
- package/src/3d/point3d.js +200 -0
- package/src/3d/surface3d.js +220 -0
- package/src/3d/threed.js +38 -0
- package/src/3d/view3d.js +529 -0
- package/src/base/board.js +62 -45
- package/src/base/constants.js +2 -1
- package/src/base/coordselement.js +1 -4
- package/src/base/element.js +23 -14
- package/src/base/foreignobject.js +7 -1
- package/src/base/line.js +1 -1
- package/src/base/point.js +1 -0
- package/src/base/polygon.js +88 -33
- package/src/base/ticks.js +9 -2
- package/src/element/composition.js +62 -23
- package/src/element/slider.js +12 -0
- package/src/jsxgraph.js +6 -4
- package/src/loadjsxgraph.js +17 -11
- package/src/math/clip.js +0 -1
- package/src/math/geometry.js +187 -2
- package/src/math/math.js +9 -0
- package/src/options.js +24 -9
- package/src/options3d.js +265 -0
- package/src/parser/jessiecode.js +103 -0
- package/src/reader/sketch.js +6 -6
- package/src/renderer/abstract.js +4 -1
- package/src/renderer/svg.js +7 -4
- package/src/utils/color.js +1 -2
- package/src/utils/type.js +2 -2
|
@@ -0,0 +1,375 @@
|
|
|
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 linear spaces of dimension at least one,
|
|
33
|
+
* i.e. lines and planes.
|
|
34
|
+
*/
|
|
35
|
+
define(['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d'
|
|
36
|
+
], function (JXG, Type, Mat, Geometry, ThreeD) {
|
|
37
|
+
"use strict";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @class This element is used to provide a constructor for a 3D line.
|
|
41
|
+
* @pseudo
|
|
42
|
+
* @description There are two possibilities to create a Line3D object.
|
|
43
|
+
* <p>
|
|
44
|
+
* First: the line in 3D is defined by two points in 3D (Point3D).
|
|
45
|
+
* The points can be either existing points or coordinate arrays of
|
|
46
|
+
* the form [x, y, z].
|
|
47
|
+
* <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])
|
|
48
|
+
* a direction given as array [x, y, z] and an optional range
|
|
49
|
+
* given as array [s, e]. The default value for the range is [-Infinity, Infinity].
|
|
50
|
+
* <p>
|
|
51
|
+
* All numbers can also be provided as functions returning a number.
|
|
52
|
+
*
|
|
53
|
+
* @name Line3D
|
|
54
|
+
* @augments JXG.Curve
|
|
55
|
+
* @constructor
|
|
56
|
+
* @type JXG.Curve
|
|
57
|
+
* @throws {Exception} If the element cannot be constructed with the given parent
|
|
58
|
+
* objects an exception is thrown.
|
|
59
|
+
* @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given
|
|
60
|
+
* as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the
|
|
61
|
+
* line will determine the radius), or another {@link JXG.Circle}.
|
|
62
|
+
*
|
|
63
|
+
*/
|
|
64
|
+
ThreeD.createLine = function (board, parents, attributes) {
|
|
65
|
+
var view = parents[0],
|
|
66
|
+
attr, D3, point, point1, point2,
|
|
67
|
+
el;
|
|
68
|
+
|
|
69
|
+
// Range
|
|
70
|
+
D3 = {
|
|
71
|
+
elType: 'line3d',
|
|
72
|
+
range: parents[3] || [-Infinity, Infinity]
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Point
|
|
76
|
+
if (Type.isPoint(parents[1])) {
|
|
77
|
+
point = parents[1];
|
|
78
|
+
} else {
|
|
79
|
+
point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });
|
|
80
|
+
}
|
|
81
|
+
D3.point = point;
|
|
82
|
+
|
|
83
|
+
// Direction
|
|
84
|
+
if (Type.isPoint(parents[2]) && Type.exists(parents[2].D3)) {
|
|
85
|
+
// Line defined by two points
|
|
86
|
+
|
|
87
|
+
point1 = point;
|
|
88
|
+
point2 = parents[2];
|
|
89
|
+
D3.direction = function () {
|
|
90
|
+
return [
|
|
91
|
+
point2.D3.X() - point.D3.X(),
|
|
92
|
+
point2.D3.Y() - point.D3.Y(),
|
|
93
|
+
point2.D3.Z() - point.D3.Z()
|
|
94
|
+
];
|
|
95
|
+
};
|
|
96
|
+
D3.range = [0, 1];
|
|
97
|
+
} else {
|
|
98
|
+
// Line defined by point, direction and range
|
|
99
|
+
|
|
100
|
+
// Directions are handled as arrays of length 4,
|
|
101
|
+
// i.e. with homogeneous coordinates.
|
|
102
|
+
if (Type.isFunction(parents[2])) {
|
|
103
|
+
D3.direction = parents[2];
|
|
104
|
+
} else if (parents[2].length === 3) {
|
|
105
|
+
D3.direction = [1].concat(parents[2]);
|
|
106
|
+
} else if (parents[2].length === 4) {
|
|
107
|
+
D3.direction = parents[2];
|
|
108
|
+
} else {
|
|
109
|
+
// Throw error
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Direction given as array
|
|
113
|
+
D3.getPointCoords = function (r) {
|
|
114
|
+
var p = [],
|
|
115
|
+
d = [],
|
|
116
|
+
i;
|
|
117
|
+
|
|
118
|
+
p.push(point.D3.X());
|
|
119
|
+
p.push(point.D3.Y());
|
|
120
|
+
p.push(point.D3.Z());
|
|
121
|
+
|
|
122
|
+
if (Type.isFunction(D3.direction)) {
|
|
123
|
+
d = D3.direction();
|
|
124
|
+
} else {
|
|
125
|
+
for (i = 1; i < 4; i++) {
|
|
126
|
+
d.push(Type.evaluate(D3.direction[i]));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (Math.abs(r) === Infinity) {
|
|
130
|
+
r = view.intersectionLineCube(p, d, r);
|
|
131
|
+
}
|
|
132
|
+
return [
|
|
133
|
+
p[0] + d[0] * r,
|
|
134
|
+
p[1] + d[1] * r,
|
|
135
|
+
p[2] + d[2] * r
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point1');
|
|
141
|
+
point1 = view.create('point3d', [
|
|
142
|
+
function () {
|
|
143
|
+
return D3.getPointCoords(Type.evaluate(D3.range[0]));
|
|
144
|
+
}
|
|
145
|
+
], attr);
|
|
146
|
+
attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point2');
|
|
147
|
+
point2 = view.create('point3d', [
|
|
148
|
+
function () {
|
|
149
|
+
return D3.getPointCoords(Type.evaluate(D3.range[1]));
|
|
150
|
+
}
|
|
151
|
+
], attr);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
attr = Type.copyAttributes(attributes, board.options, 'line3d');
|
|
155
|
+
el = view.create('segment', [point1, point2], attr);
|
|
156
|
+
el.point1 = point1;
|
|
157
|
+
el.point2 = point2;
|
|
158
|
+
point1.addChild(el);
|
|
159
|
+
point2.addChild(el);
|
|
160
|
+
el.D3 = D3;
|
|
161
|
+
|
|
162
|
+
return el;
|
|
163
|
+
};
|
|
164
|
+
JXG.registerElement('line3d', ThreeD.createLine);
|
|
165
|
+
|
|
166
|
+
ThreeD.createPlane = function (board, parents, attributes) {
|
|
167
|
+
var view = parents[0],
|
|
168
|
+
attr, D3,
|
|
169
|
+
point,
|
|
170
|
+
vec1 = parents[2],
|
|
171
|
+
vec2 = parents[3],
|
|
172
|
+
el, grid, update;
|
|
173
|
+
|
|
174
|
+
// D3: {
|
|
175
|
+
// point,
|
|
176
|
+
// vec1,
|
|
177
|
+
// vec2,
|
|
178
|
+
// poin1,
|
|
179
|
+
// point2,
|
|
180
|
+
// normal array of len 3
|
|
181
|
+
// d
|
|
182
|
+
// }
|
|
183
|
+
D3 = {
|
|
184
|
+
elType: 'plane3d',
|
|
185
|
+
dir1: [],
|
|
186
|
+
dir2: [],
|
|
187
|
+
range1: parents[4],
|
|
188
|
+
range2: parents[5],
|
|
189
|
+
vec1: vec1,
|
|
190
|
+
vec2: vec2
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (Type.isPoint(parents[1])) {
|
|
194
|
+
point = parents[1];
|
|
195
|
+
} else {
|
|
196
|
+
point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });
|
|
197
|
+
}
|
|
198
|
+
D3.point = point;
|
|
199
|
+
|
|
200
|
+
D3.updateNormal = function () {
|
|
201
|
+
var i;
|
|
202
|
+
for (i = 0; i < 3; i++) {
|
|
203
|
+
D3.dir1[i] = Type.evaluate(D3.vec1[i]);
|
|
204
|
+
D3.dir2[i] = Type.evaluate(D3.vec2[i]);
|
|
205
|
+
}
|
|
206
|
+
D3.normal = Mat.crossProduct(D3.dir1, D3.dir2);
|
|
207
|
+
D3.d = Mat.innerProduct(D3.point.D3.coords.slice(1), D3.normal, 3);
|
|
208
|
+
};
|
|
209
|
+
D3.updateNormal();
|
|
210
|
+
|
|
211
|
+
attr = Type.copyAttributes(attributes, board.options, 'plane3d');
|
|
212
|
+
el = board.create('curve', [[], []], attr);
|
|
213
|
+
el.D3 = D3;
|
|
214
|
+
|
|
215
|
+
el.updateDataArray = function () {
|
|
216
|
+
var s1, e1, s2, e2,
|
|
217
|
+
c2d, l1, l2,
|
|
218
|
+
planes = ['xPlaneRear', 'yPlaneRear', 'zPlaneRear'],
|
|
219
|
+
points = [],
|
|
220
|
+
v1 = [0, 0, 0],
|
|
221
|
+
v2 = [0, 0, 0],
|
|
222
|
+
q = [0, 0, 0],
|
|
223
|
+
p = [0, 0, 0], d, i, j, a, b, first, pos, pos_akt;
|
|
224
|
+
|
|
225
|
+
this.dataX = [];
|
|
226
|
+
this.dataY = [];
|
|
227
|
+
|
|
228
|
+
this.D3.updateNormal();
|
|
229
|
+
|
|
230
|
+
// Infinite plane
|
|
231
|
+
if (this.D3.elType !== 'axisplane3d' && view.defaultAxes &&
|
|
232
|
+
(!D3.range1 || !D3.range2)
|
|
233
|
+
) {
|
|
234
|
+
|
|
235
|
+
// Start with the rear plane.
|
|
236
|
+
// Determine the intersections with the view bbox3d
|
|
237
|
+
// For each face of the bbox3d we determine two points
|
|
238
|
+
// which are the ends of the intersection line.
|
|
239
|
+
// We start with the three rear planes.
|
|
240
|
+
for (j = 0; j < planes.length; j++) {
|
|
241
|
+
p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]]);
|
|
242
|
+
|
|
243
|
+
if (p[0].length === 3 && p[1].length === 3) {
|
|
244
|
+
// This test is necessary to filter out intersection lines which are
|
|
245
|
+
// identical to intersections of axis planes (they would occur twice).
|
|
246
|
+
for (i = 0; i < points.length; i++) {
|
|
247
|
+
if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||
|
|
248
|
+
(Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (i === points.length) {
|
|
253
|
+
points.push(p.slice());
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Point on the front plane of the bbox3d
|
|
258
|
+
p = [0, 0, 0];
|
|
259
|
+
p[j] = view.D3.bbox3d[j][1];
|
|
260
|
+
|
|
261
|
+
// d is the rhs of the Hesse normal form of the front plane.
|
|
262
|
+
d = Mat.innerProduct(p, view.defaultAxes[planes[j]].D3.normal, 3);
|
|
263
|
+
p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]], d);
|
|
264
|
+
|
|
265
|
+
if (p[0].length === 3 && p[1].length === 3) {
|
|
266
|
+
// Do the same test as above
|
|
267
|
+
for (i = 0; i < points.length; i++) {
|
|
268
|
+
if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||
|
|
269
|
+
(Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (i === points.length) {
|
|
274
|
+
points.push(p.slice());
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Concatenate the intersection points to a polygon.
|
|
280
|
+
// If all wents well, each intersection should appear
|
|
281
|
+
// twice in the list.
|
|
282
|
+
first = 0;
|
|
283
|
+
pos = first;
|
|
284
|
+
i = 0;
|
|
285
|
+
do {
|
|
286
|
+
p = points[pos][i];
|
|
287
|
+
if (p.length === 3) {
|
|
288
|
+
c2d = view.project3DTo2D(p);
|
|
289
|
+
this.dataX.push(c2d[1]);
|
|
290
|
+
this.dataY.push(c2d[2]);
|
|
291
|
+
}
|
|
292
|
+
i = (i + 1) % 2;
|
|
293
|
+
p = points[pos][i];
|
|
294
|
+
|
|
295
|
+
pos_akt = pos;
|
|
296
|
+
for (j = 0; j < points.length; j++) {
|
|
297
|
+
if (j !== pos && Geometry.distance(p, points[j][0]) < Mat.eps) {
|
|
298
|
+
pos = j;
|
|
299
|
+
i = 0;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
if (j !== pos && Geometry.distance(p, points[j][1]) < Mat.eps) {
|
|
303
|
+
pos = j;
|
|
304
|
+
i = 1;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (pos === pos_akt) {
|
|
309
|
+
console.log("Error: update plane3d: did not find next", pos);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
} while (pos !== first);
|
|
313
|
+
c2d = view.project3DTo2D(points[first][0]);
|
|
314
|
+
this.dataX.push(c2d[1]);
|
|
315
|
+
this.dataY.push(c2d[2]);
|
|
316
|
+
|
|
317
|
+
} else {
|
|
318
|
+
// 3D bounded flat
|
|
319
|
+
s1 = Type.evaluate(this.D3.range1[0]);
|
|
320
|
+
e1 = Type.evaluate(this.D3.range1[1]);
|
|
321
|
+
s2 = Type.evaluate(this.D3.range2[0]);
|
|
322
|
+
e2 = Type.evaluate(this.D3.range2[1]);
|
|
323
|
+
|
|
324
|
+
q = this.D3.point.D3.coords.slice(1);
|
|
325
|
+
|
|
326
|
+
v1 = this.D3.dir1.slice();
|
|
327
|
+
v2 = this.D3.dir2.slice();
|
|
328
|
+
l1 = Mat.norm(v1, 3);
|
|
329
|
+
l2 = Mat.norm(v2, 3);
|
|
330
|
+
for (i = 0; i < 3; i++) {
|
|
331
|
+
v1[i] /= l1;
|
|
332
|
+
v2[i] /= l2;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
for (j = 0; j < 4; j++) {
|
|
336
|
+
switch (j) {
|
|
337
|
+
case 0: a = s1; b = s2; break;
|
|
338
|
+
case 1: a = e1; b = s2; break;
|
|
339
|
+
case 2: a = e1; b = e2; break;
|
|
340
|
+
case 3: a = s1; b = e2;
|
|
341
|
+
}
|
|
342
|
+
for (i = 0; i < 3; i++) {
|
|
343
|
+
p[i] = q[i] + a * v1[i] + b * v2[i];
|
|
344
|
+
}
|
|
345
|
+
c2d = view.project3DTo2D(p);
|
|
346
|
+
this.dataX.push(c2d[1]);
|
|
347
|
+
this.dataY.push(c2d[2]);
|
|
348
|
+
}
|
|
349
|
+
// Close the curve
|
|
350
|
+
this.dataX.push(this.dataX[0]);
|
|
351
|
+
this.dataY.push(this.dataY[0]);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
attr = Type.copyAttributes(attributes.mesh3d, board.options, 'mesh3d');
|
|
356
|
+
|
|
357
|
+
if (D3.range1 && D3.range2) {
|
|
358
|
+
grid = view.create('mesh3d', [point.D3.coords.slice(1), vec1, D3.range1, vec2, D3.range2], attr);
|
|
359
|
+
el.grid = grid;
|
|
360
|
+
el.inherits.push(grid);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// update = el.update;
|
|
364
|
+
// el.update = function () {
|
|
365
|
+
// if (el.needsUpdate) {
|
|
366
|
+
// update.apply(el);
|
|
367
|
+
// }
|
|
368
|
+
// return this;
|
|
369
|
+
// };
|
|
370
|
+
|
|
371
|
+
return el;
|
|
372
|
+
};
|
|
373
|
+
JXG.registerElement('plane3d', ThreeD.createPlane);
|
|
374
|
+
|
|
375
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
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
|
+
define(['jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type', '3d/view3d'
|
|
32
|
+
], function (JXG, Const, Mat, Geometry, Type, ThreeD) {
|
|
33
|
+
"use strict";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @class This element is used to provide a constructor for a 3D Point.
|
|
37
|
+
* @pseudo
|
|
38
|
+
* @description There are two possibilities to create a Line3D object.
|
|
39
|
+
* <p>
|
|
40
|
+
* First: the line in 3D is defined by two points in 3D (Point3D).
|
|
41
|
+
* The points can be either existing points or coordinate arrays of
|
|
42
|
+
* the form [x, y, z].
|
|
43
|
+
* <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])
|
|
44
|
+
* a direction given as array [x, y, z] and an optional range
|
|
45
|
+
* given as array [s, e]. The default value for the range is [-Infinity, Infinity].
|
|
46
|
+
* <p>
|
|
47
|
+
* All numbers can also be provided as functions returning a number.
|
|
48
|
+
*
|
|
49
|
+
* @name Point3D
|
|
50
|
+
* @augments JXG.Point
|
|
51
|
+
* @constructor
|
|
52
|
+
* @type JXG.Point
|
|
53
|
+
* @throws {Exception} If the element cannot be constructed with the given parent
|
|
54
|
+
* objects an exception is thrown.
|
|
55
|
+
* @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given
|
|
56
|
+
* as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the
|
|
57
|
+
* line will determine the radius), or another {@link JXG.Circle}.
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
ThreeD.createPoint = function (board, parents, attributes) {
|
|
61
|
+
var view = parents[0],
|
|
62
|
+
attr, update2D, D3,
|
|
63
|
+
i, c2d,
|
|
64
|
+
el;
|
|
65
|
+
|
|
66
|
+
attr = Type.copyAttributes(attributes, board.options, 'point3d');
|
|
67
|
+
|
|
68
|
+
D3 = {
|
|
69
|
+
elType: 'point3d',
|
|
70
|
+
coords: [1, 0, 0, 0],
|
|
71
|
+
X: function () { return this.coords[1]; },
|
|
72
|
+
Y: function () { return this.coords[2]; },
|
|
73
|
+
Z: function () { return this.coords[3]; }
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// If the last element of partents is a 3D object, the point is a glider
|
|
77
|
+
// on that element.
|
|
78
|
+
if (parents.length > 2 && Type.exists(parents[parents.length - 1].D3)) {
|
|
79
|
+
D3.slide = parents.pop();
|
|
80
|
+
} else {
|
|
81
|
+
D3.slide = null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (parents.length === 2) {
|
|
85
|
+
D3.F = parents[1]; // (Array [x, y, z] | function) returning [x, y, z]
|
|
86
|
+
D3.coords = [1].concat(Type.evaluate(D3.F));
|
|
87
|
+
} else if (parents.length === 4) {
|
|
88
|
+
D3.F = parents.slice(1); // 3 numbers | functions
|
|
89
|
+
for (i = 0; i < 3; i++) {
|
|
90
|
+
D3.coords[i + 1] = Type.evaluate(D3.F[i]);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
// Throw error
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Update the 4D coords array
|
|
98
|
+
* @returns Object
|
|
99
|
+
*/
|
|
100
|
+
D3.updateCoords = function () {
|
|
101
|
+
var res, i;
|
|
102
|
+
if (Type.isFunction(this.F)) {
|
|
103
|
+
res = Type.evaluate(this.F);
|
|
104
|
+
this.coords = [1, res[0], res[1], res[2]];
|
|
105
|
+
} else {
|
|
106
|
+
this.coords[0] = 1;
|
|
107
|
+
for (i = 0; i < 3; i++) {
|
|
108
|
+
if (Type.isFunction(this.F[i])) {
|
|
109
|
+
this.coords[i + 1] = Type.evaluate(this.F[i]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
};
|
|
115
|
+
D3.updateCoords();
|
|
116
|
+
|
|
117
|
+
c2d = view.project3DTo2D(D3.coords);
|
|
118
|
+
el = board.create('point', c2d, attr);
|
|
119
|
+
el.D3 = D3;
|
|
120
|
+
el.D3.c2d = el.coords.usrCoords.slice(); // Copy of the coordinates to detect dragging
|
|
121
|
+
update2D = el.update;
|
|
122
|
+
|
|
123
|
+
if (el.D3.slide) {
|
|
124
|
+
el._minFunc = function (n, m, x, con) {
|
|
125
|
+
var surface = el.D3.slide.D3,
|
|
126
|
+
c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])],
|
|
127
|
+
c2d = view.project3DTo2D(c3d);
|
|
128
|
+
|
|
129
|
+
con[0] = el.X() - c2d[1];
|
|
130
|
+
con[1] = el.Y() - c2d[2];
|
|
131
|
+
|
|
132
|
+
return con[0] * con[0] + con[1] * con[1];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
el.projectCoords2Surface = function () {
|
|
136
|
+
var n = 2, // # of variables
|
|
137
|
+
m = 2, // number of constraints
|
|
138
|
+
x = [0, 0],
|
|
139
|
+
// Various Cobyla constants, see Cobyla docs in Cobyja.js
|
|
140
|
+
rhobeg = 5.0,
|
|
141
|
+
rhoend = 1.0e-6,
|
|
142
|
+
iprint = 0,
|
|
143
|
+
maxfun = 200,
|
|
144
|
+
surface = this.D3.slide.D3,
|
|
145
|
+
r, c3d, c2d;
|
|
146
|
+
|
|
147
|
+
if (Type.exists(this.D3.params)) {
|
|
148
|
+
x = this.D3.params.slice();
|
|
149
|
+
}
|
|
150
|
+
r = Mat.Nlp.FindMinimum(this._minFunc, n, m, x, rhobeg, rhoend, iprint, maxfun);
|
|
151
|
+
|
|
152
|
+
c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])];
|
|
153
|
+
c2d = view.project3DTo2D(c3d);
|
|
154
|
+
this.D3.params = x;
|
|
155
|
+
this.D3.coords = c3d;
|
|
156
|
+
this.coords.setCoordinates(Const.COORDS_BY_USER, c2d);
|
|
157
|
+
this.D3.c2d = c2d;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
el.update = function (drag) {
|
|
162
|
+
var c3d, foot;
|
|
163
|
+
if (!this.needsUpdate) {
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Update is called in from two methods:
|
|
168
|
+
// Once in setToPositionDirectly and
|
|
169
|
+
// once in the subsequent board.update
|
|
170
|
+
if (this.draggable() &&
|
|
171
|
+
Geometry.distance(this.D3.c2d, this.coords.usrCoords) !== 0) {
|
|
172
|
+
|
|
173
|
+
if (this.D3.slide) {
|
|
174
|
+
this.projectCoords2Surface();
|
|
175
|
+
} else {
|
|
176
|
+
// Drag the point in its xy plane
|
|
177
|
+
foot = [1, 0, 0, this.D3.coords[3]];
|
|
178
|
+
c3d = view.project2DTo3DPlane(el, [1, 0, 0, 1], foot);
|
|
179
|
+
if (c3d[0] !== 0) {
|
|
180
|
+
this.D3.coords = view.project3DToCube(c3d);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
this.D3.updateCoords();
|
|
185
|
+
// Update 2D point from its 3D view
|
|
186
|
+
el.coords.setCoordinates(Const.COORDS_BY_USER,
|
|
187
|
+
view.project3DTo2D([1, this.D3.X(), this.D3.Y(), this.D3.Z()])
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
this.D3.c2d = el.coords.usrCoords.slice();
|
|
191
|
+
|
|
192
|
+
update2D.apply(this, [drag]);
|
|
193
|
+
return this;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
return el;
|
|
197
|
+
};
|
|
198
|
+
JXG.registerElement('point3d', ThreeD.createPoint);
|
|
199
|
+
|
|
200
|
+
});
|