Exemple #1
0
    // Returns neighbor of face_i that has largest area.
    private int FindNeighborOnLongestEdge(int face_ind)
    {
        VoronoiFace face_i = faces[face_ind];

        if (face_i.neighbors.Count == 0)
        {
            return(-1);
        }

        int   current_neighbor_on_longest_edge_ind = -1;
        float current_longest_edge_length          = -1f;

        foreach (HalfEdge he in face_i.half_edges)
        {
            float len = Vector3.Distance(vertices[he.start], vertices[he.end]);
            if (len > current_longest_edge_length && he.twin_id > -1 && halfedges[he.twin_id].face > -1)
            {
                current_neighbor_on_longest_edge_ind = halfedges[he.twin_id].face;
            }
        }

        if (current_neighbor_on_longest_edge_ind > -1)
        {
            return(current_neighbor_on_longest_edge_ind);
        }

        return(-1);
    }
Exemple #2
0
    // Returns neighbor of face_i that has largest area.
    private int FindNeighborWithLargestArea(int face_ind)
    {
        VoronoiFace face_i = faces[face_ind];
        //float area = ComputeFaceArea(i);
        float area = face_i.area;

        if (face_i.neighbors.Count == 0)
        {
            return(-1);
        }

        // Iterate over neighbors, find one with largest area.
        int   current_largest_area_face_index = face_i.neighbors[0];
        float current_largest_area            = (face_i.neighbors[0] != -1) ? faces[face_i.neighbors[0]].area : -1f;

        for (int j = 1; j < face_i.neighbors.Count; ++j)
        {
            int current_face_index = face_i.neighbors[j];
            //float current_face_area = ComputeFaceArea(face_i.neighbors[j]);
            float current_face_area = (face_i.neighbors[j] != -1) ? faces[face_i.neighbors[j]].area : -1f;

            if (((current_face_area > current_largest_area || current_largest_area < 0) && current_face_area > 0))
            {
                current_largest_area_face_index = current_face_index;
            }
        }

        // Merge faces with the neighbor of least area.
        if (current_largest_area_face_index >= 0)
        {
            return(current_largest_area_face_index);
        }

        return(-1);
    }
Exemple #3
0
 // Assigns the VoronoiFace struct to the FaceManager object belonging to the object containing the mesh.
 private void AssignVoronoiFace(VoronoiFace face_struct, FaceManager face_manager)
 {
     face_manager.id            = face_struct.id;
     face_manager.origin_x      = face_struct.origin_x;
     face_manager.origin_y      = face_struct.origin_y;
     face_manager.half_edges    = face_struct.half_edges;
     face_manager.neighbors_ids = face_struct.neighbors;
     face_manager.area          = face_struct.area;
     face_manager.merged        = face_struct.merged;
 }
Exemple #4
0
    private void CreateVoronoiCells()
    {
        // foreach (var point in Points)
        // {
        //     var triangles = Triangulation.Where(t => t.HasVertex(point));
        //     var circumcenters = new List<Vector3>();
        //
        //
        //     foreach (var triangle in triangles)
        //     {
        //         circumcenters.Add(triangle.Circumcenter);
        //     }
        //
        //     SortClockwise(ref circumcenters);
        //     voronoiFaces.Add(new VoronoiFace(circumcenters, new Plane(Vector3.back, Vector3.zero)));
        // }


        foreach (var point in Points)
        {
            var neighbors = Triangulation.Where(t => t.HasVertex(point));


            List <Vector3> neighborVertices = new List <Vector3>();
            foreach (var triangle in neighbors)
            {
                neighborVertices.Add(triangle.V1);
                neighborVertices.Add(triangle.V2);
                neighborVertices.Add(triangle.V3);
            }

            neighborVertices = neighborVertices.Distinct().ToList();
            neighborVertices.Remove(point);

            foreach (var vertex in neighborVertices)
            {
                var dir = (vertex - point).normalized;
                var mid = (vertex + point) / 2;

                Plane p = new Plane(dir, mid);

                List <Vector3> VoronoiVertices = new List <Vector3>();
                foreach (var triangle in neighbors)
                {
                    if (Math.Abs(p.GetDistanceToPoint(triangle.Circumcenter)) < 0.01)
                    {
                        VoronoiVertices.Add(triangle.Circumcenter);
                    }
                }

                var face = new VoronoiFace(VoronoiVertices.ToList(), p);
                voronoiFaces.Add(face);
            }
        }
    }
Exemple #5
0
    // Computes face area by iterating over the composing triangles.
    private float ComputeFaceArea(int face_index)
    {
        if (face_index < 0)
        {
            return(-1);
        }

        VoronoiFace f    = faces[face_index];
        float       area = 0f;

        for (int i = 0; i < f.half_edges.Count; ++i)
        {
            HalfEdge he = f.half_edges[i];
            area += TriangleArea(vertices[he.start], vertices[he.end], new Vector3(f.origin_x, 0, f.origin_y));
        }

        return(area);
    }
Exemple #6
0
    // Finds the center of a face by averaging the vertices.
    private void RecomputeFaceCenter(int face_index)
    {
        VoronoiFace f = faces[face_index];

        // Assuming the face is convex, we can just put the center at the
        // average of the vertices.

        Vector3 new_center = Vector3.zero;

        for (int i = 0; i < f.half_edges.Count; ++i)
        {
            new_center += vertices[f.half_edges[i].start];
        }
        new_center = new_center / f.half_edges.Count;

        faces[face_index].origin_x = new_center.x;
        faces[face_index].origin_y = new_center.z;
    }
    public List <Vector3> ClipPolygon()
    {
        var mesh  = meshToCut.GetComponent <MeshFilter>().mesh;
        var faces = new List <VoronoiFace>();

        for (var index = 0; index < mesh.triangles.Length; index += 3)
        {
            var v1 = meshToCut.transform.TransformPoint(mesh.vertices[mesh.triangles[index]]);
            var v2 = meshToCut.transform.TransformPoint(mesh.vertices[mesh.triangles[index + 1]]);
            var v3 = meshToCut.transform.TransformPoint(mesh.vertices[mesh.triangles[index + 2]]);

            Plane p    = new Plane(v1, v2, v3);
            var   face = new VoronoiFace(new List <Vector3> {
                v1, v2, v3
            }, p);
            foreach (var meshVertex in mesh.vertices)
            {
                var point = meshToCut.transform.TransformPoint(meshVertex);
                var dot   = Vector3.Dot(v1 - point, p.normal);
                if (Math.Abs(dot) < 0.00000001f)
                {
                    face.points.Add(point);
                }
            }

            face.points = face.points.Distinct().ToList();
            faces.Add(face);
        }

        faces = faces.GroupBy(x => x.Plane).Select(g => g.First()).ToList();
        var meshCell = new VoronoiCell(faces);

        var outputList = new List <Vector3>();

        foreach (var cell in voronoiCells)
        {
            foreach (var voronoiFace in cell.Faces)
            {
                var inputList = faces.ToList();
                faces.Clear();

                foreach (var face in inputList)
                {
                    Vector3 intersectionPoint = Vector3.zero;
                    Vector3 intersectionDir   = Vector3.zero;


                    ComputePlanePlaneIntersection(out intersectionPoint, out intersectionDir, voronoiFace.Plane, voronoiFace.points[0],
                                                  face.Plane, face.points[0]);
                    if (intersectionPoint == Vector3.zero && intersectionDir == Vector3.zero)
                    {
                        continue;
                    }

                    var tmpIntersections = new List <Vector3>();

                    foreach (var edge in voronoiFace.GetEdges())
                    {
                        Plane   p            = new Plane(edge.Start, edge.End, new Vector3(10, 10, 10));
                        Vector3 intersection = Vector3.zero;

                        ComputeLinePlaneIntersection(out intersection, intersectionDir, intersectionPoint, p.normal, edge.Start);

                        List <Vector3> isIntersecting = new List <Vector3> {
                            edge.Start, edge.End, intersection
                        };
                        isIntersecting = isIntersecting.OrderBy(x => Vector3.Dot(edge.End - edge.Start, x)).ToList();


                        if (intersection != Vector3.zero && isIntersecting[1] == intersection)
                        {
                            tmpIntersections.Add(intersection);
                        }
                    }

                    if (!tmpIntersections.Any())
                    {
                        continue;
                    }
                    tmpIntersections = tmpIntersections.OrderBy(x => Vector3.Dot(intersectionDir, x)).ToList();
                    var voronoiEdge = new Edge(tmpIntersections.First(), tmpIntersections.Last());

                    tmpIntersections.Clear();
                    foreach (var edge in face.GetEdges())
                    {
                        Plane   p            = new Plane(edge.Start, edge.End, new Vector3(10, 10, 10));
                        Vector3 intersection = Vector3.zero;

                        ComputeLinePlaneIntersection(out intersection, intersectionDir, intersectionPoint, p.normal, edge.Start);

                        List <Vector3> isIntersecting = new List <Vector3> {
                            edge.Start, edge.End, intersection
                        };
                        isIntersecting = isIntersecting.OrderBy(x => Vector3.Dot(edge.End - edge.Start, x)).ToList();


                        if (intersection != Vector3.zero && isIntersecting[1] == intersection)
                        {
                            //tmpIntersections.Add((intersection, 'f'));
                            tmpIntersections.Add(intersection);
                        }
                    }

                    if (!tmpIntersections.Any())
                    {
                        continue;
                    }
                    tmpIntersections = tmpIntersections.OrderBy(x => Vector3.Dot(intersectionDir, x)).ToList();
                    var meshEdge = new Edge(tmpIntersections.First(), tmpIntersections.Last());

                    Vector3 min1 = new Vector3(Mathf.Min(voronoiEdge.Start.x, voronoiEdge.End.x),
                                               Mathf.Min(voronoiEdge.Start.y, voronoiEdge.End.y), Mathf.Min(voronoiEdge.Start.z, voronoiEdge.End.z));

                    Vector3 max1 = new Vector3(Mathf.Max(voronoiEdge.Start.x, voronoiEdge.End.x),
                                               Mathf.Max(voronoiEdge.Start.y, voronoiEdge.End.y), Mathf.Max(voronoiEdge.Start.z, voronoiEdge.End.z));

                    Vector3 min2 = new Vector3(Mathf.Min(meshEdge.Start.x, meshEdge.End.x),
                                               Mathf.Min(meshEdge.Start.y, meshEdge.End.y), Mathf.Min(meshEdge.Start.z, meshEdge.End.z));

                    Vector3 max2 = new Vector3(Mathf.Max(meshEdge.Start.x, meshEdge.End.x),
                                               Mathf.Max(meshEdge.Start.y, meshEdge.End.y), Mathf.Max(meshEdge.Start.z, meshEdge.End.z));


                    Vector3 minIntersection = new Vector3(Math.Max(min1.x, min2.x), Math.Max(min1.y, min2.y), Math.Max(min1.z, min2.z));
                    Vector3 maxIntersection = new Vector3(Math.Min(max1.x, max2.x), Math.Min(max1.y, max2.y), Math.Min(min1.z, min2.z));

                    outputList.Add(minIntersection);
                    outputList.Add(maxIntersection);

                    // face.SortEdges();
                    // var outputFace = face.points.ToList();
                    // face.points.Clear();
                    // for (int i = 0; i < face.points.Count; i++)
                    // {
                    //     Vector3 currentPoint = face.points[i];
                    //     var index = i - 1;
                    //     if (index < 0) index = face.points.Count - 1;
                    //     Vector3 prevPoint = face.points[index];
                    //
                    //
                    //     Vector3 intersection = Vector3.zero;
                    //     var success = ComputeLinePlaneIntersection(out intersection, currentPoint - prevPoint, prevPoint,
                    //         voronoiFace.Plane.normal, voronoiFace.points[0]);
                    //
                    //     var prevInside = !voronoiFace.Plane.GetSide(prevPoint);
                    //     var currentInside = !voronoiFace.Plane.GetSide(currentPoint);
                    //
                    //     if (currentInside)
                    //     {
                    //         if (!prevInside)
                    //         {
                    //             outputFace.Add(intersection);
                    //         }
                    //
                    //         outputFace.Add(currentPoint);
                    //     }
                    //     else if (prevInside)
                    //     {
                    //         outputFace.Add(intersection);
                    //         outputFace.Add(prevPoint);
                    //     }
                    // }
                }
            }

            //outputList.Add(new VoronoiCell(faces));
        }

        return(outputList);
    }
Exemple #8
0
    // Iterate over faces. Identify small ones. Merge with neighbors.
    private void MergeSmallFaces()
    {
        bool merged_faces = false;
        int  iterations   = 0;

        do
        {
            merged_faces = false;
            print("Face merge iteration " + iterations.ToString());
            ++iterations;

            for (int i = 0; i < faces.Length; ++i)
            {
                //print(i);

                VoronoiFace face_i = faces[i];
                if (face_i.merged)
                {
                    //print("FACE ALREADY MERGED.");
                    continue;
                }

                //float area = ComputeFaceArea(i);
                float area = face_i.area;

                if (area < MIN_FACE_AREA)
                {
                    // FIX THIS.
                    if (face_i.neighbors.Count == 0)
                    {
                        //print("NO NEIGHBORS, PROCEEDING.");
                        continue;
                    }

                    int neighbor_to_merge_with = -1;

                    switch (defaultFaceMergingRule)
                    {
                    case FaceMergingRule.SMALLEST_AREA_NEIGHBOR:
                        neighbor_to_merge_with = FindNeighborWithSmallestArea(i);
                        break;

                    case FaceMergingRule.LARGEST_AREA_NEIGHBOR:
                        neighbor_to_merge_with = FindNeighborWithLargestArea(i);
                        break;

                    case FaceMergingRule.LARGEST_EDGE_NEIGHBOR:
                        neighbor_to_merge_with = FindNeighborOnLongestEdge(i);
                        break;
                    }

                    // Merge faces with the neighbor of least area.
                    if (neighbor_to_merge_with >= 0)
                    {
                        print("Merging " + i + ", " + neighbor_to_merge_with);
                        MergeFaces(i, neighbor_to_merge_with);
                        merged_faces = true;
                    }
                }
            }
        } while (merged_faces && iterations < MAX_MERGING_ITERATIONS);

        print("COMPLETED MERGING FACES.");
    }
Exemple #9
0
    // Generates meshes from vertices and edges.
    private void GenerateMesh()
    {
        for (int i = 0; i < faces.Length; ++i)
        {
            // Skip if face area is 0..
            faces[i].area = ComputeFaceArea(i);
            //float area = ComputeFaceArea(i);

            VoronoiFace current_face = faces[i];
            List <int>  triangles    = new List <int>();

            Vector3        faceCenter   = new Vector3(current_face.origin_x, 0, current_face.origin_y);
            List <Vector3> faceVertices = new List <Vector3>();
            List <Vector3> normals      = new List <Vector3>();
            List <Vector2> uvs          = new List <Vector2>();

            foreach (HalfEdge he in current_face.half_edges)
            {
                Vector3 v0 = faceCenter;
                Vector3 v1 = vertices[he.start];
                Vector3 v2 = vertices[he.end];

                triangles.Add(faceVertices.Count);
                triangles.Add(faceVertices.Count + 1);
                triangles.Add(faceVertices.Count + 2);

                faceVertices.Add(v2);
                faceVertices.Add(v1);
                faceVertices.Add(v0);

                Vector3 normal = Vector3.Cross(v2 - v0, v1 - v0);
                normals.Add(normal);
                normals.Add(normal);
                normals.Add(normal);

                uvs.Add(new Vector2(0.0f, 0.0f));
                uvs.Add(new Vector2(0.0f, 0.0f));
                uvs.Add(new Vector2(0.0f, 0.0f));
            }

            Mesh chunkMesh = new Mesh();
            chunkMesh.vertices  = faceVertices.ToArray();
            chunkMesh.uv        = uvs.ToArray();
            chunkMesh.triangles = triangles.ToArray();
            chunkMesh.normals   = normals.ToArray();

            Transform chunk = Instantiate <Transform>(chunkPrefab, transform.position, transform.rotation);
            chunk.GetComponent <MeshFilter>().mesh = chunkMesh;

            if (faces[i].area >= EPSILON)
            {
                chunk.GetComponent <MeshCollider>().sharedMesh = chunkMesh;
            }

            chunk.rotation         = new Quaternion(0.707f, 0, 0, -0.707f);
            chunk.transform.parent = transform;
            chunk.gameObject.AddComponent <MapClickDetector>();
            chunk.gameObject.GetComponent <MeshRenderer>().material.color = Color.red;

            faces[i].mesh  = chunkMesh;
            faces[i].chunk = chunk;
            AssignVoronoiFace(faces[i], chunk.GetComponent <FaceManager>());
        }

        print("SUCCESSFULLY GENERATED MESH!");
    }