// This method is for when the system starts up fresh and hasn't // positioned the legs in any way. // 1 Enumerate the Distance holders into an array. // 2 Project thier position onto the ground plane/surface // 3 Use the projections to form a movement restriction region // 4 Apply paired anchor points to project positions. // 5 Calculate anchor position radii void startUpSequence() { // Collect distance holders if (distanceHolders == null) { distanceHolders = GetComponentsInChildren <BMod_DistanceHolder>(); } // Proceed if there are distance holders defined updateRestrictionRegion(true); // Place anchor points at the projected ground positions for each anchor points parent distance holder int layerMask = 1 << 8; RaycastHit strikePoint; Vector3 centerPoint = new Vector3(); bool centerPointFound = false; // Project the attached vertex position down to the ground as a centre point. if (Physics.Raycast(controlVertex.transform.position, -Vector3.up, out strikePoint, 200.0f, layerMask)) { centerPoint = strikePoint.point; centerPointFound = true; biasCentreTrack = centerPoint; // Update the roving centre point. } List <BMod_AnchorPoint> anchorList = new List <BMod_AnchorPoint>(); foreach (BMod_DistanceHolder distanceHolder in distanceHolders) { // Get the anchor point attached to this distance holder BMod_AnchorPoint anchorPoint = distanceHolder.transform.GetComponentInChildren <BMod_AnchorPoint>(); if (anchorPoint != null) { anchorList.Add(anchorPoint); // Set down the anchor points to be scaled out slightly from the centre point if (centerPointFound) { Vector3 anchorPosition = ((distanceHolder.projectedGroundPosition - centerPoint) * dropAreaRatio) + centerPoint; anchorPoint.lockedPosition = anchorPosition; } else { anchorPoint.lockedPosition = distanceHolder.projectedGroundPosition; } anchorPoint.dropPosition = anchorPoint.lockedPosition; anchorPoint.unlockedPosition = distanceHolder.preferredUnlockPosition; anchorPoint.currentAction = BMod_AnchorPoint.AnchorCurrentActionEnum.movingToStartingLockPosition; } } if (anchorList.Count > 0) { anchorPoints = anchorList.ToArray(); } }
void updateRestrictionRegion(bool startUpSequence) { if (distanceHolders != null) { // Call their project routines // Collect each projected distance holder point into a array. List <Vector3> collectVectors = new List <Vector3>(); Vector3 sumVector = new Vector3(); foreach (BMod_DistanceHolder distanceHolder in distanceHolders) { distanceHolder.updateProjectionValues(); if (startUpSequence) { collectVectors.Add(distanceHolder.projectedGroundPosition); sumVector = sumVector + distanceHolder.projectedGroundPosition; } else { // Use anchor point if locked. BMod_AnchorPoint anchorPoint = distanceHolder.transform.GetComponentInChildren <BMod_AnchorPoint>(); if (anchorPoint != null) { if (anchorPoint.lockedInPosition && anchorPoint.currentAction != BMod_AnchorPoint.AnchorCurrentActionEnum.waitingForBalance) { collectVectors.Add(anchorPoint.lockedPosition); sumVector = sumVector + anchorPoint.lockedPosition; } } } } // Form restriction region from collected ground positions. // Should an actual 3D object be created that's really tall? Vector3 centrePoint = sumVector / collectVectors.Count; biasMovementRestrictionArea = new List <Vector3>(); // Shrink each vector towards the centre point. foreach (Vector3 workVector in collectVectors) { Vector3 scaledVector = ((workVector - centrePoint) * restrictionAreaShrinkRatio) + centrePoint; biasMovementRestrictionArea.Add(scaledVector); } // Build a line renderer LineRenderer debugLineDraw = GetComponent <LineRenderer>(); if (debugLineDraw != null) { Vector3[] positions = biasMovementRestrictionArea.ToArray(); debugLineDraw.positionCount = biasMovementRestrictionArea.Count; // Set position count first debugLineDraw.SetPositions(positions); } } }
// Update is called once per frame void Update() { // TODO Balance position needs to be upgraded to use a centre of balance // system, where the body is tilted and shifted as needed. // Process each of the distance holder and anchor points attached to this // class. if (restrictedMovementAreaUpdateRequired) { updateRestrictionRegion(false); restrictedMovementAreaUpdateRequired = false; } // Control pad movement float hozAxis = Input.GetAxis("Horizontal") * maxSlideMovementSpeed; float verAxis = Input.GetAxis("Vertical") * maxSlideMovementSpeed; noncumulativeOffset.x = Input.GetAxis("Horizontal"); noncumulativeOffset.z = Input.GetAxis("Vertical"); float keyBiasOffset = 0.5f; // This goes towards how far forward the anchor point // is positioned in the direction of movement for keyboard based control. // Collect bias from external controls if (Input.GetKey(KeyCode.UpArrow)) { slideOffset.z = slideOffset.z + (maxSlideMovementSpeed * Time.deltaTime); noncumulativeOffset.z = keyBiasOffset; noncumulativeOffset.x = 0.0f; } if (Input.GetKey(KeyCode.DownArrow)) { slideOffset.z = slideOffset.z - (maxSlideMovementSpeed * Time.deltaTime); noncumulativeOffset.z = -keyBiasOffset; noncumulativeOffset.x = 0.0f; } if (Input.GetKey(KeyCode.LeftArrow)) { slideOffset.x = slideOffset.x + (maxSlideMovementSpeed * Time.deltaTime); noncumulativeOffset.z = 0.0f; noncumulativeOffset.x = keyBiasOffset; } if (Input.GetKey(KeyCode.RightArrow)) { slideOffset.x = slideOffset.x - (maxSlideMovementSpeed * Time.deltaTime); noncumulativeOffset.z = 0.0f; noncumulativeOffset.x = -keyBiasOffset; } // Controls switches bool isLeaningSwitch = Input.GetButton("Button_R"); bool isNoLegLiftingSwitch = Input.GetButton("Button_L"); // Manual leg lifting button presses int anchorLift = -1; if (Input.GetButtonDown("Button_A")) { anchorLift = 0; } if (Input.GetButtonDown("Button_B")) { anchorLift = 1; } if (Input.GetButtonDown("Button_X")) { anchorLift = 3; } if (Input.GetButtonDown("Button_Y")) { anchorLift = 2; } if (anchorLift != -1) { BMod_AnchorPoint anchorPoint = anchorPoints[anchorLift]; anchorPoint.needsToLift = true; } //Debug.Log("Hoz " + hozAxis + ", Ver " + verAxis); // Only apply horizontal and vertical slide axis if bal pos is ready for work if (balPosWorkingStatus == balPolStatusEnum.readyForWork) { slideOffset.x = slideOffset.x + (hozAxis * Time.deltaTime); slideOffset.z = slideOffset.z + (verAxis * Time.deltaTime); } // Rotation around centre point slide calculations here float rotAxis = Input.GetAxis("Hoz Rotate") * rotationDegreeDelta; // Calculate the restriction centre and compare with the actual roving centre. Vector3 biasActualCentre = new Vector3(); foreach (Vector3 biasVector in biasMovementRestrictionArea) { biasActualCentre = biasActualCentre + biasVector; } biasActualCentre = biasActualCentre / biasMovementRestrictionArea.Count; if (Vector3.Distance(biasCentreTrack, biasActualCentre) > 0.0f) { // If the centre if off then the robot is adjusting its balance balPosWorkingStatus = balPolStatusEnum.adjustingBalance; Vector3 biasMoved = Vector3.MoveTowards(biasCentreTrack, biasActualCentre, maxSlideMovementSpeed * Time.deltaTime); slideOffset = slideOffset + (biasCentreTrack - biasMoved) * 1.2f; // Boost the movement // Move the bias centre. biasCentreTrack = biasCentreTrack - (biasCentreTrack - biasMoved); if (biasCentreRepresentation != null) { biasCentreRepresentation.transform.position = biasCentreTrack; } } else { // If the balance point has been reached then declare ready for work, unless still in the start up sequence. if (balPosWorkingStatus != balPolStatusEnum.startingUp) { balPosWorkingStatus = balPolStatusEnum.readyForWork; } } // Roll through the anchor points and collect the limit reached offset vectices foreach (BMod_AnchorPoint anchorPoint in anchorPoints) { // Only pull from the ones locked in place if (anchorPoint.lockedInPosition) { Vector3 limitCorrection = anchorPoint.limitReachCorrectionVector(); slideOffset.x = slideOffset.x + limitCorrection.x; slideOffset.z = slideOffset.z + limitCorrection.z; } } // Update position sliders (Anchor points for now) with acceleration bias. // Only allow movement when balanced. if ((previousSlideOffset != slideOffset || rotAxis != 0.0f) && !isLeaningSwitch && anchorPoints != null) { // Apply the slide and rotation changes to the anchor points. float angleRad = rotAxis * rotationDegreeDelta * Mathf.Deg2Rad; // Changed rotationDegreeDelta to movementSpeed foreach (BMod_AnchorPoint anchorPoint in anchorPoints) { if (anchorPoint.lockedInPosition) { // Only apply offset as translation difference from previous offset if the anchor is locked. Vector3 rotationOffset = Vector3.zero; if (rotAxis != 0.0f) { // Rotation offset Vector3 currentPosition = anchorPoint.anchorVertex.transform.position; // The current position should be a vector from x = 0, z = 0. So be applying a rotation // to the current position and keeping the offset, this should work as a way of creating rotation. float xVal = currentPosition.x * Mathf.Cos(angleRad) - currentPosition.z * Mathf.Sin(angleRad); float yVal = currentPosition.y; // We're not changing the height. Future versions may need to height check. float zVal = currentPosition.x * Mathf.Sin(angleRad) + currentPosition.z * Mathf.Cos(angleRad); rotationOffset = (new Vector3(xVal, yVal, zVal)) - currentPosition; } anchorPoint.anchorVertex.offset += (slideOffset - previousSlideOffset) + rotationOffset; // Apply the change in offset } } previousSlideOffset = slideOffset; } // Check if any anchors have reached thier drop points. checkForCompletedAnchors(); // If the counter bias has zero movement then any anchor points waiting for // release can be processed. // Check if prevent lift button is not pressed if (!isNoLegLiftingSwitch) { checkForReleaseableAnchors(); } //else { // Debug.Log("Button R pressed held"); // } // Adjust distance holder offsets float crouchAxis = Input.GetAxis("Crouch") * crouchRange; if (distanceHolders != null) { if (isLeaningSwitch) { // This is to allow the rotational leaning of the robot. Vector3 leanAxis = new Vector3(-Input.GetAxis("Hoz Rotate"), 0.0f, Input.GetAxis("Crouch")); leanAxis = leanAxis * 1.5f; // Increase the movement range foreach (BMod_DistanceHolder distanceHolder in distanceHolders) { Vector3 distHold = distanceHolder.vertexPoint.transform.position; Vector3 groundHolder = new Vector3(distHold.x, 0.0f, distHold.z); float distToCentre = Vector3.Distance(biasActualCentre, groundHolder); float distToTracked = Vector3.Distance(biasActualCentre + leanAxis, groundHolder); float ratioAlt = distToTracked / distToCentre; float tiltOffset = 0.0f; if (ratioAlt != 1.0) { tiltOffset = distanceHolder.distanceToHold - (distanceHolder.distanceToHold * ratioAlt); } distanceHolder.distanceToHoldOffset = tiltOffset; } } else { // Alter the height of each distance holder by the crouch axis foreach (BMod_DistanceHolder distanceHolder in distanceHolders) { distanceHolder.distanceToHoldOffset = crouchAxis; } } } }
void checkForReleaseableAnchors() { // Cycle through anchor points to check for any that need to be released. // Priority given to those furthest away from this balance position, which any tied then on priority value. if (anchorPoints != null) { BMod_AnchorPoint anchorToUnlock = null; int unlockedCount = 0; List <BMod_AnchorPoint> requestors = new List <BMod_AnchorPoint>(); foreach (BMod_AnchorPoint anchor in anchorPoints) { if (anchor.needsToLift) { requestors.Add(anchor); } if (anchor.lockedInPosition == false || anchor.currentAction == BMod_AnchorPoint.AnchorCurrentActionEnum.waitingForBalance) { unlockedCount++; } } // Only proceed if there's less anchor points unlocked than the maximum allowed. if (unlockedCount < maxReleasable && requestors.Count > 0) { if (requestors.Count > maxReleasable) { // Filter by distance and then by priority if needed. // Distance is how far from original lock position // Use a dictionary with the distance rounded to whole number. If a duplicat entry exists, // it is overriden if the duplcate has a lower priority level. // Dictionary is then sorted highest to lowest and first entry taken out. Dictionary <int, BMod_AnchorPoint> distanceAnchors = new Dictionary <int, BMod_AnchorPoint>(); foreach (BMod_AnchorPoint anchorCheck in requestors) { // Only working with ground height of zero for the distances for now. // Was used originally as part of the pushing through the ground test. Vector3 nonHeightAnchor = new Vector3(anchorCheck.anchorVertex.transform.position.x, 0.0f, anchorCheck.anchorVertex.transform.position.z); int distanceToOriginalLockPoint = Mathf.RoundToInt(Vector3.Distance(anchorCheck.lockedPosition, nonHeightAnchor) * 10.0f); if (distanceAnchors.ContainsKey(distanceToOriginalLockPoint)) { if (distanceAnchors[distanceToOriginalLockPoint].priorityIndex < anchorCheck.priorityIndex) { // Replace original anchor point distanceAnchors[distanceToOriginalLockPoint] = anchorCheck; } } else { distanceAnchors.Add(distanceToOriginalLockPoint, anchorCheck); } } // Loop through keys and find the largest distance int maxDistanceFound = -99; foreach (int keyEntry in distanceAnchors.Keys) { if (keyEntry > maxDistanceFound) { maxDistanceFound = keyEntry; } } // If a distance was found that wasn't the initialiser number then assign for unlocking. if (maxDistanceFound != -99) { anchorToUnlock = distanceAnchors[maxDistanceFound]; } } else { // Allow the anchor to be unlocked. anchorToUnlock = requestors[0]; } } // If an anchor point was found to release, then unlock it. // Safety check status will need to be implemented to allow centre point time to move // within restriction zone if restricted area shrinks past it. if (anchorToUnlock != null) { anchorToUnlock.currentAction = BMod_AnchorPoint.AnchorCurrentActionEnum.waitingForBalance; balPosWorkingStatus = balPolStatusEnum.adjustingBalance; // Make sure this is called. //anchorToUnlock.lockedInPosition = false; anchorToUnlock.needsToLift = false; Vector3 nonHeightAnchor = new Vector3(anchorToUnlock.anchorVertex.transform.position.x, 0.0f, anchorToUnlock.anchorVertex.transform.position.z); Vector3 currentPosition = nonHeightAnchor; // Update the unlock position to be slightly above the current position anchorToUnlock.unlockedPosition = new Vector3(currentPosition.x, currentPosition.y + anchorLiftHeight, currentPosition.z); restrictedMovementAreaUpdateRequired = true; } } }
/** * 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(); } }