I'm trying to calculate the area of a polygon giving some coordinates that can be negative.
When I pass only negative coordinates it gives me a negative area, when I pass only positives it gives me a positive but when I give it a mix ([-1, 0],[-1, 1],[1, 1],[1, 0]) it always give me a negative.
My code is:
function calculateArea(coords) {
area = 0;
points = coords.length;
j = points - 1;
for (i = 0; i < points; i++) {
area += (coords[i][0] + coords[j][0]) * (coords[i][1] - coords[j][1])
j = i;
}
return area / 2;
}
coords is an array of [x,y] coordinates.
The thing is, I'm not completely sure but I think that if I return the absolute value of the area calculated this should be correct.
Am I missing something or returning the absolute should be ok?
Area sign depends on how you order vertices not on if some coordinates are negative.
Clockwise ordering gives negative areas
Counterclockwise - positive
Assuming you have correct formula itself you could simple use Math.abs to always get positive values.
function calculateArea(coords) {
let area = 0;
for (let i = 0; i < coords.length; i++) {
const [x1, y1] = coords[i];
const [x2, y2] = coords[(i + 1) % coords.length];
area += x1 * y2 - x2 * y1
}
return area / 2;
// replace with
// return Math.abs(area) / 2;
}
console.log('Clockwise:', calculateArea([
[-1, 0],
[-1, 1],
[1, 1],
[1, 0]
]))
console.log('Counterclockwise:', calculateArea([
[-1, 0],
[-1, 1],
[1, 1],
[1, 0]
].reverse()))
Related
I have an array of "indexed" RGBA color values, and for any given image that I load, I want to be able to run through all the color values of the loaded pixels, and match them to the closest of my indexed color values. So, if the pixel in the image had a color of, say, RGBA(0,0,10,1), and the color RGBA(0,0,0,1) was my closest indexed value, it would adjust the loaded pixel to RGBA(0,0,0,1).
I know PHP has a function imagecolorclosest
int imagecolorclosest( $image, $red, $green, $blue )
Does javascript / p5.js / processing have anything similar? What's the easiest way to compare one color to another. Currently I can read the pixels of the image with this code (using P5.js):
let img;
function preload() {
img = loadImage('assets/00.jpg');
}
function setup() {
image(img, 0, 0, width, height);
let d = pixelDensity();
let fullImage = 4 * (width * d) * (height * d);
loadPixels();
for (let i = 0; i < fullImage; i+=4) {
let curR = pixels[i];
let curG = pixels[i]+1;
let curB = pixels[i+2];
let curA = pixels[i+3];
}
updatePixels();
}
Each color consists 3 color channels. Imagine the color as a point in a 3 dimensional space, where each color channel (red, green, blue) is associated to one dimension. You've to find the closest color (point) by the Euclidean distance. The color with the lowest distance is the "closest" color.
In p5.js you can use p5.Vector for vector arithmetic. The Euclidean distance between to points can be calculated by .dist(). So the distance between points respectively "colors" a and b can be expressed by:
let a = createVector(r1, g1, b1);
let b = createVector(r2, g2, b2);
let distance = a.dist(b);
Use the expression somehow like this:
colorTable = [[r0, g0, b0], [r1, g1, b1] ... ];
int closesetColor(r, g, b) {
let a = createVector(r, g, b);
let minDistance;
let minI;
for (let i=0; i < colorTable; ++i) {
let b = createVector(...colorTable[i]);
let distance = a.dist(b);
if (!minDistance || distance < minDistance) {
minI = i; minDistance = distance;
}
}
return minI;
}
function setup() {
image(img, 0, 0, width, height);
let d = pixelDensity();
let fullImage = 4 * (width * d) * (height * d);
loadPixels();
for (let i = 0; i < fullImage; i+=4) {
let closestI = closesetColor(pixels[i], pixels[i+1], pixels[i+2])
pixels[i] = colorTable[closestI][0];
pixels[i+1] = colorTable[closestI][1];
pixels[i+2] = colorTable[closestI][2];
}
updatePixels();
}
If I understand you correctly you want to keep the colors of an image within a certain limited pallet. If so, you should apply this function to each pixel of your image. It will give you the closest color value to a supplied pixel from a set of limited colors (indexedColors).
// example color pallet (no alpha)
indexedColors = [
[0, 10, 0],
[0, 50, 0]
];
// Takes pixel with no alpha value
function closestIndexedColor(color) {
var closest = {};
var dist;
for (var i = 0; i < indexedColors.length; i++) {
dist = Math.pow(indexedColors[i][0] - color[0], 2);
dist += Math.pow(indexedColors[i][1] - color[1], 2);
dist += Math.pow(indexedColors[i][2] - color[2], 2);
dist = Math.sqrt(dist);
if(!closest.dist || closest.dist > dist){
closest.dist = dist;
closest.color = indexedColors[i];
}
}
// returns closest match as RGB array without alpha
return closest.color;
}
// example usage
closestIndexedColor([0, 20, 0]); // returns [0, 10, 0]
It works the way that the PHP function you mentioned does. If you treat the color values as 3d coordinate points then the closet colors will be the ones with the smallest 3d "distance" between them. This 3d distance is calculated using the distance formula:
Before you comment, yes i have checked other questions aswell...
like this article, or this one, or maybe even this one. However, i couldn't find how to set the point of origin. So, let's say i have an array picture X coords and picture Y coords
(on a grid of 100*100)
x /y
92/81
82/47
81/03
Now i have the mouseX and mouseY.
Does anyone know how to make a function that gives you the closest point x and y values in JavaScript?
Thanks in advance!
Just do some vecor math. Given the images and the touch position:
const coords = [[92, 81], [82, 47], [81, 03]];
const touchX = 57, touchY = 84;
Just go over them and calculate the distance vecors length:
let closest = [null, null];
let distance = Infinity;
for(const [x, y] of coords){
let d = Math.sqrt((touchX - x) ** 2 + (touchY - y) ** 2);
if(d < distance){
closest = [x, y];
distance = d;
}
}
Vectors
Calculating the length
I am iterating over some image data pulled from a canvas like so:
var imageData = this.context.getImageData(0, 0, this.el.width, this.el.height);
var data = imageData.data;
for (var i = data.length; i >= 0; i -= 4) {
if (data[i + 3] > 0) {
data[i] = this.colour.R;
data[i + 1] = this.colour.G;
data[i + 2] = this.colour.B;
}
}
How do I calculate the current X and Y pixel coordinates that I am at?
Corrected and tested version of code:
var x = (i / 4) % this.el.width;
var y = Math.floor((i / 4) / this.el.width);
A Simple Arithmetic Sequence:
Divide the linear position by the width. That's your Y-coordinate. Multiply that Y-coordinate by the width, and subtract that value from the linear position. The result is the X coordinate.
Also note, you will have to divide the linear position by 4 since it is RGBA.
I was wondering how to go about making tetris pieces fall, I have followed a few tutorials and I have made the complete game, but I am a little stumped on how they actually got the pieces to fall, and how they made the 2d arrays into actual blocks, can someone guide me in the right direction here? I am just trying to learn the process better, this was all done in a canvas.
for example, here is the lpiece
function LPiece(){
//the pieces are represented in arrays shaped like the pieces, for example, here is an L.
//each state is a form the piece takes on, so each state after this.state1 is this.state1 rotated.
//each state is individual so we can call out which state to use depending on the option selected.
this.state1 = [ [1, 0],
[1, 0],
[1, 1]];
//and heres a different piece
this.state2 = [ [0, 0, 1],
[1, 1, 1]];
this.state3 = [
[1,1],
[0,1],
[0,1]];
this.state4 = [
[1, 1, 1],
[1, 0, 0]];
//and now we tie them all to one
this.states = [this.state1, this.state2, this.state3, this.state4];
//reference to the state the piece is currently in.
this.curState = 0;
//color of piece
this.color = 0;
//tracking pieces of grid of x and y coords, this is set at 4, -3 so it isn't initially visable.
this.gridx = 4;
this.gridy = -3;
}
piece.color = Math.floor(Math.random() *8);
I added comments to try to make me understand initially
and here is the image they used for each block, each block was one color
http://i.imgur.com/Mh5jMox.png
so how would he translate the array to be an actual block, and then get that to fall from the board, I have searched endlessly, I am just confused, like how he set the gridx and gridy to the x and y coordinates without ever saying this.y = gridy or something like that? does anyone have any suggestions on what to do here? thanks
here is how he drew the piece i guess, I still don't understand how he linked the x and y to the gridx and y of the piece without actually saying the x and y is grid x and y.
function drawPiece(p){
//connecting the y and x coords or pieces to draw using the arrays to pieces we defined earlier.
var drawX = p.gridx;
var drawY = p.gridy;
var state = p.curState;
//looping through to get a pieces currentstate, and drawing it to the board.
//rows, the p.state is deciding the length by the currentstate(the block width)
for(var r = 0, len = p.states[state].length; r < len; r++){
//columns the p.state is deciding the length by the currentstate(the block width)
for(var c = 0, len2 = p.states[state][r].length; c < len2; c++){
//detecting if there is a block to draw depending on size of value returned.
if(p.states[state][r][c] == 1 && drawY >= 0){
ctx.drawImage(blockImg, p.color * SIZE, 0, SIZE, SIZE, drawX * SIZE, drawY * SIZE, SIZE, SIZE);
}
drawX += 1;
}
//resetting the gridx
drawX = p.gridx;
//incrementing gridy to get the second layer of arrays from the block states.
drawY += 1;
}
}
He converts to canvas pixel units in ctx.drawImage here is a simplified version
var canvasX = drawX * SIZE;
var canvasY = drawY * SIZE;
ctx.drawImage(blockImg, p.color * SIZE, 0, SIZE, SIZE, canvasX, canvasY, SIZE, SIZE);
https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D#drawImage()
I am iterating over some image data pulled from a canvas like so:
var imageData = this.context.getImageData(0, 0, this.el.width, this.el.height);
var data = imageData.data;
for (var i = data.length; i >= 0; i -= 4) {
if (data[i + 3] > 0) {
data[i] = this.colour.R;
data[i + 1] = this.colour.G;
data[i + 2] = this.colour.B;
}
}
How do I calculate the current X and Y pixel coordinates that I am at?
Corrected and tested version of code:
var x = (i / 4) % this.el.width;
var y = Math.floor((i / 4) / this.el.width);
A Simple Arithmetic Sequence:
Divide the linear position by the width. That's your Y-coordinate. Multiply that Y-coordinate by the width, and subtract that value from the linear position. The result is the X coordinate.
Also note, you will have to divide the linear position by 4 since it is RGBA.