Given a triangle with vertice A, B and C in 3D world and a axis-aligned bounding cuboid with length*width*height=nd*md*ld(n, m, l are integers and d is float) containing it, partition the cuboid into n*m*l cubes and how to find the cubes passed through by the triangle?
There are many algorithm to detect whether a triangle and a cube intersect. Loop over all cubes the problem can be solved. However, the complexity of this approach is O(n*m*l) or O(n^3). Is there an approach with complexity O(n^2) or even O(nlogn)?
You cannot improve upon O(n m l) for the following reason: select m=1 and l=1.
Then one has a planar arrangement of n cubes, and your triangle could intersect every one. If you need to report each cube intersected, you would have to report all n cubes.
But clearly this is just a flaw in your problem statement. What you should ask is the situation where n=m=l. So now you have an n x n x n set of cubes, and one triangle can only intersect O(n^2) of them.
In this case, certainly a triangle might intersect Ω(n^2) cubes, so one cannot
improve upon quadratic complexity. This rules out O(n log n).
So the question becomes: Is there a subcubic algorithm for identifying
the O(n^2) cubes intersected by a triangle? (And one may replace "triangle"
with "plane.")
I believe the answer is Yes. One method is to construct an octree representing
the cubes. Searches for "voxels" and "octree intersection" may lead you
to explicit algorithms.
Related
I need to quickly find the k nearest points to a plane (or hyperplane) in 3 (or more) dimensions. Is there a fast way to perform this search, using some sort of clever data structure (similar to how a kd-tree works for k nearest neighbors)?
I know I can rotate the plane and all the points so that the plane is orthogonal to one of the axes, then measure the distance of each point to the plane by simply using the ordinate in that axis. However, the time complexity of this brute force approach is O(N), where (N) is the number of points. Since I have to find the k nearest neighbors for a large number of planes and a large number of points, I need to find a faster algorithm if possible.
I think you can simply use any spatial data structure (kd-tree, R-tree, ...) that supports custom distance functions. You should be able to define a distance function that simply uses the distance to the plane instead of distance to a center point.
How to calculate this distance is described by #Spektre.
I have no idea how that scales, because it may depend on the kNN search algorithm used by the implementation.
However, I believe the standard algorithm (Hjaltason and Samet: "Distance browsing in spatial databases.") should at least be better than O(n).
In case you are using Java, the R-Tree, Quadtree and PH-Tree indexes in my TinSpin library all use this algorithm.
measure the distance by using dot product with hyper plane normal... So let:
n - be the hyperplane normal unit vector
p0 - be any point point on the hyperplane
p[i] - be i-th point from your pointcloud i={ 0,1,2...n-1 }
then the distance to hyperplane plane is:
d = |dot( p[i] - p0 , n )|
as you can see no need to transform/align anything and its O(1) without any expensive operations. I expect that any pre sorting of points or using clever structures will be slower than this in most cases...
Now you got 2 options either compute the d for each point and then quick sort which leads to O(n.log(n)) time and O(n) space complexity.
Or remember k closest points on the run leading to O(k*n) time and O(k) space.
So if k is small (k < log(n)) or you have not enough memory to spare use second approach otherwise use first one ...
I've been wanting to build a 3D engine starting from scratch as a coding challenge with the end objective of implementing it on a fantasy console.
The best (i.e. most simple?) way I found was raytracing/raycasting. I haven't found much by looking online for raycasting algorithms, only finding point-in-polygon problems (which only tell me whether a ray intersects a polygon or not, not quite my interest since I wouldn't have info about the first intersection nor I'd have the intersection points).
The only solution I could think of is brute forcing the ray by moving it at small intervals and every time check whether that point is occupied by something or not (which would require having filled shapes and wouldn't let me have 2D shapes since they would never be rendered, although none of those is a problem). Still, it looks way too complex performance-wisely.
As far as I know, most of those problems are solved using linear algebra, but I'm not quite as competent as to build up a solution on my own. Does this problem have a practical solution?
EDIT: I just found an algebric solution in 2D which could maybe be expanded in 3D. The idea is:
For each edge, check whether one of the two vertices are in the field of view (i.e. if O is the origin of every ray and P is the vertex, you have to check first that the point is inside the far point of sight, and then whether the angle with the forward vector is less than the angle of vision). If at least one of the two vertices is inside the field of view, add them to an array E.
If we have an array R of rays to shoot and an array of arrays I of info about hit points, we can loop for each ray in R and for each edge in E and then store f(ray, edge) in I, where f is a function that gives us info on whether the ray and the edge collided and where they did.
f uses basic linear algebra: both the ray and the edge are, for all purposes, two segments. Two segments are just parts of two lines. Let's say that if the edge has vertices A and B (AB is the vector that goes from A to B) and if the far point is called P (OP is the vector that goes from O to P). We can create two lines, r and s, defined by A + ηAB and O + λOP. After we do a check to see whether r and s are parallel (check if the absolute value of the dot product of AB and OP is equal to the norm of AB times the norm of OP), it's trivial to get the values for η and λ.
Now, if η < 0 OR η > 1 we have that the two segments are not colliding.
After we've done this for every ray and every edge, we compare every element in each array i in I to see which one had the lowest λ. The lowest λ carries the first collision and hence the data to show on screen.
Everything here is linear algebra, though I fear that it might still be computationally heavy, since there's a lot going on, and it's still only 2D.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I have this problem: given a set of rectangles {R1,R2...Rn}, and a new rectangle Rq, find where to put Rq so it intersects (it does not matter how much area) the maximum number of the rectangles in the set. I´m searching for a simple resolution not involving too complex data structures, however, any working answer will be very appreciated, thanks!
Here is a O(n^2) or O(n (log n + m)) (average case only) complexity algorithm (where m is the maximum number of intersecting rectangles). See O(n log n) method later on.
The first idea, is to consider that there are n places to look for solutions. That is, for each rectangle Ri, the case where Ri is the right-most rectangle that intersects Rq is a candidate solution.
You will scan from left to right. Adding the rectangles in order of minimum x-coordinate to a buffer container, and also to a priority queue (based on maximum x-coordinate). As you add each rectangle, also check which rectangles need to be removed (based on the priority queue) so that the range of rectangles in the buffer can be intersected by the rectangle Rq if you ignore the y-axis for now.
Before adding each rectangle Ri to the buffer, you can consider how many rectangles in the buffer can be intersected if you require Rq to intersect Ri (with Ri being the right-most intersecting rectangle with Rq). This can be done in linear time.
Thus overall complexity is O(n^2).
The runtime of the algorithm can be improved, by using an interval tree for any rectangle nodes stored in the buffer. Since Wikipedia gives a good amount of information on this, and how it may be implemented, I will not explain how it works here, particularly because the balancing of it can be quite complex. This will improve the average complexity to O(n (log n + m)), where m is the answer - the maximum number of intersecting rectangles (which could still be as large as n in the worst case). This is due to the algorithmic complexity of querying an interval tree (O(log n + m) time per query). The worst case is still O(n^2), because m for the number of results returned (for interval trees), may be up to O(n), even if the answer is not on the order of n.
Here follows a method with O(n log n) time, but is quite complex.
Instead of storing rectangles as a sorted array, self balancing binary search tree (based on only minimum y), or an interval tree, the rectangles can also be stored in a custom data structure.
Consider the self balancing binary search tree (based on maximum y). We can add some metadata to this. Notably, since we try to maximize the rectangles intersected in the buffer, and keep looking for how the maximum changes as the buffer scans from left to right, we can consider the number of rectangles intersected if each rectangle in the buffer is the bottom-most rectangle.
If we can store the number of rectangles that is, we might be able to query it faster.
The solution is to store it in a different way, to reduce update costs. A binary search tree has a number of edges. Suppose each node should know how many rectangles can be intersected if that node is the bottom-most rectangle to be intersected. Instead, we can store the change in the number of rectangles intersected by the nodes on either side of each edge (call this the diff). For example, for the following tree (with min & max y of the rectangles):
(3,4)
/ \
(2,3) (5,6)
For Rq with a height of 2, if (2,3) is bottom-most, we can intersect 2 rectangles in total, for (3,4), it is 2, and for (5,6), it is 1.
Thus, the edges' diff can be 0 and -1, representing the change in the answer from child to parent.
Using the weights, we can quickly find the highest number, if each node also stores the maximum sum of a subpath in its subtree (call this maxdiff). For the leaves, it is 0, but for (3,4), the maximum of 0 and -1 is 0, thus, we can store 0 as the maximum sum of the edges of a subpath in the root node.
We therefore know that the optimal answer is 0 more than the answer of the root node. We can find the answer of the root node, but keeping more metadata.
However, all this metadata can be queried and updated in log n time. This is because when we add a rectangle, adding it to the self balancing binary search tree takes log n time, as we may need to do up to log n rotations. When we do a rotation, we may need to update the weights on the edges, as well as maxdiff on the affected nodes - however this is O(1) for each rotation.
In addition, the effect of the extra rectangle on the diff of the edges needs to be updated. However, at most O(log n) edges must be updated, specifically, if we search the tree by the min y and max y of the new rectangle, we will find all the edges that need to be updated (although whether an edge that is traversed must be updated depends on whether we took the left or right child - some careful working is needed here to determine the exact rule).
Deleting a rectangle is just the reverse, so takes O(log n) time.
In this way, we can update the buffer in O(log n) time, and query it in O(log n) time, for an overall algorithmic complexity of O(n log n).
Note: to find the maximum rectangles intersected in the buffer, we use maxdiff, which is the difference in answer between optimal, and that of the root node. To find the actual answer, we must find the difference between the answer of the lowest ordered rectangle in the binary search tree, and the root node. This is easily done in O(log n) time, by going down the left-most path, and summing up diff on the edges. Finally, find the answer on the lowest ordered rectangle. This is done by storing a 2nd self balancing binary search tree, ordered by minimum y. We can use this to find the number of rectangles intersected if the bottom-most rectangle is the lowest ordered rectangle when sorting by maximum y.
Update of this extra BST and querying also take O(log n) time, so this extra work does not change the overall complexity.
Here's the task I'm trying to solve:
Given a polygon A with N vertices and a polygon B with M vertices, find all intersections between a segment in A and a segment in B.
Both A and B may be non-convex.
So far, I have implemented the obvious solution(check every edge in A with every edge in B, O(M*N)).
Now, for certain polygons it is in fact possible that there are (almost) M*N intersections, so the worst case for any such algorithm is O(M*N).
My question is:
Does there exist an algorithm for determining the points of intersection between two non-convex polygons with complexity in the average case that is lower than O(N*M)
If yes, then please give me the name of the algorithm, if no - some resource that proves it to be impossible.
Excerpt from a paper on the Greiner-Hormann (PDF) polygon clipping algorithm:
... if we have a
polygon with n edges and another with
m edges, the number of intersections
can be nm in the worst case. So the
average number of intersections grows
on the order of O(nm).
There is a
well-known result in computational
geometry based on the plane sweep
algorithm, which says that if there
are N line segments generating k
intersections, then these
intersections can be reported in time
O((N+k) log(N)) [7]. Note that this
relation yields an even worse
complexity in the worst case.
I believe N in the second paragraph is m + n from the first paragraph. The average time depends the average value of k, the number of intersections. If there are only a handful of intersections the time goes to O(N log N).
The reference to the "well-known" result is:
[7] F. P. Preparata and M. I. Shamos.
Computational Geometry: An
Introduction. Texts and Monographs in
Computer Science. Springer, New York,
1985.
Here's a paper on the line sweep algorithm.
Suppose there are a number of convex polygons on a plane, perhaps a map. These polygons can bump up against each other and share an edge, but cannot overlap.
To test if two polygons P and Q overlap, first I can test each edge in P to see if it intersects with any of the edges in Q. If an intersection is found, I declare that P and Q intersect. If none intersect, I then have to test for the case that P is completely contained by Q, and vice versa. Next, there's the case that P==Q. Finally, there's the case that share a few edges, but not all of them. (These last two cases can probably be thought of as the same general case, but that might not be important.)
I have an algorithm that detects where two line segments intersect. If the two segments are co-linear, they are not considered to intersect for my purposes.
Have I properly enumerated the cases? Any suggestions for testing for these cases?
Note that I'm not looking to find the new convex polygon that is the intersection, I just want to know if an intersection exists. There are many well documented algorithms for finding the intersection, but I don't need to go through all the effort.
You could use this collision algorithm:
To be able to decide whether two convex polygons are intersecting (touching each other) we can use the Separating Axis Theorem. Essentially:
If two convex polygons are not intersecting, there exists a line that passes between them.
Such a line only exists if one of the sides of one of the polygons forms such a line.
The first statement is easy. Since the polygons are both convex, you'll be able to draw a line with one polygon on one side and the other polygon on the other side unless they are intersecting. The second is slightly less intuitive. Look at figure 1. Unless the closest sided of the polygons are parallel to each other, the point where they get closest to each other is the point where a corner of one polygon gets closest to a side of the other polygon. This side will then form a separating axis between the polygons. If the sides are parallel, they both are separating axes.
So how does this concretely help us decide whether polygon A and B intersect? Well, we just go over each side of each polygon and check whether it forms a separating axis. To do this we'll be using some basic vector math to squash all the points of both polygons onto a line that is perpendicular to the potential separating line (see figure 2). Now the whole problem is conveniently 1-dimensional. We can determine a region in which the points for each polygon lie, and this line is a separating axis if these regions do not overlap.
If, after checking each line from both polygons, no separating axis was found, it has been proven that the polygons intersect and something has to be done about it.
There are several ways to detect intersection and / or containment between convex polygons. It all depends on how efficient you want the algorithm to be. Consider two convex polygons R and B with r and b vertices, respectively:
Sweep line based algorithm. As you mentioned you can perform a sweep line procedure and keep the intervals resulting from the intersection of the polygons with the sweeping line. If at any time the intervals overlap, then the polygons intersect. The complexity is O((r + b) log (r + b)) time.
Rotating Callipers based algorithm. See here and here for more details. The complexity is O(r + b) time.
The most efficient methods can be found here and here. These algorithms take O(log r + log b) time.
if the polygons are always convex, first calculate the angle of a line drawn from center to center of the polygons. you can then eliminate needing to test edge segments in the half of the polygon(s) 180 degrees away from the other polygon(s).
to eliminate the edges, Start with the polygon on the left. take the line segment from the center of the polygon that is perpendicular to the line segment from the previous bullet, and touches both sides of the polygon. call this line segment p, with vertexes p1 and p2. Then, for all vertexes if the x coordinate is less than p1.x and p2.x That vertex can go in the "safe bucket".
if it doesn't, you have to check to make sure it is on the "safe" side of the line (just check the y coordinates too)
-if a line segment in the polygon has all vertexes in the "safe bucket" you can ignore it.
-reverse the polarity so you are "right oriented" for the second polygon.
GJK collision detection should work.
Since altCognito already gave you a solution, I'll only point out an excellent book on computational geometry that might interest you.
Your test cases should work, since you're checking the case where the polygons don't intersect at all (completely outside or completely inside), as well as where there is any form of partial intersection (edges intersect always if there is overlap).
For testing, I would just make sure to test every potential combination. The one missing above from what I see is a single edge shared, but one poly contained in the other. I would also add tests for some more complex poly shapes, from tri -> many sided, just as a precaution.
Also, if you had a U shaped poly that completely surrounded the poly, but didn't overlap, I believe your case would handle that, but I would add that as a check, as well.
Here's an idea:
Find the center point of each polygon
Find the two points of each polygon closest to the center point of the other. They will be adjacent points in convex polygons. These define the nearest edge of each polygon, let's call the points {A, B} and {Y, Z}
Find the intersection of lines AB and YZ. If the line segments cross (the intersection on AB lies between A and B), your polygons intersect. If AB and XY are parallel ignore this condition, the next step will trap the problem.
There is one more case you need to check for, which is when the polygons intersect heavily enough that AB and XY are completely past each other and don't actually intersect.
To trap this case, calculate the perpendicular distances of AB and XY to each polygons center points. If either center point is closer to the opposite polygon's line segment your polygon overlap heavily.