Find the intersection between line and grid in a fast manner - c#

Is there anyway that allows me to find all the intersection points between a line and a grid? ( The intersection circles are not drawn to scale with each other, I know)
A brute force way is to compute very intersection for the x-y grid with the line, but this algorithm is awfully inefficient (O(m*n), where m is the number of x grid and n is the number of y grid).
I'm looking for a better algorithm on this.

Sounds like you need a Digital Differential Analyzer or Bresenham's line algorithm. Bresenham is the same algorithm used to draw lines on a bitmap; in this case, coloring a pixel is equivalent to checking for collisions in that square.

I'm not sure I really understand the question. Is this what you're looking for by any chance?

If the grid is axis aligned:
find out the line equation
calculate the intersection points
directly using either the grid
line's x or y as a fixed variable
If the grid is regular, the distance between the intersections with each horizontal line will be the same. The same also goes for the vertical lines. You could just do a simple iterative algorithm with dx and dy in that case.

Algorithm:
The grid consists out of walls.
A wall is of/in a certain dimension: (Vertical, Horizontal, Depth)
The wall dimensions intersect forming cells (in final dimension)
The line intersects the walls primarly in their own dimension.
The solution is to view the problem as: How to intersect a line with a wall in it's own dimension.
The solution is to slide across the line from wall to wall, switch dimensions as necessary.
The sliding across the line happens such that the nearest wall is always chosen as the next destination.
The sliding from wall to wall in it's own dimension is constant/always the same.
The intersection of the line and the walls is different per dimension.
This ultimately decides the order of the wall intersections.
The solution is therefore to:
Phase 1: Initialization
Compute Dimension.IntersectT
Compute Dimension.SlideT
Phase 2: Start sliding from origin towards destination selecting nearest wall:
Dimension.T := Dimension.IntersectT
while ? end condition ?
Select smallest Dimension.T
Update selected Dimension.T += Dimension.SlideT
end
The difficulty lies in computing the Ts.
Bye,
Skybuck.

Related

How to check the highest object's highest point on the y axis

I'm still making the game about tower building using Unity and now I have problem that have haunted me for about week now.
Game mechanic for losing is that there is line which goes up at a certain speed and when it goes above the tower, game should end. I'm wondering is there any way of checking highest objects highest point(because of rotated objects and irregularly stacked objects)?
There's a few ways to achieve this:
1) You can shoot a bunch of rays down from high up in the sky. Find all the hit.point positions and then loop through the points and store which building is the highest.
2) Another would be for each block of your building that is added - keep it as a child of an Empty Building gameObject. Then all you need to do is see which Building gameObject has the most children and you know it's the tallest. This assumes all blocks are the same size in Y and then you can easily calculate the height with highestChildCount * blockSizeY
3) Another way to do it would be to use the point in the line that is traveling up. Shoot a ray out of that point to the left and right. If it is hitting a building then the game continues. If it doesn't hit anything the game is over. This is the simpliest as it doesn't require calculation of any heights and your buildings can be made any way you like as long as they have colliders on it for the ray to hit. <--- This is likely the best method for what I'm hearing you asking.
(Note. I might have some spelling mistakes in the naming of methods so proofread before copy-pasting)
Since your are using a line, you might want to find the bounding box of an object. I have never tried the bounding box method so it might not work. The second method uses a little bit of math. If your line is vertical, then finding the highest point is easy. All you need to do is find the y position of the object and add half the y-scale to find the highest point. Note it will only work if the transform origin of the object is at the center. If the origin is at the bottom of the line you will have to add the full y-scale value. If its one third the way up, then only 2 thirds the y-scale value. I think you get the idea. This rule apples for the next condition too. If your line is at an angle, this is where it gets a little bit more complicated. We need to find the absolute value of the rotation in which the line is rotated at. Make sure the line is rotated at less than a 90 degree angle from being vertical. After this, we need to know the length of the line. Imagine a right triangle that the line itself is the hypotenuse, the base is the distance between the farthest left point of the line to the farthest right on the line(or other way around), and the distance from the lowest point of the line to the highest point of the line being the actual height of the triangle. Since we know the angle the line is rotated at and the length of the line, we need to figure out the ratio between the side opposite to the angle that represents the rotation the the hypotenuse(aka the length of the line) and the hypotenuse. This always stays the same if the rotation is the same for all right triangles. Because of this why use mathf.sin(), the rotation of the line. Remember to convert the rotation value(which is stored in degrees) to radians. This can be done by multiplying the rotation value by mathf.deg2rad. Once we know the sin, we multiply the length by the sin value that is outputted. Now we know how long the distance from the bottom to the top of the line is. Again, if the origin is the middle we add the y-position to half the value we get from the previous calculations. If it is in the bottom then the y-position plus the whole value we get from the previous calculations. Same rule as before. I am also quite new to Unity, only a little over a year of experience so there may be fallacies in my answer. Hope it helps. :)

Get the distance covered from a curve line?

Sorry for the newbie question. I want to create a curve way point line that the player will travel or move to by dragging, my question is how to know the total distance covered by the player based on the total length of the curved line? I can compare it as a Canvas slider UI with a value of 0 to 1 but instead of a straight, it can be a curved line.
The distance over a straight line is trivial, but in a general case, a curved line is not. To approximate distance over a curve the typical approach is to pick a smallish step, and iterate over your curve and sum partial distances for each step. The smaller the step the better the aproximation

c# how to detect intersecting circles as separate from edgepoints

I am trying to create a 2(or more) circles from a list of edgepoints which is sorted. A egdepoint is just a point. A list of edgepoints make the edge of a circle. Drawing a line between the edgepoints gives the black line in the pictures. So there is no radius and circles can vary in size.
It looks like this:
My idea is to split it like picture 2. Next, create circles like in this article. Ofcourse with the fist, middle and last point.
I created a method to detect whether the edgepoints are sorted clockwise or counter clockwise. Unfortunately I am stuck on how to detect these "split points" The picture can be rotated ofcourse.
The result should be 2(or more) list with edgepoints:
So how can I detect these "split points"? Or is there a better way to detect intersecting circles as separate?
Input: Something like Point[]. Output: Something like List[Circle]
Assume input is sorted by position around the outer edge of some picture that is made up of overlapping circles. Any points in the interior of the picture are not included.
I thought about it more and I think you can find the points easier if you consider slope. Points where the slope varies wildly are the points you are looking for.
[Revised thought - Find the transition points first, then the circles.]
Start by using a function to calculate the slope of a line segment between two points. As you go around a circle, you will have a reasonable change in slope (you will have to discover this by reviewing how close the points are together). Say you have points like { A, B, C, D, ...}. Compute the slope of A->B and B->C. If the points are evenly spaced, that difference or the average difference might be a tolerance (you have to be careful of transition points here - maybe compute an average over the entire set of points). If at some point the slope of K->L and L->M is very different from J->K and K->L then record that index as a transition point. Once you have traversed the whole set (include a test for Y->Z and Z->A as well if it is a closed shape), the recorded indexes should define the transition points. Use the mid-point of each segment as the third point for each circle. (e.g. if you identified I and M as transition points, then use I, K, and M to define a circle).
[Original thought - find the circles first]
Use the referenced article to determine the center of a circle based on three points. Then determine if it is really an interesting circle by testing some of the points around the reference points. (Say, pick every 5th or 10th point then verify with all the interior points). With more overlapping circles, this becomes a less effective process so you will have to define the algorithm carefully. Once you get all the reference circles, process through all of the edge points (assuming these are points on the exterior of the drawing). Using center, radius, a distance formula, and a tolerance, determine which points are on which circle. Points that fit the tolerance on more than one circle are the points you are looking for I think.

How to sort found chessboard corners?

I have a question about sorting found corners from chessboard.
I'm doing my program in C# using OpenCVSharp.
I need to sort found corners which are points described by X and Y.
This is the part of my code:
...
CvPoint2D32f[] corners;
bool found = Cv.FindChessboardCorners(gray, board_sz, out corners, out corner_count,
ChessboardFlag.NormalizeImage | ChessboardFlag.FilterQuads);
Cv.FindCornerSubPix(gray, corners, corner_count, new CvSize(11,11), new CvSize(-1,-1),
Cv.TermCriteria(CriteriaType.Epsilon | CriteriaType.Iteration, 30, 0.1));
Cv.DrawChessboardCorners(img1, board_sz, corners, found);
...
After that I'm displaying found corners in ImageBox:
see good order in all pictures
and this is the order of corners what I need always, but when I rotate the chessboard a bit - found corners changes like this:
see bad order in all pictures
I need always the same (like in picture 1) order of these points so I decided to use:
var ordered = corners.OrderBy(p => p.Y).ThenBy(p => p.X);
corners = ordered.ToArray();
but it doesn't work like I want:
see bad result 1 in all pictures
see bad result 2 in all pictures
The main point is that my chessboard won't be rotated too much, just for a little angle.
The second point is that the corners must be ordered from the first white square on the top left side of the board.
I know, that the base point (0,0) is on the left top corner of the image and the positive values of Y are increasing in the direction to the bottom of image and positive values of X are increasing in direction to the right side of image.
I'm working on the program to obtain this ordering (these pistures are edited in picture editor):
see example 1 in all pictures
see example 2 in all pictures
Thanks for any help.
Please find below some examples for how OpenCV's findChessboardCorners might return the corner point list and how drawChessboardCorners might display the corners.
For more clarity the order of indices of the subscribing quadrilateral is added as 0,1,2,3.
Basically there are 4 possible rotations of the result leading to the initial red marker being either:
topLeft
topRight
bottomLeft
bottomRight
So when you'd like to resort you can take this knowledge into account and change the order of indices accordingly. The good news is that with this approach you don't have to look at all the x,y values. It's sufficient to compare the first and last value in the list to find out what the rotation is.
To simplify the sorting you might want to "reshape" the list to an array that fits the chesspattern that you supplied to findChessBoardCorners in the fist place e.g. 9x9. In Python numpy there is a function for that i don't know how this would be done in C#.
Work on straightened points. Determine the slope of the image, for instance by taking the difference of the upper right and upper left points. See Rotation (mathematics). Instead of taking the cos you could as well take -diff.Y (the minus because we want to rotate back) and diff.X for the sin. The effect of taking these "wrong" values will result in a scaling.
Now determine the minimum and maximum of x and y of these straightened points. You get two pieces of information from these: 1) an offset from the coordinate origin. 2) The size of the board. Now rescale the transformed point to make them have coordinates between 0.0 and 8.0. Now if the image was perfect all the points’ coordinates should have integer values.
Because they don't, round the coordinates to make them all integers. Sorting these integer coordinates by y and then by x should yield your desired order. This is because the points on the same horizontal line now really have the same y value. This was not the case before. Since they probably all had different y-coordinates, only the second sorting by x had an effect.
In order to sort the original points, put the transformed ones and the original ones into the same class or struct (e.g. a Tuple) and sort them together.

What is the quickest way to find the shortest cartesian distance between two polygons

I have 1 red polygon say and 50 randomly placed blue polygons - they are situated in geographical 2D space. What is the quickest/speediest algorithim to find the the shortest distance between a red polygon and its nearest blue polygon?
Bear in mind that it is not a simple case of taking the points that make up the vertices of the polygon as values to test for distance as they may not necessarily be the closest points.
So in the end - the answer should give back the closest blue polygon to the singular red one.
This is harder than it sounds!
I doubt there is better solution than calculating the distance between the red one and every blue one and sorting these by length.
Regarding sorting, usually QuickSort is hard to beat in performance (an optimized one, that cuts off recursion if size goes below 7 items and switches to something like InsertionSort, maybe ShellSort).
Thus I guess the question is how to quickly calculate the distance between two polygons, after all you need to make this computation 50 times.
The following approach will work for 3D as well, but is probably not the fastest one:
Minimum Polygon Distance in 2D Space
The question is, are you willing to trade accuracy for speed? E.g. you can pack all polygons into bounding boxes, where the sides of the boxes are parallel to the coordinate system axes. 3D games use this approach pretty often. Therefor you need to find the maximum and minimum values for every coordinate (x, y, z) to construct the virtual bounding box. Calculating the distances of these bounding boxes is then a pretty trivial task.
Here's an example image of more advanced bounding boxes, that are not parallel to the coordinate system axes:
Oriented Bounding Boxes - OBB
However, this makes the distance calculation less trivial. It is used for collision detection, as you don't need to know the distance for that, you only need to know if one edge of one bounding box lies within another bounding box.
The following image shows an axes aligned bounding box:
Axes Aligned Bounding Box - AABB
OOBs are more accurate, AABBs are faster. Maybe you'd like to read this article:
Advanced Collision Detection Techniques
This is always assuming, that you are willing to trade precision for speed. If precision is more important than speed, you may need a more advanced technique.
You might be able to reduce the problem, and then do an intensive search on a small set.
Process each polygon first by finding:
Center of polygon
Maximum radius of polygon (i.e., point on edge/surface/vertex of the polygon furthest from the defined center)
Now you can collect, say, the 5-10 closest polygons to the red one (find the distance center to center, subtract the radius, sort the list and take the top 5) and then do a much more exhaustive routine.
For polygon shapes with a reasonable number of boundary points such as in a GIS or games application it might be quicker easier to do a series of tests.
For each vertex in the red polygon compute the distance to each vertex in the blue polygons and find the closest (hint, compare distance^2 so you don't need the sqrt() )
Find the closest, then check the vertex on each side of the found red and blue vertex to decide which line segments are closest and then find the closest approach between two line segments.
See http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/ (it's easy to simply for the 2d case)
This screening technique is intended to reduce the number of distance computations you need to perform in the average case, without compromising the accuracy of the result. It works on convex and concave polygons.
Find the the minimum distance between each pair of vertexes such that one is a red vertex and one is a blue. Call it r. The distance between the polygons is at most r. Construct a new region from the red polygon where each line segment is moved outward by r and is joined to its neighbors by an arc of radius r is centered at the vertex. Find the distance from each vertex inside this region to every line segment of the opposite color that intersects this region.
Of course you could add an approximate method such as bounding boxes to quickly determine which of the blue polygons can't possibly intersect with the red region.
Maybe the Frechet Distance is what your looking for?
Computing the Fréchet distance between two polygonal curves
Computing the Fréchet Distance Between Simple Polygons
I know you said "the shortest distance" but you really meant the optimal solution or a "good/very good" solution is fine for your problem?
Because if you need to find the optimal solution, you have to calculate the distance between all of your source and destination poligon bounds (not only vertexes). If you are in 3D space then each bound is a plane. That can be a big problem (O(n^2)) depending on how many vertexes you have.
So if you have vertex count that makes that squares to a scarry number AND a "good/very good" solution is fine for you, go for a heuristic solution or approximation.
You might want to look at Voronoi Culling. Paper and video here:
http://www.cs.unc.edu/~geom/DVD/
I would start by bounding all the polygons by a bounding circle and then finding an upper bound of the minimal distance.
Then i would simply check the edges of all blue polygons whose lower bound of distance is lower than the upper bound of minimal distance against all the edges of the red polygon.
upper bound of min distance = min {distance(red's center, current blue's center) + current blue's radius}
for every blue polygon where distance(red's center, current blue's center) - current blue's radius < upper bound of min distance
check distance of edges and vertices
But it all depends on your data. If the blue polygons are relatively small compared to the distances between them and the red polygon, then this approach should work nicely, but if they are very close, you won't save anything (many of them will be close enough). And another thing -- If these polygons don't have many vertices (like if most of them were triangles), then it might be almost as fast to just check each red edge against each blue edge.
hope it helps
As others have mentioned using bounding areas (boxes, circles) may allow you to discard some polygon-polygon interactions. There are several strategies for this, e.g.
Pick any blue polygon and find the distance from the red one. Now pick any other polygon. If the minimum distance between the bounding areas is greater than the already found distance you can ignore this polygon. Continue for all polygons.
Find the minimum distance/centroid distance between the red polygon and all the blue polygons. Sort the distances and consider the smallest distance first. Calculate the actual minimum distance and continue through the sorted list until the maximum distance between the polygons is greater than the minimum distance found so far.
Your choice of circles/axially aligned boxes, or oriented boxes can have a great affect on performance of the algorithm, dependent on the actual layout of the input polygons.
For the actual minimum distance calculation you could use Yang et al's 'A new fast algorithm for computing the distance between two disjoint convex polygons based on Voronoi diagram' which is O(log n + log m).
Gotta run off to a funeral in a sec, but if you break your polygons down into convex subpolies, there are some optimizations you can do. You can do a binary searches on each poly to find the closest vertex, and then I believe the closest point should either be that vertex, or an adjacent edge. This means you should be able to do it in log(log m * n) where m is the average number of vertices on a poly, and n is the number of polies. This is kind of hastey, so it could be wrong. Will give more details later if wanted.
You could start by comparing the distance between the bounding boxes. Testing the distance between rectangles is easier than testing the distance between polygons, and you can immediately eliminate any polygons that are more than nearest_rect + its_diagonal away (possibly you can refine that even more). Then, you can test the remaining polygons to find the closest polygon.
There are algorithms for finding polygon proximity - I'm sure Wikipedia has a good review of them. If I recall correctly, those that only allow convex polygons are substantially faster.
I believe what you are looking for is the A* algorithm, its used in pathfinding.
The naive approach is to find the distance between the red and 50 blue objects -- so you're looking at 50 3d Pythagorean calculations + sorting to find the answer. That would only really work for finding the distance between center points though.
If you want arbitrary polygons, maybe your best best is a raytracing solution that emits rays from the surface of the red polygon with respect to the normal, and reports when another polygon is hit.
A hybrid might work -- we could find the distance from the center points, assuming we had some notion of the relative size of the blue polygons, we could cull the result set to the closest among those, then use raytracing to narrow down the truly closest polygon(s).

Categories

Resources