I'm trying to create a triangulated plane in WebGL and I have the following code. However, when I render this in the browser, it just gives me a vertical line parallel to the y-axis.
var quads = 200;
for (var y = 0; y <= quads; ++y) {
var v = y / quads * 40;
for (var x = 0; x <= quads; ++x) {
var u = x / quads * 40;
recipient.vertices.push( vec3(u, v, 1))
recipient.normals.push( vec3(0, 0, 1))
}
}
var rowSize = (quads + 1);
for (var y = 0; y < quads; ++y) {
var rowOffset0 = (y + 0) * rowSize;
var rowOffset1 = (y + 1) * rowSize;
for (var x = 0; x < quads; ++x) {
recipient.indices.push(rowOffset0, rowOffset0 + 1, rowOffset1);
recipient.indices.push(rowOffset1, rowOffset0 + 1, rowOffset1 + 1);
}
}
Also as a followup question, I was hoping to get some tips on how to make a curved surface with this plane, something similar to a hill.
There was a bug in the original answer. It should be this
var quads = 200;
for (var y = 0; y <= quads; ++y) {
var v = y / quads;
for (var x = 0; x <= quads; ++x) {
var u = x / quads;
recipient.vertices.push( vec3(u, v, 1))
recipient.normals.push( vec3(0, 0, 1))
}
}
var rowSize = (quads + 1);
for (var y = 0; y < quads; ++y) {
var rowOffset0 = (y + 0) * rowSize;
var rowOffset1 = (y + 1) * rowSize;
for (var x = 0; x < quads; ++x) {
var offset0 = rowOffset0 + x;
var offset1 = rowOffset1 + x;
recipient.indices.push(offset0, offset0 + 1, offset1);
recipient.indices.push(offset1, offset0 + 1, offset1 + 1);
}
}
Fixed in original answer as well.
function Vec3Array() {
this.array = [];
this.push = function(v3) {
this.array.push.apply(this.array, v3);
}
}
function vec3(x, y, z) {
return [x, y, z];
}
var recipient = {
vertices: new Vec3Array(),
normals: new Vec3Array(),
indices: [],
};
var quads = 200;
for (var y = 0; y <= quads; ++y) {
var v = y / quads;
for (var x = 0; x <= quads; ++x) {
var u = x / quads;
recipient.vertices.push( vec3(u, v, 1))
recipient.normals.push( vec3(0, 0, 1))
}
}
var rowSize = (quads + 1);
for (var y = 0; y < quads; ++y) {
var rowOffset0 = (y + 0) * rowSize;
var rowOffset1 = (y + 1) * rowSize;
for (var x = 0; x < quads; ++x) {
var offset0 = rowOffset0 + x;
var offset1 = rowOffset1 + x;
recipient.indices.push(offset0, offset0 + 1, offset1);
recipient.indices.push(offset1, offset0 + 1, offset1 + 1);
}
}
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: recipient.vertices.array,
indices: recipient.indices,
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
var scale = 2 + (Math.sin(time) * 0.5 + 0.5) * 16;
var uniforms = {
matrix: [
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, 1, 0,
-1, -1, 0, 1,
],
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.LINE_STRIP, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
html, body {
width: 100%;
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
}
<script src="https://twgljs.org/dist/twgl.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
uniform mat4 matrix;
void main() {
gl_Position = matrix * position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
void main() {
gl_FragColor = vec4(1,0,0,1);
}
</script>
<canvas id="c"></canvas>
Related
I'm working on this program for a grid that generates geometric shapes and I want the function drawSubdividedCircle to always appear only once at a random position on the grid and take up the with and height of two rows/columns. I think the main problem is stacking because when i run it now the objects overlap. This is basically my goal:
And this is the code:
let colors = [
"#F7F7F7",
"#141414",
"#f07f45",
"#bcaad6",
"#60388e",
"#00afc6",
"#aae3ea"
];
let tilesX = 5;
let tilesY = 5;
let tileW;
let tileH;
let tileSize;
function drawSubdividedCircle (x, y, size, segments, layers) {
segments = random (1,13);
layers = random (1,13);
const r = 360 / segments;
for (let i = 0; i < segments; i++)
{
for (let j = 0; j < layers; j++)
{
fill(random(colors));
const s = map(j, 0, layers, size, 0);
arc(
x + size / 2,
y + size / 2,
s,
s,
radians(r * i),
radians(r * (i + 1)));
}
}
}
function setup() {
createCanvas(500, 500, SVG);
tileW = width / tilesX;
tileH = height / tilesY;
tileSize = (tileW, tileH);
}
function draw() {
noStroke();
frameRate(2);
for (let x = 0; x < tilesX; x++)
{
for (let y = 0; y < tilesY; y++)
{
let r = random(1);
if (r < 0.5)
{
ellipse((x - 0.5) * tileSize, (y - 0.5) * tileSize, tileSize, tileSize);
fill(random(colors));
}
else
{
rect(x * tileSize, y * tileSize, tileSize, tileSize);
fill(random(colors));
}{ drawSubdividedCircle(x * tileSize, y * tileSize, tileSize*2);
fill(random(colors));
}
}
}
//save("sketch1.6.5.svg");
//print("saved svg");
//noLoop();
}
Added an array to keep track of the state of each individual tile. Could be optimized for sure, but this works just fine.
https://editor.p5js.org/Kroepniek/sketches/MsFlcY3kl
let colors = [
"#F7F7F7",
"#141414",
"#f07f45",
"#bcaad6",
"#60388e",
"#00afc6",
"#aae3ea"
];
let tilesX = 5;
let tilesY = 5;
let tileW;
let tileH;
let tileSize;
let tileIsFree;
let subdividedCirclesCount = 0;
const subdividedCirclesLimit = 1;
function reinitTileStateArray()
{
tileIsFree = [];
for (let x = 0; x < tilesX; x++)
{
for (let y = 0; y < tilesY; y++)
{
tileIsFree[y * tilesX + x] = true;
}
}
subdividedCirclesCount = 0;
}
function drawSubdividedCircle (x, y, size, segments, layers) {
subdividedCirclesCount++;
segments = random (1,13);
layers = random (1,13);
const r = 360 / segments;
for (let j = 0; j < layers; j++)
{
for (let i = 0; i < segments; i++)
{
fill(random(colors));
const s = map(j, 0, layers, size, 0);
arc(
x + size / 2,
y + size / 2,
s,
s,
radians(r * i),
radians(r * (i + 1)));
}
}
}
function setup() {
createCanvas(500, 500);
frameRate(2);
tileW = width / tilesX;
tileH = height / tilesY;
tileSize = (tileW, tileH);
}
function draw() {
background(0);
noStroke();
reinitTileStateArray();
let randomChance = 0.5;
for (let y = 0; y < tilesY; y++)
{
for (let x = 0; x < tilesX; x++)
{
let r = random();
if (tileIsFree[y * tilesX + x])
{
fill(random(colors));
rect(x * tileSize, y * tileSize, tileSize, tileSize);
if (r < randomChance)
{
fill(random(colors));
ellipse((x + 0.5) * tileSize, (y + 0.5) * tileSize, tileSize, tileSize);
}
else if (subdividedCirclesCount < subdividedCirclesLimit && tileIsFree[y * tilesX + x + 1])
{
drawSubdividedCircle(x * tileSize, y * tileSize, tileSize * 2);
tileIsFree[y * tilesX + x] = false;
tileIsFree[y * tilesX + x + 1] = false;
tileIsFree[(y + 1) * tilesX + x] = false;
tileIsFree[(y + 1) * tilesX + x + 1] = false;
randomChance = 0.75;
}
}
}
}
//save("sketch1.6.5.svg");
//print("saved svg");
//noLoop();
}
I'm drawing each point of a vector as a vertex in P5.js.
I would like to change the color of each vertex in a loop separately like a rainbow. The thing is that it changes the color of all the vertex and I don't know why.
var x = 0.01
var y = 0
var z = 0
var sigma = 10
var prandtl = 28
var rayleigh = 8 / 3
var dt = 0.01
var positionPoint = []
var colorChange = 0;
function setup() {
createCanvas(800, 800, WEBGL)
colorMode(HSB)
}
function draw() {
background("grey")
formula()
noFill()
scale(5)
strokeWeight(3)
beginShape()
rotateZ(frameCount * 0.01);
rotateY(frameCount * 0.01);
for (var i = 0; i < positionPoint.length; i++) {
stroke(colorChange, 255, 255)
vertex(positionPoint[i].x, positionPoint[i].y, positionPoint[i].z)
colorChange += 0.001
if (colorChange > 255) {
colorChange = 0
}
}
endShape()
}
const formula = () => {
var dx = (sigma * (y - x)) * dt
var dy = (x * (prandtl - z) - y) * dt
var dz = (x * y - rayleigh * z) * dt
x = x + dx
y = y + dy
z = z + dz
positionPoint.push(createVector(x, y, z))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
Shapes drawn from corner points can only be colored uniformly. You need to draw separate line segments.
vertex(positionPoint[i].x, positionPoint[i].y, positionPoint[i].z)
line(positionPoint[i].x, positionPoint[i].y, positionPoint[i].z,
positionPoint[i+1].x, positionPoint[i+1].y, positionPoint[i+1].z)
Color channels are in range [0, 255]. Set colorChange = 0 before the loop and inclrement it by 1 in the loop:
colorChange = 0;
for (var i = 0; i < positionPoint.length-1; i++) {
// [...]
colorChange += 1
if (colorChange > 255) {
colorChange = 0
}
}
var x = 0.01
var y = 0
var z = 0
var sigma = 10
var prandtl = 28
var rayleigh = 8 / 3
var dt = 0.01
var positionPoint = []
var colorChange = 0;
function setup() {
createCanvas(800, 800, WEBGL)
colorMode(HSB)
}
function draw() {
background("grey")
formula()
noFill()
scale(5)
strokeWeight(3)
//beginShape()
rotateZ(frameCount * 0.01);
rotateY(frameCount * 0.01);
colorChange = 0;
for (var i = 0; i < positionPoint.length-1; i++) {
stroke(colorChange, 255, 255)
//vertex(positionPoint[i].x, positionPoint[i].y, positionPoint[i].z)
line(positionPoint[i].x, positionPoint[i].y, positionPoint[i].z, positionPoint[i+1].x, positionPoint[i+1].y, positionPoint[i+1].z)
colorChange += 1
if (colorChange > 255) {
colorChange = 0
}
}
//endShape()
}
const formula = () => {
var dx = (sigma * (y - x)) * dt
var dy = (x * (prandtl - z) - y) * dt
var dz = (x * y - rayleigh * z) * dt
x = x + dx
y = y + dy
z = z + dz
positionPoint.push(createVector(x, y, z))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
I am making a clone of agar.io and I am stuck in my code. I can't understand why my camera's position is not correctly calculated. I want my camera's position to half the vector between the farthest blob and the closest blob.
Below is a picture and my code:
<html>
<head>
<title>Play Agario Clone</title>
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="game">
kindly update your browser.
</canvas>
<script>
var
canvas,
ctx,
width = innerWidth,
height = innerHeight,
mouseX = 0,
mouseY = 0;
var
camera = {
x: 0,
y: 0,
// camera
update: function(obj) {
var farthestBlobX = Math.max.apply(0, obj.blobs.map(function(cell) { return cell.x }));
var farthestBlobY = Math.max.apply(0, obj.blobs.map(function(cell) { return cell.y }));
var closestBlobX = Math.min.apply(0, obj.blobs.map(function(cell) { return cell.x }));
var closestBlobY = Math.min.apply(0, obj.blobs.map(function(cell) { return cell.y }));
var x = farthestBlobX - closestBlobX;
var y = farthestBlobY - closestBlobY;
var length = Math.sqrt(x * x + y * y);
this.x = length/2 - width/2;
this.y = length/2 - height/2;
}
},
player = {
defaultMass: 54,
x: 0,
y: 0,
blobs: [],
update: function () {
for (var i = 0; i < this.blobs.length; i ++) {
var x = mouseX + camera.x - this.blobs[i].x;
var y = mouseY + camera.y - this.blobs[i].y;
var length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var speed = 54/this.blobs[i].mass;
this.blobs[i].velX = x/length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].velY = y/length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].x += this.blobs[i].velX;
this.blobs[i].y += this.blobs[i].velY;
for (var j = 0; j < this.blobs.length; j ++) {
if (j != i && this.blobs[i] !== undefined) {
var blob1 = this.blobs[i];
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
if (dist < blob1.mass + blob2.mass) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * (blob1.mass + blob2.mass);
blob1.y = blob2.y - y * (blob1.mass + blob2.mass);
}
}
}
}
this.x += (mouseX - width/2)/(width/2) * 1;
this.y += (mouseY - height/2)/(height/2) * 1
},
split: function (cell) {
cell.mass /= 2;
this.blobs.push({
x: cell.x,
y: cell.y,
mass: cell.mass
});
},
draw: function () {
for (var i = 0; i < this.blobs.length; i ++) {
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(-camera.x + this.blobs[i].x, -camera.y + this.blobs[i].y, this.blobs[i].mass, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
}
};
function handleMouseMove (e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function setup () {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push({
x: 0,
y: 0,
mass: player.defaultMass
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass/2
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass*2
});
var loop = function () {
update();
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
}
function update () {
camera.update(player);
player.update();
}
function draw () {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
player.draw();
}
setup();
</script>
</body>
</html>
Instead of computing everything relative to your camera, use your camera to set the global transformation matrix of your canvas, and only for this.
This way, your blobs' updates will be cleaner, and your camera easier to manage.
Now to get the middle position between two points, do (pt1 + pt2) / 2.
You were not clear in your question, if fartherstX and fartherstY should represent the same blob. In your code it wasn't, so I didn't change it.
Also, I didn't gone into all your logics, but beware NaN values, I got some while doing the edit.
function draw() {
var cw = ctx.canvas.width / 2;
var ch = ctx.canvas.height / 2;
// reset transform to clear the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
// here we really set the camera position
ctx.setTransform(1, 0, 0, 1, -camera.x + cw, -camera.y + ch);
ctx.strokeRect(0, 0, width, height); // just to show the original area
player.draw();
}
var
canvas,
ctx,
width = innerWidth,
height = innerHeight,
mouseX = 0,
mouseY = 0;
var camera = {
x: 0,
y: 0,
// camera
update: function(obj) {
var farthestBlobX = Math.max.apply(0, obj.blobs.map(function(cell) {
return cell.x
}));
var farthestBlobY = Math.max.apply(0, obj.blobs.map(function(cell) {
return cell.y
}));
var closestBlobX = Math.min.apply(0, obj.blobs.map(function(cell) {
return cell.x
}));
var closestBlobY = Math.min.apply(0, obj.blobs.map(function(cell) {
return cell.y
}));
this.x = (closestBlobX + farthestBlobX) / 2 || 0;
this.y = (closestBlobY + farthestBlobY) / 2 || 0;
}
},
player = {
defaultMass: 54,
x: 0,
y: 0,
blobs: [],
update: function() {
for (var i = 0; i < this.blobs.length; i++) {
var x = mouseX - this.blobs[i].x || 0;
var y = mouseY - this.blobs[i].y || 0;
var length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var speed = 54 / this.blobs[i].mass;
this.blobs[i].velX = x / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].velY = y / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
this.blobs[i].x += this.blobs[i].velX;
this.blobs[i].y += this.blobs[i].velY;
for (var j = 0; j < this.blobs.length; j++) {
if (j != i && this.blobs[i] !== undefined) {
var blob1 = this.blobs[i];
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
if (dist < blob1.mass + blob2.mass) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * (blob1.mass + blob2.mass);
blob1.y = blob2.y - y * (blob1.mass + blob2.mass);
}
}
}
}
this.x += (mouseX - width / 2) / (width / 2) * 1;
this.y += (mouseY - height / 2) / (height / 2) * 1;
},
split: function(cell) {
cell.mass /= 2;
this.blobs.push({
x: cell.x,
y: cell.y,
mass: cell.mass
});
},
draw: function() {
for (var i = 0; i < this.blobs.length; i++) {
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(this.blobs[i].x, this.blobs[i].y, this.blobs[i].mass, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
};
function handleMouseMove(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function setup() {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push({
x: 10,
y: 10,
mass: player.defaultMass
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass / 2
});
player.blobs.push({
x: 100,
y: 100,
mass: player.defaultMass * 2
});
var loop = function() {
update();
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
}
function update() {
camera.update(player);
player.update();
}
setup();
body {
margin: 0;
padding: 0;
}
<canvas id="game">kindly update your browser.</canvas>
I see there is an answer already..
var canvas;
var ctx;
var width = innerWidth;
var height = innerHeight;
var mouseX = 0;
var mouseY = 0;
const camera = {
x : 0,
y : 0,
update(obj) { // camera
this.x = (obj.blobsExtent.minx + obj.blobsExtent.maxx) / 2;
this.y = (obj.blobsExtent.miny + obj.blobsExtent.maxy) / 2;
this.x -= width / 2;
this.y -= height / 2;
}
};
const player = {
defaultMass : 54,
blobs : [],
blobsExtent : { // get the extent while updating the blobs save you having to iterate all the objects a second time to get extent
minx :0,
miny : 0,
maxx : 0,
maxy : 0,
},
update () {
var be = this.blobsExtent; // be for Blob Extent alias to save typing and make code easier to read
for (var i = 0; i < this.blobs.length; i++) {
var blob1 = this.blobs[i];
var x = mouseX - blob1.x;
var y = mouseY - blob1.y;
// to stop the divide by zero propigating NaN set length to 1 if less than 1
var length = Math.max(1,Math.sqrt(x * x + y * y)); // x * x is quicker than Math.pow(x,2)
var speed = 54 / blob1.mass;
blob1.velX = x / length * speed * Math.min(1, Math.pow(x / blob1.mass, 2));
blob1.velY = y / length * speed * Math.min(1, Math.pow(x / blob1.mass, 2));
blob1.x += blob1.velX;
blob1.y += blob1.velY;
for (var j = 0; j < this.blobs.length; j++) {
if (j != i) {
var blob2 = this.blobs[j];
var x = blob2.x - blob1.x;
var y = blob2.y - blob1.y;
var dist = Math.sqrt(x * x + y * y);
var radTotal = blob1.mass + blob2.mass;
if (dist < radTotal) {
x /= dist;
y /= dist;
blob1.x = blob2.x - x * radTotal;
blob1.y = blob2.y - y * radTotal;
}
}
}
if(i === 0){ // use first blob to setup min max
be.maxx = be.minx = blob1.x;
be.maxy = be.miny = blob1.y;
}else{
be.maxx = Math.max(be.maxx, blob1.x);
be.maxy = Math.max(be.maxy, blob1.y);
be.minx = Math.min(be.minx, blob1.x);
be.miny = Math.min(be.miny, blob1.y);
}
}
},
split (cell) {
cell.mass /= 2;
this.blobs.push(createBlob(cell.x, cell.y, cell.mass));
},
draw () {
var b; // alias for blob
ctx.fillStyle = "red"; // all the same colour then can render as one path
ctx.setTransform(1,0,0,1,-camera.x,-camera.y);
ctx.beginPath();
for (var i = 0; i < this.blobs.length; i++) {
b = this.blobs[i];
ctx.arc( b.x, b.y, b.mass, 0, Math.PI * 2);
ctx.closePath();
}
ctx.fill();
ctx.setTransform(1,0,0,1,0,0); // restore default transform
}
};
function handleMouseMove(e) {
mouseX = e.clientX + camera.x;
mouseY = e.clientY + camera.y;
}
function createBlob(x,y,mass){ return {x,y,mass} }
function setup() {
canvas = document.getElementById("game");
ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
addEventListener("mousemove", handleMouseMove);
player.blobs.push(createBlob(0,0,player.defaultMass));
player.blobs.push(createBlob(100,100,player.defaultMass / 2));
player.blobs.push(createBlob(100,100,player.defaultMass * 2));
}
function update() {
camera.update(player);
player.update();
}
function draw() {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
player.draw();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
setup();
requestAnimationFrame(loop);
body {
margin: 0;
padding: 0;
}
<canvas id="game"></canvas>
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;
}
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]));