javascript - Calculate minimum value not between set of ranges -
given array of circles (x,y,r values), want place new point, such has fixed/known y-coordinate (shown horizontal line), , close possible center not within of existing circles. in example images, point in red result.
circles have known radius , y-axis attribute, easy calculate points intersect horizontal line @ known y value. efficiency important, don't want have try bunch of x coords , test them against each item in circles array. there way work out optimal x coordinate mathematically? appreciated. way, i'm writing in javascript using raphael.js library (because 1 supports ie8) - more of logic problem language doesn't matter.
basically equation of circle (x - cx)2 + (y - cy)2 = r2. therefore can find intersection points between circle , x axis substituting y 0. after have simple quadratic equation solve: x2 - 2cxx + cx2 + cy2 - r2 = 0 . have 3 possible outcomes:
- no intersection - determinant irrational number (nan in javascript), ignore result;
- one intersection - both solutions match, use [value, value];
- two intersections - both solutions different, use [value1, value2].
sort newly calculated intersection intervals, try merge them possible. take in mind in every program language there approximation, therefore need define delta value dot approximation , take consideration when merging intervals.
when intervals merged can generate x coordinates subtracting/adding same delta value beginning/end of every interval. , lastly points, 1 closest 0 answer.
here example o(n log n) complexity oriented rather towards readability. i've used 1*10-10 delta :
var circles = [ {x:0, y:0, r:1}, {x:2.5, y:0, r:1}, {x:-1, y:0.5, r:1}, {x:2, y:-0.5, r:1}, {x:-2, y:0, r:1}, {x:10, y:10, r:1} ]; console.log(getclosestpoint(circles, 1e-10)); function getclosestpoint(circles, delta) { var intervals = [], len = circles.length, i, result; (i = 0; < len; i++) { result = getxintersection(circles[i]) if (result) { intervals.push(result); } } intervals = intervals.sort(function(a, b){ return a.from - b.from; }); if (intervals.length <= 0) return 0; intervals = mergeintervals(intervals, delta); var points = getclosestpoints(intervals, delta); points = points.sort(function(a, b){ return math.abs(a) - math.abs(b); }); return points[0]; } function getxintersection(circle) { var d = math.sqrt(circle.r * circle.r - circle.y * circle.y); return isnan(d) ? null : {from: circle.x - d, to: circle.x + d}; } function mergeintervals(intervals, delta) { var curr = intervals[0], result = [], len = intervals.length, i; (i = 1 ; < len ; i++) { if (intervals[i].from <= curr.to + delta) { curr.to = math.max(curr.to, intervals[i].to); } else { result.push(curr); curr = intervals[i]; } } result.push(curr); return result; } function getclosestpoints(intervals, delta) { var result = [], len = intervals.length, i; (i = 0 ; < len ; i++) { result.push( intervals[i].from - delta ); result.push( intervals[i].to + delta ); } return result; }
Comments
Post a Comment