// Use this for initialization void Start() { arcLength = 0; measuredArc = 0; transform.position = TelescopeUtils.TranslateAlongHelix(curvature, torsion, arcLength); transform.rotation = TelescopeUtils.RotateAlongHelix(curvature, torsion, arcLength); }
public void MakeShellsFromDiffs(List <TelescopeParameters> diffs) { initNumShells = diffs.Count; parameters = diffs; shells = new List <TelescopeShell>(); initialDirection.Normalize(); // Compute the absolute parameter values from the list of diffs we are given. List <TelescopeParameters> concreteParams = new List <TelescopeParameters>(); TelescopeParameters theParams = diffs[0]; concreteParams.Add(new TelescopeParameters(diffs[0])); for (int i = 1; i < initNumShells; i++) { if (diffs[i].radius > -wallThickness) { diffs[i].radius = -wallThickness; } theParams = theParams + diffs[i]; theParams.length -= 0; // wallThickness; //theParams.radius -= wallThickness; concreteParams.Add(theParams); } // Make sure the final shell is greater than the minimum possible width. if (concreteParams[concreteParams.Count - 1].radius < wallThickness) { concreteParams[concreteParams.Count - 1].radius = wallThickness; } // Make sure that all the shells fit inside each other. TelescopeUtils.growChainToFit(concreteParams); MakeShellsFromFinalList(concreteParams); }
public TelescopeShell addChildShell(TelescopeShell parent, TelescopeParameters parentParams, TelescopeParameters childParams, TelescopeParameters nextParams, bool isNotLast) { int i = shells.Count; // Make the new shell, and set the previous shell as its parent GameObject shellObj = new GameObject(); shellObj.transform.parent = parent.transform; shellObj.name = name + "-shell" + i; // Make the geometry, etc. TelescopeShell newShell = shellObj.AddComponent <TelescopeShell>(); newShell.GenerateGeometry(childParams, nextParams, doOverhang: true); newShell.setMaterial(material); // Set the shell's rest transformation relative to its parent. // When the shell's current extension ratio is 0, this is where // it is located relative to its parent. // newShell.baseRadians = newShell.radiansOfLength(wallThickness); newShell.baseTranslation = TelescopeUtils.childBasePosition(parentParams, childParams); newShell.baseRotation = TelescopeUtils.childBaseRotation(parentParams, childParams); shells.Add(newShell); shellObj.layer = 8; newShell.containingSegment = this; return(newShell); }
CylinderMesh GenerateInnerCylinder(TelescopeParameters nextParams, bool overhang, float arcOffset, int extraRings = 0) { TelescopeParameters ourParams = getParameters(); CylinderMesh innerCyl; // If there is a change in profile from this shell to the next... if (nextParams != null && (nextParams.curvature != curvature || nextParams.torsion != torsion || nextParams.radius < radius - Constants.WALL_THICKNESS * 1.01f)) { // Generate the outer profile of the child shell; this will become // the inner profile of this shell. TelescopeParameters innerParams = new TelescopeParameters(nextParams.length, nextParams.radius, nextParams.thickness, nextParams.curvature, nextParams.torsion, nextParams.twistFromParent); innerCyl = GenerateCylinder(innerParams, Constants.TAPER_SLOPE, innerGroove: true, overhang: overhang, extraRings: extraRings); // Move and rotate the inner profile so that the end circles align. Quaternion alignRotation = TelescopeUtils.childBaseRotation(ourParams, nextParams); Vector3 alignTranslation = TelescopeUtils.childBasePosition(ourParams, nextParams); Quaternion backRotation = TelescopeUtils.RotateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); Vector3 backTranslation = TelescopeUtils.TranslateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); innerCyl.ApplyRotation(backRotation); innerCyl.ApplyTranslation(backTranslation); innerCyl.ApplyRotation(alignRotation); innerCyl.ApplyTranslation(alignTranslation); } else { TelescopeParameters innerParams = new TelescopeParameters(length, radius - thickness, thickness, curvature, torsion, 0); innerCyl = GenerateCylinder(innerParams, Constants.TAPER_SLOPE, innerGroove: (nextParams != null), overhang: overhang, extraRings: extraRings); if (nextParams != null) { Quaternion backRotation = TelescopeUtils.RotateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); Vector3 backTranslation = TelescopeUtils.TranslateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); innerCyl.ApplyRotation(backRotation); innerCyl.ApplyTranslation(backTranslation); } } return(innerCyl); }
Vector3 TransformedHelixPoint(CurveSegment cs, float arcLen) { // Get the helix point in local coordinates Vector3 helixPoint = TelescopeUtils.TranslateAlongHelix(cs.curvature, cs.torsion, arcLen); // Transform to world Quaternion rotateToWorld = Quaternion.LookRotation(cs.frame.T, cs.frame.N); Vector3 world = rotateToWorld * helixPoint + cs.startPosition; return(world); }
Vector3 StartEndpointCC(float angleOffset) { Vector3 circumBegin = TelescopeUtils.Circumcenter(points[1], points[2], points[3]); Vector3 normalBegin = Vector3.Cross(points[2] - points[1], points[3] - points[1]); Vector3 beginOffset = points[1] - circumBegin; Vector3 rotatedBegin = Quaternion.AngleAxis(-angleOffset, normalBegin) * beginOffset + circumBegin; //Vector3 diffBegin = (rotatedBegin - points[1]).normalized * 0.1f; return(rotatedBegin); }
public void MakeShellsFromConcrete(List <TelescopeParameters> concreteParams) { initNumShells = concreteParams.Count; shells = new List <TelescopeShell>(); initialDirection.Normalize(); // Make sure that all the shells fit inside each other. TelescopeUtils.growChainToFit(concreteParams); MakeShellsFromFinalList(concreteParams); }
OrthonormalFrame TransformedHelixFrame(CurveSegment cs, float arcLen) { // Apply the local helix rotation. Quaternion oldRot = Quaternion.LookRotation(cs.frame.T, cs.frame.N); Quaternion newRot = oldRot * TelescopeUtils.RotateAlongHelix(cs.curvature, cs.torsion, arcLen) * Quaternion.Inverse(oldRot); OrthonormalFrame newFrame = cs.frame.RotatedBy(newRot); return(newFrame); }
public void ShrinkToFit() { if (selected) { TelescopeSegment segment = selected.containingSegment; List <TelescopeParameters> allParams = segment.getParamList(); TelescopeUtils.growChainToFit(allParams, shrinkFit: true); segment.MakeAllShells(allParams); segment.SetShellExtensions(1); selected = null; } }
Vector3 EndEndpointCC(float angleOffset) { int last = points.Count - 1; Vector3 circumEnd = TelescopeUtils.Circumcenter(points[last - 1], points[last - 2], points[last - 3]); Vector3 normalEnd = Vector3.Cross(points[last - 2] - points[last - 1], points[last - 3] - points[last - 1]); Vector3 endOffset = points[last - 1] - circumEnd; Vector3 rotatedEnd = Quaternion.AngleAxis(-angleOffset, normalEnd) * endOffset + circumEnd; //Vector3 diffEnd = (rotatedEnd - points[last - 1]).normalized * 0.1f; return(rotatedEnd); }
// Update is called once per frame void Update() { arcLength += Time.deltaTime; Vector3 pos = TelescopeUtils.TranslateAlongHelix(curvature, torsion, arcLength); float diff = Vector3.Distance(pos, transform.position); measuredArc += diff; transform.position = pos; transform.rotation = TelescopeUtils.RotateAlongHelix(curvature, torsion, arcLength); velocity = diff / Time.deltaTime; }
float AverageCurvature() { // Get the average curvature of this curve float averageCurvature = 0; foreach (DCurvePoint dcp in discretizedPoints) { averageCurvature += dcp.bendingAngle * Mathf.Deg2Rad; } averageCurvature /= discretizedPoints.Count; averageCurvature = TelescopeUtils.CurvatureOfDiscrete(averageCurvature, segmentLength); return(averageCurvature); }
public OrthonormalFrame PropagateBishop(Vector3 prevPos, Vector3 nextPos, OrthonormalFrame prevFrame) { Vector3 tangent = (nextPos - position).normalized; Vector3 prevTangent = (position - prevPos).normalized; Vector3 binormal = Vector3.Cross(prevTangent, tangent).normalized; float angle = TelescopeUtils.AngleBetween(prevTangent, tangent, binormal); Quaternion rotation = Quaternion.AngleAxis(angle, binormal); OrthonormalFrame rotated = prevFrame.RotatedBy(rotation); bishopFrame = rotated; return(rotated); }
public static void growChainToFit(List <TelescopeParameters> parameters, bool shrinkFit = false) { // Make a pass in reverse that grows each parent so that it is large enough // to contain its child. for (int i = parameters.Count - 1; i > 0; i--) { if (parameters[i - 1].torsion != 0 || parameters[i].torsion != 0) { TelescopeUtils.growParentToChildHelix(parameters[i - 1], parameters[i], shrinkFit); } else { TelescopeUtils.growParentToChild(parameters[i - 1], parameters[i], shrinkFit); } } }
/// <summary> /// Create a set of vertices arranged evenly spaced in a circle, with the specified radius, /// centered at centerPoint, and with the specified normal direction. The number of vertices /// is given by verticesPerCircle. /// </summary> /// <param name="centerPoint"></param> /// <param name="direction"></param> /// <param name="radius"></param> /// <returns></returns> List <IndexedVertex> GenerateCircle(int circNum, Vector3 centerPoint, Vector3 direction, Vector3 normal, float radius, bool addInnerGrooves = false, bool addOuterGroove = false) { float angleStep = (2 * Mathf.PI) / Constants.VERTS_PER_CIRCLE; float degreeStep = angleStep * Mathf.Rad2Deg; int twistCuts = Mathf.CeilToInt(Mathf.Abs(nextTwistAngle) / degreeStep); twistCuts *= Mathf.RoundToInt(Mathf.Sign(nextTwistAngle)); List <IndexedVertex> verts = new List <IndexedVertex>(); int grooveRange = Constants.GROOVE_CUT_RADIUS; // First create points in a circle in the XY plane, facing the forward direction. // Then apply the rotation that will rotate the normal onto the desired direction. // Finally, offset it in space to the desired location. Quaternion circleRotation = Quaternion.FromToRotation(Vector3.forward, direction); Vector3 initNormal = Vector3.up; Vector3 rotatedNormal = circleRotation * initNormal; float angle = TelescopeUtils.AngleBetween(rotatedNormal, normal, direction); Quaternion normalRotation = Quaternion.AngleAxis(angle, direction); for (int i = 0; i < Constants.VERTS_PER_CIRCLE; i++) { float currentAngle = i * angleStep; float radiusOffset = 0; if (i < grooveRange || Mathf.Abs(i - Constants.VERTS_PER_CIRCLE / 2) < grooveRange || Mathf.Abs(i - Constants.VERTS_PER_CIRCLE) < grooveRange) { if (addInnerGrooves) { radiusOffset = (thickness - Constants.SHELL_GAP) * Constants.INDENT_RATIO; } else if (addOuterGroove) { radiusOffset = (thickness - Constants.SHELL_GAP / 2) * Constants.INDENT_RATIO; } } else if (circNum >= Constants.CUTS_PER_CYLINDER - 1 && circNum < Constants.CUTS_PER_CYLINDER + Constants.FIN_CUTS) { if (addInnerGrooves && (IsInRadius(i, 0, twistCuts, grooveRange) || IsInRadius(i, Constants.VERTS_PER_CIRCLE, Constants.VERTS_PER_CIRCLE + twistCuts, grooveRange) || IsInRadius(i, Constants.VERTS_PER_CIRCLE / 2, Constants.VERTS_PER_CIRCLE / 2 + twistCuts, grooveRange))) { radiusOffset = (thickness - Constants.SHELL_GAP) * Constants.INDENT_RATIO; } } // Make the vertices in clockwise order Vector3 vert = new Vector3(Mathf.Cos(currentAngle), -Mathf.Sin(currentAngle)); // Scale by radius. vert *= (radius + radiusOffset); // Rotate it to orbit the desired direction. vert = circleRotation * vert; // Rotate it again so that the curvature normal is aligned. vert = normalRotation * vert; // Offset in space to the center point. vert += centerPoint; IndexedVertex iv = new IndexedVertex(vert, currentIndex); currentIndex++; verts.Add(iv); } return(verts); }
public Quaternion rotationOfDistance(float arcLength, float curvature, float torsion) { return(TelescopeUtils.RotateAlongHelix(curvature, torsion, arcLength)); }
Vector3 translationOfDistance(float arcLength, float curvature, float torsion) { return(TelescopeUtils.TranslateAlongHelix(curvature, torsion, arcLength)); }
// Compute all internal bending axes/angles from a list of points. public void InitFromPoints(List <Vector3> points, float segLength) { segmentLength = segLength; StartingPoint = points[0]; startingTangent = points[1] - points[0]; startingTangent.Normalize(); discretizedPoints = new List <DCurvePoint>(); Vector3 prevBinormal = Vector3.zero; // We need to store bending angles / directions of all the interior // vertices of the curve (but not the endpoints). for (int i = 1; i < points.Count - 1; i++) { Vector3 previousVec = points[i] - points[i - 1]; Vector3 nextVec = points[i + 1] - points[i]; previousVec.Normalize(); nextVec.Normalize(); // If zero, then treat it as a straight segment if (nextVec.magnitude < 0.5f) { DCurvePoint d = new DCurvePoint(prevBinormal, 0, 0); discretizedPoints.Add(d); continue; } Vector3 curvatureBinormal = Vector3.Cross(previousVec, nextVec).normalized; if (i == 1) { startingBinormal = curvatureBinormal; } // Compute bending angles (discrete curvature). float dot = Vector3.Dot(previousVec, nextVec); float bendAngle = (dot >= 1) ? 0 : Mathf.Rad2Deg * Mathf.Acos(dot); // Compute twisting angles (discrete torsion). float twistAngle; // Compute twist angles as we go along. // The first vertex is considered to have no twist. if (i == 1) { twistAngle = 0; } else { twistAngle = TelescopeUtils.AngleBetween(prevBinormal, curvatureBinormal, previousVec); // If the bend angle is tiny, then the curve is basically straight, so // just set twist values to 0 to avoid unnecessary twisting. /*if (Mathf.Abs(bendAngle) <= 0.1) * { * bendAngle = 0; * twistAngle = 0; * }*/ } if (float.IsNaN(bendAngle)) { throw new System.Exception("Bend angle is nan, dot = " + dot); } if (float.IsNaN(twistAngle)) { throw new System.Exception("Twist angle is nan"); } prevBinormal = curvatureBinormal; DCurvePoint dcp = new DCurvePoint(curvatureBinormal.normalized, bendAngle, twistAngle); discretizedPoints.Add(dcp); } if (startingBinormal.magnitude < 0.001f) { if (startingTangent == Vector3.up) { startingBinormal = Vector3.right; } else { startingBinormal = Vector3.up; Vector3 orthogonal = Vector3.Dot(startingBinormal, startingTangent) * startingTangent; startingBinormal = startingBinormal - orthogonal; startingBinormal.Normalize(); } } targetEndPoint = ReconstructFromAngles(); ComputeFrenetFrames(); ComputeBishopFrames(); }
// Update is called once per frame void Update() { if (ReversedOption != Reversed) { ReverseTelescope(); Reversed = ReversedOption; } if (Input.GetKeyDown("[")) { List <Vector3> pts = new List <Vector3>(); pts.Add(BasePointAtCenter); pts.Add(BasePointOnSurface); TelescopeUtils.DisplayLine(pts); } /* * if (Input.GetKey("left shift") && Input.GetKeyDown("enter")) * { * ExtendImmediate(0); * * STLWriter.WriteSTLOfSegment(this, WorldSpaceMin - new Vector3(0.01f, 0.01f, 0.01f), name + ".stl"); * * Mesh volume = shells[0].GenerateInnerVolume(shells[1].getParameters(), -0.5f); * GameObject innerVolume = new GameObject(); * MeshFilter mf = innerVolume.AddComponent<MeshFilter>(); * innerVolume.AddComponent<MeshRenderer>().material = DesignerController.instance.defaultTelescopeMaterial; * mf.mesh = volume; * * innerVolume.transform.parent = shells[0].transform; * innerVolume.transform.localPosition = Vector3.zero; * innerVolume.transform.localRotation = Quaternion.identity; * * //shells[0].ReplaceMesh(volume); * * for (int i = 1; i < shells.Count; i++) * { * shells[i].GetComponent<MeshRenderer>().enabled = false; * } * * //STLWriter.WriteSTLOfMesh(shells[0].mesh, "scad/innerVolume.stl"); * } */ if (rootSegment) { if (Input.GetKeyDown("e")) { ExtendTo(1, Mathf.Log(shells.Count)); } else if (Input.GetKeyDown("q")) { ExtendTo(0, Mathf.Log(shells.Count)); } } if (currentlyInterp) { extensionTime += Time.deltaTime; currentExtension = Mathf.Lerp(oldExtension, targetExtension, extensionTime / extensionTimespan); if (extensionTime >= extensionTimespan) { currentlyInterp = false; currentExtension = targetExtension; } SetShellExtensions(currentExtension); } for (int i = 1; i < shells.Count; i++) { shells[i].SetTransform(); } if (Input.GetKeyDown("/")) { List <Vector3> firstRing = FirstVertRing; List <Vector3> lastRing = LastVertRing; foreach (Vector3 v in firstRing) { GameObject g = GameObject.CreatePrimitive(PrimitiveType.Sphere); g.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); g.transform.position = v; } foreach (Vector3 v in lastRing) { GameObject g = GameObject.CreatePrimitive(PrimitiveType.Sphere); g.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); g.transform.position = v; } } }