You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1012 lines
34 KiB
1012 lines
34 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Metamesh
|
|
{
|
|
public class PrimaryIsoTriangle
|
|
{
|
|
public int m;
|
|
public int n;
|
|
public List<Vector3> cartesian = new List<Vector3>();
|
|
public List<IsoVector> vertices = new List<IsoVector>();
|
|
public List<int> max = new List<int>();
|
|
public List<int> min = new List<int>();
|
|
public Dictionary<string, int> vecToidx = new Dictionary<string, int>();
|
|
public Dictionary<string, List<int>> vertByDist = new Dictionary<string, List<int>>();
|
|
public Dictionary<int, List<int>> closestTo = new Dictionary<int, List<int>>();
|
|
|
|
public List<List<string>> innerFacets = new List<List<string>>();
|
|
public List<List<IsoVector>> isoVecsABOB = new List<List<IsoVector>>();
|
|
public List<List<IsoVector>> isoVecsOBOA = new List<List<IsoVector>>();
|
|
public List<List<IsoVector>> isoVecsBAOA = new List<List<IsoVector>>();
|
|
public List<List<int>> vertexTypes = new List<List<int>>();
|
|
|
|
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<Vector3>
|
|
{
|
|
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<List<int>>
|
|
{
|
|
new List<int> { 0, 2, 1 },
|
|
new List<int> { 0, 3, 2 },
|
|
new List<int> { 0, 4, 3 },
|
|
new List<int> { 0, 5, 4 },
|
|
new List<int> { 0, 1, 5 },
|
|
new List<int> { 7, 6, 1 },
|
|
new List<int> { 8, 7, 2 },
|
|
new List<int> { 9, 8, 3 },
|
|
new List<int> { 10, 9, 4 },
|
|
new List<int> { 6, 10, 5 },
|
|
new List<int> { 2, 7, 1 },
|
|
new List<int> { 3, 8, 2 },
|
|
new List<int> { 4, 9, 3 },
|
|
new List<int> { 5, 10, 4 },
|
|
new List<int> { 1, 6, 5 },
|
|
new List<int> { 11, 6, 7 },
|
|
new List<int> { 11, 7, 8 },
|
|
new List<int> { 11, 8, 9 },
|
|
new List<int> { 11, 9, 10 },
|
|
new List<int> { 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<string, int>();
|
|
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<int>();
|
|
string idx;
|
|
string idxR;
|
|
string isoId;
|
|
string isoIdR;
|
|
|
|
var closestTo = new Dictionary<int, List<int>>();
|
|
var vDist = this.vertByDist;
|
|
|
|
System.Action<int, int, string, string> 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<int> { -vDist[isoId][0], vDist[isoId][1], vecToidx[idx] };
|
|
}
|
|
else
|
|
{
|
|
closestTo[vecToidx[idx]] = new List<int> { 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<int> { 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<int> { 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<int> { 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<int>
|
|
{ -vDist[isoId][0], vDist[isoId][1], vecToidx[idx] };
|
|
}
|
|
else
|
|
{
|
|
closestTo[vecToidx[idx]] = new List<int>
|
|
{ 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<string>
|
|
{ "|" + 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<string>
|
|
{ "|" + 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<int> { 1, 0, 0 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { point, maxPrev, maxLeftPrev });
|
|
//down
|
|
this.vertexTypes.Add(new List<int> { 1, 0, 0 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { point, maxLeftPrev, maxPoint });
|
|
}
|
|
else if (pointR.y == nextR.y)
|
|
{
|
|
// type1
|
|
//up
|
|
this.vertexTypes.Add(new List<int> { 1, 1, 0 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { point, prev, maxPrev });
|
|
//down
|
|
this.vertexTypes.Add(new List<int> { 1, 0, 1 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { point, maxPrev, next });
|
|
}
|
|
else
|
|
{
|
|
// type 0
|
|
//up
|
|
this.vertexTypes.Add(new List<int> { 1, 1, 0 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { point, prev, maxPrev });
|
|
//down
|
|
this.vertexTypes.Add(new List<int> { 1, 0, 0 });
|
|
this.isoVecsABOB.Add(new List<IsoVector> { 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<IsoVector>();
|
|
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<IsoVector>();
|
|
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 Dictionary<int, List<float>>();
|
|
|
|
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<float> { 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<IsoVector>();
|
|
|
|
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 = Enumerable.Repeat(int.MaxValue, m + n + 1).ToList();
|
|
var max = Enumerable.Repeat(int.MinValue, m + n + 1).ToList();
|
|
|
|
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<IsoVector, string, int> 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 = Enumerable.Repeat(Vector3.zero, len).ToList();
|
|
var distFromO = Enumerable.Repeat(0, len).ToArray();
|
|
var distFromA = Enumerable.Repeat(0, len).ToArray();
|
|
var distFromB = Enumerable.Repeat(0, len).ToArray();
|
|
var vertByDist = new Dictionary<string, List<int>>();
|
|
;
|
|
var vertData = new List<List<int>>();
|
|
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<int> { 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<int> { 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<Vector3> vertex;
|
|
public List<List<int>> face;
|
|
public List<(int, string, int, string)> edgematch;
|
|
|
|
public PolyhedronData(
|
|
string name,
|
|
string category,
|
|
List<Vector3> vertex,
|
|
List<List<int>> face
|
|
)
|
|
{
|
|
this.name = name;
|
|
this.category = category;
|
|
this.vertex = vertex;
|
|
this.face = face;
|
|
}
|
|
}
|
|
|
|
public class GeodesicData : PolyhedronData
|
|
{
|
|
//public override edgematch: (number | string)[][];
|
|
public List<List<int>> adjacentFaces;
|
|
public int sharedNodes;
|
|
public int poleNodes;
|
|
|
|
private GeodesicData(
|
|
string name,
|
|
string category,
|
|
List<Vector3> vertex,
|
|
List<List<int>> face
|
|
) : base(name, category, vertex, face)
|
|
{
|
|
}
|
|
|
|
private 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());
|
|
}
|
|
}
|
|
|
|
private 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<string>();
|
|
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<int>
|
|
{ primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] });
|
|
}
|
|
}
|
|
|
|
private 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<string>();
|
|
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<int>
|
|
{ primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] });
|
|
}
|
|
}
|
|
|
|
private 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<string>();
|
|
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<int>
|
|
{ primTri.vecToidx[temp[0]], primTri.vecToidx[temp[1]], primTri.vecToidx[temp[2]] });
|
|
}
|
|
}
|
|
|
|
private void OrderData(PrimaryIsoTriangle primTri)
|
|
{
|
|
var nearTo = new Dictionary<int, List<List<int>>>();
|
|
for (var i = 0; i < 13; i++)
|
|
{
|
|
nearTo[i] = new List<List<int>>();
|
|
}
|
|
|
|
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<int> { i, close[i][1] });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nearTo[12].Add(new List<int> { i, close[i][0] });
|
|
}
|
|
}
|
|
|
|
/*
|
|
var near = new List<int>();
|
|
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;
|
|
}
|
|
|
|
private List<int> SetOrder(int m, List<int> faces)
|
|
{
|
|
var adjVerts = new List<int>();
|
|
var dualFaces = new List<int>();
|
|
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<Vector3>(), new List<List<int>>());
|
|
goldbergPolyhedronData.name = "GD dual";
|
|
var verticesNb = this.vertex.Count;
|
|
var map = new List<int>[verticesNb];
|
|
for (var v = 0; v < verticesNb; v++)
|
|
{
|
|
map[v] = new List<int>();
|
|
}
|
|
|
|
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<int> face;
|
|
Vector3 vertex;
|
|
this.adjacentFaces = new List<List<int>>();
|
|
for (var m = 0; m < map.Length; m++)
|
|
{
|
|
var tempFace = this.SetOrder(m, new List<int>(map[m]));
|
|
if (goldbergPolyhedronData.face.Count <= m)
|
|
{
|
|
goldbergPolyhedronData.face.Add(tempFace);
|
|
}
|
|
else
|
|
{
|
|
goldbergPolyhedronData.face[m] = tempFace;
|
|
}
|
|
|
|
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];
|
|
}
|
|
|
|
var tempVertex = new Vector3(cx / 3, cy / 3, cz / 3);
|
|
if (goldbergPolyhedronData.vertex.Count <= el)
|
|
{
|
|
goldbergPolyhedronData.vertex.Add(tempVertex);
|
|
}
|
|
else
|
|
{
|
|
goldbergPolyhedronData.vertex[el] = tempVertex;
|
|
}
|
|
}
|
|
|
|
;
|
|
}
|
|
|
|
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<Vector3>()
|
|
{
|
|
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<List<int>>()
|
|
);
|
|
|
|
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;
|
|
}
|
|
}
|
|
} |