im trying to draw rectangles of different sizes on a grid for a uni assignment. so what i want to do is drawing and colouring them in blue. but i want to check first if at a given position a rectangle exists. is there a method in the library for this or do i have to develop that method. In the latter case where should i start?
thanks!
Let's say you have an LTRB (left/top/right/bottom) representation for a rectangle. You can check if a point (x,y) is inside the rectangle like so:
boolean pointInRect(int x, int y, int l, int t, int r, int b)
{
return x >= l && x <= r &&
y >= t && y <= b;
}
Note that if you use java.awt.Rectangle, there is a contains method that already does this, though I'm not sure if that would be considered "cheating" or not in the context of a school assignment.
So given a position, you can iterate through a list of rectangles you have (the same ones you draw to the screen) and see which one contains the point/position.
If you want to do this in faster than linear time, you can use, say, a quad-tree or partition your rectangles into a fixed NxM grid. In the latter case, you can just check the rectangles that belong to the same grid cell the mouse cursor is over. That might be overkill for this assignment though.
Edit
After some back-and-forth, I think more helpful to your situation is a test to see if a rectangle overlaps with another.
// Returns true if two solid rectangles intersect.
bool rectIntersect(int l1, int t1, int r1, int b1,
int l2, int t2, int r2, int b2)
{
return l1 <= r2 && r1 >= l2 &&
t1 <= b2 && b1 >= t2;
}
Using this function, whenever you want to add a new rectangle, you can loop through the existing rectangles you have and see if any one of them intersect the new one you're trying to add. This isn't the most efficient approach, but it should give you the desired behavior.
Related
This is my solution to this question:
Given a circle represented as (radius, x_center, y_center) and an
axis-aligned rectangle represented as (x1, y1, x2, y2), where (x1, y1)
are the coordinates of the bottom-left corner, and (x2, y2) are the
coordinates of the top-right corner of the rectangle.
Return True if the circle and rectangle are overlapped otherwise
return False.
In other words, check if there are any point (xi, yi) such that
belongs to the circle and the rectangle at the same time.
class Solution {
public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
for(int i=x1; i<=x2; ){
for(int j=y1; j<=y2; ){
System.out.println((Math.pow(i-x_center, 2) +" "+ Math.pow(j-y_center, 2))+" "+Math.pow(radius, 2));
System.out.println(i+" "+j);
if((Math.pow(i-x_center, 2)+Math.pow(j-y_center, 2))<=Math.pow(radius, 2)){
return true;
}
j += 1;
}
i += 1;
}
return false;
}
}
I am pretty confident that the logic is correct. Ranging from the bottom left corner of the rectangle to the top right point, for every point, I am checking if it lies inside the circle.
If I increase the increment step to anything beyond '1', I see that the code fails for the test cases where the rectangle and circle just 'touch' each other. But having it this way leads to exceeding the time limit in some cases. How do I optimize the code for this logic?
Thanks in advance.
This problem can be simplified. I've found a solution of time complexity O(1) and memory complexity O(1). Instead of checking for every single pixel from the rectangle, you can even only take into consideration the bounds themselves.
As I see it, there are 3 cases:
Circle is fully inside rectangle.
Rectangle is fully inside circle
Circle and rectangle outlines intersect in at least one point. This is the tougher one.
I'll call center of the circle coordinates x0 and y0.
You can simply check the bounding box for the circle, as in, which is the northern most point of the circle(x0,y0-radius), which is the southern-most point of the circle(x0,y0+radius), eastern-most(x0-radius,y0) and western-most(x0+radius,y0). If they all fall within the rectangle, then problem solved.
If a rectangle is fully within a circle, that definitely means that its corners are at a smaller distance from the center of the circle than the radius. Simply check this distance for each corner.
Now comes the hard part.
So, as you have figured out, being in a circle(or intersecting one) means that some point must be at a smaller or equal distance from the center than the radius.
However, we can do an optimization for the rectangle checking part, too. Intersection with a rectangle likely means intersection with at least one of the segments that make the outline of the rectangle. So, in the case of an intersection between a rectangle and a circle, you need to check if there is any segment that would be at a smaller or equal distance from the center of the circle than the radius.
Edit: Also, the reason that your code fails on tests where they barely touch is likely due to floating-point errors. Do not use == (or in this case <=, which is similar) for checking if two floating point(or even a floating-point and integer) values are the same. Math.pow() in Java returns double. Just use normal multiplication for squaring.
In fact, you might want to stay as far from floating-point as possible, unless you can't figure out how to get rid of them and the problem says "0.001 error is acceptable" or something around the lines. They are both slow and prone to errors.
Edit 2: Also, I've written the code to help you aid in understanding this explanation. I've tested it on the site, it works for every test with runtime 1ms and memory usage 37.7Mb.
class Solution {
public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
//case 1: circle is fully inside rectangle
//check the bounding box of the circle against the rectangle
if(x_center-radius>=x1&&y_center-radius>=y1
&&x_center+radius<=x2&&y_center+radius<=y2
)
return true;
//case 2: checking closest corner against circle bounds
int minX=(Math.abs(x_center-x1)>Math.abs(x_center-x2))?(x_center-x2):(x_center-x1);
int minY=(Math.abs(y_center-y1)>Math.abs(y_center-y2))?(y_center-y2):(y_center-y1);
if(minX*minX+minY*minY<=radius*radius)
return true;
//case 3: checking distances to segments against circle bounds
//Checking distance from a segment to a point is alike checking
//the distance from the line the segment is part of to a point,
//except you have to check if the closest point from the segment
//is actually on the segment. If it isn't, the distance from a
//segment to a point is the minimum distance from one of its
//corners to the point.
if(x1<=x_center&&x_center<=x2)
if(minY*minY<=radius*radius)
return true;
if(y1<=y_center&&y_center<=y2)
if(minX*minX<=radius*radius)
return true;
return false;
}
}
This code could be possibly shortened. However, time complexity-wise, it can't get better than O(1).
I have the following situation, for illustrative purposes split into 2 situations.
The green rectangle in the middle is the rectangle that I am referring to as my base, since it is the rectangle that is constant.
Now I'd like to know if a yellow rectangle is intersecting, is inside or fully encapsulates the green rectangle.
I've seen this post and understand it, but (unless I forget something) it ignores the case of a yellow rectangle being inside the green rectangle. The simplest solution I can think of is to double check the 4 points in either order, but is that the only("best") solution?
Two rectangles A, B have a non-empty intersection iif
A.l < B.r and A.r > B.l and A.t < B.b and A.b > B.t
(left, right, top, bottom coordinates, y downward).
A wholly contains B iif
A.l <= B.l and A.r >= B.r and A.t <= B.t and A.b >= B.b
In Java, I have a function like this:
public void setPixel(int x, int y, boolean on);
It sets a virtual black and white pixel, given whether it is on or not.
How can I call this function so the resulting display will be four times larger?
I tried this:
int x = 3;
int y = 3;
setPixel(x, y, true);
setPixel(x+1, y+1, true);
setPixel(x+2, y+2, true);
setPixel(x+3, y+3, true);
But naturally, it overlapped when I tried to draw something. How should I call the method?
While I'm tagging this Java, the concept could apply to any language.
Answering on these assumptions: setPixel sets a single pixel to white or black (if on is true, to black, else to white). You want to use this function to get a B&W image and make it four times larger. The code you provided is wrong and just makes a diagonal instad of a 4x4 block. Is this correct? If so:
A way to draw a 4 times larger image would then be, for example, to have a "getPixel(x,y)" which gets you whether the pixel at (x,y) is on in the original image and then start painting somewhere else in 4x4 blocks. Whenever you move by one pixel in either X or Y direction when getting the values of your original image, you move by 4 in your new image to scale. So then what you intended to do maybe was something like this?
void setBlock(int x, int y, boolean on, int scale)
for(int i=0; i < scale; i++){
for(int j=0; j < scale; j++){
setPixel(scale*x + i, scale*y + j, on);
And then iterate over your original image's coordinates doing something like this?
setBlock(x, y, getPixel(x, y), 4);
I figured out how to drag to highlight multiple cells in a GridLayout-designed grid (which wasn't too hard) and how to drag a cell from one such grid to another (which involved brute force and math, but it turned out not to be all that hard, either).
But the code looks and feels hacked.
How should I have done it?
Here are code fragments that typify what I did to drag content (one char):
For each cell in txtUser[] grid add mouse listener to identify the cell about to be dragged and also access its content:
txtUser[i].addMouseListener(new java.awt.event.MouseListener()
{
public void mousePressed(MouseEvent e) {
currentUserCell.index = interp(e.getXOnScreen(), ulcUser.x, txtUser[0].getWidth());
if(txtUser[currentUserCell.index].getText().length() > 0)
currentUserCell.content = txtUser[currentUserCell.index].getText().charAt(0);
}
Here's interp(), which converts from absolute screen pixel (x) to (returned) grid element number, given the upper-left corner of the text field array and the width of one element:
static int interp(int x, int ulc, int w){
return (x - ulc)/w;
}
If the user moves the frame, interp() above doesn't work, requiring need to reorient():
void reorient(){
ulcGrid = new Point(cells[ 0][ 0].getLocationOnScreen().x, cells[ 0][ 0].getLocationOnScreen().y);
ulcUser = new Point(txtUser[ 0] .getLocationOnScreen().x, txtUser[ 0] .getLocationOnScreen().y);
}
(I tried to use relative pixel locations, but couldn't make it work. I may revisit this.)
In order to drop the dragged content, the destination had better be inbounds():
boolean inbounds(int r, int c){
return ! (r >= N || c >= N || r < 0 || c < 0);
}
If inbounds, the letter is dropped, as long as destination is empty:
public void mouseReleased(MouseEvent e) {
int x, y;
if(! dragging)
return;
dragging = false;
x = e.getLocationOnScreen().x;
y = e.getLocationOnScreen().y;
int c = Utilities.interp(x, ulcGrid.x);
int r = Utilities.interp(y, ulcGrid.y);
if(! inbounds(r, c))
return;
if(cells[r][c].getText().length() > 0)
return;
cells[r][c].setText("" + currentUserCell.content);
The previous method required a MouseMotionAdapter for each cell of the source array.
And it just seems so hacked. One reason I say this is that I rely on several global variables, such as ulcGrid and ulcUser and currentUserCell and dragging:
private void txtUserMouseDragged(MouseEvent evt)
{
dragging = true;
}
I had a nice learning experience, but I'd rather have more-professional-looking code, most notably with fewer global variables. (I realize that a good start would be to not rely on absolute pixel addresses.)
So I'm asking where to find a better way, specifically how to identify the drag source and destination cells of a one- or two-dimensional array of text fields.
=================
--EDIT--
My program works. My question is about whether there is a library that would make it easier and more reliable than what I've written to drag from the one-dimenional array at the bottom of the screen below onto the large grid.
But now that I've read the comments, maybe this is just another bad question that should be deleted.
I'm trying to determine whether two rectangles border each other. If they share an edge or part of an edge, then I want to include them, if they only share a vertice then I don't.
I've tried using android android.graphics.Rect, I was hoping that the intersect method would return true giving me a rectangle, with 0 width but the points of the intersecting edge. I'm using andEngine and also tried the collideswith method of org.andengine.entity.primitive.Rectangle however that returns true, even if the rectangle only share one corner vertice.
Is there a nice way of doing this? The only other way I can think of is to try and create a collection of all the edges then see if they're equal or are in someway partly equal.
Here's an image to demonstrate what I want. If I click on rect 1 then I want to return rects 2,3 and 4, but not 5.
"Map":
It sounds like you need a new class to do this. I would take the coordinates of each corner of the rectangles. Then, when you are selecting a rectangle, you can get those adjacent to it by finding them one side at a time. Starting with the top for an example, you check which other rectangles have corners at the same height. From that list, you check to see which ones exist on at least one point between the two top corners. So, if top left is 0,3 and top right is 4,3 then you would look for the list of corners at y=3. From that list you find all corners where 0<=x<=4 and anything that fits will be adjacent. You then do the same thing for each additional side. It should be an easy class to make, but I am not going to write any code as I do not know anything about how you stored your data or how you would reference this in your code. If you need help with that, write a comment.
Write a function to find which rectangles share edges with rectangles within all considered rectangles.
Then, map these rectangles which share edges to one another. An Adjacency List is just a way of representing a graph in code.
Sometimes code is easier to understand, so here's code. I have not tested this, but it should get you most the way there.
Also, I'm not sure what you're end goal is here but here's a question I answered that deals with rectangular compression.
List<Rectangle> allRectangles;
public boolean shareAnEdge(Rectangle r1, Rectangle r2){
int y1 = r1.y + r1.height;
int y2 = r2.y+r2.height;
int x1 = r1.x+r1.width;
int x2 = r2.x+r2.width;
boolean topShared = (y1 == r2.y && r2.x == r1.x);
boolean bottomShared = (y2 == r2.y && r2.x==r1.x);
boolean rightShared = (x1 == r2.x && r2.y==r1.y);
boolean leftShared = (x2 == r1.x && r2.y==r1.y);
if (topShared || bottomShared || rightShared || leftShared) {
return true;
}
return false;
}
public List<Rectangle> findSharedEdgesFor(Rectangle input){
List<Rectangle> output = new List<Rectangle>();
for(Rectangle r : allRectangles){
if(r!=input && shareAnEdge(r, input)){
output.add(r);
}
}
}
public AdjacencyList createGraph(List<Rectangle> rectangles){
AdjacencyList graph = new AdjacencyList();
for(Rectangle r : rectangles){
List<Rectangle> sharedEdges = findSharedEdgesFor(r);
for(Rectangle shared : sharedEdges){
graph.createEdgeBetween(r, shared);
}
}
}