finding cells in a grid that intersect a given rectangle - java

(I'll tag this for both Java and language-agnostic, since I think the idea doesn't really require Java, but that's my specific application, so IDK which of the two tags is appropriate).
Let's say I have a grid with an arbitrary number of rows and columns, and and arbitrary cell size.
This grid represents a 2d space. Now let's say I have a rectangle somewhere in that 2d space - in the past, I remember being able to get back all the cells that intersected the rectangle, (without having to loop), but the math is escaping me at the moment.
To firm up the example, lets say there are 12 rows and 10 columns. Cells are 256 square (so rows at 256 tall, and columns are 256 wide). If there was a rectangle at x:400, y:300 that was 200x200, I know that it would intersect the second and third columns in the second row.
So if cell structure was defined like so:
// reference[rows][columns]
SomeCellClass[][] cells = SomeCellClass[12][10]
Then the intersections would be SomeCellClass[1][1] and SomeCellClass[1][2]
And ideally the return would be something like
private SomeCellClass[] blah(){
// do work
SomeCellClass[] product = new SomeCellClass[total];
SomeCellClass[0] = // first one that intersects...
SomeCellClass[1] = // second one that intersects...
// etc...
}
I remember it has something do do with dividing the rectangle position and dimension by cell size and flooring/ceiling to get back the index, but can't get my head around the specifics. Again, I get how to do this with a loop but would like to be able to use just math and array indices.
Any help would be appreciated.
TYIA.

Looks like it's basically this:
int startingColumn = Math.floor( rect.left / columnWidth );
int endingColumn = Math.ceil( rect.right / columnWidth );
int startingRow = Math.floor( rect.top / rowHeight );
int endingRow = Math.ceil( rect.bottom / rowHeight );
Then obviously loop from startingColunn/Row through endingColumn/Row.

Related

Trying to get multiple images out of a single image

I've been stuck at something recently.
What I want to do is to get multiple sub-images out of 1 big image.
So take this example. I have a frame of 128x128 pixels where all the images need to be in.
I'm putting all the bufferedImages inside a list and scaling all those images to 128x128.
The image you see on that link is showing that I need 4 sub-images from that image, so at the end, I have 4 images which are 128x128 but 4 times.
Or if you have an image with 128x384 it will give 3 sub-images going from top to bottom.
https://i.stack.imgur.com/RsCkf.png
I know there is a function called
BufferedImage.getSubimage(int x, int y, int w, int h);
But the problem is that I can't figure out what math I need to implement.
What I tried is if the height or width is higher than 200 then divide it by 2 but that never worked for me.
I'm not sure I fully understand what you are asking, but I think what you want is something like this:
First, loop over the image in both dimensions.
Then compute the size of the tile (the smaller value of 128 and (image dimension - start pos)). This is to make sure you don't try to fetch a tile out of bounds. If your images are always a multiple of 128 in any dimension, you could just skip this step and just use 128 (just make sure you validate that input images follow this assumption).
If you only want tiles of exactly 128x128, you could also just skip the remainder, if the tile is less than 128x128, I'm not sure what your requirement is here. Anyway, I'll leave that to you. :-)
Finally, get the subimage of that size and coordinates and store in the list.
Code:
BufferedImage image = ...;
int tileSize = 128;
List<BufferedImage> tiles = new ArrayList<>();
for (int y = 0; y < image.height(); y += tileSize) {
int h = Math.min(tileSize, image.height() - y);
for (int x = 0; x < image.width(); x += tileSize) {
int w = Math.min(tileSize, image.width() - x);
tiles .add(image.getSubimage(x, y, w, h));
}
}

MPAndroidChart Display Label Over Horizontal Line on Graph

Is it possible to display custom text centered between 2 points on the graph?
I've got MPAndroidChart setup to display a step function type graph (representing hours spent doing a specific task) with horizontal and vertical lines only. What I would like to be able to do is show a label over the horizontal sections indicating the size of the section (aka the time spent calculated by taking the difference between the x values). Is there a way to do this? I've been look into modifying the library but I can't seem to figure out where would be the correct place to do so.
My best guess would be some changes in BarLineChartBase onDraw() method or maybe in the LineChartRenderer drawLinear() method.
Here is what I am able to produce:
Here is an example of what I am trying to produce:
Figured it out! Just add a new method drawTime() to the LineChart class at the end of onDraw() right after drawDescription(). Since each horizontal line is described by 2 Entry points I simply loop through 2 entries at a time for my single data set and calculate the difference:
protected void drawTime(Canvas c)
{
Paint timePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
timePaint.setTextSize(Utils.convertDpToPixel(16));
timePaint.setColor(Color.BLUE);
timePaint.setTextAlign(Paint.Align.CENTER);
MPPointD position;
LineData data = this.getLineData();
ILineDataSet dataSet = data.getDataSetByIndex(0);
for (int i = 1; i < dataSet.getEntryCount(); i+=2)
{
Entry e1 = dataSet.getEntryForIndex(i-1);
Entry e2 = dataSet.getEntryForIndex(i);
float time = e2.getX() - e1.getX();
position = getPixelForValues(e1.getX() + time/2, e1.getY() - 0.05f, YAxis.AxisDependency.LEFT);
c.drawText(String.valueOf(time), (float)position.x, (float)position.y, timePaint);
}
}
The resulting graph looks like this

Java Random Number Fails If statement test in For Loop

I have built a simple program to draw a city skyline within a frame with some random elements. The number of buildings will be a random number between [5 - 9], the width and height of each building are also random (within a given range) as is the gap between each building. The problem I am having comes when I try to select a different gap range depending on the amount of buildings. Here is the the section of code in question (I have imported java.util.*;):
Random gen = new Random();
int buildNum = gen.nextInt(5) + 5; //generate random number [5 - 9]
for (int i = 0; i < buildNum; i++)
{
//generate random width
buildWidth = gen.nextInt(26) + 35; //[35 - 60]
//generate random height
buildHeight = gen.nextInt(201) + 200; //[200 - 400]
//instantiate building
building = new Building (gap, 500 - buildHeight, buildWidth, buildHeight, Color.gray);
buildingsArray.add(building);
//draw building
buildingsArray.get(i).draw (page);
//generate random gap between building
if (buildNum < 7)
{
gap += buildWidth + gen.nextInt(16) + 40;
}
if (buildNum == 7)
{
gap += buildWidth + gen.nextInt(9) + 15;
}
if (buildNum > 7)
{
gap += buildWidth + gen.nextInt(9) + 8;
}
}
The buildNum variable is initialized with a random number, then that number is used to iterate through. The issue is that when I check the buildNum variable in the three ifs at the bottom, the output does not seem to correspond with what I would expect. I will get 5 buildings with very small gaps (as though it passed the buildNum > 7 test), or I will get 7 buildings with the first six normal, but a very small gap before the seventh building. I'm sure it's something very simple that I am overlooking, but I have been starting at this for hours and tried many different things (including testing buildNum at fixed values 5, 6, 7, 8, or 9, and putting an else clause instead of a third if.) Ultimately, I would like the program to pick a number of buildings between 5 and 9 and then scale the gaps accordingly. I tried factoring in both buildNum and buildWidth, but I couldn't get it to work and settled for this. If anyone has a better way or can shed some light on my problem, I would greatly appreciate it!
Update: I have tested with a constant number of buildings to see what the range of output looks like. The problem is that I would be expecting 5 or 6 buildings to have wide gaps due to the if (buildNum < 7) condition and be progressively smaller due to the other 2 conditions. Instead, I end up with 5 buildings having really really small gaps (6 buildings is fine) and seven and 8 buildings going off the page (even though I've done the math and the gap that is added within the if conditionals would not allow this). There are some helpful comments here already, to answer your questions: Yes, the gap is an absolute position from the left. A small gap is initialized so that the first building does not touch the left side of the frame. Then, buildings are instantiated one at a time with a gap size chosen from those if statements. The position of the next building's left side is determined from a compounding gap variable that includes all previous gaps and all previous building widths. I am especially curious about Lee's comment that the if (buildNum ==7) and (buildNum>7) clauses might never happen. Could you explain that a little further? Wouldn't 8 or 9 satisfy the >7 condition and 7 satisfy the ==7 condition? if not, what can I do to change it? also, here is my constructor:
/**
* Constructor: sets background color and frame size
*/
public SkylinePanel()
{
setPreferredSize (new Dimension(600, 500));
setBackground (Color.black);
}
There is not much to it, the real work (including the above shown for loop) is within paintComponent and I've shown everything that is related to the building gaps already. Here is the draw method (it's in my building class):
/**
* Draws a building or window with the specified parameters
*/
public void draw (Graphics page)
{
page.setColor (color);
page.fillRect (x, y, width, height);
winNum = gen.nextInt(8) + 2;
//generate a random number [2 - 9] of windows to draw on a given building
for (int i = 0; i < winNum; i++)
{
page.setColor (Color.yellow);
page.fillRect (gen.nextInt(width - WIN_X) + x, gen.nextInt(height - WIN_Y) + y, WIN_X, WIN_Y);
}
}
Ignore the code about windows, that works fine. I added that after I decided to move on from the gap problem for the time being.
Oh, and just in case anyone needs to see it, here is the constructor of the Building class:
public Building (int upperX, int upperY, int buildWidth, int buildHeight, Color shade)
{
x = upperX;
y = upperY;
width = buildWidth;
height = buildHeight;
color = shade;
}
Any other thoughts or questions would be greatly appreciated!

Uniform grid collision detection between circles in 2d

I am working on a 2d arcade game where I have 5 types of circles with different sizes: The ship, the missiles, and 3 types of monsters.
This is what it looks like:
Currently I'm using brute force collision detection where I check every missile vs. every monster without taking probability of collision into account. Sadly, this makes the process REALLY slow.
This here is my Grid class, but it's incomplete. I'd greatly appreciate your help.
public class Grid {
int rows;
int cols;
double squareSize;
private ArrayList<Circle>[][] grid;
public Grid(int sceneWidth, int sceneHeight, int squareSize) {
this.squareSize = squareSize;
// Calculate how many rows and cols for the grid.
rows = (sceneHeight + squareSize) / squareSize;
cols = (sceneWidth + squareSize) / squareSize;
// Create grid
this.grid = (ArrayList[][]) new ArrayList[cols][rows]; //Generic array creation error workaround
}
The addObject method inside the Grid class.
public void addObject(Circle entity) {
// Adds entity to every cell that it's overlapping with.
double topLeftX = Math.max(0, entity.getLayoutX() / squareSize);
double topLeftY = Math.max(0, entity.getLayoutY() / squareSize);
double bottomRightX = Math.min(cols - 1, entity.getLayoutX() + entity.getRadius() - 1) / squareSize;
double bottomRightY = Math.min(rows - 1, entity.getLayoutY() + entity.getRadius() - 1) / squareSize;
for (double x = topLeftX; x < bottomRightX; x++) {
for (double y = topLeftY; y < bottomRightY; y++) {
grid[(int) x][(int) y].add(entity); //Cast types to int to prevent loosy conversion type error.
}
}
}
But that's where I am at a complete loss. I'm not even sure the source code I provided is correct. Please let me know how to make the grid based collision work. I've read basically every tutorial I could get my hands on but without much effect.
Thanks.
I found it easier (and I guess faster) to store in the object itself a binary number representing which cells the object overlaps with (instead of saving an array for every cell). I think it's called a spatial mask.
More specifically, before any collision testing, I calculate 2^(x/column_width + columns*y/row_width) for each of topLeft, topRight... then combine all those 4 in a single number (with a bitwise OR), so that I end up with a number like 5 (00000011, meaning the object hits the cells 1 and 2).
Having it this way, you then proceed to test each object with all the others, but skip the slow part if they fail to be in the same cell:
Check the bitwise AND of the numbers in both objects (this will only be !=0 if some of the cells are 1 for both objects).
If the result is something other than 0, do the proper (slow) collision checks (in your case probably pythagoras, since those are circles and I read pythagoras is faster than checking bounding squares).

Generate n colors between two colors

I'm trying to write function, which can generate colors between two colors based on a given value. An example would explain it better..
Input ..
X : 1
Y : 0.5
Z : 0
The user gives any set of color:value pairs, then enters a number(say 0.75). I have to then generate color which is a blend of Y and Z in proportion(based on the their values and the input value). I was thinking of the following approach.
Find the colors which surround the value, for 0.75 it will be 0.5 and 1.
Mix those two colors somehow, based on the value and generate new colors.
I'm completely lost, as how to generate colors and are there any libraries for this.
UPDATE:
It is part of a bigger project I'm working on. Lets say we have ..
1 : X
0 : Y
and the user inputs, 0.25
I would like to have something..
(X*0.25 + Y*0.75)
as it's more near to Y, that's why the higher proportion. If the user inputs, 0.5.. the output should be
(X*0.5 + Y*0.5)
and so on. I have no idea how to do this with RGB colors.
P.S: The questions is not specific to language, but I'm doing this in Java.
You have to blend each color channel (red, green and blue) seperately like this:
Color x,y; //set by you
float blending;//set by you
float inverse_blending = 1 - blending;
float red = x.getRed() * blending + y.getRed() * inverse_blending;
float green = x.getGreen() * blending + y.getGreen() * inverse_blending;
float blue = x.getBlue() * blending + y.getBlue() * inverse_blending;
//note that if i pass float values they have to be in the range of 0.0-1.0
//and not in 0-255 like the ones i get returned by the getters.
Color blended = new Color (red / 255, green / 255, blue / 255);
So far for the color example. Generally if you want a linear interpolation between two values you have to do the following:
var firstValue;
var secondValue;
var interpolation;
var interpolated = firstValue * interpolation +
secondValue * (1 - interpolation);
But since you have Color-Objects in your case, you cannot interpolate the whole object in one step, you have to interpolate each relevant value on its own. Eventually you have to interpolate the alpha-channel as well, don´t know that, since you didn´t mention it, but for completeness i include it in this answer.
A color is a point in a three-dimensional space. The exact coordinates used depend on what's called a "color space", of which there are several: RGB, HSV, and so on. So to compute a color in between two given colors, get those two colors in the same color space, and compute a third point between those two along the line in 3d-space between them.
The simplest way to do this would be simply to do a linear interpolation for each of the three values of the colorspace (R, G, and B, for example). But there's a further complication that the coordinate values are often not linear, so you have to linearize them first (for example, TV colors are exponential with a lambda of about 2.2). Depending on your application, incorrectly assuming linearity might work OK anyway, especially if the starting colors are already close.
(As mentioned by luk2302, add a fourth coordinate for alpha if necessary).
You could use Java.awt.color by doing somting like this:
public Color mixColors(Color color1, Color color2, double percent){
double inverse_percent = 1.0 - percent;
int redPart = (int) (color1.getRed()*percent + color2.getRed()*inverse_percent);
int greenPart = (int) (color1.getGreen()*percent + color2.getGreen()*inverse_percent);
int bluePart = (int) (color1.getBlue()*percent + color2.getBlue()*inverse_percent);
return new Color(redPart, greenPart, bluePart);
}

Categories

Resources