void GenerateMesh() { Meshes = new Mesh[triangles.Count]; for (int i = 0; i < triangles.Count; ++i) { GameObject triObj = new GameObject(i.ToString(), typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); Utils.SetupMeshRenderer(triObj); triObj.tag = Tags.Debris; triObj.layer = Layers.Debris; triObj.transform.SetParent(mainObj.transform); var mesh = new Mesh(); mesh.name = "mesh_" + i; Vector2[] points = triangles[i]; Vector2 centroid = PolyGraph.GetCentroid(points); Vector2[] vertices = new Vector2[3]; for (int j = 0; j < 3; ++j) { vertices[j] = points[j] - centroid; } mesh.vertices = Array.ConvertAll(vertices, v => (Vector3)v); mesh.triangles = new int[] { 0, 1, 2 }; mesh.colors = new Color[] { colors[i], colors[i], colors[i] }; triObj.GetComponent <MeshFilter>().mesh = mesh; triObj.transform.localPosition = centroid; triObj.GetComponent <MeshCollider>().sharedMesh = mesh; Meshes[i] = mesh; } }
void GenerateMesh() { Texture2D texture = null; if (useVertColor) { string path = string.Format("{0}/{1}/{1}.png", Paths.AssetArtworks, graph.name); texture = AssetDatabase.LoadAssetAtPath <Texture2D>(path); if (null == texture) { throw new Exception("Failed to load texture " + path); } } Meshes = new Mesh[triangles.Count]; for (int i = 0; i < triangles.Count; ++i) { GameObject triObj = new GameObject(i.ToString(), typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); Utils.SetupMeshRenderer(triObj); triObj.tag = Tags.Debris; triObj.layer = Layers.Debris; triObj.transform.SetParent(mainObj.transform); var mesh = new Mesh(); mesh.name = "mesh_" + i; Vector2[] points = triangles[i]; Vector2 centroid = PolyGraph.GetCentroid(points); Vector2[] vertices = new Vector2[3]; for (int j = 0; j < 3; ++j) { vertices[j] = points[j] - centroid; } mesh.vertices = Array.ConvertAll(vertices, v => (Vector3)v); mesh.triangles = new int[] { 0, 1, 2 }; if (useVertColor) { Color fillColor = texture.GetPixelBilinear( centroid.x / graph.size.x, centroid.y / graph.size.y); mesh.colors = new Color[] { fillColor, fillColor, fillColor }; } else { Vector2[] uv = new Vector2[3]; for (int j = 0; j < mesh.vertices.Length; ++j) { uv[j].x = points[j].x / graph.size.x; uv[j].y = points[j].y / graph.size.y; } mesh.uv = uv; } triObj.GetComponent <MeshFilter>().mesh = mesh; triObj.transform.localPosition = centroid; triObj.GetComponent <MeshCollider>().sharedMesh = mesh; Meshes[i] = mesh; } }
static bool Resolve(PolyGraph graph) { int nextIndex = 0; var xforms = new Transform[graph.transform.childCount]; for (int i = 0; i < xforms.Length; ++i) { var xform = graph.transform.GetChild(i); xforms[i] = xform; int index = int.Parse(xform.name); if (index > nextIndex) { nextIndex = index; } } ++nextIndex; bool modified = false; for (int i = 0; i < xforms.Length; ++i) { modified |= ResolveRegion(graph, xforms[i], ref nextIndex); } return(modified); }
void InternalInit(PolyGraph graph, bool[] finished) { Clear(); this.graph = graph; graph.transform.localPosition = new Vector3(0f, 0f, Config.Instance.zorder.debrisStart); var renderer = graph.GetComponentInChildren <MeshRenderer>(); if (null != renderer) { InitMaterial(renderer.sharedMaterial); } for (int i = 0; i < graph.transform.childCount; ++i) { var child = graph.transform.GetChild(i); child.gameObject.layer = Layers.Snapshot; renderer = child.GetComponent <MeshRenderer>(); if (null != renderer) { if (null == finished || i >= finished.Length || !finished[i]) { renderer.sharedMaterial = greyscaleMat; } else { renderer.sharedMaterial = originMat; } } } PuzzleCamera.SetupCamera(ssCamera, graph.size, Config.Instance.camera.sizeExtendScale); InitBackground(null == finished); }
void Clear() { if (null != graph) { Utils.Destroy(graph); graph = null; } if (null != backgroundObject) { var renderer = backgroundObject.GetComponent <MeshRenderer>(); if (Application.isPlaying) { Utils.Destroy(renderer.material); } else { Utils.Destroy(renderer.sharedMaterial); } Utils.Destroy(backgroundObject); backgroundObject = null; } if (null != originMat) { Utils.Destroy(originMat); originMat = null; } if (null != greyscaleMat) { Utils.Destroy(greyscaleMat); greyscaleMat = null; } }
void RecenterGraph(PolyGraph graph) { MeshRenderer[] renderers = graph.GetComponentsInChildren <MeshRenderer>(); var bounds = renderers[0].bounds; for (int i = 1; i < renderers.Length; ++i) { bounds.Encapsulate(renderers[i].bounds); } var newSize = new Vector2Int((int)bounds.size.x, (int)bounds.size.y); if (newSize.x != bounds.size.x || newSize.y != bounds.size.y) { Debug.LogErrorFormat("{0}: bounds.size can't convert to integers, {1}", graph.name); return; } graph.size = newSize; Vector2 centerOffset = bounds.extents - bounds.center; for (int i = 0; i < renderers.Length; ++i) { renderers[i].transform.localPosition += (Vector3)centerOffset; } }
public void GenerateGraph() { while (transform.childCount != 0) { DestroyImmediate(transform.GetChild(0).gameObject); } Random.InitState(seed); PolyGraph polyGraph = new PolyGraph(width, height, faceSize, faceSize, smoothingSteps, new CentriodCorner()); graph = new Graph(polyGraph); for (int index = 0; index < graph.faces.Length; index++) { Face face = graph.faces[index]; Tile tile = (Tile)Object.Instantiate( tilePrefab, face.position, Quaternion.identity); tile.transform.SetParent(transform); tile.Initialize(face, new GroundTile()); face.tile = tile; } GraphNoiseGenerator graphNoiseGenerator = GetComponent <GraphNoiseGenerator>(); if (graphNoiseGenerator != null) { graphNoiseGenerator.GenerateGraphNoise(); } }
public void SetColor(Color color, PolyGraph graph, Region region, bool thisRegionOnly = false) { if (!thisRegionOnly) { var queue = new Queue <Region>(); queue.Enqueue(region); var visited = new HashSet <Region>(); visited.Add(region); for (int i = 0; i < showRegions && queue.Count > 0; ++i) { var r = queue.Dequeue(); InternalSetColor(color, r.borderEdges); for (int index = 0; index < r.adjacents.Count; ++index) { var adj = graph.regions[r.adjacents[index]]; if (!visited.Contains(adj)) { queue.Enqueue(adj); visited.Add(adj); } } } } else { InternalSetColor(color, region.borderEdges); } mesh.colors = colors; }
public static void SaveInitialSnapshot(PolyGraph graph) { string path = string.Format( "{0}/{1}/{2}/{3}", Application.dataPath, Paths.AssetArtworksNoPrefix, graph.name, Paths.SnapshotFile); string saveName = graph.name + '_' + Paths.Snapshot; var go = new GameObject(saveName); var holder = go.AddComponent <PuzzleSnapshotHolder>(); PuzzleSnapshotOneOff.Take(graph, null, path); holder.texture = AssetDatabase.LoadAssetAtPath <Texture2D>(Paths.ToAssetPath(path)); string prefabPath = string.Format( "{0}/{1}/{2}.prefab", Paths.AssetResArtworks, graph.name, saveName); UnityEngine.Object prefab = PrefabUtility.CreatePrefab(prefabPath, go); PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ConnectToPrefab); GameObject.DestroyImmediate(go); }
static void NewRegion( List <int> region, List <Triangle> triangles, PolyGraph graph, Material mat, Vector3[] verts, Color[] colors, Vector2[] uv, int index) { Vector3[] newVerts = new Vector3[region.Count * 3]; Color[] newColors = new Color[region.Count * 3]; for (int i = 0; i < region.Count; ++i) { for (int j = 0; j < 3; ++j) { int k = triangles[region[i]].vertices[j]; newVerts[i * 3 + j] = verts[k]; newColors[i * 3 + j] = colors[k]; } } Vector3 centroid = PolyGraph.GetCentroid(newVerts); int[] newTris = new int[newVerts.Length]; for (int i = 0; i < newVerts.Length; ++i) { newVerts[i] -= centroid; newTris[i] = i; } var mesh = new Mesh(); mesh.name = "mesh_" + index; mesh.vertices = newVerts; mesh.triangles = newTris; mesh.colors = newColors; mesh.uv = uv; MeshUtility.Optimize(mesh); string savePath = string.Format("{0}/{1}/Meshes/{2}.prefab", Paths.AssetArtworks, graph.name, mesh.name); AssetDatabase.CreateAsset(mesh, savePath); AssetDatabase.SaveAssets(); GameObject triObj = new GameObject( index.ToString(), typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); Utils.SetupMeshRenderer(triObj); triObj.tag = Tags.Debris; triObj.layer = Layers.Debris; triObj.transform.SetParent(graph.transform); triObj.transform.localPosition = centroid; triObj.GetComponent <MeshFilter>().mesh = mesh; triObj.GetComponent <MeshRenderer>().sharedMaterial = mat; triObj.GetComponent <MeshCollider>().sharedMesh = mesh; }
public static void Take(PolyGraph puzzleObject, bool[] finished = null, string savePath = null) { var go = new GameObject("PuzzleSnapshot"); var snapshot = go.AddComponent <PuzzleSnapshot>(); snapshot.Init(puzzleObject, finished); snapshot.Take(savePath); }
static void SetBackgroundTexture(PolyGraph graph) { string bgTexPath = string.Format( "{0}/{1}/{1}_background.png", Paths.AssetArtworks, graph.name); graph.background = AssetDatabase.LoadAssetAtPath <Texture2D>(bgTexPath); }
static void ProcessAfterImport(PolyGraph graph) { using (TimeCount.Start("Resolve Regions")) RegionResolver.Resolve(graph); using (TimeCount.Start("Create Wireframe")) WireframeCreator.Create(graph); using (TimeCount.Start("Saving initial snapshot")) Others.SaveInitialSnapshot(graph); }
public static GameObject Create(PolyGraph graph, Bounds bounds, bool circularShape = false, bool grey = false) { var prefab = PrefabLoader.Load(Prefabs.Background); var go = prefab.Instantiate <GameObject>(); bounds = CalculateBounds(bounds); go.transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, Config.Instance.zorder.background); var renderer = go.GetComponent <MeshRenderer>(); Material mat; if (Application.isPlaying) { mat = renderer.material; } else { mat = GameObject.Instantiate(renderer.sharedMaterial); renderer.sharedMaterial = mat; } if (null != graph.background) { float boundsAspect = bounds.size.x / bounds.size.y; float aspect = (float)graph.background.width / graph.background.height; if (aspect >= boundsAspect) { go.transform.localScale = new Vector3(aspect * bounds.size.y, bounds.size.y, 1f); } else { go.transform.localScale = new Vector3(bounds.size.x, bounds.size.x / aspect, 1f); } mat.EnableKeyword(ShaderFeatures._TEXTURE_BG); mat.SetTexture("_MainTex", graph.background); } else { go.transform.localScale = new Vector3(bounds.size.x, bounds.size.y, 1f); if (circularShape) { mat.EnableKeyword(ShaderFeatures._USE_CIRCLE_ALPHA); } mat.SetColor("_Color", BackgroundColor(graph)); mat.SetVector("_Bounds", new Vector4(bounds.extents.x, bounds.extents.y)); } if (grey) { mat.EnableKeyword(ShaderFeatures._GREYSCALE); } return(go); }
static Color BackgroundColor(PolyGraph graph) { ArtCollection.Item item; if (ArtCollection.Instance.itemMap.TryGetValue(graph.name, out item)) { return(Utils.ColorFromString(item.bgColor)); } else { return(AvarageColor(graph)); } }
static bool ConnectedCheck(PolyGraph graph, List <GameObject> gameObjects) { var xforms = gameObjects.ConvertAll(v => v.transform).ToArray(); var resolver = new RegionResolver(graph); resolver.Collect(xforms); resolver.CalculateTriangleAdjacents(); resolver.CalculateRegionAdjacents(); List <int> regionIndexs = Enumerable.Range(0, resolver.regions.Count).ToList(); List <List <string> > connectedRegions = new List <List <string> >(); while (regionIndexs.Count > 0) { List <string> connected = new List <string>(); Queue <int> queue = new Queue <int>(); queue.Enqueue(regionIndexs[0]); while (queue.Count > 0) { int i = queue.Dequeue(); regionIndexs.Remove(i); var region = resolver.regions[i]; connected.Add(region.name); foreach (int adj in region.adjacents) { if (regionIndexs.Contains(adj) && !queue.Contains(adj)) { queue.Enqueue(adj); } } } connectedRegions.Add(connected); } if (connectedRegions.Count > 1) { var log = new StringBuilder("Selected regions are not all connected, connected regions are:\n"); foreach (var names in connectedRegions) { log.AppendFormat("{{ {0} }}\n", string.Join(", ", names)); } Debug.LogError(log); return(false); } else { return(true); } }
public static void Resolve(PolyGraph graph) { Transform[] xforms = new Transform[graph.transform.childCount]; for (int i = 0; i < graph.transform.childCount; ++i) { xforms[i] = graph.transform.GetChild(i); } var resolver = new RegionResolver(graph); resolver.Collect(xforms); resolver.CalculateTriangleAdjacents(); resolver.CalculateRegionAdjacents(); resolver.CalculateRegionBorderEdges(); resolver.Apply(); }
public static GameObject Combine(PolyGraph graph, List <GameObject> gameObjects) { if (!ConnectedCheck(graph, gameObjects)) { return(null); } int index = NextIndex(graph.transform); CombineInstance[] combine = new CombineInstance[gameObjects.Count]; for (int i = 0; i < combine.Length; ++i) { var meshFilter = gameObjects[i].GetComponent <MeshFilter>(); combine[i].mesh = meshFilter.sharedMesh; combine[i].transform = meshFilter.transform.localToWorldMatrix; } var mesh = new Mesh(); mesh.name = "mesh_" + index; mesh.CombineMeshes(combine); Vector3 centroid; mesh.vertices = Centralize(mesh.vertices, out centroid); mesh.RecalculateBounds(); MeshUtility.Optimize(mesh); string savePath = string.Format("{0}/{1}/Meshes/{2}.prefab", Paths.AssetArtworks, graph.name, mesh.name); AssetDatabase.CreateAsset(mesh, savePath); AssetDatabase.SaveAssets(); var go = new GameObject( index.ToString(), typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); Utils.SetupMeshRenderer(go); go.tag = Tags.Debris; go.layer = Layers.Debris; go.transform.parent = graph.transform; go.GetComponent <MeshFilter>().mesh = mesh; go.transform.localPosition = centroid; go.GetComponent <MeshCollider>().sharedMesh = mesh; return(go); }
public static Color AvarageColor(PolyGraph graph) { Vector4 c = Vector4.zero; int count = 0; for (int i = 0; i < graph.transform.childCount; ++i) { var child = graph.transform.GetChild(i); var mesh = child.GetComponent <MeshFilter>().sharedMesh; var material = child.GetComponent <MeshRenderer>().sharedMaterial; int[] tris = mesh.triangles; if (material.IsKeywordEnabled(ShaderFeatures._USE_VERT_COLOR)) { Color[] colors = mesh.colors; for (int j = 0; j < tris.Length; j += 3, ++count) { c += (Vector4)colors[tris[j]]; } } else { Vector3[] verts = mesh.vertices; var texture = (Texture2D)material.mainTexture; for (int j = 0; j < tris.Length; j += 3, ++count) { Vector2[] points = new Vector2[] { child.localPosition + verts[tris[j]], child.localPosition + verts[tris[j + 1]], child.localPosition + verts[tris[j + 2]] }; Vector2 centroid = PolyGraph.GetCentroid(points); c += (Vector4)texture.GetPixelBilinear( centroid.x / graph.size.x, centroid.y / graph.size.y); } } } c /= count; return(c); }
void FindTriangles() { HashSet <long> finishedPoints = new HashSet <long>(); foreach (var kv in adjacents) { long hashCode = kv.Key; var p0 = kv.Value.point; foreach (var p1 in kv.Value.adjacents) { long p1h = PolyGraph.PointHash(p1, size); if (finishedPoints.Contains(p1h)) { continue; } foreach (var p2 in adjacents[p1h].adjacents) { long p2h = PolyGraph.PointHash(p2, size); if (finishedPoints.Contains(p2h) && p2h != hashCode) { continue; } if (-1 != adjacents[p2h].adjacents.FindIndex(v => PolyGraph.PointHash(v, size) == hashCode)) { float cross = Vector3.Cross(p1 - p0, p2 - p0).z; if (cross == 0f) { throw new Exception("Cross Product is zero, we got some degenerated triangles"); } if (cross < 0f) { triangles.Add(new Vector2[] { p0, p1, p2 }); } } } } finishedPoints.Add(hashCode); } }
void AddPoint(Vector2 p0, Vector2 p1) { long p0h = PolyGraph.PointHash(p0, size); long p1h = PolyGraph.PointHash(p1, size); AdjacentPoints ap; if (!adjacents.TryGetValue(p0h, out ap)) { ap = new AdjacentPoints() { point = p0 }; adjacents.Add(p0h, ap); } if (-1 == ap.adjacents.FindIndex(v => PolyGraph.PointHash(v, size) == p1h)) { ap.adjacents.Add(p1); } }
public RegionResolver(PolyGraph graph) { this.graph = graph; }
public void Init(PolyGraph puzzleObject, bool[] finished = null) { puzzleName = puzzleObject.name; InternalInit(Instantiate(puzzleObject, transform), finished); }
void Awake() { graph = GetComponent <PolyGraph>(); sharedMat = GetComponentInChildren <MeshRenderer>().sharedMaterial; }
static bool ResolveRegion(PolyGraph graph, Transform xform, ref int nextIndex) { List <Triangle> triangles = new List <Triangle>(); List <List <int> > regions = new List <List <int> >(); var mesh = xform.GetComponent <MeshFilter>().sharedMesh; int[] tris = mesh.triangles; Color[] colors = mesh.colors; Vector2[] uv = mesh.uv; Vector3[] verts = Array.ConvertAll(mesh.vertices, v => v + xform.localPosition); for (int i = 0; i < tris.Length; i += 3) { var triangle = new Triangle() { vertices = new int[] { tris[i], tris[i + 1], tris[i + 2] }, hashes = new long[] { graph.PointHash(verts[tris[i]]), graph.PointHash(verts[tris[i + 1]]), graph.PointHash(verts[tris[i + 2]]) }, adjacents = new List <int>() }; triangles.Add(triangle); } CalculateTriangleAdjacents(triangles); List <int> triIndex = Enumerable.Range(0, triangles.Count).ToList(); while (triIndex.Count > 0) { List <int> region = new List <int>(); Queue <int> queue = new Queue <int>(); queue.Enqueue(triIndex[0]); while (queue.Count > 0) { int i = queue.Dequeue(); triIndex.Remove(i); region.Add(i); var triangle = triangles[i]; foreach (int adj in triangle.adjacents) { if (triIndex.Contains(adj) && !queue.Contains(adj)) { queue.Enqueue(adj); } } } regions.Add(region); } if (regions.Count > 1) { Debug.LogFormat("<color=yellow>{0}: breaking region {1}</color>", graph.name, xform.name); var mat = xform.GetComponent <MeshRenderer>().sharedMaterial; foreach (var region in regions) { Debug.LogFormat("<color=green>{0}: create new region {1}</color>", graph.name, nextIndex); NewRegion(region, triangles, graph, mat, verts, colors, uv, nextIndex++); } GameObject.DestroyImmediate(xform.gameObject); string meshPath = string.Format("{0}/{1}/Meshes/{2}.prefab", Paths.AssetArtworks, graph.name, mesh.name); AssetDatabase.DeleteAsset(meshPath); return(true); } else { return(false); } }
public static void Create(PolyGraph graph, float?width = null) { float w = width.HasValue ? width.Value : Config.Instance.wireframe.width; if (width <= 0f) { throw new Exception("Width must greater than 0!"); } List <Vector3> verts = new List <Vector3>(); List <int> tris = new List <int>(); List <EdgeIndex> edgeIndex = new List <EdgeIndex>(); foreach (var region in graph.regions) { foreach (var edge in region.borderEdges) { var ei = edgeIndex.Find(v => v.edge.EqualTo(edge)); if (null != ei) { edge.wireframeTriangles = ei.index; continue; } Vector3 v0 = new Vector3(edge.v0.x, edge.v0.y, 0f); Vector3 v1 = new Vector3(edge.v1.x, edge.v1.y, 0f); Vector3 d = Vector3.Cross(Vector3.back, v1 - v0).normalized * 0.5f * w; Vector3 p0 = v0 + d; Vector3 p1 = v0 - d; Vector3 p2 = v1 + d; Vector3 p3 = v1 - d; int start = verts.Count; verts.Add(p0); verts.Add(p1); verts.Add(p2); verts.Add(p3); List <int> index = new List <int>(); if (Vector3.Cross(p2 - p0, p3 - p0).z < 0) { index.Add(start); index.Add(start + 2); index.Add(start + 3); index.Add(start); index.Add(start + 3); index.Add(start + 1); } else { index.Add(start); index.Add(start + 1); index.Add(start + 3); index.Add(start); index.Add(start + 3); index.Add(start + 2); } edge.wireframeTriangles = index; tris.AddRange(index); edgeIndex.Add(new EdgeIndex(edge, index)); } } var wireframeObject = new GameObject( graph.name + '_' + Paths.Wireframe, typeof(MeshFilter), typeof(MeshRenderer), typeof(PuzzleWireframe)); wireframeObject.layer = Layers.Debris; var mesh = new Mesh(); mesh.name = graph.name + '_' + Paths.Wireframe; mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.colors = Enumerable.Repeat(Color.black, verts.Count).ToArray(); MeshUtility.Optimize(mesh); string savePath = string.Format("{0}/{1}/meshes/{2}.prefab", Paths.AssetArtworks, graph.name, mesh.name); AssetDatabase.CreateAsset(mesh, savePath); var meshFilter = wireframeObject.GetComponent <MeshFilter>(); meshFilter.sharedMesh = mesh; var renderer = wireframeObject.GetComponent <MeshRenderer>(); Utils.SetupMeshRenderer(renderer); renderer.sharedMaterial = AssetDatabase.LoadAssetAtPath <Material>(Paths.PolyWireframeMat); string prefabPath = string.Format("{0}/{1}/{2}.prefab", Paths.AssetResArtworks, graph.name, wireframeObject.name); UnityEngine.Object prefab = PrefabUtility.CreatePrefab(prefabPath, wireframeObject); PrefabUtility.ReplacePrefab(wireframeObject, prefab, ReplacePrefabOptions.ConnectToPrefab); GameObject.DestroyImmediate(wireframeObject); }
public VectorGraphImporter(string name) { mainObj = new GameObject(name); graph = mainObj.AddComponent <PolyGraph>(); }
public Graph(PolyGraph polyGraph) { Initialize(polyGraph); }
private void Initialize(PolyGraph polyGraph) { width = polyGraph.width; height = polyGraph.height; faces = polyGraph.faces .Select((kvp, i) => new Face(i, kvp.Value)) .ToArray(); corners = polyGraph.corners .Select((kvp, i) => new Corner(i, kvp.Value)) .ToArray(); edges = polyGraph.edges .Select((kvp, i) => new Edge(i, kvp.Value)) .ToArray(); int index; for (index = 0; index < faces.Length; index++) { Face face = faces[index]; PolyFace polyFace = polyGraph.faces[index]; face.corners = polyFace.surroundingCorners .Select(polyCorner => corners[polyCorner.id]) .OrderBy(corner => face.position.GetAngle(corner.position)) .ToArray(); face.faces = polyFace.neighbouringFaces .Select(otherPolyFace => faces[otherPolyFace.id]) .OrderBy(otherFace => face.position.GetAngle(otherFace.position)) .ToArray(); face.edges = polyFace.surroundingEdges .Select(polyEdge => edges[polyEdge.id]) .OrderBy(edge => face.position.GetAngle(edge.position)) .ToArray(); face.triangles = polyFace.triangles; face.vertices = polyFace.vertices .Select(vertex => vertex.ToVector2()) .ToArray(); face.normals = polyFace.normals .Select((vertex => vertex.ToVector2())) .ToArray(); } for (index = 0; index < corners.Length; index++) { Corner corner = corners[index]; PolyCorner polyCorner = polyGraph.corners[index]; corner.faces = polyCorner.surroundingFaces .Select(polyFace => faces[polyFace.id]) .OrderBy(face => corner.position.GetAngle(face.position)) .ToArray(); corner.edges = polyCorner.surroundingEdges .Select(polyEdge => edges[polyEdge.id]) .OrderBy(edge => corner.position.GetAngle(edge.position)) .ToArray(); } for (index = 0; index < edges.Length; index++) { Edge edge = edges[index]; PolyEdge polyEdge = polyGraph.edges[index]; edge.faces = polyEdge.surroundingFaces .Select(polyFace => faces[polyFace.id]) .OrderBy(face => edge.position.GetAngle(face.position)) .ToArray(); edge.corners = polyEdge.surroundingCorners .Select(polyCorner => corners[polyCorner.id]) .OrderBy(corner => edge.position.GetAngle(corner.position)) .ToArray(); } }