chore: version inicial del codigo fuente del LMS Estafeta
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
/* *
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
import Geometry from './Geometry.js';
|
||||
var getAngleBetweenPoints = Geometry.getAngleBetweenPoints, getCenterOfPoints = Geometry.getCenterOfPoints, getDistanceBetweenPoints = Geometry.getDistanceBetweenPoints;
|
||||
/**
|
||||
* @private
|
||||
* @param {number} x
|
||||
* Number to round
|
||||
* @param {number} decimals
|
||||
* Number of decimals to round to
|
||||
* @return {number}
|
||||
* Rounded number
|
||||
*/
|
||||
function round(x, decimals) {
|
||||
var a = Math.pow(10, decimals);
|
||||
return Math.round(x * a) / a;
|
||||
}
|
||||
/**
|
||||
* Calculates the area of a circle based on its radius.
|
||||
* @private
|
||||
* @param {number} r
|
||||
* The radius of the circle.
|
||||
* @return {number}
|
||||
* Returns the area of the circle.
|
||||
*/
|
||||
function getAreaOfCircle(r) {
|
||||
if (r <= 0) {
|
||||
throw new Error('radius of circle must be a positive number.');
|
||||
}
|
||||
return Math.PI * r * r;
|
||||
}
|
||||
/**
|
||||
* Calculates the area of a circular segment based on the radius of the circle
|
||||
* and the height of the segment.
|
||||
* See http://mathworld.wolfram.com/CircularSegment.html
|
||||
* @private
|
||||
* @param {number} r
|
||||
* The radius of the circle.
|
||||
* @param {number} h
|
||||
* The height of the circular segment.
|
||||
* @return {number}
|
||||
* Returns the area of the circular segment.
|
||||
*/
|
||||
function getCircularSegmentArea(r, h) {
|
||||
return r * r * Math.acos(1 - h / r) - (r - h) * Math.sqrt(h * (2 * r - h));
|
||||
}
|
||||
/**
|
||||
* Calculates the area of overlap between two circles based on their radiuses
|
||||
* and the distance between them.
|
||||
* See http://mathworld.wolfram.com/Circle-CircleIntersection.html
|
||||
* @private
|
||||
* @param {number} r1
|
||||
* Radius of the first circle.
|
||||
* @param {number} r2
|
||||
* Radius of the second circle.
|
||||
* @param {number} d
|
||||
* The distance between the two circles.
|
||||
* @return {number}
|
||||
* Returns the area of overlap between the two circles.
|
||||
*/
|
||||
function getOverlapBetweenCircles(r1, r2, d) {
|
||||
var overlap = 0;
|
||||
// If the distance is larger than the sum of the radiuses then the circles
|
||||
// does not overlap.
|
||||
if (d < r1 + r2) {
|
||||
if (d <= Math.abs(r2 - r1)) {
|
||||
// If the circles are completely overlapping, then the overlap
|
||||
// equals the area of the smallest circle.
|
||||
overlap = getAreaOfCircle(r1 < r2 ? r1 : r2);
|
||||
}
|
||||
else {
|
||||
// Height of first triangle segment.
|
||||
var d1 = (r1 * r1 - r2 * r2 + d * d) / (2 * d),
|
||||
// Height of second triangle segment.
|
||||
d2 = d - d1;
|
||||
overlap = (getCircularSegmentArea(r1, r1 - d1) +
|
||||
getCircularSegmentArea(r2, r2 - d2));
|
||||
}
|
||||
// Round the result to two decimals.
|
||||
overlap = round(overlap, 14);
|
||||
}
|
||||
return overlap;
|
||||
}
|
||||
/**
|
||||
* Calculates the intersection points of two circles.
|
||||
*
|
||||
* NOTE: does not handle floating errors well.
|
||||
* @private
|
||||
* @param {Highcharts.CircleObject} c1
|
||||
* The first circle.
|
||||
* @param {Highcharts.CircleObject} c2
|
||||
* The second sircle.
|
||||
* @return {Array<Highcharts.PositionObject>}
|
||||
* Returns the resulting intersection points.
|
||||
*/
|
||||
function getCircleCircleIntersection(c1, c2) {
|
||||
var d = getDistanceBetweenPoints(c1, c2), r1 = c1.r, r2 = c2.r;
|
||||
var points = [];
|
||||
if (d < r1 + r2 && d > Math.abs(r1 - r2)) {
|
||||
// If the circles are overlapping, but not completely overlapping, then
|
||||
// it exists intersecting points.
|
||||
var r1Square = r1 * r1, r2Square = r2 * r2,
|
||||
// d^2 - r^2 + R^2 / 2d
|
||||
x = (r1Square - r2Square + d * d) / (2 * d),
|
||||
// y^2 = R^2 - x^2
|
||||
y = Math.sqrt(r1Square - x * x), x1 = c1.x, x2 = c2.x, y1 = c1.y, y2 = c2.y, x0 = x1 + x * (x2 - x1) / d, y0 = y1 + x * (y2 - y1) / d, rx = -(y2 - y1) * (y / d), ry = -(x2 - x1) * (y / d);
|
||||
points = [
|
||||
{ x: round(x0 + rx, 14), y: round(y0 - ry, 14) },
|
||||
{ x: round(x0 - rx, 14), y: round(y0 + ry, 14) }
|
||||
];
|
||||
}
|
||||
return points;
|
||||
}
|
||||
/**
|
||||
* Calculates all the intersection points for between a list of circles.
|
||||
* @private
|
||||
* @param {Array<Highcharts.CircleObject>} circles
|
||||
* The circles to calculate the points from.
|
||||
* @return {Array<Highcharts.GeometryObject>}
|
||||
* Returns a list of intersection points.
|
||||
*/
|
||||
function getCirclesIntersectionPoints(circles) {
|
||||
return circles.reduce(function (points, c1, i, arr) {
|
||||
var additional = arr.slice(i + 1)
|
||||
.reduce(function (points, c2, j) {
|
||||
var indexes = [i, j + i + 1];
|
||||
return points.concat(getCircleCircleIntersection(c1, c2)
|
||||
.map(function (p) {
|
||||
p.indexes = indexes;
|
||||
return p;
|
||||
}));
|
||||
}, []);
|
||||
return points.concat(additional);
|
||||
}, []);
|
||||
}
|
||||
/**
|
||||
* Tests wether the first circle is completely overlapping the second circle.
|
||||
*
|
||||
* @private
|
||||
* @param {Highcharts.CircleObject} circle1 The first circle.
|
||||
* @param {Highcharts.CircleObject} circle2 The The second circle.
|
||||
* @return {boolean} Returns true if circle1 is completely overlapping circle2,
|
||||
* false if not.
|
||||
*/
|
||||
function isCircle1CompletelyOverlappingCircle2(circle1, circle2) {
|
||||
return getDistanceBetweenPoints(circle1, circle2) + circle2.r <
|
||||
circle1.r + 1e-10;
|
||||
}
|
||||
/**
|
||||
* Tests wether a point lies within a given circle.
|
||||
* @private
|
||||
* @param {Highcharts.PositionObject} point
|
||||
* The point to test for.
|
||||
* @param {Highcharts.CircleObject} circle
|
||||
* The circle to test if the point is within.
|
||||
* @return {boolean}
|
||||
* Returns true if the point is inside, false if outside.
|
||||
*/
|
||||
function isPointInsideCircle(point, circle) {
|
||||
return getDistanceBetweenPoints(point, circle) <= circle.r + 1e-10;
|
||||
}
|
||||
/**
|
||||
* Tests wether a point lies within a set of circles.
|
||||
* @private
|
||||
* @param {Highcharts.PositionObject} point
|
||||
* The point to test.
|
||||
* @param {Array<Highcharts.CircleObject>} circles
|
||||
* The list of circles to test against.
|
||||
* @return {boolean}
|
||||
* Returns true if the point is inside all the circles, false if not.
|
||||
*/
|
||||
function isPointInsideAllCircles(point, circles) {
|
||||
return !circles.some(function (circle) {
|
||||
return !isPointInsideCircle(point, circle);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Tests wether a point lies outside a set of circles.
|
||||
*
|
||||
* TODO: add unit tests.
|
||||
* @private
|
||||
* @param {Highcharts.PositionObject} point
|
||||
* The point to test.
|
||||
* @param {Array<Highcharts.CircleObject>} circles
|
||||
* The list of circles to test against.
|
||||
* @return {boolean}
|
||||
* Returns true if the point is outside all the circles, false if not.
|
||||
*/
|
||||
function isPointOutsideAllCircles(point, circles) {
|
||||
return !circles.some(function (circle) {
|
||||
return isPointInsideCircle(point, circle);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Calculates the points for the polygon of the intersection area between a set
|
||||
* of circles.
|
||||
*
|
||||
* @private
|
||||
* @param {Array<Highcharts.CircleObject>} circles
|
||||
* List of circles to calculate polygon of.
|
||||
* @return {Array<Highcharts.GeometryObject>} Return list of points in the
|
||||
* intersection polygon.
|
||||
*/
|
||||
function getCirclesIntersectionPolygon(circles) {
|
||||
return getCirclesIntersectionPoints(circles)
|
||||
.filter(function (p) {
|
||||
return isPointInsideAllCircles(p, circles);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Calculate the path for the area of overlap between a set of circles.
|
||||
* @todo handle cases with only 1 or 0 arcs.
|
||||
* @private
|
||||
* @param {Array<Highcharts.CircleObject>} circles
|
||||
* List of circles to calculate area of.
|
||||
* @return {Highcharts.GeometryIntersectionObject|undefined}
|
||||
* Returns the path for the area of overlap. Returns an empty string if
|
||||
* there are no intersection between all the circles.
|
||||
*/
|
||||
function getAreaOfIntersectionBetweenCircles(circles) {
|
||||
var intersectionPoints = getCirclesIntersectionPolygon(circles), result;
|
||||
if (intersectionPoints.length > 1) {
|
||||
// Calculate the center of the intersection points.
|
||||
var center_1 = getCenterOfPoints(intersectionPoints);
|
||||
intersectionPoints = intersectionPoints
|
||||
// Calculate the angle between the center and the points.
|
||||
.map(function (p) {
|
||||
p.angle = getAngleBetweenPoints(center_1, p);
|
||||
return p;
|
||||
})
|
||||
// Sort the points by the angle to the center.
|
||||
.sort(function (a, b) {
|
||||
return b.angle - a.angle;
|
||||
});
|
||||
var startPoint = intersectionPoints[intersectionPoints.length - 1];
|
||||
var arcs = intersectionPoints
|
||||
.reduce(function (data, p1) {
|
||||
var startPoint = data.startPoint, midPoint = getCenterOfPoints([startPoint, p1]);
|
||||
// Calculate the arc from the intersection points and their
|
||||
// circles.
|
||||
var arc = p1.indexes
|
||||
// Filter out circles that are not included in both
|
||||
// intersection points.
|
||||
.filter(function (index) {
|
||||
return startPoint.indexes.indexOf(index) > -1;
|
||||
})
|
||||
// Iterate the circles of the intersection points and
|
||||
// calculate arcs.
|
||||
.reduce(function (arc, index) {
|
||||
var circle = circles[index], angle1 = getAngleBetweenPoints(circle, p1), angle2 = getAngleBetweenPoints(circle, startPoint), angleDiff = angle2 - angle1 +
|
||||
(angle2 < angle1 ? 2 * Math.PI : 0), angle = angle2 - angleDiff / 2;
|
||||
var width = getDistanceBetweenPoints(midPoint, {
|
||||
x: circle.x + circle.r * Math.sin(angle),
|
||||
y: circle.y + circle.r * Math.cos(angle)
|
||||
});
|
||||
var r = circle.r;
|
||||
// Width can sometimes become to large due to floating
|
||||
// point errors
|
||||
if (width > r * 2) {
|
||||
width = r * 2;
|
||||
}
|
||||
// Get the arc with the smallest width.
|
||||
if (!arc || arc.width > width) {
|
||||
arc = {
|
||||
r: r,
|
||||
largeArc: width > r ? 1 : 0,
|
||||
width: width,
|
||||
x: p1.x,
|
||||
y: p1.y
|
||||
};
|
||||
}
|
||||
// Return the chosen arc.
|
||||
return arc;
|
||||
}, null);
|
||||
// If we find an arc then add it to the list and update p2.
|
||||
if (arc) {
|
||||
var r = arc.r;
|
||||
data.arcs.push(['A', r, r, 0, arc.largeArc, 1, arc.x, arc.y]);
|
||||
data.startPoint = p1;
|
||||
}
|
||||
return data;
|
||||
}, {
|
||||
startPoint: startPoint,
|
||||
arcs: []
|
||||
}).arcs;
|
||||
if (arcs.length === 0) {
|
||||
// empty
|
||||
}
|
||||
else if (arcs.length === 1) {
|
||||
// empty
|
||||
}
|
||||
else {
|
||||
arcs.unshift(['M', startPoint.x, startPoint.y]);
|
||||
result = {
|
||||
center: center_1,
|
||||
d: arcs
|
||||
};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
var geometryCircles = {
|
||||
getAreaOfCircle: getAreaOfCircle,
|
||||
getAreaOfIntersectionBetweenCircles: getAreaOfIntersectionBetweenCircles,
|
||||
getCircleCircleIntersection: getCircleCircleIntersection,
|
||||
getCirclesIntersectionPoints: getCirclesIntersectionPoints,
|
||||
getCirclesIntersectionPolygon: getCirclesIntersectionPolygon,
|
||||
getCircularSegmentArea: getCircularSegmentArea,
|
||||
getOverlapBetweenCircles: getOverlapBetweenCircles,
|
||||
isCircle1CompletelyOverlappingCircle2: isCircle1CompletelyOverlappingCircle2,
|
||||
isPointInsideCircle: isPointInsideCircle,
|
||||
isPointInsideAllCircles: isPointInsideAllCircles,
|
||||
isPointOutsideAllCircles: isPointOutsideAllCircles,
|
||||
round: round
|
||||
};
|
||||
export default geometryCircles;
|
||||
Reference in New Issue
Block a user