Is a point inside regular hexagon - java

I'm looking for advice on the best way to proceed. I'm trying to find whether a given point A:(a, b) is inside a regular hexagon, defined with center O:(x, y) and diameter of circumscribing circle.
It seems like overkill to use Ray-casting, or Winding-number to determine this, for such a simple case, and I'm currently looking at the option of finding the angle (from horizontal) of the line OA, and "normalising" (probably not the right word) it into one of the 6 equilateral triangles and seeing if this new point lies within this triangle.
I get the feeling I'm missing something simple, and there's an easy way (or if I'm really lucky, a Java API) to do this simply and efficiently.
Thanks for your help.
Edit: The hexagon is oriented such that one of the sides is flat with the horizontal.

You can use the equations for each of the sides of the hexagon; with them you can find out if a given point is in the same half-plane as the center of the hexagon.
For example, the top-right side has the equation:
-sqrt(3)x - y + sqrt(3)/2 = 0
You plug in this the coordinates of the point and then the coordinates of the center. If the results have the same sign, then the point is in the bottom-left half-plane (so it may be inside the hexagon).
You then repeat by using the equations of the others sides.
Note that this algorithm will work for any convex polygon.

If you reduce the problem down to checking {x = 0, y = 0, d = 1} in a single quadrant, you could make very simple.
public boolean IsInsideHexagon(float x0, float y0, float d, float x, float y) {
float dx = Math.abs(x - x0)/d;
float dy = Math.abs(y - y0)/d;
float a = 0.25 * Math.sqrt(3.0);
return (dy <= a) && (a*dx + 0.25*dy <= 0.5*a);
}
dy <= a checks that the point is below the horizontal edge.
a*dx + 0.25*dy <= 0.5*a checks that the point is to the left of the sloped right edge.
For {x0 = 0, y0 = 0, d = 1}, the corner points would be (±0.25, ±0.43) and (±0.5, 0.0).

This is what I have been using:
public bool InsideHexagon(float x, float y)
{
// Check length (squared) against inner and outer radius
float l2 = x * x + y * y;
if (l2 > 1.0f) return false;
if (l2 < 0.75f) return true; // (sqrt(3)/2)^2 = 3/4
// Check against borders
float px = x * 1.15470053838f; // 2/sqrt(3)
if (px > 1.0f || px < -1.0f) return false;
float py = 0.5f * px + y;
if (py > 1.0f || py < -1.0f) return false;
if (px - py > 1.0f || px - py < -1.0f) return false;
return true;
}
px and py are the coordinates of x and y projected onto a coordinate system where it is much easier to check the boundaries.

Looks like you know general solution: "It seems like overkill to use...". So here is my idea:
Calculate distance from point to center and let's call it l.
Then you can compare it to inradius (r) and circumradius (R). if l < r then point is inside hexagon, if l > R then outside. If r < l < R then you have to check against each side respectively, but since R - r is very small (13% of length of side of hex) so probability that you will have to do complex calculations is tiny.
Formulas can be found here: http://mathworld.wolfram.com/Hexagon.html

I would first check if the point is inside the inscribed circle (you can compute the inscribed circle radius easily) or outside the circumscribed circle (that you already have).
The first means the point is in, the latter means it's out.
Statistically, most of the input points should allow you to decide based on the above simple tests.
For the worst case scenario (point is in between the inscribed and circumscribed circles), I think you can find the two vertices that are closest to the point and then see on which side of the segment V1V2 the point is (inner or outer, as relative to the O center).
Special case: point is equal to one of the vertices => it's in.
If I'll have a more clever idea (or if I'll ever start to really learn trigonometry), I'll edit the answer to let you know :)

Subtract the position of the center of the hexagon from your point P to get a vector V. Then, take the dot product of V with the following vectors, which correspond to the three pairs of opposing hexagon edges:
[0,1] ; the edges that are flat with the horizontal
[cos(30),sin(30)] ; the upper-right and lower-left edges
[cos(-30),sin(-30)] ; the lower-right and upper-left edges
If any of the dot products are greater in magnitude than the distance from the center of the hexagon to one of its edges, then the point is not inside the hexagon.
For reference, the dot product of vectors [a,b] and [c,d] is a*c+b*d.
The angle "30" above is in degrees ;)

What you want is the code to find out whether a point is inside a convex polygon, an hexagon being a particular case of that.
Here's a good answer:
https://stackoverflow.com/a/34689268/516188
I did modify that function for my use, I find my version clearer. It's typescript (you just squint and it's javascript):
function vectorX(v: Vector): number {
return v[1].x - v[0].x;
}
function vectorY(v: Vector): number {
return v[1].y - v[0].y;
}
function crossProduct(v1: Vector, v2: Vector): number {
return vectorX(v1)*vectorY(v2) - vectorY(v1)*vectorX(v2);
}
function isInConvexPolygon(testPoint: Point, polygon: Polygon): boolean {
// https://stackoverflow.com/a/34689268/516188
if (polygon.length < 3) {
throw "Only supporting polygons of length at least 3";
}
// going through all the edges around the polygon. compute the
// vector cross-product http://allenchou.net/2013/07/cross-product-of-2d-vectors/
// to find out for each edge on which side of the edge is the point.
// if the point is on the same side for all the edges, it's inside
let initCrossIsPositive = undefined;
for (var i=0;i<polygon.length;i++) {
if (polygon[i].x === testPoint.x &&
polygon[i].y === testPoint.y) {
// testPoint is an edge of the polygon
return true;
}
const curPointOnEdge = polygon[i];
const nextPointOnEdge = polygon[(i+1)%polygon.length];
const vector1 = <[Point,Point]>[curPointOnEdge, nextPointOnEdge];
const vector2 = <[Point,Point]>[curPointOnEdge, testPoint];
const cross = crossProduct(vector1, vector2);
if (initCrossIsPositive === undefined) {
initCrossIsPositive = cross > 0;
} else {
if (initCrossIsPositive !== (cross > 0)) {
return false;
}
}
}
// all the cross-products have the same sign: we're inside
return true;
}

There's a nice generalization to a hex lattice using homogeneous coordinates, by representing the lattice as the cube-lattice intersected with the plane x+y+z=0, see https://www.redblobgames.com/grids/hexagons/#coordinates

Related

Line-Triangle Intersection Check Returns Wrong Intersection Point

I'm writing a very basic raycaster for a 3D scene with triangulated objects and everything worked fine until I decided to try casting rays from points other than the origin of the scene (0/0/0).
However, when I changed to origin of the ray to (0/1/0) the intersection test suddenly returned a wrong intersection point for one of the triangles.
I'm deliberately "shooting" the rays into the direction of the center of the triangle, so obviously this should be the intersection point. I just simply don't know what's exactly leading to the wrong results in my code.
(I'm not using Möller-Trumbore at the moment because I'd like to start out with a simpler, more basic approach, but I will switch to Möller-Trumbore when optimizing the code.)
These are the coordinates of my the three vertices of the above mentioned triangle:
-2.0/2.0/0.0 | 0.0/3.0/2.0 | 2.0/2.0/0.0
This is the center of the triangle:
0.0/2.3333333333333335/0.6666666666666666
This is my ray (origin + t * Direction):
Origin: 0.0/1.0/0.0
Direction (normalized): 0.0/0.894427190999916/0.4472135954999579
This is the obviously wrong intersection point my program calculated (before checking and finding out that the point is not even on the triangle:
0.0/5.0/1.9999999999999996
So yeah, it's not hard to see (even without a calculator) that the ray should hit the triangle at its center at roughly t = 1.5. My code, however, returns the value 4.472135954999579 for t.
Here's my code for the intersection check:
public Vector intersectsWithTriangle(Ray ray, Triangle triangle) {
boolean intersects = false;
Vector triangleNormal = triangle.getNormalVector();
double normalDotRayDirection = triangleNormal.dotProduct(ray.getDirection());
if(Math.abs(normalDotRayDirection) == 0) {
// parallel
return null;
}
double d = triangleNormal.dotProduct(triangle.getV1AsVector());
double t = (triangleNormal.dotProduct(ray.getOrigin()) + d) / normalDotRayDirection;
// Check if triangle is behind ray
if (t < 0) return null;
// Get point of intersection between ray and triangle
Vector intersectionPoint = ray.getPosAt(t);
// Check if point is inside the triangle
if(isPointInTriangle(intersectionPoint, triangle, triangleNormal)) {
intersects = true;
return intersectionPoint;
}
return null;
}
Any ideas what's wrong with the line that calculates t?
If the ray is given by o + t*v and the triangle plane is defined by normal vector n and point p, then we are looking for t s.t. n*(o + t*v) = n*p which gives t = (n*p - n*o)/(n*v). So you seem to have a sign error and the correct computation for t should be:
double t = (d - triangleNormal.dotProduct(ray.getOrigin())) / normalDotRayDirection;
As long as the ray origin was (0,0,0) the wrong sign did not matter.

Find overlapping circles in Java

is there a simple way to find overlapping circles (each with one point in the middle and the same radius) in Java?
For example, if I have a dataset and I have those points
Point1 (3|3)
Point2 (4|2)
r = 1
So I will have it like this:
How can I check in Java, whether those two points are overlapping?
Best and thank you in advance!
The circles overlap if the distance between the centers is less than the sum of the radii:
public static boolean checkOverlap(Circle c1, Circle c2) {
return Math.hypot(c1.x - c2.x, c1.y - c2.y) < c1.r + c2.r;
}
If you have many circles and are looking for pairwise overlaps, you might be able to use a k-d tree to do better than O(n2).
A simple heuristic. (This is just an addition to arshajii's answer.)
If you want to avoid the k-D tree, you can sort the centers on their X coordinate. Then consider all circles in turn, and check overlap only with those having a center abscissa in [X,X+2R].
Assuming N circles uniformly spread in a domain of relative size M (side over diameter), you will trade N²/2 comparisons for max(N²/M, N) only.
It's actually just a matter of applying the Pythagorean theorem.
boolean areCirclesOverlappint(Point a, Point b, double radius) {
double diffX = a.x - b.x;
double diffY = a.y - b.y;
return diffX * diffX + diffY * diffy <= radius * radius * 4;
}

How can I check if an object(s) are in front of the camera?

I have got some trees, which are greatly lagging the game, so I would like to check if the trees are in front of the camera or not.
I have had some help from the Mathematics forum, and also had a look at This link to help me convert pitch/yaw to the directional vector needed.
But for some reason, whenever I move the camera to the left, the trees become visible, wheras whenever I move it to the right, they become unvisible (So if camera is pointing at +1 on the Z axis, it seems to be rendering the trees, but -1 on the Z axis and it seems to not render them).
(See http://i.gyazo.com/cdd05dc3f5dbdc07577c6e41fab3a549 for a less-jumpy .mp4)
I am using the following code to check if an object is in front of the camera or not:
Ship you = shipsID.get(UID);
int dis = 300;
Vector3f X = new Vector3f(camera.x(), camera.y(), camera.z());
float x = (float) (Math.cos(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float y = (float) (Math.sin(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float z = (float) Math.sin(Math.toRadians(camera.pitch()));
Vector3f V = new Vector3f(x, y, z);
for (Tree tree : trees){
Vector3f Y = new Vector3f(tree.location.x, tree.location.y, tree.location.z);
Vector3f YMinusX = Y.negate(X);//new Vector3f(Y.x - X.x, Y.y - X.y, Y.z - X.z);
float dot = Vector3f.dot(YMinusX, V);
if (dot > 0){
tree.render();
}
}
Is anyone able to tell me what I have done wrong here? I can't work out if it's the math.. Or the code.. Or what?
Camera translation code:
public void applyTranslations() {
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glRotatef(pitch, 1, 0, 0);
glRotatef(yaw, 0, 1, 0);
lastYaw = yaw;
glRotatef(roll, 0, 0, 1);
glTranslatef(-x, -y, -z);
glPopAttrib();
}
UPDATE:
It appears to be where the camera is looking. For example, if I look to -Z, nothing happens, but if I look to +Z, they all render.
The if (dot > 0) code appears to somehow being +Z rather than +TheCameraRotation.
Your camera rotations yaw around Y, implying Y is your up vector. However, float z = (float) Math.sin(Math.toRadians(camera.pitch())); gives Z for your up vector. There is an inconsistency. I'd start by swapping y and z here, then print everything out every frame so you can see what happens as you rotate the camera. Also render just one tree and print dot. E.g. you might quickly notice the numbers approach 1.0 only when you look at 90 degrees left of the tree which narrows down the problem. As #DWilches notes, swapping cos/sin will change the phase of the rotation, which would produce such an effect.
You might consider limiting the dot product to the camera's field of view. There are still problems in that trees are not just points. A better way would be to test tree bounding boxes against the camera frustum, as #glampert suggests.
Still, the tree geometry doesn't look that complex. Optimization wise, I'd start trying to draw them faster. Are you using VBOs? Perhaps look at methods to reduce draw calls such as instancing. Perhaps even use a few models for LOD or billboards. Going even further, billboards with multiple trees on them. Occlusion culling methods could be used to ignore trees behind mountains.
[EDIT]
Since your trees are all roughly on a plane, you could limit the problem to the camera's yaw:
float angleToTree = Math.atan2(tree.location.z - camera.z(), tree.location.x - camera.x());
float angleDiff = angleToTree - camera.yaw();
if (angleDiff > Math.PI)
angleDiff -= 2.0f * Math.PI;
if (angleDiff < -Math.PI)
angleDiff += 2.0f * Math.PI;
if (abs(angleDiff) < cameraFOV + 0.1f) //bias as trees are not points
tree.render();
Could you write it like this
Ship you = shipsID.get(UID);
int dis = 300;
Vector3f X = new Vector3f(camera.x(), camera.y(), camera.z());
float x = (float) (Math.cos(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float y = (float) (Math.sin(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float z = (float) Math.sin(Math.toRadians(camera.pitch()));
Vector3f V = new Vector3f(x, y, z);
for (Tree tree : trees){
Vector3f Y = new Vector3f(tree.location.x, tree.location.y, tree.location.z);
Vector3f YMinusX = Y.negate(X);//new Vector3f(Y.x - X.x, Y.y - X.y, Y.z - X.z);
float dot = Vector3f.dot(YMinusX, V);
if (dot > 0){
tree.render();
}
}
As you can see there is far less calculation being performed for each tree.
For what I see here the correct formulas are:
x = Math.sin(pitch) * Math.cos(yaw);
y = Math.sin(pitch) * Math.sin(yaw);
z = Math.cos(pitch);
Could you try them ?

Getting bullet X to Y movement ratio from 2 points

I'm making pretty simple game. You have a sprite onscreen with a gun, and he shoots a bullet in the direction the mouse is pointing. The method I'm using to do this is to find the X to Y ratio based on 2 points (the center of the sprite, and the mouse position). The X to Y ratio is essentially "for every time the X changes by 1, the Y changes by __".
This is my method so far:
public static Vector2f getSimplifiedSlope(Vector2f v1, Vector2f v2) {
float x = v2.x - v1.x;
float y = v2.y - v1.y;
// find the reciprocal of X
float invert = 1.0f / x;
x *= invert;
y *= invert;
return new Vector2f(x, y);
}
This Vector2f is then passed to the bullet, which moves that amount each frame.
But it isn't working. When my mouse is directly above or below the sprite, the bullets move very fast. When the mouse is to the right of the sprite, they move very slow. And if the mouse is on the left side, the bullets shoot out the right side all the same.
When I remove the invert variable from the mix, it seems to work fine. So here are my 2 questions:
Am I way off-track, and there's a simpler, cleaner, more widely used, etc. way to do this?
If I'm on the right track, how do I "normalize" the vector so that it stays the same regardless of how far away the mouse is from the sprite?
Thanks in advance.
Use vectors to your advantage. I don't know if Java's Vector2f class has this method, but here's how I'd do it:
return (v2 - v1).normalize(); // `v2` is obj pos and `v1` is the mouse pos
To normalize a vector, just divide it (i.e. each component) by the magnitude of the entire vector:
Vector2f result = new Vector2f(v2.x - v1.x, v2.y - v1.y);
float length = sqrt(result.x^2 + result.y^2);
return new Vector2f(result.x / length, result.y / length);
The result is unit vector (its magnitude is 1). So to adjust the speed, just scale the vector.
Yes for both questions:
to find what you call ratio you can use the arctan function which will provide the angle of of the vector which goes from first object to second object
to normalize it, since now you are starting from an angle you don't need to do anything: you can directly use polar coordinates
Code is rather simple:
float magnitude = 3.0; // your max speed
float angle = Math.atan2(y,x);
Vector2D vector = new Vector(magnitude*sin(angle), magnitude*cos(angle));

Java 2D: Moving a point P a certain distance closer to another point?

What is the best way to go about moving a Point2D.Double x distance closer to another Point2D.Double?
Edit: Tried to edit, but so went down for maintenance. No this is not homework
I need to move a plane (A) towards the end of a runway (C) and point it in the correct direction (angle a).
alt text http://img246.imageshack.us/img246/9707/planec.png
Here is what I have so far, but it seems messy, what is the usual way to go about doing something like this?
//coordinate = plane coordinate (Point2D.Double)
//Distance = max distance the plane can travel in this frame
Triangle triangle = new Triangle(coordinate, new Coordinate(coordinate.x, landingCoordinate.y), landingCoordinate);
double angle = 0;
//Above to the left
if (coordinate.x <= landingCoordinate.x && coordinate.y <= landingCoordinate.y)
{
angle = triangle.getAngleC();
coordinate.rotate(angle, distance);
angle = (Math.PI-angle);
}
//Above to the right
else if (coordinate.x >= landingCoordinate.x && coordinate.y <= landingCoordinate.y)
{
angle = triangle.getAngleC();
coordinate.rotate(Math.PI-angle, distance);
angle = (Math.PI*1.5-angle);
}
plane.setAngle(angle);
The triangle class can be found at http://pastebin.com/RtCB2kSZ
Bearing in mind the plane can be in in any position around the runway point
You can minimize the difference along both axis by a percent (that depends on how much you want to move the points).
For example:
Point2D.Double p1, p2;
//p1 and p2 inits
// you don't use abs value and use the still point as the first one of the subtraction
double deltaX = p2.getX() - p1.getX();
double deltaY = p2.getY() - p1.getY();
// now you know how much far they are
double coeff = 0.5; //this coefficient can be tweaked to decice how much near the two points will be after the update.. 0.5 = 50% of the previous distance
p1.setLocation(p1.getX() + coeff*deltaX, p1.getY() + coeff*deltaY);
So you moved p1 halfway toward p2. The good thing avoid abs is that, if you choose which point will be moved and which one will stand still you can avoid if tests and just use the raw coefficient.
The shortest distance between two points is a line, so simply move that point x units along the line that connects the two points.
Edit: I didn't want to give away the specifics of the answer if this is homework, but this is simple enough that it can be illustrated without being too spoiler-y.
Let us assume you have two points A = (x1, y1) and B = (x2, y2). The line that includes these two points has the equation
(x1, y1) + t · (x2 - x1, y2 - y1)
where t is some parameter. Notice that when t = 1, the point specified by the line is B, and when t = 0, the point specified by the line is A.
Now, you would like to move B to B', a point which is a new distance d away from A:
A B' B
(+)---------------------(+)-----------(+)
<========={ d }=========>
The point B', like any other point on the line, is also governed by the equation we showed earlier. But what value of t do we use? Well, when t is 1, the equation points to B, which is |AB| units away from A. So the value of t that specifies B' is t = d/|AB|.
Solving for |AB| and plugging this into the above equation is left as an exercise to the reader.
Vectors to the rescue!
Given points A and B. Create a vector V from A to B (by doing B-A). Normalize vector V into a unit vector and then just multiply it with the distance, d, you want and finally add the resulting vector to point A. ie:
A_moved = A + |(B-A)|*d
Java(ish)
Vector2D a_moved = a.add(b.subtract(a).norm().multiply(d));
No angles, no nasty trig needed.
double angle = Math.atan2(landingCoordinate.y-coordinate.y, landingCoordinate.x-coordinate.x);
coordinate.x += Math.cos(angle)*distance;
coordinate.y += Math.sin(angle)*distance;
//Add 90 degress to the plane angle
plane.setAngle(angle + 1.57079633);
(point A is to be moved closer to B)
if (A.x > B.x)
//decrement A.x
if (A.x < B.x)
//increment A.x
that might be the basic idea in pseudocode, but there's a lot more to it than that. How do you define 'best' way?
Certain things need to be considered:
Is there a specific measure/ratio you want the points to be apart from each other, or do you just want them closer?
Should both coordinates always be modified? (e.g. if you want to move (1,50) closer to (0,0), do you make it (.5, 25) or just (1,25)?
if the point is to be 1 unit away, should it be 1 unit horizontally? directly diagonally? 1 unit away on the line between the 2 points?
Give us a little more detail and we'll see what we've got. :D
In this game, integral coordinates are used to represent squares in a grid. The method move(int row, int col) moves toward the specified row and column by advancing one square in one of eight semi-cardinal directions, as seen here.

Categories