public PBCircleNode(PBCircleNode node) { circle = node.circle; position = node.position; tangent = node.tangent; angle = node.angle; }
public float deltaAngle(PBCircleNode targetNode) { float deltaAngle = targetNode.angle - this.angle; if (deltaAngle < 0) { deltaAngle += 360; } return(deltaAngle); }
public void GetBottomMidSample(out Vector3 position, out Vector3 tangent, out Vector3 emit, out float distance) { //单圆 if (curveType == PBCircleCurveType.OneCircle) { PBCircleNode node = nodes.First.Value; Vector3 r = -node.circle.up.normalized; position = node.circle.center + r * node.circle.radius; tangent = -node.tangent; emit = r; distance = 0.5f * nodes.Last.Value.distance; return; } PBCircleNode node1; PBCircleNode node2; if (curveType == PBCircleCurveType.Line) { int half = (nodes.Count - 1) / 2; int index = half + half / 2; node1 = nodes.ElementAt(index - 1); node2 = nodes.ElementAt(index); } else { int half = (nodes.Count - 1) / 2; node1 = nodes.ElementAt(half - 1); node2 = nodes.ElementAt(half); } if (node1.ConnectLine(node2)) { position = Vector3.Lerp(node1.position, node2.position, 0.5f); tangent = node1.tangent; emit = (node1.position - node1.circle.center).normalized; distance = 0.5f * (node1.distance + node2.distance); } else { PBCircle circle = node1.circle; float angle = node1.angle + 0.5f * node1.deltaAngle(node2); Vector3 r = Quaternion.AngleAxis(angle, circle.forward) * circle.up; r.Normalize(); position = circle.center + r * circle.radius; tangent = Quaternion.AngleAxis(angle, circle.forward) * (-circle.right); emit = r; distance = 0.5f * (node1.distance + node2.distance); } }
private static PBCircleNode[] CalculateTangentLines(PBCircle c1, PBCircle c2) { Vector3 o1o2 = c2.center - c1.center; float o1o2_distance = o1o2.magnitude; o1o2.Normalize(); float angle;// 90-圆心连线与公切线的夹角 if (Mathf.Approximately(c1.radius, c2.radius)) { angle = 90; } else { float r1 = Mathf.Max(c1.radius, c2.radius); float r2 = Mathf.Min(c1.radius, c2.radius); float x = o1o2_distance * r1 / (r1 - r2); angle = Mathf.Acos(r1 / x) * Mathf.Rad2Deg; if (c1.radius < c2.radius) { angle = 180 - angle; } } Vector3[] Rs = new[] { Quaternion.AngleAxis(angle, c1.forward) * o1o2, Quaternion.AngleAxis(angle, -c1.forward) * o1o2, }; PBCircleNode[] nodes = new PBCircleNode[4]; for (int i = 0; i < Rs.Length; i++) { PBCircleNode n1, n2; //第 i 条公切线的c1、c2上的点 Vector3 r = Rs[i]; Vector3 p = c1.center + r * c1.radius; Vector3 tangent = Quaternion.AngleAxis(90, c1.forward) * r; n1 = new PBCircleNode(c1, p, tangent, GetAngle(c1, r)); p = c2.center + r * c2.radius; n2 = new PBCircleNode(c2, p, tangent, GetAngle(c2, r)); nodes[i * 2] = n1; nodes[i * 2 + 1] = n2; } return(nodes); }
/// <summary> /// 通过距离起点的距离,获取线上的点的坐标、斜率、圆心到坐标的单位向量(垂直于斜率) /// </summary> public void GetSampleAtDistance(float distance, out Vector3 position, out Vector3 tangent, out Vector3 emit) { LinkedListNode <PBCircleNode> listNode = nodes.First; PBCircleNode startNode = null; PBCircleNode endNode = null; while (listNode != null) { if (distance < listNode.Value.distance) { startNode = listNode.Previous.Value; endNode = listNode.Value; break; } listNode = listNode.Next; } if (startNode == null) { throw new ArgumentException(string.Format("Distance must be less than curve length. Curve length: {0}, distance: {1}", nodes.Last.Value.distance, distance)); } float t = (distance - startNode.distance) / (endNode.distance - startNode.distance); if (startNode.ConnectLine(endNode)) { //直线 position = Vector3.Lerp(startNode.position, endNode.position, t); tangent = startNode.tangent; emit = (startNode.position - startNode.circle.center).normalized; } else { //圆弧 PBCircle circle = startNode.circle; float angle = startNode.angle + t * startNode.deltaAngle(endNode); Vector3 r = Quaternion.AngleAxis(angle, circle.forward) * circle.up; r.Normalize(); position = circle.center + r * circle.radius; tangent = Quaternion.AngleAxis(angle, circle.forward) * (-circle.right); emit = r; } }
public static LinkedList <PBCircleNode> Build(PBCircle[] circles, PBCircleCurveType type) { LinkedList <PBCircleNode> nodes = null; switch (type) { case PBCircleCurveType.OneCircle: nodes = BuildForOne(circles); break; case PBCircleCurveType.Line: nodes = BuildForLine(circles); break; case PBCircleCurveType.Enclosed: nodes = BuildForEnclosed(circles); break; } //compute distance for nodes LinkedListNode <PBCircleNode> listNode = nodes.First; listNode.Value.distance = 0; listNode = listNode.Next; while (listNode != null) { PBCircleNode node = listNode.Value; PBCircleNode preNode = listNode.Previous.Value; if (node.ConnectLine(preNode)) { //直线 node.distance = preNode.distance + Vector3.Distance(node.position, preNode.position); //Debug.Log(">>>>>>>1 distance: " + node.distance); } else { //圆弧 float radius = node.circle.radius; node.distance = preNode.distance + preNode.deltaAngle(node) * Mathf.Deg2Rad * radius; //Debug.Log(">>>>>>>2 distance: " + node.distance); } listNode = listNode.Next; } return(nodes); }
private static LinkedList <PBCircleNode> BuildForOne(PBCircle[] circles) { LinkedList <PBCircleNode> nodes = new LinkedList <PBCircleNode>(); PBCircle circle = circles[0]; PBCircleNode node1 = new PBCircleNode( circle, circle.center + circle.up * circle.radius, -circle.right, 0); nodes.AddFirst(node1); PBCircleNode node2 = new PBCircleNode(node1); node2.angle = 360; nodes.AddLast(node2); return(nodes); }
/// <summary> /// 两点间连圆弧 /// </summary> public bool ConnectArc(PBCircleNode nextNode) { return(nextNode.circle == this.circle); }
/// <summary> /// 两点间连直线(两圆公切线) /// </summary> public bool ConnectLine(PBCircleNode nextNode) { return(nextNode.circle != this.circle); }