Minimum Bounding Sphere for a Single 3D Triangle - java

--Original Post--
I'm trying to calculate the minimum bounding sphere for a 3-dimensional triangle.
The triangle is given by the points point0, point1, point2.
The code below was created from http://en.wikipedia.org/wiki/Circumscribed_circle#Barycentric_coordinates_from_cross-_and_dot-products
For the sample input (0,0,10), (0,10,0), (10,0,0), the following code gives:
radius = 8.164967, which is correct (verified by using Google Sketchup to draw a model).
minSphereCenter = (10, 3.333..., 1.111...), which is incorrect.
The correct center point would be (3.333..., 3.333..., 3.333...).
What am I doing wrong?
Note: I know that this will not give the minimum bounding sphere for obtuse triangles.
--Solution--
class Triangle{
Vector3f point0, point1, point2;
Vector3f minSphereCenter;
float minSphereRadius;
private void calculateMinimumBoundingSphere() {
minSphereRadius=
(point0.distance(point1)*point1.distance(point2)*point2.distance(point0))/
(2*(new Vector3f().cross(new Vector3f().sub(point0, point1), new Vector3f().sub(point1, point2)).length()));
float divisor=2*(new Vector3f().cross(new Vector3f().sub(point0, point1), new Vector3f().sub(point1, point2)).lengthSquared());
float
i=point1.distanceSquared(point2)*new Vector3f().sub(point0, point1).dot(new Vector3f().sub(point0, point2))/
divisor,
j=point0.distanceSquared(point2)*new Vector3f().sub(point1, point0).dot(new Vector3f().sub(point1, point2))/
divisor,
k=point0.distanceSquared(point1)*new Vector3f().sub(point2, point0).dot(new Vector3f().sub(point2, point1))/
divisor;
minSphereCenter=new Vector3f(point0).scale(i).add(new Vector3f(point1).scale(j)).add(new Vector3f(point2).scale(k));
System.out.println(minSphereCenter);
System.out.println(minSphereRadius);
}

I've found the problem: The original minSphereCenter code used a scaleAdd() function, which I assumed worked like an addScale() function.
The original question has been edited with the solution.

Related

How to check if lng/lat bounding box intersects with another?

Assume I have several bounding boxes with 4 coordinates pair (long/lat only) each representing the 4 corners of a square box. How can I check if 2 of those boxes intersects?
I know I could use java.awt.Rectangle to check if 2 rectangles intersects, but the problem is it is calculated using X/Y/Width/Height instead of coordinates.
Can someone please give me some directions on how can I do this calculations?
Thanks.
EDIT
What I am trying to accomplish is the same represented by this library.
Basically it calculates a square bounding box around a given point and check if the (imaginary) squares intersects with each other, like in this image:
(source: google.com)
So far I've been able to calculate the corners for each marker and now I need to somehow check if they intersect with each other. How can I do this intersection calculation?
EDIT 2
This is how I am calculating the corners:
private static double getLatitude(double distance, double lat, double angle) {
return toDegrees(asin(sin(toRadians(lat)) * cos(distance / RADIUS) + cos(toRadians(lat)) * sin(distance / RADIUS) * cos(toRadians(angle))));
}
private static double getLongitude(double distance, double lat, double lng, double angle) {
double newLat = getLatitude(distance, lat, angle);
return toDegrees(toRadians(lng) + atan2(sin(toRadians(angle)) * sin(distance / RADIUS) * cos(toRadians(lat)), cos(distance / RADIUS) - sin(toRadians(lat)) * sin(toRadians(newLat))));
}
Where RADIUS = 6378.1 and angle = 45/135/225/315 (top right, bottom right, bottom left and top left).
Example output
I'm assuming that in your "lat/long bounding box' each side follows the lines of constant longitude and latitude - in other words that the top side follows the line of constant latitude, and the left side the line of constant longitude.
While this is not actually a rectangle in real life, it can actually be treated as one for our purposes. Mathematically you can think of this as transforming the bounding box into a "lat/long' space, where the shape is in fact a rectangle. If that doesn't make sense you may have to take my word for it. In any case it is possible to show that the curved shapes in real space intersect if and only if the rectangles intersect in curved space.
The short version of this is: if you do a standard test for intersection of rectangles (using the Java Rectangle class code, and using latitude and longitude as the rectangle bounds) you will get the right result.
EXAMPLE
You have two areas, defined as:
The area between 50 and 52 degrees N and 75 and 77 degrees E
The area between 51 and 53 degrees N and 76 and 79 degrees E
You can correctly test for their intersection by doing:
Rectangle r1 = new Rectangle(75,50,2,2);
Rectangle r2 = new Rectangle(76,51,2,3);
boolean intersects = r1.insersects(r2);
It doesn't matter that the rectangles are not rectangular in Euclidean space.
P.S. This will not work if one of your rectangles actually contains either the north or south pole. In that case you will need to split each rectangle into two, one on each side of the pole. You need to normalize everything to +/- 90 latitude and +/- 180 longitude. You will need to do something clever if one or more of the rectangles overlaps the +/-180 longitude line.

3D rotation of a circle to make the edge cross two points

I am trying to make a circle (actually a flat cylinder) rotate so that the edge crosses two points in world position. These two points can be anywhere on a sphere. The sphere has the same radius and position as the cylinder. the origin of both is [0,0,0].
It's a little bit hard to explain, so I included three pictures that I hope illustrates what I am trying to accomplish.
Here you see what I am trying to accomplish. The yellow circle represents one of the points along the sphere, while the red circle represents the other point. The blue line is actually a flat cylinder going through the sphere, and is rotated so that it goes through both points.
Here is another similar picture, but with the points at different locations.
In this picture one can see the cylinder in full, as the sphere has been hidden.
Now, I am really terrible at math, so I would really love an answer made up of pseudo code or a programming language. And if I should be so lucky, java.
The circles rotation can be represented with either a quaternion or a matrix
So far, what I have tried, is rotating the cylinder with an up vector towards one of the points, and a forward vector towards the other point. But I can't seem to make it work. I have also tried other solutions, most of them involving two rotations (one for each point), but I end up having trouble when combining the rotations.
Here is my current non-working code:
This code makes the circle go through the first point, and then rotates it with an "up vector" towards the same point, this second rotation varies depending on the first point position, and is kind off all over the place.
//calculate direction vector between the two points
point1point2dir.set(point1Pos);
//subtract point two position
point1point2dir.sub(point2Pos);
//normalize
point1point2dir.nor();
//make two quaternions for rotation
Quaternion rot1=new Quaternion();
Quaternion rot2=new Quaternion();
//set first rotation two a rotation between X-axis and point1 position. Vector3.X = (1,0,0)
rot1.set(m.quatUtils.getRot(Vector3.X, point1Pos));
//crossmuliply direction vector between the two points with X-axis
point1point2dir.crs(Vector3.X);
//set the second rotation to a rotation between Z-Axis and the crossmultiplied direction vector
rot2.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));
//multiply the two rotations
rot1.mul(rot2);
//apply the rotation to the cylinders matrix
cylinderMatrix.rotate(rot1);
//the function that gets the quaternion rotation between two vectors
Quaternion getRot(Vector3 pStart, Vector3 pDest) {
start.set(pStart);
dest.set(pDest);
start.nor();
dest.nor();
cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
dest.z);
rotationAxis.set(0.0f, 0.0f, 0.0f);
if (cosTheta < -1.0f + 0.001f) {
rotationAxis.set(Z_AXIS);
rotationAxis.crs(start);
if (rotationAxis.len2() < 0.01f) {
rotationAxis.set(X_AXIS);
rotationAxis.crs(start);
}
rotationAxis.nor();
resultQuat.set(rotationAxis, 180.0f);
return resultQuat;
}
rotationAxis.set(start);
rotationAxis.crs(dest);
s = (float) Math.sqrt((1 + cosTheta) * 2);
invs = 1.0f / s;
resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
rotationAxis.z * invs, s * 0.5f);
return resultQuat;
}
I would suggest this solution:
Calculate v1 and v2 as the vectors from the center of the sphere to each point that you want the cylinder to pass trough.
Cross product v1 and v2 to get the vector up of the cylinder, let's call it n.
Position the center of the cylinder in the center of the sphere.
Rotate the cylinder using n as vector up.
I figured out the solution! It was actually really simple. I don't know how I managed to bungle the math as much as I did earlier. I actually did spend alot of time on this >:)
Sorry if I wasted anybodys time!
The solution:
find direction vector from point1 (A) to point2 (B).
crossmultiply direction vector with point2 to get (C)
Find the quaternion which represents the rotation from Z-axis to the crossmultiplied direction vector (C), function for doing this included in the code attached to the question.
apply rotation.
Here is the working code (yay):
//the rotation
Quaternion rot=new Quaternion();
//the direction from point1 to point 2 (the point positions are in this case also the direction vectors from center)
point1point2dir.set(point1Pos);
point1point2dir.sub(point2Pos);
point1point2dir.nor();
//crossmultiplied with point2
point1point2dir.crs(point2Pos);
//set the rotation to the rotation between Z-axis and the crossmultiplied direction between point 1 and 2
rot.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));
//apply rotation
ekvatorMatrix.rotate(rot);
And here is the code for the function that returns the quaternion between two vectors:
Quaternion getRot(Vector3 pStart, Vector3 pDest) {
start.set(pStart);
dest.set(pDest);
start.nor();
dest.nor();
cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
dest.z);
rotationAxis.set(0.0f, 0.0f, 0.0f);
if (cosTheta < -1.0f + 0.001f) {
rotationAxis.set(Z_AXIS);
rotationAxis.crs(start);
if (rotationAxis.len2() < 0.01f) {
rotationAxis.set(X_AXIS);
rotationAxis.crs(start);
}
rotationAxis.nor();
resultQuat.set(rotationAxis, 180.0f);
return resultQuat;
}
rotationAxis.set(start);
rotationAxis.crs(dest);
s = (float) Math.sqrt((1 + cosTheta) * 2);
invs = 1.0f / s;
resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
rotationAxis.z * invs, s * 0.5f);
return resultQuat;
}
Assuming that the initial cylinder is axis aligned with the "circle" ends in positive and negative X direction, and assuming cylinder and sphere is initially unit size (radius=1.0) I would do the following:
Convert the world coordinate representation of the Red and "Yellow" points (let's just for fun call them A and B shall we) to normalized vectors pointing from centre [0,0,0] (from now on called C)
Calculate the angle between CA and CB (which is really just between A and B). Let's call this angle W
Calculate the vector perpendicular to both A and B by doing a cross product. Lets call this new vector D.
Find the rotation matrix that rotates from [0,0,1] to B. Lets call this M1. This can be done in the same way as in point 3 (create a perpendicular vector and rotate identity matrix around it with the angle between the normalized vectors).
Find the rotation matrix that rotates W around D. Let's call this M2
Combine M1 + M2 into M3
You result is M3
This was not tested and so I don't know if it works.

Algorithm to detect the point intersect the semi circle in android Java [duplicate]

This question already has answers here:
What algorithm can I use to determine points within a semi-circle?
(11 answers)
Closed 8 years ago.
I have a points x and y and I need to check the point which intersect within a semi- pie.
I need an algorithm to find the point is intersect in the semi circle. for rectangle we have point contains method to check the point intersect the rectangle, but this doesn't work for semi circle segments with start and end angle.
I have created many semi pie segment, when I touch the pie segment, I need to check the point intersect of which segment.
I'm assuming this is speed-critical, and also that you want to be able to specify the semi-circle as having a center and arbitrary start and end angles, so not just a semi-circle but a circular sector. For a semi-circle just make the start and end angles 180 degrees apart, or remove the test against endVector.
Make the test a two-step process. For a given point, first check that it is inside a rectangle enclosing the semi-circle. You can use your existing sort and binary search algorithm for this. If a point is not in the rectangle then reject the point, if it is then test against the semi-circle.
Also, outside of the loop, convert the values specifying the semi-circle into a form that will enable the tests to be done faster:
Convert the radius to radius squared. Compare the distance of a point from the center squared, to the radius squared. This saves a square root when computing the distance.
Convert the start and end angles of the semi-circle to a couple of 2D vectors, and then use these to check whether the point is inside the sector. Then you won't have to use any trig functions like atan2(y, x), which are slow, or do annoying fiddly comparisons to start and end angles and handling the case where angles wrap around from 360 to 0.
pseudo code:
float radiusSquared;
float startVectorX;
float startVectorY;
float endVectorX;
float endVectorY;
float centerX;
float centerY;
void convertSector(float radius, float startAngle, float endAngle)
{
radiusSquared = radius * radius;
startVectorX = cos(startAngle);
startVectorY = sin(startAngle);
endVectorX = cos(endAngle);
endVectorY = sin(endAngle);
}
boolean testPoint(float x, float y)
{
// check if point is within the radius:
float distanceX = x - centerX;
float distanceY = y - centerY;
if((distanceX * distanceX) + (distanceY * distanceY)) > radiusSq)
return false;
// check if point is outside start radius vector using 2D dot-product with normal:
if(((distanceX * -startVectorY) + (distanceY * startVectorX)) < 0.0f)
return false;
// check if point is outside end radius vector using 2D dot-product with normal:
if(((distanceX * -endVectorY) + (distanceY * endVectorX)) > 0.0f)
return false;
return true;
}
The above code will only work for sectors with an internal angle of <= 180 degrees. To test a point against sectors larger than that (i.e. Pac-Man like shapes), test if the point is inside the circle and then test that it is not inside the sector making up the remainder of the circle.

Trying to rotate a polygon using math

I have a school assignment where I'm supposed to (among other things) rotate a polygon. I can not use any premade rotate functions, so I have an array of points. The array is set up like this:
intArray[2][amount_of_points] where intArray[0] equals the points x coordinate, and intArray[1] holds the y coordinates.
//x=pivot point x coordinate, y = pivot point y coordinate.
public int[][] rotate(int[][]matrix,int x, int y, double degrees){
double s=Math.sin(degrees);
double c=Math.cos(degrees);
for (int i=0;i<matrix.length;i++){
//translate to origin
int px=matrix[0][i]-x;
int py=matrix[1][i]-y;
//rotate
double xnew = (px*c)-(py*s);
double ynew = (px*s)+(py*c);
//translate back
px=(int)((xnew+x)+0.5);
py=(int)((ynew+y)+0.5);
matrix[0][i]=px;
matrix[1][i]=py;
}
This is my code so far, and it is definitely not working out for me. I tried to trim the code as much as I could. Any help would mean a lot!
edit: I'm not getting any errors when I run the code, no exceptions etc. The only problem is that the polygon isn't rotating the way I intend it to.
I've made a test polygon:
polyArray = new int [2][3];
polyArray[0][0]=400;
polyArray[1][0]=200;
polyArray[0][1]=300;
polyArray[1][1]=500;
polyArray[0][2]=500;
polyArray[1][2]=500;
Which I draw in a JPanel, then I run this array through the rotation method like this:
polyArray=mm.rotate(polyArray, polyArray[0][0], polyArray[1][0], Math.PI);
Using the top point as pivotpoint. The whole polygon is then deformed.
Although still not very clear on question, I feel your problem is with the loop.
matrix.length is 2. So, the code never uses these :
polyArray[0][2]=500;
polyArray[1][2]=500;
If you change the condition as below, it should work :
for (int i=0;i<matrix[0].length;i++)

Point in Circle with JTS

I have a huge set of points already loaded within a plane I need to draw a circle/ellipse starting from a given point and a radius distance in meters then check which points are inside the circle.
I've already done this with a polygon with the within() method, but I can't find a way to draw a circle/ellipse without having to specify every point around the polygon.
Is there a way to do this on JTS or do I need another java library?
If I understood correctly you have the radius and the center, so you can draw a circle with JTS like this:
public static Geometry createCircle(double x, double y, final double RADIUS) {
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(32);
shapeFactory.setCentre(new Coordinate(x, y));
shapeFactory.setSize(RADIUS * 2);
return shapeFactory.createCircle();
}
You can just verify that the distance from the point is less than the radius. No need to draw the circle to know which points are inside it. For faster run times, compare the square of the distance with the square of the radius; this saves unnecessary square root operations.
For ellipses, the problem is only slightly harder, involving a quadratic form x^2 + k y^2.
You can simply buffer the circle center with a positive value like so:
Point centerPoint = ...;
Polygon circle = (Polygon) centerPoint.buffer(0.1);

Categories

Resources