jsxgraph 1.14.0 → 1.14.1

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.
Files changed (99) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/distrib/docs/3d_linspace3d.js.html +16 -10
  3. package/distrib/docs/3d_point3d.js.html +0 -5
  4. package/distrib/docs/3d_sphere3d.js.html +92 -69
  5. package/distrib/docs/3d_view3d.js.html +24 -16
  6. package/distrib/docs/Angle.html +7 -7
  7. package/distrib/docs/CircumcircleSector.html +2 -2
  8. package/distrib/docs/Conic.html +1 -1
  9. package/distrib/docs/Ellipse.html +23 -1
  10. package/distrib/docs/Hyperbola.html +24 -1
  11. package/distrib/docs/JXG.Board.infobox.html +1 -1
  12. package/distrib/docs/JXG.Board_.html +130 -130
  13. package/distrib/docs/JXG.CanvasRenderer.html +10 -10
  14. package/distrib/docs/JXG.Composition.html +3 -3
  15. package/distrib/docs/JXG.GeometryElement.html +26 -26
  16. package/distrib/docs/JXG.Math.Numerics.html +45 -47
  17. package/distrib/docs/JXG.Math.Statistics.html +14 -15
  18. package/distrib/docs/JXG.Math.Tiling.html +3 -7
  19. package/distrib/docs/JXG.Math.html +101 -83
  20. package/distrib/docs/JXG.Point3D.html +2 -2
  21. package/distrib/docs/JXG.SVGRenderer.html +12 -12
  22. package/distrib/docs/JXG.Sphere3D.html +1255 -2
  23. package/distrib/docs/JXG.View3D.html +29 -29
  24. package/distrib/docs/JXG.html +20 -20
  25. package/distrib/docs/MajorSector.html +1 -1
  26. package/distrib/docs/MinorSector.html +1 -1
  27. package/distrib/docs/NonReflexAngle.html +1 -1
  28. package/distrib/docs/Parabola.html +1 -1
  29. package/distrib/docs/Point3D.html +1 -1
  30. package/distrib/docs/ReflexAngle.html +1 -1
  31. package/distrib/docs/Sector.html +12 -12
  32. package/distrib/docs/Sphere3D.html +17 -1
  33. package/distrib/docs/View3D.html +1 -1
  34. package/distrib/docs/base_board.js.html +63 -13
  35. package/distrib/docs/base_composition.js.html +3 -3
  36. package/distrib/docs/base_constants.js.html +1 -1
  37. package/distrib/docs/base_element.js.html +2 -1
  38. package/distrib/docs/base_text.js.html +2 -2
  39. package/distrib/docs/element_conic.js.html +35 -1
  40. package/distrib/docs/element_sector.js.html +6 -3
  41. package/distrib/docs/index.html +1 -1
  42. package/distrib/docs/math_math.js.html +64 -35
  43. package/distrib/docs/math_numerics.js.html +13 -12
  44. package/distrib/docs/math_statistics.js.html +19 -19
  45. package/distrib/docs/math_tiling.js.html +6 -288
  46. package/distrib/docs/parser_jessiecode.js.html +1 -1
  47. package/distrib/docs/renderer_canvas.js.html +7 -6
  48. package/distrib/docs/renderer_svg.js.html +15 -7
  49. package/distrib/docs/scripts/jsxgraphcore.js +2 -2
  50. package/distrib/docs/styles/jsxgraph.css +1 -1
  51. package/distrib/docs/utils_type.js.html +11 -4
  52. package/distrib/geogebra.min.js +1 -1
  53. package/distrib/geonext.min.js +1 -1
  54. package/distrib/index.d.ts +11 -0
  55. package/distrib/intergeo.min.js +1 -1
  56. package/distrib/jsxgraph.css +1 -1
  57. package/distrib/jsxgraphcore.js +2 -2
  58. package/distrib/jsxgraphcore.mjs +2 -2
  59. package/distrib/jsxgraphcore.mjs.map +1 -1
  60. package/distrib/jsxgraphsrc.js +380 -496
  61. package/distrib/jsxgraphsrc.mjs +380 -496
  62. package/distrib/jsxgraphsrc.mjs.map +1 -1
  63. package/package.json +10 -12
  64. package/src/3d/linspace3d.js +16 -10
  65. package/src/3d/point3d.js +0 -5
  66. package/src/3d/sphere3d.js +92 -69
  67. package/src/3d/view3d.js +24 -16
  68. package/src/base/board.js +63 -13
  69. package/src/base/composition.js +3 -3
  70. package/src/base/constants.js +1 -1
  71. package/src/base/element.js +2 -1
  72. package/src/base/text.js +2 -2
  73. package/src/element/conic.js +35 -1
  74. package/src/element/sector.js +6 -3
  75. package/src/index.d.ts +11 -0
  76. package/src/math/math.js +64 -35
  77. package/src/math/numerics.js +13 -12
  78. package/src/math/statistics.js +19 -19
  79. package/src/math/tiling.js +6 -288
  80. package/src/parser/jessiecode.js +1 -1
  81. package/src/renderer/canvas.js +7 -6
  82. package/src/renderer/svg.js +15 -7
  83. package/src/utils/type.js +11 -4
  84. package/src/unused/bst.js +0 -475
  85. package/src/unused/heap.js +0 -135
  86. package/src/unused/locus.js +0 -162
  87. package/src/unused/server/JXG.py +0 -74
  88. package/src/unused/server/JXGServer.py +0 -94
  89. package/src/unused/server/JXGServerModule.py +0 -9
  90. package/src/unused/server/README.md +0 -63
  91. package/src/unused/server/RStats.py +0 -45
  92. package/src/unused/server/YahooFinance.py +0 -81
  93. package/src/unused/server/fft.py +0 -136
  94. package/src/unused/server/geoloci.py +0 -210
  95. package/src/unused/server/jxggroebner.py +0 -219
  96. package/src/unused/server/jxgtestplugin.py +0 -19
  97. package/src/unused/server/server.js +0 -280
  98. package/src/unused/sketch.js +0 -2895
  99. package/src/unused/symbolic.js +0 -416
@@ -1,162 +0,0 @@
1
- /*
2
- Copyright 2008-2026
3
- Matthias Ehmann,
4
- Michael Gerhaeuser,
5
- Carsten Miller,
6
- Bianca Valentin,
7
- Alfred Wassermann,
8
- Peter Wilfahrt
9
-
10
- This file is part of JSXGraph.
11
-
12
- JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
13
-
14
- You can redistribute it and/or modify it under the terms of the
15
-
16
- * GNU Lesser General Public License as published by
17
- the Free Software Foundation, either version 3 of the License, or
18
- (at your option) any later version
19
- OR
20
- * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
21
-
22
- JSXGraph is distributed in the hope that it will be useful,
23
- but WITHOUT ANY WARRANTY; without even the implied warranty of
24
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
- GNU Lesser General Public License for more details.
26
-
27
- You should have received a copy of the GNU Lesser General Public License and
28
- the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
29
- and <https://opensource.org/licenses/MIT/>.
30
- */
31
-
32
- /*global JXG: true, define: true*/
33
- /*jslint nomen: true, plusplus: true*/
34
-
35
- import JXG from "../jxg.js";
36
- import Symbolic from "../math/symbolic.js";
37
- import Type from "../utils/type.js";
38
-
39
- /**
40
- * @class The locus element is used to visualize the curve a given constraint point describes.
41
- * @pseudo
42
- * @constructor
43
- * @name Locus
44
- * @type JXG.Curve
45
- * @augments JXG.Curve
46
- * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
47
- * @param {Point} p The constructed curve is the geometric locus of the given point.
48
- *
49
- * @example
50
- * // This examples needs JXG.Server up and running, otherwise it won't work.
51
- * p1 = board.create('point', [0, 0]);
52
- * p2 = board.create('point', [6, -1]);
53
- * c1 = board.create('circle', [p1, 2]);
54
- * c2 = board.create('circle', [p2, 1.5]);
55
- * g1 = board.create('glider', [6, 3, c1]);
56
- * c3 = board.create('circle', [g1, 4]);
57
- * g2 = board.create('intersection', [c2,c3,0]);
58
- * m1 = board.create('midpoint', [g1,g2]);
59
- * loc = board.create('locus', [m1], {strokeColor: 'red'});
60
- * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
61
- * <script type="text/javascript">
62
- * (function() {
63
- * board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
64
- * p1 = board.create('point', [0, 0]);
65
- * p2 = board.create('point', [6, -1]);
66
- * c1 = board.create('circle', [p1, 2]);
67
- * c2 = board.create('circle', [p2, 1.5]);
68
- * g1 = board.create('glider', [6, 3, c1]);
69
- * c3 = board.create('circle', [g1, 4]);
70
- * g2 = board.create('intersection', [c2,c3,0]);
71
- * m1 = board.create('midpoint', [g1,g2]);
72
- * loc = board.create('locus', [m1], {strokeColor: 'red'});
73
- * })();
74
- * </script><pre>
75
- */
76
- JXG.createLocus = function (board, parents, attributes) {
77
- var c, p;
78
-
79
- if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) {
80
- p = parents[0];
81
- } else {
82
- throw new Error(
83
- "JSXGraph: Can't create locus with parent of type other than point." +
84
- "\nPossible parent types: [point]"
85
- );
86
- }
87
-
88
- c = board.create("curve", [[null], [null]], attributes);
89
- c.dontCallServer = false;
90
-
91
- c.elType = 'locus'
92
- c.setParents([p.id]);
93
-
94
- /**
95
- * Should be documented in JXG.Curve
96
- * @ignore
97
- */
98
- c.updateDataArray = function () {
99
- var spe, cb, data;
100
-
101
- if (c.board.mode > 0) {
102
- return;
103
- }
104
-
105
- spe = Symbolic.generatePolynomials(board, p, true).join("|");
106
- if (spe === c.spe) {
107
- return;
108
- }
109
-
110
- c.spe = spe;
111
-
112
- cb = function (x, y, eq, t) {
113
- c.dataX = x;
114
- c.dataY = y;
115
-
116
- /**
117
- * The implicit definition of the locus.
118
- * @memberOf Locus.prototype
119
- * @name eq
120
- * @type String
121
- */
122
- c.eq = eq;
123
-
124
- /**
125
- * The time it took to calculate the locus
126
- * @memberOf Locus.prototype
127
- * @name ctime
128
- * @type Number
129
- */
130
- c.ctime = t;
131
-
132
- // convert equation and use it to build a generatePolynomial-method
133
- c.generatePolynomial = (function (equations) {
134
- return function (point) {
135
- var i,
136
- x = "(" + point.symbolic.x + ")",
137
- y = "(" + point.symbolic.y + ")",
138
- res = [];
139
-
140
- for (i = 0; i < equations.length; i++) {
141
- res[i] = equations[i]
142
- .replace(/\*\*/g, "^")
143
- .replace(/x/g, x)
144
- .replace(/y/g, y);
145
- }
146
-
147
- return res;
148
- };
149
- })(eq);
150
- };
151
- data = Symbolic.geometricLocusByGroebnerBase(board, p, cb);
152
-
153
- cb(data.datax, data.datay, data.polynomial, data.exectime);
154
- };
155
- return c;
156
- };
157
-
158
- JXG.registerElement("locus", JXG.createLocus);
159
-
160
- // export default {
161
- // createLocus: JXG.createLocus
162
- // };
@@ -1,74 +0,0 @@
1
- import json
2
- import inspect
3
-
4
- class Request(object):
5
-
6
- def __init__(self, action, id, data):
7
- self._action = action
8
- self._id = id
9
- self._data = data
10
-
11
- def getValue(self, item, default = 'empty'):
12
- if item == 'action':
13
- return self._action
14
- elif item == 'id':
15
- return self._id
16
- else:
17
- return json.loads(self._data)[item]
18
-
19
- def getList(self, item):
20
- return self._data.getlist(item)
21
-
22
-
23
- class Response(object):
24
-
25
- def __init__(self, _id):
26
- self._id = _id
27
- self._type = 'response'
28
- self._data = {}
29
- self._fields = []
30
- self._handler = []
31
-
32
- def error(self, msg):
33
- self._type = 'error'
34
- self._message = msg
35
-
36
- def dump(self):
37
- if self._type == 'error':
38
- # drop all the data and methods, just output the error
39
- return json.dumps({ \
40
- 'type' : 'error', \
41
- 'id' : self._id, \
42
- 'message' : self._message \
43
- })
44
- else:
45
- return json.dumps({ \
46
- 'type' : 'response', \
47
- 'id' : self._id, \
48
- 'fields' : self._fields, \
49
- 'handler' : self._handler, \
50
- 'data' : self._data \
51
- })
52
-
53
- def addField(self, namespace, name, value):
54
- self._fields.append({ \
55
- 'namespace' : namespace, \
56
- 'name' : name, \
57
- 'value' : value \
58
- })
59
-
60
- def addData(self, name, value):
61
- self._data[name] = value
62
-
63
- def addHandler(self, function, callback):
64
- params = [];
65
- args = inspect.getargspec(function);
66
- for i in range(0, len(args.args)):
67
- if (args.args[i] != 'resp') and (args.args[i] != 'self'):
68
- params.append(args.args[i])
69
-
70
- self._handler.append({ \
71
- 'name' : function.__name__,\
72
- 'callback' : callback, \
73
- 'parameters' : params \
74
- })
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- # ZIP compression
4
- import zlib
5
- # Base64 en-/decoding
6
- import base64
7
- # CGI variables handling
8
- import cgi
9
-
10
- import JXG
11
- import inspect
12
-
13
-
14
- # Base plugin
15
- from JXGServerModule import JXGServerModule
16
-
17
- def print_httpheader():
18
- print("""\
19
- Content-Type: text/plain\n
20
- """)
21
-
22
-
23
- def default_action(req, resp):
24
- action = req.getvalue('action', 'empty')
25
- resp.error("action \"" + action + "\" is undefined")
26
- return resp.dump()
27
-
28
- def import_module(plugin, resp):
29
- try:
30
- __import__(plugin, None, None, [''])
31
-
32
- tp = JXGServerModule.__subclasses__()
33
- if len(tp) == 0:
34
- resp.error("error loading module \"" + plugin + "\"")
35
- return tp
36
- tp = tp[0]()
37
-
38
- if not tp.isJXGServerModule:
39
- resp.error("not a jxg server module: \"" + plugin + "\"")
40
- return tp
41
- except Exception as e:
42
- resp.error("error loading jxg server module: \"" + plugin + "\": " + e.__str__())
43
- return
44
-
45
- return tp
46
-
47
- def load_module(req, resp):
48
- plugin = req.getValue("module", 'none')
49
- tp = import_module(plugin, resp)
50
-
51
- if resp._type != 'error':
52
- tp.init(resp)
53
- return resp.dump()
54
-
55
- def exec_module(req, resp):
56
- handler = req.getValue('handler', 'none')
57
- module = req.getValue('module', 'none')
58
-
59
- m = import_module(module, resp)
60
- if resp._type == 'error':
61
- return resp.dump()
62
-
63
- method = getattr(m, handler)
64
- params = ()
65
- args = inspect.getargspec(method)
66
- for i in range(0, len(args.args)):
67
- if args.args[i] == 'self':
68
- pass
69
- elif args.args[i] == 'resp':
70
- params += (resp, )
71
- else:
72
- params += (req.getValue(args.args[i]), )
73
-
74
- method(*params)
75
-
76
- return resp.dump()
77
-
78
- # Get Data from post/get parameters
79
- form = cgi.FieldStorage();
80
-
81
- action = form.getfirst('action', 'empty')
82
- id = form.getfirst('id', 'none')
83
- data = base64.b64decode(form.getfirst('dataJSON', ''))
84
-
85
- actions_map = { \
86
- 'load': load_module, \
87
- 'exec': exec_module \
88
- }
89
- ret = actions_map.get(action, default_action)(JXG.Request(action, id, data), JXG.Response(id))
90
-
91
- print_httpheader()
92
-
93
- print(base64.b64encode(zlib.compress(ret, 9)))
94
-
@@ -1,9 +0,0 @@
1
- import JXG
2
-
3
- class JXGServerModule(object):
4
-
5
- def __init__(self):
6
- self.isJXGServerModule = True
7
-
8
- def init(self, resp):
9
- return
@@ -1,63 +0,0 @@
1
- # JSXGraph server scripts
2
-
3
- __Update 18.10.2024__
4
-
5
- Since v1.10.1 this module is retired !
6
-
7
- The server module needs a complete rewrite. The installation is error prone,
8
- since python 3.13 the module `cgi` is not longer supported.
9
- A modern implementation would use a different approach with nodejs or
10
- a comparable system for python.
11
-
12
- ## Description
13
-
14
- JSXGraph is a cross-browser library for interactive geometry, function plotting,
15
- graphs, and data visualization in a web browser. It is implemented completely in
16
- JavaScript and uses SVG and VML.
17
- Using the JSXGraph server scripts it is possible to do computations with software
18
- not running in a browser and use the results in JSXGraph, e.g. it is possible to
19
- compute the polynomial equation of the geometric locus of a point in a construction,
20
- use matplotlib to extract the points of the graph and return a list of points and
21
- plot that points in JSXGraph.
22
-
23
- Scripts available:
24
-
25
- - `jxggroebner.py`
26
-
27
- ## General configuration
28
-
29
- By default server scripts are stored in the subdirectory `server` of the JavaScript
30
- files. If you want the scripts in another place you'll have to adjust
31
- `JXG.serverBase`
32
- either directly in JSX source (loadjsxgraph[InOneFile].js) or by setting it with
33
- javascript in your page after loading JSXGraph.
34
-
35
- ## jxggroebner.py
36
-
37
- - __Required software__
38
-
39
- - CoCoA (https://cocoa.dima.unige.it/)
40
- - Python (https://python.org/)
41
- - numpy (https://numpy.scipy.org/)
42
- - matplotlib (https://matplotlib.sourceforge.net/)
43
-
44
- - __Setup__
45
-
46
- Install CoCoA so it can be started by just typing cocoa in a terminal or adjust
47
- the configuration in `jsxgroebner.py`. Install all of the python packages.
48
-
49
- Your webserver has to be configured to execute python .py scripts as cgi, e.g.
50
- for Apache you have to configure
51
-
52
- Options +ExecCGI
53
- AddHandler cgi-script .py
54
-
55
- for the directory JSXGraph server scripts are in.
56
-
57
- It is highly recommended to adjust the `os.environ['MPLCONFIGDIR']` variable in
58
- the script or setting the variable `$MPLCONFIGDIR` for the webserver environment
59
- to somewhere more persistent than '/tmp' and writable by the webserver. If you
60
- don't do this, the matplotlib configuration will be erased at times (e.g. the
61
- server gets rebooted) and every first plot after matplotlib config erasure
62
- takes much more time because of matplotlib generating a new default config in
63
- that place.
@@ -1,45 +0,0 @@
1
- from JXGServerModule import JXGServerModule
2
- from rpy import r
3
- import JXG
4
- import io, gzip
5
- import datetime, math, random
6
-
7
- class RStats(JXGServerModule):
8
-
9
- def __init__(self):
10
- JXGServerModule.__init__(self)
11
-
12
- def init(self, resp):
13
- resp.addHandler(self.mean, 'function(data) { }')
14
- resp.addHandler(self.sd, 'function(data) { }')
15
- resp.addHandler(self.median, 'function(data) { }')
16
- resp.addHandler(self.mad, 'function(data) { }')
17
- resp.addHandler(self.all, 'function(data) { }')
18
- return
19
-
20
- def mean(self, resp, x):
21
- y = r.mean(x);
22
- resp.addData('mean', y)
23
- return
24
-
25
- def sd(self, resp, x):
26
- y = r.sd(x);
27
- resp.addData('sd', y)
28
- return
29
-
30
- def median(self, resp, x):
31
- y = r.median(x);
32
- resp.addData('median', y)
33
- return
34
-
35
- def mad(self, resp, x):
36
- y = r.mad(x);
37
- resp.addData('mad', y)
38
- return
39
-
40
- def all(self, resp, x):
41
- self.mean(resp, x)
42
- self.sd(resp, x)
43
- self.median(resp, x)
44
- self.mad(resp, x)
45
- return
@@ -1,81 +0,0 @@
1
- from JXGServerModule import JXGServerModule
2
- import JXG
3
- import urllib.request, urllib.error, urllib.parse, http.client, io, gzip
4
- import datetime, math, random
5
-
6
- class YahooFinance(JXGServerModule):
7
-
8
- def __init__(self):
9
- self.djmin = 9641.01
10
- self.djmax = 9735.93
11
- self.daxmin = 5559.47
12
- self.daxmax = 5620.13
13
- JXGServerModule.__init__(self)
14
-
15
- def init(self, resp):
16
- resp.addHandler(self.getCurrentSharePrice, 'function(data) { alert(data.price); }')
17
- resp.addHandler(self.getMinMax, 'function(data) { }')
18
- resp.addHandler(self.getFakeCurrentSharePrice, 'function(data) { alert(data.price); }')
19
- resp.addHandler(self.getFakeMinMax, 'function(data) { }')
20
- return
21
-
22
- def _getData(self, share):
23
- #httplib.HTTPConnection.debuglevel = 1
24
- # todo: adjust the s parameter to input the share given with parameter share
25
- request = urllib.request.Request('http://finance.yahoo.com/d/quotes.csv?s=' + share.lower() + '&f=sl1d1t1c1ohgv&e=.csv')
26
- # accept compressed data
27
- request.add_header('Accept-encoding', 'gzip')
28
- opener = urllib.request.build_opener()
29
- f = opener.open(request)
30
-
31
- compresseddata = f.read()
32
- compressedstream = io.StringIO(compresseddata)
33
- gzipper = gzip.GzipFile(fileobj=compressedstream)
34
- try:
35
- data = gzipper.read()
36
- # if data is gzip compressed no exception is thrown
37
- except:
38
- # data is not compressed, read original response from server
39
- data = compresseddata
40
- return data
41
-
42
- def getCurrentSharePrice(self, resp, share):
43
- data = self._getData(share)
44
- datalist = data.split(',')
45
-
46
- resp.addData('price', datalist[1])
47
- return
48
-
49
- def getMinMax(self, resp, share):
50
- data = self._getData(share)
51
- datalist = data.split(',')
52
-
53
- resp.addData('max', datalist[6])
54
- resp.addData('min', datalist[7])
55
- return
56
-
57
- def getFakeCurrentSharePrice(self, resp, share):
58
- if share=='^DJI':
59
- smax = self.djmax
60
- smin = self.djmin
61
- else:
62
- smax = self.daxmax
63
- smin = self.daxmin
64
-
65
- diff = smax - smin
66
- base = smin + diff/2. * (1. + math.sin(datetime.datetime.now().second * 2*math.pi))
67
- price = base + random.uniform(-diff/60., diff/60.)
68
- resp.addData('price', price)
69
- return
70
-
71
- def getFakeMinMax(self, resp, share):
72
- if share=='^DJI':
73
- smax = self.djmax
74
- smin = self.djmin
75
- else:
76
- smax = self.daxmax
77
- smin = self.daxmin
78
-
79
- resp.addData('max', smax)
80
- resp.addData('min', smin)
81
- return
@@ -1,136 +0,0 @@
1
- from JXGServerModule import JXGServerModule
2
- import numpy
3
- import numpy.fft
4
- import wave, struct, uuid
5
- import os, subprocess
6
- import io, gzip, base64
7
- import datetime, math, random
8
-
9
- # Should be changed to something more persistent but must be writable by
10
- # the webserver (usually user www-data)
11
- #if not 'MPLCONFIGDIR' in os.environ:
12
- # os.environ['MPLCONFIGDIR'] = '/tmp/'
13
- # os.environ['MPLCONFIGDIR'] = 'C:/xampp/tmp'
14
-
15
- #import matplotlib
16
- #import matplotlib.pyplot as plt
17
-
18
- class FFT(JXGServerModule):
19
-
20
- def __init__(self):
21
- JXGServerModule.__init__(self)
22
-
23
- def init(self, resp):
24
- resp.addHandler(self.fft, 'function(data) { }')
25
- resp.addHandler(self.ifft, 'function(data) { }')
26
- resp.addHandler(self.cutoutrange, 'function(data) { }')
27
- resp.addHandler(self.makeAudio, 'function(data) { }')
28
- resp.addHandler(self.loadAudio, 'function(data) { }')
29
- resp.addHandler(self.sampleifft, 'function(data) { }')
30
- return
31
-
32
- def fft(self, resp, x):
33
- y = numpy.fft.rfft(x)
34
- y = list(map(abs, y));
35
- resp.addData('y', y)
36
- return
37
-
38
- def _real(self, val):
39
- return val.real
40
-
41
- def ifft(self, resp, x):
42
- y = numpy.fft.irfft(x)
43
- y = list(map(self._real, y));
44
- resp.addData('y', y)
45
- return
46
-
47
- def _set0(val):
48
- return 0
49
-
50
- def sampleifft(self, resp, name, s, e, factor):
51
- # read wav
52
- pathtowavefiles = '/share8/home/michael/www-store/audio/'
53
- fname = pathtowavefiles + os.path.basename(name) + '.wav'
54
- w = wave.open(fname, 'r')
55
- (nchannels, sampwidth, framerate, nframes, comptype, compname) = w.getparams()
56
- frames = w.readframes(nframes*nchannels)
57
- out = [value/8192. for value in struct.unpack_from("%dh" % nframes * nchannels, frames)]
58
- w.close()
59
- # apply fft
60
- x = numpy.fft.rfft(out)
61
- # filters
62
- l = len(x)
63
- for i in range(0, s):
64
- x[i] = x[i] * factor
65
- for i in range(e, l):
66
- x[i] = x[i] * factor
67
- #ifft
68
- y = numpy.fft.irfft(x)
69
- y = list(map(self._real, y));
70
- resp.addData('y', y)
71
- self.makeAudio(resp, 'ogg', framerate, y)
72
- return
73
-
74
- # s: 0 < Start < len(x)/2
75
- # e: 0 < End < len(x)/2
76
- def cutoutrange(self, resp, x, s, e, factor):
77
- l = len(x)
78
- for i in range(0, s):
79
- x[i] = x[i] * factor
80
- for i in range(e, l):
81
- x[i] = x[i] * factor
82
- resp.addData('y', x)
83
- return
84
-
85
- def loadAudio(self, resp, type, name):
86
- pathtowavefiles = '/share8/home/michael/www-store/audio/'
87
- fname = pathtowavefiles + os.path.basename(name) + '.wav'
88
- fogg = pathtowavefiles + os.path.basename(name) + '.ogg'
89
- # read ogg
90
- f = open(fogg, 'r')
91
- audio = f.read()
92
- audio = "data:audio/ogg;base64," + base64.b64encode(audio)
93
- resp.addData('audioB64', audio)
94
- # read wav
95
- w = wave.open(fname, 'r')
96
- (nchannels, sampwidth, framerate, nframes, comptype, compname) = w.getparams()
97
- frames = w.readframes(nframes*nchannels)
98
- out = [value/8192. for value in struct.unpack_from("%dh" % nframes * nchannels, frames)]
99
- w.close()
100
- step = math.floor(len(out)/7500);
101
- #resp.addData('audioData', [out[i] for i in range(len(out)) if i % step == 0]);
102
- resp.addData('audioData', out);
103
- resp.addData('seconds', (nframes*1.0)/framerate)
104
- resp.addData('samplerate', framerate)
105
- return
106
-
107
- def makeAudio(self, resp, type, samplerate, data):
108
- fname = '/tmp/'+str(uuid.uuid4())
109
- fogg = fname + '.ogg'
110
- # Validate that the generated paths are confined to the expected
111
- # temp directory before they are passed to the external oggenc
112
- # binary, guarding against path/argument manipulation.
113
- tmp_dir = os.path.abspath('/tmp') + os.sep
114
- if not os.path.abspath(fname).startswith(tmp_dir) or not os.path.abspath(fogg).startswith(tmp_dir):
115
- raise ValueError('Invalid audio file path')
116
- w = wave.open(fname, 'w')
117
- w.setnchannels(1)
118
- w.setsampwidth(2)
119
- w.setframerate(samplerate)
120
- w.setnframes(len(data))
121
- for s in data:
122
- if s < -4:
123
- s = -4
124
- if s > 4:
125
- s = 4
126
- w.writeframes(struct.pack('h', int(s*4000)))
127
- w.close()
128
- ogg_process = subprocess.Popen(["oggenc", fname, "-Q", "-o", fogg], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
129
- output = ogg_process.communicate('')[0]
130
- f = open(fogg, 'r')
131
- audio = f.read()
132
- audio = "data:audio/ogg;base64," + base64.b64encode(audio)
133
- resp.addData('audioB64', audio)
134
- os.remove(fname)
135
- os.remove(fogg)
136
- return