static GameObject createStrutIfNotExisting(RFrame_Object frameObject, GameObject strutInstantiator, List <GameObject> strutsCheck, int v1, int v2)
        {
            RFrame_Strut strutToCheck;
            bool         foundExistingStrut = false;

            //if (strutsCheck.Count==0) return false;
            foreach (GameObject strutToCheckGameObject in strutsCheck)
            {
                strutToCheck = strutToCheckGameObject.GetComponent <RFrame_Strut>();
                if (strutToCheck.v1 == v1 && strutToCheck.v2 == v2)
                {
                    foundExistingStrut = true;
                }
                if (strutToCheck.v1 == v2 && strutToCheck.v2 == v1)
                {
                    foundExistingStrut = true;
                }
            }
            if (!foundExistingStrut)
            {
                GameObject   strutGameObject = Instantiate(strutInstantiator, frameObject.transform);
                RFrame_Strut newStrut        = strutGameObject.GetComponent <RFrame_Strut>();
                newStrut.v1 = v1;
                newStrut.v2 = v2;
                strutsCheck.Add(strutGameObject);
                return(strutGameObject);
            }
            return(null);           //foundExistingStrut;
        }
        // Update is called once per frame
        void Update()
        {
            // Update this game objects position to be by the angle joint.
            RFrame_Object parentFrame = transform.parent.gameObject.GetComponent <RFrame_Object>();
            GameObject    centerObj   = parentFrame.allVertices[this.centerVertex];

            transform.localPosition = centerObj.transform.localPosition;
            // Call the angle measuring function.
            measureAngle();
        }
        public void measureAngle(bool measuringInitialAngle = false)
        {
            RFrame_Object parentFrame    = transform.parent.gameObject.GetComponent <RFrame_Object>();
            GameObject    centerObj      = parentFrame.allVertices[this.centerVertex];
            GameObject    upObj          = parentFrame.allVertices[this.upVertex];
            GameObject    measure1Obj    = parentFrame.allVertices[this.measure1];
            GameObject    measure2Obj    = parentFrame.allVertices[this.measure2];
            Vector3       measure1Vertex = measure1Obj.transform.localPosition - centerObj.transform.localPosition;
            Vector3       measure2Vertex = measure2Obj.transform.localPosition - centerObj.transform.localPosition;

            // Measure the angle based on the measuring angle type.
            switch (angleMeasureType)
            {
            case AngleMeasureTypeEnum.quaternionBased: {
                Vector3    upVertex     = upObj.transform.localPosition - centerObj.transform.localPosition;
                Quaternion orientation1 = Quaternion.LookRotation(measure1Vertex, upVertex);
                Quaternion orientation2 = Quaternion.LookRotation(measure2Vertex, upVertex);
                angleBetween = Quaternion.Angle(orientation1, orientation2);
                break;
            }

            case AngleMeasureTypeEnum.lineBased: {
                // Use the dot product method of finding the angle
                float dotProduct = Vector3.Dot(measure1Vertex, measure2Vertex);
                float magMult    = measure1Vertex.magnitude * measure2Vertex.magnitude;
                if (magMult > 0.0f)
                {
                    // Converted to degrees.
                    angleBetween = Mathf.Acos(dotProduct / magMult) * Mathf.Rad2Deg;
                }
                break;
            }
            }

            // Record the initial angle
            if (measuringInitialAngle)
            {
                initialAngle = angleBetween;
            }
            // Calculate the change in angle and apply that to the bias angle to be sent to the channel
            float diff       = (angleBetween - initialAngle);
            float scaledDiff = diff * angleChangeScaling;

            channelSendAngle = biasAngle + (invertedSendAngle ? -scaledDiff : scaledDiff);
            // Check if channel angle is within limits.
            if (channelSendAngle < minimumAngle)
            {
                channelSendAngle = minimumAngle;
            }
            if (channelSendAngle > maximumAngle)
            {
                channelSendAngle = maximumAngle;
            }
        }
        // Update is called once per frame
        void Update()
        {
            // Position the attached mesh to the centre vertex
            RFrame_Object parentFrame   = transform.parent.gameObject.GetComponent <RFrame_Object>();
            GameObject    centerObj     = parentFrame.allVertices[this.centerVertex];
            GameObject    upObj         = parentFrame.allVertices[this.upVertex];
            GameObject    forwardObj    = parentFrame.allVertices[this.forwardVertex];
            Vector3       upVertex      = upObj.transform.localPosition - centerObj.transform.localPosition;
            Vector3       forwardVertex = forwardObj.transform.localPosition - centerObj.transform.localPosition;
            Quaternion    orientation   = Quaternion.LookRotation(forwardVertex, upVertex);

            transform.localPosition = centerObj.transform.localPosition;
            transform.rotation      = orientation;
        }
 // Update is called once per frame
 void Update()
 {
     // Update the transform of this object so that it starts at v1 and points
     // towards v2.
     // Only update the struts line renderer if its enabled.
     if (GetComponent <LineRenderer>().enabled)
     {
         RFrame_Object parentFrame = transform.parent.gameObject.GetComponent <RFrame_Object>();
         GameObject    v1Obj       = parentFrame.allVertices[this.v1];
         GameObject    v2Obj       = parentFrame.allVertices[this.v2];
         Vector3[]     positions   = { v1Obj.transform.localPosition, v2Obj.transform.localPosition };
         this.updateLineRenderPositions(positions);
     }
 }
        /**
         * Test method for creating a Frame_Object from an OBJ file
         * 23 Jan 2019 - Updated to read from modified OBJ files.
         * @param objFile The filename of the OBJ file
         * @return A Frame_Object file
         * @throws FileNotFoundException
         */
        void createFromOBJ(TextAsset objFile)
        {
            //System.out.println("Loading OBJ file : " + objFile.toString());

            string[] inFile = objFile.text.Split('\n');

            List <GameObject> verticesBuild  = new List <GameObject>();
            List <GameObject> strutBuild     = new List <GameObject>();
            List <GameObject> angleViewBuild = new List <GameObject>();
            List <GameObject> compRepBuild   = new List <GameObject>();
            List <GameObject> balPosBuild    = new List <GameObject>();
            List <GameObject> disHolBuild    = new List <GameObject>();
            List <GameObject> ancPoiBuild    = new List <GameObject>();

            int vertexIndex = 0;

            foreach (string objLine in inFile)
            {
                //System.out.println(objLine); // Debug print to console the current line.
                // Reading in a vertex line
                if (objLine.StartsWith("v") && !objLine.StartsWith("vn") && !objLine.StartsWith("vt") && !objLine.StartsWith("vp"))
                {
                    // Split the string using space. e.g. v 3.00 2.00 -2.00
                    //System.out.println("Vertex : " + objLine);
                    string[] splits = objLine.Split(' ');
                    float    x      = float.Parse(splits[1]);
                    float    y      = float.Parse(splits[2]);
                    float    z      = float.Parse(splits[3]);

                    GameObject vertexGameObject = Instantiate(VertexInstantiator, this.transform);
                    vertexGameObject.name = vertexGameObject.name + "_" + vertexIndex;
                    vertexGameObject.transform.localPosition = new Vector3(x, y, z);
                    RFrame_Vertex vertexScript = vertexGameObject.GetComponent <RFrame_Vertex>();
                    vertexScript.x = x;
                    vertexScript.y = y;
                    vertexScript.z = z;
                    // Check for lock character
                    if (splits.Length > 4)
                    {
                        if (splits[4] == "l")
                        {
                            vertexScript.lockedInPlace = true;
                        }
                    }
                    verticesBuild.Add(vertexGameObject);
                    vertexIndex++;
                }
                else if (objLine.StartsWith("l"))
                {
                    // This is for any standalone lines, which will be turned into struts.
                    // Modified to only work with the first two vertice indexes

                    string[] splits = objLine.Split(' ');
                    // Remember that indexes start at 1 in the obj/txt file and need converting to zero-indexed.
                    int        v1 = int.Parse(splits[1]) - 1;
                    int        v2 = int.Parse(splits[2]) - 1;
                    GameObject strutGameObject = RFrame_Object.createStrutIfNotExisting(this, StrutInstantiator, strutBuild, v1, v2);
                    // Check if strut is displayed. This is determined by having more than three entries in splits.
                    // Basically any character entered after the 2 indexes will trigger this.
                    //if(strutGameObject!=null && splits.Length > 3) {
                    if (splits.Length == 5)
                    {
                        RFrame_Strut strutScript = strutGameObject.GetComponent <RFrame_Strut>();
                        strutScript.minLength = float.Parse(splits[3]);
                        strutScript.maxLength = float.Parse(splits[4]);
                    }
                    // All line renderers will be switched off.
                    LineRenderer lineRenderer = strutGameObject.GetComponent <LineRenderer>();
                    // Used when debugging the a fresh OBJ frame.
                    lineRenderer.enabled = transform.GetComponentInParent <RFrame_Bridge>().displayStrutsOnLoad;
                    //}
                }
                else if (objLine.StartsWith("anglink"))
                {
                    // Angle link entry.
                    // Requires 4 vertex indexes and a link channel number which will represent the angle measurer struts.
                    // and the actuator/motor/servo this is linked too.
                    // Centering and angle limits should be entered.
                    string[]         splits             = objLine.Split(' ');
                    int              centerVertex       = int.Parse(splits[1]);
                    int              upVertex           = int.Parse(splits[2]);
                    int              measure1           = int.Parse(splits[3]);
                    int              measure2           = int.Parse(splits[4]);
                    int              channel            = int.Parse(splits[5]);    // Channel number should already be zero-indexed.
                    bool             invertChannel      = bool.Parse(splits[6]);   // Should be 0, 1, true or false
                    float            minChannelAngle    = float.Parse(splits[7]);  // Channel won't be sent any number smaller than this.
                    float            maxChannelAngle    = float.Parse(splits[8]);  // Channel won't be sent any number larger than this.
                    float            biasAngle          = float.Parse(splits[9]);  // The bias to apply. Indicates that a servo may need recentering
                    int              angleMeasureType   = int.Parse(splits[10]);   // Quaternion or dot product angle
                    float            scaleChangedAngled = float.Parse(splits[11]); // How much to scale the change in angle from initial. Increases range of movement.
                    GameObject       angleViewerObj     = Instantiate(AngleViewerInstantiator, this.transform);
                    RFrame_AngleLink angleLinker        = angleViewerObj.GetComponent <RFrame_AngleLink>();
                    angleLinker.centerVertex       = centerVertex;
                    angleLinker.upVertex           = upVertex;
                    angleLinker.measure1           = measure1;
                    angleLinker.measure2           = measure2;
                    angleLinker.linkChannel        = channel;
                    angleLinker.invertedSendAngle  = invertChannel;
                    angleLinker.minimumAngle       = minChannelAngle;
                    angleLinker.maximumAngle       = maxChannelAngle;
                    angleLinker.biasAngle          = biasAngle;
                    angleLinker.angleChangeScaling = scaleChangedAngled;
                    switch (angleMeasureType)
                    {
                    case 0: {
                        angleLinker.angleMeasureType = RFrame_AngleLink.AngleMeasureTypeEnum.quaternionBased;
                        break;
                    }

                    case 1: {
                        angleLinker.angleMeasureType = RFrame_AngleLink.AngleMeasureTypeEnum.lineBased;
                        break;
                    }

                    default: {
                        angleLinker.angleMeasureType = RFrame_AngleLink.AngleMeasureTypeEnum.quaternionBased;
                        break;
                    }
                    }
                    angleViewBuild.Add(angleViewerObj);
                }
                else if (objLine.StartsWith("comprep") && transform.GetComponentInParent <RFrame_Bridge>().displayComponentRepsOnLoad)
                {
                    // Component representation
                    string[]         splits        = objLine.Split(' ');
                    int              centerVertex  = int.Parse(splits[1]);
                    int              upVertex      = int.Parse(splits[2]);
                    int              forwardVertex = int.Parse(splits[3]);
                    string           meshName      = splits[4];
                    float            xRot          = float.Parse(splits[5]);
                    float            yRot          = float.Parse(splits[6]);
                    float            zRot          = float.Parse(splits[7]);
                    float            xTran         = float.Parse(splits[8]);
                    float            yTran         = float.Parse(splits[9]);
                    float            zTran         = float.Parse(splits[10]);
                    GameObject       compRepObj    = Instantiate(ComponentRepresentorInstantiator, this.transform);
                    RFrame_Component componentRep  = compRepObj.GetComponent <RFrame_Component>();
                    componentRep.centerVertex  = centerVertex;
                    componentRep.forwardVertex = forwardVertex;
                    componentRep.upVertex      = upVertex;
                    GameObject meshObject = Instantiate(Resources.Load <GameObject>(meshName), compRepObj.transform);
                    meshObject.transform.localPosition = new Vector3(xTran, yTran, zTran);
                    meshObject.transform.localRotation = Quaternion.Euler(xRot, yRot, zRot);
                }
                else if (objLine.StartsWith("balpos"))
                {
                    // Balance position behaviour module building here
                    string[]             splits            = objLine.Split(' ');
                    int                  vertexAttachIndex = int.Parse(splits[1]);
                    float                reduceRatio       = float.Parse(splits[2]);
                    GameObject           balPolObj         = Instantiate(BalancePositionInstantiator, this.transform);
                    BMod_BalancePosition balPosMod         = balPolObj.GetComponent <BMod_BalancePosition>();
                    balPosMod.restrictionAreaShrinkRatio = reduceRatio;
                    balPosMod.controlVertex = verticesBuild[vertexAttachIndex].GetComponent <RFrame_Vertex>();
                    //balPosMod.controlVertex.lockedInPlace = true;
                    balPosBuild.Add(balPolObj);
                }
                else if (objLine.StartsWith("dishol"))
                {
                    // Distance holder behaviour module building here
                    string[]            splits            = objLine.Split(' ');
                    int                 balPosIndex       = int.Parse(splits[1]);
                    int                 vertexAttachIndex = int.Parse(splits[2]);
                    float               distanceToHold    = float.Parse(splits[3]);
                    int                 typeOfDisHol      = int.Parse(splits[4]);
                    GameObject          disHolObj         = Instantiate(DistanceHolderInstantiator, balPosBuild[balPosIndex].transform);
                    BMod_DistanceHolder disHolMod         = disHolObj.GetComponent <BMod_DistanceHolder>();
                    disHolMod.vertexPoint = verticesBuild[vertexAttachIndex].GetComponent <RFrame_Vertex>();
                    // Experimenting with not locking the vertex in place.
                    // Need to make sure frame doesn't move out of place.
                    disHolMod.vertexPoint.lockedInPlace = true;
                    disHolMod.distanceToHold            = distanceToHold;
                    switch (typeOfDisHol)
                    {
                    case 0: disHolMod.moduleType = BMod_DistanceHolder.DistanceModuleType.groundDistance; break;

                    case 1: disHolMod.moduleType = BMod_DistanceHolder.DistanceModuleType.allRoundDistance; break;

                    default: disHolMod.moduleType = BMod_DistanceHolder.DistanceModuleType.groundDistance; break;
                    }
                    disHolBuild.Add(disHolObj);
                }
                else if (objLine.StartsWith("ancpoi"))
                {
                    // Anchor Point behaviour module building here
                    string[]         splits            = objLine.Split(' ');
                    int              disHolIndex       = int.Parse(splits[1]);
                    int              vertexAttachIndex = int.Parse(splits[2]);
                    int              priorityValue     = int.Parse(splits[3]);
                    int              typeOfAnchor      = int.Parse(splits[4]);
                    GameObject       anchorObj         = Instantiate(AnchorPointInstantiator, disHolBuild[disHolIndex].transform);
                    BMod_AnchorPoint anchorMod         = anchorObj.GetComponent <BMod_AnchorPoint>();
                    anchorMod.anchorVertex = verticesBuild[vertexAttachIndex].GetComponent <RFrame_Vertex>();
                    anchorMod.anchorVertex.lockedInPlace = true;
                    anchorMod.priorityIndex = priorityValue;
                    switch (typeOfAnchor)
                    {
                    case 0: anchorMod.anchorType = BMod_AnchorPoint.AnchorTypeEnum.primaryAnchor; break;

                    case 1: anchorMod.anchorType = BMod_AnchorPoint.AnchorTypeEnum.secondaryAnchor; break;

                    case 2: anchorMod.anchorType = BMod_AnchorPoint.AnchorTypeEnum.tertiaryAnchor; break;

                    default: anchorMod.anchorType = BMod_AnchorPoint.AnchorTypeEnum.primaryAnchor; break;
                    }
                    ancPoiBuild.Add(anchorObj);
                }
            }
            // Set the parents of the objects instatiated to this object and
            // call the function for calculating all the distances between
            // struts.
            if (verticesBuild.Count != 0 && strutBuild.Count != 0)
            {
                // Apply the created vertices and struts to this object.
                // Set the parent of the vertices and struts to the transform of this frame object.
                // foreach (GameObject vertex in verticesBuild) {
                //  vertex.transform.SetParent(this.transform);
                // }
                // foreach (GameObject strut in strutBuild) {
                //  strut.transform.SetParent(this.transform);
                // }
                allVertices = verticesBuild;
                struts      = strutBuild;
                angleLinks  = angleViewBuild;
                compReps    = compRepBuild;
                this.calculateDistancesThenOrientate();
                // Get the initial measured angles for each angle link.
                foreach (GameObject angleLinkObj in angleViewBuild)
                {
                    angleLinkObj.GetComponent <RFrame_AngleLink>().measureAngle(true);
                }
                //frame.gatherBounds();
            }
        }