Polygon Collision Javascript - javascript

The collision Function doesn't work, i don't know why...
Every other function should work, the drawing on the canvas has been tested.
It returns 0 but in this example the two polygons collide.
If you need more Details write it in the comments...
<script type='text/javascript'>
var canvas = document.getElementById("c");
var ctx = canvas.getContext('2d');
var coordinates = new Array();
var newCoordinate = new Array("4/2", "20/80", "50/30", "40/8");
coordinates.push(newCoordinate);
var newCoordinate = new Array("30/50", "60/80", "90/30", "70/8");
coordinates.push(newCoordinate);
drawPolygonFromArray(coordinates[0], ctx, '#f00');
drawBoundingFromArray(coordinates[0], ctx, 'rgba(255,0,0,0.5)');
drawPolygonFromArray(coordinates[1], ctx, '#0f0');
drawBoundingFromArray(coordinates[1], ctx, 'rgba(0,255,0,0.5)');
function drawPolygonFromArray(coordinates, c, color) {
if (color == undefined) color = '#f00';
c.fillStyle = color;
c.beginPath();
var splitted = coordinates[0].split("/");
c.moveTo(parseInt(splitted[0]), parseInt(splitted[1]));
for (var i = 1; i < coordinates.length; i++) {
var splitted = coordinates[i].split("/");
c.lineTo(parseInt(splitted[0]), parseInt(splitted[1]));
}
var splitted = coordinates[0].split("/");
c.lineTo(parseInt(splitted[0]), parseInt(splitted[1]));
c.closePath();
c.fill();
}
function drawBoundingFromArray(coordinates, c, color) {
if (color == undefined) color = '#f00';
c.fillStyle = color;
c.beginPath();
var splitted = getTopLeftCoordinate(coordinates).split("/");
ctx.rect(parseInt(splitted[0]), parseInt(splitted[1]), getWidthOfPolygon(coordinates), getHeightOfPolygon(coordinates));
c.closePath();
c.fill();
}
function getWidthOfPolygon(pCoordinates, minX) {
if(minX == undefined) var minX = 999999999999;
maxX = -1;
for (var i = 0; i < pCoordinates.length; i++) {
var splitted = pCoordinates[i].split("/");
if (parseInt(splitted[0]) < minX) minX = parseInt(splitted[0]);
if (parseInt(splitted[0]) > maxX) maxX = parseInt(splitted[0]);
}
return maxX - minX;
}
function getHeightOfPolygon(pCoordinates, minY) {
if(minY == undefined) var minY = 999999999999;
maxY = -1;
for (var i = 0; i < pCoordinates.length; i++) {
var splitted = pCoordinates[i].split("/");
if (parseInt(splitted[1]) < minY) minY = parseInt(splitted[1]);
if (parseInt(splitted[1]) > maxY) maxY = parseInt(splitted[1]);
}
return maxY - minY;
}
function getTopLeftCoordinate(pCoordinates) { // returns "x/y"
minX = 999999999999;
minY = 999999999999;
for (var i = 0; i < pCoordinates.length; i++) {
var splitted = pCoordinates[i].split("/");
if (parseInt(splitted[0]) < minX) minX = parseInt(parseInt(splitted[0]));
if (parseInt(splitted[1]) < minY) minY = parseInt(parseInt(splitted[1]));
}
return minX + "/" + minY;
}
function getAllCoordinates(pCoordinates) { // returns "x/y"
coordinates = new Array();
for (var i = 0; i < pCoordinates.length; i++) {
var splitted = pCoordinates[i].split("/");
coordinates.push(splitted[0]+"/"+splitted[1]);
}
return coordinates;
}
function collision(p1, p2) {
//bounding boxes
var splitted = getTopLeftCoordinate(p1).split("/");
var x1 = parseInt(splitted[0]); var y1 = parseInt(splitted[1]); var w1 = getWidthOfPolygon(p1);
var h1 = getHeightOfPolygon(p1);
splitted = getTopLeftCoordinate(p2).split("/");
var x2 = parseInt(splitted[0]); var y2 = parseInt(splitted[1]); var w2 = getWidthOfPolygon(p1);
var h2 = getHeightOfPolygon(p2);
var coo1 = getAllCoordinates(p1);
var coo2 = getAllCoordinates(p2);
for(var a = 0; a<p1.length; a++) {
var splitted = coo1[a].split("/");
var x = parseInt (splitted[0]);
var w = parseInt(getWidthOfPolygon(p1, x));
var y = parseInt (splitted[1]);
var h = parseInt (getHeightOfPolygon(p1, y));
for(var b = 0; b<p2.length; b++) {
var splitted2 = coo2[b].split("/");
var x1 = parseInt(splitted2[0]);
var w1 = parseInt (getWidthOfPolygon(p2, x1));
var y1 = parseInt(splitted2[1]);
var h1 = parseInt (getHeightOfPolygon(p2, y1));
alert(a + " " + x + " " + x1 + " " +y + " " + y1 + " " + h + " " + w + " " + (x1 + w));
if (x >=x1 && x<= x1+w && y>=y1 && y<=y1+h) return 1;
}
}
return 0;
}
alert(collision(coordinates[0],coordinates[1]));

It works now:
JSFiddle: http://jsfiddle.net/sh3rlock/2LfUA/
var canvas = document.getElementById("c");
var ctx = canvas.getContext('2d');
var coordinates = new Array();
var coordinates = [
[
[4, 2],
[20, 80],
[50, 30],
[40, 8]
],
[
[50, 20],
[60, 80],
[90, 31],
[70, 50]
]
];
drawPolygonFromArray(coordinates[0], ctx, '#f00');
drawBoundingFromArray(coordinates[0], ctx, 'rgba(255,0,0,0.5)');
drawPolygonFromArray(coordinates[1], ctx, '#0f0');
drawBoundingFromArray(coordinates[1], ctx, 'rgba(0,255,0,0.5)');
function drawPolygonFromArray(coordinates, c, color) {
if (typeof color === "undefined") color = '#f00';
c.fillStyle = color;
c.beginPath();
c.moveTo(coordinates[0][0], coordinates[0][1]);
for (var i = 1; i < coordinates.length; i++) {
c.lineTo(coordinates[i][0], coordinates[i][1]);
}
c.lineTo(coordinates[0][0], coordinates[0][1]);
c.closePath();
c.fill();
}
function drawBoundingFromArray(coordinates, c, color) {
if (typeof color === "undefined") color = '#f00';
c.fillStyle = color;
c.beginPath();
var topleft = getTopLeftCoordinate(coordinates);
ctx.rect(topleft[0], topleft[1], getWidthOfPolygon(coordinates), getHeightOfPolygon(coordinates));
c.closePath();
c.fill();
}
function getAllCoordinates(pCoordinates) { // returns "x/y"
coordinates = new Array();
for (var i = 0; i < pCoordinates.length; i++) {
var coords = pCoordinates[i];
coordinates.push([coords[0], coords[1]]);
}
return coordinates;
}
function linehits(p1, p2, p3) {
var x1 = p1[0];
var y1 = p1[1];
var x2 = p2[0];
var y2 = p2[1];
var a = (-(y1 - y2)) / (x2 - x1); // A von der Gerade P1-P2
var c = (x2 * y1 - x1 * y2) / (x2 - x1); // C von der Gerade P1-P2
if (typeof p4 === "undefined") {
//alert();
var a2 = 0;
var c2 = p3[1]; // y-Punkt des P3
var xS = (c2 - c) / a; // X-Schnittpunkt
var yS = a * xS + c; // Y-SchnittPunkt
if (((xS < p2[0] && xS > p1[0]) || (xS > p2[0] && xS < p1[0])) && xS < p3[0] && (yS < p2[1] || yS < p1[1])) return [xS, yS];
} else {
x1 = p3[0];
y1 = p3[1];
x2 = p4[0];
y2 = p4[1];
var a2 = (-(y1 - y2)) / (x2 - x1); // A von der Gerade P1-P2
var c2 = (x2 * y1 - x1 * y2) / (x2 - x1); // C von der Gerade P1-P2
var xS = (c2 - c) / (a - a2); // X-Schnittpunkt
var yS = a * xS + c; // Y-SchnittPunkt
if (((xS < p2[0] && xS > p1[0]) || (xS > p2[0] && xS < p1[0])) && xS < p3[0] && (yS < p2[1] || yS < p1[1])) return [xS, yS];
}
return 888;
}
function drawALine(p1, p2, c) {
c.beginPath();
c.moveTo(p1[0], p1[1]);
for (var i = 1; i < coordinates.length; i++) {
c.lineTo(p2[0], p2[1]);
}
c.stroke();
c.closePath();
}
function pgIntersectsPg(p1, p2) { // p1 means Array with points [[0,6],[20,90],...,[10,8]]
for (a = 0; a < p1.length; a++) {
var point3 = p1[a];
var hits = 0;
for (b = 0; b < p2.length; b++) {
var point1 = p2[b];
var point2 = 0.0;
if (b < p2.length - 1) {
point2 = p2[b + 1];
} else {
point2 = p2[0];
}
if (linehits(point1, point2, point3).length == 2) {
hits++;
}
//alert(linehits(point1,point2,point3));
}
if (hits % 2 > 0) return 1;
}
for (a = 0; a < p2.length; a++) {
var point3 = p2[a];
//alert(hits);
var hits = 0;
for (b = 0; b < p1.length; b++) {
var point1 = p1[b];
var point2 = 0.0;
if (b < p1.length - 1) {
point2 = p1[b + 1];
} else {
point2 = p1[0];
}
if (linehits(point1, point2, point3).length == 2) {
hits++;
drawALine(point1, point2, ctx)
//alert([0,point3[1]] + " " +point3);
//drawALine([0,point3[1]],point3);
}
//alert(linehits(point1,point2,point3));
}
drawALine([0, point3[1]], point3, ctx);
if (hits % 2 > 0) return 1;
}
return 0;
}
alert("Test: " + pgIntersectsPg(coordinates[0], coordinates[1]));

Related

Problems with translating c++ to javascript

I was trying to replicate this c++ code in javascript.
https://github.com/OneLoneCoder/videos/blob/master/OneLoneCoder_PathFinding_AStar.cpp
The code should draw a yellow line from the red point to the green point.
I checked my implementation multiple times but I still can't figure out why it is not working.
For some reason it won't set the parent for my objects correctly.
Which results in the path not getting drawn.
Could really need some help here.
width = 11;
height = 9;
s = 50;
c = document.createElement("canvas");
document.body.appendChild(c);
ctx = c.getContext("2d");
c.width = width * s;
c.height = height * s;
nodes = [];
for (x = 0; x < width; x++) {
row = [];
nodes.push(row);
for (y = 0; y < height; y++) {
row.push(new Node(x, y));
}
}
SetNeighbours();
function SetNeighbours() {
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
if (x > 0) {
nodes[x][y].neighbours.push(nodes[x - 1][y])
}
if (x < width - 1) {
nodes[x][y].neighbours.push(nodes[x + 1][y])
}
if (y > 0) {
nodes[x][y].neighbours.push(nodes[x][y - 1])
}
if (y < height - 1) {
nodes[x][y].neighbours.push(nodes[x][y + 1])
}
}
}
}
nodes[3][0].obstacle = true;
nodes[3][1].obstacle = true;
nodes[3][2].obstacle = true;
nodes[3][3].obstacle = true;
nodes[3][4].obstacle = true;
nodes[3][5].obstacle = true;
nodes[7][3].obstacle = true;
nodes[7][4].obstacle = true;
nodes[7][5].obstacle = true;
nodes[7][6].obstacle = true;
nodes[7][7].obstacle = true;
nodes[7][8].obstacle = true;
start = nodes[1][1];
end = nodes[9][7];
//end.parent = nodes[9][6];
//nodes[9][6].parent = nodes[9][5]
current = start;
start.localGlobal = 0;
start.globalGoal = heuristic(start, end);
notTested = [];
notTested.push(start);
while (notTested.length > 0 && current != end) {
notTested.sort(function(a, b) {
return a.globalGoal < b.globalGoal
});
while (notTested.length > 0 && notTested[0].visited) {
notTested.shift();
}
if (notTested.length == 0) {
break;
}
current = notTested[0];
current.visited = true;
for (let n of current.neighbours) {
if (!n.visited && !n.obstacle) {
notTested.push(n);
}
newGoal = current.localGoal + distance(current, n);
if (newGoal < n.localGoal) {
n.parent = current;
n.localGoal = newGoal;
n.globalGoal = n.localGoal + heurisitc(n, end);
}
}
}
DrawCanvas();
function DrawCanvas() {
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
for (let node of nodes[x][y].neighbours) {
ctx.beginPath();
ctx.moveTo(x * s + (s / 2), y * s + (s / 2));
ctx.lineTo(node.x * s + (s / 2), node.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "navy";
ctx.stroke();
}
}
}
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
if (nodes[x][y] == start) {
ctx.fillStyle = "crimson";
} else if (nodes[x][y] == end) {
ctx.fillStyle = "green";
} else if (nodes[x][y].visited) {
ctx.fillStyle = "blue";
} else if (nodes[x][y].obstacle) {
ctx.fillStyle = "grey";
} else {
//ctx.fillStyle = x % 2 != y % 2 ? "lightgrey" : "darkgrey";
ctx.fillStyle = "navy";
}
ctx.fillRect(x * s + 5, y * s + 5, s - 10, s - 10);
}
}
}
if (end != null) {
p = end;
while (p.parent != null) {
ctx.beginPath();
ctx.moveTo(p.x * s + (s / 2), p.y * s + (s / 2));
ctx.lineTo(p.parent.x * s + (s / 2), p.parent.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
p = p.parent;
}
}
function Node(x, y) {
this.obstacle = false;
this.visited = false;
this.globalGoal = 1000000;
this.localGoal = 1000000;
this.x = x;
this.y = y;
this.neighbours = [];
this.parent = null;
}
function distance(a, b) {
return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2)
}
function heuristic(a, b) {
return distance(a, b);
}
body
{
background: black;
}
In line where you set current variable you have a typo
There should be start.localGoal = 0; and not start.localGlobal = 0;
width = 11;
height = 9;
s = 50;
c = document.createElement("canvas");
document.body.appendChild(c);
ctx = c.getContext("2d");
c.width = width * s;
c.height = height * s;
nodes = [];
for (let x = 0; x < width; x++) {
nodes[x] = [];
for (let y = 0; y < height; y++) {
nodes[x].push(new Node(x, y));
}
}
SetNeighbours();
function SetNeighbours() {
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
if (x > 0) {
nodes[x][y].neighbours.push(nodes[x - 1][y])
}
if (x < width - 1) {
nodes[x][y].neighbours.push(nodes[x + 1][y])
}
if (y > 0) {
nodes[x][y].neighbours.push(nodes[x][y - 1])
}
if (y < height - 1) {
nodes[x][y].neighbours.push(nodes[x][y + 1])
}
}
}
}
nodes[3][0].obstacle = true;
nodes[3][1].obstacle = true;
nodes[3][2].obstacle = true;
nodes[3][3].obstacle = true;
nodes[3][4].obstacle = true;
nodes[3][5].obstacle = true;
nodes[7][3].obstacle = true;
nodes[7][4].obstacle = true;
nodes[7][5].obstacle = true;
nodes[7][6].obstacle = true;
nodes[7][7].obstacle = true;
nodes[7][8].obstacle = true;
start = nodes[1][1];
end = nodes[9][7];
//end.parent = nodes[9][6];
//nodes[9][6].parent = nodes[9][5]
start.localGoal = 0;
start.globalGoal = heuristic(start, end);
current = start;
notTested = [];
notTested.push(start);
while (notTested.length > 0 && current !== end) {
notTested.sort(function (a, b) {
return a.globalGoal < b.globalGoal
});
while (notTested.length > 0 && notTested[0].visited) {
notTested.shift();
}
if (notTested.length === 0) {
break;
}
const current = notTested[0];
current.visited = true;
for (let n of current.neighbours) {
if (!n.visited && !n.obstacle) {
notTested.push(n);
}
const newGoal = current.localGoal + distance(current, n);
if (newGoal < n.localGoal) {
n.parent = current;
n.localGoal = newGoal;
n.globalGoal = n.localGoal + heuristic(n, end);
}
}
}
DrawCanvas();
function DrawCanvas() {
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
for (let node of nodes[x][y].neighbours) {
ctx.beginPath();
ctx.moveTo(x * s + (s / 2), y * s + (s / 2));
ctx.lineTo(node.x * s + (s / 2), node.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "navy";
ctx.stroke();
}
}
}
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
if (nodes[x][y] === start) {
ctx.fillStyle = "crimson";
} else if (nodes[x][y] === end) {
ctx.fillStyle = "green";
} else if (nodes[x][y].visited) {
ctx.fillStyle = "blue";
} else if (nodes[x][y].obstacle) {
ctx.fillStyle = "grey";
} else {
//ctx.fillStyle = x % 2 != y % 2 ? "lightgrey" : "darkgrey";
ctx.fillStyle = "navy";
}
ctx.fillRect(x * s + 5, y * s + 5, s - 10, s - 10);
}
}
}
if (end != null) {
p = end;
while (p.parent != null) {
ctx.beginPath();
ctx.moveTo(p.x * s + (s / 2), p.y * s + (s / 2));
ctx.lineTo(p.parent.x * s + (s / 2), p.parent.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
p = p.parent;
}
}
function Node(x, y) {
this.obstacle = false;
this.visited = false;
this.globalGoal = 1000000;
this.localGoal = 1000000;
this.x = x;
this.y = y;
this.neighbours = [];
this.parent = null;
}
function distance(a, b) {
return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
}
function heuristic(a, b) {
return distance(a, b);
}
body
{
background: black;
}

Why does it undefined when it should have defined it?

After the maze is generated, if you move your player around a bit, soon it'll say "No cell found", which happens whenever the cell is undefined. I don't know why the cell is not in the check array. I really don't know what to do to fix this, or why it's not being added to the array. Also sometimes you can't move a certain direction your supposed to move, and you can move through walls. I think this is because some cells are added twice. My full program is underneath.
var cols, rows;
var diffeculty = 0;
var w = 50;
var grid = [];
var stack = [];
var current;
var check = []
var k = 0;
var m = 0;
var won = false;
function setup() {
//frameRate(10)
createCanvas(600, 400);
cols = floor(width / w)
rows = floor(height / w)
for (var j = 0; j < rows; j++) {
for (var i = 0; i < cols; i++) {
var cell = new Cell(i, j)
grid.push(cell)
}
}
current = grid[0];
}
function index(i, j) {
if (i < 0 || j < 0 || i > cols - 1 || j > cols - 1) {
return -1;
}
return i + j * cols
}
function Cell(i, j) {
this.visited = false;
this.i = i;
this.j = j;
this.walls = [true, true, true, true];
this.checkNeighbors = function() {
var neighbors = []
var top = grid[index(i, j - 1)]
var right = grid[index(i + 1, j)]
var left = grid[index(i - 1, j)]
var bottom = grid[index(i, j + 1)]
var Wall = this.walls;
var wall=[]
wall.push(i,j,Wall)
if (top && !top.visited) {
neighbors.push(top);
}
if (right && !right.visited) {
neighbors.push(right);
}
if (bottom && !bottom.visited) {
neighbors.push(bottom);
}
if (left && !left.visited) {
neighbors.push(left);
}
if (neighbors.length > 0) {
var r = floor(random(0, neighbors.length))
return neighbors[r];
} else {
return undefined;
}
}
this.highlight = function() {
var x = this.i * w;
var y = this.j * w;
noStroke();
fill(0, 0, 255, 100)
rect(x, y, w, w);
}
this.show = function() {
var x = this.i * w;
var y = this.j * w;
stroke(255);
noFill();
if (this.walls[0]) {
line(x, y, x + w, y);
}
if (this.walls[1]) {
line(x + w, y, x + w, y + w);
}
if (this.walls[2]) {
line(x + w, y + w, x, y + w);
}
if (this.walls[3]) {
line(x, y + w, x, y);
}
if (this.visited) {
fill(255, 0, 255, 100);
noStroke();
rect(x, y, w, w);
}
}
};
function removeWalls(a, b) {
var x = a.i - b.i;
if (x === 1) {
a.walls[3] = false;
b.walls[1] = false;
} else if (x === -1) {
a.walls[1] = false;
b.walls[3] = false;
}
var y = a.j - b.j;
if (y === 1) {
a.walls[0] = false;
b.walls[2] = false;
} else if (y === -1) {
a.walls[2] = false;
b.walls[0] = false;
}
}
function draw() {
background(51);
for (var i = 0; i < grid.length; i++) {
grid[i].show()
}
//Step One
current.visited = true;
current.highlight();
var next = current.checkNeighbors()
if (next) {
next.visited = true;
//Step 2
stack.push(current);
check.push(current)
//Step 3
removeWalls(current, next)
{}
//Step 4
current = next;
} else if (stack.length > 0) {
current = stack.pop();
}
if (stack[0] === undefined) {
fill(0, 105, 100)
rect(0, 0, w, w)
rect(width - w, height - w, w, w)
frameRate(8)
var c = check.find(cell => cell.i == ~~(k/w) && cell.j == ~~(m/w));
if(c===undefined){
console.log('no cell found');
}else{
console.log('i',c.i,'j', c.j,'walls', c.walls);
}
if(keyIsDown(UP_ARROW)&&!c.walls[0]) {
k -= w
}
if (keyIsDown(RIGHT_ARROW)&&!c.walls[1]) {
m += w
}
if (keyIsDown(DOWN_ARROW)&&!c.walls[2]) {
k += w
}
if (keyIsDown(LEFT_ARROW)&&!c.walls[3]) {
m -= w
}
fill(0, 255, 255, 100)
rect(m, k, w, w)
if (m < 0) {
m = 0
}
if (k < 0) {
k = 0
}
if (m > width - w) {
m = width - w
}
if (k > height - w) {
k = height - w
}
if (k === height - w && m === width - w || won === true) {
won = true
background(0)
textSize(40)
text("You Win", width / 2, height / 2)
}
}
}
I can spot a couple of problems with function index(i, j):
if i is cols and j is rows, then if you if statement, you should check i > rows - 1 instead of i > cols - 1
you probably want to return cols-1 instead of cols:
return i + j * cols-1;

Javascript canvas color not smooth change in brightness

Full demo of what I'm talking about is here:
https://ggodfrey.github.io/ComplexColor/index.html
I'm trying to make a website that can attempt to plot a complex-valued function using color. The hue is determined using the angle of the complex answer, and the brightness is determined by taking the log of the magnitude of the complex answer and then finding the fractional part. From there, I use a function to convert HSL to RGB, then putting that into an Image object that I draw onto the canvas, allowing me to draw on each pixel.
As seen on the page above, the brightness "levels" have "rough" edges between where the logarithm changes from one integer to another. It should look something more like this. Is this issue having to do with how I actually calculate the brightness or using the javascript canvas?
window.onload = function(){
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im){
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other){
return new Complex(this.re+other.re, this.im+other.im);
}
Complex.prototype.multiply = function(other){
return new Complex(this.re*other.re-other.im*this.im, this.re*other.im+this.im*other.re);
}
Complex.prototype.power = function(num){
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num)*Math.cos(num*theta);
var b = Math.pow(r, num)*Math.sin(num*theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function(){
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function(){
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other){
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re/y.re, x.im/y.re);
return x;
}
function hslToRgb(h, s, l){ //NOT MY CODE
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j){
var z = new Complex(x_min+j*(x_max-x_min)/canvas.width, y_min+i*(y_max-y_min)/canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle()/(2*Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness)/Math.log(2) % 1;
return [color, brightness];
}
function main(){
var data = image.data;
if(EQUATION !== null){
var count = 0;
for(var i=0;i<canvas.height;i++){
for(var j=0;j<canvas.width;j++){
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 1, 0.4+c[1]/5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count*4;
data[c] = r;
data[c+1] = g;
data[c+2] = b;
data[c+3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return {x: (evt.clientX-rect.left)/(rect.right-rect.left)*canvas.width,
y: (evt.clientY-rect.top)/(rect.bottom-rect.top)*canvas.height};
}
document.getElementById("submit").addEventListener("mousedown", function(event){
EQUATION = document.getElementById("equation").innerHTML;
var x = main();
})
document.getElementById("canvas").addEventListener("mousemove", function(event){
var loc = getMousePos(canvas, event);
document.getElementById('x').innerHTML = Math.round(loc.x*100)/100;
document.getElementById('y').innerHTML = Math.round(loc.y*100)/100;
document.getElementById('brightness').innerHTML = evaluate(loc.y, loc.x)[1];
})
}
<head>
<title>Complex Color</title>
<meta charset="utf-8"></head>
<body>
<input id="equation" type="text">Type Equation</input><button id="submit">Submit</button><br>
<canvas id="canvas" style="width:500px;height:500px"></canvas><p> <span id="x"></span>, <span id="y"></span>, <span id="brightness"></span></p>
</body>
Assuming the formulas are correct:
Increase the bitmap resolution of the canvas and use a smaller CSS size to introduce smoothing - or - implement a manual anti-aliasing. This is because you write on a pixel by pixel basis which bypasses anti-aliasing.
Decrease saturation to about 80%: rgb = hslToRgb(c[0], 0.8, 0.4 + c[1] / 5);. 100% will typically produce an over-saturated looking image on screen. For print though use 100%.
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im) {
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other) {
return new Complex(this.re + other.re, this.im + other.im);
}
Complex.prototype.multiply = function(other) {
return new Complex(this.re * other.re - other.im * this.im, this.re * other.im + this.im * other.re);
}
Complex.prototype.power = function(num) {
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num) * Math.cos(num * theta);
var b = Math.pow(r, num) * Math.sin(num * theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function() {
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function() {
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other) {
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re / y.re, x.im / y.re);
return x;
}
function hslToRgb(h, s, l) { //NOT MY CODE
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j) {
var z = new Complex(x_min + j * (x_max - x_min) / canvas.width, y_min + i * (y_max - y_min) / canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle() / (2 * Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness) / Math.log(2) % 1;
return [color, brightness];
}
function main() {
var data = image.data;
if (EQUATION !== null) {
var count = 0;
for (var i = 0; i < canvas.height; i++) {
for (var j = 0; j < canvas.width; j++) {
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 0.8, 0.4 + c[1] / 5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count * 4;
data[c] = r;
data[c + 1] = g;
data[c + 2] = b;
data[c + 3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
#canvas {width:500px;height:500px}
<canvas id="canvas" width=1000 height=1000></canvas>
CSS' width and height are not the same as the attributes of a canvas element of the same name - They just stretch the canvas to the given size (also see this answer). Therefore canvas.width === 300 and canvas.height === 150, the default values. This low resolution creates your immediate problem. Here is your identical code and just the canvas' attributes set properly instead of using incorrect css:
window.onload = function(){
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im){
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other){
return new Complex(this.re+other.re, this.im+other.im);
}
Complex.prototype.multiply = function(other){
return new Complex(this.re*other.re-other.im*this.im, this.re*other.im+this.im*other.re);
}
Complex.prototype.power = function(num){
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num)*Math.cos(num*theta);
var b = Math.pow(r, num)*Math.sin(num*theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function(){
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function(){
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other){
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re/y.re, x.im/y.re);
return x;
}
function hslToRgb(h, s, l){ //NOT MY CODE
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j){
var z = new Complex(x_min+j*(x_max-x_min)/canvas.width, y_min+i*(y_max-y_min)/canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle()/(2*Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness)/Math.log(2) % 1;
return [color, brightness];
}
function main(){
var data = image.data;
if(EQUATION !== null){
var count = 0;
for(var i=0;i<canvas.height;i++){
for(var j=0;j<canvas.width;j++){
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 1, 0.4+c[1]/5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count*4;
data[c] = r;
data[c+1] = g;
data[c+2] = b;
data[c+3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return {x: (evt.clientX-rect.left)/(rect.right-rect.left)*canvas.width,
y: (evt.clientY-rect.top)/(rect.bottom-rect.top)*canvas.height};
}
document.getElementById("submit").addEventListener("mousedown", function(event){
EQUATION = document.getElementById("equation").innerHTML;
var x = main();
})
document.getElementById("canvas").addEventListener("mousemove", function(event){
var loc = getMousePos(canvas, event);
document.getElementById('x').innerHTML = Math.round(loc.x*100)/100;
document.getElementById('y').innerHTML = Math.round(loc.y*100)/100;
document.getElementById('brightness').innerHTML = evaluate(loc.y, loc.x)[1];
})
}
<input id="equation" type="text">Type Equation</input>
<canvas id="canvas" width="500" height="500"></canvas>
<button id="submit">Submit</button><br><span id="x"></span>, <span id="y"></span>, <span id="brightness"></span></p>
Afterwards, increasing the resolution and "stretching smaller" (a kind of supersampling) as described in another answer helps further, but is not the core issue.

Javascript Bradley adaptive thresholding implementation

I have been trying to implement Bradley Adaptive thresholding. I know there is a python code in one of the stack overflow questions. But i am struggling to implement the same in JS by following that. Can anyone please help me? So far my code is:
function computeAdaptiveThreshold (imagetest,imageWidth,imageHeight,callback)
{
var size = imageWidth*imageHeight*4;
var s = imageWidth/8;
var s2=s>>1;
var t=0.15;
var it=1.0-t;
var i,j,diff,x1,y1,x2,y2,ind1,ind2,ind3;
var sum=0;
var ind=0;
var integralImg = [];
var canvas = document.createElement('canvas');
var bin = canvas.getContext('2d').createImageData(imageWidth, imageHeight);
for(i=0;i<imageWidth;i++)
{
sum = 0;
for(j=0;j<imageHeight;j++)
{
index = i *imageHeight + j;
sum += imagetest.data[index];
if(i== 0)
{
integralImg[index] = sum;
}
else
{
//index = (i-1) * height + j;
integralImg[index] = integralImg[(i-1) * imageHeight + j] + sum;
}
}
}
x1=0;
for(i=1;i<imageWidth;++i)
{
sum=0;
ind=i;
ind3=ind-s2;
if(i>s)
{
x1=i-s;
}
diff=i-x1;
for(j=0;j<imageHeight;++j)
{
sum+=imagetest.data[ind];// & 0xFF;
integralImg[ind] = integralImg[(ind-1)]+sum;
ind+=imageWidth;
if(i<s2)continue;
if(j<s2)continue;
y1=(j<s ? 0 : j-s);
ind1=y1*imageWidth;
ind2=j*imageWidth;
if (((imagetest.data[ind3])*(diff * (j - y1))) < ((integralImg[(ind2 + i)] - integralImg[(ind1 + i)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
bin.data[ind3] = 0;
} else {
bin.data[ind3] = 255;
}
ind3 += imageWidth;
}
}
y1 = 0;
for( j = 0; j < imageHeight; ++j )
{
i = 0;
y2 =imageHeight- 1;
if( j <imageHeight- s2 )
{
i = imageWidth - s2;
y2 = j + s2;
}
ind = j * imageWidth + i;
if( j > s2 ) y1 = j - s2;
ind1 = y1 * imageWidth;
ind2 = y2 * imageWidth;
diff = y2 - y1;
for( ; i < imageWidth; ++i, ++ind )
{
x1 = ( i < s2 ? 0 : i - s2);
x2 = i + s2;
// check the border
if (x2 >= imageWidth) x2 = imageWidth - 1;
if (((imagetest.data[ind])*((x2 - x1) * diff)) < ((integralImg[(ind2 + x2)] - integralImg[(ind1 + x2)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
bin.data[ind] = 0;
} else {
bin.data[ind] = 255;
}
}
}
callback(bin);`
I am getting very bad images. I should say i cannot call it as a image.
I think your first effort should be to refactor your code : it will be much easier to handle the index.
Then you'll see that you have issues with your indexes : an image -even a gray one- is an RGBA Array, meaning 4 bytes = 32 bits per pixel.
You could handle this by doing a conversion RGBA-> b&W image, then thresholding, then doing b&w -> RGBA back.
...Or handle the RGBA components as you go. Notice that here you only want to output black or white, so you can create an Int32 view on the array, and write at once R,G,B,A for each pixels.
So some code (working here : http://jsfiddle.net/gamealchemist/3zuopz19/8/ ) :
function computeAdaptiveThreshold(sourceImageData, ratio, callback) {
var integral = buildIntegral_Gray(sourceImageData);
var width = sourceImageData.width;
var height = sourceImageData.height;
var s = width >> 4; // in fact it's s/2, but since we never use s...
var sourceData = sourceImageData.data;
var result = createImageData(width, height);
var resultData = result.data;
var resultData32 = new Uint32Array(resultData.buffer);
var x = 0,
y = 0,
lineIndex = 0;
for (y = 0; y < height; y++, lineIndex += width) {
for (x = 0; x < width; x++) {
var value = sourceData[(lineIndex + x) << 2];
var x1 = Math.max(x - s, 0);
var y1 = Math.max(y - s, 0);
var x2 = Math.min(x + s, width - 1);
var y2 = Math.min(y + s, height - 1);
var area = (x2 - x1 + 1) * (y2 - y1 + 1);
var localIntegral = getIntegralAt(integral, width, x1, y1, x2, y2);
if (value * area > localIntegral * ratio) {
resultData32[lineIndex + x] = 0xFFFFFFFF;
} else {
resultData32[lineIndex + x] = 0xFF000000;
}
}
}
return result;
}
function createImageData(width, height) {
var canvas = document.createElement('canvas');
return canvas.getContext('2d').createImageData(width, height);
}
function buildIntegral_Gray(sourceImageData) {
var sourceData = sourceImageData.data;
var width = sourceImageData.width;
var height = sourceImageData.height;
// should it be Int64 Array ??
// Sure for big images
var integral = new Int32Array(width * height)
// ... for loop
var x = 0,
y = 0,
lineIndex = 0,
sum = 0;
for (x = 0; x < width; x++) {
sum += sourceData[x << 2];
integral[x] = sum;
}
for (y = 1, lineIndex = width; y < height; y++, lineIndex += width) {
sum = 0;
for (x = 0; x < width; x++) {
sum += sourceData[(lineIndex + x) << 2];
integral[lineIndex + x] = integral[lineIndex - width + x] + sum;
}
}
return integral;
}
function getIntegralAt(integral, width, x1, y1, x2, y2) {
var result = integral[x2 + y2 * width];
if (y1 > 0) {
result -= integral[x2 + (y1 - 1) * width];
if (x1 > 0) {
result += integral[(x1 - 1) + (y1 - 1) * width];
}
}
if (x1 > 0) {
result -= integral[(x1 - 1) + (y2) * width];
}
return result;
}

Draw a border around an arbitrarily positioned set of shapes with RaphaelJS

I'm using RaphaelJS to draw a set of shapes at random positions on the paper, using this code:
http://jsbin.com/ixiqiy/2/edit
What I'm trying to do now is find the outermost set of positions, so that I can draw a border around the whole group. For example:
Can anyone help? Thanks.
OK, so using the Jarvis March algorithm and this python implementation I've managed to put together my own JS/RaphaelJS solution, which can be found here: http://jsbin.com/ixiqiy/12/edit.
Just in case that ever disappears, here's the code:
(function() {
function cmp(x, y) {
if (x > y) {
return 1;
} else if (x < y) {
return -1;
} else {
return 0;
}
}
function turn(p, q, r) {
return cmp((q[0] - p[0]) * (r[1] - p[1]) - (r[0] - p[0]) * (q[1] - p[1]), 0);
}
function dist(p, q) {
var dx = q[0] - p[0];
var dy = q[1] - p[1];
return dx * dx + dy * dy;
}
function next_hull_pt(points, p) {
var q = p,
r,
t;
for (var i = 0; i < points.length; i++) {
r = points[i];
t = turn(p, q, r);
if (t == -1 || t == 0 && dist(p, r) > dist(p, q)) {
q = r;
}
}
return q;
}
function convex_hull(points) {
var left,
point;
for (var i = 0; i < points.length; i++) {
point = points[i];
if (!left || point[0] < left[0]) {
left = point;
}
}
var hull = [left],
p,
q;
for (var i = 0; i < hull.length; i++) {
p = hull[i];
q = next_hull_pt(points, p);
if (q[0] != hull[0][0] || q[1] != hull[0][1]) {
hull.push(q);
}
}
hull.push(left);
return hull;
}
var paper = Raphael(0, 0, 800, 800),
set = paper.set(),
points = [],
point;
for (var i = 0; i < 20; i++) {
points[i] = [
Math.round(Math.random() * 500) + 100,
Math.round(Math.random() * 500) + 100
];
}
for (var i = 0; i < points.length; i++) {
point = points[i];
set.push(paper.circle(point[0], point[1], 5));
}
set.attr('fill', '#ff0000');
set.attr('stroke', '#ffffff');
var outline = convex_hull(points),
previous = [0, 0],
path = 'M';
for (var i = 0; i < outline.length; i++) {
point = outline[i];
path = path + (i == 0 ? 'M' : 'L') + point[0] + ',' + point[1] + ' ';
}
var path = paper.path(path);
path.attr('stroke', '#0000ff');
})();

Categories

Resources