Overall goal: Given a list of points in 3-dimensional space, I need to generate a sphere around that point given the point's radius and then pro grammatically check if there is space between two or more spheres given a certain point.
Problem: I'm having trouble thinking of a data structure to represent a grid of points (that represent the center of the sphere) and the surrounding sphere, these may not always be hole numbers.
Example Data:
Point A: (-3, .25, 4) Radius: 1.35
Point B: (5, 6.35, 1) Radius: 2
Point C: (1, 0, -1) Radius: .5
My original idea was to have a 3-dimensional array of integers that was of size the absolute value of the maximum and minimum values of the axes added together divided by the smallest accuracy you wanted. You would then use a conversion factor to convert from the array location (whole integers) to the decimal location of a point you were looking for. I would then fill in the array with some data to represent that a sphere exists around the sphere center.
What I'm looking for is the data structure I should use to represent this 3d grid of non-whole numbers. I feel like my technique isn't correct.
This is in Java.
Any and all help is greatly appreciated, thanks!
Why not just represent them with the 3 coordinates x,y,z (3d-point) and the radius, just as you listed them and use (3dimensional) distance to evaluate if points are inside a sphere or not?
Or am I missing the use case here? This sounds like it: "check if there is space between two or more spheres given a certain point"
I actually did something very similar earlier this week.
What I did is decide the minimum distance two points are allowed to have (here for you found by adding the radii of your two spheres if I understood you correctly). Using this I created a random field of spheres using a starting sphere at (0, 0, 0) and then incrementally add extra spheres a random distance away from that.
Since in my case (not sure if you need this as well) I also had a maximum distance I just shifted the coordinates of one of the already accepted spheres and check whether the distances matched.
So, to summarize:
Have a starting point
Randomly place a point (within a specific range) to one of your existing points
Check if it meets your spacing restrictions
Repeat 2-3 until you have enough spheres.
Hope that's any help to anybody.
Related
I have a position given in decimal degrees (x.xxxxxxxx and y.yyyyyyyy). I need to draw a rectangle around it. The center of the rectangle matches the position. The dimensions of the rectangle is given in meters and it has a rotation ranging from 0-360 degrees.
Question
How can I calculate the four corners of the rectangle and return the result as four decimal degree values? Like arrayOf<LatLon> getRectangle(LatLon position, int rectWidthCm, int rectLengthCm, double rectRotation).
Example
I have a position given in LatLon format with two two values: latitude and longitude. We will assume this location is precise.
The main task is to draw a rectangle based on this position in a Google Maps chart. The rectangle can have any dimentions but let's use these in this example: Width = 0.9 meter and Length = 1.2 meters. Any heading may also be given so lets use this heading: 45. 0 Is north and going clockwise round (east = 90, south = 180 and west = 270). When the rectangle is pointing north it has the length in the north/south direction. Finally, the rectangle center should be equal to the given position.
Note: The project setup is an Android application with Kotlin support and a google maps chart. I am interested in a modern approach to this problem. Regarding precision loss it should at most be within centimeters.
I understand that you are looking for a function geo_rect(x,y,w,h,a) with the following parameters
x is the longitude according to WGS84
y is the latitude
w is the width of the rectangle in meters
h is the height of the rectangle in meters
a is the angle to which the rectangle is turned from w being horizontal (meaning pointing exactly West to East). I suggest to allow values ranging within the open interval (-90°,90°) as this makes the math either to understand.
Your function getRectangle(LatLon position, int rectWidthCm, int rectLengthCm, double rectRotation) deliver all the required information, you need a small wrapper function which determines w, h, and a from rectWidthCm, rectLengthCm and rectRotation, with the latter being within [0°,360°).
The function geo_rect() will return an arrayOf<LatLon> of length four, namely the coordinates of all four corners, starting on the top left and then going clockwise. We will refer to the points as P_NE,P_NW,P_SE, and P_SW respectively.
Assumptions
In order to keep things mathematically feasible, we make some assumptions
We assume that we can use as approximation that the rectangle is a plane, which is okay if w ~ h << r with r = 6378 km being the radius of the Earth.
We further assume that the Earth is a ideal sphere rather than an ellipsoid or even more bumpy. For an accessible article on that issue, see e.g. Zachary C. Eilon's blog
Basic structure of the algorithm
The algorithm could be structured as follows:
Determine the distance d from (x,y) to all four end points. Because of our first assumption we can use simple Euclidian geometry rather than intricate Spherical geometry. Pythagoras holds: d^2 = (w/2)^2 + (h/2)^2.
We also need the four bearings, e.g. b_NW for the angle between the vector pointing to the North Pole and the vector pointing from (x,y) to point P_NW.
Given the information (x,y,d,b_NW, b_NE, b_SW, b_SE) from the previous steps, we can now follow Get lat/long given current point, distance and bearing to calculate the position of all four points. This is the mathematically hard part where I suggest to use a well-established and tested library for.
Last but not least, let us double-check whether the calculation went well by evaluating Great circle distances between some or all pairs of points. For instance d(P_NE,P_NW) should approximately be w, d(P_NW,P_SW) should approximately be h. Don't be surprised if there is actually a difference - this errors are due the assumptions we made. Normal GPS under usual conditions will anyhow not allow you to determine your position up to the centimeter, you will need DPGS for that.
Further reading
At https://www.movable-type.co.uk/scripts/latlong-vectors.html you can experiment online to determine a destination point along a great-circle given the distance and bearing from a start point (in our case: the center of the rectangle).
Old, but amazingly documented and well tested tool kit for geo-applications in general are the https://www.generic-mapping-tools.org/ - you might want to look at the command gmtvector.
If you are looking for java implementations, I found e.g.
https://introcs.cs.princeton.edu/java/12types/GreatCircle.java.html on of many implementations for calculating great circle distances
Need a standalone Java library for performing spatial calculations on lat/lon data
Calculate point based on distance and direction
Given a list of colors(RGB values) L and a color C, determine if we can mix 2 or more colors from the list L to obtain C. The colors from the list can be mixed in any proportion.
You can visualize the RGB values as points in 3D space. The problem then becomes whether you can express the RGB value of your target color as an interpolation between other points in the color space.
An ideal way to do this is by using Barycentric co-ordinates, with the condition that the co-ordinates (i.e. the mixing proportions) add to 1. So, you need to go through your list and find a set of 2 to 4 points that form a line, triangle or tetrahedron simplex that encloses your target point. The cartesian co-ordinates of a point (in this case, the RGB values) can be calculated as a linear combination of the simplex points with the barycentric co-ordinates as co-efficients, so the barycentric co-ordinates of the point will be your mixing proportions. The point needs to be inside the simplex, or else you will end up with proportions that aren't in the range of 0-1, which I assume is invalid.
If you have a large list of points and you want to find out if a valid set of mixing proportions exists, compute the convex hull of all the points and check if your target point lies inside it.
You can try using rectilinear transformation of coordination compression. Visualize it as a 3d space and then combine three points to get to the target color.
Hope that helps!
I am making a java program that classifies a set of lat/lng coordinates to a specific rectangle of a custom size, so in effect, map the surface of the earth into a custom grid and be able to identify what rectangle/ polygon a point lies in.
The way to do this I am looking into is by using a map projection (possibly Mercator).
For example, assuming I want to classify a long/lat into 'squares' of 100m x 100m,
44.727549, 10.419704 and 44.727572, 10.420460 would classify to area X
and
44.732496, 10.528092 and 44.732999, 10.529465 would classify to area Y as they are within 100m apart.
(this assumes they lie within the same boundary of course)
Im not too worried about distortion as I will not need to display the map, but I do need to be able to tell what polygon a set of coordinates belong to.
Is this possible? Any suggestions welcome. Thanks.
Edit
Omitting projection of the poles is also an acceptable loss
Here is my final solution (in PHP), creates a bin for every square 100m :
function get_static_pointer_table_id($lat, $lng)
{
$earth_circumference = 40000; // km
$lat_bin = round($lat / 0.0009);
$lng_length = $earth_circumference * cos(deg2rad($lat));
$number_of_bins_on_lng = $lng_length * 10;
$lng_bin = round($number_of_bins_on_lng * $lng / 360);
//the 'bin' unique identifier
return $lat_bin . "_" . $lng_bin;
}
If I understand correctly, you are looking for
a way to divide the surface of the earth into approximately 100m x 100m squares
a way to find the square in which a point lies
Question 1 is mission impossible with squares but much less so with polygons. A very simple way to create the polygons would to use the coordinates themselves. If each polygon is 0.0009° in latitude and longitude, you will have approximately square 100m x 100m grid on the equator, put the slices will become very thin close to the poles.
Question 2 depends on the approximation used to solve the challenge outlined above. If you use the very simple method above, then placing each coordinate into a bin is just a division by 0.0009 (and rounding down to the closest integer).
So, first you will have to decide what you can compromise. Is it important to have equal area in the polygons, equal longitudinal distance, equal latitude distance, etc.? Is it important to have four corners in the polygon? Is it important to have similar or almost similar polygons close to the poles and close to the equator? Once you know the limitations set by your application, choosing the projection becomes easier.
What you are trying to do here is a projection onto a flat surface of an ellipsoid. So as long as your points are close together, and, well, you don't mind getting the answer slightly wrong you can assume that your projection plane intersects in the centre of your collection of points, and, each degree of lat and lon are a constant number of metres. Then the problem is a simple planar calculation.
This is wrong, of course. I would actually recommend that you look into map projections, pick one that makes sense, and go for that. Remember that you can move the centre of the projection to the centre to your set of points which will reduce distortion.
I suspect that PROJ.4 might help you in terms of libraries. There also must be a good Java one but that is not my speciality.
Finally you can could assume that the earth is a sphere and do your calculations on the sphere. Or, if you really want to get it right you can pick a standard earth ellipsoid and do the calculations on that.
Problem: Given a list of spheres, find all empty spaces that are completely enclosed by spheres.
Detail: This is a problem I am working on in which I try to determine the cavities located in a protein. I am given a list of atoms that make up the protein ((x,y,z) coordinates and radius). I then run my algorithm to find all empty spaces that lie within the bounds of the protein by checking if a probe (of given radius) can be placed at a location without colliding with other spheres. There are two types of empty spaces, void spaces and cavities. Void spaces are spaces that can lead to or on the outside of the protein. Cavities are empty spaces that are completely enclosed by protein atoms. Here is an image of the sample "protein" we are working with.
It can be viewed in three dimensions here.
There is a cavity located near the center of the protein, the tunnel you see going through the protein would be considered a void space because it is not fully enclosed by atoms.
Example: Given a list of 26 atoms, these atoms are evenly spaced from (0,0,0) to (1,1,1) in a 3-dimensional grid. Each atom has a radius of 0.25 and is placed on either 0, 0.5, or 1 on any axis. There is no atom at the point (0.5, 0.5, 0.5). If we were to draw a 3D figure of these atoms, it would be a cube like shape with the center missing. A cavity would be designated at (0.5,0.5,0.5) with a radius of 0.25. It can be assumed that this cavity is surrounded by proteins on all sides.
Example image:
Note that the above is only a 2D representation of the cube and protein. It is actually 3D.
How would one go about determining void spaces vs. cavities for a much larger and irregularly shaped group of atoms?
I was thinking about implementing a recursive algorithm that checks every direction to see if it can reach the maximum and minimum bounds of the graph but I am not sure if this is the correct way to go about doing it.
Extra: Is there a different algorithm that would say the cavity in the example is actually a void space because there are very small "paths" to reach the outside of the protein? A cavity would have to be completely enclosed by atoms to exist. Any void spaces that have a path (in any direction, not necessarily straight) to the outside of the protein would not be considered cavities.
Cool question. Here's an algorithm that should do the trick:
Notation:
Let's call our moveable sphere S.
Write diam(X) for the diameter of a sphere X
Write dist(X,Y) for the distance from X to Y; this is the same as the distance from the center of X to the center of Y minus the sum of the radii.
The algorithm:
For any two unmoveable spheres A and B, check whether S can pass directly between the centers of A and B (i.e. is diam(S) <= dist(A,B)?).
If so, for each other sphere C, check whether S could simultaneously touch all three spheres A, B, and C, if there were no other spheres present. If S could simultaneously touch all 3, draw a triangle between the centers of A, B, and C.
This can be checked in several ways. One fairly easy way: the possible positions of the center of S while touching both A and B form a circle. You want to know whether this circle has a point on it which is less than diam(S) + diam(C) away from the center of C. This is easy geometry.
The problem now reduces to the question: do the triangles separate the initial position of the center of S from infinity? You can answer this one connected component at a time. In fact, you can even answer this one "edge-connected" component at a time, where a component is edge-connected if any two non-vertex points can be linked by a path that doesn't pass through any vertices. You can calculate these components through a simple graph search.
For a given edge-connected component, you need to decide whether the component separates the center of S from infinity. There are a few ways you might do this:
Calculate the 2-homology of the component, choose effective generators, and for each, ask whether your point and infinity are on the same side of the cycle or not, which can be checked using the orientation class.
Or, just start painting the component:
Start with a triangle that you can reach from S, and paint every face that can be reached from there. This is slightly subtle, but the algorithm is just "start anywhere, queue up the edges, cross each edge onto the face forming the smallest angle with that edge, and stop when there are no edges left." Keep in mind that the opposite side of the same triangle might be the face forming the smallest angle.
Do the same from infinity. Did you cross any painted triangles? If yes, your sphere can escape. If no, it can't.
Why it works
Step 3 is true because if you don't hit any sphere C while "rolling around" the edge between A and B, then you can reach any side of that edge. Put another way, any position that stops you from going to infinity must involve S touching at least 3 spheres.
Note that there are some subtleties that arise from "exceptional" situations, like when S touches 4 spheres at once. You can avoid these subtleties by re-triangulating your shape before performing steps 3 and 4.
I have two geo-spatial simple convex polygon areas, in latitudes and longitudes (decimal degrees) that I want to compute using Javas Polygon class. I basically want to see if these two lat,long polygons intersect, and to calculate the areas (in sq meters) of both.
Now java.awt.Polygon class only uses x,y co-ordinate system, but I need to use lats,longs.
How can I do this, and/or is there any other classes/libraries available?
Why not use Polygon class multiplying coordinates for 10^n making them integers? Polygon accepts arrays of int as points.
Just an Idea
All you need to do is convert from spherical to rectangular coordinates if you think that really matters.
I'm not sure that it does, because the java.awt.Polygon is merely a data structure holding for pairs of values. If you read the javadocs, they say
The Polygon class encapsulates a description of a closed, two-dimensional region within a coordinate space. This region is bounded by an arbitrary number of line segments, each of which is one side of the polygon. Internally, a polygon comprises of a list of (x,y) coordinate pairs, where each pair defines a vertex of the polygon, and two successive pairs are the endpoints of a line that is a side of the polygon. The first and final pairs of (x,y) points are joined by a line segment that closes the polygon.
They happen to label those points as x and y, which makes all of us think rectangular coordinates, but they need not be from your point of view. A bug on the service of your sphere would view it as a 2D space. Your radius is large and constant. You just can't count on using any of Polygon's methods (e.g., contains(), getBounds2D(), etc.)
In this case, the important thing is your area calculation. You can use a Polygon for your area calculation, storing lats and longs, as long as you view Polygon as a data structure.
You might also thing of abandoning this idea and writing your own. It's not too hard to create your own Point and Polygon for spherical coordinates and doing it all with that coordinate system in mind from the start. Better abstraction, less guessing for clients. Your attempt to reuse java.awt.Polygon is admirable, but not necessary.
You can perform the area calculation easily by converting it to a contour integral and using Gaussian quadrature to integrate along each straight line boundary segment. You can even include the curvature of each segment at each integration point, since you know the formula.
Going off my intuition here.
If the polygons are small in ratio to the size of the planet you can treat them as flat polygons. The steps involved would be converting the lat/long into absolute x/y/z, taking any three of the points and finding the normal of the plane the polygons lie on and then using this to project the points into two dimensions. Once you have the 2D points it's easy to calculate the area or if they intersect.
Probably not the best answer but hopefully it will motivate some people to make better ones because it's a good question.
Maybe you could use GeoTools for this. It allows you to create Geometry objects, and check wether they intersect (see: Geometry Relationships)
Here is a solution that works like a charm:
Class PolygonArea from net.sf.geographiclib
Refer link below with sample code:
https://geographiclib.sourceforge.io/html/java/net/sf/geographiclib/PolygonArea.html
gradle dependency:
compile group: 'net.sf.geographiclib', name: 'GeographicLib-Java', version: '1.42'