I have two hexagons which I am trying to make snap together when the edges hit a certain tolerance.
How can I find which edges are the closest?
Here is the code returning the two closest Hexagons:
Canvas.getClosestPiece = function(){
var current = {};
current.x = selection.MidPoint.X;
current.y = selection.MidPoint.Y;
smallestDistance = null;
closestHex = null;
hexagons.forEach(function(hexagon){
if(hexagon !== selection){
testPiece = {};
testPiece.x = hexagon.MidPoint.X;
testPiece.y = hexagon.MidPoint.Y;
if((lineDistance(current, testPiece) < smallestDistance) || smallestDistance === null){
smallestDistance = lineDistance(current, testPiece)
closestHex = hexagon
hexagons.forEach(function(hexagon){
hexagon.lineColor = 'grey'
})
hexagon.lineColor = 'red';
}
}
})
// console.log(smallestDistance)
return [selection, closestHex]
}
Distance between two hexagon midpoints:
function lineDistance( point1, point2 ){
var xs = 0;
var ys = 0;
xs = point2.x - point1.x;
xs = xs * xs;
ys = point2.y - point1.y;
ys = ys * ys;
return Math.sqrt( xs + ys );
}
And here is a standard point array for one of the hexagons that getClosestPiece returns:
Point {X: 658, Y: 284}
Point {X: 704, Y: 304}
Point {X: 704, Y: 354}
Point {X: 658, Y: 375}
Point {X: 613, Y: 354}
Point {X: 613, Y: 304}
If your have 2 points with their coordinate like p1(x1, y1) and p2(x2, y2). You can do this:
var disptance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
For calculating if to snap, see the other answers.
As to where to snap (which edges), which I think is your real question: calculate the relative angle using
atan2(midy1-midy2, midx1-midx2).
You get a value in radians, which describes the angle of the connection line between the hexes. 0 = horizontal line.
Calculate Math.floor(value*6/(2*pi)) --> you get a number between 0..5 denoting the edge pairing.
If your hexes are rotatable, you need to add/substract the rotatins (in rad) to/from value. (The signs are best figured out on a piece of paper).
edit: regarding your distance calculation, it is advisable to work with the square of the distance as long as possible (e.g. compare x^2+y^2 against threshold^2), to avoid the expensive Math.sqrt operation. Especially when testing distance against a multitude of other objects.
Use Euclian Distance formula
dist=sqrt((x2-xq)^2 + (y2-y1)^2)
to find which edges are the closest you hav to say us that how do you have information of the edge lines of each hexagon. here, i assume they are accessible through an array as a property of each hexagon. so we have 6 edges (edges[0] to edges[5]) for each hexagon. we can find closest edges by looping through them and measuring the distance between center of each two edges. a sample code will look like this:
var dMin=-1, iMin=-1, jMin=-1; //info about the min distance
for(var i=0; i<5; i++) //loop through hexagon1.edges
{
var p1 = midPointOfLine( hexagon1.edges[i] ); //center of this edge line
for(var j=0; j<5; j++) //loop through hexagon2.edges
{
var p2 = midPointOfLine( hexagon2.edges[j] ); //center of this edge line
var d = getDistance(p1, p2); //get distance of two points
if (d<dMin || dMin==-1) {dMin=d; iMin=i; jMin=j;} //store the info about the min distance
}
}
function midPointOfLine(edge) // return new point( X=(X1+X2)/2 , Y=(Y1+Y2)/2 )
{
var mp; //define a new point
mp.X = (edge.startPoint.X + edge.endPoint.X) / 2;
mp.Y = (edge.startPoint.Y + edge.endPoint.Y) / 2;
return mp;
}
function getDistance(p1, p2) //return sqrt( (X2-X1)^2 + (Y2-Y1)^2 )
{
return Math.sqrt( Math.pow(p2.X - p1.X, 2) + Math.pow(p2.Y - p1.Y, 2) );
}
In Summary:
Check distance between center of each edge of hexagon1 and center of
each edge of hexagon2.
The center of each edge is mid point of its
start and end points: ( (x1+x2)/2, (y1+y2)/2 ).
The distance of two points can be calculated from sqrt(dx*dx + dy*dy) formula.
Related
const coords = [
{
name: "Rijnstraat vervolg",
points: [
[695, 500],
[680, 480],
[580, 475],
[520, 460],
],
width: 10,
types: [types.car, types.truck, types.pedestrian, types.bike],
oneway: true,
},
...
]
I have an array that looks like the above and I want to make a function that generates a path (along the other paths, which are the black lines in the image) from a black or gray circle to another black or gray circle. So I want the function to take in a start and end point (black or gray circle) and return an array of points that follow the already existings paths. (Which are sort of like roads)
And the function can be described as someone who is trying to get to somewhere.
I already tried a recursive function that looks like this:
function calculatePathToShop(startPoint, shopPoint) {
const targetShopPoint = findClosestPointOnPath(shopPoint);
const targetPathIndex = findPathByPoint(targetShopPoint);
const connectedPaths = calculateConnectedPaths(targetPathIndex);
let startPathIndex = -1;
connectedPaths.forEach(path => {
const pathPoints = coords[path].points;
pathPoints.forEach(pathPoint => {
if (comparePoints(startPoint.point, pathPoint)) startPathIndex = path;
});
});
if (startPathIndex == -1) return false;
let startPathPoints = coords[startPathIndex].points;
let targetPathPoints = coords[targetPathIndex].points;
if (!comparePoints(startPoint.point, startPathPoints[0])) startPathPoints.reverse();
ctx.strokeStyle = "rgba(255, 0, 0, .05)";
}
This one generated a path (along the existing ones) to a shop point, which is almost the same as a gray point. But this worked for some starting points, but the rest would just straight up fail
So does anyone know an algorithm, or has a function/solution that I can use to generate the path that someone can walk along the road (the black lines in the image)
Full coords array, and part of my already existing code is found here: https://raw.githubusercontent.com/CodeFoxDev/people-simulation/main/func/paths.js
(The rest of the code is in the github repo itself)
Fixed step interpolation
To interpolate a line segment you divide the vector from the start pointing to the end by the number of steps.
EG
steps = 100;
start = {x: 50, y: 100}
end = {x: 150, y: 300}
step = {x: (end.x - start.x) / steps, y: (end.y - start.y) / steps};
Then loop that number of steps adding the vector to a position initialized to the start point.
points = []; // array of interpolated points
point = {...start} // set start position.
while (steps--) {
points.push({...point});
point.x += vec.x;
point.y += vec.y;
}
points.push({...end}); // last point at end
This will create different spacing for different line lengths.
Fixed distance interpolation
To get a constant spacing between points you will need to use the lines' length to get the number of steps.
pixelsPerStep = 2; // distance between points.
start = {x: 50, y: 100}
end = {x: 150, y: 300}
step = {x: end.x - start.x, y: end.y - start.y};
lineSteps = Math.hypot(step.x, step.y) / pixelsPerStep;
points = []; // array of interpolated points
for (i = 0; i < lineSteps ; i += 1) {
u = i / lineSteps;
points.push({x: start.x + step.x * u, y: start.y + step.y * u});
}
// check to add end point
Note that the last point may or may not be at the correct distance. Due to rounding errors in floating point numbers you will need to check if the last point is close to the correct spacing and whether or not to include it.
eg from code above
// add last point if within (0.01 * pixelsPerStep) pixels of correct spacing
if (Math.abs(lineSteps - i) < 0.01) {
points.push({...end});
}
Note Use the overflow lineSteps - i when interpolating many line segments, to carry the correct start offset to each subsequent line segment.
Example
The code below is an example of a constant spaced set of points interpolated from another set of points.
The example draws the new points in black dots. The original points are rendered in red.
Note that the distance between new points is constant and thus may not fall on the original (red) points.
Note that there is a check at the end to test if a last point should be added.
const ctx = canvas.getContext("2d");
const P2 = (x, y) => ({x, y});
const points = [
P2(100,90),
P2(300,210),
P2(350,110),
P2(50,10),
P2(6,219),
];
const interpolatedPoints = interpolatePath(points, 35);
drawPoints(interpolatedPoints, 2);
ctx.fillStyle = "RED";
drawPoints(points);
function drawPoints(points, size = 1) {
ctx.beginPath();
for (const p of points) {
ctx.rect(p.x - size, p.y - size, size * 2 + 1, size * 2 + 1);
}
ctx.fill();
}
function interpolatePath(path, pixelStep) {
const res = [];
var p2, i = 1, overflow = 0;
while (i < path.length) {
const p1 = path[i - 1];
p2 = path[i];
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const len = Math.hypot(dx, dy) / pixelStep;
let j = overflow;
while (j < len) {
const u = j / len;
res.push(P2(p1.x + dx * u, p1.y + dy * u));
j++;
}
overflow = j - len;
i++;
}
// add last point if close to correct distance
if (Math.abs(overflow) < 0.01) {
res.push(P2(p2.x, p2.y));
}
return res;
}
<canvas id="canvas" width="400" height="400"></canvas>
I would like to rotate a polygon
I have array of polygon like this
[ [-17.999999999999986, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ]
Fist step: I calculate the Centroid
function getCentroid(coord) {
var center = coord.reduce(function (x,y) {
return [x[0] + y[0]/coord.length, x[1] + y[1]/coord.length]
}, [0,0])
return center;
}
Seconde Step: Rotation:
function rotate(CX, CY, X, Y, angle) {
var rad = angle * (Math.PI / 180.0);
var nx = Math.cos(rad) * (X-CX) - Math.sin(rad) * (Y-CY) + CX;
var ny = Math.sin(rad) * (X-CX) + Math.cos(rad) * (Y-CY) + CY;
return [nx,ny];
}
the problem is every time I rotate the polygon it become biger.
Maybe I have a problem in the formula but this one is used by alot of programmers.
Thank you for your answers.
You tagged svg.js so I assume that you are using it.
So here is how I would do it.
// assuming that you have a div with the id "canvas" here
var canvas = SVG('canvas')
var angle = 20
// draw polygon
var polygon = canvas.polygon([ [-18, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ])
.fill('none')
.stroke('black')
// we clone it so we have something to compare
var clone = polygon.clone()
// get center of polygon
var box = polygon.bbox()
var {cx, cy} = box
// get the values of the points
var rotatedPoints = polygon.array().valueOf().map((p) => {
// transform every point
var {x, y} = new SVG.Point(p)
.transform(new SVG.Matrix().rotate(angle, cx, cy))
return [x, y]
})
// update polygon with points
polygon.plot(rotatedPoints)
Fiddle: https://jsfiddle.net/Fuzzy/3qzubk5y/1/
Ofc you dont need to make a polygon first to rotate the points. You can go straight withy our array and call the same map function on it. But in this case you need to figure out the cx and cy yourself:
function getCentroid(coord) {
var center = coord.reduce(function (x,y) {
return [x[0] + y[0]/coord.length, x[1] + y[1]/coord.length]
}, [0,0])
return center;
}
var canvas = SVG("canvas")
var points = [ [-18, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ]
var center = getCentroid(points)
var angle = 20
// polygon before rotation
canvas.polygon(points).fill('none').stroke('black')
// get the values of the points
var rotatedPoints = points.map((p) => {
// transform every point
var {x, y} = new SVG.Point(p)
.transform(new SVG.Matrix().rotate(angle, center[0], center[1]))
return [x, y]
})
// polygon after rotation
canvas.polygon(rotatedPoints).fill('none').stroke('black')
Fiddle: https://jsfiddle.net/Fuzzy/g90w10gg/
So since your centroid function seems to work, your mistake has to be somewhere in your rotate function. However, I prefer to use the capcabilities of the libraries when I have them there. No need to reinvent the weel :)
// EDIT:
I pimped your centroid function a bit so the variable naming is a bit more clear:
function getCentroid(coord) {
var length = coord.length
var center = coord.reduce(function (last, current) {
last.x += current[0] / length
last.y += current[1] / length
return last
}, {x: 0, y: 0})
return center;
}
I'm receiving all distances between a random number of points in a 2 dimensional coordinate system.
How can I visualize this as coordinates on a map in my browser?
In case there are many solutions I just want to see the first possible one that my algorithm can come up with.
So here's an extremely easy example:
PointCount = 3
Distances:
0-1 = 2
0-2 = 4
1-2 = 2
Does anyone know an easy way (existing solution/framework maybe) to do it using whatever is out there to make it easier to implement?
I was thinking maybe using the html canvas element for drawing, but I don't know how to create an algorithm that could come up with possible coordinates for those points.
The above example is simplified -
Real distance values could look like this:
(0) (1) (2) (3)
(0) 0 2344 3333 10000
(1) 0 3566 10333
(2) 0 12520
I'm not sure this is relevant for SO, but anyway...
The way to do this is quite simply to place the points one by one using the data:
Pick a random location for the first point (let's say it's 0,0).
The second point is on a circle with radius d(0,1) with the first point as its center, so you can pick any point on the circle. Let's pick (d(0,1),0).
The third point is at the intersection of a circle with radius d(0,2) and center point 1, and a circle with radius d(1,2) and center point 2. You will get either 0, 1, 2 or an infinity of solutions. If the data comes from real points, 0 shouldn't happen. 1 and infinity are edge cases, but you should still handle them. Pick any of the solutions.
The fourth point is at the intersection of 3 circles. Unless you're very unlucky (but you should account for it), there should be only one solution.
Continue like this until all points have been placed.
Note that this doesn't mean you'll get the exact locations of the original points: you can have any combination of a translation (the choice of your first point), rotation (the choice of your second point) and symmetry (the choice of your third point) making the difference.
A quick and dirty implementation (not handling quite a few cases, and tested very little):
function distance(p1, p2) {
return Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
}
// adapted from https://stackoverflow.com/a/12221389/3527940
function intersection(x0, y0, r0, x1, y1, r1) {
var a, dx, dy, d, h, rx, ry;
var x2, y2;
/* dx and dy are the vertical and horizontal distances between
* the circle centers.
*/
dx = x1 - x0;
dy = y1 - y0;
/* Determine the straight-line distance between the centers. */
d = Math.sqrt((dy * dy) + (dx * dx));
/* Check for solvability. */
if (d > (r0 + r1)) {
/* no solution. circles do not intersect. */
return false;
}
if (d < Math.abs(r0 - r1)) {
/* no solution. one circle is contained in the other */
return false;
}
/* 'point 2' is the point where the line through the circle
* intersection points crosses the line between the circle
* centers.
*/
/* Determine the distance from point 0 to point 2. */
a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d);
/* Determine the coordinates of point 2. */
x2 = x0 + (dx * a / d);
y2 = y0 + (dy * a / d);
/* Determine the distance from point 2 to either of the
* intersection points.
*/
h = Math.sqrt((r0 * r0) - (a * a));
/* Now determine the offsets of the intersection points from
* point 2.
*/
rx = -dy * (h / d);
ry = dx * (h / d);
/* Determine the absolute intersection points. */
var xi = x2 + rx;
var xi_prime = x2 - rx;
var yi = y2 + ry;
var yi_prime = y2 - ry;
return [
[xi, yi],
[xi_prime, yi_prime]
];
}
function generateData(nbPoints) {
var i, j, k;
var originalPoints = [];
for (i = 0; i < nbPoints; i++) {
originalPoints.push([Math.random() * 20000 - 10000, Math.random() * 20000 - 10000]);
}
var data = [];
var distances;
for (i = 0; i < nbPoints; i++) {
distances = [];
for (j = 0; j < i; j++) {
distances.push(distance(originalPoints[i], originalPoints[j]));
}
data.push(distances);
}
//console.log("original points", originalPoints);
//console.log("distance data", data);
return data;
}
function findPointsForDistances(data, threshold) {
var points = [];
var solutions;
var solutions1, solutions2;
var point;
var i, j, k;
if (!threshold)
threshold = 0.01;
// First point, arbitrarily set at 0,0
points.push([0, 0]);
// Second point, arbitrarily set at d(0,1),0
points.push([data[1][0], 0]);
// Third point, intersection of two circles, pick any solution
solutions = intersection(
points[0][0], points[0][1], data[2][0],
points[1][0], points[1][1], data[2][1]);
//console.log("possible solutions for point 3", solutions);
points.push(solutions[0]);
//console.log("solution for points 1, 2 and 3", points);
found = true;
// Subsequent points, intersections of n-1 circles, use first two to find 2 solutions,
// the 3rd to pick one of the two
// then use others to check it's valid
for (i = 3; i < data.length; i++) {
// distances to points 1 and 2 give two circles and two possible solutions
solutions = intersection(
points[0][0], points[0][1], data[i][0],
points[1][0], points[1][1], data[i][1]);
//console.log("possible solutions for point " + (i + 1), solutions);
// try to find which solution is compatible with distance to point 3
found = false;
for (j = 0; j < 2; j++) {
if (Math.abs(distance(solutions[j], points[2]) - data[i][2]) <= threshold) {
point = solutions[j];
found = true;
break;
}
}
if (!found) {
console.log("could not find solution for point " + (i + 1));
console.log("distance data", data);
console.log("solution for points 1, 2 and 3", points);
console.log("possible solutions for point " + (i + 1), solutions);
console.log("distances to point 3",
distance(solutions[0], points[2]),
distance(solutions[1], points[2]),
data[i][2]
);
break;
}
// We have found a solution, we need to check it's valid
for (j = 3; j < i; j++) {
if (Math.abs(distance(point, points[j]) - data[i][j]) > threshold) {
console.log("Could not verify solution", point, "for point " + (i + 1) + " against distance to point " + (j + 1));
found = false;
break;
}
}
if (!found) {
console.log("stopping");
break;
}
points.push(point);
}
if (found) {
//console.log("complete solution", points);
return points;
}
}
console.log(findPointsForDistances([
[],
[2344],
[3333, 3566],
[10000, 10333, 12520],
]));
console.log(findPointsForDistances([
[],
[2],
[4, 2],
]));
console.log(findPointsForDistances([
[],
[4000],
[5000, 3000],
[3000, 5000, 4000]
]));
console.log(findPointsForDistances([
[],
[2928],
[4938, 3437],
[10557, 10726, 13535]
]));
var nbPoints, i;
for (nbPoints = 4; nbPoints < 8; nbPoints++) {
for (i = 0; i < 10; i++) {
console.log(findPointsForDistances(generateData(nbPoints)));
}
}
Fiddle here: https://jsfiddle.net/jacquesc/82aqmpnb/15/
Minimum working example. Remember that in canvas coordinates, the y value is inverted but you could do something like:
y = canvasHeight - y
If you also have negative points then if would take a little bit of extra work. Also it may be helpful in that case to draw lines and tick marks to visualize the axis.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let scale = 10;
let radius = 10;
function point(x, y) {
ctx.fillRect(x*scale, y*scale, radius, radius);
}
// test
point(10, 15);
point(20, 8);
<html>
<body>
<canvas id="canvas" width=1000 height=1000></canvas>
</body>
</html>
There are plenty of libraries out there.
chartist.js is easy to use and responsive JavaS cript library. I used it last year for basic charts after trying many others but it was the only one that scaling easily in different screen sizes.
chartJS is another better looking library.
And you can use html5 canvas it's easy and fun but it will take time especially in scaling.
To scale and position, you should use the minimum and maximum values for x and y.
Good luck
This is a box with an irregular shape that I have generated:
And this is the end effect I'd like to achieve (note the smooth edges):
Here's the code for my sharp version:
var path1 = new Path({
segments: [[123, 6], [290, 6], [304, 142], [112, 142]],
strokeColor: 'white',
closed: true,
strokeWidth: 3,
strokeJoin: 'round'
});
Thing is, I'm already using the strokeJoin: 'round' option and the difference is hardly noticeable with a stroke width of 3px. It's a small thing but could turn into a game breaker as there are going to be multiple objects like this and the difference is huge.
Is there any way to achieve that with paper.js without overdoing it?
As markE mentioned, strokeJoin only changes the canvas style of a path's stroke. Paper.js does not come with a corner-rounding function, you'll have to make your own.
Here's a quick function that you can use a starting point. It will negatively offset the points of a polygon by a given distance and add the appropriate handles.
function roundPath(path,radius) {
var segments = path.segments.slice(0);
path.segments = [];
for(var i = 0, l = segments.length; i < l; i++) {
var curPoint = segments[i].point;
var nextPoint = segments[i + 1 == l ? 0 : i + 1].point;
var prevPoint = segments[i - 1 < 0 ? segments.length - 1 : i - 1].point;
var nextDelta = curPoint - nextPoint;
var prevDelta = curPoint - prevPoint;
nextDelta.length = radius;
prevDelta.length = radius;
path.add({
point:curPoint - prevDelta,
handleOut: prevDelta/2
});
path.add({
point:curPoint - nextDelta,
handleIn: nextDelta/2
});
}
path.closed = true;
return path;
}
Here it is in action.
I was looking for an exact implementation, as described here: http://shanfanhuang.com/everything/2015/10/27/rounding-corners
My implementation works as follows:
curPoint is the corner, prevPoint and nextPoint as above
nextNorm and prevNorm are the normalized versions of the points
angle is the angle of the corner, derived from the dot product
delta is the distance from the corner points to where the control points need to be inserted, this is derived from a right triangle formed by the control point, curPoint and the center of the corner arc. The corner is a half angle, and the side opposing that corner is the radius
prevDelta and nextDelta are the new endpoints of the sides, between those an arc is inserted
through is a point halfway on the arc, found by getting the hypotenuse of the above triangle and subtracting the radius.
var segments = path.segments.slice(0);
path.segments = [];
for(var i = 0, l = segments.length; i < l; i++) {
var curPoint = segments[i].point;
var nextPoint = segments[i + 1 == l ? 0 : i + 1].point;
var prevPoint = segments[i - 1 < 0 ? segments.length - 1 : i - 1].point;
var nextNorm = (curPoint - nextPoint).normalize();
var prevNorm = (curPoint - prevPoint).normalize();
var angle = Math.acos(nextNorm.dot(prevNorm));
var delta = radius/Math.tan(angle/2);
var prevDelta = prevNorm.normalize(delta);
var nextDelta = nextNorm.normalize(delta);
var through = curPoint - (prevNorm + nextNorm).normalize(Math.sqrt(delta*delta + radius*radius) - radius);
path.add(curPoint - prevDelta);
path.arcTo(through, curPoint - nextDelta);
}
Given three circles with their center point and radius, how can you define the area of intersection?
So far what I have is:
var point1 = {x: -3, y: 0};
var point2 = {x: 3, y: 0};
var point3 = {x: 0, y: -3};
var r1 = 5;
var r2 = 5;
var r3 = 5;
var area = returnIntersectionArea(point1, point2, point3, r1, r2, r3);
Also, if two collide but not the third, the function should return null.
If none collide, null should be returned.
This article describes how to find the area of the intersection between two circles. The result it easily extended to three circles.
-------------EDIT-------------
OK, the problem is not easily extended to three circles, I found PhD theses on the subject. Assuming the three circles intersect as shown below, an approximate solution can be found (I think). Before we attempt it, we must check if the three circles indeed intersect as shown below. The problem changes quite a bit if say one circle is inside the other and the third intersects them both.
.
Let S1,S2 and S3 denote the areas of the three circles, and X1,X2 and X3 denote the area of the intersections between each pair of circles (index increases in clockwise direction). As we already established, there are exact formulae for these. Consider the following system of linear equations:
A+D+F+G = A+D+X1 = S1
B+D+E+G = B+D+ X3 = S2
B+E+D+G = B+E+X2 = S3
It is underdetermined, but an approximate solution can be found using least squares. I haven't tried it numerically but will get back to you as soon as I do :D
If the least-squares solution seems wrong, we should also impose several constraints, e.g. the area if the intersection between any pair of circles is smaller than the area of the circles.
Comments are appreciated.
PS +1 to Simon for pointing out I shouldn't qualify things as easy
One way of approaching this problem is via a Monte Carlo simulation:
function returnIntersectionArea(point1, point2, point3, r1, r2, r3) {
// determine bounding rectangle
var left = Math.min(point1.x - r1, point2.x - r2, point3.x - r3);
var right = Math.max(point1.x + r1, point2.x + r2, point3.x + r3);
var top = Math.min(point1.y - r1, point2.y - r2, point3.y - r3);
var bottom = Math.max(point1.y + r1, point2.y + r2, point3.y + r3);
// area of bounding rectangle
var rectArea = (right - left) * (bottom - top);
var iterations = 10000;
var pts = 0;
for (int i=0; i<iterations; i++) {
// random point coordinates
var x = left + Math.rand() * (right - left);
var y = top + Math.rand() * (bottom - top);
// check if it is inside all the three circles (the intersecting area)
if (Math.sqrt(Math.pow(x - point1.x, 2) + Math.pow(y - point1.y, 2)) <= r1 &&
Math.sqrt(Math.pow(x - point2.x, 2) + Math.pow(y - point2.y, 2)) <= r2 &&
Math.sqrt(Math.pow(x - point3.x, 2) + Math.pow(y - point3.y, 2)) <= r3)
pts++;
}
// the ratio of points inside the intersecting area will converge to the ratio
// of the area of the bounding rectangle and the intersection
return pts / iterations * rectArea;
}
The solution can be improved to arbitrary precision (within floating-point limits) by increasing the number of iterations, although the rate at which the solution is approached may become slow. Obviously, choosing a tight bounding box is important for achieving good convergence.