Original post:
I'm trying to find the outermost vertices of a convex polygon (with relation to a point P outside the polygon). For now, I'm only concerned with rectangles (however, I'd like an algorithm that works with any convex polygon).
My plan is to construct a line from external point P to central point C. From this line of reference, I will construct lines from point P to points 1, 2, 3 and 4. Since points 2 and 4 will have the largest (most positive) and smallest (most negative) angles from the line of reference, they will be identified as the outermost vertices.
Is this the best algorithm for the job? How does one calculate angles from a reference angle (preferably in Java)?
Update for clarification:
I've drawn the lines (line of reference in red). As you can see, the line from P to 2 creates the largest angle on one side of the line of reference, while the line from P to 4 creates the largest angle of the other side. Hence, these are the outermost vertices.
This is pretty much the convex hull problem. You would be looking for a set of vertices (x1, x2) around a polygon. The methodology that would be applied is called "quick-hull", analogous to quicksort (in that we divide our region of points every time we step through). It is also a safe assumption that P can be used as a mid-point between an arbitrary starting point and its parallel ending point, so you would get a convex hull around P.
It would take a while to produce some reliable Java to poke at (from my happenstance), but I think that the Wikipedia entry will give you a great starting point.
The use of trigonometry is extremely slow. You should use another angle comparison.
For an angle between two flat vectors:
cos(OA, OB) = (OAx * OBx + OAy* OBy) / sqrt((OAx2 + OAy2)* (OBx 2 + OBy2))
I think, you can compare angles having cosines.
I solved the problem as follows:
// code simplified for demonstration
double angleBetweenVertices;
double maxAngleBetweenVertices;
vectorA.setStartingPoint(outerPoint);
vectorA.setTerminationPoint(polygonCenter);
vectorB.setStartingPoint(outerPount);
// For each vertex, calculate the angle between the outer point, the polygon's center and the vertex
for (Point2D.Double vertex : vertices) {
vectorB.setTerminationPoint(vertex);
double angleBetweenVertices =
Math.toDegrees(
Math.atan2(
(vectorA.perpDotProduct(vectorB)),
(vectorA.dotProduct(vectorB))
)
);
// Update the min and Max
if (angleBetweenVertices >= maxAngleBetweenVertices) {
maxVertex = vertex;
maxAngleBetweenVertices = angleBetweenVertices;
} else if (angleBetweenVertices <= minAngleBetweenVertices) {
minVertex = vertex;
minAngleBetweenVertices = angleBetweenVertices;
}
}
Related
So I'm attempting to calculate if a point is inside of an angle. While researching, I came across many terms I am unfamiliar with. Essentially from a point (A) with a 120° angle protruding from point (A). I want to test if a secondary point (B) would be inside of the angle. All that is known is the degree of the angle and the degree at which the angle is facing and the X and Y values of both points. This will all be done in Java so any and all help is appreciated!
To better explain it:
There is a point with two vectors protruding from said point. The angle that is known is the angle that is created by the protrusion of the two vectors.
First of all, an angle is not defined for two points -- only for two lines.
Define a line that is your 0° 2D-space. For a line, you need a point and a direction.
Calculate the normal-vector for your line (Turn your directional vector by 90°); normalize both your directional and normal vector so that sqrt(x^2+y^2) = 1.
Calculate the distance vector between your initial point and the other point, this is your second line, sharing the same initial point.
Calculate the dot-product of a and b:
a = distance vector × normal vector
b = distance vector × directional vector
Use simple trigonometry to calculate the angle. It's the arctangent of (a/b) or (b/a).
You probably wanna take the absolute value of the result as well if you don't care about left and right.
I am making my own implementation of a raycaster in a game I am making, and I have come across a very hard problem. I have a player (the black dot), and I need to find the intersection nearest to the player. In the image below, the arrow is pointing to the intersection point I need.
What I guess I am trying to say is that I need a function something like this:
// Each line would take in 2 map values for it's 2 points
// In turn, the map would have to have an even number of points
public Point getNearestIntersection(int playerX, int playerY, int lineDir, Point[] map) {
// whatever goes here
}
I am going to have to do this about 50 times every frame, with about 100 lines. I would like to get 40 fps at the least if possible... Even if I divide it up into threads I still feel that it would cause a lot of lag.
The class Point has a method called distance which calculates the distance of two points. You then could loop all points to get the nearest. Could be something like this:
Point currentNearestIntersection;
double smallestDistance;
for (Point inter : intersections) {
double distance = player.distance(inter );
if (distance < smallestDistance) {
currentNearestIntersection= inter;
smallestDistance = distance;
}
}
axis/line intersection is in reality solving:
p(t)=p0+dp*t
q(u)=q0+(q1-q0)*u
p(t)=q(u)
t=? u=?
where:
p0 is your ray start point (vector)
dp is ray direction (vector)
q0,q1 are line endpoints (vectors)
p(t),q(u) are points on axis,line
t,u are line parameters (scalars)
This is simple system of 2 linear equations (but in vectors) so it lead to N solutions where N is the dimensionality of the problem so choose the one that is not division by zero ... Valid result is if:
t>=0 and u=<0.0,1.0>
if you use unit dp vector for direction of your ray then from computing intersection between axis and line the t parameter is directly distance from the ray start point. So you can directly use that ...
if you need to speed up the intersections computation see
brute force line/line intersection with area subdivision
And instead of remebering all intersections store always the one with smallest but non negative t ...
[Notes]
if you got some lines as a grid then you can compute that even faster exploiting DDA algorithm and use real line/line intersection only for the iregular rest... nice example of this is Wolfenstein pseudo 3D raycaster problem like this
For a Java program I'm making I need to interpolate 4 points, to calculate the y-value of a 5th point, at given x-value.
Say I have the following points:
p1(0, 0)
p2(1, 2)
p3(2, 4)
p4(3, 3)
// The x-values will always be 0, 1, 2, and 3
Now I want to interpolate these points to find what the y-value should be for given x, say x=1.2 (this x value will always be between point 2 and point 3)
Can anyone help me to make a Java method for finding the y coordinate of this fifth point?
Generally given two points (x0,y0) and (x1,y1), for x0 < x < x1, by interpolation,
y = y0 + (x - x0)/(x1 - x0) * (y1 - y0)
Here,
y = 2 + (x-1) * 2
There are an infinite number of lines that can go through all four of your points.
For example, you could assume that at each point the slope is zero and then draw simple s shaped curves between them, or you could assume that the slope is calculated from the neighboring points (with some special decisions about the ends), or you could assume that the slope at the points is 2, etc.
And it doesn't stop there, you could effectively draw a curve that will encapsulate your points and any other point you could imagine while still meeting the requirement of being continuous (as you call, smooth).
I think you need to start off with a formula you wish to fit against the points, and then choose the technique you use to minimize the error of the fit. Without you making more decisions, it is very likely that it will be very hard to give more direction.
I'm working on a project where some flying object scans the ground to know where its exact location is. For instance, let the following grid be the ground, the letters are literally placed on the ground. Each triangle in the grid is unique.
A---B---C---D
\ / \ / \ / \
E---A---H---G
/ \ / \ / \ / \
H---F---B---E---A
The flying object has access to a file containing these letters, separated by spaces. A zero denotes an empty node.
A B C D 0
E A H G 0
H F B E A
The flying object takes a picture of the ground, but because it's close to the ground, it only sees a part of the ground.
A---H---G
\ / \ /
B---E
The airplane scans this pattern in using OpenCV, it recognizes the numbers. It can also put a coordinate on each of the scanned numbers. For instance, A is placed on coordinate (100,200) on the taken picture, H on coordinate (301,201), B on coordinate (195,403) and so on.
Given the letters with their (approximate) coordinates (on the picture), and also the coordinates of the center of the picture, how does the airplane find out exactly where it is on the grid. It would be optimal if the following output could be produced:
If the airplane hovers above a triangle, return the 3 letters of that triangle.
If the airplane hovers approximately along the side of a triangle, return the 2 letters of that side.
If the airplane hovers approximately on a node, return the letter of that node.
I'm sorry if this is a very wide problem, I just have no idea how to solve it. I tried representing the problem as the subgraph isomorphism problem but the solution to that problem is NP-complete. The grid can have as much as 200 letters.
I'm currently working in python but any solution to this problem (or an idea) is appreciated.
Edit: A part of the question may have been a bit vague. After finding above which vertex/edge/triangle the airplane is flying, I need to find this vertex/edge/triangle on the given grid-file. That's why I tried the subgraph isomorphism problem. So if the airplane finds out it hovers above:
vertex H which is part of triangle HBE, the algorithm should return [(2,1)]
edge HB which is part of triangle HBE, the algorithm should return [(2,1) , (2,2)]
triangle HBE, the algorithm should return [(2,1) , (2,2) , (3,2)]
Thanks a lot!
One issue is that you are over-complicating it. Sub-graph isomorphism is much, much harder than what you are trying to do.
Assuming that you are able to analyze the imagine and determine the approximate coordinates (on the image) for each of the letters. You should be able to take the point set of the letters, with each point uniquely mapped to a letter, and do a linear search to find the three points nearest to to the center of the image.
The next step is the triangle lookup. First, is it important to know that since each triangle in the grid is unique, you can simply loop through all the triangles in the grid, standardize (via a canonization) them, then add them to dictionary to provide a fast lookups. Thus the code for building the look-up dictionary looks something like this:
def canonize_triangle_letters(letter_triple):
# Used in larger algorithm below
return tuple(sorted(list(letter_triple)))
def triangle_lookup_from_grid(triangle_grid)
# This is a preprocessing step
# Only needs to be done once if the grid doesn't change.
# If grid does change, a more complex approach will be needed.
triangle_lookup = {} # Used in larger algorithm below
for points_triple in get_points_triples(triangle_grid):
letter_to_point = dict((point_to_letter[p],p) for p in points_triple)
triangle = canonize_triangle_letters(letter_to_point.keys())
triangle_lookup[triangle] = letter_to_point
return triangle_lookup
The next step is to determine if the return a vertex, edge or triangle. A simple, but rather subjective method, rather useful for example if you want to bias the algorithm towards returning an edge rather than a vertex or triangle.
If the center is significantly closer to one point, return the letter of that point.
If the center is close to two points, return the letters of those two points.
Otherwise, return all three points.
A more balanced, precise way requires some extra math. The below image shows roughly how to go about it. To avoid confusion between areas where a vertex is returned (A), an edge is returned (AB) or a triangle is returned (ABC) as well as the math. The vertex A is labeled as 5, the vertex B is labeled as 6 and the vertex C is labeled as 7. Note that L/3 is showing the radius there, where L is the length of a side. The image assumes that closest point to the center is A followed by B then C. Thus a point would never be on the right side side of the line from vertices 5 and 8, as it breaks the assumption of the point being closer to A and B than C.
The way it is evaluated is as followed:
If the closest point (A) is within L/3 of the center. Then return A.
Create a point, p1 (vertex 8 in the diagram), that is way along the angle halfway between the angle from A to B and A to C. You then place a second point, p2 (vertex 9 in the diagram), at the same angle as A to B and at a distance of L. From there you can use the crossproduct to determine which side of the line the center is on.
If cross(p1,screen_center,p2) less than 0, then return AB, else return ABC.
The code then looks something like below. There are a few magic math functions in the code, but the algorithms for them shouldn't be difficult to look-up online.
def find_nearest_triangle(points, screen_center):
# Returns the nearest triangle, sorted by distance to center
dist_to_center = lambda p: distance(p, screen_center)
# Use the first three points in the list to create the inital triangle
nearest_triangle = set(points[:3])
farthest_point = max(nearest_triangle, key=dist_to_center)
farthest_dist = dist_to_center(farthest_point)
for point in points[3:]:
dist = dist_to_center(point)
if dist < farthest_dist: # Check for a closer point
farthest_dist = dist
nearest_triangle.remove(farthest_point)
nearest_triangle.add(point)
# Find the new farthest point
farthest_point = max(nearest_triangle, key=dist_to_center)
return sorted(list(nearest_triangle), key=dist_to_center)
def get_location(nearest_triangle, screen_center):
# nearest_triangle should be the same as returned by find_nearest_triangle.
# This algorithm only returns the 1-3 points that make up the triangle.
A, B = nearest_triangle[:2]
side_length = distance(A, B)
vertex_radius = side_length / 3.0
if distance(A, screen_center) < vertex_radius:
return [A], nearest_triangle
def cross(o, a, b): # Cross product
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
angle_AB = angle(A, B)
angle_AC = angle(A, C)
middle_angle = ((angle_AB + angle_AC) % 360) / 2.0 # For angle in degrees
p1 = offset_point_by_angle_dist(A, middle_angle, distance)
p2 = offset_point_by_angle_dist(p1, angle_AB, side_length)
if cross(p1,screen_center,p2) < 0:
return [A,B]
return [A,B,C]
def lookup_location(triangle_lookup, image_point_to_letter, points, screen_center):
nearest_triangle = find_nearest_triangle(points, screen_center)
triangle = canonize_triangle_letters([image_point_to_letter[p] for p in nearest_triangle])
letter_to_position = triangle_lookup[triangle]
location = get_location(nearest_triangle, screen_center)
letters = [image_point_to_letter[p] for p in location]
return [letter_to_position[L] for L in letters]
Note the above algorithm has a runtime of O(N), where N is the number of points in the point set. However, it must be ran for each image. Thus if a lot of images need to be checked, it is best to try to limit the number of letters. Although, it's likely that extracting the letters from the image will be more time intensive. Although, since the algorithm only needs the closest three letters, it should be best
So, I'm working on a 2D physics engine, and I have an issue. I'm having a hard time conceptualizing how you would calculate this:
Take two squares:They move, collide, and at some vector based off of the velocity of the two + the shape of them.
I have two vector lists(2D double lists) that represent these two shapes, how does one get the normal vector?
The hit vector is just (s1 is the first shape, s2 the second) s2 - s1 in terms of the position of the center of mass.
Now, I know a normal vector is one perpendicular to an edge, and I know that you can get the perpendicular vector of a line by 90 degrees, but what edge?
I read in several places, it is the edge a corner collided on. How do you determine this?
It just makes no sense to me, how you would mathematically or programmatically determine what edge.
Can anyone point out what I'm doing wrong in my understanding? Sorry for providing no code to explain this, as I'm having an issue writing the code for it in the first place.
Figure1: In 2D the normal vector is perpendicular to the tangent line:
Figure2: In 3D the normal vector is perpindicular to the tangent plane
Figure3: For a square the normal vector is easy if you are not at a corner; It is just perpendicular to the side of the square (in the image above, n = 1 i + 0 j, for any point along the right side of the square).
However, at a corner it becomes a little more difficult because the tangent is not well-defined (in terms of derivatives, the tangent is discontinuous at the corner, so perpendicular is ambiguous).
Even though the normal vector is not defined at a corner, it is defined directly to the left and right of it. Therefore, you can use the average of those two normals (n1 and n2) as the normal at a corner.
To be less technical, the normal vector will be in the direction from the center of the square to the corner of the collision.
EDIT: To answer the OP's further questions in the chat below: "How do you calculate the normal vector for a generic collision between two polygons s1 and s2 by only knowing the intersecting vertices."
In general, you can calculate the norm like this (N is total verts, m is verts inside collision):
vcenter = (∑N vi) / N
vcollision = (∑m vi) / m
n = vcollision - vcenter
Fig. 1 - vcollision is only a single vertex.
Fig. 2 - vcollision is avg of two verts.
Fig. 3 - vcollision for generic polygon intersection.