passagemath-plot 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.whl
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.
Potentially problematic release.
This version of passagemath-plot might be problematic. Click here for more details.
- passagemath_plot-10.6.31rc3.dist-info/METADATA +172 -0
- passagemath_plot-10.6.31rc3.dist-info/RECORD +82 -0
- passagemath_plot-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_plot-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_plot.dylibs/libgfortran.5.dylib +0 -0
- passagemath_plot.dylibs/libgsl.28.dylib +0 -0
- passagemath_plot.dylibs/libopenblasp-r0.3.29.dylib +0 -0
- passagemath_plot.dylibs/libquadmath.0.dylib +0 -0
- sage/all__sagemath_plot.py +15 -0
- sage/ext_data/threejs/animation.css +195 -0
- sage/ext_data/threejs/animation.html +85 -0
- sage/ext_data/threejs/animation.js +273 -0
- sage/ext_data/threejs/fat_lines.js +48 -0
- sage/ext_data/threejs/threejs-version.txt +1 -0
- sage/ext_data/threejs/threejs_template.html +597 -0
- sage/interfaces/all__sagemath_plot.py +1 -0
- sage/interfaces/gnuplot.py +196 -0
- sage/interfaces/jmoldata.py +208 -0
- sage/interfaces/povray.py +56 -0
- sage/plot/all.py +42 -0
- sage/plot/animate.py +1796 -0
- sage/plot/arc.py +504 -0
- sage/plot/arrow.py +671 -0
- sage/plot/bar_chart.py +205 -0
- sage/plot/bezier_path.py +400 -0
- sage/plot/circle.py +435 -0
- sage/plot/colors.py +1606 -0
- sage/plot/complex_plot.cpython-314-darwin.so +0 -0
- sage/plot/complex_plot.pyx +1446 -0
- sage/plot/contour_plot.py +1792 -0
- sage/plot/density_plot.py +318 -0
- sage/plot/disk.py +373 -0
- sage/plot/ellipse.py +375 -0
- sage/plot/graphics.py +3580 -0
- sage/plot/histogram.py +354 -0
- sage/plot/hyperbolic_arc.py +404 -0
- sage/plot/hyperbolic_polygon.py +416 -0
- sage/plot/hyperbolic_regular_polygon.py +296 -0
- sage/plot/line.py +626 -0
- sage/plot/matrix_plot.py +629 -0
- sage/plot/misc.py +509 -0
- sage/plot/multigraphics.py +1294 -0
- sage/plot/plot.py +4183 -0
- sage/plot/plot3d/all.py +23 -0
- sage/plot/plot3d/base.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/base.pxd +12 -0
- sage/plot/plot3d/base.pyx +3378 -0
- sage/plot/plot3d/implicit_plot3d.py +659 -0
- sage/plot/plot3d/implicit_surface.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/implicit_surface.pyx +1453 -0
- sage/plot/plot3d/index_face_set.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/index_face_set.pxd +32 -0
- sage/plot/plot3d/index_face_set.pyx +1873 -0
- sage/plot/plot3d/introduction.py +131 -0
- sage/plot/plot3d/list_plot3d.py +649 -0
- sage/plot/plot3d/parametric_plot3d.py +1130 -0
- sage/plot/plot3d/parametric_surface.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/parametric_surface.pxd +12 -0
- sage/plot/plot3d/parametric_surface.pyx +893 -0
- sage/plot/plot3d/platonic.py +601 -0
- sage/plot/plot3d/plot3d.py +1442 -0
- sage/plot/plot3d/plot_field3d.py +162 -0
- sage/plot/plot3d/point_c.pxi +148 -0
- sage/plot/plot3d/revolution_plot3d.py +309 -0
- sage/plot/plot3d/shapes.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/shapes.pxd +22 -0
- sage/plot/plot3d/shapes.pyx +1382 -0
- sage/plot/plot3d/shapes2.py +1512 -0
- sage/plot/plot3d/tachyon.py +1779 -0
- sage/plot/plot3d/texture.py +453 -0
- sage/plot/plot3d/transform.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/transform.pxd +21 -0
- sage/plot/plot3d/transform.pyx +268 -0
- sage/plot/plot3d/tri_plot.py +589 -0
- sage/plot/plot_field.py +362 -0
- sage/plot/point.py +624 -0
- sage/plot/polygon.py +562 -0
- sage/plot/primitive.py +249 -0
- sage/plot/scatter_plot.py +199 -0
- sage/plot/step.py +85 -0
- sage/plot/streamline_plot.py +328 -0
- sage/plot/text.py +432 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>SAGE_TITLE</title>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<meta name=viewport content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
|
7
|
+
<style>
|
|
8
|
+
|
|
9
|
+
body { margin: 0px; overflow: hidden; }
|
|
10
|
+
|
|
11
|
+
#menu-container { position: absolute; bottom: 30px; right: 40px; cursor: default; }
|
|
12
|
+
|
|
13
|
+
#menu-message { position: absolute; bottom: 0px; right: 0px; white-space: nowrap;
|
|
14
|
+
display: none; background-color: #F5F5F5; padding: 10px; }
|
|
15
|
+
|
|
16
|
+
#menu-content { position: absolute; bottom: 0px; right: 0px;
|
|
17
|
+
display: none; background-color: #F5F5F5; border-bottom: 1px solid black;
|
|
18
|
+
border-right: 1px solid black; border-left: 1px solid black; }
|
|
19
|
+
|
|
20
|
+
#menu-content div { border-top: 1px solid black; padding: 10px; white-space: nowrap; }
|
|
21
|
+
|
|
22
|
+
#menu-content div:hover { background-color: #FEFEFE; }
|
|
23
|
+
|
|
24
|
+
.dark-theme #menu-container { color: white; }
|
|
25
|
+
|
|
26
|
+
.dark-theme #menu-message { background-color: #181818; }
|
|
27
|
+
|
|
28
|
+
.dark-theme #menu-content { background-color: #181818; border-color: white; }
|
|
29
|
+
|
|
30
|
+
.dark-theme #menu-content div { border-color: white; }
|
|
31
|
+
|
|
32
|
+
.dark-theme #menu-content div:hover { background-color: #303030; }
|
|
33
|
+
|
|
34
|
+
</style>
|
|
35
|
+
SAGE_STYLES
|
|
36
|
+
</head>
|
|
37
|
+
|
|
38
|
+
<body>
|
|
39
|
+
SAGE_SCRIPTS
|
|
40
|
+
<script>
|
|
41
|
+
|
|
42
|
+
var options = SAGE_OPTIONS;
|
|
43
|
+
var animate = options.animate;
|
|
44
|
+
|
|
45
|
+
if ( options.theme === 'dark' )
|
|
46
|
+
document.body.className = 'dark-theme';
|
|
47
|
+
|
|
48
|
+
var scene = new THREE.Scene();
|
|
49
|
+
|
|
50
|
+
var renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );
|
|
51
|
+
renderer.setPixelRatio( window.devicePixelRatio );
|
|
52
|
+
renderer.setSize( window.innerWidth, window.innerHeight );
|
|
53
|
+
renderer.setClearColor( options.theme === 'dark' ? 0 : 0xffffff, 1 );
|
|
54
|
+
document.body.appendChild( renderer.domElement );
|
|
55
|
+
|
|
56
|
+
var b = SAGE_BOUNDS; // bounds
|
|
57
|
+
|
|
58
|
+
if ( b[0].x === b[1].x ) {
|
|
59
|
+
b[0].x -= 1;
|
|
60
|
+
b[1].x += 1;
|
|
61
|
+
}
|
|
62
|
+
if ( b[0].y === b[1].y ) {
|
|
63
|
+
b[0].y -= 1;
|
|
64
|
+
b[1].y += 1;
|
|
65
|
+
}
|
|
66
|
+
if ( b[0].z === b[1].z ) {
|
|
67
|
+
b[0].z -= 1;
|
|
68
|
+
b[1].z += 1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var rxRange = Math.sqrt( Math.pow( b[1].z - b[0].z, 2 )
|
|
72
|
+
+ Math.pow( b[1].y - b[0].y, 2 ) );
|
|
73
|
+
var ryRange = Math.sqrt( Math.pow( b[1].x - b[0].x, 2 )
|
|
74
|
+
+ Math.pow( b[1].z - b[0].z, 2 ) );
|
|
75
|
+
var rzRange = Math.sqrt( Math.pow( b[1].x - b[0].x, 2 )
|
|
76
|
+
+ Math.pow( b[1].y - b[0].y, 2 ) );
|
|
77
|
+
var xRange = b[1].x - b[0].x;
|
|
78
|
+
var yRange = b[1].y - b[0].y;
|
|
79
|
+
var zRange = b[1].z - b[0].z;
|
|
80
|
+
|
|
81
|
+
var ar = options.aspectRatio;
|
|
82
|
+
var a = [ ar[0], ar[1], ar[2] ]; // aspect multipliers
|
|
83
|
+
|
|
84
|
+
var autoScaling = options.autoScaling;
|
|
85
|
+
var autoAspect = 2.5;
|
|
86
|
+
if ( xRange > autoAspect * rxRange && autoScaling[0] ) a[0] = autoAspect * rxRange / xRange;
|
|
87
|
+
if ( yRange > autoAspect * ryRange && autoScaling[1] ) a[1] = autoAspect * ryRange / yRange;
|
|
88
|
+
if ( zRange > autoAspect * rzRange && autoScaling[2] ) a[2] = autoAspect * rzRange / zRange;
|
|
89
|
+
|
|
90
|
+
// Distance from (xMid,yMid,zMid) to any corner of the bounding box, after applying aspectRatio
|
|
91
|
+
var midToCorner = Math.sqrt( a[0]*a[0]*xRange*xRange + a[1]*a[1]*yRange*yRange + a[2]*a[2]*zRange*zRange ) / 2;
|
|
92
|
+
|
|
93
|
+
var xMid = ( b[0].x + b[1].x ) / 2;
|
|
94
|
+
var yMid = ( b[0].y + b[1].y ) / 2;
|
|
95
|
+
var zMid = ( b[0].z + b[1].z ) / 2;
|
|
96
|
+
|
|
97
|
+
var box = new THREE.Geometry();
|
|
98
|
+
box.vertices.push( new THREE.Vector3( a[0]*b[0].x, a[1]*b[0].y, a[2]*b[0].z ) );
|
|
99
|
+
box.vertices.push( new THREE.Vector3( a[0]*b[1].x, a[1]*b[1].y, a[2]*b[1].z ) );
|
|
100
|
+
var boxMesh = new THREE.Line( box );
|
|
101
|
+
var boxColor = options.theme === 'dark' ? 'white' : 'black';
|
|
102
|
+
if ( options.frame ) scene.add( new THREE.BoxHelper( boxMesh, boxColor ) );
|
|
103
|
+
|
|
104
|
+
if ( options.axesLabels ) {
|
|
105
|
+
|
|
106
|
+
var d = options.decimals; // decimals
|
|
107
|
+
var offsetRatio = 0.1;
|
|
108
|
+
var al = options.axesLabels;
|
|
109
|
+
var als = options.axesLabelsStyle || [{}, {}, {}];
|
|
110
|
+
|
|
111
|
+
var offset = offsetRatio * a[1]*( b[1].y - b[0].y );
|
|
112
|
+
var xm = xMid.toFixed(d);
|
|
113
|
+
if ( /^-0.?0*$/.test(xm) ) xm = xm.substr(1);
|
|
114
|
+
addLabel( al[0] + '=' + xm, a[0]*xMid, a[1]*b[1].y+offset, a[2]*b[0].z, als[0] );
|
|
115
|
+
addLabel( ( b[0].x ).toFixed(d), a[0]*b[0].x, a[1]*b[1].y+offset, a[2]*b[0].z, als[0] );
|
|
116
|
+
addLabel( ( b[1].x ).toFixed(d), a[0]*b[1].x, a[1]*b[1].y+offset, a[2]*b[0].z, als[0] );
|
|
117
|
+
|
|
118
|
+
var offset = offsetRatio * a[0]*( b[1].x - b[0].x );
|
|
119
|
+
var ym = yMid.toFixed(d);
|
|
120
|
+
if ( /^-0.?0*$/.test(ym) ) ym = ym.substr(1);
|
|
121
|
+
addLabel( al[1] + '=' + ym, a[0]*b[1].x+offset, a[1]*yMid, a[2]*b[0].z, als[1] );
|
|
122
|
+
addLabel( ( b[0].y ).toFixed(d), a[0]*b[1].x+offset, a[1]*b[0].y, a[2]*b[0].z, als[1] );
|
|
123
|
+
addLabel( ( b[1].y ).toFixed(d), a[0]*b[1].x+offset, a[1]*b[1].y, a[2]*b[0].z, als[1] );
|
|
124
|
+
|
|
125
|
+
var offset = offsetRatio * a[1]*( b[1].y - b[0].y );
|
|
126
|
+
var zm = zMid.toFixed(d);
|
|
127
|
+
if ( /^-0.?0*$/.test(zm) ) zm = zm.substr(1);
|
|
128
|
+
addLabel( al[2] + '=' + zm, a[0]*b[1].x, a[1]*b[0].y-offset, a[2]*zMid, als[2] );
|
|
129
|
+
addLabel( ( b[0].z ).toFixed(d), a[0]*b[1].x, a[1]*b[0].y-offset, a[2]*b[0].z, als[2] );
|
|
130
|
+
addLabel( ( b[1].z ).toFixed(d), a[0]*b[1].x, a[1]*b[0].y-offset, a[2]*b[1].z, als[2] );
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function addLabel( text, x, y, z, style ) {
|
|
135
|
+
|
|
136
|
+
var color = style.color || 'black';
|
|
137
|
+
var fontSize = style.fontSize || 14;
|
|
138
|
+
var fontFamily = style.fontFamily || 'monospace';
|
|
139
|
+
var fontStyle = style.fontStyle || 'normal';
|
|
140
|
+
var fontWeight = style.fontWeight || 'normal';
|
|
141
|
+
var opacity = style.opacity || 1;
|
|
142
|
+
|
|
143
|
+
if ( options.theme === 'dark' )
|
|
144
|
+
if ( color === 'black' || color === '#000000' )
|
|
145
|
+
color = 'white';
|
|
146
|
+
|
|
147
|
+
if ( Array.isArray( fontStyle ) ) {
|
|
148
|
+
fontFamily = fontFamily.map( function( f ) {
|
|
149
|
+
// Need to put quotes around fonts that have whitespace in their names.
|
|
150
|
+
return /\s/.test( f ) ? '"' + f + '"' : f;
|
|
151
|
+
}).join(', ');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
var canvas = document.createElement( 'canvas' );
|
|
155
|
+
var context = canvas.getContext( '2d' );
|
|
156
|
+
var pixelRatio = Math.round( window.devicePixelRatio );
|
|
157
|
+
|
|
158
|
+
// For example: italic bold 20px "Times New Roman", Georgia, serif
|
|
159
|
+
var font = [fontStyle, fontWeight, fontSize + 'px', fontFamily].join(' ');
|
|
160
|
+
|
|
161
|
+
context.font = font;
|
|
162
|
+
var width = context.measureText( text ).width;
|
|
163
|
+
var height = fontSize;
|
|
164
|
+
|
|
165
|
+
// The dimensions of the canvas's underlying image data need to be powers
|
|
166
|
+
// of two in order for the resulting texture to support mipmapping.
|
|
167
|
+
canvas.width = THREE.MathUtils.ceilPowerOfTwo( width * pixelRatio );
|
|
168
|
+
canvas.height = THREE.MathUtils.ceilPowerOfTwo( height * pixelRatio );
|
|
169
|
+
|
|
170
|
+
// Re-compute the unscaled dimensions after the power of two conversion.
|
|
171
|
+
width = canvas.width / pixelRatio;
|
|
172
|
+
height = canvas.height / pixelRatio;
|
|
173
|
+
|
|
174
|
+
canvas.style.width = width + 'px';
|
|
175
|
+
canvas.style.height = height + 'px';
|
|
176
|
+
|
|
177
|
+
context.scale( pixelRatio, pixelRatio );
|
|
178
|
+
context.fillStyle = color;
|
|
179
|
+
context.font = font; // Must be set again after measureText.
|
|
180
|
+
context.textAlign = 'center';
|
|
181
|
+
context.textBaseline = 'middle';
|
|
182
|
+
context.fillText( text, width/2, height/2 );
|
|
183
|
+
|
|
184
|
+
var texture = new THREE.Texture( canvas );
|
|
185
|
+
texture.needsUpdate = true;
|
|
186
|
+
|
|
187
|
+
var materialOptions = { map: texture, sizeAttenuation: false, depthWrite: false };
|
|
188
|
+
if ( opacity < 1 ) {
|
|
189
|
+
// Setting opacity=1 would cause the texture's alpha component to be
|
|
190
|
+
// discarded, giving the text a black background instead of the
|
|
191
|
+
// background being transparent.
|
|
192
|
+
materialOptions.opacity = opacity;
|
|
193
|
+
}
|
|
194
|
+
var sprite = new THREE.Sprite( new THREE.SpriteMaterial( materialOptions ) );
|
|
195
|
+
sprite.position.set( x, y, z );
|
|
196
|
+
|
|
197
|
+
// Scaling factor, chosen somewhat arbitrarily so that the size of the text
|
|
198
|
+
// is consistent with previously generated plots.
|
|
199
|
+
var scale = 1/625;
|
|
200
|
+
if ( options.projection === 'orthographic' ) {
|
|
201
|
+
scale = midToCorner/256; // Needs to scale along with the plot itself.
|
|
202
|
+
}
|
|
203
|
+
sprite.scale.set( scale * width, scale * height, 1 );
|
|
204
|
+
|
|
205
|
+
scene.add( sprite );
|
|
206
|
+
|
|
207
|
+
return sprite;
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if ( options.axes ) scene.add( new THREE.AxesHelper( Math.min( a[0]*b[1].x, a[1]*b[1].y, a[2]*b[1].z ) ) );
|
|
212
|
+
|
|
213
|
+
var camera = createCamera();
|
|
214
|
+
camera.up.set( 0, 0, 1 );
|
|
215
|
+
camera.position.set( a[0]*xMid, a[1]*yMid, a[2]*zMid );
|
|
216
|
+
|
|
217
|
+
// camera is positioned so that the line from the camera to the center
|
|
218
|
+
// of the bounding sphere of the objects makes an angle of 60 degrees with x-axis
|
|
219
|
+
// and an angle of 30 degrees with z-axis and the field of view of the camera looking
|
|
220
|
+
// at the center has an angle of 45 degrees.
|
|
221
|
+
const sin8 = Math.sin(Math.PI / 8);
|
|
222
|
+
const sin5 = Math.sin(Math.PI / 5);
|
|
223
|
+
const cos5 = Math.cos(Math.PI / 5);
|
|
224
|
+
const sin3 = Math.sin(Math.PI / 3);
|
|
225
|
+
const cos3 = Math.cos(Math.PI / 3);
|
|
226
|
+
var r = midToCorner / sin8;
|
|
227
|
+
var offset = new THREE.Vector3( r * sin3 * cos5, r * sin3 * sin5, r * cos3 );
|
|
228
|
+
|
|
229
|
+
if ( options.viewpoint ) {
|
|
230
|
+
|
|
231
|
+
var aa = options.viewpoint;
|
|
232
|
+
var axis = new THREE.Vector3( aa[0][0], aa[0][1], aa[0][2] ).normalize();
|
|
233
|
+
var angle = aa[1] * Math.PI / 180;
|
|
234
|
+
var q = new THREE.Quaternion().setFromAxisAngle( axis, angle ).inverse();
|
|
235
|
+
|
|
236
|
+
offset.set( 0, 0, offset.length() );
|
|
237
|
+
offset.applyQuaternion( q );
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
camera.position.add( offset );
|
|
242
|
+
|
|
243
|
+
function createCamera() {
|
|
244
|
+
|
|
245
|
+
var aspect = window.innerWidth / window.innerHeight;
|
|
246
|
+
|
|
247
|
+
// Scale the near and far clipping planes along with the overall plot size.
|
|
248
|
+
var nearClip = 0.01 * midToCorner;
|
|
249
|
+
var farClip = 100 * midToCorner;
|
|
250
|
+
|
|
251
|
+
if ( options.projection === 'orthographic' ) {
|
|
252
|
+
var camera = new THREE.OrthographicCamera( -1, 1, 1, -1, -farClip, farClip );
|
|
253
|
+
updateCameraAspect( camera, aspect );
|
|
254
|
+
return camera;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return new THREE.PerspectiveCamera( 45, aspect, nearClip, farClip );
|
|
258
|
+
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function updateCameraAspect( camera, aspect ) {
|
|
262
|
+
|
|
263
|
+
if ( camera.isPerspectiveCamera ) {
|
|
264
|
+
camera.aspect = aspect;
|
|
265
|
+
} else if ( camera.isOrthographicCamera ) {
|
|
266
|
+
// Fit the camera frustum to the bounding box's diagonal so that the entire plot fits
|
|
267
|
+
// within at the default zoom level and camera position.
|
|
268
|
+
if ( aspect > 1 ) { // Wide window
|
|
269
|
+
camera.top = midToCorner;
|
|
270
|
+
camera.right = midToCorner * aspect;
|
|
271
|
+
} else { // Tall or square window
|
|
272
|
+
camera.top = midToCorner / aspect;
|
|
273
|
+
camera.right = midToCorner;
|
|
274
|
+
}
|
|
275
|
+
camera.bottom = -camera.top;
|
|
276
|
+
camera.left = -camera.right;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
camera.updateProjectionMatrix();
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
var lights = SAGE_LIGHTS;
|
|
284
|
+
for ( var i=0 ; i < lights.length ; i++ ) {
|
|
285
|
+
var light = new THREE.DirectionalLight( lights[i].color, 1 );
|
|
286
|
+
light.position.set( a[0]*lights[i].x, a[1]*lights[i].y, a[2]*lights[i].z );
|
|
287
|
+
if ( lights[i].parent === 'camera' ) {
|
|
288
|
+
light.target.position.set( a[0]*xMid, a[1]*yMid, a[2]*zMid );
|
|
289
|
+
scene.add( light.target );
|
|
290
|
+
camera.add( light );
|
|
291
|
+
} else scene.add( light );
|
|
292
|
+
}
|
|
293
|
+
scene.add( camera );
|
|
294
|
+
|
|
295
|
+
var ambient = SAGE_AMBIENT;
|
|
296
|
+
scene.add( new THREE.AmbientLight( ambient.color, 1 ) );
|
|
297
|
+
|
|
298
|
+
var controls = new THREE.OrbitControls( camera, renderer.domElement );
|
|
299
|
+
controls.target.set( a[0]*xMid, a[1]*yMid, a[2]*zMid );
|
|
300
|
+
controls.addEventListener( 'change', function() { if ( !animate ) render(); } );
|
|
301
|
+
|
|
302
|
+
window.addEventListener( 'resize', function() {
|
|
303
|
+
|
|
304
|
+
renderer.setSize( window.innerWidth, window.innerHeight );
|
|
305
|
+
updateCameraAspect( camera, window.innerWidth / window.innerHeight );
|
|
306
|
+
if ( window.rescaleFatLines ) rescaleFatLines();
|
|
307
|
+
if ( !animate ) render();
|
|
308
|
+
|
|
309
|
+
} );
|
|
310
|
+
|
|
311
|
+
var texts = SAGE_TEXTS;
|
|
312
|
+
for ( var i=0 ; i < texts.length ; i++ ) addText( texts[i] );
|
|
313
|
+
|
|
314
|
+
function addText( json ) {
|
|
315
|
+
var sprite = addLabel( json.text, a[0]*json.x, a[1]*json.y, a[2]*json.z, json );
|
|
316
|
+
sprite.userData = json;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
var points = SAGE_POINTS;
|
|
320
|
+
for ( var i=0 ; i < points.length ; i++ ) addPoint( points[i] );
|
|
321
|
+
|
|
322
|
+
function addPoint( json ) {
|
|
323
|
+
|
|
324
|
+
var geometry = new THREE.Geometry();
|
|
325
|
+
var v = json.point;
|
|
326
|
+
geometry.vertices.push( new THREE.Vector3( a[0]*v[0], a[1]*v[1], a[2]*v[2] ) );
|
|
327
|
+
|
|
328
|
+
var canvas = document.createElement( 'canvas' );
|
|
329
|
+
canvas.width = 128;
|
|
330
|
+
canvas.height = 128;
|
|
331
|
+
|
|
332
|
+
var context = canvas.getContext( '2d' );
|
|
333
|
+
context.arc( 64, 64, 64, 0, 2 * Math.PI );
|
|
334
|
+
context.fillStyle = json.color;
|
|
335
|
+
context.fill();
|
|
336
|
+
|
|
337
|
+
var texture = new THREE.Texture( canvas );
|
|
338
|
+
texture.needsUpdate = true;
|
|
339
|
+
|
|
340
|
+
var transparent = json.opacity < 1 ? true : false;
|
|
341
|
+
var size = camera.isOrthographicCamera ? json.size : json.size/100;
|
|
342
|
+
var material = new THREE.PointsMaterial( { size: size, map: texture,
|
|
343
|
+
transparent: transparent, opacity: json.opacity,
|
|
344
|
+
alphaTest: .1 } );
|
|
345
|
+
|
|
346
|
+
var c = new THREE.Vector3();
|
|
347
|
+
geometry.computeBoundingBox();
|
|
348
|
+
geometry.boundingBox.getCenter( c );
|
|
349
|
+
geometry.translate( -c.x, -c.y, -c.z );
|
|
350
|
+
|
|
351
|
+
var mesh = new THREE.Points( geometry, material );
|
|
352
|
+
mesh.position.set( c.x, c.y, c.z );
|
|
353
|
+
mesh.userData = json;
|
|
354
|
+
scene.add( mesh );
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
var lines = SAGE_LINES;
|
|
359
|
+
for ( var i=0 ; i < lines.length ; i++ ) addLine( lines[i] );
|
|
360
|
+
|
|
361
|
+
function addLine( json ) {
|
|
362
|
+
|
|
363
|
+
var geometry = new THREE.Geometry();
|
|
364
|
+
for ( var i=0 ; i < json.points.length ; i++ ) {
|
|
365
|
+
var v = json.points[i];
|
|
366
|
+
geometry.vertices.push( new THREE.Vector3( a[0]*v[0], a[1]*v[1], a[2]*v[2] ) );
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
var c = new THREE.Vector3();
|
|
370
|
+
geometry.computeBoundingBox();
|
|
371
|
+
geometry.boundingBox.getCenter( c );
|
|
372
|
+
geometry.translate( -c.x, -c.y, -c.z );
|
|
373
|
+
|
|
374
|
+
var transparent = json.opacity < 1 ? true : false;
|
|
375
|
+
var materialOptions = { color: json.color, linewidth: json.linewidth,
|
|
376
|
+
transparent: transparent, opacity: json.opacity };
|
|
377
|
+
|
|
378
|
+
var mesh;
|
|
379
|
+
if ( json.linewidth > 1 && window.createFatLineStrip ) {
|
|
380
|
+
mesh = createFatLineStrip( geometry, materialOptions );
|
|
381
|
+
} else {
|
|
382
|
+
var material = new THREE.LineBasicMaterial( materialOptions );
|
|
383
|
+
mesh = new THREE.Line( geometry, material );
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
mesh.position.set( c.x, c.y, c.z );
|
|
387
|
+
mesh.userData = json;
|
|
388
|
+
scene.add( mesh );
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
var surfaces = SAGE_SURFACES;
|
|
393
|
+
for ( var i=0 ; i < surfaces.length ; i++ ) addSurface( surfaces[i] );
|
|
394
|
+
|
|
395
|
+
function addSurface( json ) {
|
|
396
|
+
|
|
397
|
+
var useFaceColors = 'faceColors' in json ? true : false;
|
|
398
|
+
|
|
399
|
+
var geometry = new THREE.Geometry();
|
|
400
|
+
for ( var i=0 ; i < json.vertices.length ; i++ ) {
|
|
401
|
+
var v = json.vertices[i];
|
|
402
|
+
geometry.vertices.push( new THREE.Vector3( a[0]*v.x, a[1]*v.y, a[2]*v.z ) );
|
|
403
|
+
}
|
|
404
|
+
for ( var i=0 ; i < json.faces.length ; i++ ) {
|
|
405
|
+
var f = json.faces[i];
|
|
406
|
+
for ( var j=0 ; j < f.length - 2 ; j++ ) {
|
|
407
|
+
var face = new THREE.Face3( f[0], f[j+1], f[j+2] );
|
|
408
|
+
if ( useFaceColors ) face.color.set( json.faceColors[i] );
|
|
409
|
+
geometry.faces.push( face );
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
geometry.computeVertexNormals();
|
|
413
|
+
|
|
414
|
+
var side = json.singleSide ? THREE.FrontSide : THREE.DoubleSide;
|
|
415
|
+
var transparent = json.opacity < 1 ? true : false;
|
|
416
|
+
var depthWrite = 'depthWrite' in json ? json.depthWrite : !transparent;
|
|
417
|
+
var flatShading = json.useFlatShading ? json.useFlatShading : false;
|
|
418
|
+
|
|
419
|
+
var material = new THREE.MeshPhongMaterial( { side: side,
|
|
420
|
+
color: useFaceColors ? 'white' : json.color,
|
|
421
|
+
vertexColors: useFaceColors ? THREE.FaceColors : THREE.NoColors,
|
|
422
|
+
transparent: transparent, opacity: json.opacity,
|
|
423
|
+
shininess: 20, flatShading: flatShading,
|
|
424
|
+
depthWrite: depthWrite } );
|
|
425
|
+
|
|
426
|
+
var c = new THREE.Vector3();
|
|
427
|
+
geometry.computeBoundingBox();
|
|
428
|
+
geometry.boundingBox.getCenter( c );
|
|
429
|
+
geometry.translate( -c.x, -c.y, -c.z );
|
|
430
|
+
|
|
431
|
+
var mesh = new THREE.Mesh( geometry, material );
|
|
432
|
+
mesh.position.set( c.x, c.y, c.z );
|
|
433
|
+
if ( transparent && json.renderOrder ) mesh.renderOrder = json.renderOrder;
|
|
434
|
+
mesh.userData = json;
|
|
435
|
+
scene.add( mesh );
|
|
436
|
+
|
|
437
|
+
if ( json.showMeshGrid ) addSurfaceMeshGrid( json );
|
|
438
|
+
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function addSurfaceMeshGrid( json ) {
|
|
442
|
+
|
|
443
|
+
var geometry = new THREE.Geometry();
|
|
444
|
+
|
|
445
|
+
for ( var i=0 ; i < json.faces.length ; i++ ) {
|
|
446
|
+
var f = json.faces[i];
|
|
447
|
+
for ( var j=0 ; j < f.length ; j++ ) {
|
|
448
|
+
var k = j === f.length-1 ? 0 : j+1;
|
|
449
|
+
var v1 = json.vertices[f[j]];
|
|
450
|
+
var v2 = json.vertices[f[k]];
|
|
451
|
+
// vertices in opposite directions on neighboring faces
|
|
452
|
+
var nudge = f[j] < f[k] ? .0005*zRange : -.0005*zRange;
|
|
453
|
+
geometry.vertices.push( new THREE.Vector3( a[0]*v1.x, a[1]*v1.y, a[2]*(v1.z+nudge) ) );
|
|
454
|
+
geometry.vertices.push( new THREE.Vector3( a[0]*v2.x, a[1]*v2.y, a[2]*(v2.z+nudge) ) );
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
var c = new THREE.Vector3();
|
|
459
|
+
geometry.computeBoundingBox();
|
|
460
|
+
geometry.boundingBox.getCenter( c );
|
|
461
|
+
geometry.translate( -c.x, -c.y, -c.z );
|
|
462
|
+
|
|
463
|
+
var gridColor = options.theme === 'dark' ? 'white' : 'black';
|
|
464
|
+
var linewidth = json.linewidth || 1;
|
|
465
|
+
var materialOptions = { color: gridColor, linewidth: linewidth };
|
|
466
|
+
|
|
467
|
+
var mesh;
|
|
468
|
+
if ( linewidth > 1 && window.createFatLineSegments ) {
|
|
469
|
+
mesh = createFatLineSegments( geometry, materialOptions );
|
|
470
|
+
} else {
|
|
471
|
+
var material = new THREE.LineBasicMaterial( materialOptions );
|
|
472
|
+
mesh = new THREE.LineSegments( geometry, material );
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
mesh.position.set( c.x, c.y, c.z );
|
|
476
|
+
mesh.userData = json;
|
|
477
|
+
scene.add( mesh );
|
|
478
|
+
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function render() {
|
|
482
|
+
|
|
483
|
+
if ( window.updateAnimation ) animate = updateAnimation();
|
|
484
|
+
if ( animate ) requestAnimationFrame( render );
|
|
485
|
+
|
|
486
|
+
renderer.render( scene, camera );
|
|
487
|
+
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
render();
|
|
491
|
+
controls.update();
|
|
492
|
+
if ( !animate ) render();
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
// menu functions
|
|
496
|
+
|
|
497
|
+
function toggleMenu() {
|
|
498
|
+
|
|
499
|
+
var m = document.getElementById( 'menu-content' );
|
|
500
|
+
if ( m.style.display === 'block' ) m.style.display = 'none'
|
|
501
|
+
else m.style.display = 'block';
|
|
502
|
+
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
function saveAsPNG() {
|
|
507
|
+
|
|
508
|
+
var a = document.body.appendChild( document.createElement( 'a' ) );
|
|
509
|
+
a.href = renderer.domElement.toDataURL( 'image/png' );
|
|
510
|
+
a.download = 'screenshot';
|
|
511
|
+
a.click();
|
|
512
|
+
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function saveAsHTML() {
|
|
516
|
+
|
|
517
|
+
toggleMenu(); // otherwise visible in output
|
|
518
|
+
event.stopPropagation();
|
|
519
|
+
|
|
520
|
+
var blob = new Blob( [ '<!DOCTYPE html>\n' + document.documentElement.outerHTML ] );
|
|
521
|
+
var a = document.body.appendChild( document.createElement( 'a' ) );
|
|
522
|
+
a.href = window.URL.createObjectURL( blob );
|
|
523
|
+
a.download = suggestFilename();
|
|
524
|
+
a.click();
|
|
525
|
+
|
|
526
|
+
function suggestFilename() {
|
|
527
|
+
if ( !document.title ) {
|
|
528
|
+
return 'graphic.html';
|
|
529
|
+
} else if ( /\.html?$/i.test( document.title ) ) {
|
|
530
|
+
return document.title; // already ends in .htm or .html
|
|
531
|
+
} else {
|
|
532
|
+
return document.title + '.html';
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function getViewpoint() {
|
|
539
|
+
|
|
540
|
+
function roundTo( x, n ) { return +x.toFixed(n); }
|
|
541
|
+
|
|
542
|
+
var v = camera.quaternion.inverse();
|
|
543
|
+
var r = Math.sqrt( v.x*v.x + v.y*v.y + v.z*v.z );
|
|
544
|
+
var axis = [ roundTo( v.x / r, 4 ), roundTo( v.y / r, 4 ), roundTo( v.z / r, 4 ) ];
|
|
545
|
+
var angle = roundTo( 2 * Math.atan2( r, v.w ) * 180 / Math.PI, 2 );
|
|
546
|
+
|
|
547
|
+
var textArea = document.createElement( 'textarea' );
|
|
548
|
+
textArea.textContent = JSON.stringify( axis ) + ',' + angle;
|
|
549
|
+
textArea.style.csstext = 'position: absolute; top: -100%';
|
|
550
|
+
document.body.append( textArea );
|
|
551
|
+
textArea.select();
|
|
552
|
+
document.execCommand( 'copy' );
|
|
553
|
+
|
|
554
|
+
var m = document.getElementById( 'menu-message' );
|
|
555
|
+
m.innerHTML = 'Viewpoint copied to clipboard';
|
|
556
|
+
m.style.display = 'block';
|
|
557
|
+
setTimeout( function() { m.style.display = 'none'; }, 2000 );
|
|
558
|
+
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function getCamera() {
|
|
562
|
+
|
|
563
|
+
function roundTo( x, n ) { return +x.toFixed(n); }
|
|
564
|
+
|
|
565
|
+
var pos = camera.position;
|
|
566
|
+
var pos_r = [ roundTo( pos.x, 4 ), roundTo( pos.y, 4 ), roundTo( pos.z, 4 ) ];
|
|
567
|
+
// var up = camera.up; // up is always (0,0,1)
|
|
568
|
+
var textArea = document.createElement('textarea');
|
|
569
|
+
var cam_position = JSON.stringify(pos_r);
|
|
570
|
+
textArea.textContent = ',camera_position=' + cam_position;
|
|
571
|
+
textArea.style.csstext = 'position: absolute; top: -100%';
|
|
572
|
+
document.body.append( textArea );
|
|
573
|
+
textArea.select();
|
|
574
|
+
document.execCommand( 'copy' );
|
|
575
|
+
|
|
576
|
+
var m = document.getElementById( 'menu-message' );
|
|
577
|
+
m.innerHTML = 'Camera position '+ cam_position+' copied to clipboard';
|
|
578
|
+
m.style.display = 'block';
|
|
579
|
+
setTimeout( function() { m.style.display = 'none'; }, 2000 );
|
|
580
|
+
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
</script>
|
|
584
|
+
|
|
585
|
+
<div id="menu-container" onclick="toggleMenu()">ⓘ
|
|
586
|
+
<div id="menu-message"></div>
|
|
587
|
+
<div id="menu-content">
|
|
588
|
+
<div onclick="saveAsPNG()">Save as PNG</div>
|
|
589
|
+
<div onclick="saveAsHTML()">Save as HTML</div>
|
|
590
|
+
<div onclick="getCamera()">Get camera</div>
|
|
591
|
+
<div onclick="getViewpoint()">Get viewpoint</div>
|
|
592
|
+
<div>Close Menu</div>
|
|
593
|
+
</div></div>
|
|
594
|
+
|
|
595
|
+
SAGE_EXTRA_HTML
|
|
596
|
+
</body>
|
|
597
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|