What algorithm can I use to determine points within a semi-circle? - algorithm

I have a list of two-dimensional points and I want to obtain which of them fall within a semi-circle.
Originally, the target shape was a rectangle aligned with the x and y axis. So the current algorithm sorts the pairs by their X coord and binary searches to the first one that could fall within the rectangle. Then it iterates over each point sequentially. It stops when it hits one that is beyond both the X and Y upper-bound of the target rectangle.
This does not work for a semi-circle as you cannot determine an effective upper/lower x and y bounds for it. The semi-circle can have any orientation.
Worst case, I will find the least value of a dimension (say x) in the semi-circle, binary search to the first point which is beyond it and then sequentially test the points until I get beyond the upper bound of that dimension. Basically testing an entire band's worth of points on the grid. The problem being this will end up checking many points which are not within the bounds.

Checking whether a point is inside or outside a semi-circle (or a rectangle for that matter) is a constant-time operation.
Checking N points lie inside or outside a semi-circle or rectangle is O(N).
Sorting your N points is O(N*lg(N)).
It is asymptotically faster to test all points sequentially than it is to sort and then do a fast culling of the points based on a binary search.
This may be one of those times where what seems fast and what is fast are two different things.
EDIT
There's also a dead-simple way to test containment of a point in the semi-circle without mucking about with rotations, transformations, and the like.
Represent the semi-circle as two components:
a line segment from point a to b representing the diameter of the semi-circle
an orientation of either left-of or right-of indicating that the semi-circle is either to the left or right of line segment ab when traveling from a to b
You can exploit the right-hand rule to determine if the point is inside the semicircle.
Then some pseudo-code to test if point p is in the semi-circle like:
procedure bool is_inside:
radius = distance(a,b)/2
center_pt = (a+b)/2
vec1 = b - center_pt
vec2 = p - center_pt
prod = cross_product(vec1,vec2)
if orientation == 'left-of'
return prod.z >= 0 && distance(center_pt,p) <= radius
else
return prod.z <= 0 && distance(center_pt,p) <= radius
This method has the added benefit of not using any trig functions and you can eliminate all square-roots by comparing to the squared distance. You can also speed it up by caching the 'vec1' computation, the radius computation, center_pt computation, and reorder a couple of the operations to bail early. But I was trying to go for clarity.
The 'cross_product' returns an (x,y,z) value. It checks if the z-component is positive or negative. This can also be sped up by not using a true cross product and only calculating the z-component.

First, translate & rotate the semi-circle so that one end is on the negative X-axis, and the other end is on the positive X-axis, centered on the origin (of course, you won't actually translate & rotate it, you'll just get the appropriate numbers that would translate & rotate it, and use them in the next step).
Then, you can treat it like a circle, ignoring all negative y-values, and just test using the square root of the sum of the squares of X & Y, and see if it's less than or equal to the radius.

"Maybe they can brute force it since they have a full GPU dedicated to them."
If you have a GPU at your disposal, then there are more ways to do it. For example, using a stencil buffer:
clear the stencil buffer and set the stencil operation to increment
render your semicircle to the stencil buffer
render your points
read back the pixels and check the values at your points
the points that are inside the semicircle would have been incremented twice.
This article describes how stencil buffers can be used in OpenGL.

If there's a standard algorithm for doing this, I'm sure someone else will come up with it, but if not: you could try sorting the points by distance from the center of the circle and iterating over only those whose distance is less than the semicircle's radius. Or if computing distance is expensive, I'd just try finding the bounding box of the semicircle (or even the bounding square of the circle of which the semicircle is part) and iterating over the points in that range. To some extent it depends on the distribution of the points, i.e. do you expect most of them or only a small fraction of them to fall within the semicircle?

You can find points in a circle and points on one side of a given slope, right?
Just combine the two.

Here's part of a function I wrote do get a cone firing arc for a weapon in a tile based game.
float lineLength;
float lineAngle;
for(int i = centerX - maxRange; i < centerX + maxRange + 1; i++){
if(i < 0){
continue;
}
for(int j = centerY - maxRange; j < centerY + maxRange + 1; j++){
if(j < 0){
continue;
}
lineLength = sqrt( (float)((centerX - i)*(centerX - i)) + (float)((centerY - j)*(centerY - j)));
lineAngle = lineAngles(centerX, centerY, forwardX, forwardY, centerX, centerY, i, j);
if(lineLength < (float)maxRange){
if(lineAngle < arcAngle){
if( (float)minRange <= lineLength){
AddToHighlightedTiles(i,j);
}
}
}
}
}
The variables should be self explanatory and the line angles function takes 2 lines and finds the angle between them. The forwardX and forwardY is just one tile in the correct direction from the center X and Y based on what angle you're pointing in. Those can be gotten easily with a switch statement.
float lineAngles(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4){
int a = x2 - x1;
int b = y2 - y1;
int c = x4 - x3;
int d = y4 - y3;
float ohSnap = ( (a * c) + (b * d) )/(sqrt((float)a*a + b*b) * sqrt((float)c*c + d*d) );
return acos(ohSnap) * 180 / 3.1415926545f;
}

It would appear that a simple scheme will work here.
Reduce the number of points in the set, by first computing the convex hull. Only the points on the convex hull will contribute to any interaction with any convex bounding shape. So retain only the subset of points on the perimeter of the hull.
It can easily be argued that the minimal radius bounding semi-circle must have one edge (two points) of the convex hull coincident along the diameter of the semi-circle. I.e., if some edge of the hull does not lie in the diameter, then there exists a different semi-circle with smaller diameter that contains the same set of points.
Test each edge in sequence. (A convex hull often has relatively few edges, so this will go quickly.) Now it becomes a simple 1-d minimization problem. If we choose to assume the edge in question lies on the diameter, then we merely need to find the center of the sphere. It must lie along the current line which we are considering to be the diameter. So as a function of the position of the point along the current diameter, just find the point which lies farthest away from the nominal center. By minimizing that distance, we find the radius of the minimal semi-circle along that line as a diameter.
Now, just choose the best of the possible semi-circles found over all edges of the convex hull.

If your points have integer co-ordinates, the fastest solution may be a lookup table. Since a semicircle is convex, for each y co-ordinate, you get a fixed range of x, so each entry in your lookup table gives maximum and minimum X co-ordinates.
Of course you still need to precalculate the table, and if your semicircle isn't fixed, you may be doing that a lot. That said, this is basically one part of what would once have been done to render a semicircle - the full shape would be rendered as a series of horizontal spans by repeatedly calling a horizontal line drawing function.
To calculate the spans in the first place (if you need to do it repeatedly), you'd probably want to look for an old copy of Michael Abrash's Zen of Graphics Programming. That described Bresenhams well-known line algorithm, and the not-so-well-known Hardenburghs circle algorithm. It shouldn't be too hard to combine the span-oriented versions of the two to quickly calculate the spans for a semi-circle.
IIRC, Hardenburgh uses the x^2 + y^2 = radius^2, but exploits the fact that you're stepping through spans to avoid calculating square roots - I think it uses the fact that (x+1)^2 = x^2 + 2x + 1 and (y-1)^2 = y^2 - 2y + 1, maintaining running values for x, y, x^2 and (radius^2 - y^2), so each step only requires a comparison (is the current x^2 + y^2 too big) and a few additions. It's done for one octant only (the only way to ensure single-pixel steps), and extended to the full circle through symmetry.
Once you have the spans for the full circle, it should be easy to use Bresenhams to cut off the half you don't want.
Of course you'd only do all this if you're absolutely certain that you need to (and that you can work with integers). Otherwise stick with stbuton.

translate the center of the arc to the origin
compute angle between ordinate axis and end points of radii of semi-cirlce
translate the point in question by same dx,dy
compute distance from origin to translated x,y of point, if d > radius of circle/arc eliminate
compute angle between ordinate axis and end point
if angle is not between starting and ending arc of semi-cirlce, eliminate
points remaning should be inside semi-circle

I guess someone found the same solution as me here but I have no code to show as its pretty far in my memory...
I'd do it by steps...
1. I'd look if i'm within a circle... if yes look on which side of the circle.
2. By drawing a normal vector that come from the vector made by the semi-sphere. I could know if I'm behind or in front of the vector...and if you know which side is the semi sphere and which side is the void...It will be pretty damn easy to find if you're within the semi sphere. You have to do the dot product.
I'm not sure if it's clear enough but the test shouldn't be that hard to do...In the end you have to look for a negative or positive value...if it's 0 you're on the vector of the semisphere so it's up to you to say if it's outside or inside the semi-sphere.

The fastest way to do this will depend on your typical data. If you have real-world data to look at, do that first. When points are outside the semi-circle, is it usually because they are outside the circle? Are your semi-circles typically thin pie slices?
There are several ways to do this with vectors. You can scale the circle to a unit circle and use cross-products and look at the resultant vectors. You can use dot-products and see how the prospective point lands on the other vectors.
If you want something really easy to understand, first check to make sure it's inside the circle, then get the angle and make sure it's between the angle of the two vectors that dictate the semi-circle.
Edit: I had forgotten that a semicircle is always half a circle. I was thinking of any arbitrary section of a circle.
Now that I have remembered what a semicircle is, here's how I would do that. It's similar to stbuton's solution, but it represents the semicircle differently.
I'd represent the semicircle as the unit vector that bisects the semicircle. You can easily get that from either one of the vectors that indicate the boundary of the semicircle (because they are 90 degrees away from the representation) by swapping x and y and negating one of them.
Now you just cross the vector created by subtracting the point to be tested from the circle's center. The sign of z tells you whether the point is in the semicircle, and the length of z can be compared against the radius.
I did all the physics for Cool Pool (from Sierra Online). It's all done in vectors and it's filled with dots and crosses. Vectors solutions are fast. Cool Pool was able to run on a P60, and did reasonable breaks and even spin.
Note: For solutions where you're checking sqrt(xx+yy), don't even do the sqrt. Instead, keep the square of the radius around and compare against that.

Related

Point in circle segment

I have a circle I want to divide up in to a number of segments all defined by X and Y coordinates. How to I test to see if a point (X, Y) is in a particular segment?
A code example would be preferable.
You don't need to use trigonometry for this (and in general, trigonometry should be avoided whenever possible... it leads to too many precision, domain, and around-the-corner problems).
To determine whether a point P is counter-clockwise of another point A (in the sense of being in the half-plane defined by the left side of a directed line going through the origin and then through A), you can examine the sign of the result of Ax*Py - Ay*Px. This is generally known as the "perpendicular dot product", and is the same as the Z coordinate of the 3D cross product.
If there are two points A and B (with B defining the CCW-most extent) defining a sector, and the sector is less than half the circle, any point which is CCW of A and CW of B can be classified as in that sector.
That leaves only a sector which is more than half of the circle. Obviously, a given set of points can only define at most one such sector. There's clever things you can do with angle bisection, but the easiest approach is probably just to classify points as in that sector if you can't classify them as being in any other sector.
Oh, forgot to mention -- determining the order of the points for the purposes of pairing them up for sectors. Not to go against my previous advice, but the most straightforward thing here is just to sort them by their atan2 (not atan... never ever use atan).
Use the polar coordinate system centred at the centre of the circle, and examine the angular coordinate (φ in the Wikipedia article).
What exactly you do with φ depends on how your segments are defined. For example, if you have n equal segments that start at 0 radians, floor(φ * n / (2 * π)) will give you the segment number.
Your segment is defined by two intersections between the circle and a line. You just have to know if:
The angle between the center of your circle and your point is between
the angles formed by the two previous points and the center.
the point is in the circle (the length from this point to the center is smaller than the radius)
from what side is the point compared to the line (it must be beyond the line).
Remark
In geometry, a circular segment (symbol: ⌓) is a region of a circle
which is "cut off" from the rest of the circle by a secant or a chord.
Here is a segment:
If x & y are not already relative to the center of the circle, subtract the coordinates of the center of the circle:
x -= circle.x
y -= circle.y
Use atan2 to get the angle of the point about the origin of the circle:
angle = atan2(y, x)
This angle is negative for points below the x-axis, so adjust to always be positive:
if (angle < 0) angle += 2 * pi
Assuming your segments are equally spaced, use this formula to get the index of the segment:
segment = floor((angle * numSegments) / (2 * pi))
If you find the result is referring to a segment on the opposite side of the circle to what you want, you might have to do y = -y in the beginning or a segment = (numSegments - 1) - segment at the end to flip it round the right way, but it should basically work.

Breakpoint Convergence in Fortune's Algorithm

I am implementing Fortune's sweepline algorithm for computing Voronoi diagrams. My primary reference is "Computational Geometry: Algorithms and Applications" by de Berg et al., and while their coverage of the topic is very clear, they pass over several small but important details that I have been having trouble working out myself. I've searched the web for help, but other websites either give an even higher overview than the textbook, or give the exact same pseudocode provided by the book.
I need a way to determine whether a pair of breakpoints determined by a triple of arcs on the beach line converges or diverges, in order to detect upcoming circle events. It seems that to make a decision I would need knowledge about the shape of the Voronoi cell edges that the breakpoints trace out as Fortune's algorithm progresses. For example, if I could find the slope of the edge traced by a breakpoint I could calculate where the two lines formed by the breakpoints and their respective slopes intersect, and decide whether they converge based on that result. However, I have no idea how to get information on the slopes, only the current position of the breakpoints.
The only information I have to work with is the x,y location of the three sites and the current y-coordinate of the sweepline (I'm using a horizontal sweepline).
Actually, I do have one idea for determining convergence. Given two sites, the breakpoint between the two sections of the beachline they define is governed only by the current position of the sweep line. I thought about recording the position of the two breakpoints, temporarily advancing the sweep line a small amount, and recording their new positions. Because edges in a normal Voronoi diagram do not curve, if the distance between the new pair of breakpoints is less than the distance between the old pair, then the breakpoints converge; otherwise, they diverge. But this seems both dangerous (I have no idea if it always works) and ugly. Surely there must be a better way.
Any ideas would be appreciated, and pseudocode (in a C#-like syntax if possible) especially so. Also I am aware that there are computational geometry libraries that I could use to get Voronoi diagrams, but this is a personal learning exercise, so I want to implement all parts of the algorithm myself.
So this is rather embarassing, but after sleeping on the problem the answer seems obvious. I'm writing this to hopefully help students in the future with the same question as me.
The Voronoi edge between two sites perpendicularly bisects the (imaginary) line segment connecting the sites. You could derive the slope of the edge by taking the perpendicular of the slope of the connecting line segment, and then performing a line intersection test on the two edges, but there is an even easier way.
As long as three sites are not collinear, then the edges that perpendicularly bisect the segments between the sites are also tangent to the circle whose edge contains all three sites. Therefore the breakpoints defined by a triple of Voronoi sites converge if the center of the circle defined by the three sites is in front of the middle site, where "in front" and "behind" depend on the coordinate system and sweepline alignment you have chosen.
In my case, I have a horizontal sweepline that I am moving from minimum y to maximum y, so the breakpoints converge if the y-coordinate of the center of the circle is greater than the y-coordinate of the middle site, and diverge otherwise.
Edit: Kristian D'Amato rightfully points out that the algorithm above misses some convergence cases. The final algorithm I ended up using is below. Of course, I'm not confident that its 100% correct, but it seems to work for all the cases I tried it out on.
Given left, middle, right sites
if they are collinear, return false
center = ComputeCircleCenterDefinedBy3Points(left, middle, right)
return IsRightOfLine(left, middle, center) && IsRightOfLine(middle, right, center)
IsRightOfLine(start, end, point)
((end.X - start.X) * (point.Y - start.Y) - (end.Y - start.Y) * (point.X - start.X)) <= 0
Welcome Drake. I implemented it by checking whether the breakpoints physically converge on the circle center in a 'fictitious' increment of the sweepline position. This actually complicates itself a bit because in certain cases the circle center can be almost or precisely at the sweepline position, so the sweepline increment needs to be proportional to the difference between the current sweepline position and the circle center generated as you recommend.
Say:
1. currentSweeplineY = 1.0f; circleCenterY = 0.5f (and we are moving downwards, i.e. in the decreasing y direction).
2. Set sweepYIncrement = (circleCenterY - currentSweepLineY) / 10.0f (the 10.0f divisor is arbitrarily chosen).
3. Check new breakpoint positions at new sweepline position.
4. Check distance to circle center.
5. If both distances are less than current distances, the breakpoints converge.
I know this is probably very expensive, since you have to calculate the breakpoint positions multiple times, but I'm confident it takes care of all possible cases.
Anyway, I'm finding serious issues with floating point precision error elsewhere in the algorithm. Definitely not as straightforward as I thought initially.
If the sites are ordered clockwise around the center of the circle, the arc is converging. If they are ordered counterclockwise around the center of the circle, the arc is diverging. (or vice versa, depending on your implementation). Testing for cw or ccw falls out of the code you use to find the center of the circle.
Here's a snippet of C# code for computing the circumcenter d of points a,b,c:
Vector2 ba = b - a;
Vector2 ca = c - a;
float baLength = (ba.x * ba.x) + (ba.y * ba.y);
float caLength = (ca.x * ca.x) + (ca.y * ca.y);
float denominator = 2f * (ba.x * ca.y - ba.y * ca.x);
if (denominator <= 0f ) { // Equals 0 for colinear points. Less than zero if points are ccw and arc is diverging.
return false; // Don't use this circle event!
};
d.x = a.x + (ca.y * baLength - ba.y * caLength) / denominator ;
d.y = a.y + (ba.x * caLength - ca.x * baLength) / denominator ;

Drawing a circle on an array for CCD integration purposes

I am writing a function to draw an approximate circle on a square array (in Matlab, but the problem is mainly algorithmic).
The goal is to produce a mask for integrating light that falls on a portion of a CCD sensor from a diffraction-limited point source (whose diameter corresponds to a few pixels on the CCD array). In summary, the CCD sensor sees a pattern with revolution-symmetry, that has of course no obligation to be centered on one particular pixel of the CCD (see example image below).
Here is the algorithm that I currently use to produce my discretized circular mask, and which works partially (Matlab/Octave code):
xt = linspace(-xmax, xmax, npixels_cam); % in physical coordinates (meters)
[X Y] = meshgrid(xt-center(1), xt-center(2)); % shifted coordinate matrices
[Theta R] = cart2pol(X,Y);
R = R'; % cart2pol uses a different convention for lines/columns
mask = (R<=radius);
As you can see, my algorithm selects (sets to 1) all the pixels whose physical distance (in meters) is smaller or equal to a radius, which doesn't need to be an integer.
I feel like my algorithm may not be the best solution to this problem. In particular, I would like it to include the pixel in which the center is present, even when the radius is very small.
Any ideas ?
(See http://i.stack.imgur.com/3mZ5X.png for an example image of a diffraction-limited spot on a CCD camera).
if you like to select pixels if and only if they contain any part of the circle C:
in each pixel place a small circle A with the radius = halv size of the pixel, and another one around it with R=sqrt(2)*half size of the circle (a circumscribed circle)
To test if two circles touch each other you just calculate the center to center distances and subtract the sum of the two radii.
If the test circle C is within A then you select the pixel. If it's within B but not C you need to test all four pixel sides for overlap like this Circle line-segment collision detection algorithm?
A brute force approximate method is to make a much finer grid within each pixel and test each center point in that grid.
This is a well-studied problem. Several levels of optimization are possible:
You can brute-force check if every pixel is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2)
You can brute-force check if every pixel in a square bounding the circle is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2 where |x-x0| < r and |y-y0| < r)
You can go line-by-line (where |y-y0| < r) and calculate the starting x ending x and fill all the lines in between. (Although square roots aren't cheap.)
There's an infinite possibility of more sophisticated algorithms. Here's a common one: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm (filling in the circle is left as an exercise)
It really depends on how sophisticated you want to be based on how imperative good performance is.

Arduino convex hull algorithm

I am working on a project using an Arduino that needs to calculate the area of a polygon made up of many points. I use surveyor's theorem,
But the points are in random order, not (counter)clockwise. Some make lines that cross, and they make polygons like a bow-tie or hourglass, which don't work for the surveyor's theorem, so I need to sort them in (counter)clockwise order. what is the easiest way to do this?
You don't need to find the convex hull. Just use the area formula from a bunch of points ordered counterclockwise:
http://en.wikipedia.org/wiki/Polygon#Area_and_centroid
float totalArea = 0.0;
for(i=0; i<N; i++) {
float parallelogramArea = (point[i].x*point[i+1].y - point[i+1].x*point[i].y)
float triangleArea = parallelogramArea / 2.0;
totalArea += triangleArea;
}
// or divide by 2 out here for efficiency
The area formula comes from taking each edge AB, and calculating the (signed) area between the edge and the origin (triangle ABO) by taking the cross-product (which gives you the area of a parallelogram) and cutting it in half (factor of 1/2). As one wraps around the polygon, these positive and negative triangles will overlap, and the area between the origin and the polygon will be cancelled out and sum to 0, while only the area inside remains. This is why the formula is called the Surveyor's Formula, since the "surveyor" is at the origin; if going counterclockwise, positive area is added when going left->right and negative area is added when going right->left, from the perspective of the origin.
The mathematical formula is given below, but does not provide the intuition behind it (as given above):
edit (after question has been changed)
There is absolutely no way to "get their order" without additional assumptions, e.g. "the polygon is convex".
If the polygon is concave, it becomes nearly impossible in the general case without lots of extra assumptions (proof: consider a point which lies within the convex hull, but whose neighbors do not; there are many possible valid polygons you can construct using that point, its neighbors, and their neighbors).
If the polygon is convex, all you need to do is sort by the angle from some arbitrary point inside the polygon (e.g. centroid of three arbitrary points).
You could find the center of gravity (cx,cy) of the points and then calculate the angles of the points relative to (cx,cy).
angle[i] = atan2(y[i]-cy, x[i]-cx) ;
Then sort the points by angle.
Just beware that a random set of points does not describe a single unique polygon. So this method will just give you one of the possible polygons, and not necessarily the polygon you would have obtained if you had manually connected the dots.

calculate the area of a polygon in ruby

I have an array of latitude/longitude coordinate pairs that represent a polygon. I'm trying to determine the total area within that polygon. How would I go about doing that in Ruby?
Here's an example array of the polygon:
[[37.7663613767094, -122.452969210084], [37.7674219449606, -122.444718340349], [37.7701838510542, -122.445330289514], [37.7709974013834, -122.439159589248], [37.7700761930893, -122.438861402472], [37.7703501163684, -122.436868738421], [37.7712650571321, -122.437078116573], [37.7736056746515, -122.437533130227], [37.7714671036087, -122.453964210266], [37.7663613767094, -122.452969210084]]
It probably doesn't matter that much on the language. You can make use of the formula mentioned in here for calculating the area of a polygon:
http://mathworld.wolfram.com/PolygonArea.html
Assuming your points are (x1, y1) (x2, y2) .. (xn, yn) and they enclose a small area:
Area = 0.5 * (x1 * y2 - x2 * y1 + x2 * y3 - x3 * y2 ..... + xn * y1 - x1 * yn)
Note: This won't work for larger areas, for which you need to use more complex method to calculate the area, which involves angular co-ordinates. But, this does the job for small areas, which can be assumed to be planar.
Edit:
To get area in sq miles, you can do the following, from there, convert to whatever units you want.
areaInSqMiles = Area * (60 * 60 * 1.15 * 1.15)
language independent solution:
GIVEN: a polygon can ALWAYS be composed by n-2 triangles that do not overlap (n = number of points OR sides). 1 triangle = 3 sided polygon = 1 triangle; 1 square = 4 sided polygon = 2 triangles; etc ad nauseam QED
therefore, a polygon can be reduced by "chopping off" triangles and the total area will be the sum of the areas of these triangles. try it with a piece of paper and scissors, it is best if you can visualize the process before following.
if you take any 3 consecutive points in a polygons path and create a triangle with these points, you will have one and only one of three possible scenarios:
resulting triangle is completely inside original polygon
resulting triangle is totally outside original polygon
resulting triangle is partially contained in original polygon
we are interested only in cases that fall in the first option (totally contained).
every time we find one of these, we chop it off, calculate its area (easy peasy, wont explain formula here) and make a new polygon with one less side (equivalent to polygon with this triangle chopped off). until we have only one triangle left.
how to implement this programatically:
create an array of points. run the array making triangles from points x, x+1 and x+2. transform each triangle from a shape to an area and intersect it with area created from polygon. IF the resulting intersection is identical to the original triangle, then said triangle is totally contained in polygon and can be chopped off. remove x+1 from the array and start again from x=0. otherwise, move to next point x+1 in array.
additionally if you are looking to integrate with mappping and are starting from geopoints, you must convert from geopoints to screenpoints. this requires deciding a modelling and formula for earths shape (though we tend to think of the earth as a sphere, it is actually an irregular ovoid (eggshape), with dents. there are many models out there, for further info wiki.
You can use this library which wraps GEOS (a C geospatial library itself a port of the JTS).
https://github.com/dark-panda/ffi-geos
This library can handle the calculations in coordinate space and takes care of the approximations.
Depending on how much accuracy you need I would project the data first to an appropriate projection (not Mercator). Then calculate your area
There is an awesome example on how to multiply verticies. Essentially exactly what you would like to do!!
http://www.wikihow.com/Calculate-the-Area-of-a-Polygon
Some techniques for this include integration (divide the polygon into latitudinal strips and integrate. You can also project onto a flat surface and calculate that area.

Resources