algorithms/distance.js

  1. "use strict";
  2. let IntervalTree = require('flatten-interval-tree');
  3. module.exports = function(Flatten) {
  4. let {Polygon, Point, Segment, Arc, Circle, Line, Ray, Vector} = Flatten;
  5. let {vector} = Flatten;
  6. Flatten.Distance = class Distance {
  7. /**
  8. * Calculate distance and shortest segment between points
  9. * @param pt1
  10. * @param pt2
  11. * @returns {Number | Segment} - distance and shortest segment
  12. */
  13. static point2point(pt1, pt2) {
  14. return pt1.distanceTo(pt2);
  15. }
  16. /**
  17. * Calculate distance and shortest segment between point and line
  18. * @param pt
  19. * @param line
  20. * @returns {Number | Segment} - distance and shortest segment
  21. */
  22. static point2line(pt, line) {
  23. let closest_point = pt.projectionOn(line);
  24. let vec = vector(pt, closest_point);
  25. return [vec.length, new Segment(pt, closest_point)];
  26. }
  27. /**
  28. * Calculate distance and shortest segment between point and circle
  29. * @param pt
  30. * @param circle
  31. * @returns {Number | Segment} - distance and shortest segment
  32. */
  33. static point2circle(pt, circle) {
  34. let [dist2center, shortest_dist] = pt.distanceTo(circle.center);
  35. if (Flatten.Utils.EQ_0(dist2center)) {
  36. return [circle.r, new Segment(pt, circle.toArc().start)];
  37. }
  38. else {
  39. let dist = Math.abs(dist2center - circle.r);
  40. let v = vector(circle.pc, pt).normalize().multiply(circle.r);
  41. let closest_point = circle.pc.translate(v);
  42. return [dist, new Segment(pt, closest_point)];
  43. }
  44. }
  45. /**
  46. * Calculate distance and shortest segment between point and segment
  47. * @param pt
  48. * @param segment
  49. * @returns {Number | Segment} - distance and shortest segment
  50. */
  51. static point2segment(pt, segment) {
  52. /* Degenerated case of zero-length segment */
  53. if (segment.start.equalTo(segment.end)) {
  54. return Distance.point2point(pt, segment.start);
  55. }
  56. let v_seg = new Flatten.Vector(segment.start, segment.end);
  57. let v_ps2pt = new Flatten.Vector(segment.start, pt);
  58. let v_pe2pt = new Flatten.Vector(segment.end, pt);
  59. let start_sp = v_seg.dot(v_ps2pt);
  60. /* dot product v_seg * v_ps2pt */
  61. let end_sp = -v_seg.dot(v_pe2pt);
  62. /* minus dot product v_seg * v_pe2pt */
  63. let dist;
  64. let closest_point;
  65. if (Flatten.Utils.GE(start_sp, 0) && Flatten.Utils.GE(end_sp, 0)) { /* point inside segment scope */
  66. let v_unit = segment.tangentInStart(); // new Flatten.Vector(v_seg.x / this.length, v_seg.y / this.length);
  67. /* unit vector ||v_unit|| = 1 */
  68. dist = Math.abs(v_unit.cross(v_ps2pt));
  69. /* dist = abs(v_unit x v_ps2pt) */
  70. closest_point = segment.start.translate(v_unit.multiply(v_unit.dot(v_ps2pt)));
  71. return [dist, new Segment(pt, closest_point)];
  72. }
  73. else if (start_sp < 0) { /* point is out of scope closer to ps */
  74. return pt.distanceTo(segment.start);
  75. }
  76. else { /* point is out of scope closer to pe */
  77. return pt.distanceTo(segment.end);
  78. }
  79. };
  80. /**
  81. * Calculate distance and shortest segment between point and arc
  82. * @param pt
  83. * @param arc
  84. * @returns {Number | Segment} - distance and shortest segment
  85. */
  86. static point2arc(pt, arc) {
  87. let circle = new Flatten.Circle(arc.pc, arc.r);
  88. let dist_and_segment = [];
  89. let dist, shortest_segment;
  90. [dist, shortest_segment] = Distance.point2circle(pt, circle);
  91. if (shortest_segment.end.on(arc)) {
  92. dist_and_segment.push(Distance.point2circle(pt, circle));
  93. }
  94. dist_and_segment.push( Distance.point2point(pt, arc.start) );
  95. dist_and_segment.push( Distance.point2point(pt, arc.end) );
  96. Distance.sort(dist_and_segment);
  97. return dist_and_segment[0];
  98. }
  99. /**
  100. * Calculate distance and shortest segment between segment and line
  101. * @param seg
  102. * @param line
  103. * @returns {Number | Segment}
  104. */
  105. static segment2line(seg, line) {
  106. let ip = seg.intersect(line);
  107. if (ip.length > 0) {
  108. return [0, new Segment(ip[0],ip[0])]; // distance = 0, closest point is the first point
  109. }
  110. let dist_and_segment = [];
  111. dist_and_segment.push(Distance.point2line(seg.start, line));
  112. dist_and_segment.push(Distance.point2line(seg.end, line));
  113. Distance.sort( dist_and_segment );
  114. return dist_and_segment[0];
  115. }
  116. /**
  117. * Calculate distance and shortest segment between two segments
  118. * @param seg1
  119. * @param seg2
  120. * @returns {Number | Segment} - distance and shortest segment
  121. */
  122. static segment2segment(seg1, seg2) {
  123. let ip = Segment.intersectSegment2Segment(seg1, seg2);
  124. if (ip.length > 0) {
  125. return [0, new Segment(ip[0],ip[0])]; // distance = 0, closest point is the first point
  126. }
  127. // Seg1 and seg2 not intersected
  128. let dist_and_segment = [];
  129. dist_and_segment.push(Distance.point2segment(seg2.start, seg1));
  130. dist_and_segment.push(Distance.point2segment(seg2.end, seg1));
  131. dist_and_segment.push(Distance.point2segment(seg1.start, seg2));
  132. dist_and_segment.push(Distance.point2segment(seg1.end, seg2));
  133. Distance.sort( dist_and_segment );
  134. return dist_and_segment[0];
  135. }
  136. /**
  137. * Calculate distance and shortest segment between segment and circle
  138. * @param seg
  139. * @param circle
  140. * @returns {Number | Segment} - distance and shortest segment
  141. */
  142. static segment2circle(seg, circle) {
  143. /* Case 1 Segment and circle intersected. Return the first point and zero distance */
  144. let ip = seg.intersect(circle);
  145. if (ip.length > 0) {
  146. return [0, new Segment(ip[0], ip[0])];
  147. }
  148. // No intersection between segment and circle
  149. /* Case 2. Distance to projection of center point to line bigger than radius
  150. * And projection point belong to segment
  151. * Then measure again distance from projection to circle and return it */
  152. let line = new Flatten.Line(seg.ps, seg.pe);
  153. let [dist, shortest_segment] = Distance.point2line(circle.center, line);
  154. if (Flatten.Utils.GE(dist, circle.r) && shortest_segment.end.on(seg)) {
  155. return Distance.point2circle(shortest_segment.end, circle);
  156. }
  157. /* Case 3. Otherwise closest point is one of the end points of the segment */
  158. else {
  159. let [dist_from_start, shortest_segment_from_start] = Distance.point2circle(seg.start, circle);
  160. let [dist_from_end, shortest_segment_from_end] = Distance.point2circle(seg.end, circle);
  161. return Flatten.Utils.LT(dist_from_start, dist_from_end) ?
  162. [dist_from_start, shortest_segment_from_start] :
  163. [dist_from_end, shortest_segment_from_end];
  164. }
  165. }
  166. /**
  167. * Calculate distance and shortest segment between segment and arc
  168. * @param seg
  169. * @param arc
  170. * @returns {Number | Segment} - distance and shortest segment
  171. */
  172. static segment2arc(seg, arc) {
  173. /* Case 1 Segment and arc intersected. Return the first point and zero distance */
  174. let ip = seg.intersect(arc);
  175. if (ip.length > 0) {
  176. return [0, new Segment(ip[0], ip[0])];
  177. }
  178. // No intersection between segment and arc
  179. let line = new Flatten.Line(seg.ps, seg.pe);
  180. let circle = new Flatten.Circle(arc.pc, arc.r);
  181. /* Case 2. Distance to projection of center point to line bigger than radius AND
  182. * projection point belongs to segment AND
  183. * distance from projection point to circle belongs to arc =>
  184. * return this distance from projection to circle */
  185. let [dist_from_center, shortest_segment_from_center] = Distance.point2line(circle.center, line);
  186. if (Flatten.Utils.GE(dist_from_center, circle.r) && shortest_segment_from_center.end.on(seg)) {
  187. let [dist_from_projection, shortest_segment_from_projection] =
  188. Distance.point2circle(shortest_segment_from_center.end, circle);
  189. if (shortest_segment_from_projection.end.on(arc)) {
  190. return [dist_from_projection, shortest_segment_from_projection];
  191. }
  192. }
  193. /* Case 3. Otherwise closest point is one of the end points of the segment */
  194. let dist_and_segment = [];
  195. dist_and_segment.push(Distance.point2arc(seg.start, arc));
  196. dist_and_segment.push(Distance.point2arc(seg.end, arc));
  197. let dist_tmp, segment_tmp;
  198. [dist_tmp, segment_tmp] = Distance.point2segment(arc.start, seg);
  199. dist_and_segment.push([dist_tmp, segment_tmp.reverse()]);
  200. [dist_tmp, segment_tmp] = Distance.point2segment(arc.end, seg);
  201. dist_and_segment.push([dist_tmp, segment_tmp.reverse()]);
  202. Distance.sort(dist_and_segment);
  203. return dist_and_segment[0];
  204. }
  205. /**
  206. * Calculate distance and shortest segment between two circles
  207. * @param circle1
  208. * @param circle2
  209. * @returns {Number | Segment} - distance and shortest segment
  210. */
  211. static circle2circle(circle1, circle2) {
  212. let ip = circle1.intersect(circle2);
  213. if (ip.length > 0) {
  214. return [0, new Segment(ip[0], ip[0])];
  215. }
  216. // Case 1. Concentric circles. Convert to arcs and take distance between two arc starts
  217. if (circle1.center.equalTo(circle2.center)) {
  218. let arc1 = circle1.toArc();
  219. let arc2 = circle2.toArc();
  220. return Distance.point2point(arc1.start, arc2.start);
  221. }
  222. else {
  223. // Case 2. Not concentric circles
  224. let line = new Line(circle1.center, circle2.center);
  225. let ip1 = line.intersect(circle1);
  226. let ip2 = line.intersect(circle2);
  227. let dist_and_segment = [];
  228. dist_and_segment.push(Distance.point2point(ip1[0], ip2[0]));
  229. dist_and_segment.push(Distance.point2point(ip1[0], ip2[1]));
  230. dist_and_segment.push(Distance.point2point(ip1[1], ip2[0]));
  231. dist_and_segment.push(Distance.point2point(ip1[1], ip2[1]));
  232. Distance.sort(dist_and_segment);
  233. return dist_and_segment[0];
  234. }
  235. }
  236. /**
  237. * Calculate distance and shortest segment between two circles
  238. * @param circle
  239. * @param line
  240. * @returns {Number | Segment} - distance and shortest segment
  241. */
  242. static circle2line(circle, line) {
  243. let ip = circle.intersect(line);
  244. if (ip.length > 0) {
  245. return [0, new Segment(ip[0], ip[0])];
  246. }
  247. let [dist_from_center, shortest_segment_from_center] = Distance.point2line(circle.center, line);
  248. let [dist, shortest_segment] = Distance.point2circle(shortest_segment_from_center.end, circle);
  249. shortest_segment = shortest_segment.reverse();
  250. return [dist, shortest_segment];
  251. }
  252. /**
  253. * Calculate distance and shortest segment between arc and line
  254. * @param arc
  255. * @param line
  256. * @returns {Number | Segment} - distance and shortest segment
  257. */
  258. static arc2line(arc, line) {
  259. /* Case 1 Line and arc intersected. Return the first point and zero distance */
  260. let ip = line.intersect(arc);
  261. if (ip.length > 0) {
  262. return [0, new Segment(ip[0], ip[0])];
  263. }
  264. let circle = new Flatten.Circle(arc.center, arc.r);
  265. /* Case 2. Distance to projection of center point to line bigger than radius AND
  266. * projection point belongs to segment AND
  267. * distance from projection point to circle belongs to arc =>
  268. * return this distance from projection to circle */
  269. let [dist_from_center, shortest_segment_from_center] = Distance.point2line(circle.center, line);
  270. if (Flatten.Utils.GE(dist_from_center, circle.r)) {
  271. let [dist_from_projection, shortest_segment_from_projection] =
  272. Distance.point2circle(shortest_segment_from_center.end, circle);
  273. if (shortest_segment_from_projection.end.on(arc)) {
  274. return [dist_from_projection, shortest_segment_from_projection];
  275. }
  276. }
  277. else {
  278. let dist_and_segment = [];
  279. dist_and_segment.push( Distance.point2line(arc.start, line) );
  280. dist_and_segment.push( Distance.point2line(arc.end, line) );
  281. Distance.sort(dist_and_segment);
  282. return dist_and_segment[0];
  283. }
  284. }
  285. /**
  286. * Calculate distance and shortest segment between arc and circle
  287. * @param arc
  288. * @param circle2
  289. * @returns {Number | Segment} - distance and shortest segment
  290. */
  291. static arc2circle(arc, circle2) {
  292. let ip = arc.intersect(circle2);
  293. if (ip.length > 0) {
  294. return [0, new Segment(ip[0], ip[0])];
  295. }
  296. let circle1 = new Flatten.Circle(arc.center, arc.r);
  297. let [dist, shortest_segment] = Distance.circle2circle(circle1, circle2);
  298. if (shortest_segment.start.on(arc)) {
  299. return [dist, shortest_segment];
  300. }
  301. else {
  302. let dist_and_segment = [];
  303. dist_and_segment.push(Distance.point2circle(arc.start, circle2));
  304. dist_and_segment.push(Distance.point2circle(arc.end, circle2));
  305. Distance.sort(dist_and_segment);
  306. return dist_and_segment[0];
  307. }
  308. }
  309. /**
  310. * Calculate distance and shortest segment between two arcs
  311. * @param arc1
  312. * @param arc2
  313. * @returns {Number | Segment} - distance and shortest segment
  314. */
  315. static arc2arc(arc1, arc2) {
  316. let ip = arc1.intersect(arc2);
  317. if (ip.length > 0) {
  318. return [0, new Segment(ip[0], ip[0])];
  319. }
  320. let circle1 = new Flatten.Circle(arc1.center, arc1.r);
  321. let circle2 = new Flatten.Circle(arc2.center, arc2.r);
  322. let [dist, shortest_segment] = Distance.circle2circle(circle1, circle2);
  323. if (shortest_segment.start.on(arc1) && shortest_segment.end.on(arc2)) {
  324. return [dist, shortest_segment];
  325. }
  326. else {
  327. let dist_and_segment = [];
  328. let dist_tmp, segment_tmp;
  329. [dist_tmp, segment_tmp] = Distance.point2arc(arc1.start, arc2);
  330. if (segment_tmp.end.on(arc2)) {
  331. dist_and_segment.push([dist_tmp, segment_tmp]);
  332. }
  333. [dist_tmp, segment_tmp] = Distance.point2arc(arc1.end, arc2);
  334. if (segment_tmp.end.on(arc2)) {
  335. dist_and_segment.push([dist_tmp, segment_tmp]);
  336. }
  337. [dist_tmp, segment_tmp] = Distance.point2arc(arc2.start, arc1);
  338. if (segment_tmp.end.on(arc1)) {
  339. dist_and_segment.push([dist_tmp, segment_tmp.reverse()]);
  340. }
  341. [dist_tmp, segment_tmp] = Distance.point2arc(arc2.end, arc1);
  342. if (segment_tmp.end.on(arc1)) {
  343. dist_and_segment.push([dist_tmp, segment_tmp.reverse()]);
  344. }
  345. [dist_tmp, segment_tmp] = Distance.point2point(arc1.start, arc2.start);
  346. dist_and_segment.push([dist_tmp, segment_tmp]);
  347. [dist_tmp, segment_tmp] = Distance.point2point(arc1.start, arc2.end);
  348. dist_and_segment.push([dist_tmp, segment_tmp]);
  349. [dist_tmp, segment_tmp] = Distance.point2point(arc1.end, arc2.start);
  350. dist_and_segment.push([dist_tmp, segment_tmp]);
  351. [dist_tmp, segment_tmp] = Distance.point2point(arc1.end, arc2.end);
  352. dist_and_segment.push([dist_tmp, segment_tmp]);
  353. Distance.sort(dist_and_segment);
  354. return dist_and_segment[0];
  355. }
  356. }
  357. /**
  358. * Calculate distance and shortest segment between point and polygon
  359. * @param point
  360. * @param polygon
  361. * @returns {Number | Segment} - distance and shortest segment
  362. */
  363. static point2polygon(point, polygon) {
  364. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Segment()];
  365. for (let edge of polygon.edges) {
  366. let [dist, shortest_segment] = (edge.shape instanceof Segment) ?
  367. Distance.point2segment(point, edge.shape) : Distance.point2arc(point, edge.shape);
  368. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  369. min_dist_and_segment = [dist, shortest_segment];
  370. }
  371. }
  372. return min_dist_and_segment;
  373. }
  374. static shape2polygon(shape, polygon) {
  375. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Segment()];
  376. for (let edge of polygon.edges) {
  377. let [dist, shortest_segment] = shape.distanceTo(edge.shape);
  378. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  379. min_dist_and_segment = [dist, shortest_segment];
  380. }
  381. }
  382. return min_dist_and_segment;
  383. }
  384. /*
  385. static arc2polygon(arc, polygon) {
  386. let ip = arc.intersect(polygon);
  387. if (ip.length > 0) {
  388. return [0, new Segment(ip[0], ip[0])];
  389. }
  390. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Segment()];
  391. for (let edge of polygon.edges) {
  392. let [dist, shortest_segment] = arc.distanceTo(edge.shape);
  393. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  394. min_dist_and_segment = [dist, shortest_segment];
  395. }
  396. }
  397. return min_dist_and_segment;
  398. }
  399. static line2polygon(line, polygon) {
  400. let ip = line.intersect(polygon);
  401. if (ip.length > 0) {
  402. return [0, new Segment(ip[0], ip[0])];
  403. }
  404. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Segment()];
  405. for (let edge of polygon.edges) {
  406. let [dist, shortest_segment] = line.distanceTo(edge.shape);
  407. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  408. min_dist_and_segment = [dist, shortest_segment];
  409. }
  410. }
  411. return min_dist_and_segment;
  412. }
  413. static circle2polygon(circle, polygon) {
  414. let ip = circle.intersect(polygon);
  415. if (ip.length > 0) {
  416. return [0, new Segment(ip[0], ip[0])];
  417. }
  418. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Segment()];
  419. for (let edge of polygon.edges) {
  420. let [dist, shortest_segment] = circle.distanceTo(edge.shape);
  421. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  422. min_dist_and_segment = [dist, shortest_segment];
  423. }
  424. }
  425. return min_dist_and_segment;
  426. }
  427. */
  428. /**
  429. * Calculate distance and shortest segment between two polygons
  430. * @param polygon1
  431. * @param polygon2
  432. * @returns {Number | Segment} - distance and shortest segment
  433. */
  434. static polygon2polygon(polygon1, polygon2) {
  435. let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Flatten.Segment()];
  436. for (let edge1 of polygon1.edges) {
  437. for (let edge2 of polygon2.edges) {
  438. let [dist, shortest_segment] = edge1.shape.distanceTo(edge2.shape);
  439. if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) {
  440. min_dist_and_segment = [dist, shortest_segment];
  441. }
  442. }
  443. }
  444. return min_dist_and_segment;
  445. }
  446. /**
  447. * Returns [mindist, maxdist] array of squared minimal and maximal distance between boxes
  448. * Minimal distance by x is
  449. * (box2.xmin - box1.xmax), if box1 is left to box2
  450. * (box1.xmin - box2.xmax), if box2 is left to box1
  451. * 0, if box1 and box2 are intersected by x
  452. * Minimal distance by y is defined in the same way
  453. *
  454. * Maximal distance is estimated as a sum of squared dimensions of the merged box
  455. *
  456. * @param box1
  457. * @param box2
  458. * @returns {Number | Number} - minimal and maximal distance
  459. */
  460. static box2box_minmax(box1, box2) {
  461. let mindist_x = Math.max( Math.max(box1.xmin - box2.xmax, 0), Math.max(box2.xmin - box1.xmax, 0) );
  462. let mindist_y = Math.max( Math.max(box1.ymin - box2.ymax, 0), Math.max(box2.ymin - box1.ymax, 0) );
  463. let mindist = mindist_x*mindist_x + mindist_y*mindist_y;
  464. let box = box1.merge(box2);
  465. let dx = box.xmax - box.xmin;
  466. let dy = box.ymax - box.ymin;
  467. let maxdist = dx*dx + dy*dy;
  468. return [mindist, maxdist];
  469. }
  470. static minmax_tree_process_level(shape, level, min_stop, tree) {
  471. // Calculate minmax distance to each shape in current level
  472. // Insert result into the interval tree for further processing
  473. // update min_stop with maxdist, it will be the new stop distance
  474. let mindist, maxdist;
  475. for (let node of level) {
  476. // [mindist, maxdist] = Distance.box2box_minmax(shape.box, node.max);
  477. // if (Flatten.Utils.GT(mindist, min_stop))
  478. // continue;
  479. // Estimate min-max dist to the shape stored in the node.item, using node.item.key which is shape's box
  480. [mindist, maxdist] = Distance.box2box_minmax(shape.box, node.item.key);
  481. if (node.item.value instanceof Flatten.Edge) {
  482. tree.insert([mindist, maxdist], node.item.value.shape);
  483. }
  484. else {
  485. tree.insert([mindist, maxdist], node.item.value);
  486. }
  487. if (Flatten.Utils.LT(maxdist, min_stop)) {
  488. min_stop = maxdist; // this will be the new distance estimation
  489. }
  490. }
  491. if (level.length === 0)
  492. return min_stop;
  493. // Calculate new level from left and right children of the current
  494. let new_level_left = level.map(node => node.left.isNil() ? undefined : node.left ).filter(node => node !== undefined);
  495. let new_level_right = level.map(node => node.right.isNil() ? undefined : node.right).filter(node => node !== undefined);
  496. // Merge left and right subtrees and leave only relevant subtrees
  497. let new_level = [...new_level_left, ...new_level_right].filter( node => {
  498. // Node subtree quick reject, node.max is a subtree box
  499. let [mindist, maxdist] = Distance.box2box_minmax(shape.box, node.max);
  500. return (Flatten.Utils.LE(mindist, min_stop));
  501. });
  502. min_stop = Distance.minmax_tree_process_level(shape, new_level, min_stop, tree);
  503. return min_stop;
  504. }
  505. /**
  506. * Calculates sorted tree of [mindist, maxdist] intervals between query shape
  507. * and shapes of the planar set.
  508. * @param shape
  509. * @param set
  510. */
  511. static minmax_tree(shape, set, min_stop) {
  512. let tree = new IntervalTree();
  513. let level = [set.index.root];
  514. let squared_min_stop = min_stop < Number.POSITIVE_INFINITY ? min_stop*min_stop : Number.POSITIVE_INFINITY;
  515. squared_min_stop = Distance.minmax_tree_process_level(shape, level, squared_min_stop, tree);
  516. return tree;
  517. }
  518. static minmax_tree_calc_distance(shape, node, min_dist_and_segment) {
  519. let min_dist_and_segment_new, stop;
  520. if (node != null && !node.isNil()) {
  521. [min_dist_and_segment_new, stop] = Distance.minmax_tree_calc_distance(shape, node.left, min_dist_and_segment);
  522. if (stop) {
  523. return [min_dist_and_segment_new, stop];
  524. }
  525. if (Flatten.Utils.LT(min_dist_and_segment_new[0], Math.sqrt(node.item.key.low))) {
  526. return [min_dist_and_segment_new, true]; // stop condition
  527. }
  528. let [dist, shortest_segment] = Distance.distance(shape, node.item.value);
  529. // console.log(dist)
  530. if (Flatten.Utils.LT(dist, min_dist_and_segment_new[0])) {
  531. min_dist_and_segment_new = [dist, shortest_segment];
  532. }
  533. [min_dist_and_segment_new, stop] = Distance.minmax_tree_calc_distance(shape, node.right, min_dist_and_segment_new);
  534. return [min_dist_and_segment_new, stop];
  535. }
  536. return [min_dist_and_segment, false];
  537. }
  538. /**
  539. * Calculates distance between shape and Planar Set of shapes
  540. * @param shape
  541. * @param {PlanarSet} set
  542. * @param {Number} min_stop
  543. * @returns {*}
  544. */
  545. static shape2planarSet(shape, set, min_stop = Number.POSITIVE_INFINITY) {
  546. let min_dist_and_segment = [min_stop, new Flatten.Segment()];
  547. let stop = false;
  548. if (set instanceof Flatten.PlanarSet) {
  549. let tree = Distance.minmax_tree(shape, set, min_stop);
  550. [min_dist_and_segment, stop] = Distance.minmax_tree_calc_distance(shape, tree.root, min_dist_and_segment);
  551. }
  552. return min_dist_and_segment;
  553. }
  554. static sort(dist_and_segment) {
  555. dist_and_segment.sort((d1, d2) => {
  556. if (Flatten.Utils.LT(d1[0], d2[0])) {
  557. return -1;
  558. }
  559. if (Flatten.Utils.GT(d1[0], d2[0])) {
  560. return 1;
  561. }
  562. return 0;
  563. });
  564. }
  565. static distance(shape1, shape2) {
  566. return shape1.distanceTo(shape2);
  567. }
  568. }
  569. };