GithubHelp home page GithubHelp logo

rudythedev / sharpvoronoilib Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sesopenko/voronoilib

19.0 1.0 3.0 2.38 MB

C# implementation of Voronoi diagram/tessellation using Fortune's Algorithm

License: MIT License

C# 100.00%
fortune-algorithm lloyds-algorithm voronoi voronoi-tessellation

sharpvoronoilib's Introduction

build_and_test

SharpVoronoiLib

C# implementation of generating a Voronoi diagram from a set of points in a plane (using Fortune's Algorithm) with edge clipping and border closure. This implementation guarantees O(n×ln(n)) performance.

voronoi example

The key differences from the original VoronoiLib repo

  • Borders can be closed, that is, edges generated along the boundary
  • Edges and points/sites contain additional useful data
  • Multiple critical and annoyingly-rare bugs and edge cases fixes
  • LOTS more unit testing

Known issues:

  • The algorithm uses a lot of allocations, forcing garbage collection
  • There is no visual output/example since the original used MonoGame

Examples

TODO: several pretty pictures here

Use

Quick-start:

List<VoronoiSite> sites = new List<VoronoiSite>
{
    new VoronoiSite(300, 300),
    new VoronoiSite(300, 400),
    new VoronoiSite(400, 300)
};

List<VoronoiEdge> edges = VoronoiPlane.TessellateOnce(
    sites, 
    0, 0, 
    600, 600
);

The tesselation result for the given VoronoiSites contains VoronoiEdges and VoronoiPoints. The returned collection contains the generated edges.

voronoi terms

  • VoronoiEdge.Start and .End are the start and end points of the edge.
  • VoronoiEdge.Right and .Left are the sites the edge encloses. Border edges move clockwise and will only have the .Right site. And if no points are within the region, both will be null.
  • Edge end VoronoiPoints also contain a .BorderLocation specifying if it's on a border and which one.
  • VoronoiEdge.Neighbours (on-demand) are edges directly "connecting" to this edge, basically creating a traversable edge graph.
  • VoronoiEdge.Length (on-demand) is the distance between its end points.
  • VoronoiSite.Cell contains the edges that enclose the site (the order is not guaranteed).
  • VoronoiSite.ClockwiseCell (on-demand) contains these edges sorted clockwise (starting from the bottom-right "corner" end point).
  • VoronoiSite.Neighbors contains the site's neighbors (in the Delaunay Triangulation), that is, other sites across its edges.
  • VoronoiSite.Points (on-demand) contains points of the cell, that is, edge end points / edge nodes.
  • VoronoiSite.ClockwisePoints (on-demand) contains these points sorted clockwise (starting from the bottom-right "corner").

voronoi terms - site voronoi terms - edge

If closing borders around the boundary is not desired (leaving sites with unclosed cells/polygons):

List<VoronoiEdge> edges = VoronoiPlane.TessellateOnce(
    sites, 
    0, 0, 
    600, 600,
    BorderEdgeGeneration.DoNotMakeBorderEdges
);

Full syntax (leaving a reusable VoronoiPlane instance):

VoronoiPlane plane = new VoronoiPlane(0, 0, 600, 600);

plane.SetSites(sites);

List<VoronoiEdge> edges = plane.Tessellate();

Sites can be quickly randomly-generated:

VoronoiPlane plane = new VoronoiPlane(0, 0, 600, 600);

plane.GenerateRandomSites(1000, PointGenerationMethod.Uniform);

plane.Tessellate();

Lloyds relaxation algorithm can be applied to "smooth" cells:

VoronoiPlane plane = new VoronoiPlane(0, 0, 600, 600);

plane.SetSites(sites);

plane.Tessellate();

List<VoronoiEdge> edges = plane.Relax();
// List<VoronoiEdge> edges = plane.Relax(3, 0.7f); // relax 3 times with 70% strength each time 

Dependencies

The main library is compiled for .NET (Core) 6.0 and .NET Standard 2.0 at C# 8.0 and targets compatible OSes - Windows, Linux & macOS - and frameworks like Xamarin, Mono, UWP, or Unity.

Credits

Original implementation inspired by:

sharpvoronoilib's People

Contributors

chrisvm avatar rudythedev avatar rurounijones avatar sesopenko avatar zalgo2462 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

sharpvoronoilib's Issues

Merging Sites

Great to see this fork and all the improvements on it. I think, with all the stuff you have added, that this could be the turn-key solution I am looking for where my lack of brain-power is covered by the library itself 😆

My use-case is to generate a Voronoi Diagram then merge all sites with neighours that share an arbitrary property.

So having said all that; A Nuget package would be great😀

the order of clockwisePoints

hello,
I am the person who emailed you before,the question has been solved and thank you very much.And I find a new bug.

bug detail

I print a site's ClockwisePoints

foreach (var item in sites[i].ClockwisePoints)
{
        float x = (float)item.X;
        float y = (float)item.Y;
        ver.Add(new Vector3(x, 0, y));
        uv.Add(new Vector2(x / Mapwidth, y / Mapheight));
        DebugInfo.PrintStruct("x is",x,"y is",y);
}

QQ截图20230123171250
QQ截图20230123171329
It is anticlockwise.Not clockwise.

why bug happen

In VoronoiSite.cs file,326 line

private static int SortPointsClockwise(VoronoiPoint point1, VoronoiPoint point2, double x, double y)
{
      // originally, based on: https://social.msdn.microsoft.com/Forums/en-US/c4c0ce02-bbd0-46e7-aaa0-df85a3408c61/sorting-list-of-xy-coordinates-clockwise-sort-works-if-list-is-unsorted-but-fails-if-list-is?forum=csharplanguage
      // comparer to sort the array based on the points relative position to the center
      double atan1 = Atan2(point1.Y - y, point1.X - x);
      double atan2 = Atan2(point2.Y - y, point2.X - x);
      
      if (atan1 < atan2) return -1; //there
      if (atan1 > atan2) return 1;
      return 0;
}

QQ截图20230123174159
if atan2>atan1,it is supposed to return 1 to make atan2 in front of atan1 in the list.
I can't pull request.Maybe do you off the function?Thank you for your reply.

Final edge in VoronoiSite.ClockwiseCell is randomly backwards

Approx 50/50 chance of this happening, that when requesting .ClockwiseCell, the Edge instances I get are all correct except the final one, where Start and End are reversed.

Guess: the code for ClockwiseCell has an out-by-1 error and is failing to reverse the final edge, so its a matter of luck whether the edge was already clockwise before the conversion took place.

Incorrect VoronoiSite.Neighbours

Pasting bug report from an e-mail (trimmed and slightly altered to just the immediate problem information).


In some cases,the VoronoiSite.Neighbours value is not correct.

Red sphere represent voronoipoint.

dkfsghjlfdks

Code below prints:
the voronoi site 0 neighbor is [4,3,2]
the voronoi site 1 neighbor is [2,4,3]
the voronoi site 2 neighbor is [4,0,3,1]
the voronoi site 3 neighbor is [0,2,1]
the voronoi site 4 neighbor is [0,2,1]
Obviously,the site 1,3,4 is not correct.

other details:
the coordinate:
the mapzone num 0 coordinate is 309.2762 29.37344
the mapzone num 1 coordinate is 498.7968 410.0901
the mapzone num 2 coordinate is 328.3032 284.3138
the mapzone num 3 coordinate is 25.5397 184.688
the mapzone num 4 coordinate is 373.5264 73.77794
the map width is 500,the map height is 500.

private void generatePlane()
{
    List<VoronoiSite> sites = new List<VoronoiSite>();
    for (int i = 0; i < pointPositions.Count; i++)
    {
        sites.Add(new VoronoiSite(pointPositions[i].x, pointPositions[i].z, pointPositions[i].MapSegmentIndex));
        DebugInfo.PrintStruct("the mapzone num", pointPositions[i].MapSegmentIndex, "coordinate is", pointPositions[i].x, pointPositions[i].z);
    }

    VoronoiPlane.TessellateOnce(sites,0, 0,Mapwidth,Mapheight);
    _mapEntire = new MapEntire(sites,MapWalkZoneNum, pointPositions,Mapwidth,Mapheight);

    for (int i = 0; i < sites.Count; i++)
    {

        var neighbor = new List<int>();
        foreach (var item in sites[i].Neighbours)
        {
            neighbor.Add(item.MapSegmentIndex);
        }

        DebugInfo.PrintStruct<int>("the voronoi site",i,"neighbor is", neighbor);
        //if (_mapEntire.MapZones[sites[i].MapSegmentIndex].IsCanWalk == false)
        //    continue;
        var ver = new List<Vector3>();
        var uv = new List<Vector2>();
        foreach (var item in sites[i].ClockwisePoints)
        {
            float x = (float)item.X;
            float y = (float)item.Y;
            ver.Add(new Vector3(x, 0, y));
            uv.Add(new Vector2(x / Mapwidth, y / Mapheight));
        }
        ver.Reverse();
        uv.Reverse();
        List<int> tri = new List<int>();
        for (int j = 1; j < ver.Count - 1; j++)
        {
            tri.Add(0);
            tri.Add(j);
            tri.Add(j + 1);
        }
        Mesh mesh = new Mesh();
        mesh.vertices = ver.ToArray();
        mesh.triangles = tri.ToArray();
        mesh.uv = uv.ToArray();
        var gameObject = Resources.Load<GameObject>("zone");
        MeshFilter meshfilter = gameObject.GetComponent<MeshFilter>();
        meshfilter.mesh = mesh;
        //material.color= Color.black;
        gameObject.GetComponent<MeshRenderer>().material = material;
        gameObject.GetComponent<MeshCollider>().sharedMesh = mesh;
        var obj=Instantiate(gameObject, Vector3.zero, Quaternion.identity, _mapZone);
        obj.GetComponent<MeshRenderer>().material.color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f));
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.