{"id":27969353,"url":"https://github.com/anvaka/isect","last_synced_at":"2025-05-07T21:10:04.063Z","repository":{"id":33734856,"uuid":"151803547","full_name":"anvaka/isect","owner":"anvaka","description":"Segments intersection detection library","archived":false,"fork":false,"pushed_at":"2025-03-11T06:26:15.000Z","size":1662,"stargazers_count":279,"open_issues_count":8,"forks_count":19,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-07T21:09:57.650Z","etag":null,"topics":["bentley-ottmann","brute-force","computational-geometry","segments","sweep-line"],"latest_commit_sha":null,"homepage":"https://anvaka.github.io/isect/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anvaka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-06T04:07:58.000Z","updated_at":"2025-04-09T10:49:51.000Z","dependencies_parsed_at":"2024-02-22T04:29:20.928Z","dependency_job_id":"2fcf3def-fd10-44ee-af67-df1869c1d6fa","html_url":"https://github.com/anvaka/isect","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fisect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fisect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fisect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fisect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anvaka","download_url":"https://codeload.github.com/anvaka/isect/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252954410,"owners_count":21830905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bentley-ottmann","brute-force","computational-geometry","segments","sweep-line"],"created_at":"2025-05-07T21:10:03.433Z","updated_at":"2025-05-07T21:10:04.040Z","avatar_url":"https://github.com/anvaka.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# isect - intersection detection library [![build status](https://github.com/anvaka/isect/actions/workflows/tests.yaml/badge.svg)](https://github.com/anvaka/isect/actions/workflows/tests.yaml)\n\nThis library allows you to find all intersections in a given set of\nsegments. \n\n[![demo](https://i.imgur.com/XiQ45h7.gif)](https://anvaka.github.io/isect/)\n\n[Try the demo online](https://anvaka.github.io/isect/)\n\n# Algorithms\n\nThe library implements three algorithms\n\n## Bentley-Ottmann sweep line algorithm\n\nThis algorithm has `O(n*log(n) + k*log(n))` performance, where `n` is number of\nsegments, and `k` is number of intersections.\n\nThis method is preferred when you have large number of lines, and not too many\nintersections (`k = o(n^2/log(n))`, to be more specific). \n\nThe algorithm follows \"Computation Geometry, Algorithms and Applications\" book\nby Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars. It does support\ndegenerate cases, though read limitations to learn more.\n\n[![demo](https://i.imgur.com/dQrGKTt.gif)](https://anvaka.github.io/isect/?isAsync=true\u0026p0=12\u0026p1=40\u0026generator=complete\u0026algorithm=sweep\u0026stepsPerFrame=1)\n\n## Brute force algorithm\n\nThis is \"naive\" implementation where each segment is compared with all other segments,\nand thus has O(n*n) performance.\n\nDespite its naiveté, it works much faster than Bentley-Ottmann algorithm for the cases\nwhen there are a few thousand lines and millions of intersections. This scenario is\ncommon in force-based graph drawing, where \"hairball\" is formed by a few thousand lines.\n\n[![demo](https://i.imgur.com/SUKRHt4.gif)](https://anvaka.github.io/isect/?isAsync=true\u0026p0=12\u0026p1=40\u0026generator=complete\u0026algorithm=brute\u0026stepsPerFrame=1)\n\n## \"Bush\" algorithm\n\nThis algorithm was suggested by [@mourner](https://twitter.com/mourner/status/1049325199617921024) and\n[@dy](https://github.com/anvaka/isect/issues/1). \nIt uses [mourner/flatbush](https://github.com/mourner/flatbush) as a spatial\nindex of segments, and then iterates over every segment, checking overlapping bounding boxes.\n\nIntuitively, worst case performance of this algorithm is comparable with brute force. When every segment\noverlaps with every other segment we should expect `O(n^2)` operations. In practice, however, this \nalgorithm beats both `Bentley-Ottman` and `Brute force` approaches.\n\nIts beauty is in its simplicity. It adapts very well to both sparse and dense segments distribution.\n\nYou can also find performance test suite below, so you can decide for yourself. I would absolutely go with\nthis algorithm as my default choice.\n\n## Performance \n\nThe benchmark code is [available here](https://github.com/anvaka/isect/blob/master/perf/index.js). Higher ops per second is better!\n\n### K12 graph\n\n[![K12 graph](https://i.imgur.com/PTXwvd3m.png)](https://anvaka.github.io/isect/?isAsync=false\u0026p0=12\u0026p1=40\u0026generator=complete\u0026algorithm=brute\u0026stepsPerFrame=1)\n\n* Sweep: Circular lines 12x40 x 1,069 ops/sec ±1.98% (91 runs sampled)\n* **Brute: Circular lines 12x40 x 7,463 ops/sec ±3.01% (76 runs sampled)**\n* Bush: Circular lines 12x40 x 5,678 ops/sec ±2.20% (80 runs sampled)\n\nThe graph has only `66` unique segments, and `313` unique\nintersections. Brute force algorithm is 7x faster than Sweep Line, closely followed by\n\n\n### 100 random lines\n\n[![100 random lines](https://i.imgur.com/ytOEsyNm.png)](https://anvaka.github.io/isect/?isAsync=false\u0026p0=100\u0026p1=40\u0026generator=random\u0026algorithm=brute\u0026stepsPerFrame=1)\n\nIn this demo 100 lines are randomly sampled inside a box with a side of 42px.\n\n* Sweep: 100 Random lines lines in 42px box x 277 ops/sec ±1.20% (87 runs sampled)\n* **Brute: 100 Random lines lines in 42px box x 3,606 ops/sec ±3.61% (74 runs sampled)**\n* Bush: 100 Random lines in 42px box x 3,314 ops/sec ±2.66% (83 runs sampled)\n\nAgain, the brute force algorithm wins. The distance between brute force and \nBush shortens. Sweep line comes last.\n\n### Sparse intersections\n\n[![sparse](https://i.imgur.com/ZkzZS9sm.png)](https://anvaka.github.io/isect/?isAsync=false\u0026p0=50\u0026p1=40\u0026generator=sparse\u0026algorithm=sweep\u0026stepsPerFrame=1)\n\n* Sweep: 2,500 sparse lines x 156 ops/sec ±0.97% (80 runs sampled)\n* Brute: 2,500 sparse lines x 13.62 ops/sec ±0.91% (38 runs sampled)\n* **Bush: 2,500 sparse lines x 592 ops/sec ±1.05% (93 runs sampled)**\n\nNow Bush algorithm wins by huge margin. Bentley-Ottman comes second, and brute\nforce comes the last.\n\n### Parallel Slanted lines\n\n[![slanted](https://i.imgur.com/vYAZzNvm.png)](https://anvaka.github.io/isect/?isAsync=false\u0026p0=1000\u0026p1=40\u0026generator=parallelSlanted\u0026algorithm=sweep\u0026stepsPerFrame=1)\n\n* **Sweep: 1000 slanted, not intersect x 622 ops/sec ±1.23% (91 runs sampled)**\n* Brute: 1000 slanted, not intersect x 230 ops/sec ±2.37% (87 runs sampled)\n* Bush: 1000 slanted, not intersect x 243 ops/sec ±1.07% (87 runs sampled)\n\nIn this example there too many lines, and none of them intersect. Furthermore, most of the\nrectangular bounding boxes do intersect, which gives more work for the `bush` algorithm\n\n# usage\n\nInstall the module from npm:\n\n```\nnpm i isect\n```\n\nOr download from CDN:\n\n``` html\n\u003cscript src='https://cdn.rawgit.com/anvaka/isect/v2.0.0/build/isect.min.js'\u003e\u003c/script\u003e\n```\n\nIf you download from CDN the library will be available under `isect` global name.\n\n## Basic usage\n\nThe code below detects all intersections between segments in the array:\n\n``` js\nvar isect = require('isect');\n\n// Prepare the library to detect all intersection\nvar detectIntersections = isect.bush([{\n  from: {x:  0, y:  0},\n  to:   {x: 10, y: 10}\n}, {\n  from: {x:  0, y: 10},\n  to:   {x: 10, y:  0}\n}]);\n\n// Detect them all, operation is synchronous. \nvar intersections = detectIntersections.run();\nconsole.log(intersections);\n// Prints:\n// \n//    [ { point: { x: 5, y: 5 }, segments: [ [Object], [Object] ] } ]\n// \n// array of segments contain both segments.\n```\n\n## Brute force and Sweep Line\n\nYou can also run the above example with a different algorithm. Simply\nchange `.bush()` to `.sweep()` (to run Bentley-Ottman) or to `.brute()` (to try\nbrute force):\n\n``` js\n\nvar isect = require('isect');\n\n// Prepare the library to detect all intersection\nvar bruteForce = isect.brute([{\n  from: {x:  0, y:  0},\n  to:   {x: 10, y: 10}\n}, {\n  from: {x:  0, y: 10},\n  to:   {x: 10, y:  0}\n}]);\n\nvar intersections = bruteForce.run();\nconsole.log(intersections);\n\n// do the same with sweep line:\nvar sweepLine = isect.sweep([{\n  from: {x:  0, y:  0},\n  to:   {x: 10, y: 10}\n}, {\n  from: {x:  0, y: 10},\n  to:   {x: 10, y:  0}\n}]);\n\nvar intersections = sweepLine.run();\nconsole.log(intersections);\n```\n\nAll algorithms have identical API. In every example below\nyou can replace `.bush()` with `.sweeep()` or `.brute()`  - just pay attention to notes that calls out\na discrepancies in the API.\n\n## Early stopping\n\nIf you don't care about all intersections, but want to know if there is\nat least one intersection, you can pass a `onFound()` callback and request\nthe library to stop as soon as it finds an intersection:\n\n``` js\nvar intersections = isect.bush([/* array of segments */], {\n  onFound(point, segments) {\n    // `point` is {x, y} of the intersection,\n    // `segments` are intersecting segments.\n\n    // If you return true from this method, no further processing will be done:\n\n    return true; // yes, stop right now!\n  }\n});\n```\n\n## Asynchronous workflow\n\nIf you want to give browser time to catch up with user input, it may be desirable to break the\nalgorithm into chunks (so that UI thread is not swamped). You can do this by calling `.step()`\nmethod of the algorithm's instance:\n\n\n``` js\nvar detector = isect.bush([/* array of segments */]);\n// instead of detector.run(), we do:\nvar isDone = detector.step()\n// isDone will be set to true, once the algorithm is completed.\n```\n\nThis is precisely how I do step-by-step animation of the algorithm:\n\n[![demo](https://i.imgur.com/dQrGKTt.gif)](https://anvaka.github.io/isect/?isAsync=true\u0026p0=12\u0026p1=40\u0026generator=complete\u0026algorithm=sweep\u0026stepsPerFrame=1)\n\n[Click here](https://anvaka.github.io/isect/?isAsync=true\u0026p0=12\u0026p1=40\u0026generator=complete\u0026algorithm=sweep\u0026stepsPerFrame=1) to see it in action. \n\n## Limitations\n\nThe sweep line algorithm is susceptible to floating point rounding errors. It is\npossible to construct an example, with nearly horizontal lines, that would\ncause it to fail.\n\nWhile sweep line implementation detects `point-segment` overlap, I didn't implement `point-point`\noverlap. I.e. identical points in the input array that do not overlap any segment\nare not reported.\n\n# Miscellaneous \n\n* The source code for the demo is [available here](https://github.com/anvaka/isect/tree/master/demo/interactive).\n* The sweep line algorithm requires a binary search tree. I'm using [w8r/splay-tree](https://github.com/w8r/splay-tree) for this purpose. Love the library a lot!\nI have also tried AVL tree, but found their performance worse than splay tree.\n* If you need a sweep line with higher precision, consider porting this library to\nuse [decimal.js](https://github.com/MikeMcl/decimal.js-light).\n* I would absolutely love to have faster intersection algorithms implemented in JavaScript.\nIf you know any - please share. In particular this paper [An optimal algorithm for finding segments intersections](http://club.pdmi.ras.ru/moodle/file.php/15/Materials/p211-balaban.pdf) looks very promising!\nTheir runtime is `O(n * log(n) + k)` which should be faster than Bentley-Ottmann.\n\n# License\n\nMIT\n\n# Thanks!\n\nI hope you enjoy the library. Feel free to ping me (anvaka@gmail.com or https://twitter.com/anvaka) if\nyou have any feedback.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanvaka%2Fisect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanvaka%2Fisect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanvaka%2Fisect/lists"}