If we define a rectangle (x1,y1), (x2,y2) by its top left and bottom right hand corners and assume that all points are integer valued, I would l like to list all points in the union of a number of rectangles.
For one rectangle, the following function returns all the points within it.
def findpoints(x1,y1,x2,y2):
return [(x,y) for x in xrange(x1,x2+1) for y in xrange(y1,y2+1)]
I can find all the points in the union of two rectangles by,
set(findpoints(x1,y1,x2,y2)) | set(findpoints(x3,y3,x4,y4))
However I have a lot of rectangles and this is potentially very inefficient. For example, imagine if all the rectangles were almost identical. Is there a fast way of doing this?
I agree with StoryTeller but I think it is better to write it in more detail so it is understandable even for those of us with poor English skills
compute the minimal rectangle which is the overlapped area of all rectangles to test
x1 = max (rec[i].x1)
y1 = max (rec[i].y1)
x2 = min (rec[i].x2)
y2 = min (rec[i].y2)
i=0,... all rectangles -1
if x1>x2 or y1>y2 then all rectangles do not overlap and so no points are inside
test all points only against this new rectangle (x1,y1,x2,y2)
if (x>=x1) and (x<=x2) and (y>=y1) and (y<=y2) then point(x,y) is inside
Related
After edge detection of an image, I have a list of point that make arbitrary shape, but i want to eliminate those that dont contribute to a rectangle shape. In the following example picture, the two points in the bottom left (E, F) should be removed, so the shape of the remaining points is almost a rect (since D is a little above, it give a trapezoid shape, but it is not significant)
I thought of brute force all points and compare their area, but it is not guarranteing of being a rect. But i dont know how to implement this in python.
If someone has a better approach i'd like to hear it please.
Thanks in advance.
p = [ (8,133), (78,13), (242,89), (183,217), (217,235), (213,240) ]
The best approach you can follow is using Slope
The mathematical formula for the slope of a given line is shown below.
m = (y2-y1)/(x2-x1)
so for example: if the slope of (8,133),(78,13) is equal to (242,89),(183,217) this means we have 2 parallel lines, then we have a rectangle, but this doesn't mean that the 4 points on the 4 corners. however, they would be within 2 sides of a rectangle.
If you want to make sure they are on the 4 corners you can compute the slope of (8,133)(183,217) and the slope of (78,13)(242,89), then compare them, if they are equal, then you have 4 corners points of a rectangle.
backing to the code
first, you are going to need all possible combinations of length 4 of all the points, to accomplish this use combinations from itertools
from itertools import combinations
p = [(8,133), (78,13), (242,89), (183,217), (217,235), (213,240)]
possible_combinations = []
for comb in combinations(p, 4):
possible_combinations.append(comb)
after that apply the above algorithm to each combination to get your rectangle.
two scenarios
I have an x axis size, a y axis size, a render distance, a list of grid position numbers and a central grid position.
I am trying to create a list of all the grid positions within the render distance of a central grid position.
The size of the x and y axis may be different independently. Optimally this algorithm would not attempt to get positions where the render distance extends over the side of the x or y axis.
Thanks.
I'm writing this to help you answer your own question in the style that I would go about it. As with anything in coding, what you need to do is be able to break down a big problem into multiple smaller ones.
Design two functions to convert to and from (x, y) coordinates (optional, it'll make your life easier, but won't be as efficient, personally I would avoid this for a bit of a challenge).
Given n, size and distance, calculate up, down, left and right. If the size is different for different axis, then just provide the function with the correct one.
eg.
def right(n, size, distance):
return n + size * distance
def down(n, size, distance):
return n - distance
Given size, make sure the above functions don't go off the edge of the grid. Converting the points to (x, y) coordinates for this part may help.
Now you have the sides of the square, run the functions again to get the corners. For example, to get the top right corner, you could do right(up(*args)) or up(right(*args))
With the corners, you can now calculate what's in your square. Converting the points to (x, y) coordinates will make it easier.
Sorry if the title doesn't make it clear.
Here is the more detailed situation.
Given n dots and n rectangles.
Rectangles can overlap.
Dots are represented as (x,y)
Rectangles are represented as (x,y,w,h)
x,y refer to location in x and y axes, respectively
w,h refer to width and height, respectively
How do i check if the following two conditions are met simultaneously:
each dot falls in a certain rectangle (doesn't matter which)
AND
each rectangle contains at least one dot.
Is there a better way instead of iterating through each dot and each rectangle?
It would be best if you can show me how to do this in python.
Thanks!
I think you can use what is called oriented surfaces created by the mathematician Gauss i believe. this allows you to calculate any polygon area. Using the point to test as a fifth point and one other rectangle point as sixth point (duplicate) you can calculate a new area for this new six-side polygon. You will obtain the same area or a bigger area depending on the point position compared to the rectangle.
Addendum
The oriented surfaces allows you to calculate the area of any polygon when knowing their coordinates. The polygon must be defined as a set of points P(Xp,Yp) in the specific order describing the contour. Two consecutive points will be connected by a line.
In the picture below the polygon can be defined as the set [A,B,C,D], but also as [C,D,A,B] or [B,A,D,C].
It cannot be defined as [A,C,B,D] since this would define a polygon shaped like a butterfly wings as shown below.
Oriented Surfaces
For each couple of ordered successive point - meaning [A,B], [B,C], [C,D], [D,A] for the defined set [A,B,C,D] for example - the formula allows us to calculate the area of the triangle formed by a couple and the axis origin. This surface is oriented - meaning it has a positive or a negative value - according to the rotation (clockwise or counter-clockwise). In the figure below the triangles (OAB) and (OBC) and (ODA) will have a negative area, while the triangle (OCD) will have a positive area. By adding all those area, one can notice that the result will be the area of polygon (A,B,C,D), which is negative because it is drawn clockwise.
Calculations
You can find a clear example of the calculations and try a few things here: https://www.mathopenref.com/coordpolygonarea.html. To complete my example I have drawn a polygon similar (but not identical) to the ones above on this website and the result is as follow: -22
Adding a point
When you add a point, which is the point you want to test, you will obtain a 5-point polygon. The first thing you have to do is to place it in the correct order so that you don't have segments crossing. To do that you can create loop where the new point P is placed successively at the different positions in the set - meaning (PABCD), then (APBCD), etc until (ABCDP)- and calculate for each the area. The set giving you the maximum area in absolute value is the one you keep.
Here is an example from the website https://rechneronline.de/pi/simple-polygon.php. The first polygon is the initial, the second is badly defined and the last one is correctly defined.
One can see that that if the added point is outside the original polygon then the area is increased. At the opposite, if the added point is inside the original polygon, the area is decreased:
Note
If the original point set is not ordered correctly, you will have to reorder it as described just above
In Python you will have to use ordered object such as a list
To check that each rectangle has at least a point inside, you will have to check each point against all rectangles and maintain a dictionary describing which point is inside which rectangle
Adding: I also realized that since a rectangle is convex it is possible to know whether a point P is inside by just checking the four oriented triangle area in order namely (ABP) (BCP) (CDP) and (DAP). If those four area have the same sign then P is inside the rectangle (ABCD), otherwise it is outside.
I am trying to estimate the value of pi using a monte carlo simulation. I need to use two unit circles that are a user input distance from the origin. I understand how this problem works with a single circle, I just don't understand how I am meant to use two circles. Here is what I have got so far (this is the modified code I used for a previous problem the used one circle with radius 2.
import random
import math
import sys
def main():
numDarts=int(sys.argv[1])
distance=float(sys.argv[2])
print(montePi(numDarts,distance))
def montePi(numDarts,distance):
if distance>=1:
return(0)
inCircle=0
for I in range(numDarts):
x=(2*(random.random()))-2
y=random.random()
d=math.sqrt(x**2+y**2)
if d<=2 and d>=-2:
inCircle=inCircle+1
pi=inCircle/numDarts*4
return pi
main()
I need to change this code to work with 2 unit circles, but I do not understand how to use trigonometry to do this, or am I overthinking the problem? Either way help will be appreciated as I continue trying to figure this out.
What I do know is that I need to change the X coordinate, as well as the equation that determines "d" (d=math.sqrt(x*2+y*2)), im just not sure how.
These are my instructions-
Write a program called mcintersection.py that uses the Monte Carlo method to
estimate the area of this shape (and prints the result). Your program should take
two command-line parameters: distance and numDarts. The distance parameter
specifies how far away the circles are from the origin on the x-axis. So if distance
is 0, then both circles are centered on the origin, and completely overlap. If
distance is 0.5 then one circle is centered at (-0.5, 0) and the other at (0.5, 0). If
distance is 1 or greater, then the circles do not overlap at all! In that last case, your
program can simply output 0. The numDarts parameter should specify the number
of random points to pick in the Monte Carlo process.
In this case, the rectangle should be 2 units tall (with the top at y = 1 and the
bottom at y = -1). You could also safely make the rectangle 2 units wide, but this
will generally be much bigger than necessary. Instead, you should figure out
exactly how wide the shape is, based on the distance parameter. That way you can
use as skinny a rectangle as possible.
If I understand the problem correctly, you have two unit circles centered at (distance, 0) and (-distance, 0) (that is, one is slightly to the right of the origin and one is slightly to the left). You're trying to determine if a given point, (x, y) is within both circles.
The simplest approach might be to simply compute the distance between the point and the center of each of the circles. You've already done this in your previous code, just repeat the computation twice, once with the offset distance inverted, then use and to see if your point is in both circles.
But a more elegant solution would be to notice how your two circles intersect each other exactly on the y-axis. To the right of the axis, the left circle is completely contained within the right one. To the left of the y-axis, the right circle is entirely within the left circle. And since the shape is symmetrical, the two halves are of exactly equal size.
This means you can limit your darts to only hitting on one side of the axis, and then get away with just a single distance test:
def circle_intersection_area(num_darts, distance):
if distance >= 1:
return 0
in_circle = 0
width = 1-distance # this is enough to cover half of the target
for i in range(num_darts):
x = random.random()*width # random value from 0 to 1-distance
y = random.random()*2 - 1 # random value from -1 to 1
d = math.sqrt((x+distance)**2 + y**2) # distance from (-distance, 0)
if d <= 1:
in_circle += 1
sample_area = width * 2
target_area = sample_area * (in_circle / num_darts)
return target_area * 2 # double, since we were only testing half the target
In Python, how would one find all integer points common to two circles?
For example, imagine a Venn diagram-like intersection of two (equally sized) circles, with center-points (x1,y1) and (x2,y2) and radii r1=r2. Additionally, we already know the two points of intersection of the circles are (xi1,yi1) and (xi2,yi2).
How would one generate a list of all points (x,y) contained in both circles in an efficient manner? That is, it would be simple to draw a box containing the intersections and iterate through it, checking if a given point is within both circles, but is there a better way?
Keep in mind that there are four cases here.
Neither circle intersects, meaning the "common area" is empty.
One circle resides entirely within the other, meaning the "common area" is the smaller/interior circle. Also note that a degenerate case of this is if they are the same concentric circle, which would have to be the case given the criteria that they are equal-diameter circles that you specified.
The two circles touch at one intersection point.
The "general" case where there are going to be two intersection points. From there, you have two arcs that define the enclosed area. In that case, the box-drawing method could work for now, I'm not sure there's a more efficient method for determining what is contained by the intersection. Do note, however, if you're just interested in the area, there is a formula for that.
You may also want to look into the various clipping algorithms used in graphics development. I have used clipping algorithms to solve alot of problems similar to what you are asking here.
If the locations and radii of your circles can vary with a granularity less than your grid, then you'll be checking a bunch of points anyway.
You can minimize the number of points you check by defining the search area appropriately. It has a width equal to the distance between the points of intersection, and a height equal to
r1 + r2 - D
with D being the separation of the two centers. Note that this rectangle in general is not aligned with the X and Y axes. (This also gives you a test as to whether the two circles intersect!)
Actually, you'd only need to check half of these points. If the radii are the same, you'd only need to check a quarter of them. The symmetry of the problem helps you there.
You're almost there.
Iterating over the points in the box should be fairly good, but you can do better if for the second coordinate you iterate directly between the limits.
Say you iterate along the x axis first, then for the y axis, instead of iterating between bounding box coords figure out where each circle intersects the x line, more specifically you are interested in the y coordinate of the intersection points, and iterate between those (pay attention to rounding)
When you do this, because you already know you are inside the circles you can skip the checks entirely.
If you have a lot of points then you skip a lot of checks and you might get some performance improvements.
As an additional improvement you can pick the x axis or the y axis to minimize the number of times you need to compute intersection points.
So you want to find the lattice points that are inside both circles?
The method you suggested of drawing a box and iterating through all the points in the box seems the simplest to me. It will probably be efficient, as long as the number of points in the box is comparable to the number of points in the intersection.
And even if it isn't as efficient as possible, you shouldn't try to optimize it until you have a good reason to believe it's a real bottleneck.
I assume by "all points" you mean "all pixels". Suppose your display is NX by NY pixels. Have two arrays
int x0[NY], x1[NY]; initially full of -1.
The intersection is lozenge-shaped, between two curves.
Iterate x,y values along each curve. At each y value (that is, where the curve crosses y + 0.5), store the x value in the array. If x0[y] is -1, store it in x0, else store it in x1.
Also keep track of the lowest and highest values of y.
When you are done, just iterate over the y values, and at each y, iterate over the x values between x0 and x1, that is, for (ix = x0[iy]; ix < x1[iy]; ix++) (or the reverse).
It's important to understand that pixels are not the points where x and y are integers. Rather pixels are the little squares between the grid lines. This will prevent you from having edge-case problems.