devNotes 4-25-16 voronoi position list and data structure

Vect

boofpng

    List<Vector3> pts_catesian = new List<Vector3>();

    void sphere_fibonacci_build_cartesian(int num)
    {
        //pts_cartesian = new Vector3[num];
        float rnd = Random.Range(0, 1) * num;  //not sure why they rand here? -- which jacks with phi
        float offset = 2.0f / num;
        float increment = Mathf.PI * (3 - Mathf.Sqrt(5.0f));

        for (int i = 0; i < num; i++)
        {
            float y = (i * offset) - 1 + (offset / 2.0f);
            float r = Mathf.Sqrt(1 - Mathf.Pow(y, 2));
            float phi = ((i + rnd) % num) * increment;
            float x = Mathf.Cos(phi) * r;
            float z = Mathf.Sin(phi) * r;

            pts_catesian.Add(new Vector3(x, y, z));
        }
    }

Verify 3

Verify_3

Verify 2

Verify_2

Verify 1

Verify_1

in Cosahedra.cs

using UnityEngine;
using System.Collections;
using ProceduralToolkit;
using UnityEngine.UI;
using System.Collections.Generic;
using System.IO;

public class Cosahedra : MonoBehaviour
{
    public Text NumTrisText;
    public float m_fRadius = 1.5f;

    public ArgosMeshDraft aMD = new ArgosMeshDraft();
    public ArgosMeshDraft aMD_IcosaSphere = new ArgosMeshDraft();
    MeshDraft mD_Tri = new MeshDraft();

    public GameObject hexPreFab;
    public float m_fFact = 1; // force Multiplier

    StreamWriter sWrite;

    public int depth = 3;

    bool bSimulateForces = false;

    public enum ICO_Type
    {
        HEX,
        TRIANGLE,
        ICO_TREE_GENERATOR,
    };

    public ICO_Type icoType;

    public class GO_Tracker
    {
        public GameObject go;
        public ArgVert aVNode;
    }

    public List<GO_Tracker> lstHex_GO = new List<GO_Tracker>();

    void Start ()
    {
        sWrite = new StreamWriter("Argos_ICO_Tree_Hex_Construction.txt");

        aMD.Clear();
        aMD.Add(MeshDraft.Icosahedron(m_fRadius));
        aMD_IcosaSphere.Clear();
        Create_GP(depth);
        Vector3 vApex = new Vector3(0.0f, 5.0f, 0.0f);

        Quaternion q;
        Vector3 vN_In;

       for(int i = 0; i<aMD_IcosaSphere.icoPointCloud.Count-1;i++)
       {
            vN_In = aMD_IcosaSphere.icoPointCloud[i].vPos.normalized;
            q = Quaternion.LookRotation(vN_In);
            int lev0, lev1, lev2, lev3;
            GameObject gO;
            GO_Tracker gT;

            gO = (GameObject)Instantiate(hexPreFab, aMD_IcosaSphere.icoPointCloud[i].vPos, q);
            gT = new GO_Tracker();
            gT.go = gO;
            gT.aVNode = aMD_IcosaSphere.icoPointCloud[i];
            lstHex_GO.Add(gT);
            lev3 = aMD_IcosaSphere.icoPointCloud[i].itn.nodePath;
            lev0 = lev3 >> 6;
            lev1 = lev3 >> 4 & 3;
            lev2 = lev3 >> 2 & 3;
            lev3 = lev3 & 3;

            //lstHex_GO[lstHex_GO.Count - 1].go.GetComponentInChildren<Text>().text = lev0.ToString() + lev1.ToString() + lev2.ToString() + lev3.ToString(); 
            lstHex_GO[lstHex_GO.Count - 1].go.GetComponentInChildren<Text>().text = i.ToString();

        }

        foreach (GO_Tracker gActedUpon in lstHex_GO)
        {
            gActedUpon.go.transform.position = gActedUpon.aVNode.vPos;
        }

        aMD_IcosaSphere.FlipNormals();
        GetComponent<MeshFilter>().mesh = aMD_IcosaSphere.ToMesh();
    }


    public void ArgosVoronoi(bool bDoNeighbors)
    {
        Vector3 vForce;
        Vector3 vAccumForce;
        float dist_sqd;
        float fMag = 0;

        float delta = 0.05f;

        foreach (GO_Tracker gActedUpon in lstHex_GO)
        {
            vAccumForce = Vector3.zero;
            foreach (GO_Tracker gPushing in lstHex_GO)
            {
                if (gActedUpon != gPushing)
                {
                    vForce = gActedUpon.aVNode.vPos - gPushing.aVNode.vPos;
                    dist_sqd = vForce.x * vForce.x + vForce.y * vForce.y + vForce.z * vForce.z;
                    vAccumForce += vForce.normalized / dist_sqd;

                    if (bDoNeighbors)
                    {
                        gActedUpon.aVNode.insNeighbor_One_Shot(dist_sqd, gPushing.aVNode);
                    }
                }
            }

            fMag = vAccumForce.magnitude;
            vAccumForce = vAccumForce.normalized;

            gActedUpon.aVNode.vForce = 100f * vAccumForce;
            gActedUpon.aVNode.vPos += gActedUpon.aVNode.vForce * (delta * delta);
            gActedUpon.aVNode.vPos = gActedUpon.aVNode.vPos.normalized;
            gActedUpon.aVNode.vPos *= m_fRadius;
        }
    }

    public void OnStartButtonDown()
    {
        bSimulateForces = true;
    } 

    public void OnStopButtonDown()
    {
        ArgosVoronoi(true);
        bSimulateForces = false;
        List<ArgVert> aVL = aMD_IcosaSphere.icoPointCloud;
        for (int i = 0; i < aMD_IcosaSphere.icoPointCloud.Count - 1; i++)
        {
            
            sWrite.WriteLine(i.ToString()
            + "| N0 = " + aVL[i].avNeigbor[0].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[0].distFrom).ToString("F4")
            + " N1 = " + aVL[i].avNeigbor[1].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[1].distFrom).ToString("F4")
            + " N2 = " + aVL[i].avNeigbor[2].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[2].distFrom).ToString("F4")
            + " N3 = " + aVL[i].avNeigbor[3].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[3].distFrom).ToString("F4")
            + " N4 = " + aVL[i].avNeigbor[4].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[4].distFrom).ToString("F4")
            + " N5 = " + aVL[i].avNeigbor[5].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[5].distFrom).ToString("F4")
            + " v = " + aVL[i].vPos.ToString("F3")
            );
        }
        sWrite.Close();
    }

    void Update ()
    {
        if (bSimulateForces)
        {
            ArgosVoronoi(false);

            foreach (GO_Tracker gActedUpon in lstHex_GO)
            {
                gActedUpon.go.transform.position = gActedUpon.aVNode.vPos;
            }
        }
    }

    void OnApplicationQuit()
    {
        //sWrite.Close();
    }

    void Create_GP(int depth)
    {
        for(int i = 0; i<20; i++)
        {
            Vector3 v0 = aMD.vertices[aMD.triangles[i*3]];
            Vector3 v1 = aMD.vertices[aMD.triangles[i*3 +1]];
            Vector3 v2 = aMD.vertices[aMD.triangles[i*3 + 2]];
            Color col = getWhite();
            subdivide(v0, v1, v2, depth, col,i,0);
        }
    }

    int ITG_idx = 0; 

    void subdivide(Vector3 v1, Vector3 v2, Vector3 v3, int depth, Color col,int sector, int nID)
    {
        Vector3 v12, v23, v31;
        Vector3 v12_n, v23_n, v31_n;
        int i;

        if (depth == 0)
        {
            if (icoType == ICO_Type.HEX)
            {
                addHex(v1, v2, v3, col);
            }
            else if(icoType == ICO_Type.TRIANGLE)
            {
                addTriangle(v1, v2, v3, col);
            }    
            else if(icoType == ICO_Type.ICO_TREE_GENERATOR)
            {

                addITG_Node(v1, v2, v3, sector, nID, ITG_idx);
                ITG_idx++;

            }
            return;
        }

        v12 = (v1 + v2) / 2.0f;
        v23 = (v2 + v3) / 2.0f;
        v31 = (v3 + v1) / 2.0f;

        /* extrude midpoints to lie on unit sphere */
        v12_n = v12.normalized * m_fRadius;
        v23_n = v23.normalized * m_fRadius;
        v31_n = v31.normalized * m_fRadius;

        int shifter = nID;
        shifter = shifter << 2;

        /* recursively subdivide new triangles */
        subdivide(v1, v12_n, v31_n, depth - 1, col, sector, shifter | 0);
        subdivide(v12_n, v2, v23_n, depth - 1, col, sector, shifter | 1);
        subdivide(v31_n, v23_n, v3, depth - 1, col, sector, shifter | 2);
        subdivide(v23_n, v31_n, v12_n,  depth - 1, col, sector, shifter | 3);
    }

    void addITG_Node(Vector3 v0, Vector3 v1, Vector3 v2,int Sector, int nID, int id)
    {
        mD_Tri = MeshDraft.Triangle(v0, v1, v2);
        aMD_IcosaSphere.Add_ITN_Node(mD_Tri, Sector, nID, id);
    }

    void addTriangle(Vector3 v0, Vector3 v1, Vector3 v2, Color col)
    {
        mD_Tri.Clear();
        mD_Tri = MeshDraft.Triangle(v0, v1, v2);
        mD_Tri.Paint(col);

        aMD_IcosaSphere.AddTriQual(mD_Tri);
    }

    void addHex(Vector3 v0, Vector3 v1, Vector3 v2, Color col)
    {
        mD_Tri.Clear();
        mD_Tri = MeshDraft.Triangle(v0, v1, v2);
        mD_Tri.Paint(col);

        aMD_IcosaSphere.AddHex(mD_Tri);
    }

    public void writeMesh()
    {
        GetComponent<MeshFilter>().mesh = aMD_IcosaSphere.ToMesh();
    }

    public ArgosMeshDraft getArgosMeshDraft()
    {
        return aMD_IcosaSphere;
    }

    Color getIDXolor(int i)
    {
        Color col;

        col.r = 0.2f + (float)(i) * 0.8f / 20f ;
        col.g = 0.5f + (float)(i) * 0.5f / 20f;
        col.b = 1f - (float)(i) * 0.8f / 20f;
        col.a = 1f;
        return col;
    }

    Color getWhite() // :)
    {
        Color col;

        col.r = 1f;
        col.g = 1f;
        col.b = 1f;
        col.a = 1f;
        return col;
    }

    Color getINColor(int i)
    {
        Color col;

        col.r = (float)(i) / 1024f;
        col.g = 1f - (float)(i)  / 1024f;
        col.b = 0.5f - (float)(i) / 1024f;
        if(col.b>0) col.b = 1f- (float)(i) / 1024f;
        col.a = 1f;
        return col;
    }
}

in ArgosMeshDraft.cs

    public class ICO_Tree_Node_ID
    {
        public int sector;   // 20 sectors to ICO
        public int nodePath; // 2 bits per depth level 
    }

    public class ArgVert
    {
        public Vector3 vPos;
        public ICO_Tree_Node_ID itn = new ICO_Tree_Node_ID();
        public float dist;
        public Vector3 vForce; //constrain position to sphere radius
        public Vector3 vVel;
        public float maxDistToNeighbor = 0;
        public float minDistToNeighbor = float.MaxValue;
        public int idx;

        public class NB
        {
            public ArgVert aV;
            public float distFrom;

            public NB()
            {
                aV = null;
                distFrom = float.MaxValue;
            }
        }

        public List<NB> avNeigbor = new List<NB>();

        public ArgVert()
        {
            for (int i = 0; i < 6; i++)
            {
                avNeigbor.Add(new NB());
                avNeigbor[i].aV = this;
            }
        }

        public float getMaxDistToNeighbor()
        {
            maxDistToNeighbor = 0;
            for (int i = 0; i < 6; i++)
            {
                if (avNeigbor[i].distFrom > maxDistToNeighbor)
                {
                    maxDistToNeighbor = avNeigbor[i].distFrom;
                }
            }
            return maxDistToNeighbor;
        }

        public float getMinDistToNeighbor()
        {
            minDistToNeighbor = float.MaxValue;
            for (int i = 0; i < 6; i++)
            {
                if (avNeigbor[i].distFrom < minDistToNeighbor)
                {
                    minDistToNeighbor = avNeigbor[i].distFrom;
                }
            }
            return minDistToNeighbor;

        }

        public bool isAVinNeighborList(ArgVert aV)
        {
            for (int i = 0; i < 6; i++)
            {
                if (avNeigbor[i].aV == aV) return true;
            }
            return false;
        }

        public int isLessThan(float dist)
        {
            for (int i = 0; i < 6; i++)
            {
                if (dist < avNeigbor[i].distFrom) return i;
            }
            return -1;
        }

        public bool goesHere(int i, float dist, ArgVert aV_Contender)
        {
            if (dist < avNeigbor[i].distFrom)
            {

                NB nb = new NB();
                nb.aV = aV_Contender;
                nb.distFrom = dist;
                avNeigbor.Insert(i, nb);
                avNeigbor.RemoveAt(6);
                return true;
            }
            return false;
        }


        public void insNeighbor_One_Shot(float dist, ArgVert aV_Contender)
        {
            for (int i = 0; i < 6; i++)
            {
                if (goesHere(i, dist, aV_Contender)) return;
            }
        }
    }

    public class ArgosMeshDraft : MeshDraft
    {
        public List<Vector3> vTriCenter = new List<Vector3>();
        public List<int> vQual = new List<int>();
        public List<ArgVert> icoPointCloud = new List<ArgVert>();

        public ArgosMeshDraft() : base()
        {

        }

        public void Add_ITN_Node(MeshDraft tri, int sector, int nodePath, int ITG_idx)
        {
            Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f;

            ArgVert aV = new ArgVert();

            aV.vPos = vC;
            aV.itn.sector = sector;
            aV.itn.nodePath = nodePath;
            aV.idx = ITG_idx;

            icoPointCloud.Add(aV);
        }

        public void SetSortDist(Vector3 Apex)
        {
            foreach (ArgVert aV in icoPointCloud)
            {
                aV.dist = (aV.vPos - Apex).magnitude;
            }
        }

        public void sortPointCloud()
        {
            icoPointCloud.Sort((x, y) => x.dist.CompareTo(y.dist));
        }

        public void AddTriQual(MeshDraft tri)
        {
            Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f;
            int qual = TriQual.UNDEFINED;

            Add(tri);

            for (int i = 0; i < 3; i++)//Track the quality of the triangle UVs
            {
                vTriCenter.Add(vC);
                vQual.Add(qual);
            }
        }

        public void AddHex(MeshDraft tri)//from triangle see: http://argos.vu/wp-content/uploads/2016/04/HCs-1.png
        {
            Vector3 HC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f;

            Vector3 H0 = (tri.vertices[1] + tri.vertices[0]) / 2f;

            Vector3 H1 = (tri.vertices[1] + HC) / 2f;

            Vector3 H2 = (tri.vertices[2] + tri.vertices[1]) / 2f;

            Vector3 H3 = (tri.vertices[2] + HC) / 2f;

            Vector3 H4 = (tri.vertices[0] + tri.vertices[2]) / 2f;

            Vector3 H5 = (tri.vertices[0] + HC) / 2f;

            List<Vector3> vL = new List<Vector3>(8) { HC, H0, H1, H2, H3, H4, H5, H0 };

            List<Vector2> uvMapL = new List<Vector2>(8) { new Vector2(0.5f, 0.5f), new Vector2(0.5f, 1f), new Vector2(1, 0.75f), new Vector2(1, 0.25f), new Vector2(0.5f, 0), new Vector2(0, 0.25f), new Vector2(0, 0.75f), new Vector2(0.5f, 1f) };

            Add(HexFan(vL, uvMapL));
        }

        public void AddTriQual(MeshDraft tri, int qual)
        {
            Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f;

            Add(tri);

            for (int i = 0; i < 3; i++)//Track the quality of the triangle UVs
            {
                vTriCenter.Add(vC);
                vQual.Add(qual);
            }
        }
    }
}

 

FTN_36.mp3

me100im3