diff --git a/Assets/Code/Hexasphere/Face.cs b/Assets/Code/Hexasphere/Face.cs index 7fd0a5e..c4cea05 100644 --- a/Assets/Code/Hexasphere/Face.cs +++ b/Assets/Code/Hexasphere/Face.cs @@ -14,16 +14,20 @@ public class Face public Face(Point point1, Point point2, Point point3, bool trackFaceInPoints = true) { _id = Guid.NewGuid().ToString(); - _points = new List {point1, point2, point3}; - if (trackFaceInPoints) - { - _points.ForEach(point => point.AssignFace(this)); - } float centerX = (point1.Position.x + point2.Position.x + point3.Position.x) / 3; float centerY = (point1.Position.y + point2.Position.y + point3.Position.y) / 3; float centerZ = (point1.Position.z + point2.Position.z + point3.Position.z) / 3; _centerPoint = new Point(new Vector3(centerX, centerY, centerZ)); + + _points = IsNormalPointingAwayFromPoint(_centerPoint, GetNormal(point1, point2, point3)) ? + new List {point1, point2, point3} : + new List {point1, point3, point2}; + + if (trackFaceInPoints) + { + _points.ForEach(point => point.AssignFace(this)); + } } public string ID => _id; @@ -63,5 +67,23 @@ private bool IsPointPartOfFace(Point point) { return _points.Any(facePoint => facePoint.ID == point.ID); } + + public static Vector3 GetNormal(Point point1, Point point2, Point point3) + { + Vector3 u = point2.Position - point1.Position; + Vector3 v = point3.Position - point1.Position; + + float x = u.y * v.z - u.z * v.y; + float y = u.z * v.x - u.x * v.z; + float z = u.x * v.y - u.y * v.x; + + return new Vector3(x, y, z); + } + + public static bool IsNormalPointingAwayFromPoint(Point point, Vector3 normal) + { + Vector3 pos = point.Position; + return pos.x * normal.x >= 0 && pos.y * normal.y >= 0 && pos.z * normal.z >= 0; + } } } diff --git a/Assets/Code/Hexasphere/Hexasphere.cs b/Assets/Code/Hexasphere/Hexasphere.cs index f00522d..bf5cebb 100644 --- a/Assets/Code/Hexasphere/Hexasphere.cs +++ b/Assets/Code/Hexasphere/Hexasphere.cs @@ -12,9 +12,9 @@ public class Hexasphere private static float _tao = Mathf.PI / 2; private List _points; private const float DefaultSize = 100f; - private const float PointComparisonAccuracy = 0.00001f; + private const float PointComparisonAccuracy = 0.000001f; - private static readonly List _corners = new List + private static readonly List Corners = new List { new Point(new Vector3(DefaultSize, _tao * DefaultSize, 0f)), new Point(new Vector3(-DefaultSize, _tao * DefaultSize, 0f)), @@ -30,28 +30,29 @@ public class Hexasphere new Point(new Vector3(-_tao * DefaultSize, 0f, -DefaultSize)) }; - private List _faces = new List + private List _faces; + private List _icosahedronFaces = new List { - new Face(_corners[0], _corners[1], _corners[4], false), - new Face(_corners[1], _corners[9], _corners[4], false), - new Face(_corners[4], _corners[9], _corners[5], false), - new Face(_corners[5], _corners[9], _corners[3], false), - new Face(_corners[2], _corners[3], _corners[7], false), - new Face(_corners[3], _corners[2], _corners[5], false), - new Face(_corners[7], _corners[10], _corners[2], false), - new Face(_corners[0], _corners[8], _corners[10], false), - new Face(_corners[0], _corners[4], _corners[8], false), - new Face(_corners[8], _corners[2], _corners[10], false), - new Face(_corners[8], _corners[4], _corners[5], false), - new Face(_corners[8], _corners[5], _corners[2], false), - new Face(_corners[1], _corners[0], _corners[6], false), - new Face(_corners[11], _corners[1], _corners[6], false), - new Face(_corners[3], _corners[9], _corners[11], false), - new Face(_corners[6], _corners[10], _corners[7], false), - new Face(_corners[3], _corners[11], _corners[7], false), - new Face(_corners[11], _corners[6], _corners[7], false), - new Face(_corners[6], _corners[0], _corners[10], false), - new Face(_corners[9], _corners[1], _corners[11], false) + new Face(Corners[0], Corners[1], Corners[4], false), + new Face(Corners[1], Corners[9], Corners[4], false), + new Face(Corners[4], Corners[9], Corners[5], false), + new Face(Corners[5], Corners[9], Corners[3], false), + new Face(Corners[2], Corners[3], Corners[7], false), + new Face(Corners[3], Corners[2], Corners[5], false), + new Face(Corners[7], Corners[10], Corners[2], false), + new Face(Corners[0], Corners[8], Corners[10], false), + new Face(Corners[0], Corners[4], Corners[8], false), + new Face(Corners[8], Corners[2], Corners[10], false), + new Face(Corners[8], Corners[4], Corners[5], false), + new Face(Corners[8], Corners[5], Corners[2], false), + new Face(Corners[1], Corners[0], Corners[6], false), + new Face(Corners[11], Corners[1], Corners[6], false), + new Face(Corners[3], Corners[9], Corners[11], false), + new Face(Corners[6], Corners[10], Corners[7], false), + new Face(Corners[3], Corners[11], Corners[7], false), + new Face(Corners[11], Corners[6], Corners[7], false), + new Face(Corners[6], Corners[0], Corners[10], false), + new Face(Corners[9], Corners[1], Corners[11], false) }; public Hexasphere(float radius, int divisions, float hexSize) @@ -61,13 +62,36 @@ public Hexasphere(float radius, int divisions, float hexSize) _hexSize = hexSize; _points = new List(); + _faces = new List(); + + Corners.ForEach(point => CachePoint(point)); + + _icosahedronFaces.ForEach(icoFace => + { + List facePoints = icoFace.Points; + List previousPoints; + List bottomSide = new List {facePoints[0]}; + List leftSide = facePoints[0].Subdivide(facePoints[1], divisions, CachePoint); + List rightSide = facePoints[0].Subdivide(facePoints[2], divisions, CachePoint); + for (int i = 1; i <= divisions; i++) + { + previousPoints = bottomSide; + bottomSide = leftSide[i].Subdivide(rightSide[i], i, CachePoint); + for (int j = 0; j < i; j++) + { + _faces.Add(new Face(previousPoints[j], bottomSide[j], bottomSide[j+1])); + if (j == 0) continue; + _faces.Add(new Face(previousPoints[j-1], previousPoints[j], bottomSide[j])); + } + } + }); } - public List Faces => _faces; + public List Points => _points; - public List Corners => _corners; + public List Faces => _faces; - public Point GetPointFromCacheIfExists(Point point) + private Point CachePoint(Point point) { Point existingPoint = _points.FirstOrDefault(candidatePoint => Mathf.Abs(candidatePoint.Position.x - point.Position.x) <= PointComparisonAccuracy && diff --git a/Assets/Scripts/DrawHexasphere.cs b/Assets/Scripts/DrawHexasphere.cs index 447eaa2..84e88b8 100644 --- a/Assets/Scripts/DrawHexasphere.cs +++ b/Assets/Scripts/DrawHexasphere.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Code.Hexasphere; @@ -14,15 +15,15 @@ void Start() _meshFilter = GetComponent(); _meshFilter.mesh = mesh; - Hexasphere hexasphere = new Hexasphere(1f, 2, 1f); - mesh.vertices = hexasphere.Corners.Select(point => point.Position).ToArray(); + Hexasphere hexasphere = new Hexasphere(1f, 4, 1f); + mesh.vertices = hexasphere.Points.Select(point => point.Position).ToArray(); List triangleList = new List(); hexasphere.Faces.ForEach(face => { face.Points.ForEach(point => { - int vertexIndex = hexasphere.Corners.FindIndex(corner => corner.ID == point.ID); + int vertexIndex = hexasphere.Points.FindIndex(corner => corner.ID == point.ID); triangleList.Add(vertexIndex); }); });