Voronoi Joint

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;

//Set to Template option

public class Voronoi_Joint : MonoBehaviour
{
    public enum GEOMETRY
    {
        TETRA,
        OCTA,
    };

    public GEOMETRY geo = GEOMETRY.TETRA;

    public GameObject[] centerRbs = new GameObject[6];//4
    public GameObject[] connected_Joints = new GameObject[6];//4
    private Vector3[] cj_12_EndPoints = new Vector3[12];
    private Vector3[] cj_24_EndPoints = new Vector3[24];

    private Vector3 startPosition;

    //private int[,] vN_Points_to;

    private Six_Splines    six_splines;
    private Twelve_Splines twelve_Splines;

    public bool bPrint_Debug = false;

    public Button_VU bvToggle_Hi_Res;


    /// <image url="$(SolutionDir)\EMB\EMB_Edge_Vert.png" scale="0.36" /> 

    /// <image url="$(SolutionDir)\EMB\EMB_Edge_Vert_2.png" scale="0.1" /> 

    public float radius = 1;
    public float outerforceMag = 10;
    public float centering_Mult = 1;
    public float torque_Coefficient = 1f;
    private VRTK_InteractableObject vrtk_Interact_1;

    public enum Handle_States
    {
        NORMAL,
        TOUCHED,
        GRABBED,
    }

    private Handle_States handle_State = Handle_States.NORMAL;

    public Color handle_Base_Col;
    public Color handle_Touched_Col;
    public Color handle_Grabbed_Col;
    private Color handle_Base_Emissive_Col;

    private VU_UI_MANAGER VU_UI;

    public bool bUsePhysics = true;
    public bool bSetTetraPositions = false;
    public GameObject TetraVoronoi;

    void Start()
    {
        startPosition = transform.position;

        bvToggle_Hi_Res.isON = false;

        vrtk_Interact_1 = GetComponent<VRTK_InteractableObject>();
        VU_UI = VU_UI_MANAGER.Instance;

        if (geo == GEOMETRY.TETRA)
        {
            six_splines = GetComponentInChildren<Six_Splines>();
            six_splines.Set_CJ_0_GO(connected_Joints[0]);//For OutII
        }
        else if(geo == GEOMETRY.OCTA)
        {
            twelve_Splines = GetComponentInChildren<Twelve_Splines>();
        }

        vrtk_Interact_1.InteractableObjectTouched += new InteractableObjectEventHandler(DoObject_1_Touched);
        vrtk_Interact_1.InteractableObjectUntouched += new InteractableObjectEventHandler(DoObject_1_Untouched);

        vrtk_Interact_1.InteractableObjectGrabbed += new InteractableObjectEventHandler(DoObject_1_Grabbed);
        vrtk_Interact_1.InteractableObjectUngrabbed += new InteractableObjectEventHandler(DoObject_1_Ungrabbed);

        if (!bUsePhysics)
        {
            Rigidbody[] rbs = GetComponentsInChildren<Rigidbody>();
            foreach(Rigidbody rb in rbs)
            {
                rb.isKinematic = true;
            }
             
            for (int i = 0; i < centerRbs.Length; i++)
            {
                centerRbs[i].GetComponent<Rigidbody>().isKinematic = true;
                centerRbs[i].GetComponent<ConfigurableJoint>().enablePreprocessing = false;
                connected_Joints[i].GetComponent<Rigidbody>().isKinematic = true;
            }
        }
        if(bSetTetraPositions)
        {
            Voronoi_Joint vj = TetraVoronoi.GetComponent<Voronoi_Joint>();

            Vector3 thisBasePosition = transform.position;

            float edgeLength = (connected_Joints[0].transform.position - connected_Joints[1].transform.position).magnitude;

            Vector3 vfaceCenter = ( connected_Joints[0].transform.localPosition +
                                    connected_Joints[1].transform.localPosition +
                                    connected_Joints[2].transform.localPosition) / 3f;

            Vector3 vDir = vfaceCenter.normalized;

            float tetraHeight = edgeLength * Mathf.Sqrt(0.666666667f);

            TetraVoronoi.transform.position = transform.position + vfaceCenter + vDir * edgeLength * Mathf.Sqrt(6) / 12f;

            Vector3[] vTetraPos = new Vector3[4];

            vTetraPos[0] = connected_Joints[0].transform.position;
            vTetraPos[1] = connected_Joints[1].transform.position;
            vTetraPos[2] = connected_Joints[2].transform.position;
            vTetraPos[3] = thisBasePosition + vfaceCenter + vDir*edgeLength*Mathf.Sqrt(6)/3;

            vj.SetPositions(ref vTetraPos);
        }
    }

    public void SetPositions(ref Vector3[] positions)
    {
        for(int i = 0; i < connected_Joints.Length; i++)
        {
            connected_Joints[i].transform.position = positions[i];
        }
    }

    private void DoObject_1_Touched(object sender, InteractableObjectEventArgs e)
    {
        handle_State = Handle_States.TOUCHED;
        VU_UI.Report_Touched(vrtk_Interact_1.gameObject, e.interactingObject);
    }

    private void DoObject_1_Untouched(object sender, InteractableObjectEventArgs e)
    {
        handle_State = Handle_States.NORMAL;
        VU_UI.Report_UnTouched(vrtk_Interact_1.gameObject, e.interactingObject);
    }

    private void DoObject_1_Grabbed(object sender, InteractableObjectEventArgs e)
    {
        handle_State = Handle_States.GRABBED;
    }

    private void DoObject_1_Ungrabbed(object sender, InteractableObjectEventArgs e)
    {
        handle_State = Handle_States.NORMAL;
    }

    private bool isValid_Vector(Vector3 v)
    {
        if (!float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public void Return_To_Start_Position()
    {
        transform.position = startPosition;
    }

    void FixedUpdate()
    {
        if (bUsePhysics)
        {
            //Angular Adjustment
            for (int j = 0; j < connected_Joints.Length; j++)
            {
                Vector3 vA = connected_Joints[j].transform.right;
                GameObject gAlign = connected_Joints[0];

                //subtract y component to get projection on current XZ plane
                float yDot = Vector3.Dot(connected_Joints[j].transform.up, gAlign.transform.up);
                Vector3 yProjected = gAlign.transform.up + yDot * gAlign.transform.up;

                float torque = torque_Coefficient * Vector3.Dot(yProjected, connected_Joints[j].transform.forward);
                Rigidbody rbc = connected_Joints[j].GetComponent<Rigidbody>();
                rbc.AddTorque(rbc.transform.up * torque);
            }

            //Distribute around sphere - Voronoi Action
            foreach (GameObject go in connected_Joints)
            {
                Rigidbody rb = go.GetComponent<Rigidbody>();
                Rigidbody rbInner;
                Vector3 vFrom;
                Vector3 vSum;
                Vector3 vRecip;

                foreach (GameObject gInner in connected_Joints)
                {
                    vSum = Vector3.zero;
                    float r;//Radius from Neighbor

                    if (go != gInner)
                    {
                        rbInner = gInner.GetComponent<Rigidbody>();
                        vFrom = rb.position - rbInner.position;
                        r = vFrom.magnitude;
                        vRecip = (1f / r) * vFrom.normalized;
                        vSum += vRecip;
                    }
                    if (isValid_Vector(vSum))
                    {
                        rb.AddForce(outerforceMag * vSum);
                    }
                }
            }
            //Pull centerRbs into Center of Sphere
            Vector3 vDiff;
            foreach (GameObject gCent in centerRbs)
            {
                Rigidbody rb = gCent.GetComponent<Rigidbody>();
                vDiff = transform.position - rb.position;

                rb.velocity = vDiff / Time.fixedDeltaTime;
            }

            if (bPrint_Debug)
            {
                //for (int i = 0; i < 4; i++)
                //{
                //    for (int j = 0; j < 3; j++)
                //    {
                //        print("VN_[" + i.ToString() + "," + j.ToString() + "] points to " + vN_Points_to[i, j].ToString());
                //    }
                //}
                bPrint_Debug = false;
            }
        }
    }

    Color curr_Color;
    Color curr_dot_Color;
    Color targ_Color;
    Color targ_dot_Color;

    float theta = 390;
    float target_theta = 0;

    public void Animate_Handle_Material()//UI HANDLE
    {
        curr_Color = Color.Lerp(curr_Color, targ_Color, Time.deltaTime * 1.61803f);
        curr_dot_Color = Color.Lerp(curr_dot_Color, targ_dot_Color, Time.deltaTime * 1.61803f);

        if (handle_State == Handle_States.NORMAL)
        {
            //target_theta = 300;
            targ_Color = handle_Base_Col;

        }
        else if (handle_State == Handle_States.TOUCHED)
        {
            //target_theta = 390;
            targ_Color = handle_Touched_Col;
        }
        else if (handle_State == Handle_States.GRABBED)
        {
            //target_theta = 570;
            targ_Color = handle_Grabbed_Col;

        }
        Renderer rend = GetComponent<Renderer>();
        rend.material.SetColor("_Color", curr_Color);
        rend.material.SetColor("_EmissionColor", curr_Color);
    }

    public void Toggle_Hi_Res_From_Voronoi()
    {
        bvToggle_Hi_Res.isON = !bvToggle_Hi_Res.isON;
        six_splines = TetraVoronoi.GetComponentInChildren<Six_Splines>();
        six_splines.Set_Hi_Res(bvToggle_Hi_Res.isON);
        twelve_Splines.Set_Hi_Res(bvToggle_Hi_Res.isON);
    }

    private void Update()
    {
        //Animate_Handle_Material();
        if (geo == GEOMETRY.TETRA)
        {
            cj_12_EndPoints[0] = connected_Joints[0].transform.localPosition;
            cj_12_EndPoints[1] = connected_Joints[1].transform.localPosition;
            cj_12_EndPoints[2] = connected_Joints[0].transform.localPosition;
            cj_12_EndPoints[3] = connected_Joints[2].transform.localPosition;
            cj_12_EndPoints[4] = connected_Joints[0].transform.localPosition;
            cj_12_EndPoints[5] = connected_Joints[3].transform.localPosition;

            cj_12_EndPoints[6] = connected_Joints[1].transform.localPosition;
            cj_12_EndPoints[7] = connected_Joints[2].transform.localPosition;
            cj_12_EndPoints[8] = connected_Joints[1].transform.localPosition;
            cj_12_EndPoints[9] = connected_Joints[3].transform.localPosition;
            cj_12_EndPoints[10] = connected_Joints[2].transform.localPosition;
            cj_12_EndPoints[11] = connected_Joints[3].transform.localPosition;

            six_splines.Generate_Splines(cj_12_EndPoints, transform.position);
        }
        else if(geo == GEOMETRY.OCTA)
        {
            cj_24_EndPoints[0] = connected_Joints[0].transform.localPosition;
            cj_24_EndPoints[1] = connected_Joints[1].transform.localPosition;
            cj_24_EndPoints[2] = connected_Joints[0].transform.localPosition;
            cj_24_EndPoints[3] = connected_Joints[2].transform.localPosition;

            cj_24_EndPoints[4] = connected_Joints[0].transform.localPosition;
            cj_24_EndPoints[5] = connected_Joints[3].transform.localPosition;
            cj_24_EndPoints[6] = connected_Joints[0].transform.localPosition;
            cj_24_EndPoints[7] = connected_Joints[4].transform.localPosition;

            cj_24_EndPoints[8] = connected_Joints[1].transform.localPosition;
            cj_24_EndPoints[9] = connected_Joints[2].transform.localPosition;
            cj_24_EndPoints[10] = connected_Joints[1].transform.localPosition;
            cj_24_EndPoints[11] = connected_Joints[5].transform.localPosition;

            cj_24_EndPoints[12] = connected_Joints[1].transform.localPosition;
            cj_24_EndPoints[13] = connected_Joints[4].transform.localPosition;
            cj_24_EndPoints[14] = connected_Joints[2].transform.localPosition;
            cj_24_EndPoints[15] = connected_Joints[5].transform.localPosition;

            cj_24_EndPoints[16] = connected_Joints[2].transform.localPosition;
            cj_24_EndPoints[17] = connected_Joints[3].transform.localPosition;
            cj_24_EndPoints[18] = connected_Joints[3].transform.localPosition;
            cj_24_EndPoints[19] = connected_Joints[5].transform.localPosition;

            cj_24_EndPoints[20] = connected_Joints[3].transform.localPosition;
            cj_24_EndPoints[21] = connected_Joints[4].transform.localPosition;
            cj_24_EndPoints[22] = connected_Joints[4].transform.localPosition;
            cj_24_EndPoints[23] = connected_Joints[5].transform.localPosition;

            twelve_Splines.Generate_Splines(cj_24_EndPoints, transform.position);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ProceduralToolkit;
using VRTK;
using UnityEngine.UI;
using VRTK.GrabAttachMechanics;

public class Six_Splines : MonoBehaviour
{
    public Face_Tetra faces;
    public GameObject test_Octahedron;

    public GameObject Horn_Handle_Prefab;
    private GameObject[] tangent_Handles = new GameObject[14];
    [Range(0, 100f)]
    public  float scale_tangent_Handles = 27f;
    private bool  bEdge_Rotation_On = false;
    private float edge_Angular_Rate = 0f;
    public Slider sld_Edge_Angular_Rate;
    private bool bHandles_On = true;
    public Button_VU bvAngular_On;

    private GameObject go_cj_0;

    public Button_VU[] bvEdge_Switches;

    private bool[] bEdge_Switch = new bool[6];

    public Button_VU bvHorns_Handles_On;

    public Slider sld_Tangent;
    public Slider sld_Extend;

    public float tan_Slide_Val = 0;
    public float extend_Slide_Val = 0;

    public Slider_VU sv_Tangent_Adjust;
    public Slider_VU sv_Extend_Adjust;

    public bool bHi_Res_On = false;
    public bool bRun_Once = false;

    public Button_VU bv_Outii; //One Face Opposite Tangents

    public Vector3[] tetra_Edges = new Vector3[12]; //edge 0 -> 0,1 | edge 1 -> 2-3 etc.

    private VRTK_InteractableObject interact;

    private ArgosMeshDraft aMD_Spline_Green;
    private ArgosMeshDraft aMD_Spline_Red;
    private ArgosMeshDraft aMD_Spline_Blue;
    private ArgosMeshDraft aMD_Spline_Yellow;
    private ArgosMeshDraft aMD_Spline_Orange;
    private ArgosMeshDraft aMD_Spline_Violet;

    private ArgosMeshDraft aMD_Spline_Cross;

    public GameObject spline_Green;
    public GameObject spline_Red;
    public GameObject spline_Blue;
    public GameObject spline_Yellow;
    public GameObject spline_Orange;
    public GameObject spline_Violet;

    public GameObject spline_Cross;

    public float[] spline_lens_Green  = new float[256];
    public float[] spline_lens_Red    = new float[256];
    public float[] spline_lens_Blue   = new float[256];
    public float[] spline_lens_Yellow = new float[256];
    public float[] spline_lens_Orange = new float[256];
    public float[] spline_lens_Violet = new float[256];

    public float[] spline_lens_Cross = new float[256];

    private List<Vector3> lst_SplineGreen  = new List<Vector3>();
    private List<Vector3> lst_SplineRed    = new List<Vector3>();
    private List<Vector3> lst_SplineBlue   = new List<Vector3>();
    private List<Vector3> lst_SplineYellow = new List<Vector3>();
    private List<Vector3> lst_SplineOrange = new List<Vector3>();
    private List<Vector3> lst_SplineViolet = new List<Vector3>();

    //private List<Vector3> lst_SplineCross = new List<Vector3>();

    private Vector3 p0_1, p0_2;
    private Vector3 p1_1, p1_2;
    private Vector3 p2_1, p2_2;
    private Vector3 p3_1, p3_2;
    private Vector3 p4_1, p4_2;
    private Vector3 p5_1, p5_2;

    [Range(0, 0.5f)]
    public float radial_Mag = 0.5f;

    [Range(-20, 20f)]
    public float tangent_Mag = 1f;

    [Range(-20, 20f)]
    public float tRad = 0.0f;

    public bool bUpdate = false;
    public bool bTangents_From_Octahedron = false;
    public Twelve_Splines twelve_Splines;

    private VU_UI_MANAGER VU_UI;

    void Start ()
    {
        bv_Outii.isON = false;

        //tan_Slide_Val = sld_Tangent.value;
        //extend_Slide_Val = sld_Extend.value;
        //edge_Angular_Rate = sld_Edge_Angular_Rate.value;

        for (int i = 0; i<6; i++)
        {
            bEdge_Switch[i] = false;
        }

        VU_UI = VU_UI_MANAGER.Instance;

        aMD_Spline_Green  = new ArgosMeshDraft();
        aMD_Spline_Red    = new ArgosMeshDraft();
        aMD_Spline_Blue   = new ArgosMeshDraft();
        aMD_Spline_Yellow = new ArgosMeshDraft();
        aMD_Spline_Orange = new ArgosMeshDraft();
        aMD_Spline_Violet = new ArgosMeshDraft();

        aMD_Spline_Cross = new ArgosMeshDraft();

        //Generate_Splines();

        spline_Green.GetComponent<MeshFilter>().mesh.MarkDynamic(); 
        spline_Red.GetComponent<MeshFilter>().mesh.MarkDynamic();
        spline_Blue.GetComponent<MeshFilter>().mesh.MarkDynamic();
        spline_Yellow.GetComponent<MeshFilter>().mesh.MarkDynamic();
        spline_Orange.GetComponent<MeshFilter>().mesh.MarkDynamic();
        spline_Violet.GetComponent<MeshFilter>().mesh.MarkDynamic();

        spline_Cross.GetComponent<MeshFilter>().mesh.MarkDynamic();

        for (int i = 0; i < 12; i++)
        {
            tangent_Handles[i] = Instantiate(Horn_Handle_Prefab);
            tangent_Handles[i].transform.localPosition = Vector3.zero;
            tangent_Handles[i].transform.localRotation = Quaternion.identity;

            if (!GetComponentInParent<Voronoi_Joint>().bUsePhysics)
            {
                tangent_Handles[i].GetComponent<Rigidbody>().isKinematic = true;
            }
        }
        for (int i = 0; i < 12; i++)
        {
            if (i % 2 == 0)
            {
                tangent_Handles[i].GetComponent<Handle_Tangent_Interact>().Set_Dual(tangent_Handles[i + 1].GetComponent<Handle_Tangent_Interact>());
            }
            else
            {
                tangent_Handles[i].GetComponent<Handle_Tangent_Interact>().Set_Dual(tangent_Handles[i - 1].GetComponent<Handle_Tangent_Interact>());
            }
        }
    }

    public void Set_CJ_0_GO(GameObject cj_0_go)
    {
        go_cj_0 = cj_0_go;
    }

    public void Show_Handles(bool bON)
    {
        for (int i = 0; i < 14; i++)
        {
            tangent_Handles[i].SetActive(bON);
        }
    }

    //public Slider sld_Tangent;
    //public Slider sld_Extend;

    public void onSld_Tangent()
    {
        tan_Slide_Val = sld_Tangent.value;
        VU_UI.Set_Active_Slider(sv_Tangent_Adjust.gameObject);
        UI_Ladder.Instance.fine_Tuner.Active_FTS(sld_Tangent);
    }

    public void onSld_Extend()
    {
        extend_Slide_Val = sld_Extend.value;
        VU_UI.Set_Active_Slider(sv_Extend_Adjust.gameObject);
        UI_Ladder.Instance.fine_Tuner.Active_FTS(sld_Extend);
    }

    public void Set_Hi_Res(bool bON)
    {
        bHi_Res_On = bON;
        faces.Set_Hi_Res(bON);
        bRun_Once = bON;
    }

    public void onBV_Outii()
    {
        bv_Outii.isON = !bv_Outii.isON;
    }

    public void On_Edge_Switch_BV(int i)
    {
        bEdge_Switch[i] = !bEdge_Switch[i];
        if(bvEdge_Switches[0] != null)
        {
            bvEdge_Switches[i].isON = bEdge_Switch[i];
        }      
    }

    public void onSld_Cross_Tangent()
    {
        tan_Slide_Val = sld_Tangent.value;
        VU_UI.Set_Active_Slider(sv_Tangent_Adjust.gameObject);
        UI_Ladder.Instance.fine_Tuner.Active_FTS(sld_Tangent);
    }

    public void onSld_Cross_Extend()
    {
        extend_Slide_Val = sld_Extend.value;
        VU_UI.Set_Active_Slider(sv_Extend_Adjust.gameObject);
        UI_Ladder.Instance.fine_Tuner.Active_FTS(sld_Extend);
    }

    public void On_Edge_Angular_Rotation_sld()
    {
        edge_Angular_Rate = sld_Edge_Angular_Rate.value;
    }

    public void On_Edge_Rotation_Button()
    {
        bEdge_Rotation_On = !bEdge_Rotation_On;
        bvAngular_On.isON = bEdge_Rotation_On;
    }

    public void OnHandles_OnOff()
    {
        bHandles_On = !bHandles_On;
        bvHorns_Handles_On.isON = bHandles_On;

        for(int i = 0; i<12; i++)
        {
            tangent_Handles[i].GetComponent<Handle_Tangent_Interact>().Show(bHandles_On);
        }
    }

    float ang = 0;
    void Update()
    {
        if (bUpdate)
        {
            if (bEdge_Rotation_On)
            {
                ang += edge_Angular_Rate * Time.deltaTime;
            }
            else
            {
                ang = 0;
            }
            for (int i = 0; i < 12; i++)
            {
                tangent_Handles[i].transform.localScale = scale_tangent_Handles * Vector3.one;
                tangent_Handles[i].transform.position   = transform.position + transform.parent.TransformVector(tetra_Edges[i]);
            }
            Vector3 v_i1_i0;
            Quaternion q0, q1;
            Quaternion qZ_0, qZ_1; 
            for (int i = 0; i < 6; i++)
            {
                v_i1_i0 = tangent_Handles[i*2].transform.position - tangent_Handles[i*2+1].transform.position;

                q0 = Quaternion.LookRotation(-v_i1_i0, tangent_Handles[i * 2].transform.position - transform.position);
                q1 = Quaternion.LookRotation(v_i1_i0, tangent_Handles[i * 2 + 1].transform.position - transform.position);

                float direction = 1f;
                if(bEdge_Switch[i])
                {
                    direction = -1f;
                }

                float tanDir = 1f;

                Quaternion q0_bub = Quaternion.identity;
                Quaternion q1_bub = Quaternion.identity;

                qZ_0 = Quaternion.Euler(0, 0, direction*ang);
                qZ_1 = Quaternion.Euler(0, 0, -direction*ang);

                tangent_Handles[i * 2].transform.rotation = q0 * qZ_0 * Quaternion.Euler(new Vector3(tanDir*tan_Slide_Val, 0, 0))*q0_bub;
                tangent_Handles[i * 2 + 1].transform.rotation = q1 * qZ_1 * Quaternion.Euler(new Vector3(tanDir*tan_Slide_Val, 0, 0)) * q1_bub;

                //if (bv_Outii.isON && i > 2)
                //{
                //    if (i == 4)
                //    {

                //        //tanDir = -1f;
                //        Vector3 nYellow0 = Vector3.Cross(go_cj_0.transform.up, tangent_Handles[i * 2].transform.forward).normalized;
                //        Vector3 nYellow1 = Vector3.Cross(tangent_Handles[i * 2 + 1].transform.forward, go_cj_0.transform.up).normalized;

                //        Vector3 nPlanar0 = Vector3.Cross(go_cj_0.transform.up, nYellow0).normalized;
                //        Vector3 nPlanar1 = Vector3.Cross(go_cj_0.transform.up, nYellow1).normalized;

                //        float cosTheta0 = Vector3.Dot(nPlanar0, nYellow0);
                //        float cosTheta1 = Vector3.Dot(nPlanar1, nYellow1);

                //        float ang0_R = Mathf.Acos(cosTheta0);
                //        float ang1_R = Mathf.Acos(cosTheta1);

                //        float convR_to_D = 180f / Mathf.PI;
                //        float ang0_D = ang0_R * convR_to_D;
                //        float ang1_D = ang1_R * convR_to_D;

                //        q0_bub = Quaternion.AngleAxis(ang0_D, nYellow0);
                //        q1_bub = Quaternion.AngleAxis(2 * ang1_D, nYellow1);

                //        tangent_Handles[i * 2].transform.localRotation = q0_bub * tangent_Handles[i * 2].transform.localRotation;
                //        //tangent_Handles[i * 2 + 1].transform.rotation = q1_bub;
                //    }
                //}

                tangent_Handles[i * 2].GetComponent<Handle_Tangent_Interact>().Set_Tangent_Position(extend_Slide_Val);
                tangent_Handles[i * 2 + 1].GetComponent<Handle_Tangent_Interact>().Set_Tangent_Position(extend_Slide_Val);
            }       
        }
    }

    public void Generate_Splines(Vector3[] points, Vector3 vCenter)
    {
        if (!bHi_Res_On || bRun_Once)
        {
            bRun_Once = false;

            aMD_Spline_Green.Clear();
            aMD_Spline_Red.Clear();
            aMD_Spline_Blue.Clear();
            aMD_Spline_Yellow.Clear();
            aMD_Spline_Orange.Clear();
            aMD_Spline_Violet.Clear();

            //aMD_Spline_Cross.Clear();

            lst_SplineGreen.Clear();
            lst_SplineRed.Clear();
            lst_SplineBlue.Clear();
            lst_SplineYellow.Clear();
            lst_SplineOrange.Clear();
            lst_SplineViolet.Clear();

            //lst_SplineCross.Clear();

            for (int i = 0; i < 12; i++)
            {
                tetra_Edges[i] = points[i];
            }

            p0_1 = points[0];//0
            p0_2 = points[1];//1
            p1_1 = points[2];//0
            p1_2 = points[3];//2
            p2_1 = points[4];//0
            p2_2 = points[5];//3

            p3_1 = points[6];//1
            p3_2 = points[7];//2
            p4_1 = points[8];//1
            p4_2 = points[9];//3
            p5_1 = points[10];//2
            p5_2 = points[11];//3

            Vector3 vTn_01, vTn_02, vTn_11, vTn_12, vTn_31, vTn_32;

            if (bTangents_From_Octahedron)
            {
                //0-1
                vTn_01 = twelve_Splines.getTan_Han(0).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_01 = transform.parent.InverseTransformVector(vTn_01);

                //1-0
                vTn_02 = twelve_Splines.getTan_Han(1).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_02 = transform.parent.InverseTransformVector(vTn_02);

                //--------------------------
                //0-2
                vTn_11 = twelve_Splines.getTan_Han(2).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_11 = transform.parent.InverseTransformVector(vTn_11);
                
                //2-0
                vTn_12 = twelve_Splines.getTan_Han(3).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_12 = transform.parent.InverseTransformVector(vTn_12);

                //---------------------------
                //1-2
                vTn_31 = twelve_Splines.getTan_Han(8).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_31 = transform.parent.InverseTransformVector(vTn_31);
                
                //2-1
                vTn_32 = twelve_Splines.getTan_Han(9).GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_32 = transform.parent.InverseTransformVector(vTn_32);
            }
            else
            {
                //0-1
                vTn_01 = tangent_Handles[0].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_01 = transform.parent.InverseTransformVector(vTn_01);

                //1-0
                vTn_02 = tangent_Handles[1].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_02 = transform.parent.InverseTransformVector(vTn_02);

                //--------------------------
                //0-2
                vTn_11 = tangent_Handles[2].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_11 = transform.parent.InverseTransformVector(vTn_11);
                //2-0
                vTn_12 = tangent_Handles[3].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_12 = transform.parent.InverseTransformVector(vTn_12);

                //---------------------------
                //1-2
                vTn_31 = tangent_Handles[6].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_31 = transform.parent.InverseTransformVector(vTn_31);
                //2-1
                vTn_32 = tangent_Handles[7].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
                vTn_32 = transform.parent.InverseTransformVector(vTn_32);
            }
            
            //---------------------------
            //0-3
            Vector3 vTn_21 = tangent_Handles[4].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_21 = transform.parent.InverseTransformVector(vTn_21);
            //3-0
            Vector3 vTn_22 = tangent_Handles[5].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_22 = transform.parent.InverseTransformVector(vTn_22);

            //---------------------------
            //1-3
            Vector3 vTn_41 = tangent_Handles[8].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_41 = transform.parent.InverseTransformVector(vTn_41);
            //3-1
            Vector3 vTn_42 = tangent_Handles[9].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_42 = transform.parent.InverseTransformVector(vTn_42);

            //---------------------------
            //2-3
            Vector3 vTn_51 = tangent_Handles[10].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_51 = transform.parent.InverseTransformVector(vTn_51);
            //3-2
            Vector3 vTn_52 = tangent_Handles[11].GetComponent<Handle_Tangent_Interact>().Get_Tangent_Position() - vCenter;
            vTn_52 = transform.parent.InverseTransformVector(vTn_52);

            //Local Coordinates
            if (bv_Outii.isON)
            {
                //Mirror
                Vector3 vLocal_Up_0 = transform.parent.InverseTransformVector(go_cj_0.transform.up).normalized;

                Vector3 vHandle_Pos = tangent_Handles[6].gameObject.transform.position - vCenter;
                vHandle_Pos = transform.parent.InverseTransformVector(vHandle_Pos);

                Vector3 vTo_Tangent = vTn_31 - vHandle_Pos;

                float dot;
                dot = Vector3.Dot(vTo_Tangent, vLocal_Up_0);
                float mir = -2f * dot;
                vTn_31 += mir * vLocal_Up_0;
                vTn_32 += mir * vLocal_Up_0;
                vTn_41 += mir * vLocal_Up_0;
                vTn_42 += mir * vLocal_Up_0;
                vTn_51 += mir * vLocal_Up_0;
                vTn_52 += mir * vLocal_Up_0;
            }

            //---------------------------
            Compute_Dist_Spline(ref lst_SplineGreen, ref spline_lens_Green, p0_1, vTn_01, vTn_02, p0_2);
            Compute_Dist_Spline(ref lst_SplineRed, ref spline_lens_Red, p1_1, vTn_11, vTn_12, p1_2);
            Compute_Dist_Spline(ref lst_SplineBlue, ref spline_lens_Blue, p2_1, vTn_21, vTn_22, p2_2);

            //---------------------------
            Compute_Dist_Spline(ref lst_SplineYellow, ref spline_lens_Yellow, p3_1, vTn_31, vTn_32, p3_2);
            Compute_Dist_Spline(ref lst_SplineOrange, ref spline_lens_Orange, p4_1, vTn_41, vTn_42, p4_2);
            Compute_Dist_Spline(ref lst_SplineViolet, ref spline_lens_Violet, p5_1, vTn_51, vTn_52, p5_2);

            aMD_Spline_Green.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineGreen));
            aMD_Spline_Red.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineRed));
            aMD_Spline_Blue.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineBlue));
            aMD_Spline_Yellow.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineYellow));
            aMD_Spline_Orange.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineOrange));
            aMD_Spline_Violet.Add(MeshDraft.Along_Spline(radial_Mag, 6, lst_SplineViolet));

            spline_Green.GetComponent<MeshFilter>().mesh = aMD_Spline_Green.ToMeshInternal();
            spline_Red.GetComponent<MeshFilter>().mesh = aMD_Spline_Red.ToMeshInternal();
            spline_Blue.GetComponent<MeshFilter>().mesh = aMD_Spline_Blue.ToMeshInternal();
            spline_Yellow.GetComponent<MeshFilter>().mesh = aMD_Spline_Yellow.ToMeshInternal();
            spline_Orange.GetComponent<MeshFilter>().mesh = aMD_Spline_Orange.ToMeshInternal();
            spline_Violet.GetComponent<MeshFilter>().mesh = aMD_Spline_Violet.ToMeshInternal();

            //p0 = p0_1
            //p1 = p1_1
            //p2 = p2_1

            //Tangents
            //  6 & 7 -> tan 1,2 tu1 & tu2
            //
            //  tv1 = 

            //cj_12_EndPoints[0] = connected_Joints[0].transform.localPosition;
            //cj_12_EndPoints[1] = connected_Joints[1].transform.localPosition;
            //cj_12_EndPoints[2] = connected_Joints[0].transform.localPosition;
            //cj_12_EndPoints[3] = connected_Joints[2].transform.localPosition;
            //cj_12_EndPoints[4] = connected_Joints[0].transform.localPosition;
            //cj_12_EndPoints[5] = connected_Joints[3].transform.localPosition;

            //cj_12_EndPoints[6] = connected_Joints[1].transform.localPosition;
            //cj_12_EndPoints[7] = connected_Joints[2].transform.localPosition;
            //cj_12_EndPoints[8] = connected_Joints[1].transform.localPosition;
            //cj_12_EndPoints[9] = connected_Joints[3].transform.localPosition;
            //cj_12_EndPoints[10] = connected_Joints[2].transform.localPosition;
            //cj_12_EndPoints[11] = connected_Joints[3].transform.localPosition;

            /*test_Octahedron.transform.localPosition = */

            faces.Clear_Faces();
            faces.Generate_Face(tetra_Edges[0],  tetra_Edges[3], tetra_Edges[1],  vTn_32, vTn_31,  vTn_12, vTn_02, vTn_11, vTn_01 );
            faces.Generate_Face(tetra_Edges[0],  tetra_Edges[5], tetra_Edges[3],  vTn_52, vTn_51,  vTn_22, vTn_12, vTn_21, vTn_11 );
            faces.Generate_Face(tetra_Edges[0],  tetra_Edges[1], tetra_Edges[5],  vTn_41, vTn_42,  vTn_02, vTn_22, vTn_01, vTn_21 );
            faces.Generate_Face(tetra_Edges[6],  tetra_Edges[7], tetra_Edges[9],  vTn_51, vTn_52,  vTn_32, vTn_42, vTn_31, vTn_41 );

            faces.toMesh_Internal();

            //Generate_Face(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 tu1, Vector3 tu2, Vector3 tv1, Vector3 tv2, Vector3 tv01, Vector3 tv02)
        }
        /// <image url="$(SolutionDir)\EMB\EMB_tetra_Faces.png" scale="0.15" /> 

        //aMD_Spline_Red.Add(MeshDraft.Along_Spline(0.007f, 6, lst_SplineRed));
        //aMD_Spline_Blue.Add(MeshDraft.Along_Spline(0.007f, 6, lst_SplineBlue));
    }

    private void Compute_Spline(ref List<Vector3> spline_lst, ref float[] lengths,  Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
    {
        float t = 0.0f;
        float dt = 1f / 72f;

        Vector3 vB = GetPointOnBezierCurve(p0, p1, p2, p3, get_Adjusted(t, ref lengths));

        for (int i = 0; i < 72; i++)
        {
            vB = GetPointOnBezierCurve(p0, p1, p2, p3, get_Adjusted(t, ref lengths));

            spline_lst.Add(vB);
            t += dt;
        }
    }

    private float get_Adjusted(float t, ref float[] lengths)
    {
        int i = 0;
        while (i < 256 && lengths[i] < t)
        {
            i++;
        }
        return (float)i / 256;
    }

    private void Compute_Dist_Spline(ref List<Vector3> spline_lst, ref float[] lengths, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
    {
        float t = 0.0f;
        float dt = 1f / 256;

        Vector3 vB = GetPointOnBezierCurve(p0, p1, p2, p3, t);
        Vector3 vB_Last = vB;
        float running_Len = 0;

        for (int i = 0; i < 256; i++)
        {
            vB = GetPointOnBezierCurve(p0, p1, p2, p3, t);
            running_Len += (vB - vB_Last).magnitude;
            lengths[i] = running_Len;
            vB_Last = vB;
            t += dt;
        }
        for (int i = 0; i < 256; i++)
        {
            lengths[i] /= running_Len;
        }
        Compute_Spline(ref spline_lst, ref lengths, p0, p1, p2, p3);
    }

    public Vector3 GetPointOnBezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
    {
        float u = 1f - t;
        float t2 = t * t;
        float u2 = u * u;
        float u3 = u2 * u;
        float t3 = t2 * t;

        Vector3 result =
            (u3) * p0 +
            (3f * u2 * t) * p1 +
            (3f * u * t2) * p2 +
            (t3) * p3;

        return result;
    }
}