{"id":21570557,"url":"https://github.com/jcash/voronoi","last_synced_at":"2025-05-15T10:02:13.037Z","repository":{"id":29529903,"uuid":"33068518","full_name":"JCash/voronoi","owner":"JCash","description":"A C implementation for creating 2D voronoi diagrams","archived":false,"fork":false,"pushed_at":"2024-12-08T12:02:39.000Z","size":3219,"stargazers_count":673,"open_issues_count":20,"forks_count":96,"subscribers_count":21,"default_branch":"dev","last_synced_at":"2025-04-14T16:53:52.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","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/JCash.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":"2015-03-29T10:06:08.000Z","updated_at":"2025-04-11T17:12:29.000Z","dependencies_parsed_at":"2025-01-12T07:00:43.002Z","dependency_job_id":"03699603-510e-4eb8-85d5-761fd6cd3626","html_url":"https://github.com/JCash/voronoi","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JCash%2Fvoronoi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JCash%2Fvoronoi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JCash%2Fvoronoi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JCash%2Fvoronoi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JCash","download_url":"https://codeload.github.com/JCash/voronoi/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319716,"owners_count":22051072,"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":[],"created_at":"2024-11-24T11:13:07.369Z","updated_at":"2025-05-15T10:02:12.294Z","avatar_url":"https://github.com/JCash.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n|Branch      | macOS/Linux/Windows |\n|------------|---------------------|\n|master      | [![Build](https://github.com/JCash/voronoi/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/JCash/voronoi/actions/workflows/build.yml) |\n|dev         | [![Build](https://github.com/JCash/voronoi/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/JCash/voronoi/actions/workflows/build.yml) |\n\n\n# jc_voronoi\nA fast C/C++ header only implementation for creating 2D Voronoi diagrams from a point set\n\nUses [Fortune's sweep algorithm.](https://en.wikipedia.org/wiki/Fortune%27s_algorithm)\n\n\u003cimg src=\"images/example1.png\" alt=\"vanilla\" width=\"350\"\u003e \u003cimg src=\"images/example2.png\" alt=\"custom clipping\" width=\"350\"\u003e\n\n# Brief\n\nI was realizing that the previous 2D voronoi generator I was using, was taking up too much time in my app,\nand worse, sometimes it also produced errors.\n\nSo I started looking for other implementations.\n\nGiven the alternatives out there, they usually lack one aspect or the other.\nSo this project set out to achieve a combination of the good things the other libs provide.\n\n* Easy to use\n* Robustness\n* Speed\n* Small memory footprint\n* Single/Double floating point implementation\n* Readable code\n* Small code (single source file)\n* No external dependencies\n* Cells have a list of edges (for easier/faster relaxation)\n* Edges should be clipped\n* A clear license\n\nBut mostly, I did it for fun :)\n\n# Disclaimer\n\nThis software is supplied \"AS IS\" without any warranties and support\n\n# License\n\n[LICENSE](./LICENSE) ([The MIT license](http://choosealicense.com/licenses/mit/))\n\n# Feature comparisons\n\n| Feature vs Impl        | voronoi++ | boost | fastjet | jcv |\n|-----------------------:|-----------|-------|---------|-----|\n| Language               |    C++    |  C++  |    C    |  C  |\n| Edge clip              |     *     |       |    *    |  *  |\n| Generate Edges         |     *     |   *   |    *    |  *  |\n| Generate Cells         |     *     |   *   |         |  *  |\n| Cell Edges Not Flipped |           |   *   |         |  *  |\n| Cell Edges CCW         |           |   *   |         |  *  |\n| Easy Relaxation        |           |       |         |  *  |\n| Custom Allocator       |           |       |         |  *  |\n| Delauney generation    |           |       |         |  *  |\n\n# Usage\n\nThe main api contains these functions\n\n```C\nvoid jcv_diagram_generate( int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, jcv_diagram* diagram );\nvoid jcv_diagram_generate_useralloc( int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, void* userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn, jcv_diagram* diagram );\nvoid jcv_diagram_free( jcv_diagram* diagram );\n\nconst jcv_site* jcv_diagram_get_sites( const jcv_diagram* diagram );\nconst jcv_edge* jcv_diagram_get_edges( const jcv_diagram* diagram );\nconst jcv_edge* jcv_diagram_get_next_edge( const jcv_edge* edge );\n```\n\nThe input points are pruned if\n\n* There are duplicates points\n* The input points are outside of the bounding box\n* The input points are rejected by the clipper's test function\n\nThe input bounding box is optional\n\nThe input clipper is optional, a default box clipper is used by default\n\n## Delauney triangulation\n\nAfter generating the Voronoi diagram, you can iterate over the Delauney edges like so:\n(See [main.c](./src/main.c) for a practical example)\n\n```C\njcv_delauney_iter iter;\njcv_delauney_begin( \u0026diagram, \u0026iter );\njcv_delauney_edge delauney_edge;\nwhile (jcv_delauney_next( \u0026iter, \u0026delauney_edge ))\n{\n    ...\n}\n```\n\n## Example\nExample implementation (see [main.c](./src/main.c) for actual code)\n```C\n\n#define JC_VORONOI_IMPLEMENTATION\n#include \"jc_voronoi.h\"\n\nvoid draw_edges(const jcv_diagram* diagram);\nvoid draw_cells(const jcv_diagram* diagram);\nvoid draw_delauney(const jcv_diagram* diagram);\n\nvoid generate_and_draw(int numpoints, const jcv_point* points, int imagewidth, int imageheight)\n{\n    jcv_diagram diagram;\n    memset(\u0026diagram, 0, sizeof(jcv_diagram));\n    jcv_diagram_generate(count, points, 0, 0, \u0026diagram );\n\n    draw_edges(\u0026diagram);\n    draw_cells(\u0026diagram);\n    draw_delauney(\u0026diagram);\n\n    jcv_diagram_free( \u0026diagram );\n}\n\nvoid draw_edges(const jcv_diagram* diagram)\n{\n    // If all you need are the edges\n    const jcv_edge* edge = jcv_diagram_get_edges( diagram );\n    while( edge )\n    {\n        draw_line(edge-\u003epos[0], edge-\u003epos[1]);\n        edge = jcv_diagram_get_next_edge(edge);\n    }\n}\n\nvoid draw_cells(const jcv_diagram* diagram)\n{\n    // If you want to draw triangles, or relax the diagram,\n    // you can iterate over the sites and get all edges easily\n    const jcv_site* sites = jcv_diagram_get_sites( diagram );\n    for( int i = 0; i \u003c diagram-\u003enumsites; ++i )\n    {\n        const jcv_site* site = \u0026sites[i];\n\n        const jcv_graphedge* e = site-\u003eedges;\n        while( e )\n        {\n            draw_triangle( site-\u003ep, e-\u003epos[0], e-\u003epos[1]);\n            e = e-\u003enext;\n        }\n    }\n}\n\nvoid draw_delauney(const jcv_diagram* diagram)\n{\n    jcv_delauney_iter delauney = jcv_delauney_begin( \u0026diagram );\n    jcv_delauney_edge delauney_edge;\n    while (jcv_delauney_next( \u0026delauney, \u0026delauney_edge ))\n    {\n        draw_line(delauney_edge.pos[0], delauney_edge.pos[1]);\n    }\n}\n```\n\n## Relaxing the points\n\nHere is an example of how to do the relaxations of the cells.\n\n```C\nvoid relax_points(const jcv_diagram* diagram, jcv_point* points)\n{\n    const jcv_site* sites = jcv_diagram_get_sites(diagram);\n    for( int i = 0; i \u003c diagram-\u003enumsites; ++i )\n    {\n        const jcv_site* site = \u0026sites[i];\n        jcv_point sum = site-\u003ep;\n        int count = 1;\n\n        const jcv_graphedge* edge = site-\u003eedges;\n\n        while( edge )\n        {\n            sum.x += edge-\u003epos[0].x;\n            sum.y += edge-\u003epos[0].y;\n            ++count;\n            edge = edge-\u003enext;\n        }\n\n        points[site-\u003eindex].x = sum.x / count;\n        points[site-\u003eindex].y = sum.y / count;\n    }\n}\n```\n\n\n## Double floating point precision\n\nIf you wish to use doubles, you can override these defines:\n\n```C\n#define JC_VORONOI_IMPLEMENTATION\n#define JCV_REAL_TYPE double\n#define JCV_ATAN2 atan2\n#define JCV_SQRT sqrt\n#define JCV_FLT_MAX DBL_MAX\n#define JCV_PI 3.141592653589793115997963468544185161590576171875\n//define JCV_EDGE_INTERSECT_THRESHOLD 1.0e-10F\n#include \"jc_voronoi.h\"\n```\n\n## Custom clipping\n\nThe library also comes with a second header, that contains code for custom clipping of edges against a convex polygon.\n\nThe polygon is defined by a set of\n\nAgain, see [main.c](./src/main.c) for a practical example\n\n```C\n\n    #define JC_VORONOI_CLIP_IMPLEMENTATION\n    #include \"jc_voronoi_clip.h\"\n\n    jcv_clipping_polygon polygon;\n    // Triangle\n    polygon.num_points = 3;\n    polygon.points = (jcv_point*)malloc(sizeof(jcv_point)*(size_t)polygon.num_points);\n\n    polygon.points[0].x = width/2;\n    polygon.points[1].x = width - width/5;\n    polygon.points[2].x = width/5;\n    polygon.points[0].y = height/5;\n    polygon.points[1].y = height - height/5;\n    polygon.points[2].y = height - height/5;\n\n    jcv_clipper polygonclipper;\n    polygonclipper.test_fn = jcv_clip_polygon_test_point;\n    polygonclipper.clip_fn = jcv_clip_polygon_clip_edge;\n    polygonclipper.fill_fn = jcv_clip_polygon_fill_gaps;\n    polygonclipper.ctx = \u0026polygon;\n\n    jcv_diagram diagram;\n    memset(\u0026diagram, 0, sizeof(jcv_diagram));\n    jcv_diagram_generate(count, (const jcv_point*)points, 0, clipper, \u0026diagram);\n```\n\n# Some Numbers\n\n*Tests run on a Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz MBP with 16 GB 2133 MHz LPDDR3 ram. Each test ran 20 times, and the minimum time is presented below*\n\n*I removed the voronoi++ from the results, since it was consistently 10x-15x slower than the rest and consumed way more memory*\n_\n\u003cbr/\u003e\n\u003cimg src=\"test/images/timings_voronoi.png\" alt=\"timings\" width=\"350\"\u003e\n\u003cimg src=\"test/images/memory_voronoi.png\" alt=\"memory\" width=\"350\"\u003e\n\u003cimg src=\"test/images/num_allocations_voronoi.png\" alt=\"num_allocations\" width=\"350\"\u003e\n\n[Same stats, as tables](./test/report.md)\n\n\n# General thoughts\n\n## Fastjet\n\nThe Fastjet version is built upon Steven Fortune's original C version, which Shane O'Sullivan improved upon.\nGiven the robustness and speed improvements of the implementation done by Fastjet,\nthat should be the base line to compare other implementations with.\n\nUnfortunately, the code is not very readable, and the license is unclear (GPL?)\n\nAlso, if you want access to the actual cells, you have to recreate that yourself using the edges.\n\n\n## Boost\n\nUsing boost might be convenient for some, but the sheer amount of code is too great in many cases.\nI had to install 5 modules of boost to compile (config, core, mpl, preprocessor and polygon).\nIf you install full boost, that's 650mb of source.\n\nIt is ~2x as slow as the fastest algorithms, and takes ~2.5x as much memory.\n\nThe boost implementation also puts the burden of clipping the final edges on the client.\n\nThe code consists of only templated headers, and it increases compile time a *lot*.\nFor simply generating a 2D voronoi diagram using points as input, it is clearly overkill.\n\n\n## Voronoi++\n\nThe performance of it is very slow (~20x slower than fastjet) and\nAnd it uses ~2.5x-3x more memory than the fastest algorithms.\n\nUsing the same data sets as the other algorithms, it breaks under some conditions.\n\n\n## O'Sullivan\n\nA C++ version of the original C version from Steven Fortune.\n\nAlthough fast, it's not completely robust and will produce errors.\n\n\n\n# Gallery\n\nI'd love to see what you're using this software for!\nIf possible, please send me images and some brief explanation of your usage of this library!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjcash%2Fvoronoi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjcash%2Fvoronoi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjcash%2Fvoronoi/lists"}