Simplify if statement condition - javascript

I am making a function to check the dimensions of an item to see if it will fit in a certain box. The problem I am having is how long the if conditional statement is. for example;
item's dimensions are 7x3x2, box's dimension are 7x5x3.
if(l <= 7 && w <= 5 && h <= 3
|| l <= 7 && w <= 3 && h <= 5
|| l <= 5 && w <= 7 && h <= 3
|| l <= 5 && w <= 3 && h <= 7
|| l <= 3 && w <= 5 && h <= 7
|| l <= 3 && w <= 7 && h <= 5) {
console.log("your item fits in this box!");
} else {
...
}
Is there a way to cover every possible combination instead of writing 6 different ways on the if statement?

Order the length, width, and height from highest to lowest first, then compare once:
const item1 = { l: 3, w: 8, h: 5 };
const item2 = { l: 2, w: 3, h: 9};
const item3 = { l: 3, w: 7, h: 5};
function orderDims(l, w, h) {
const length = Math.max(l, w, h);
const width = Math.max(Math.min(l, w), Math.min(Math.max(l, w), h));
const height = Math.min(l, w, h);
return [length, width, height];
}
function itemFits(l, w, h) {
const dimArr = orderDims(l, w, h);
return dimArr[0] <=7 && dimArr[1] <= 5 && dimArr[2] <= 3;
}
console.log(itemFits(item1['l'], item1['w'], item1['h']));
console.log(itemFits(item2['l'], item2['w'], item2['h']));
console.log(itemFits(item3['l'], item3['w'], item3['h']));

You could sort their values and compare like this:
const x = 7;
const y = 3;
const z = 5;
console.log(JSON.stringify([x, y, z].sort()) === JSON.stringify([3, 5, 7]));
So your if statement could look like this:
if (JSON.stringify([l, w, h].sort()) === JSON.stringify([3, 5, 7])) {
...
}
You could refactor it like this:
class Container {
constructor(...dimensions) {
this.dimensions = dimensions;
}
fits(l, w, h) {
return JSON.stringify([l, w, h].sort()) === JSON.stringify(this.dimensions);
}
}
const container = new Container(3, 5, 7);
console.log(container.fits(3, 5, 7));
console.log(container.fits(3, 7, 5));
console.log(container.fits(5, 3, 7));
console.log(container.fits(5, 7, 3));
console.log(container.fits(7, 3, 5));
console.log(container.fits(7, 5, 3));

I think you would want to avoid extended if statements like that just for readability and code maintenance purposes? You could achieve the same logic written slightly different. Something like (pseudocode):
let fits = true;
if (x > 7){
fits = false;
}
if (y > 5){
fits = false;
}
if (z > 3) {
fits = false;
}
return fits;

You can solve this question easily, if you find the volume of the item and the box and then compare the volumes.
For example:
item's dimensions - 7x3x2
Box's dimensions - 7x5x3
Item volume - 42
Box volume - 105
Since volume of item is less than volume of box the, item can be fitted inside the box.
Using only one if else you can easily solve the question.

Related

Check amount of 'overlap' of two sides of adjacent rectangles

I have two rectangles that are guaranteed not to overlap.
However, I need to know if they are next to each other and if they are that they touch each other by two or more units. For example, the following rectangles touch at 4 units.
In the above example I am comparing the following:
rect1 = {
x: 4,
y: 4,
width: 3,
height: 5
}
and
rect2 = {
x: 7,
y: 1,
width: 4,
height: 7
}
I am currently trying to accomplish this by several nested if/else statements, but I know there would be a more adequate way.
What is an efficient way of accomplishing this?
Disclaimer:
I used the term overlap in the title as I wasn't sure how else to describe it even though they do not actually overlap.
Here's a simple version:
function rectOverlaps2(r1, r2) {
let overlapX, overlapY;
if ( r1.x <= r2.x ) {
overlapX = r1.x + r1.width - r2.x;
} else {
overlapX = r2.x + r2.width - r1.x;
}
if ( r1.y <= r2.y ) {
overlapY = r1.y + r1.height - r2.y;
} else {
overlapY = r2.y + r2.height - r1.y;
}
return (overlapX == 0 && overlapY >= 2) || (overlapY == 0 && overlapX >= 2);
}
Added: Just realized that there is an edge case - if the overlapping dimension (width or height) of one rectangle is just 1 unit, then the overlap should not be counted. Since this looks like a homework question, fixing this will be left as an exercise to the reader.
here's my solution for this problem. My idea is to create an array that contains all numbers between the start of the rectangle and its end in the Y direction, for example. Then if the other rectangle contains any of the indices in between, that means they are 'overlapping'
I didn't try any performance optimization, but that's the general idea.
rect1 = {
x: 4,
y: 4,
width: 3,
height: 5
}
rect2 = {
x: 7,
y: 1,
width: 4,
height: 7
}
function createMap(start, end) {
return Array(end - start + 1).fill().map((_, idx) => start + idx)
}
function getEndPoints(rect){
const endX = rect.x + rect.width;
const endY = rect.y + rect.height;
return {endX, endY};
}
function getOverlap(r1, r2){
const r1Range = createMap(r1.y, r1.endY);
const r2Range = createMap(r2.y, r2.endY);
const verticalOverlap = r1Range.filter(val => !r2Range.includes(val));
console.log(`These two rectangles overlap by: ${verticalOverlap.length} squares`)
// Then just do the same for horizontal
}
rect1 = {...rect1, getEndpoints(rect1)}
rect2 = {...rect2, getEndpoints(rect2)}
getOverlap(rect1, rect2);

Javascript for loop conditional iterations and resetting variable

With the following code, I'm looping through an array of colors (favorites), creating rectangles for a jsPDF document.
After 5 iterations, I want to reset the x variable back to startX and then add 1.875 with each iteration. Likewise for the next 5 iterations: reset x to startX adding 1.875 until 10, then again until 15.
I'm just not having any luck resetting x in these conditionals. I'm sure it's something obvious but what am I missing here?
Or should I structure the loop in a different way?
What I'm trying to accomplish is create up to 3 rows of 5 rectangles. Once I hit 5, start a new row, hence the reset of x which is a page location coordinate.
let startX = 1
let startY = 1
let secondY = 4
let thirdY = 6.5
let n = favorites.length
for (let i = 0, x = startX, y = startY; i < n; x += 1.875, i++) {
if (i < 5) {
doc.setFillColor(favorites[i].h)
doc.rect(x, y, 1.5, 1, 'F')
doc.text(favorites[i].h.toString(), x, y + 1.5)
} else if (i >= 5 && i < 10) {
x = 1 // resets but then doesn't increment
y = secondY
doc.setFillColor(favorites[i].h)
doc.rect(x, y, 1.5, 1, 'F')
doc.text(favorites[i].h.toString(), x, y + 1.5)
} else if (i >= 10 && i < 15) {
x = 1 // resets but then doesn't increment
y = thirdY
doc.setFillColor(favorites[i].h)
doc.rect(x, y, 1.5, 1, 'F')
doc.text(favorites[i].h.toString(), x, y + 1.5)
}
}
You can use the modulo operator (%), and set x and y outside the loop declaration:
const yValues = [1, 4, 6.5];
for (let i = 0 ; i < 15; i++) {
const x = 1 + ((i%5) * 1.875);
const y = yValues[Math.floor(i/5)];
// commented lines to make this example run
// doc.setFillColor(favorites[i].h)
// doc.rect(x, y, 1.5, 1, 'F')
// doc.text(favorites[i].h.toString(), x, y + 1.5)
console.log({x,y});
}
Incrementation in a for loop occur before any commands in the loop. Right now, every iteration in your second and third if blocks resets x to 1, and always does so after x's incrementation in the for loop, thus overwriting it. That's why x isn't changing.
A better approach might be to increment only i, and set x to depend on i's value, something like this:
x = 1 + ((i - 5) * 1.875)
x = 1 + ((i - 10) * 1.875)
And actually, it would be even better to use startX instead of 1:
x = startX + ((i - 5) * 1.875)
x = startX + ((i - 10) * 1.875)

Optimise object overlapping detection (Javascript)

Issue
I am writing a program which involves calculating how many pixels one moving object overlaps the other. I'd have to return this value many times a second, so the program would have to be efficient. The example that I have come up with seems not to be.
Example
Let's scale-down for a minute and imagine we have an object that is 3*3 pixels and one that is 3*2
a b c
d e f j k l
g h i m n o
Each letter represents an individual pixel of each object. The 3*3 object sits on the left, and the 3*2 object sits on the right, with an x value 4 greater than that of the larger object. They are not overlapping.
Code
Currently, I am returning the number of overlapping pixels through a simple function that checks every pixel in object one against every pixel in object two for overlaps:
var a = {
width: 3,
height: 3,
x: 0,
y: 0
}
var b = {
width: 3,
height: 2,
x: 4,
y: 0
}
function overlappingPixels(object_1, object_2) {
var overlapping = 0;
for (var w_1 = 0; w_1 < object_1.width; w_1++) {
for (var h_1 = 0; h_1 < object_1.height; h_1++) {
for (var w_2 = 0; w_2 < object_1.width; w_2++) {
for (var h_2 = 0; h_2 < object_1.height; h_2++) {
if (w_1 + object_1.x == w_2 + object_2.x && h_1 + object_1.y == h_2 + + object_2.y) {
overlapping++;
}
}
}
}
}
return overlapping;
}
overlappingPixels(a, b); returns 0, because the two objects have no overlapping pixels.
Recap
To recap, I have built a function that compares each pixel of object one to each pixel of object two for any overlaps. This seems horribly inefficient, and I was curious as to whether there was a quicker option if this calculation needed to be performed very quickly for moving objects. The speed of the function breaks down quickly as the size of the objects increase. I'd be performing this calculation on larger objects anyway, so this isn't ideal.
Thanks!
There is an easy and efficient way to check if two rectangles collide.
var rect1 = {x: 5, y: 5, width: 50, height: 50}
var rect2 = {x: 20, y: 10, width: 10, height: 10}
if (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.height + rect1.y > rect2.y) {
// collision detected!
}
See MDN 2D object collision detection
To get the size of overlap is also quite easy once you know there is collision for sure. Just get the heigth and width where they overlap, and get the area by multiplying them. See the calculateCollisionLength function in the snippet to see how you can calculate the overlap without going over it pixel by pixel.
const calculateCollisionLength = (point1, point2, length1, length2) => {
const pointb1 = point1 + length1;
const pointb2 = point2 + length2;
const diff1 = Math.abs(point1 - point2);
const diff2 = Math.abs(pointb1 - pointb2);
return (length1 + length2 - diff1 - diff2) / 2;
}
function checkCollusion(rect1, rect2) {
if (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.height + rect1.y > rect2.y) {
// collision detected!
const collision = { xLength: 0, yLength: 0 };
collision.xLength = calculateCollisionLength(rect1.x, rect2.x, rect1.width, rect2.width);
collision.yLength = calculateCollisionLength(rect1.y, rect2.y, rect1.height, rect2.height);
return collision.xLength * collision.yLength;
}
else return null;
}
var rect1 = { x: 5, y: 5, width: 50, height: 50 }
var rect2 = { x: 20, y: 10, width: 10, height: 10 }
console.log(checkCollusion(rect1, rect2))

checking rolled by image number?

So, I have a code that is rolling a random number from 1024 to 4096 and changing backgroundPosition to rolled number. (jsfiddle)
function slide()
{
var x = 1;
var y = 30;
var z = Math.floor((Math.random() * 4096) + 1024); // background offset
var zz = Math.floor((Math.random() * 14) + 0); // number
var clr = setInterval(function()
{
if(x >= z) x = 1;
document.getElementById("slide").style.backgroundPosition = x+"px 0px";
x+=y;
y-=0.1;
if (y<=0)
{
clearInterval(clr);
document.getElementById('rolledNumber').innerHTML = z;
}
}
,10);
}
"z" is a random number between 1024 and 4096, how can I check what number on image it is? I tried if (z >= 2285 && z <= 2210){var zz = 4;}, where "zz" is a number on image, but it's not working.
Hope you guys can understand it.
You have a few problems here:
1) if (z >= 2285 && z <= 2210)
is impossible. There is no number that satisfies both "larger than 2284" AND "smaller than 2211".
2) "z" is a random number between 1024 and 4096
var z = Math.floor((Math.random() * 4096) + 1024); will actually create a random number between 1024 and 5120. Imagine the case where Math.random() returns 1. Your result would be 1 * 4096 + 1024, or 5120.
3) Your background image is repeating - if you stick to one set of 15 numbers, you could access the number by mapping the pixel offset to an array.. something like this:
var boxWidth = 150;
var boxes = [1, 14, 2, 13, 3, 12, 4, 0, 11, 5, 10, 6, 9, 7, 8];
function getNumber (offset) {
var boxNumber = Math.floor(offset / boxWidth);
return boxes[boxNumber];
}
4) No one knows the application of this logic other than you, please reword your question such that it actually makes any sense and act like you've tried to find the problem yourself.
If anyone is interested - I figured out how to do this. I'm checking "x" value, and if it's between x and y, that means rolled number is z. Fragment of code:
if (x >= 410 && x <= 485){var rolledNumber = 1;}
if (x >= 335 && x <= 410){var rolledNumber = 14;}
if (x >= 260 && x <= 335){var rolledNumber = 2;}

get pixel colour in javascript

This might be a very basic question but as I am a newbie when it comes to javascript I can't figure out the right way to solve my issue. I need to do an if statement which checks the pixel colour and if it's black - do something if it's not - do something else. (It's a back-propagation project so that's why there are iterations)
for(i=1;i<iterations;i++) {
for(j=1;j<300;i+=2) { //canvas size is 300x300
for(k=1;k<300;i+=2) {
if (context.getImageData(j,k,1,1).data == [0, 0, 0, 0])
{/*code to be executed*/}
else {/*other code*/}
}
}
}
Sorry for asking easy stuff but I have not much time to do this so can't start from basics right now.
You need to compare each items in the array:
var pixel = context.getImageData(j,k,1,1).data; // cache array
if (pixel[0] === 0 && // R
pixel[1] === 0 && // G
pixel[2] === 0 && // B
pixel[3] === 0) { // A
...
}
Better yet, not use getImageData() for each pixel but cache it before starting the iterations:
var x, y,
buffer = context.getImageData(0, 0, 300, 300).data;
for(y = 0; i < 300; y++) {
for(x = 0; x < 300; x++) {
var pos = (y * 300 + x) * 4;
if (buffer[pos] === 0 && // R
buffer[pos+1] === 0 && // G
buffer[pos+2] === 0 && // B
buffer[pos+3] === 0) { // A
...was black...
}
else {
...was not black...
}
}
}

Categories