using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Metamesh { public class PrimaryIsoTriangle { public int m; public int n; public List cartesian = new List(); public List vertices = new List(); public List max = new List(); public List min = new List(); public Dictionary vecToidx = new Dictionary(); public Dictionary> vertByDist = new Dictionary>(); public List> closestTo = new List>(); public List> innerFacets = new List>(); public List> isoVecsABOB = new List>(); public List> isoVecsOBOA = new List>(); public List> isoVecsBAOA = new List>(); public List> vertexTypes = new List>(); public float coau; public float cobu; public float coav; public float cobv; //float PHI = (1 + Mathf.Sqrt(5f)) / 2; const float PHI = 1.618034f; public PolyhedronData IDATA = new PolyhedronData( "icosahedron", "Regular", new List { new Vector3(0, PHI, -1), new Vector3(-PHI, 1, 0), new Vector3(-1, 0, -PHI), new Vector3(1, 0, -PHI), new Vector3(PHI, 1, 0), new Vector3(0, PHI, 1), new Vector3(-1, 0, PHI), new Vector3(-PHI, -1, 0), new Vector3(0, -PHI, -1), new Vector3(PHI, -1, 0), new Vector3(1, 0, PHI), new Vector3(0, -PHI, 1), }, new List> { new List {0, 2, 1}, new List {0, 3, 2}, new List {0, 4, 3}, new List {0, 5, 4}, new List {0, 1, 5}, new List {7, 6, 1}, new List {8, 7, 2}, new List {9, 8, 3}, new List {10, 9, 4}, new List {6, 10, 5}, new List {2, 7, 1}, new List {3, 8, 2}, new List {4, 9, 3}, new List {5, 10, 4}, new List {1, 6, 5}, new List {11, 6, 7}, new List {11, 7, 8}, new List {11, 8, 9}, new List {11, 9, 10}, new List {11, 10, 6}, } ); private int HighestCommonFactor(int a, int b) { var r = a % b; if (r == 0) { return b; } return HighestCommonFactor(b, r); } public void SetIndices() { var indexCount = 12; // 12 vertices already assigned var vecToidx = new Dictionary(); var m = this.m; var n = this.n; var g = m; // hcf of m, n when n != 0 var m1 = 1; var n1 = 0; if (n != 0) { g = HighestCommonFactor(m, n); } m1 = m / g; n1 = n / g; int fr; //face to the right of current face string rot; //rotation about which vertex for fr int O; int A; int B; var oVec = IsoVector.Zero(); var aVec = new IsoVector(m, n); var bVec = new IsoVector(-n, m + n); var oaVec = IsoVector.Zero(); var abVec = IsoVector.Zero(); var obVec = IsoVector.Zero(); var verts = new List(); string idx; string idxR; string isoId; string isoIdR; var closestTo = new List>(); var vDist = this.vertByDist; System.Action matchIdx = (f, fr, isoId, isoIdR) => { idx = f + "|" + isoId; idxR = fr + "|" + isoIdR; if (!(vecToidx.ContainsKey(idx) || vecToidx.ContainsKey(idxR))) { vecToidx[idx] = indexCount; vecToidx[idxR] = indexCount; indexCount++; } else if (vecToidx.ContainsKey(idx) && !(vecToidx.ContainsKey(idxR))) { vecToidx[idxR] = vecToidx[idx]; } else if (vecToidx.ContainsKey(idxR) && !(vecToidx.ContainsKey(idx))) { vecToidx[idx] = vecToidx[idxR]; } if (vDist[isoId][0] > 2) { closestTo[vecToidx[idx]] = new List { -vDist[isoId][0], vDist[isoId][1], vecToidx[idx] }; } else { closestTo[vecToidx[idx]] = new List { verts[vDist[isoId][0]], vDist[isoId][1], vecToidx[idx] }; } }; this.IDATA.edgematch = new List<(int, string, int, string)> { (1, "B", 0, ""), (2, "B", 0, ""), (3, "B", 0, ""), (4, "B", 0, ""), (0, "B", 0, ""), (10, "O", 14, "A"), (11, "O", 10, "A"), (12, "O", 11, "A"), (13, "O", 12, "A"), (14, "O", 13, "A"), (0, "O", 0, ""), (1, "O", 0, ""), (2, "O", 0, ""), (3, "O", 0, ""), (4, "O", 0, ""), (19, "B", 5, "A"), (15, "B", 6, "A"), (16, "B", 7, "A"), (17, "B", 8, "A"), (18, "B", 9, "A"), }; /***edges AB to OB***** rotation about B*/ for (var f = 0; f < 20; f++) { //f current face verts = this.IDATA.face[f]; O = verts[2]; A = verts[1]; B = verts[0]; isoId = oVec.x + "|" + oVec.y; idx = f + "|" + isoId; if (!vecToidx.ContainsKey(idx)) { vecToidx[idx] = O; closestTo[O] = new List { verts[vDist[isoId][0]], vDist[isoId][1] }; } isoId = aVec.x + "|" + aVec.y; idx = f + "|" + isoId; if (!vecToidx.ContainsKey(idx)) { vecToidx[idx] = A; closestTo[A] = new List { verts[vDist[isoId][0]], vDist[isoId][1] }; } isoId = bVec.x + "|" + bVec.y; idx = f + "|" + isoId; if (!vecToidx.ContainsKey(idx)) { vecToidx[idx] = B; closestTo[B] = new List { verts[vDist[isoId][0]], vDist[isoId][1] }; } //for edge vertices fr = this.IDATA.edgematch[f].Item1; rot = this.IDATA.edgematch[f].Item2; if (rot == "B") { for (var i = 1; i < g; i++) { abVec.x = m - i * (m1 + n1); abVec.y = n + i * m1; obVec.x = -i * n1; obVec.y = i * (m1 + n1); isoId = abVec.x + "|" + abVec.y; isoIdR = obVec.x + "|" + obVec.y; matchIdx(f, fr, isoId, isoIdR); } } if (rot == "O") { for (var i = 1; i < g; i++) { obVec.x = -i * n1; obVec.y = i * (m1 + n1); oaVec.x = i * m1; oaVec.y = i * n1; isoId = obVec.x + "|" + obVec.y; isoIdR = oaVec.x + "|" + oaVec.y; matchIdx(f, fr, isoId, isoIdR); } } fr = this.IDATA.edgematch[f].Item3; rot = this.IDATA.edgematch[f].Item4; if (rot == "A") { for (var i = 1; i < g; i++) { oaVec.x = i * m1; oaVec.y = i * n1; abVec.x = m - (g - i) * (m1 + n1); //reversed for BA abVec.y = n + (g - i) * m1; //reversed for BA isoId = oaVec.x + "|" + oaVec.y; isoIdR = abVec.x + "|" + abVec.y; matchIdx(f, fr, isoId, isoIdR); } } for (var i = 0; i < this.vertices.Count; i++) { isoId = this.vertices[i].x + "|" + this.vertices[i].y; idx = f + "|" + isoId; if (!vecToidx.ContainsKey(idx)) { vecToidx[idx] = indexCount++; if (vDist[isoId][0] > 2) { closestTo[vecToidx[idx]] = new List { -vDist[isoId][0], vDist[isoId][1], vecToidx[idx] }; } else { closestTo[vecToidx[idx]] = new List { verts[vDist[isoId][0]], vDist[isoId][1], vecToidx[idx] }; } } } } this.closestTo = closestTo; this.vecToidx = vecToidx; } public void CalcCoeffs() { var m = this.m; var n = this.n; var thirdR3 = Mathf.Sqrt(3) / 3; var LSQD = m * m + n * n + m * n; this.coau = (m + n) / LSQD; this.cobu = -n / LSQD; this.coav = (-thirdR3 * (m - n)) / LSQD; this.cobv = (thirdR3 * (2 * m + n)) / LSQD; } public void CreateInnerFacets() { var m = this.m; var n = this.n; for (var y = 0; y < n + m + 1; y++) { for (var x = this.min[y]; x < this.max[y] + 1; x++) { if (x < this.max[y] && x < this.max[y + 1] + 1) { this.innerFacets.Add(new List { "|" + x + "|" + y, "|" + x + "|" + (y + 1), "|" + (x + 1) + "|" + y }); } if (y > 0 && x < this.max[y - 1] && x + 1 < this.max[y] + 1) { this.innerFacets.Add(new List { "|" + x + "|" + y, "|" + (x + 1) + "|" + y, "|" + (x + 1) + "|" + (y - 1) }); } } } } public void EdgeVecsABOB() { var m = this.m; var n = this.n; var B = new IsoVector(-n, m + n); for (var y = 1; y < m + n; y++) { var point = new IsoVector(this.min[y], y); var prev = new IsoVector(this.min[y - 1], y - 1); var next = new IsoVector(this.min[y + 1], y + 1); var pointR = point.Clone(); var prevR = prev.Clone(); var nextR = next.Clone(); pointR.Rotate60About(B); prevR.Rotate60About(B); nextR.Rotate60About(B); var maxPoint = new IsoVector(this.max[pointR.y], pointR.y); var maxPrev = new IsoVector(this.max[pointR.y - 1], pointR.y - 1); var maxLeftPrev = new IsoVector(this.max[pointR.y - 1] - 1, pointR.y - 1); if (pointR.x != maxPoint.x || pointR.y != maxPoint.y) { if (pointR.x != maxPrev.x) { // type2 //up this.vertexTypes.Add(new List { 1, 0, 0 }); this.isoVecsABOB.Add(new List { point, maxPrev, maxLeftPrev }); //down this.vertexTypes.Add(new List { 1, 0, 0 }); this.isoVecsABOB.Add(new List { point, maxLeftPrev, maxPoint }); } else if (pointR.y == nextR.y) { // type1 //up this.vertexTypes.Add(new List { 1, 1, 0 }); this.isoVecsABOB.Add(new List { point, prev, maxPrev }); //down this.vertexTypes.Add(new List { 1, 0, 1 }); this.isoVecsABOB.Add(new List { point, maxPrev, next }); } else { // type 0 //up this.vertexTypes.Add(new List { 1, 1, 0 }); this.isoVecsABOB.Add(new List { point, prev, maxPrev }); //down this.vertexTypes.Add(new List { 1, 0, 0 }); this.isoVecsABOB.Add(new List { point, maxPrev, maxPoint }); } } } } public void MapABOBtoOBOA() { var point = new IsoVector(0, 0); for (var i = 0; i < this.isoVecsABOB.Count; i++) { var temp = new List(); for (var j = 0; j < 3; j++) { point.x = this.isoVecsABOB[i][j].x; point.y = this.isoVecsABOB[i][j].y; if (this.vertexTypes[i][j] == 0) { point.RotateNeg120(this.m, this.n); } temp.Add(point.Clone()); } this.isoVecsOBOA.Add(temp); } } public void MapABOBtoBAOA() { var point = new IsoVector(0, 0); for (var i = 0; i < this.isoVecsABOB.Count; i++) { var temp = new List(); for (var j = 0; j < 3; j++) { point.x = this.isoVecsABOB[i][j].x; point.y = this.isoVecsABOB[i][j].y; if (this.vertexTypes[i][j] == 1) { point.Rotate120(this.m, this.n); } temp.Add(point.Clone()); } this.isoVecsBAOA.Add(temp); } } public void MapToFace(int faceNb, PolyhedronData geodesicData) { var F = this.IDATA.face[faceNb]; var oidx = F[2]; var aidx = F[1]; var bidx = F[0]; var oidxVec = this.IDATA.vertex[oidx]; var aidxVec = this.IDATA.vertex[aidx]; var bidxVec = this.IDATA.vertex[bidx]; var O = new Vector3(oidxVec[0], oidxVec[1], oidxVec[2]); var A = new Vector3(aidxVec[0], aidxVec[1], aidxVec[2]); var B = new Vector3(bidxVec[0], bidxVec[1], bidxVec[2]); var OA = A - O; var OB = B - O; var x = OA * this.coau + OB * this.cobu; var y = OA * this.coav + OB * this.cobv; var mapped = new List>(); string idx; for (var i = 0; i < this.cartesian.Count; i++) { var tempVec = x * this.cartesian[i].x + y * this.cartesian[i].y + O; mapped[i] = new List { tempVec.x, tempVec.y, tempVec.z }; idx = faceNb + "|" + this.vertices[i].x + "|" + this.vertices[i].y; geodesicData.vertex[this.vecToidx[idx]] = tempVec; } } //statics /**Creates a primary triangle * @internal */ public PrimaryIsoTriangle Build(int m, int n) { var vertices = new List(); var O = IsoVector.Zero(); var A = new IsoVector(m, n); var B = new IsoVector(-n, m + n); vertices.AddRange(new IsoVector[] { O, A, B }); //max internal isoceles triangle vertices for (var iy = n; iy < m + 1; iy++) { for (var ix = 0; ix < m + 1 - iy; ix++) { vertices.Add(new IsoVector(ix, iy)); } } //shared vertices along edges when needed if (n > 0) { var g = HighestCommonFactor(m, n); var m1 = m / g; var n1 = n / g; for (var i = 1; i < g; i++) { vertices.Add(new IsoVector(i * m1, i * n1)); //OA vertices.Add(new IsoVector(-i * n1, i * (m1 + n1))); //OB vertices.Add(new IsoVector(m - i * (m1 + n1), n + i * m1)); // AB } //lower rows vertices and their rotations var ratio = m / n; for (var iy = 1; iy < n; iy++) { for (var ix = 0; ix < iy * ratio; ix++) { vertices.Add(new IsoVector(ix, iy)); vertices.Add(new IsoVector(ix, iy).Rotate120(m, n)); vertices.Add(new IsoVector(ix, iy).RotateNeg120(m, n)); } } } //order vertices by x and then y vertices.Sort((a, b) => { return a.x - b.x; }); vertices.Sort((a, b) => { return a.y - b.y; }); var min = new List { m + n + 1 }; var max = new List { m + n + 1 }; for (var i = 0; i < min.Count; i++) { min[i] = int.MaxValue; max[i] = int.MinValue; } var y = 0; var x = 0; var len = vertices.Count; for (var i = 0; i < len; i++) { x = vertices[i].x; y = vertices[i].y; min[y] = Mathf.Min(x, min[y]); max[y] = Mathf.Max(x, max[y]); } //calculates the distance of a vertex from a given primary vertex Func distFrom = (IsoVector vert, string primVert) => { var v = vert.Clone(); if (primVert == "A") { v.RotateNeg120(m, n); } if (primVert == "B") { v.Rotate120(m, n); } if (v.x < 0) { return v.y; } return v.x + v.y; }; var cartesian = new List(); var distFromO = new List(); var distFromA = new List(); var distFromB = new List(); var vertByDist = new Dictionary>(); ; var vertData = new List>(); var closest = -1; var dist = -1; for (var i = 0; i < len; i++) { cartesian[i] = vertices[i].ToCartesianOrigin(new IsoVector(0, 0), 0.5f); distFromO[i] = distFrom(vertices[i], "O"); distFromA[i] = distFrom(vertices[i], "A"); distFromB[i] = distFrom(vertices[i], "B"); if (distFromO[i] == distFromA[i] && distFromA[i] == distFromB[i]) { closest = 3; dist = distFromO[i]; } else if (distFromO[i] == distFromA[i]) { closest = 4; dist = distFromO[i]; } else if (distFromA[i] == distFromB[i]) { closest = 5; dist = distFromA[i]; } else if (distFromB[i] == distFromO[i]) { closest = 6; dist = distFromO[i]; } if (distFromO[i] < distFromA[i] && distFromO[i] < distFromB[i]) { closest = 2; dist = distFromO[i]; } if (distFromA[i] < distFromO[i] && distFromA[i] < distFromB[i]) { closest = 1; dist = distFromA[i]; } if (distFromB[i] < distFromA[i] && distFromB[i] < distFromO[i]) { closest = 0; dist = distFromB[i]; } vertData.Add(new List { closest, dist, vertices[i].x, vertices[i].y }); } vertData.Sort((a, b) => { return a[2].CompareTo(b[2]); }); vertData.Sort((a, b) => { return a[3].CompareTo(b[3]); }); vertData.Sort((a, b) => { return a[1].CompareTo(b[1]); }); vertData.Sort((a, b) => { return a[0].CompareTo(b[0]); }); for (var v = 0; v < vertData.Count; v++) { vertByDist[vertData[v][2] + "|" + vertData[v][3]] = new List { vertData[v][0], vertData[v][1], v }; } this.m = m; this.n = n; this.vertices = vertices; this.vertByDist = vertByDist; this.cartesian = cartesian; this.min = min; this.max = max; return this; } } public class PolyhedronData { public string name; public string category; public List vertex; public List> face; public List<(int, string, int, string)> edgematch; public PolyhedronData( string name, string category, List vertex, List> face ) { this.name = name; this.category = category; this.vertex = vertex; this.face = face; } } public class GeodesicData : PolyhedronData { //public override edgematch: (number | string)[][]; public List> adjacentFaces; public int sharedNodes; public int poleNodes; public GeodesicData( string name, string category, List vertex, List> face ) : base(name, category, vertex, face) { } public void innerToData(int face, PrimaryIsoTriangle primTri) { for (var i = 0; i < primTri.innerFacets.Count; i++) { this.face.Add(primTri.innerFacets[i].Select((el) => primTri.vecToidx[face + el]).ToList()); } } public void MapABOBtoDATA(int faceNb, PrimaryIsoTriangle primTri) { var fr = primTri.IDATA.edgematch[faceNb].Item1; for (var i = 0; i < primTri.isoVecsABOB.Count; i++) { var temp = new List(); for (var j = 0; j < 3; j++) { if (primTri.vertexTypes[i][j] == 0) { temp.Add(faceNb + "|" + primTri.isoVecsABOB[i][j].x + "|" + primTri.isoVecsABOB[i][j].y); } else { temp.Add(fr + "|" + primTri.isoVecsABOB[i][j].x + "|" + primTri.isoVecsABOB[i][j].y); } } this.face.Add(new List { primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] }); } } /** * @internal */ public void MapOBOAtoDATA(int faceNb, PrimaryIsoTriangle primTri) { var fr = primTri.IDATA.edgematch[faceNb].Item1; for (var i = 0; i < primTri.isoVecsOBOA.Count; i++) { var temp = new List(); for (var j = 0; j < 3; j++) { if (primTri.vertexTypes[i][j] == 1) { temp.Add(faceNb + "|" + primTri.isoVecsOBOA[i][j].x + "|" + primTri.isoVecsOBOA[i][j].y); } else { temp.Add(fr + "|" + primTri.isoVecsOBOA[i][j].x + "|" + primTri.isoVecsOBOA[i][j].y); } } this.face.Add(new List { primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] }); } } /** * @internal */ public void MapBAOAtoDATA(int faceNb, PrimaryIsoTriangle primTri) { var fr = primTri.IDATA.edgematch[faceNb].Item3; for (var i = 0; i < primTri.isoVecsBAOA.Count; i++) { var temp = new List(); for (var j = 0; j < 3; j++) { if (primTri.vertexTypes[i][j] == 1) { temp.Add(faceNb + "|" + primTri.isoVecsBAOA[i][j].x + "|" + primTri.isoVecsBAOA[i][j].y); } else { temp.Add(fr + "|" + primTri.isoVecsBAOA[i][j].x + "|" + primTri.isoVecsBAOA[i][j].y); } } this.face.Add(new List { primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] }); } } /** * @internal */ public void OrderData(PrimaryIsoTriangle primTri) { var nearTo = new Dictionary>>(); for (var i = 0; i < 13; i++) { nearTo[i] = new List>(); } var close = primTri.closestTo; for (var i = 0; i < close.Count; i++) { if (close[i][0] > -1) { if (close[i][1] > 0) { nearTo[close[i][0]].Add(new List { i, close[i][1] }); } } else { nearTo[12].Add(new List { i, close[i][0] }); } } /* var near = new List(); for (var i = 0; i < 12; i++) { near[i] = i; } */ var near = Enumerable.Range(0, 12).ToList(); var nearIndex = 12; for (var i = 0; i < 12; i++) { nearTo[i].Sort((a, b) => { return a[1] - b[1]; }); /* for (var j = 0; j < nearTo[i].Count; j++) { near[nearTo[i][j][0]] = nearIndex++; } */ foreach (var item in nearTo[i]) { near[item[0]] = nearIndex++; } } /* for (var j = 0; j < nearTo[12].Count; j++) { near[nearTo[12][j][0]] = nearIndex++; } */ foreach (var item in nearTo[12]) { near[item[0]] = nearIndex++; } /* for (var i = 0; i < this.vertex.Count; i++) { //FIX this.vertex[i].Add(near[i]); } this.vertex.Sort((a, b) => { return a[3].CompareTo(b[3]); }); for (var i = 0; i < this.vertex.Count; i++) { //FIX this.vertex[i].RemoveAt(this.vertex[i].Count - 1); } */ this.vertex = this.vertex .Select((v, index) => (Vertex: v, SortKey: near[index])) .OrderBy(x => x.SortKey) .Select(x => x.Vertex) .ToList(); for (var i = 0; i < this.face.Count; i++) { for (var j = 0; j < this.face[i].Count; j++) { this.face[i][j] = near[this.face[i][j]]; } } this.sharedNodes = nearTo[12].Count; this.poleNodes = this.vertex.Count - this.sharedNodes; } public List SetOrder(int m, List faces) { var adjVerts = new List(); var dualFaces = new List(); var face = faces.Last(); faces.RemoveAt(faces.Count - 1); dualFaces.Add(face); var index = this.face[face].IndexOf(m); index = (index + 2) % 3; var v = this.face[face][index]; adjVerts.Add(v); var f = 0; while (faces.Count > 0) { face = faces[f]; if (this.face[face].IndexOf(v) > -1) { // v is a vertex of face f index = (this.face[face].IndexOf(v) + 1) % 3; v = this.face[face][index]; adjVerts.Add(v); dualFaces.Add(face); faces.RemoveAt(f); f = 0; } else { f++; } } this.adjacentFaces.Add(adjVerts); return dualFaces; } public PolyhedronData ToGoldbergPolyhedronData() { var goldbergPolyhedronData = new PolyhedronData("GeoDual", "Goldberg", new List(), new List>()); goldbergPolyhedronData.name = "GD dual"; var verticesNb = this.vertex.Count; var map = new List[verticesNb]; for (var v = 0; v < verticesNb; v++) { map[v] = new List(); } for (var f = 0; f < this.face.Count; f++) { for (var i = 0; i < 3; i++) { map[this.face[f][i]].Add(f); } } float cx; float cy; float cz; List face; Vector3 vertex; this.adjacentFaces = new List>(); for (var m = 0; m < map.Length; m++) { goldbergPolyhedronData.face[m] = this.SetOrder(m, new List(map[m])); foreach (var el in map[m]) { cx = 0; cy = 0; cz = 0; face = this.face[el]; for (var i = 0; i < 3; i++) { vertex = this.vertex[face[i]]; cx += vertex[0]; cy += vertex[1]; cz += vertex[2]; } goldbergPolyhedronData.vertex[el] = new Vector3(cx / 3, cy / 3, cz / 3); } ; } return goldbergPolyhedronData; } public static GeodesicData BuildGeodesicData(PrimaryIsoTriangle primTri) { float PHI = (1 + Mathf.Sqrt(5f)) / 2; var geodesicData = new GeodesicData( "Geodesic-m-n", "Geodesic", new List() { new Vector3(0, PHI, -1), new Vector3(-PHI, 1, 0), new Vector3(-1, 0, -PHI), new Vector3(1, 0, -PHI), new Vector3(PHI, 1, 0), new Vector3(0, PHI, 1), new Vector3(-1, 0, PHI), new Vector3(-PHI, -1, 0), new Vector3(0, -PHI, -1), new Vector3(PHI, -1, 0), new Vector3(1, 0, PHI), new Vector3(0, -PHI, 1), }, new List>() ); primTri.SetIndices(); primTri.CalcCoeffs(); primTri.CreateInnerFacets(); primTri.EdgeVecsABOB(); primTri.MapABOBtoOBOA(); primTri.MapABOBtoBAOA(); for (var f = 0; f < primTri.IDATA.face.Count; f++) { primTri.MapToFace(f, geodesicData); geodesicData.innerToData(f, primTri); if (primTri.IDATA.edgematch[f].Item2 == "B") { geodesicData.MapABOBtoDATA(f, primTri); } if (primTri.IDATA.edgematch[f].Item2 == "O") { geodesicData.MapOBOAtoDATA(f, primTri); } if (primTri.IDATA.edgematch[f].Item4 == "A") { geodesicData.MapBAOAtoDATA(f, primTri); } } geodesicData.OrderData(primTri); var radius = 1f; geodesicData.vertex = geodesicData.vertex.Select((el) => { var a = el[0]; var b = el[1]; var c = el[2]; var d = Mathf.Sqrt(a * a + b * b + c * c); el[0] *= radius / d; el[1] *= radius / d; el[2] *= radius / d; return el; }).ToList(); return geodesicData; } } }