public void AddVert(SplineNode vert) { Length++; if(!vert.next) end = vert; if(!vert.previous) begin = vert; }
public bool FindEnds() { SplineNode[] nodes = GetComponentsInChildren<SplineNode>(); if(!begin) foreach(SplineNode node in nodes) if(!node.previous) begin = node; if(!end) foreach(SplineNode node in nodes) if(!node.next) end = node; return begin || end; }
} ///< Returns the normlaized length of the segment in the spline. /// <summary> /// Initializes a new instance of the <see cref="SplineSegment"/> class. /// </summary> /// <param name='pSpline'> /// The spline that contains the segment. /// </param> /// <param name='sNode'> /// The segment's start node. /// </param> /// <param name='eNode'> /// The segment's end node. /// </param> /// <exception cref='ArgumentNullException'> /// Is thrown when pSpline is null /> . /// </exception> public SplineSegment( Spline pSpline, SplineNode sNode, SplineNode eNode ) { if( pSpline != null ) { parentSpline = pSpline; startNode = sNode; endNode = eNode; } else { throw new ArgumentNullException( "Parent Spline must not be null" ); } }
public virtual void Start() { if(gravSpline) { //If the user has specified a gravity spline, set it up gravNode = gravSpline.begin; gravPosition = gravNode.transform.position; } if(currentSpline) { currentSpline.followers.Add(this); if(startOnVert) { groundNode = currentSpline[startVert]; if(groundNode) transform.position = groundNode.transform.position; } } }
private void GetCatMullTangentsInternal( SplineNode firstNode, ref Vector3 P1, ref Vector3 P2, out Vector3 T1, out Vector3 T2 ) { switch( tangentMode ) { case TangentMode.UseTangents: T1 = firstNode.PrevNode0.nodeTransform.position; T2 = firstNode.NextNode1.nodeTransform.position; T1.x = (P2.x - T1.x) * tension; T1.y = (P2.y - T1.y) * tension; T1.z = (P2.z - T1.z) * tension; T2.x = (T2.x - P1.x) * tension; T2.y = (T2.y - P1.y) * tension; T2.z = (T2.z - P1.z) * tension; return; case TangentMode.UseNodeForwardVector: T1 = firstNode.nodeTransform.forward * tension; T2 = firstNode.NextNode0.nodeTransform.forward * tension; return; default: T1 = firstNode.PrevNode0.nodeTransform.position; T2 = firstNode.NextNode1.nodeTransform.position; T1.x = (P2.x - T1.x); T1.y = (P2.y - T1.y); T1.z = (P2.z - T1.z); T2.x = (T2.x - P1.x); T2.y = (T2.y - P1.y); T2.z = (T2.z - P1.z); T1.Normalize( ); T2.Normalize( ); T1.x *= tension; T1.y *= tension; T1.z *= tension; T2.x *= tension; T2.y *= tension; T2.z *= tension; return; } }
// -------------------------------------------------------------------------------------------- // PRIVATE HELPERS // -------------------------------------------------------------------------------------------- float GetDuration(SplineNode[] info) { float endTime = -TimeBetweenAdjacentNodes; foreach (SplineNode e in info) endTime += TimeBetweenAdjacentNodes + e.BreakTime; return endTime; }
private void GetAdjacentNodes( SegmentParameter sParam, out SplineNode node0, out SplineNode node1, out SplineNode node2, out SplineNode node3 ) { switch( interpolationMode ) { case InterpolationMode.BSpline: node0 = GetNode( sParam.normalizedIndex,-1 ); node1 = GetNode( sParam.normalizedIndex, 0 ); node2 = GetNode( sParam.normalizedIndex, 1 ); node3 = GetNode( sParam.normalizedIndex, 2 ); return; case InterpolationMode.Hermite: node0 = GetNode( sParam.normalizedIndex, 0 ); node1 = GetNode( sParam.normalizedIndex, 1 ); node2 = GetNode( sParam.normalizedIndex,-1 ); node3 = GetNode( sParam.normalizedIndex, 2 ); return; case InterpolationMode.Linear: case InterpolationMode.Bezier: default: node0 = GetNode( sParam.normalizedIndex, 0 ); node1 = GetNode( sParam.normalizedIndex, 1 ); node2 = GetNode( sParam.normalizedIndex, 2 ); node3 = GetNode( sParam.normalizedIndex, 3 ); return; } }
private void RecalcScalars( SplineNode node0, SplineNode node1, ref double P2, ref double P3 ) { if( interpolationMode != InterpolationMode.Hermite ) return; P2 = node1.customValue - P2; P3 = P3 - node0.customValue; P2 = P2 * tension; P3 = P3 * tension; }
private SplineNode[] GetAdjacentSegmentNodes( Spline spline, SplineNode node ) { SplineNode[] segmentNodes = spline.SegmentNodes; SplineNode[] returnNodes = new SplineNode[2]; int index = System.Array.IndexOf( segmentNodes, node ); returnNodes[0] = index<=0 ? null : segmentNodes[index-1]; returnNodes[1] = index>=segmentNodes.Length-1 ? null : segmentNodes[index+1]; return returnNodes; }
private IList<Spline> GetSplinesForNode( SplineNode node ) { List<Spline> possibleSplines = new List<Spline>( ); foreach( Spline spline in splines ) { foreach( SplineNode splineNode in spline.SplineNodes ) { if( node == splineNode ) possibleSplines.Add( spline ); } } return possibleSplines; }
bool PreviousNode() { if(groundNode.previous) { groundNode = groundNode.previous; return true; } else { if(currentSpline.previous) { if(currentSpline.previous.end) { currentSpline = currentSpline.previous; groundNode = currentSpline.end; return true; } else Debug.LogWarning("Previous spline missing end"); } } return false; }
internal SplineNode(SplineNode o) { this.gameObject = o.gameObject; Point = o.Point; Rot = o.Rot; Time = o.Time; EaseIO = o.EaseIO; }
protected Vector3 SplineMovement() { if (!groundNode) { return(rigidbody.velocity); } float horizFrameVelocity = 0; switch (mode) { case Mode.KEYBOARD: horizFrameVelocity = (Vector3.Dot(rigidbody.velocity, groundNode.forward.normalized) + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime; break; case Mode.AUTO: horizFrameVelocity = (horizSpeed + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime * (goInReverse ? -1 : 1); if (!ignoreNodes && !ignoreNextNode) { if (horizFrameVelocity > 0 && groundNode.next) //We're moving "forward" and there's a next vert { if (horizFrameVelocity > (rigidbody.position - groundNode.next.transform.position).magnitude) { if (groundNode.next) { if (groundNode.next.fromPrevious) //this node wants to be activated going forward { DoNode(groundNode.next); } } } } else if (groundNode) //We're moving "backward" and there's a previous vert { if (-horizFrameVelocity > (rigidbody.position - groundNode.transform.position).magnitude) { if (groundNode) { if (groundNode.fromNext) //this node wants to be activated going forward { DoNode(groundNode); } } } } horizFrameVelocity = (horizSpeed + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime * (goInReverse ? -1 : 1); } break; } Vector3 position = rigidbody.position; Vector3 newVelocity = rigidbody.velocity; if (horizFrameVelocity != 0) { float distance = Mathf.Abs(horizFrameVelocity); int itercount = MAX_OVER_ITER; int iter = MAX_OVER_ITER; /* * This while loop "adjusts" for any incoming error on groundNode. If the first condition is * met, the node reference is too far forward, and must be decremented. If the second is met, * the opposite is true and the node must be incremented. * niiiiice 8) */ while (iter-- > 0) { if (Vector3.Dot(groundNode.forward, transform.position - groundNode.transform.position) < 0) { if (!PreviousNode()) { Detach(); return(rigidbody.velocity); } continue; } else if (groundNode.next) { if (Vector3.Dot(groundNode.forward, transform.position - groundNode.next.transform.position) > 0) { if (!NextNode()) { Detach(); return(rigidbody.velocity); } continue; } } break; } if (horizFrameVelocity < 0) //If we're going backward, come from the other direction { groundNode = groundNode.next; } if (groundNode) { Debug.DrawLine(transform.position, transform.position + groundNode.forward * horizFrameVelocity, Color.red); //We will loop until we have gone one node past the next desired position while (distance > 0) { if (horizFrameVelocity > 0) //Reaching the next vert going forward { if (!NextNode()) { Detach(); return(rigidbody.velocity); } } if (horizFrameVelocity < 0) //Reaching the previous vert going backward { if (!PreviousNode()) { Detach(); return(rigidbody.velocity); } } //calculate the distance to the next node distance -= (position - groundNode.transform.position).magnitude; //update position to the next node position = groundNode.transform.position; if (itercount-- < 0) { break; } } //This statement is complicated newVelocity = ((position + (position - transform.position).normalized * distance) - transform.position) * (1 / Time.fixedDeltaTime); //if(groundNode.num == 2) // Debug.Log(horizFrameVelocity + ", " + distance + " | " + (transform.position + newVelocity * Time.fixedDeltaTime) + " - " + Time.frameCount); if (horizFrameVelocity > 0) { groundNode = groundNode.previous; } } else { return(rigidbody.velocity); } } else { return(Vector3.zero); } return(newVelocity); }
//Setup Spline Nodes private void SetupSplineNodes(Transform[] transformNodes) { splineNodes = null; //Return if there are no nodes if (transformNodes.Length <= 0) { return; } int effectiveNodes = transformNodes.Length; if (interpolationMode == InterpolationMode.Bezier) { if (transformNodes.Length < 7) { effectiveNodes -= (transformNodes.Length) % 4; } else { effectiveNodes -= (transformNodes.Length - 4) % 3; } if (effectiveNodes < 4) { return; } } else { if (effectiveNodes < 2) { return; } } SplineNode[] newNodes = new SplineNode[effectiveNodes]; for (int i = 0; i < effectiveNodes; i++) { if (transformNodes[i] == null) { return; } newNodes[i] = new SplineNode(transformNodes[i]); } for (int i = 0; i < effectiveNodes; i++) { if (transformNodes[i] == null) { return; } int idxPrevNode0 = i - 1; int idxNextNode0 = i + 1; int idxNextNode1 = i + 2; int idxNextNode2 = i + 3; if (AutoClose) { if (idxPrevNode0 < 0) { idxPrevNode0 = effectiveNodes - 1; } idxNextNode0 %= effectiveNodes; idxNextNode1 %= effectiveNodes; idxNextNode2 %= effectiveNodes; } else { idxPrevNode0 = Mathf.Max(idxPrevNode0, 0); idxNextNode0 = Mathf.Min(idxNextNode0, effectiveNodes - 1); idxNextNode1 = Mathf.Min(idxNextNode1, effectiveNodes - 1); idxNextNode2 = Mathf.Min(idxNextNode2, effectiveNodes - 1); } //Setup adjacent nodes newNodes[i][0] = newNodes[idxPrevNode0]; newNodes[i][1] = newNodes[idxNextNode0]; newNodes[i][2] = newNodes[idxNextNode1]; newNodes[i][3] = newNodes[idxNextNode2]; } splineNodes = newNodes; ReparametrizeCurve( ); }
public bool FindSplineVertex(Spline s, Vector3 a, Vector3 b, out SplineNode vert, out Vector3 position) { return(FindSplineVertex(s, a, b, null, out vert, out position)); }
bool FindSplineVertex(Spline s, Vector3 a, Vector3 b, SplineNode guess, out SplineNode vert, out Vector3 position) { SplineNode countup, countdown; if (s != null) { if (guess == null) { if (!(s.begin && s.end)) { Debug.LogError("Could not find vertex, begin and end not set"); vert = null; position = Vector3.zero; return(false); } countup = s.begin; countdown = s.end; } else { countdown = guess; countup = guess; } Utility.Vector3Pair points; while (countdown != null || countup != null) { if (countup.next != null) { //#if(DEBUG_DRAW||DEBUG_DRAW_LND) Debug.DrawLine(countup.transform.position, countup.next.transform.position, Color.magenta); //#endif points = Utility.Dist3DSegToSeg(a, b, countup.transform.position, countup.next.transform.position); if ((points.a - points.b).magnitude < snapDistance) { //Debug.Log(points.a + ", " + points.b); Debug.DrawLine(points.b, transform.position, Color.magenta); vert = countup; if (looseFollow) { position = transform.position; } else { position = points.b; } return(true); } } countup = countup.next; if (countdown.previous != null) { //#if(DEBUG_DRAW||DEBUG_DRAW_LND) Debug.DrawLine(countdown.transform.position, countdown.previous.transform.position, Color.cyan); //#endif points = Utility.Dist3DSegToSeg(a, b, countdown.transform.position, countdown.previous.transform.position); if ((points.a - points.b).magnitude < snapDistance) { Debug.DrawLine(points.b, transform.position, Color.green); vert = countdown.previous; if (looseFollow) { position = transform.position; } else { position = points.b; } return(true); } } countdown = countdown.previous; } } else { Debug.LogError("Error in land, spline is null"); } Debug.LogWarning("Warning in land - Couldn't find a vert"); vert = null; position = Vector3.zero; return(false); }
/// <summary> /// Rebuilds the mesh for the specified lofting group /// </summary> /// <param name="group">lofting group</param> private void RebuildMesh(LoftingGroup group) { if (!group.IsValid) { throw new ArgumentException("SegmentMesh and MeshFilter can't be null"); } LoftDirection.Normalize(); var result = group.ResultMesh; float segmentStep = group.IntervalLength / group.ActiveSegmentsNumber; for (int s = 0; s < group.ActiveSegmentsNumber; s++) { ManagedMesh segment = group.ResultSegments[s]; segment.Clear(); ManagedMesh source = group.mSegmentMesh; if (s == 0 && group.mStartPiece != null) { source = group.mStartPiece; } if (s == group.ActiveSegmentsNumber - 1 && group.mEndPiece != null) { source = group.mEndPiece; } Vector3 pivotShift = Vector3.Project(source.bounds.center, LoftDirection); Vector3 startSPos = pivotShift - source.bounds.extents.Mul(LoftDirection); Vector3 endSPos = pivotShift + source.bounds.extents.Mul(LoftDirection); Vector3 sourceDir = (endSPos - startSPos); float sourceLenght = sourceDir.magnitude; bool flipSegment = RollerCoasterFix && _flipNext; Vector3 dirS = LoftDirection; Vector3[] sourceVertices = source.vertices; Vector3[] resultVertices = new Vector3[source.vertexCount]; Vector3[] sourceNormals = source.normals; Vector3[] resultNormals = new Vector3[source.vertexCount]; Vector4[] sourceTangents = source.tangents; Vector4[] resultTangents = new Vector4[source.vertexCount]; float segScaler = ((((float)(group.ActiveSegmentsNumber - s) + 1f) / (float)group.ActiveSegmentsNumber) * 2f); //Debug.Log("SegScaler: " + segScaler); for (int i = 0; i < source.vertexCount; i++) { Vector3 curSPos = sourceVertices[i] - startSPos; Vector3 projected = Vector3.Project(curSPos, dirS); Vector3 perp = curSPos - projected; // perp.Scale(SegmentScale); perp.Scale(SegmentScale * segScaler); float sourceT = Mathf.InverseLerp(0f, sourceLenght, projected.magnitude); float resultT = group.StartPosition + segmentStep * s + segmentStep * sourceT; int nodeIndex; float nodeT = GetNodeT(resultT, out nodeIndex); if (nodeIndex < 0) { nodeIndex = 0; } else if (nodeIndex > Nodes.Count - 1) { nodeIndex = Nodes.Count - 1; } int nextIndex = nodeIndex + 1; if (nodeIndex >= Nodes.Count - 1) { if (Loop) { nextIndex = 0; } else { nodeIndex = Nodes.Count - 2; nextIndex = Nodes.Count - 1; } } SplineNode fromNode = Nodes[nodeIndex]; SplineNode toNode = Nodes[nextIndex]; Vector3 startRPos = fromNode.LocalPosition; Vector3 endRPos = toNode.LocalPosition; Vector3 nodesDir = (endRPos - startRPos); Vector3 upwardVector = Vector3.up; float additionalAngle = 0f; if (RollerCoasterFix && s > 0 && nodeIndex > 0) { SplineNode prevNode = Nodes[nodeIndex - 1]; Vector3 prevNodesDir = (startRPos - prevNode.LocalPosition); Vector3 prevNodesDirXZ = prevNodesDir; prevNodesDirXZ.y = 0; Vector3 nodesDirXZ = nodesDir; nodesDirXZ.y = 0; float dot = Vector3.Dot(prevNodesDirXZ, nodesDirXZ); if (Vector3.Dot(Vector3.up, nodesDir) > 0.5f) { upwardVector = Vector3.left; additionalAngle = -90f * Mathf.Abs(Vector3.Dot(LoftDirection, Vector3.left)); _flipNext = true; } else if (Vector3.Dot(Vector3.up, nodesDir) < -0.5f) { upwardVector = Vector3.right; additionalAngle = 90f * Mathf.Abs(Vector3.Dot(LoftDirection, Vector3.left)); _flipNext = false; } else { if (flipSegment) { additionalAngle = 180f; } } } Vector3 startR_RightP = fromNode.RightP; Vector3 endRPos_RightP = toNode.RightP; Vector3 endRPos_LeftP = toNode.LeftP; float loftAngle = LoftAngle + Mathf.Lerp(fromNode.AdditionalLoftAngle, toNode.AdditionalLoftAngle, nodeT); Vector3 dirR = nodesDir.normalized; if (Loop || (nodeIndex > 0 && nodeIndex + 2 < Nodes.Count)) { dirR = (startR_RightP - startRPos).normalized; Vector3 dirN = (endRPos_RightP - endRPos).normalized; float t = QuadraticSmooth ? (nodeT * nodeT) : nodeT; dirR = Vector3.Slerp(dirR, dirN, t); } Quaternion directionRot = Quaternion.LookRotation(dirR, upwardVector) * Quaternion.Inverse(Quaternion.LookRotation(dirS, upwardVector)); Quaternion loftRot = Quaternion.AngleAxis(additionalAngle + loftAngle, dirR); resultVertices[i] = startRPos + loftRot * (directionRot * perp) + SplinePowerVector3Extensions.Bezier( startRPos - startRPos, startR_RightP - startRPos, endRPos_LeftP - startRPos, endRPos - startRPos, nodeT); if (group.ProcessOriginNormals) { resultNormals[i] = loftRot * directionRot * sourceNormals[i]; } if (group.ProcessOriginTangents) { resultTangents[i] = loftRot * directionRot * sourceTangents[i]; } } segment.vertices = resultVertices; segment.triangles = source.triangles; segment.uv = source.uv; segment.normals = resultNormals; segment.tangents = resultTangents; } for (int s = 0; s < group.ResultSegments.Length; s++) { if (group.RecalculateNormals) { group.ResultSegments[s].RecalculateNormals(); } if (s > 0) { if (group.SmoothNormals || group.Weld) { WeldAndSmooth(group, group.ResultSegments[s - 1], group.ResultSegments[s]); } } if (Loop && s == 0) { if (group.SmoothNormals || group.Weld) { WeldAndSmooth(group, group.ResultSegments[group.ResultSegments.Length - 1], group.ResultSegments[s]); } } } CombineSegments(result, group.ResultSegments); #if UNITY_EDITOR UnityEditor.MeshUtility.SetMeshCompression(result, UnityEditor.ModelImporterMeshCompression.High); result.name = ExportOptions.GetName(this, group); #endif ; result.hideFlags = HideFlags.DontSave; group.ResultMesh = result; if (group.MeshFilter != null) { group.MeshFilter.sharedMesh = null; group.MeshFilter.sharedMesh = result; } if (group.MeshCollider != null) { group.MeshCollider.sharedMesh = null; group.MeshCollider.sharedMesh = result; } }
private void OnDrawGizmos() { if (VisualOptions.ShowNodeLinks) { Gizmos.color = Color.white; for (int i = 1; i < Nodes.Count; i++) { Gizmos.DrawLine(Nodes[i - 1].transform.position, Nodes[i].transform.position); } } if (!VisualOptions.ShowSegmentsPath) { return; } Gizmos.color = Color.red; var ltw = transform.localToWorldMatrix; var wtl = transform.worldToLocalMatrix; float segmentStep = 1.0f / SegmentsNumber; Vector3[] points = new Vector3[SegmentsNumber]; for (int s = 0; s < SegmentsNumber; s++) { float resultT = segmentStep * s + segmentStep; int nodeIndex; float nodeT = GetNodeT(resultT, out nodeIndex); if (nodeIndex < 0) { nodeIndex = 0; } else if (nodeIndex > Nodes.Count - 1) { nodeIndex = Nodes.Count - 1; } int nextIndex = nodeIndex + 1; if (nodeIndex >= Nodes.Count - 1) { if (Loop) { nextIndex = 0; } else { nodeIndex = Nodes.Count - 2; nextIndex = Nodes.Count - 1; } } SplineNode fromNode = Nodes[nodeIndex]; SplineNode toNode = Nodes[nextIndex]; Vector3 startRPos = fromNode.LocalPosition; Vector3 endRPos = toNode.LocalPosition; Vector3 startR_RightP = fromNode.RightP; Vector3 endRPos_LeftP = toNode.LeftP; points[s] = startRPos + SplinePowerVector3Extensions.Bezier( startRPos - startRPos, startR_RightP - startRPos, endRPos_LeftP - startRPos, endRPos - startRPos, nodeT) + (Vector3)(wtl * transform.position); if (s > 0) { Gizmos.DrawLine(ltw * points[s - 1], ltw * points[s]); } } }
public void RemoveNodeImmediately(SplineNode node) { Nodes.Remove(node); RefreshNodesValues(); InvalidateMesh(); }
internal SplineNode(SplineNode o) { Point = o.Point; Rot = o.Rot; Time = o.Time; EaseIO = o.EaseIO; }
public SplineNode GetTransformAtTime(ref float time) { SplineNode curr = new SplineNode(Vector3.zero, Quaternion.identity, 0, Vector2.zero); if (mState == "Reset" || mState == "Stopped" || mNodes.Count < 4) { return(curr); } // We advance to next point in the path if (time >= mNodes[mCurrentIdx + 1].Time) { if (mCurrentIdx < mNodes.Count - 3) { mCurrentIdx++; } else { if (mState != "Loop") { mState = "Stopped"; // We stop right in the end point curr.Point = mNodes[mNodes.Count - 2].Point; if (mRotations) { curr.Rot = mNodes[mNodes.Count - 2].Rot; } // We call back to inform that we are ended if (mOnEndCallback != null) { mOnEndCallback(); } } else { mCurrentIdx = 1; time = 0; } } } if (mState != "Stopped") { // Calculates the t param between 0 and 1 float param = (time - mNodes[mCurrentIdx].Time) / (mNodes[mCurrentIdx + 1].Time - mNodes[mCurrentIdx].Time); // Smooth the param param = MathUtils.Ease(param, mNodes[mCurrentIdx].EaseIO.x, mNodes[mCurrentIdx].EaseIO.y); curr.Point = GetHermiteInternal(mCurrentIdx, param); if (mRotations) { curr.Rot = GetSquad(mCurrentIdx, param); } } return(curr); }
/// <summary> /// This function adds an offset to a BranchingSplineParameter while automatically switching splines when a juction is passed. /// </summary> /// <param name='bParam'> /// A BranchingSplineParameter. /// </param> /// <param name='distanceOffset'> /// An offset that shall be added to the BranchingSplineParameter (in game units). /// </param> /// <param name='bController'> /// A BranchingController-delegate that decides which path to follow if a junction is passed. /// </param> /// <returns> /// True if the spline used as reference path has been changed; False if not. /// </returns> public bool Advance(BranchingSplineParameter bParam, float distanceOffset, BranchingController bController) { bool splineChange = false; if (!SplinesAvailable) { return(false); } if (++recoursionCounter > 12) { recoursionCounter = 0; return(false); } CheckParameter(bParam); Spline currentSpline = bParam.spline; SplineNode currentNode = IsOnSplineNode(bParam.parameter, currentSpline); //Parameter on node? if (currentNode != null) { BranchingSplinePath nextPath = ChoseSpline(currentNode, bParam, bController, distanceOffset > 0); bParam.spline = nextPath.spline; bParam.direction = nextPath.direction; bParam.parameter = currentNode.Parameters[bParam.spline].PosInSpline; SplineNode[] adjacentNodes = GetAdjacentSegmentNodes(nextPath.spline, currentNode); SplineNode nextNode = adjacentNodes[ForwardOnSpline(nextPath.direction, distanceOffset) ? 1 : 0]; if (nextNode != null) { bParam.parameter += (nextNode.Parameters[bParam.spline].PosInSpline - currentNode.Parameters[bParam.spline].PosInSpline) * 0.001f; Advance(bParam, distanceOffset, bController); splineChange = false; } else { splineChange = false; } } else { SplineSegment currentSegment = currentSpline.GetSplineSegment(bParam.parameter); float signedSplineLength = currentSpline.Length * (bParam.Forward ? 1 : -1); float normalizedOffsetDir = distanceOffset / signedSplineLength; float newParameter = bParam.parameter + normalizedOffsetDir; float clampedParameter = currentSegment.ClampParameterToSegment(newParameter); float offsetDifference = newParameter - clampedParameter; bParam.parameter = clampedParameter; if (Mathf.Approximately(offsetDifference, 0)) { splineChange = false; } else { splineChange = Advance(bParam, offsetDifference * signedSplineLength, bController); } } recoursionCounter = 0; return(splineChange); }
/// <summary> /// Use this function to quickly remove a new SplineNode. /// </summary> /// <param name='splineNode'> /// A reference to the SplineNode that shall be removed. /// </param> public void RemoveSplineNode(SplineNode splineNode) { splineNodesArray.Remove(splineNode); UpdateSpline( ); }
// Gets new data from Sense public void NewData(string d) { // Remove any existing sankey foreach (Transform child in transform) { GameObject.Destroy(child.gameObject); } transform.rotation = Quaternion.identity; transform.position = new Vector3(0, 0, 0); pathGOs.Clear(); Debug.Log("data: " + d); JSONNode JPaths = JSON.Parse(d); //var pathList = new List<Path>(); var Paths = new Dictionary <int, Dictionary <string, int> >(); var CompletedPaths = new Dictionary <int, float>(); var Groups = new Dictionary <int, Dictionary <string, float> >(); int MaxSteps = 0; for (int i = 0; i < JPaths.AsArray.Count; i++) { // Splice path string p = JPaths[i]; //Debug.Log("path: " + p); string path = p.Substring(1, p.Length - 2); string[] nodes = path.Split(','); if (nodes.Length < 2) { continue; } for (int j = 0; j < nodes.Length; j++) { string n = nodes[j]; //Debug.Log("node: " + n); if (Paths.ContainsKey(j)) { if (Paths[j].ContainsKey(n)) { Paths[j][n]++; } else { Paths[j][n] = 1; } } else { Paths.Add(j, new Dictionary <string, int>()); Paths[j][n] = 1; } MaxSteps = MaxSteps > Paths[j][n] ? MaxSteps : Paths[j][n]; } } for (int i = 0; i < JPaths.AsArray.Count; i++) { string p = JPaths[i]; string path = p.Substring(1, p.Length - 2); string[] nodes = path.Split(','); if (nodes.Length < 2) { continue; } if (nodes.Length < Paths.Count) { Paths[Paths.Count - 1][nodes[nodes.Length - 1]] = 1; } } Debug.Log("Last pos length: " + Paths[Paths.Count - 1].Count); for (int i = 0; i < JPaths.AsArray.Count; i++) { // Splice path string p = JPaths[i]; Debug.Log("path: " + p); string path = p.Substring(1, p.Length - 2); string[] nodes = path.Split(','); if (nodes.Length < 2) { continue; } GameObject go = createSpline(); Vector3 pp = transform.position; // go.transform.position = new Vector3(pp.x, chartHeight / (float)JPaths.AsArray.Count * (float)i, pp.z); go.transform.position = new Vector3(pp.x, pp.y, pp.z); pathGOs.Add(go); // Setup nodes SplineFormer sf = go.GetComponent <SplineFormer>(); for (int j = 0; j < nodes.Length; j++) { string n = nodes[j]; //Debug.Log("node: " + n); // float zStep= chartLength / (nodes.Length-1); float zStep = chartLength / MaxSteps; // float zPos = zStep * (float)j; float zPos; zPos = j < (nodes.Length - 1) ? zStep * (float)j : chartLength; if (j < nodes.Length - 1) { if (CompletedPaths.ContainsKey(j)) { CompletedPaths[j]++; } else { CompletedPaths.Add(j, 1f); } } else { if (CompletedPaths.ContainsKey(Paths[Paths.Count - 1].Count)) { CompletedPaths[Paths[Paths.Count - 1].Count]++; } else { CompletedPaths.Add(Paths[Paths.Count - 1].Count, 1f); } } SplineNode sn = null; if (j > 1) { sn = sf.AddNodeImmediately(); Vector3 f = sn.transform.position; float hOffset; if (j < nodes.Length - 1) { if (Groups.ContainsKey(j)) { if (Groups[j].ContainsKey(n)) { hOffset = Groups[j][n]; } else { Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j]; hOffset = Groups[j][n]; } } else { Groups.Add(j, new Dictionary <string, float>()); Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j]; hOffset = Groups[j][n]; } } else { //hOffset = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; if (Groups.ContainsKey(Paths.Count - 1)) { if (Groups[Paths.Count - 1].ContainsKey(n)) { hOffset = Groups[Paths.Count - 1][n]; } else { Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; hOffset = Groups[Paths.Count - 1][n]; } } else { Groups.Add(Paths.Count - 1, new Dictionary <string, float>()); Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; hOffset = Groups[Paths.Count - 1][n]; } } f = f + Vector3.up * hOffset; sn.transform.position = new Vector3(f.x, f.y, zPos); } else if (j == 1) { sn = sf.Nodes[j]; Vector3 f = sn.transform.position; float hOffset; if (j < nodes.Length - 1) { //Debug.Log("Path count: " + Paths[j][n]); if (Paths[j][n] > 1) { if (Groups.ContainsKey(j)) { if (Groups[j].ContainsKey(n)) { hOffset = Groups[j][n]; } else { Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j]; hOffset = Groups[j][n]; } } else { Groups.Add(j, new Dictionary <string, float>()); Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j]; hOffset = Groups[j][n]; } } else { hOffset = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j]; } } else { //hOffset = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; if (Groups.ContainsKey(Paths.Count - 1)) { if (Groups[Paths.Count - 1].ContainsKey(n)) { hOffset = Groups[Paths.Count - 1][n]; } else { Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; hOffset = Groups[Paths.Count - 1][n]; } } else { Groups.Add(Paths.Count - 1, new Dictionary <string, float>()); Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count]; hOffset = Groups[Paths.Count - 1][n]; } } f = f + Vector3.up * hOffset; sn.transform.position = new Vector3(f.x, f.y, zPos); } else if (j == 0) { sn = sf.Nodes[j]; Vector3 f = sn.transform.position; float yStep = chartHeight / (float)JPaths.AsArray.Count; //// f = f + Vector3.up * -((float)i-1f) * yStep; // f = f + Vector3.up * chartHeight / (float)(Paths[j].Count+1); //Debug.Log("NumNodesAtPos " + j + ": " + Paths[j].Count + " for path " + i + " = " + chartHeight / (float)(Paths[j].Count + 1)); if (Groups.ContainsKey(j)) { if (!Groups[j].ContainsKey(n)) { Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1); } } else { Groups.Add(j, new Dictionary <string, float>()); Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1); } f = f + Vector3.up * Groups[j][n]; sn.transform.position = f; } // Add Sphere Nodes to nodes GameObject spNode = (GameObject)Instantiate(Resources.Load("SankeyNode"), sn.transform.position, sn.transform.rotation); Vector3 vec = new Vector3(0f, 1f, 0f); spNode.transform.Rotate(vec, 180f); spNode.transform.SetParent(sn.transform); float _nodeScaler = Mathf.Lerp(0.1f, 0.2f, Paths[j][n] / MaxSteps); spNode.transform.localScale = new Vector3(_nodeScaler, _nodeScaler, _nodeScaler); // Add Text Labels to nodes GameObject label = spNode.transform.GetChild(0).gameObject; label.transform.RotateAround(sn.transform.position, Vector3.up, 90); GameObject txt = label.transform.GetChild(0).gameObject; txt.GetComponent <UnityEngine.UI.Text>().text = n; // Add Tap Handler SelectMgr hit = spNode.AddComponent <SelectMgr>(); } sf.InvalidateMesh(); } // Move Sankey above patient Vector3 pPos = patient.transform.position; pPos.x -= 0.4f; pPos.y += 0.8f; pPos.z -= 0.5f; gameObject.transform.position = pPos; Quaternion pRot = patient.transform.rotation; pRot.y -= Mathf.PI * 0.25f; gameObject.transform.rotation = pRot; ReTag(gameObject.transform, LayerMask.NameToLayer("Sankey")); }
private void HandleMouseInput(Spline spline) { if (!EditorGUI.actionKey) { toolSphereSize = 10f; toolSphereAlpha = 0f; return; } else { toolSphereAlpha = Mathf.Lerp(toolSphereAlpha, 0.75f, deltaTime * 4f); toolSphereSize = Mathf.Lerp(toolSphereSize, toolTargetSphereSize + Mathf.Sin(Time.realtimeSinceStartup * 2f) * 0.1f, deltaTime * 15f); } Ray mouseRay = Camera.current.ScreenPointToRay(new Vector2(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 32f)); float splineParam = spline.GetClosestPointParamToRay(mouseRay, 3); Vector3 position = spline.GetPositionOnSpline(splineParam); float currentDistance = Vector3.Cross(mouseRay.direction, position - mouseRay.origin).magnitude; SplineNode selectedNode = null; foreach (SplineNode node in spline.SplineNodes) { float newDistance = Vector3.Distance(node.Position, position); if (newDistance < currentDistance || newDistance < 0.2f * HandleUtility.GetHandleSize(node.Position)) { currentDistance = newDistance; selectedNode = node; } } if (selectedNode != null) { position = selectedNode.Position; Handles.color = new Color(.7f, 0.15f, 0.1f, toolSphereAlpha); Handles.SphereCap(0, position, Quaternion.identity, HandleUtility.GetHandleSize(position) * 0.25f * toolSphereSize); Handles.color = Color.white; Handles.Label(LabelPosition2D(position, 0.3f), "Delete Node (" + selectedNode.gameObject.name + ")", sceneGUIStyleToolLabel); toolTargetSphereSize = 1.35f; } else { Handles.color = new Color(.5f, 1f, .1f, toolSphereAlpha); Handles.SphereCap(0, position, Quaternion.identity, HandleUtility.GetHandleSize(position) * 0.25f * toolSphereSize); Handles.color = Color.white; Handles.Label(LabelPosition2D(position, 0.3f), "Insert Node", sceneGUIStyleToolLabel); toolTargetSphereSize = 0.8f; } if (Event.current.type == EventType.mouseDown && Event.current.button == 1) { Undo.RegisterSceneUndo((selectedNode != null) ? "Delete Spline Node (" + selectedNode.name + ")" : "Insert Spline Node"); if (selectedNode != null) { spline.RemoveSplineNode(selectedNode.gameObject); DestroyImmediate(selectedNode.gameObject); } else { InsertNode(spline, splineParam); } ApplyChangesToTarget(spline); } HandleUtility.Repaint( ); }
private BranchingSplinePath ChoseSpline( SplineNode switchNode, BranchingSplineParameter currentPath, BranchingController bController, bool positiveValue ) { IList<Spline> possibleSplines = GetSplinesForNode( switchNode ); List<BranchingSplinePath> possiblePaths = new List<BranchingSplinePath>( ); //Eliminate unnecessary decisions if( possibleSplines.Count == 1 && possibleSplines[0] == currentPath.spline ) return new BranchingSplinePath( currentPath.spline, currentPath.direction ); if( IsMiddleNode( currentPath.spline, switchNode ) ) possiblePaths.Add( new BranchingSplinePath( currentPath.spline, currentPath.direction ) ); foreach( Spline spline in possibleSplines ) { if( spline == currentPath.spline ) continue; if( IsMiddleNode( spline, switchNode ) ) { possiblePaths.Add( new BranchingSplinePath( spline, BranchingSplinePath.Direction.Forwards ) ); possiblePaths.Add( new BranchingSplinePath( spline, BranchingSplinePath.Direction.Backwards ) ); } else { SplineNode[] splineNodes = spline.SplineNodes; int nodeIndex = System.Array.IndexOf( splineNodes, switchNode ); if( nodeIndex == 0 ) possiblePaths.Add( new BranchingSplinePath( spline, positiveValue?BranchingSplinePath.Direction.Forwards:BranchingSplinePath.Direction.Backwards ) ); if( nodeIndex == splineNodes.Length-1 ) possiblePaths.Add( new BranchingSplinePath( spline, !positiveValue?BranchingSplinePath.Direction.Forwards:BranchingSplinePath.Direction.Backwards ) ); } } return bController( currentPath, possiblePaths ); }
/// <summary> /// initializes the Diagram data /// </summary> private void InitializeDiagram() { Syncfusion.Windows.Forms.Diagram.Rectangle rect = new Syncfusion.Windows.Forms.Diagram.Rectangle(100, 25, 120, 75); rect.FillStyle.Color = Color.FromArgb(240, 242, 240); rect.FillStyle.ForeColor = Color.White; rect.FillStyle.Type = FillStyleType.LinearGradient; rect.LineStyle.LineColor = Color.DarkGray; AddLabel(rect, "Rectangle", Position.Center); diagram1.Model.AppendChild(rect); Syncfusion.Windows.Forms.Diagram.RoundRect roundRect = new Syncfusion.Windows.Forms.Diagram.RoundRect(400, 25, 120, 75, MeasureUnits.Pixel); roundRect.FillStyle.Color = Color.FromArgb(240, 242, 240); roundRect.FillStyle.ForeColor = Color.White; roundRect.LineStyle.LineColor = Color.DarkGray; roundRect.FillStyle.Type = FillStyleType.LinearGradient; AddLabel(roundRect, "RoundRect1", Position.Center); diagram1.Model.AppendChild(roundRect); Ellipse ellipse1 = new Ellipse(100, 125, 120, 80); ellipse1.FillStyle.Color = Color.FromArgb(240, 242, 240); ellipse1.FillStyle.ForeColor = Color.White; ellipse1.LineStyle.LineColor = Color.DarkGray; ellipse1.FillStyle.Type = FillStyleType.LinearGradient; AddLabel(ellipse1, "Ellipse", Position.Center); diagram1.Model.AppendChild(ellipse1); Polygon poly = new Polygon(new PointF[] { new PointF(160, 235), new PointF(100, 265), new PointF(120, 325), new PointF(200, 325), new PointF(220, 265) }); poly.FillStyle.Color = Color.FromArgb(240, 242, 240); poly.FillStyle.ForeColor = Color.White; poly.FillStyle.Type = FillStyleType.LinearGradient; poly.LineStyle.LineColor = Color.DarkGray; AddLabel(poly, "Polygon", Position.Center); diagram1.Model.AppendChild(poly); SemiCircle semiCircle = new SemiCircle(400, 125, 120, 75); semiCircle.FillStyle.Color = Color.FromArgb(240, 242, 240); semiCircle.FillStyle.ForeColor = Color.White; semiCircle.FillStyle.Type = FillStyleType.LinearGradient; semiCircle.LineStyle.LineColor = Color.DarkGray; AddLabel(semiCircle, "SemiCircle", Position.Center); diagram1.Model.AppendChild(semiCircle); TextNode textNode = new TextNode("TextNode1", new RectangleF(400, 245, 120, 50)); textNode.FontStyle.Size = 9; textNode.FontStyle.Family = "Segoe UI"; textNode.HorizontalAlignment = StringAlignment.Center; textNode.VerticalAlignment = StringAlignment.Center; textNode.LineStyle.LineColor = Color.DarkGray; textNode.FontColorStyle.Color = Color.Black; diagram1.Model.AppendChild(textNode); RichTextNode richTextNode = new RichTextNode(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Meiryo UI;}{\f1\fnil\fcharset0 Microsoft Sans Serif;}} {\colortbl ;\red255\green0\blue0;\red0\green64\blue128;} \viewkind4\uc1\pard\b\f0\fs17 This is a text symbol\f1 \b0\f0 designed using the \cf1\b\i Essential Diagram\i0 \cf2\ul RichText\ulnone node\cf0\b0 .\par \i\f1\fs20\par }", new RectangleF(400, 320, 120, 100)); richTextNode.LineStyle.LineColor = Color.DarkGray; diagram1.Model.AppendChild(richTextNode); BitmapNode bmpNode = new BitmapNode(@"..\..\..\..\..\..\..\Common\Images\Diagram\OrgChart Layout\image3.png"); bmpNode.Name = "BitmapNode1"; bmpNode.PinPoint = new PointF(700, 75); bmpNode.Size = new SizeF(120, 100); bmpNode.LineStyle.LineWidth = 0; diagram1.Model.AppendChild(bmpNode); ClosedCurveNode curve = new ClosedCurveNode(new PointF[] { new PointF(120, 350), new PointF(120, 450), new PointF(220, 400) }); curve.FillStyle.Color = Color.FromArgb(240, 242, 240); curve.FillStyle.ForeColor = Color.White; curve.FillStyle.Type = FillStyleType.LinearGradient; curve.LineStyle.LineColor = Color.DarkGray; AddLabel(curve, "ClosedCurve", Position.Center); diagram1.Model.AppendChild(curve); CurveNode curve1 = new CurveNode(new PointF[] { new PointF(120, 100), new PointF(120, 200), new PointF(220, 150) }); curve1 = new CurveNode(new PointF[] { new PointF(0, 30), new PointF(4.99999952f, 25), new PointF(18.3333321f, 0), new PointF(30, 0), new PointF(41.66666641f, 0), new PointF(58.33333321f, 30), new PointF(70, 30), new PointF(81.66666f, 30), new PointF(95, 4.99999952f), new PointF(100, 0) }); AddLabel(curve1, "CurveNode", Position.Center); diagram1.Model.AppendChild(curve1); CircularArc circular = new CircularArc(new RectangleF(640, 150, 100, 100), 0, 270); circular.FillStyle.Color = Color.FromArgb(240, 242, 240); circular.FillStyle.ForeColor = Color.White; circular.FillStyle.Type = FillStyleType.LinearGradient; circular.LineStyle.LineColor = Color.DarkGray; circular.PinPoint = new PointF(700, 200); AddLabel(circular, "CircularArc", Position.Center); diagram1.Model.AppendChild(circular); Line line1 = new Line(new PointF(700, 320), new PointF(700, 430)); line1.LineStyle.LineColor = Color.DarkGray; AddLabel(line1, "line", Position.TopCenter); diagram1.Model.AppendChild(line1); PolylineNode polyLine = new PolylineNode(new PointF[] { new PointF(640, 500), new PointF(760, 500), new PointF(640, 540), new PointF(760, 540) }); polyLine.LineStyle.LineColor = Color.DarkGray; polyLine.LineStyle.LineWidth = 1; Syncfusion.Windows.Forms.Diagram.Label label = new Syncfusion.Windows.Forms.Diagram.Label(polyLine, "PolyLine Node"); label.OffsetX = polyLine.BoundingRectangle.Width / 5f; label.OffsetY = polyLine.BoundingRectangle.Height + 10; label.FontStyle.Family = "Segoe UI"; label.FontColorStyle.Color = Color.Black; label.FontStyle.Size = 9; polyLine.Labels.Add(label); diagram1.Model.AppendChild(polyLine); BezierCurve bezier = new BezierCurve(new PointF[] { new PointF(100, 470), new PointF(160, 470), new PointF(160, 560), new PointF(220, 560) }); AddLabel(bezier, "BezierCurve", Position.BottomCenter); diagram1.Model.AppendChild(bezier); SplineNode spline = new SplineNode(new PointF[] { new PointF(400, 460), new PointF(520, 500), new PointF(400, 520) }); spline.LineStyle.LineColor = Color.Black; spline.LineStyle.LineWidth = 1; AddLabel(spline, "Spline", Position.BottomCenter); diagram1.Model.AppendChild(spline); }
private bool IsMiddleNode( Spline spline, SplineNode node ) { SplineNode[] splineNodes = spline.SplineNodes; int nodeIndex = System.Array.IndexOf( splineNodes, node ); if( nodeIndex == 0 ) return false; if( nodeIndex == splineNodes.Length-1 ) return false; return true; }
void Start() { _firstNode = spawnParent.GetComponent <Spline>().nodes[0]; }
internal SplineNode(SplineNode o) { Point = o.Point; Rot = o.Rot; Time = o.Time; }
public void SetAutoCloseMode(float joiningPointTime) { if (mState != "Reset") throw new System.Exception("Cannot change mode after start"); mEndPointsMode = eEndPointsMode.AUTOCLOSED; mNodes.Add(new SplineNode(mNodes[0] as SplineNode)); mNodes[mNodes.Count - 1].ArrivalTime = joiningPointTime; Vector3 vInitDir = (mNodes[1].Point - mNodes[0].Point).normalized; Vector3 vEndDir = (mNodes[mNodes.Count - 2].Point - mNodes[mNodes.Count - 1].Point).normalized; float firstLength = (mNodes[1].Point - mNodes[0].Point).magnitude; float lastLength = (mNodes[mNodes.Count - 2].Point - mNodes[mNodes.Count - 1].Point).magnitude; SplineNode firstNode = new SplineNode(mNodes[0] as SplineNode); firstNode.Point = mNodes[0].Point + vEndDir * firstLength; SplineNode lastNode = new SplineNode(mNodes[mNodes.Count - 1] as SplineNode); lastNode.Point = mNodes[0].Point + vInitDir * lastLength; mNodes.Insert(0, firstNode); mNodes.Add(lastNode); }
private void RecalcVectors( SplineNode node0, SplineNode node1, ref Vector3 P2, ref Vector3 P3 ) { if( interpolationMode != InterpolationMode.Hermite ) return; if( tangentMode == TangentMode.UseNodeForwardVector ) { P2 = node0.Transform.forward * tension; P3 = node1.Transform.forward * tension; } else { P2 = node1.Position - P2; P3 = P3 - node0.Position; if( tangentMode != TangentMode.UseTangents ) { P2.Normalize( ); P3.Normalize( ); } P2 = P2 * tension; P3 = P3 * tension; } }
public GameObject AddNext() { //New Node GameObject dup = (GameObject)GameObject.Instantiate(gameObject); dup.SetActiveRecursively(false); dup.active = true; if(transform.parent) dup.transform.parent = transform.parent; dup.transform.position = transform.position + Vector3.right * addOffset; dup.transform.rotation = Quaternion.FromToRotation(Vector3.forward, Vector3.right); dup.transform.localScale = transform.localScale; dup.name = "Node"; SplineNode dupNode = dup.GetComponent<SplineNode>(); dupNode.spanCollider = null; if(dupNode) { if(next) { next.previous = dupNode; dupNode.next = next; dupNode.AddCollider(); } next = dupNode; //The dup is now my previous node dupNode.previous = this; //I'm the dup's next node } AddCollider(); if(spline) spline.AddVert(dupNode); return dup; }
protected virtual void SetupSplineInterpolator(SplineInterpolator interp, SplineNode[] ninfo) { interp.Clear(); float currTime = 0; List<SplineNode> nInfoAsList = new List<SplineNode>(ninfo); for (uint c = 0; c < ninfo.Length; c++) { if (OrientationMode == eOrientationMode.NODE) { interp.AddPoint(ninfo[c].Name, ninfo[c].Point, ninfo[c].Rot, currTime, ninfo[c].BreakTime, new Vector2(0, 1)); } else if (OrientationMode == eOrientationMode.TANGENT) { Quaternion rot; Vector3 up = ninfo[c].Rot * Vector3.up; if (c != ninfo.Length - 1) // is c the last point? rot = Quaternion.LookRotation(ninfo[c+1].Point - ninfo[c].Point, up); // no, we can use c+1 else if (AutoClose) rot = Quaternion.LookRotation(ninfo[0].Point - ninfo[c].Point, up); else rot = ninfo[c].Rot; interp.AddPoint(ninfo[c].Name, ninfo[c].Point, rot, currTime, ninfo[c].BreakTime, new Vector2(0, 1)); } // when ninfo[i].StopHereForSecs == 0, then each node of the spline is reached at // Time.time == timePerNode * c (so that last node is reached when Time.time == TimeBetweenAdjacentNodes). // However, when ninfo[i].StopHereForSecs > 0, then the arrival time of node (i+1)-th needs // to account for the stop time of node i-th currTime += ninfo[c].BreakTime; if ((Speed <= 0 || Application.isEditor) && !Application.isPlaying) { currTime += TimeBetweenAdjacentNodes; } } //Debug.Log("SplineController, there are " + eOrientationMode.NODE + " nodes currently"); //Normalizes the speed by adjusting which times our spline interpolator //needs to arrive at a particular node before they are added to the actual //interpolator. if (Speed > 0 && Application.isPlaying) { ConstructCurve(interp, ninfo); } if (AutoClose) interp.SetAutoCloseMode(currTime); }
protected virtual void DoNode(SplineNode node) { switch(node.type) { case SplineNode.Type.CONTINUE: horizSpeed = node.speed; break; case SplineNode.Type.PAUSE: horizSpeed = 0; pauseTime = node.pauseTime; pauseStart = Time.time; resumeSpeed = node.speed; break; case SplineNode.Type.STOP: horizSpeed = 0; break; case SplineNode.Type.REVERSE: horizSpeed = 0; goInReverse = !goInReverse; pauseStart = Time.time; pauseTime = node.pauseTime; resumeSpeed = node.speed; break; } }
protected virtual void ConstructCurve(SplineInterpolator interp, SplineNode[] nInfo) { if (Speed <= 0 && nInfo.Length < 3) return; float totalLength = 0; float[] curveLengths = new float[nInfo.Length]; float[] nodeArrivalTimes = new float[nInfo.Length]; float currTime = 0; uint c = 1; bool pathEnded = false; //Cache the tag so we can reset it after we have calculated how fast the object should move. string actualTag = gameObject.tag; //Preserve the original position so that the object doesn't get deleted due to the simulation. Vector3 originalPosition = gameObject.transform.position; gameObject.tag = "Simulation"; //Swap splines just in case we use mSplineInterp elsewhere. interp.StartInterpolation( //On Path End. () => { //Debug.Log("On Path Ended"); pathEnded = true; }, //On Node Arrival. (int idxArrival, SplineNode nodeArrival) => { curveLengths[c] = mTotalSegmentSpeed; //Debug.Log("SplineController: mTotalSegmentSpeed is " + mTotalSegmentSpeed + "from node " + nInfo[idxArrival - 1].Point + " to " + nodeArrival.Point); totalLength += mTotalSegmentSpeed; mTotalSegmentSpeed = 0; ++c; }, //On Node Callback (int idxLeavingSpline, SplineNode OnNodeArrivalCallback) => { //Debug.Log("On Node callback: " + idxLeavingSpline); }, false, eWrapMode.ONCE); //Starts the Simulation. float deltaTime = 0.00005f; float currentTime = 0f; while (!pathEnded) { interp.Update(currentTime); mTotalSegmentSpeed += mSplineInterp.DistanceTraveled; currentTime += deltaTime; } //Debug.Log("SplineController: totalLength is " + totalLength); interp.Clear(); gameObject.transform.position = originalPosition; //From that, evaluate how much distance between each node makes up the curve and scale that time to be the break time. float totalTime = GetDuration(nInfo); //Debug.Log("SplineController: totalTime is " + totalTime); float averageSpeed = totalLength / totalTime; float timeToEnd = 0; float speedMultiplier = 0; for (int i = 0; i < curveLengths.Length; i++) { float hermiteLengthToEvaluate = curveLengths[i]; //Debug.Log("SplineController: hermiteLengthToEvaluate is " + hermiteLengthToEvaluate + " and the node is " + nInfo[i].Name); if (hermiteLengthToEvaluate > 0) { speedMultiplier = (hermiteLengthToEvaluate / totalLength) * (1 / Speed); timeToEnd = totalTime * speedMultiplier; //Debug.Log("SplineController: timeToEnd is " + timeToEnd); } interp.AddPoint(nInfo[i].Name, nInfo[i].Point, nInfo[i].Rot, timeToEnd + currTime, 0, new Vector2(0, 1)); currTime += timeToEnd; } gameObject.tag = actualTag; }
bool FindSplineVertex(Spline s, Vector3 a, Vector3 b, SplineNode guess, out SplineNode vert, out Vector3 position) { SplineNode countup, countdown; if(s != null) { if(guess == null) { if(!(s.begin && s.end)) { Debug.LogError("Could not find vertex, begin and end not set"); vert = null; position = Vector3.zero; return false; } countup = s.begin; countdown = s.end; } else { countdown = guess; countup = guess; } Utility.Vector3Pair points; while(countdown != null || countup != null) { if(countup.next != null) { //#if(DEBUG_DRAW||DEBUG_DRAW_LND) Debug.DrawLine(countup.transform.position, countup.next.transform.position, Color.magenta); //#endif points = Utility.Dist3DSegToSeg(a, b, countup.transform.position, countup.next.transform.position); if((points.a - points.b).magnitude < snapDistance) { //Debug.Log(points.a + ", " + points.b); Debug.DrawLine(points.b, transform.position, Color.magenta); vert = countup; if(looseFollow) position = transform.position; else position = points.b; return true; } } countup = countup.next; if(countdown.previous != null) { //#if(DEBUG_DRAW||DEBUG_DRAW_LND) Debug.DrawLine(countdown.transform.position, countdown.previous.transform.position, Color.cyan); //#endif points = Utility.Dist3DSegToSeg(a, b, countdown.transform.position, countdown.previous.transform.position); if((points.a - points.b).magnitude < snapDistance) { Debug.DrawLine(points.b, transform.position, Color.green); vert = countdown.previous; if(looseFollow) position = transform.position; else position = points.b; return true; } } countdown = countdown.previous; } } else Debug.LogError("Error in land, spline is null"); Debug.LogWarning("Warning in land - Couldn't find a vert"); vert = null; position = Vector3.zero; return false; }
protected override void SetupSplineInterpolator(SplineInterpolator interp, SplineNode[] ninfo) { Speed = Speeds[_SplineToExecute]; base.SetupSplineInterpolator (interp, ninfo); }
internal SplineNode(SplineNode node) { point = node.point; rot = node.rot; portion = node.portion; easeIO = node.easeIO; }
internal SplineNode(SplineNode o) { Name = o.Name; Point = o.Point; Rot = o.Rot; ArrivalTime = o.ArrivalTime; BreakTime = o.BreakTime; EaseIO = o.EaseIO; }
internal SplineNode(SplineNode o) { Name = o.Name; Point = o.Point; Rot = o.Rot; ArrivalTime = o.ArrivalTime; BreakTime = o.BreakTime; EaseIO = o.EaseIO; }
public bool FindSplineVertex(Spline s, Vector3 a, Vector3 b, out SplineNode vert, out Vector3 position) { return FindSplineVertex(s, a, b, null, out vert, out position); }
internal SplineNode(SplineNode o) { Point = o.Point; Rot = o.Rot; Time = o.Time; EaseIO = o.EaseIO; }
protected Vector3 SplineMovement() { if(!groundNode) return rigidbody.velocity; float horizFrameVelocity = 0; switch(mode) { case Mode.KEYBOARD: float newSpeed = (Vector3.Dot(rigidbody.velocity, groundNode.forward.normalized) + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime; if (newSpeed < maxCarSpeed) { horizFrameVelocity = newSpeed ; } else { horizFrameVelocity = maxCarSpeed ; } break; case Mode.AUTO: horizFrameVelocity = (horizSpeed + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime * (goInReverse ? -1 : 1); if(!ignoreNodes && !ignoreNextNode) { if(horizFrameVelocity > 0 && groundNode.next) { //We're moving "forward" and there's a next vert if(horizFrameVelocity > (rigidbody.position - groundNode.next.transform.position).magnitude) if(groundNode.next) if(groundNode.next.fromPrevious) //this node wants to be activated going forward DoNode(groundNode.next); } else if(groundNode) { //We're moving "backward" and there's a previous vert if(-horizFrameVelocity > (rigidbody.position - groundNode.transform.position).magnitude) if(groundNode) if(groundNode.fromNext) //this node wants to be activated going forward DoNode(groundNode); } horizFrameVelocity = (horizSpeed + horizAcceleration * Time.fixedDeltaTime) * Time.fixedDeltaTime * (goInReverse ? -1 : 1); } break; } Vector3 position = rigidbody.position; Vector3 newVelocity = rigidbody.velocity; if(horizFrameVelocity != 0) { float distance = Mathf.Abs(horizFrameVelocity); int itercount = MAX_OVER_ITER; int iter = MAX_OVER_ITER; /* * This while loop "adjusts" for any incoming error on groundNode. If the first condition is * met, the node reference is too far forward, and must be decremented. If the second is met, * the opposite is true and the node must be incremented. * niiiiice 8) */ while(iter-- > 0) { if(Vector3.Dot(groundNode.forward, transform.position - groundNode.transform.position) < 0) { if(!PreviousNode()) { Detach(); return rigidbody.velocity; } continue; } else if(groundNode.next) { if(Vector3.Dot(groundNode.forward, transform.position - groundNode.next.transform.position) > 0) { if(!NextNode()) { Detach(); return rigidbody.velocity; } continue; } } break; } if(horizFrameVelocity < 0) //If we're going backward, come from the other direction groundNode = groundNode.next; if(groundNode) { Debug.DrawLine(transform.position, transform.position + groundNode.forward * horizFrameVelocity, Color.red); //We will loop until we have gone one node past the next desired position while(distance > 0) { if(horizFrameVelocity > 0) { //Reaching the next vert going forward if(!NextNode()) { Detach(); return rigidbody.velocity; } } if(horizFrameVelocity < 0) { //Reaching the previous vert going backward if(!PreviousNode()) { Detach(); return rigidbody.velocity; } } //calculate the distance to the next node distance -= (position - groundNode.transform.position).magnitude; //update position to the next node position = groundNode.transform.position; if(itercount-- < 0) break; } //This statement is complicated newVelocity = ((position + (position - transform.position).normalized * distance) - transform.position) * (1 / Time.fixedDeltaTime); //if(groundNode.num == 2) // Debug.Log(horizFrameVelocity + ", " + distance + " | " + (transform.position + newVelocity * Time.fixedDeltaTime) + " - " + Time.frameCount); if(horizFrameVelocity > 0) groundNode = groundNode.previous; } else return rigidbody.velocity; } else return Vector3.zero; return newVelocity; }
void SetupSplineInterpolator(SplineInterpolator interp, SplineNode[] ninfo) { interp.Reset(); float currTime = 0; for (uint c = 0; c < ninfo.Length; c++) { if (OrientationMode == eOrientationMode.NODE) { interp.AddPoint(ninfo[c].Name, ninfo[c].Point, ninfo[c].Rot, currTime, ninfo[c].BreakTime, new Vector2(0, 1)); } else if (OrientationMode == eOrientationMode.TANGENT) { Quaternion rot; Vector3 up = ninfo[c].Rot * Vector3.up; if (c != ninfo.Length - 1) // is c the last point? rot = Quaternion.LookRotation(ninfo[c+1].Point - ninfo[c].Point, up); // no, we can use c+1 else if (AutoClose) rot = Quaternion.LookRotation(ninfo[0].Point - ninfo[c].Point, up); else rot = ninfo[c].Rot; interp.AddPoint(ninfo[c].Name, ninfo[c].Point, rot, currTime, ninfo[c].BreakTime, new Vector2(0, 1)); } // when ninfo[i].StopHereForSecs == 0, then each node of the spline is reached at // Time.time == timePerNode * c (so that last node is reached when Time.time == TimeBetweenAdjacentNodes). // However, when ninfo[i].StopHereForSecs > 0, then the arrival time of node (i+1)-th needs // to account for the stop time of node i-th TimeBetweenAdjacentNodes = 1.0f / (ninfo.Length - 1); currTime += TimeBetweenAdjacentNodes + ninfo[c].BreakTime; } if (AutoClose) interp.SetAutoCloseMode(currTime); }
//-------------------// // SPLINE PHYSICS!!!// //-------------------// bool NextNode() { if(groundNode.next) { groundNode = groundNode.next; return true; } else if(currentSpline.next) { if(currentSpline.next.begin) { currentSpline = currentSpline.next; groundNode = currentSpline.begin; return true; } else Debug.LogWarning("Next spline missing begin"); } return false; }
internal SplineNode(SplineNode o) { Point = o.Point; Rot = o.Rot; Len = o.Len; EaseIO = o.EaseIO; }
// public void UpdateSpline(){ // if(currentSpline != currentSplineSource.spline){ // Svertex oldBegin = currentSpline.begin; // Svertex newBegin = currentSplineSource.spline.begin; // while(oldBegin.next != null && newBegin.next != null){ //roll forward through both splines until we find the old groundCV // if(oldBegin == groundCV) // break; // oldBegin = oldBegin.next; // newBegin = newBegin.next; // } // groundCV = newBegin; // currentSpline = currentSplineSource.spline; // } // } public void Detach() { //Debug.Log("detach" + Time.frameCount); currentSpline = null; groundNode = null; transform.parent = null; }
void OnSceneGUI() { Event e = Event.current; if (e.type == EventType.mouseDown) { Undo.RegisterCompleteObjectUndo(spline, "change spline topography"); // if alt key pressed, we will have to create a new node if node position is changed if (e.alt) { mustCreateNewNode = true; } } if (e.type == EventType.mouseUp) { mustCreateNewNode = false; } // listen for delete key if (e.type == EventType.keyDown && e.keyCode == KeyCode.Delete) { Undo.RegisterCompleteObjectUndo(spline, "delete spline node"); DeleteNode(selection); selection = null; e.Use(); } // disable game object transform gyzmo if (Selection.activeGameObject == spline.gameObject) { Tools.current = Tool.None; if (selection == null && spline.nodes.Count > 0) { selection = spline.nodes[0]; } } // draw a bezier curve for each curve in the spline foreach (CubicBezierCurve curve in spline.GetCurves()) { Handles.DrawBezier(spline.transform.TransformPoint(curve.n1.position), spline.transform.TransformPoint(curve.n2.position), spline.transform.TransformPoint(curve.n1.direction), spline.transform.TransformPoint(curve.GetInverseDirection()), CURVE_COLOR, null, 3); } // draw the selection handles switch (selectionType) { case SelectionType.Node: // place a handle on the node and manage position change Vector3 newPosition = spline.transform.InverseTransformPoint(Handles.PositionHandle(spline.transform.TransformPoint(selection.Position), Quaternion.identity)); if (newPosition != selection.Position) { // position handle has been moved if (mustCreateNewNode) { mustCreateNewNode = false; selection = AddClonedNode(selection); selection.Direction += newPosition - selection.Position; selection.Position = newPosition; } else { selection.Direction += newPosition - selection.Position; selection.Position = newPosition; } } break; case SelectionType.Direction: selection.Direction = spline.transform.InverseTransformPoint(Handles.PositionHandle(spline.transform.TransformPoint(selection.Direction), Quaternion.identity)); break; case SelectionType.InverseDirection: selection.Direction = 2 * selection.Position - spline.transform.InverseTransformPoint(Handles.PositionHandle(2 * spline.transform.TransformPoint(selection.Position) - spline.transform.TransformPoint(selection.Direction), Quaternion.identity)); break; } // draw the handles of all nodes, and manage selection motion Handles.BeginGUI(); foreach (SplineNode n in spline.nodes) { Vector3 guiPos = HandleUtility.WorldToGUIPoint(spline.transform.TransformPoint(n.Position)); if (n == selection) { Vector3 guiDir = HandleUtility.WorldToGUIPoint(spline.transform.TransformPoint(n.Direction)); Vector3 guiInvDir = HandleUtility.WorldToGUIPoint(spline.transform.TransformPoint(2 * n.Position - n.Direction)); // for the selected node, we also draw a line and place two buttons for directions Handles.color = Color.red; Handles.DrawLine(guiDir, guiInvDir); // draw quads direction and inverse direction if they are not selected if (selectionType != SelectionType.Node) { if (Button(guiPos, directionButtonStyle)) { selectionType = SelectionType.Node; } } if (selectionType != SelectionType.Direction) { if (Button(guiDir, directionButtonStyle)) { selectionType = SelectionType.Direction; } } if (selectionType != SelectionType.InverseDirection) { if (Button(guiInvDir, directionButtonStyle)) { selectionType = SelectionType.InverseDirection; } } } else { if (Button(guiPos, nodeButtonStyle)) { selection = n; selectionType = SelectionType.Node; } } } Handles.EndGUI(); if (GUI.changed) { EditorUtility.SetDirty(target); } }