朱莉娅集查看器
Julia Set Viewer
我一直在尝试在我的站点上制作一个 julia 集查看器 http://thejamespaterson.com/scripts/julia/,但我目前无法让程序显示正确的 julia 集。例如,当使用 C 值 0+0i 进行测试时,我得到以下图像:
结果应该是一个圆圈。我不确定为什么会这样。我写了自己的复数库和绘图函数,它们贴在下面。任何帮助将不胜感激;
function complexNum(real, imaginary) {
this.real = real;
this.imaginary = imaginary;
return this;
}
function addComplex(c1, c2) {
this.real = c1.real + c2.real;
this.imaginary = c1.imaginary + c2.imaginary;
return this;
}
function multComplex(c1, c2) {
this.real = (c1.real * c2.real) - (c1.imaginary * c2.imaginary);
this.imaginary = (c1.real * c2.imaginary) + (c2.real * c1.imaginary);
return this;
}
function dispComplex(c) {
var sign = '';
if (c.imaginary >= 0) {
sign = '+';
}
return c.real + sign + c.imaginary + "i";
}
function getComplexModulus(c) {
return Math.sqrt((c.real * c.real) + (c.imaginary * c.imaginary));
}
//globals
var MAXITERATION = 100;
var BOUNDARY = 4;
var CANVASID = "juliaDraw";
var CONTEXT = document.getElementById("juliaDraw").getContext('2d');
var HEIGHT = 750;
var WIDTH = 750;
var juliaImageData = CONTEXT.createImageData(WIDTH, HEIGHT);
function readInput(inputID) {
return document.getElementById(inputID).value;
}
function drawPointOnCanvas(x, y, color) {
//console.log('drawing pixel at '+x+','+y);
CONTEXT.fillStyle = color;
CONTEXT.fillRect(x, y, 1, 1);
}
function createArray(length) {
var arr = new Array(length || 0),
i = length;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while (i--) arr[length - 1 - i] = createArray.apply(this, args);
}
return arr;
}
function doesPointEscape(c, complexNum) {
var iterations = 0;
var escaped = false;
while ((!escaped) && (iterations < MAXITERATION)) {
if (getComplexModulus(complexNum) > BOUNDARY) {
escaped = true;
}
complexNum = addComplex(multComplex(complexNum, complexNum), c);
iterations++;
}
if (escaped) {
return true;
} else {
return false;
}
}
function plotJuliaSet(canvasID, width, height, c, start, stepsize) {
var complexNumberArray = createArray(width + 1, height + 1);
var doesPointEscapeArray = createArray(width + 1, height + 1);
var real = start.real;
var imaginary = start.imaginary;
console.log('====Drawing Set====');
console.log('c = ' + dispComplex(c));
for (var x = 0; x <= width; x++) {
imaginary = start.imaginary;
for (var y = 0; y <= height; y++) {
complexNumberArray[x][y] = new complexNum(real, imaginary);
doesPointEscapeArray[x][y] = doesPointEscape(c, complexNumberArray[x][y]);
if (doesPointEscapeArray[x][y]) {
//drawPointOnCanvas(x, y,'blue');
} else {
drawPointOnCanvas(x, y, 'black');
//console.log('point '+dispComplex(complexNumberArray[x][y])+' does not escape');
}
imaginary = imaginary - stepsize;
}
real = real + stepsize;
}
//CONTEXT.putImageData(juliaImageData, 0, 0);
console.log('done');
}
function defaultDraw() {
CONTEXT.clearRect(0, 0, WIDTH, HEIGHT);
var start = new complexNum(-2, 2);
var c = new complexNum(0, 0);
plotJuliaSet(CANVASID, WIDTH, HEIGHT, c, start, 2 / 350);
}
function drawJulia() {
CONTEXT.clearRect(0, 0, WIDTH, HEIGHT);
var start = new complexNum(-2, 2);
var c = new complexNum(readInput('realValue') * 1, readInput('imagValue') * 1);
plotJuliaSet(CANVASID, WIDTH, HEIGHT, c, start, 2 / 350);
}
<!doctype html>
<html>
<head>
<title>Julia Set Viewer</title>
<style>
.desc {
float: right;
width: 300px;
}
#juliaDraw {
border: 1px dotted;
float: left;
}
</style>
</head>
<body>
<div class="desc">
<h1>Julia Set Viewer</h1>
<p>You can view Julia sets with this simple online tool. Don't know what a Julia set is? Learn about it <a href="https://www.youtube.com/watch?v=2AZYZ-L8m9Q">here.</a>
This script uses a complex number library that I built to handle the arithmetic required to process these images. The source code is hosted on my <a href="https://github.com/jamjar919">github.</a>
</p>
</div>
<canvas id="juliaDraw" width=750 height=750 onClick="defaultDraw()"></canvas>
<div class="controls">
<form>
<label>Real:
<input type="text" id="realValue" value="0">
</label>
<label>Imag:
<input type="text" id="imagValue" value="0">
</label>
<input type="button" onClick="drawJulia()">
</form>
</div>
<script src="complex.js"></script>
<script src="juliaset.js"></script>
</body>
</html>
问题源于对 Javascript 中 this
指针使用的混淆。
将 doesPointEscape() 中的 Julia 计算更改为
complexNum = new addComplex(new multComplex(complexNum, complexNum), c);
而且有效。
这将 return 来自 multComplex 的新复数,然后将其添加到 c 和 return 来自 addComplex 的新复数分配给 complexNum。
您的 multComplex 和 addComplex 函数使用 this
指针,但要使 this
指针指向您的复数之一,您必须在现有复数上调用该函数,或调用 new
创建一个新的。
或者,您可以将 multComplex() 和 addComplex() 函数重写为
function multComplex(c1, c2) {
var real = (c1.real * c2.real) - (c1.imaginary * c2.imaginary);
var imaginary = (c1.real * c2.imaginary) + (c2.real * c1.imaginary);
return new ComplexNum(real, imaginary);
}
function addComplex(c1, c2) {
var real = c1.real + c2.real;
var imaginary = c1.imaginary + c2.imaginary;
return new ComplexNum(real, imaginary);
}
那么您的 doesPointEscape() 函数应该按原样工作。
我一直在尝试在我的站点上制作一个 julia 集查看器 http://thejamespaterson.com/scripts/julia/,但我目前无法让程序显示正确的 julia 集。例如,当使用 C 值 0+0i 进行测试时,我得到以下图像:
function complexNum(real, imaginary) {
this.real = real;
this.imaginary = imaginary;
return this;
}
function addComplex(c1, c2) {
this.real = c1.real + c2.real;
this.imaginary = c1.imaginary + c2.imaginary;
return this;
}
function multComplex(c1, c2) {
this.real = (c1.real * c2.real) - (c1.imaginary * c2.imaginary);
this.imaginary = (c1.real * c2.imaginary) + (c2.real * c1.imaginary);
return this;
}
function dispComplex(c) {
var sign = '';
if (c.imaginary >= 0) {
sign = '+';
}
return c.real + sign + c.imaginary + "i";
}
function getComplexModulus(c) {
return Math.sqrt((c.real * c.real) + (c.imaginary * c.imaginary));
}
//globals
var MAXITERATION = 100;
var BOUNDARY = 4;
var CANVASID = "juliaDraw";
var CONTEXT = document.getElementById("juliaDraw").getContext('2d');
var HEIGHT = 750;
var WIDTH = 750;
var juliaImageData = CONTEXT.createImageData(WIDTH, HEIGHT);
function readInput(inputID) {
return document.getElementById(inputID).value;
}
function drawPointOnCanvas(x, y, color) {
//console.log('drawing pixel at '+x+','+y);
CONTEXT.fillStyle = color;
CONTEXT.fillRect(x, y, 1, 1);
}
function createArray(length) {
var arr = new Array(length || 0),
i = length;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while (i--) arr[length - 1 - i] = createArray.apply(this, args);
}
return arr;
}
function doesPointEscape(c, complexNum) {
var iterations = 0;
var escaped = false;
while ((!escaped) && (iterations < MAXITERATION)) {
if (getComplexModulus(complexNum) > BOUNDARY) {
escaped = true;
}
complexNum = addComplex(multComplex(complexNum, complexNum), c);
iterations++;
}
if (escaped) {
return true;
} else {
return false;
}
}
function plotJuliaSet(canvasID, width, height, c, start, stepsize) {
var complexNumberArray = createArray(width + 1, height + 1);
var doesPointEscapeArray = createArray(width + 1, height + 1);
var real = start.real;
var imaginary = start.imaginary;
console.log('====Drawing Set====');
console.log('c = ' + dispComplex(c));
for (var x = 0; x <= width; x++) {
imaginary = start.imaginary;
for (var y = 0; y <= height; y++) {
complexNumberArray[x][y] = new complexNum(real, imaginary);
doesPointEscapeArray[x][y] = doesPointEscape(c, complexNumberArray[x][y]);
if (doesPointEscapeArray[x][y]) {
//drawPointOnCanvas(x, y,'blue');
} else {
drawPointOnCanvas(x, y, 'black');
//console.log('point '+dispComplex(complexNumberArray[x][y])+' does not escape');
}
imaginary = imaginary - stepsize;
}
real = real + stepsize;
}
//CONTEXT.putImageData(juliaImageData, 0, 0);
console.log('done');
}
function defaultDraw() {
CONTEXT.clearRect(0, 0, WIDTH, HEIGHT);
var start = new complexNum(-2, 2);
var c = new complexNum(0, 0);
plotJuliaSet(CANVASID, WIDTH, HEIGHT, c, start, 2 / 350);
}
function drawJulia() {
CONTEXT.clearRect(0, 0, WIDTH, HEIGHT);
var start = new complexNum(-2, 2);
var c = new complexNum(readInput('realValue') * 1, readInput('imagValue') * 1);
plotJuliaSet(CANVASID, WIDTH, HEIGHT, c, start, 2 / 350);
}
<!doctype html>
<html>
<head>
<title>Julia Set Viewer</title>
<style>
.desc {
float: right;
width: 300px;
}
#juliaDraw {
border: 1px dotted;
float: left;
}
</style>
</head>
<body>
<div class="desc">
<h1>Julia Set Viewer</h1>
<p>You can view Julia sets with this simple online tool. Don't know what a Julia set is? Learn about it <a href="https://www.youtube.com/watch?v=2AZYZ-L8m9Q">here.</a>
This script uses a complex number library that I built to handle the arithmetic required to process these images. The source code is hosted on my <a href="https://github.com/jamjar919">github.</a>
</p>
</div>
<canvas id="juliaDraw" width=750 height=750 onClick="defaultDraw()"></canvas>
<div class="controls">
<form>
<label>Real:
<input type="text" id="realValue" value="0">
</label>
<label>Imag:
<input type="text" id="imagValue" value="0">
</label>
<input type="button" onClick="drawJulia()">
</form>
</div>
<script src="complex.js"></script>
<script src="juliaset.js"></script>
</body>
</html>
问题源于对 Javascript 中 this
指针使用的混淆。
将 doesPointEscape() 中的 Julia 计算更改为
complexNum = new addComplex(new multComplex(complexNum, complexNum), c);
而且有效。
这将 return 来自 multComplex 的新复数,然后将其添加到 c 和 return 来自 addComplex 的新复数分配给 complexNum。
您的 multComplex 和 addComplex 函数使用 this
指针,但要使 this
指针指向您的复数之一,您必须在现有复数上调用该函数,或调用 new
创建一个新的。
或者,您可以将 multComplex() 和 addComplex() 函数重写为
function multComplex(c1, c2) {
var real = (c1.real * c2.real) - (c1.imaginary * c2.imaginary);
var imaginary = (c1.real * c2.imaginary) + (c2.real * c1.imaginary);
return new ComplexNum(real, imaginary);
}
function addComplex(c1, c2) {
var real = c1.real + c2.real;
var imaginary = c1.imaginary + c2.imaginary;
return new ComplexNum(real, imaginary);
}
那么您的 doesPointEscape() 函数应该按原样工作。