您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

224 行
6.8 KiB

using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.RMGUI;
namespace RMGUI.GraphView
{
public class Edge : GraphElement
{
const float k_EndPointRadius = 4.0f;
const float k_InterceptWidth = 3.0f;
public override void OnDataChanged()
{
base.OnDataChanged();
this.Touch(ChangeType.Repaint);
}
protected static void GetTangents(Direction direction, Orientation orientation, Vector2 start, Vector2 end, out Vector3[] points, out Vector3[] tangents)
{
if (direction == Direction.Output)
{
Vector2 t = end;
end = start;
start = t;
}
bool invert = false;
if (end.x < start.x)
{
Vector3 t = start;
start = end;
end = t;
invert = true;
}
points = new Vector3[] {start, end};
tangents = new Vector3[2];
const float minTangent = 30;
float weight = .5f;
float weight2 = 1 - weight;
float y = 0;
float cleverness = Mathf.Clamp01(((start - end).magnitude - 10) / 50);
if (orientation == Orientation.Horizontal)
{
tangents[0] = start + new Vector2((end.x - start.x) * weight + minTangent, y) * cleverness;
tangents[1] = end + new Vector2((end.x - start.x) * -weight2 - minTangent, -y) * cleverness;
}
else
{
float inverse = (invert) ? 1.0f : -1.0f;
tangents[0] = start + new Vector2(y, inverse * ((end.x - start.x) * weight + minTangent)) * cleverness;
tangents[1] = end + new Vector2(-y, inverse * ((end.x - start.x) * -weight2 - minTangent)) * cleverness;
}
}
public override bool Overlaps(Rect rect)
{
// bounding box check succeeded, do more fine grained check by checking intersection between the rectangles' diagonal
// and the line segments
var edgeData = GetData<EdgeData>();
if (edgeData == null)
return false;
IConnectable leftData = edgeData.left;
IConnectable rightData = edgeData.right ?? leftData;
if (leftData == null || rightData == null)
return false;
Vector2 from = Vector2.zero;
Vector2 to = Vector2.zero;
GetFromToPoints(ref from, ref to);
Orientation orientation = leftData.orientation;
Vector3[] points, tangents;
GetTangents(leftData.direction, orientation, from, to, out points, out tangents);
Vector3[] allPoints = Handles.MakeBezierPoints(points[0], points[1], tangents[0], tangents[1], 20);
for (int a = 0; a < allPoints.Length; a++)
{
if (a >= allPoints.Length - 1)
{
break;
}
var segmentA = new Vector2(allPoints[a].x, allPoints[a].y);
var segmentB = new Vector2(allPoints[a + 1].x, allPoints[a + 1].y);
if (RectUtils.IntersectsSegment(rect, segmentA, segmentB))
return true;
}
return false;
}
public override bool ContainsPoint(Vector2 localPoint)
{
// bounding box check succeeded, do more fine grained check by measuring distance to bezier points
var edgeData = GetData<EdgeData>();
if (edgeData == null)
return false;
IConnectable leftData = edgeData.left;
IConnectable rightData = edgeData.right ?? leftData;
if (leftData == null || rightData == null)
return false;
Vector2 from = Vector2.zero;
Vector2 to = Vector2.zero;
GetFromToPoints(ref from, ref to);
// exclude endpoints
if (Vector2.Distance(from, localPoint) <= 2*k_EndPointRadius ||
Vector2.Distance(to, localPoint) <= 2*k_EndPointRadius)
{
return false;
}
Orientation orientation = leftData.orientation;
Vector3[] points, tangents;
GetTangents(leftData.direction, orientation, from, to, out points, out tangents);
Vector3[] allPoints = Handles.MakeBezierPoints(points[0], points[1], tangents[0], tangents[1], 20);
float minDistance = Mathf.Infinity;
foreach (Vector3 currentPoint in allPoints)
{
float distance = Vector3.Distance(currentPoint, localPoint);
minDistance = Mathf.Min(minDistance, distance);
if (minDistance < k_InterceptWidth)
{
return true;
}
}
return false;
}
public override void DoRepaint(PaintContext args)
{
base.DoRepaint(args);
DrawEdge(args);
}
protected void GetFromToPoints(ref Vector2 from, ref Vector2 to)
{
var edgeData = GetData<EdgeData>();
if (edgeData == null)
return;
IConnectable leftData = edgeData.left;
IConnectable rightData = edgeData.right ?? leftData;
if (leftData == null)
return;
GraphElement leftAnchor = parent.allElements.OfType<GraphElement>().First(e => e.dataProvider as IConnectable == leftData);
if (leftAnchor != null)
{
from = leftAnchor.GetGlobalCenter();
from = globalTransform.inverse.MultiplyPoint3x4(from);
}
if (edgeData.candidate)
{
to = globalTransform.inverse.MultiplyPoint3x4(new Vector3(edgeData.candidatePosition.x, edgeData.candidatePosition.y));
}
else
{
GraphElement rightAnchor = parent.allElements.OfType<GraphElement>().First(e => e.dataProvider as IConnectable == rightData);
if (rightAnchor != null)
{
to = rightAnchor.GetGlobalCenter();
to = globalTransform.inverse.MultiplyPoint3x4(to);
}
}
}
protected virtual void DrawEdge(PaintContext args)
{
var edgeData = GetData<EdgeData>();
if (edgeData == null)
return;
IConnectable leftData = edgeData.left;
if (leftData == null)
return;
Vector2 from = Vector2.zero;
Vector2 to = Vector2.zero;
GetFromToPoints(ref from, ref to);
Color edgeColor = (GetData<EdgeData>() != null && GetData<EdgeData>().selected) ? Color.yellow : Color.white;
Orientation orientation = leftData.orientation;
Vector3[] points, tangents;
GetTangents(leftData.direction, orientation, from, to, out points, out tangents);
Handles.DrawBezier(points[0], points[1], tangents[0], tangents[1], edgeColor, null, 5f);
// little widget on the middle of the edge
Vector3[] allPoints = Handles.MakeBezierPoints(points[0], points[1], tangents[0], tangents[1], 20);
Color oldColor = Handles.color;
Handles.color = Color.blue;
Handles.DrawSolidDisc(allPoints[10], new Vector3(0.0f, 0.0f, -1.0f), 6f);
Handles.color = edgeColor;
Handles.DrawWireDisc(allPoints[10], new Vector3(0.0f, 0.0f, -1.0f), 6f);
Handles.DrawWireDisc(allPoints[10], new Vector3(0.0f, 0.0f, -1.0f), 5f);
// dot on top of anchor showing it's connected
Handles.color = new Color(0.3f, 0.4f, 1.0f, 1.0f);
Handles.DrawSolidDisc(from, new Vector3(0.0f, 0.0f, -1.0f), k_EndPointRadius);
if (edgeData.right == null)
Handles.color = oldColor;
Handles.DrawSolidDisc(to, new Vector3(0.0f, 0.0f, -1.0f), k_EndPointRadius);
Handles.color = oldColor;
}
}
}