Javascript: Rotate array (2d-matrix) around a certain X/Y-point - javascript

So, I have an array like this:
var my_array = [
'00000000000000000',
'00000111111110000',
'00000111111110000',
'00000111111110000',
'00000111111110000',
'00000111111110000',
'00000000000000000'
]
...and I'd like to get a function that is able to rotate the array (2d matrix above) by a certain angle (e.g 30°) around a certain point (x/y center of array : e.g X: 8, Y: 3).
So the result for 30° should maybe look like this: (Array is not that exact, just an example...)
var rotated_array = [
"00000000000000000",
"00000000001100000",
"00000000111110000",
"00000001111111000",
"00000111111111100",
"00000111111111000",
"00000011111100000",
"00000001110000000",
"00000000100000000",
"00000000000000000"
]
I've already created a function you can find below, but the function has some errors (The rotated matrix is missing some points and looks kind of destroyed --> You can test it on your own below).
I hope somebody can help me fixing my code, so however...
Thanks in advance, jonas.
BTW: I have marked all 'new' points which were never used with a '*'-character, afterwards I will use zeros instead!
var my_array = [
'00000000000000000000000',
'00000000000000000000000',
'00000000000000000000000',
'00000000000000000000000',
'00000011111111000000000',
'00000011111111000000000',
'00000011111111000000000',
'00000011111111000000000',
'00000011111111000000000',
'00000000000000000000000',
'00000000000000000000000',
'00000000000000000000000',
'00000000000000000000000'
]
Array.prototype.rotate_matrix = function(angle, cx, cy) {
function generate_matrix(rows,cols,value){
var arr = [];
for (var i=0; i < rows; i++) {
arr.push([]);arr[i].push(new Array(cols));
for (var j=0; j < cols; j++) arr[i][j] = value;
}; return arr;
}
var radians = (Math.PI / 180) * angle;
var array = generate_matrix(this.length, this[0].length, '*')
for (var i=0; i<this.length; i++) {
for (var j=0; j<this[i].length;j++) {
var character = this[i][j],
cos = Math.cos(radians),
sin = Math.sin(radians),
newx = Math.round((cos * (j - cx)) + (sin * (i - cy)) + cx) < this[i].length ? Math.round((cos * (j - cx)) + (sin * (i - cy)) + cx) : -1,
newy = Math.round((cos * (i - cy)) - (sin * (j - cx)) + cy) < this[i].length ? Math.round((cos * (i - cy)) - (sin * (j - cx)) + cy) : 1;
try {array[newy][newx]=character;}
catch(e) {
array[i][j] = character
}
}
}
array = array.map(a => [a.join('')])
return array.concat.apply([],array);
}
console.log(my_array.rotate_matrix(30,(my_array[0].length/2),(my_array.length/2)))

Related

Color quantization using euclidean distance gives jumpy results

I'm working on an art project which converts pixels of live video feed into corporate logos based on the distance (in RGB) between the colors of the two. While this functions, it gives a jittery result. Seem like some points in the color space teeter in a sort of superposition between two "closest" points. I'm attempting a sort of naive clustering solution right now because I believe any proper one will be too slow for live video. I'm wondering if anyone has any good ideas to solve this problem? I'll include my code and an example of the result. Thank you!
(imgs array is the logos)
current result: https://gifyu.com/image/fk2y
function distance(r1, g1, b1, bright1, r2, g2, b2, bright2) {
d =
((r2 - r1) * 0.3) ** 2 +
((g2 - g1) * 0.59) ** 2 +
((b2 - b1) * 0.11) ** 2 +
((bright2 - bright1) * 0.75) ** 2;
return Math.round(d);
}
function draw() {
if (x > 100 && z == true) {
video.loadPixels();
for (var y = 0; y < video.height; y++) {
for (var x = 0; x < video.width; x++) {
var index = (video.width - x - 1 + y * video.width) * 4;
var r = video.pixels[index];
var g = video.pixels[index + 1];
var b = video.pixels[index + 2];
var bright = (r + g + b) / 3;
let least = 9999999;
for (var i = 0; i < imgs.length; i++) {
if (
distance(
imgs[i].r,
imgs[i].g,
imgs[i].b,
imgs[i].bright,
r,
g,
b,
bright
) < least
) {
least = distance(
imgs[i].r,
imgs[i].g,
imgs[i].b,
imgs[i].bright,
r,
g,
b,
bright
);
place = imgs[i].img;
}
}
image(place, round(x * vScale), y * vScale, vScale, vScale);
}
}
}
}

Centroid of a polygon script

I've read other examples on here on finding the centroid of a polygon, I do not see where I am going wrong, why my centroid is so far off. If someone could please explain to me where my calculation is off.
I came up with this solution:
function getCentroid() {
var coords = getCoords();
var signedArea = 0;
var x = 0;
var y = 0;
for (var i = 0; i < coords.length - 1; i++) {
var temp = (coords[i].x * coords[i + 1].y) - (coords[i + 1].x * coords[i].y);
signedArea += temp;
x += (coords[i].x + coords[i + 1].x) * temp;
y += (coords[i].y + coords[i + 1].y) * temp;
}
signedArea *= 0.5;
x /= 6 * signedArea;
y /= 6 * signedArea;
return "" + Math.round(x) + "," + Math.round(y);
}
getCoords() returns a JSON array in this form:
[
{
"x":"600",
"y":"124"
},
{
"x":"560",
"y":"396"
},
{
"x":"994",
"y":"370"
},
{
"x":"918",
"y":"121"
},
{
"x":"600",
"y":"124"
}
]
The function getCentroid() returns the centroid (or atleast it should) of the polygon as a commaseperated string in the form: x,y
However, what it is returning is so far off the center.
returns: 312239,219226
Can anyone point me in the right direction?
Silly me, I didn't realize that the values of the coordinates were stored as strings in the json array. I casted them to Numbers and all is well.

How to draw a 2D/3D grid from BufferGeometry in three.js

I have some points in a BufferGeometry. They arrange themselves into a regular 1D/2D/3D grid. I'm doing index mapping to higher dimensions, and moving the vertices dynamically so they end up in a proper spot relative to their neighbors (specifically, I'm visualizing a self-organizing map).
I want to draw the connections between vertices, like the above picture. Doing that for 1D is straightforward enough because it's just a new Line(myBufferGeometry), but how can the same be achieved for 2D and 3D? Do I have to create and update separate geometries for this, like make lots of
LineSegments? How can this be done efficiently? Or maybe is there some "magic" I can do, like with the index property?
I figured this out thanks to prisoner849's comment - this isn't explicitly mentioned in the docs and kinda hidden away in examples, but this is exactly what the index property is for. When LineSegments is provided with a GeometryBuffer that has the property, the lines are based on pairs of indices rather than pairs of points in the position property.
Here's a complete solution for a n x n x n cube:
let nn = n * n;
let nnn = n * n * n;
function mapTo3D(index) {
let x = index % n;
let y = Math.floor(index / n) % n;
let z = Math.floor(index / nn);
return { x: x, y: y, z: z };
}
function mapFrom3D(x, y, z) {
return x + y * n + z * nn;
}
// add nnn points to the position attribute of your myGeometryBuffer...
let indices3D = [];
for (let i = 0; i < nnn; i++) {
var p = mapTo3D(i);
if (p.x + 1 < n) {
indices3D.push(i);
indices3D.push(mapFrom3D(p.x + 1, p.y, p.z));
}
if (p.y + 1 < n) {
indices3D.push(i);
indices3D.push(mapFrom3D(p.x, p.y + 1, p.z));
}
if (p.z + 1 < n) {
indices3D.push(i);
indices3D.push(mapFrom3D(p.x, p.y, p.z + 1));
}
}
myBufferGeometry.setIndex(indices3D);
let lines = new THREE.LineSegments(myBufferGeometry);

Fastest way to iterate pixels in a canvas and copy some of them in another one

I'm into a 2D/3D graphic project and I'm facing a performance problem.
My algorithm takes two images: a picture and the relative grayscale depth map.
I have also an array of 10 canvases ("layers") initally blank. A note: all the images have the same dimension.
I need to check every pixel X;Y of the depth map and, depending on its color value, access one of the 10 canvases and draw the X;Y pixel of the original image on it.
Resulting algorithm is someting like:
for (var y = 0; y < totalHeight; ++y) {
for (var x = 0; x < totalWidth; ++x) {
var index = (y * totalWidth + x) * 4; // index of the current pixel
// parse depth level using luminosity method
var depthLevel = Math.round(
0.21 * depthData[index] +
0.71 * depthData[index + 1] +
0.07 * depthData[index + 2]
);
// get the proper layer to modify
var layerIndex = Math.floor((layersCount / 256) * depthLevel);
var layerContext = layers[layerIndex].getContext("2d");
var layerData = layerContext.getImageData(0, 0, totalWidth, totalHeight);
layerData.data[index] = originalData[index];
layerData.data[index + 1] = originalData[index + 1];
layerData.data[index + 2] = originalData[index + 2];
layerData.data[index + 3] = originalData[index + 3];
layerContext.putImageData(layerData, 0, 0);
}
A loop like that takes around 3 minutes to complete on a 200x200 image! I'm pretty sure that the slowness is caused by the last function, putImageData. Is there a faster way to draw pixels in the way I need? Thank you
Don't set your image data in every iteration of the loop. That's a heavy operation, and you're executing it 40.000 (200*200) times.
This should save you a bit of processing power:
var contexts = [];
var data = [];
// Save your contexts and data to 2 arrays.
for (var i = 0; i < layers.length; i++) {
contexts[i] = layers[i].getContext("2d");
data[i] = contexts[i].getImageData(0, 0, totalWidth, totalHeight);
}
for (var y = 0; y < totalHeight; ++y) {
for (var x = 0; x < totalWidth; ++x) {
var index = (y * totalWidth + x) * 4; // index of the current pixel
// parse depth level using luminosity method
var depthLevel = Math.round(
0.21 * depthData[index]
+ 0.71 * depthData[index + 1]
+ 0.07 * depthData[index + 2]);
// get the proper layer to modify
var layerIndex = Math.floor((layersCount / 256) * depthLevel);
data[layerIndex].data[index] = originalData[index];
data[layerIndex].data[index + 1] = originalData[index + 1];
data[layerIndex].data[index + 2] = originalData[index + 2];
data[layerIndex].data[index + 3] = originalData[index + 3];
}
}
// Apply your new data to the contexts.
for (var i = 0; i < layers.length; i++) {
contexts[i].putImageData(data[i]);
}
I haven't tested it, but this should give you a bit of an idea of how to do it.

jQuery animations with a MxN matrix

I'm splitting a element into multiple blocks (defined by a number of rows and columns), and then fade these blocks to create animation effects. The type of animation is decided by the delay() value:
$('.block').each(function (i) {
$(this).stop().delay(30 * i).animate({
'opacity': 1
}, {
duration: 420
});
});
In this case each block's fade effect is delayed by (30 * current block index). The first block gets 0 delay, the second block 30 delay, ..... the last block 30 * (number of blocks) delay. So this will fade all blocks horizontally.
I've posted a list of effects I've come up so far here: http://jsfiddle.net/MRPDw/.
What I need help with is to find the delay expression for a spiral type effect, and maybe others that you think are possible :D
Here is an example of code for a spiral pattern:
case 'spiral':
$('.block', grid).css({
'opacity': 0
});
var order = new Array();
var rows2 = rows/2, x, y, z, n=0;
for (z = 0; z < rows2; z++){
y = z;
for (x = z; x < cols - z - 1; x++) {
order[n++] = y * cols + x;
}
x = cols - z - 1;
for (y = z; y < rows - z - 1; y++) {
order[n++] = y * cols + x;
}
y = rows - z - 1;
for (x = cols - z - 1; x > z; x--) {
order[n++] = y * cols + x;
}
x = z;
for (y = rows - z - 1; y > z; y--) {
order[n++] = y * cols + x;
}
}
for (var m = 0; m < n; m++) {
$('.block-' + order[m], grid).stop().delay(100*m).animate({
opacity: 1
}, {
duration: 420,
complete: (m != n - 1) ||
function () {
alert('done');
}
});
}
break;
See it working in this fiddle.
I also improved on your "RANDOM" animation, to show all the squares, not just a subset. The code for that is:
case 'random':
var order = new Array();
var numbers = new Array();
var x, y, n=0, m=0, ncells = rows*cols;
for (y = 0; y < rows; y++){
for (x = 0; x < cols; x++){
numbers[n] = n++;
}
}
while(m < ncells){
n = Math.floor(Math.random()*ncells);
if (numbers[n] != -1){
order[m++] = n;
numbers[n] = -1;
}
}
$('.block', grid).css({
'opacity': 0
});
for (var m = 0; m < ncells; m++) {
$('.block-' + order[m], grid).stop().delay(100*m).animate({
opacity: 1
}, {
duration: 420,
complete: (m != ncells - 1) ||
function () {
alert('done');
}
});
}
break;
See it working in this fiddle.
Maybe the easiest way to think about making a spiral animation, is to think about your matrix as a piece of paper.
If you fold 2 times that paper in the x and y center axes, you end up getting a smaller square (or rectangle) quadrant.
Now, if you animate this quadrant only from bottom right to top left corner (in the same way you did for your 'diagonal-reverse'), you can propagate this movement to the other 3 quadrants in order to get the final effect of having an animation running from the center of your matrix up to the four corners.
case 'spiral':
$('.block', grid).css({
'opacity': 0
});
n = 0;
var center = {
x: cols / 2,
y: rows / 2
};
// iterate on the second quadrant only
for (var y = 0; y < center.y; y++)
for (var x = 0; x < center.x; x++) {
// and apply the animation to all quadrants, by using the multiple jQuery selector
$('.block-' + (y * rows + x) + ', ' + // 2nd quadrant
'.block-' + (y * rows + cols - x - 1) + ', ' + // 1st quadrant
'.block-' + ((rows - y - 1) * rows + x) + ', ' + // 3rd quadrant
'.block-' + ((rows - y - 1) * rows + cols - x - 1) // 4th quadrant
, grid).stop().delay(100 * (center.y - y + center.x - x)).animate({
opacity: 1
}, {
duration: 420,
complete: function () {
if (++n == rows * cols) {
alert('done'); // fire next animation...
}
}
});
}
Here is the demo (click the spiral link)

Categories