I can't quite figure this one out.
I am trying to approximate the location (latitude / longitude) of a beacon based on 3 distance measurements from 3 fixed locations. However the distance readings available may have an error of up to 1 km.
Similar questions regarding trilateration have been asked here (with precise measurements), here, here (distance measurement errors in Java, but not in lat/lon coordinates and no answers) as well as others. I also managed to dig up this paper dealing with imperfect measurement data, however it for one assumes a cartesian coordinate system and is also rather mathematical than close to a usable implementation.
So none of above links and answers are really applicable to the following problem:
All available distance measurements are approximated in km (where data most frequently contains readings in-between 1 km and 100 km, in case this matters)
Measurement errors of up to 1 km are possible.
3 distance measurements are performed based on 3 fixed (latitude / longitude known) positions.
target approximation should also be a latitude / longitude combination.
So far I have adapted this Answer to C#, however I noticed that due to the measurement inaccuracies this algorithm does not work (as the algorithm assumes the 3 distance-circles to perfectly intersect with each other):
public static class Trilateration
{
public static GeoLocation Compute(DistanceReading point1, DistanceReading point2, DistanceReading point3)
{
// not my code :P
// assuming elevation = 0
const double earthR = 6371d;
//using authalic sphere
//if using an ellipsoid this step is slightly different
//Convert geodetic Lat/Long to ECEF xyz
// 1. Convert Lat/Long to radians
// 2d. Convert Lat/Long(radians) to ECEF
double xA = earthR * (Math.Cos(Radians(point1.GeoLocation.Latitude)) * Math.Cos(Radians(point1.GeoLocation.Longitude)));
double yA = earthR * (Math.Cos(Radians(point1.GeoLocation.Latitude)) * Math.Sin(Radians(point1.GeoLocation.Longitude)));
double zA = earthR * Math.Sin(Radians(point1.GeoLocation.Latitude));
double xB = earthR * (Math.Cos(Radians(point2.GeoLocation.Latitude)) * Math.Cos(Radians(point2.GeoLocation.Longitude)));
double yB = earthR * (Math.Cos(Radians(point2.GeoLocation.Latitude)) * Math.Sin(Radians(point2.GeoLocation.Longitude)));
double zB = earthR * (Math.Sin(Radians(point2.GeoLocation.Latitude)));
double xC = earthR * (Math.Cos(Radians(point3.GeoLocation.Latitude)) * Math.Cos(Radians(point3.GeoLocation.Longitude)));
double yC = earthR * (Math.Cos(Radians(point3.GeoLocation.Latitude)) * Math.Sin(Radians(point3.GeoLocation.Longitude)));
double zC = earthR * Math.Sin(Radians(point3.GeoLocation.Latitude));
// a 64 bit Vector3 implementation :)
Vector3_64 P1 = new(xA, yA, zA);
Vector3_64 P2 = new(xB, yB, zB);
Vector3_64 P3 = new(xC, yC, zC);
//from wikipedia
//transform to get circle 1 at origin
//ransform to get circle 2d on x axis
Vector3_64 ex = (P2 - P1).Normalize();
double i = Vector3_64.Dot(ex, P3 - P1);
Vector3_64 ey = (P3 - P1 - i * ex).Normalize();
Vector3_64 ez = Vector3_64.Cross(ex, ey);
double d = (P2 - P1).Length;
double j = Vector3_64.Dot(ey, P3 - P1);
//from wikipedia
//plug and chug using above values
double x = (Math.Pow(point1.DistanceKm, 2d) - Math.Pow(point2.DistanceKm, 2d) + Math.Pow(d, 2d)) / (2d * d);
double y = ((Math.Pow(point1.DistanceKm, 2d) - Math.Pow(point3.DistanceKm, 2d) + Math.Pow(i, 2d) + Math.Pow(j, 2d)) / (2d * j)) - ((i / j) * x);
// only one case shown here
double z = Math.Sqrt(Math.Pow(point1.DistanceKm, 2d) - Math.Pow(x, 2d) - Math.Pow(y, 2d));
//triPt is a vector with ECEF x,y,z of trilateration point
Vector3_64 triPt = P1 + x * ex + y * ey + z * ez;
//convert back to lat/long from ECEF
//convert to degrees
double lat = Degrees(Math.Asin(triPt.Z / earthR));
double lon = Degrees(Math.Atan2(triPt.Y, triPt.X));
return new GeoLocation(lat, lon);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double Radians(double degrees) =>
degrees * Math.Tau / 360d;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double Degrees(double radians) =>
radians * 360d / Math.Tau;
}
Above code most often than not does not work in my case, and instead only returns "Not a number" as it tries to take the square root of a negative number when calculating the final z value (due to measurement inaccuracies).
In my case measurements may return data like this (visualized with some random online tool):
where only 2 or even none of the distance circles intersect:
What I am looking for is the an algorithm returning the best possible approximation of the target location based on three distance measurements with a known maximum error of 1 km or further approaches I could take.
I have also thought of iterating over points on the circles to then determining the minimum average distance to all the points on the other circles but the 3-dimensional sphere geometry of the earth is giving me a headache. Also there's probably a way better and simpler approach to this which I just can't figure out right now.
As this is more of an algorithmic problem, rather than any language-specific thing, I appreciate any help in whatever programming language, pseudo code or natural language.
If you have access to a scientific computing library which provides non-linear optimization utilities, then you could try finding the point which minimizes the following:
(||x - p_1|| - r_1)^2 + (||x - p_2|| - r_2)^2 + (||x - p_3|| - r_3)^2 + (||x - p_earth|| - r_earth)^2
where p_i is the location (in Cartesian coordinates) of the ith location you measure from, r_i is the corresponding distance reading, p_earth is the location of the Earth, r_earth is the radius of the earth, and ||a|| denotes the norm/length of the vector a.
Each term in the expression is trying to minimize the residual radius error.
This can of course be modified to suit your needs - e.g. if constrained optimization is available, you could encode the requirement that the point be on the surface on the earth as a constraint rather than a term to optimize for. If spherical earth model isn't accurate enough, you could define an error from the Earth's surface, or just project your result onto the Earth if that is accurate enough.
I have two known Google Geolocation points A and B. I need to return GeoLocation point C which is on AB line and on distance x from point A:
Geolocation returnGeolocationC(Geolocation A, Geolocation B, double x) {
...
return C;
}
I know that I can use Haversine formula and I can calculate AB distance and therefore I also have AC and CB distance. Any idea or hint how to implement this?
Edit: Line is straight, no need to consider roads.
Well, this is a good problem which solution will depend on the area of interest, for instance:
Consider the situation faced by a botanist studying a stand of oak trees on a small plot of land. One component of the data analysis involves determining the location of these trees and calculating the distance betwee
n them. In this situation, straight line or Euclidean distance is the most logical choice. This only requires the use of the Pythagorean Theorem to calculate the shortest distance between two points:
straight_line_distance = sqrt ( ( x2 - x1 )**2 + ( y2 - y1 )**2 );
The variables x and y refer to co-ordinates in a two-dimensional plane and can reflect any unit of measurement, such as feet or miles.
Consider a different situation, an urban area, where the objective is to calculate the distance between customers’ homes and various retail outlets. In this situation, distance takes on a more specific meaning, usually road distance, making straight line distance less suitable. Since streets in many cities are based on a grid system, the typical trip may be approximated by what is known as the Manhattan, city block or taxi cab distance (Fothering-
ham, 2002):
block_distance = ( abs( x2 - x1 ) + abs( y2 - y1 ) ) ;
Instead of the hypotenuse of the right-angled triangle that was calculated for the straight line distance, the above formula simply adds the two sides that form the right angle. The straight line and city block formulae are closely related, and can be generalized by what are referred to as the Minkowski metrics, which in this case are restricted to two dimensions:
minkowski_metric = ( abs(x2 - x1)**k + abs(y2 - y1)**k )**(1/k);
The advantage of this formula is that you only need to vary the exponent to get a range of distance measures. When k = 1, it is equivalent to the city block distance; when k=2, it is the Euclidean distance. Less commonly,
other values of k may be used if desired, usually between 1 and 2. In some situations, it may have been determined that actual distances were greater than the straight line, but less than the city block, in which case a value such as "1.4" may be more appropriate. One of the interesting features of the Minkowski metric is that for values considerably larger than 2 (approaching infinity), the distance is the larger of two sides used in the city block calculation, although this is typically not applicable in a geographic context.
So pseudocode would be something like the following:
distance2d (x1, y1, x2, y2, k)
(max( abs(x2 - x1), abs(y2 - y1) ) * (k > 2))
+
((abs(x2 - x1)**k + abs(y2 - y1)** k )**(1/ k)) * (1 <=k<=2)
end
If 1 <= k <=2, the basic Minkowski metric is applied, since (1 <= k <=2) resolves to 1 and (k > 2) resolves to 0. If k > 2, an alternate formula is applied, since computations become increasingly intensive for large values of k. This second formula is not really necessary, but is useful in demonstrating how modifications can be easily incorporated in distance measures.
The previous distance measures are based on the concept of distance in two dimensions. For small areas like cities or counties, this is a reasonable implification. For longer distances such as those that span larger countries
or continents, measures based on two dimensions are no longer appropriate, since they fail to account for the curvature of the earth. Consequently, global distance measures need to use the graticule, the co-ordinate system
comprised of latitude and longitude along with special formulae to calculate the distances. Lines of latitude run in an east to west direction either above or below the equator. Lines of longitude run north and south through the poles, often with the Prime Meridian (running through Greenwich, England) measured at 0°. Further details of latitude and longitude are available (Slocum et al., 2005). One issue with using latitude and longitude is that the co-ordinates may require some transformation and preparation before they are suitable to use in distance calculations. Coordinates are often expressed in the sexagesimal system (similar to time) of degrees, minutes, and seconds, in which each degree consists of 60 minutes and each
minute is 60 seconds. Furthermore, it is also necessary to provide and indication of the position relative to the equator (North or South) and the Prime Meridian (East or West). The full co-ordinates may take on a variety of formats; below is a typical example that corresponds approximately to the city of Philadelphia:
39° 55' 48" N 75° 12' 12" W
As you mentioned Harvesine, and also I am extending a lot, we can compare results using law of cosines and Harvesine, so pseudocode:
begin
ct = constant('pi')/180 ;
radius = 3959 ; /* 6371 km */
#Both latitude and longitude are in decimal degrees ;
lat1 = 36.12;
long1 = -86.67;
lat2 = 33.94;
long2 = -118.40 ;
#Law of Cosines ;
a = sin(lat1*ct) * sin(lat2*ct) ;
b = cos(lat1*ct) * cos(lat2*ct) * cos((long2-long1) *ct);
c = arcos(a + b) ;
d = radius * c ;
put 'Distance using Law of Cosines ' d
# Haversine ** ;
a2 = sin( ((lat2 - lat1)*ct)/2)**2 +
cos(lat1*ct) * cos(lat2*ct) * sin(((long2 - long1)*ct)/2)**2
c2 = 2 * arsin(min(1,sqrt(a2))) ;
d2 = radius * c2 ;
put 'Distance using Haversine formula =' d2
end
In addition to the constant that will be used to convert degrees to radians, the radius of the earth is required, which on average is equal to 6371 kilometres or 3959 miles. The Law of Cosines uses spherical geometry to
calculate the great circle distance for two points on the globe. The formula is analogous to the Law of Cosines for plane geometry, in which three connected great arcs correspond to the three sides of the triangle. The Haversine formula is mathematically equivalent to the Law of Cosines, but is often preferred since it is less sensitive to round-off error that can occur when measuring distances between points that are located very close tog
ether (Sinnott, 1984). With the Haversine, the error can occur for points that are on opposite sides of the earth, but this is usually less of a problem.
You can find a really easy formula at this link.
Since you have the distance from one of the points and not the fraction of the distance on the segment you can slightly modify the formula:
A=sin(d-x)/sin(d)
B=sin(x)/sin(d)
x = A*cos(lat1)*cos(lon1) + B*cos(lat2)*cos(lon2)
y = A*cos(lat1)*sin(lon1) + B*cos(lat2)*sin(lon2)
z = A*sin(lat1) + B*sin(lat2)
lat=atan2(z,sqrt(x^2+y^2))
lon=atan2(y,x)
where x is the required distance and d is the distance between A and B (that you can evaluate with Haversine), both divided by the Earth radius.
You can also use another formula for sin(d):
nx = cos(lat1)*sin(lon1)*sin(lat2) - sin(lat1)* cos(lat2)*sin(lon2)
ny = -cos(lat1)*cos(lon1)*sin(lat2) + sin(lat1)* cos(lat2)*cos(lon2)
nz = cos(lat1)*cos(lon1)*cos(lat2)*sin(lon2) - cos(lat1)*sin(lon1)*cos(lat2)*cos(lon2)
sind = sqrt(nx^2+ny^2+nz^2)
It's more complex than the Haversine formula, but you can memoize some of the factors in the two steps.
As the OP posted a non working Java implementation, this is my corrections to make it work.
private static GpsLocation CalcGeolocationWithDistance(GpsLocation pointA, GpsLocation pointB, double distanceFromA)
{ //distanceFromA = 2.0 km, PointA and PointB are in Europe on 4.0km distance.
double earthRadius = 6371000.0;
double distanceAB = CalcDistance(pointA.Latitude, pointA.Longitude, pointB.Latitude, pointB.Longitude);
//distance AB is calculated right according to Google Maps (4.0 km)
double a = Math.Sin((distanceAB - distanceFromA) / earthRadius) / Math.Sin(distanceAB / earthRadius);
double b = Math.Sin(distanceFromA / earthRadius) / Math.Sin(distanceAB / earthRadius);
double x = a * Math.Cos(pointA.Latitude * Math.PI / 180) * Math.Cos(pointA.Longitude * Math.PI / 180) + b * Math.Cos(pointB.Latitude * Math.PI / 180) * Math.Cos(pointB.Longitude * Math.PI / 180);
double y = a * Math.Cos(pointA.Latitude * Math.PI / 180) * Math.Sin(pointA.Longitude * Math.PI / 180) + b * Math.Cos(pointB.Latitude * Math.PI / 180) * Math.Sin(pointB.Longitude * Math.PI / 180);
double z = a * Math.Sin(pointA.Latitude * Math.PI / 180) + b * Math.Sin(pointB.Latitude * Math.PI / 180);
double lat = Math.Atan2(z, Math.Sqrt(x * x + y * y)) * 180 / Math.PI;
double lon = Math.Atan2(y, x) * 180 / Math.PI;
//lat and lon are mo more placed somewhere in Africa ;)
return new GpsLocation(lat, lon);
}
I'm trying to implement the following in Java.
Given a list of circles of different sizes (possibly) and positions, determine a large circle (position and size) which just exactly encloses all the circles.
public class Circle {
public int x, y, radius;
}
Any ideas?
The miniball-of-balls problem has been studied in "The smallest enclosing ball of balls: combinatorial structure and algorithms", for example. One outcome of this research was that at least some algorithms for the miniball-of-points problem (like Welzl's algorithm) cannot easily be generalised from points to balls.
The above paper presents an O(n)-algorithm to compute the miniball of a set of balls (n being the number of input balls, i.e., circles in 2D). A C++ implementation thereof is available in the Computational Geometry Algorithms Library (CGAL). (You do not need to use all of CGAL; simply extract the required header and source files.)
Note: I am a co-author of the above paper and the author of the CGAL Min_sphere_of_spheres package.
I have a roughly O(n4) true solution that I'm implementing for a product in JavaScript:
You need a function to determine whether a solution is valid: to be precise, a function that will check if all the circles lie within the proposed super-circle. This is fairly trivial: for every circle Ci, require that the distance from the centre of the super circle to the centre of Ci plus the radius of Ci is less than or equal to the radius of the super-circle.
Then, construct a super-circle out of every pair and every triple of circles.
For a pair, draw a line from the centre of Ci to the centre of Cj. Extend the line out on each end by the radius of the respective circle. The midpoint of the line is the centre of the super-circle, and its radius is half the length of the line.
For 3 circles, this is the Problem of Apollonius: http://mathworld.wolfram.com/ApolloniusProblem.html; noting that you need to get the correct signs to get one that will include all three circles.
The correct solution is the valid super-circle with the smallest radius.
Here's my code:
'use strict';
/**
* Epsilon value for floating point equality.
* #const
*/
var EPSILON = 1E-6;
/**
* Calculates the minimum bounding circle for a set of circles.
* O(n^4)
*
* #param {Array.<Object.<string, number>>} circles A list of 2+ circles.
* #return {Object.<string, number>} {cx, cy, radius} of the circle.
*/
function minimumBoundingCircleForCircles(circles) {
var areAllCirclesInOrOnCircle = function(circle) {
for (var i = 0; i < circles.length; i++) {
if (!isCircleInOrOnCircle(circles[i], circle)) return false;
}
return true;
};
// try every pair and triple
var best = {radius: 9E9};
for (var i = 0; i < circles.length; i++) {
for (var j = i + 1; j < circles.length; j++) {
var circle = circleFrom2Circles(circles[i], circles[j]);
if (areAllCirclesInOrOnCircle(circle) &&
circle.radius < best.radius) {
best.cx = circle.cx; best.cy = circle.cy;
best.radius = circle.radius;
}
for (var k = j + 1; k < circles.length; k++) {
var signs = [-1, 1, 1, 1];
circle = apollonius(circles[i], circles[j], circles[k],
signs);
if (areAllCirclesInOrOnCircle(circle) &&
circle.radius < best.radius) {
best.cx = circle.cx; best.cy = circle.cy;
best.radius = circle.radius;
}
}
}
}
return best;
}
/**
* Calculates a circle from 2 circles.
*
* #param {Object.<string, number>} circle1 The first circle.
* #param {Object.<string, number>} circle2 The second circle.
* #return {Object.<string, number>} cx, cy, radius of the circle.
*/
function circleFrom2Circles(circle1, circle2) {
var angle = Math.atan2(circle1.cy - circle2.cy,
circle1.cx - circle2.cx);
var lineBetweenExtrema = [[circle1.cx + circle1.radius * Math.cos(angle),
circle1.cy + circle1.radius * Math.sin(angle)],
[circle2.cx - circle2.radius * Math.cos(angle),
circle2.cy - circle2.radius * Math.sin(angle)]];
var center = lineMidpoint(lineBetweenExtrema[0], lineBetweenExtrema[1]);
return { cx: center[0],
cy: center[1],
radius: lineLength(lineBetweenExtrema[0],
lineBetweenExtrema[1]) / 2
};
}
/**
* Solve the Problem of Apollonius: a circle tangent to all 3 circles.
* http://mathworld.wolfram.com/ApolloniusProblem.html
*
* #param {Object.<string, number>} circle1 The first circle.
* #param {Object.<string, number>} circle2 The second circle.
* #param {Object.<string, number>} circle3 The third circle.
* #param {Array.<number>} signs The array of signs to use.
* [-1, 1, 1, 1] gives max circle.
* #return {Object.<string, number>} The tangent circle.
*/
function apollonius(circle1, circle2, circle3, signs) {
var sqr = function(x) { return x * x };
var a1 = 2 * (circle1.cx - circle2.cx);
var a2 = 2 * (circle1.cx - circle3.cx);
var b1 = 2 * (circle1.cy - circle2.cy);
var b2 = 2 * (circle1.cy - circle3.cy);
var c1 = 2 * (signs[0] * circle1.radius + signs[1] * circle2.radius);
var c2 = 2 * (signs[0] * circle1.radius + signs[2] * circle3.radius);
var d1 = (sqr(circle1.cx) + sqr(circle1.cy) - sqr(circle1.radius)) -
(sqr(circle2.cx) + sqr(circle2.cy) - sqr(circle2.radius));
var d2 = (sqr(circle1.cx) + sqr(circle1.cy) - sqr(circle1.radius)) -
(sqr(circle3.cx) + sqr(circle3.cy) - sqr(circle3.radius));
// x = (p+q*r)/s; y = (t+u*r)/s
var p = b2 * d1 - b1 * d2;
var q = (- b2 * c1) + (b1 * c2);
var s = a1 * b2 - b1 * a2;
var t = - a2 * d1 + a1 * d2;
var u = a2 * c1 - a1 * c2;
// you are not expected to understand this.
// It was generated using Mathematica's Solve function.
var det = (2 * (-sqr(q) + sqr(s) - sqr(u)));
var r = (1 / det) *
(2 * p * q + 2 * circle1.radius * sqr(s) + 2 * t * u -
2 * q * s * circle1.cx - 2 * s * u * circle1.cy + signs[3] *
Math.sqrt(sqr(-2 * p * q - 2 * circle1.radius * sqr(s) - 2 * t * u +
2 * q * s * circle1.cx + 2 * s * u * circle1.cy) -
4 * (-sqr(q) + sqr(s) - sqr(u)) *
(-sqr(p) + sqr(circle1.radius) * sqr(s) - sqr(t) +
2 * p * s * circle1.cx - sqr(s) * sqr(circle1.cx) +
2 * s * t * circle1.cy - sqr(s) * sqr(circle1.cy))))
//console.log(r);
r = Math.abs(r);
var x = (p + q * r) / s;
var y = (t + u * r) / s;
//console.log(x); console.log(y);
return {cx: x, cy: y, radius: r};
}
/**
* Is the circle inside/on another circle?
*
* #param {Object.<string, number>} innerCircle the inner circle.
* #param {Object.<string, number>} outerCircle the outer circle.
* #return {boolean} is the circle inside/on the circle?
*/
function isCircleInOrOnCircle(innerCircle, outerCircle) {
return ((lineLength([innerCircle.cx, innerCircle.cy],
[outerCircle.cx, outerCircle.cy]) +
innerCircle.radius - EPSILON) < outerCircle.radius);
}
/**
* Calculates the length of a line.
* #param {Array.<number>} pt1 The first pt, [x, y].
* #param {Array.<number>} pt2 The second pt, [x, y].
* #return {number} The length of the line.
*/
function lineLength(pt1, pt2) {
return Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) +
Math.pow(pt1[1] - pt2[1], 2));
}
/**
* Calculates the midpoint of a line.
* #param {Array.<number>} pt1 The first pt, [x, y].
* #param {Array.<number>} pt2 The second pt, [x, y].
* #return {Array.<number>} The midpoint of the line, [x, y].
*/
function lineMidpoint(pt1, pt2) {
return [(pt1[0] + pt2[0]) / 2,
(pt1[1] + pt2[1]) / 2];
}
The Wikipedia article Smallest circle problem describes a linear average time algorithm for the case where the sizes of the initial circles are equal. It looks straightforward to generalize it to differently-sized initial circles, though I'm not sure what happens to the complexity analysis then.
You could find the max boundaries (xmin, xmax, ymin, ymax), then take max on both axis, then ask java to draw an ellipse in that square or take the center of it and the side as diameter.
No ?
Regards,
Stéphane
Oops, the following does not work, as noted in comments:
Start by solving the problem for 3 circles. In that case the circumscribed circle will touch each of the three inner circles, and you can find its center as the intersection of two hyperbolas. (The locus of points that have a given difference in distance to two fixed points is a hyperbola). After a bit of algebra, that boils down to a quadratic equation.
Now add more inner circles by induction. At the beginning of each step you know the smallest circle that encompasses all of the old circles; it will touch three particular old "corner" circles. If the new circle is inside that one, there's nothing to do. If not, combine the new circle with all three ways to chose two of the old corner circles and compute the circumscribed circle for each of those triples. One of them should include the fourth one, which is now not a corner circle anymore.
Proceed until you have added all circles.
This gives a linear-time algorithm with bounded rounding errors (because each circumscribed circle is computed afresh from pristine input coordinates).
My suggested algorithm is similar to that of Svante but with a few differences.
The idea is to first create a circle which trivially encompasses all subcircles and then shrink it like a bubble until it is pinned by 1,2, or 3 circles.
first approximation:
a circle with centre 0,0 and radius max(distance from 0,0 of subcircle + radius of subcircle)
if the subcircle which determines the radius of the circle encloses all other subcircles, then it is trivially the correct result, and can be returned
second approximation:
reduce the radius of the circle found in the first approximation while keeping it tangent to the subcircle which it is 'pinned' to, moving the centre towards the pinned subcircle, until it becomes tangent to another subcircle.
final result:
reduce the radius of the circle again, keeping it tangent to the two subcircles found above, until either another subcircle becomes tangent to the circle, or the centre of the circle lies on the line between the centres of the two subcircles it is pinned to. This should be the minimum because there is no way from here to reduce the radius of the circle without one of the subcircles 'breaking through'
The part of the algorithm I'm not sure about is the 'reduce the radius until another subcircle becomes tangent' part. Obviously a binary search can give a good enough approximation in a decent amount of time, but I suspect you can reduce it to an equation.
I think that this can be done in three steps:
First bounding circle c1:
The centre is determined by xc1 = (xmax + xmin) / 2
and yc1 = (ymax + ymin) / 2.
For each circle, calculate the distance of its centre to the centre of c1 plus its radius (I call this the over-distance).
The maximum of these values is the radius of c1. The corresponding circle is a.
Second bounding circle c2:
(In this step, you move the centre of c1 in direction of a as far as possible.)
For each circle except a, determine how much you have to move the centre of c1 in the direction of a so that the over-distance from there to this circle is the same as to a. The minimum of this determines the centre of c2. The corresponding circle is b. The over-distance to a and b (both are the same) is the radius of c2.
Third bounding circle c3:
(In this step, you move the centre of c2 in the direction between a and b as far as possible.)
Determine the direction v in which you can move c2 such that the over-distance to a and b stays the same.
For each circle except a and b, determine how much you have to move the centre of c2 in direction v so that the over-distance from there to this circle is the same as to a and b. The minimum of this determines the centre of c3. The radius is the over-distance to the three circles found.
I believe that c3 is the solution (edit) a good first approximation. You can get better solutions by iteratively dropping the first circle and repeating the third step. If you arrive at a set of three circles that you have already seen, this should might be the final solution.
I'd try to find the topmost western point, then the southern downmost point, then make a circle with those points as diameter.
In order to find those points, I'd cycle through the center of the circles and their radius.
So it ends up in:
initiate max object and min object to average center of circle and zero radius
For every circle object
calculate topmost western point of the circle
check if further away than current point
if further, calculate position of topmost western point required to pass over this new point and set as new min object
calculate down most eastern point of the circle
do the same as previous step, only for max object
make a circle with center equals to middle of min-max line and radius equals to half min-max line length
If you are the bookworm type, good university libraries stock this: E.Welzl, Smallest Enclosing Disks (Balls and Ellipsoids), in H. Maurer (Ed.), New Results and New Trends in Computer Science, Lecture Notes in Computer Science, Vol. 555, Springer-Verlag, 359–37 (1991)
And if you want to read C++ code and adapt it to Java, http://miniball.sourceforge.net/.
With circles, d=2, of course.
With two circles it is easy. A line through both centres will hit the perimeter where an enclosing circle would contact them.
With more circles you would need to apply FEM (finite element analysis- http://en.wikipedia.org/wiki/Finite_element_method) on each perimeter point with the potential to be a point of contact with the outside circle. This rules out those segments which are facing other circles, for example. The computation is still rather large as you proceed to apply different radius's to your points until you find the smallest ones that intersects all the others at a common point- the centre of your enclosing cirlce.
I don't think its a packing problem per se. It sounds more like convex-hull. I think the question is:
You are given a set of circles on the plane. Find the center point and radius of the smallest circle for which every boundary point of each circle lies within or on the boundary of the containing circle.
For that, you can just run recursively: find the smallest circle containing the first two circles (and that circle's center lies on the line connecting the two centers, and its radius should be simple to determine as well), replace the first two circles with the new circle, and repeat.
The correctness of this algorithm belongs in mathematics.
It is very difficult problem, I would just outline possible ways to it, you have to finish it yourself. I assume you want to find minimal bounding circle.
Formalizing your problem - having xi, yi, ri for i = 1..N, you are looking for point [x, y] such that:
max(distance([x, y], [xi, yi]) + ri)
is minimal. This is a non-trivial minimax problem. First look at the simpler version of this problem Smallest circle problem, which is just for points:
max(distance([x, y], [xi, yi]))
So first try to improve the algorithms proposed in the above link to solve the more complex case. If this way is impassable, you might probably need to go for quadratic programming. Good luck...
I'm trying to figure out an algorithm for finding a random point a set distance away from a base point. So for example:
This could just be basic maths and my brain not working yet (forgive me, haven't had my coffee yet :) ), but I've been trying to work this out on paper and I'm not getting anywhere.
coordinate of point on circle with radius R and center (xc, yc):
x = xc + R*cos(a);
y = yc + R*sin(a);
changing value of angle a from 0 to 2*PI you can find any point on circumference.
Use the angle from the verticle as your random input.
Pseudocode:
angle = rand(0,1)
x = cos(angle * 2 * pi) * Radius + x_centre
y = sin(angle * 2 * pi) * Radius + y_centre
Basic Pythagoras.
Pick random number between 0 and 50 and solve h^2 = a^2 + b^2
Add a few random descisions on direction.