956 lines
33 KiB
C#

#define Graph_And_Chart_PRO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace ChartAndGraph
{
/// <summary>
/// this class is used internally in order to draw lines, line fill and line points into a mesh
/// </summary>
public partial class CanvasLines : EventHandlingGraphic
{
/// <summary>
/// thickness of the lines being drawn
/// </summary>
public float Thickness = 2f;
float innerTile = 1f;
int mMinModifyIndex = 0;
/// <summary>
/// Tiling value for the graphic. The tiliing is the total length of the lines being drawn. It is set by the parent graph
/// </summary>
public float Tiling
{
get { return innerTile; }
set
{
innerTile = value;
}
}
bool mNegativeFill = true;
/// <summary>
/// true if this graphic is in fill render mode (drawing the inner fill of a line graph)
/// </summary>
bool mFillRender = false;
/// <summary>
/// true if this graph is in point drawing render mode
/// </summary>
bool mPointRender = false;
/// <summary>
/// for point render mode , sets the point size
/// </summary>
float mPointSize = 5f;
/// <summary>
/// for fill render mode , this sets the boundries of the fill. (so the bottom of the fill matches the bottom of the graph)
/// </summary>
Rect mFillRect;
float mFillZero;
/// <summary>
/// if true , the Y of the fill is stretched
/// </summary>
bool mStretchY;
/// <summary>
/// The material for the graphic object
/// </summary>
Material mCachedMaterial;
Material mOriginalMaterial;
/// <summary>
/// list of lines for the line object , this will be used to render either dots , fill or lines depending on the render mode
/// </summary>
List<LineSegement> mLines;
/// <summary>
/// bounding box for the value of mLines, used for event handling
/// </summary>
float mMinX, mMinY, mMaxX, mMaxY;
public Rect? ClipRect { get; set; }
/// <summary>
/// Sets point render mode
/// </summary>
/// <param name="pointSize"></param>
public void MakePointRender(float pointSize)
{
mPointSize = pointSize;
mPointRender = true;
}
public void SetFillZero(float zero)
{
mFillZero = zero;
}
/// <summary>
/// sets inner fill render mode
/// </summary>
/// <param name="fillRect"></param>
/// <param name="stretchY"></param>
public void MakeFillRender(Rect fillRect,float fillZero, bool stretchY,bool negative)
{
mFillZero = fillZero;
mFillRect = fillRect;
mFillRender = true;
mStretchY = stretchY;
mNegativeFill = negative;
}
UIVertex[] mTmpVerts = new UIVertex[4];
/// <summary>
/// holds line data and pre cacultates normal and speration
/// </summary>
internal struct Line
{
public Line(Vector3 from, Vector3 to, float halfThickness, bool hasNext, bool hasPrev) : this()
{
Vector3 diff = (to - from);
float magDec = 0;
if (hasNext)
magDec += halfThickness;
if (hasPrev)
magDec += halfThickness;
Mag = diff.magnitude - magDec * 2;
Degenerated = false;
if (Mag <= 0)
Degenerated = true;
Dir = diff.normalized;
Vector3 add = halfThickness * 2 * Dir;
if (hasPrev)
from += add;
if (hasNext)
to -= add;
From = from;
To = to;
Normal = new Vector3(Dir.y, -Dir.x, Dir.z); // this part calculates the line inset and points based on thichkness
P1 = From + Normal * halfThickness;
P2 = from - Normal * halfThickness;
P3 = to + Normal * halfThickness;
P4 = to - Normal * halfThickness;
}
public bool Degenerated { get; private set; }
public Vector3 P1 { get; private set; }
public Vector3 P2 { get; private set; }
public Vector3 P3 { get; private set; }
public Vector3 P4 { get; private set; }
public Vector3 From { get; private set; }
public Vector3 To { get; private set; }
public Vector3 Dir { get; private set; }
public float Mag { get; private set; }
public Vector3 Normal { get; private set; }
}
/// <summary>
/// represents one line segemenet.
/// </summary>
internal class LineSegement
{
List<Vector4> mLines = new List<Vector4>();
public LineSegement(IList<Vector3> lines)
{
mLines.AddRange(lines.Select(x=>new Vector4(x.x,x.y,x.z,-1f)));
}
public LineSegement(IList<Vector4> lines)
{
mLines.AddRange(lines);
}
/// <summary>
/// reset the value of the linesSegment to the specified list
/// </summary>
/// <param name="v"></param>
public void ModifiyLines(List<Vector4> v)
{
mLines.Clear();
mLines.AddRange(v);
}
/// <summary>
/// The total amount of points in this line segmenet
/// </summary>
public int PointCount
{
get
{
if (mLines == null)
return 0;
return mLines.Count;
}
}
/// <summary>
/// Line count is point count minus one. Since all dots have to be connected
/// </summary>
public int LineCount
{
get
{
if (mLines == null)
return 0;
if (mLines.Count < 2)
return 0;
return mLines.Count - 1;
}
}
/// <summary>
/// Gets a point
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public Vector4 getPoint(int index)
{
Vector4 p = mLines[index];
return p;
}
/// <summary>
/// gets the line at the specified index.index Must be below LineCount
/// </summary>
/// <param name="index"></param>
/// <param name="from"></param>
/// <param name="to"></param>
public void GetLine(int index, out Vector3 from, out Vector3 to)
{
from = mLines[index];
to = mLines[index + 1];
}
/// <summary>
/// gets the line at the specified index.index Must be below LineCount. if the line has a previous or a next line an inset is calculated for better visual aperance
/// </summary>
/// <param name="index"></param>
/// <param name="from"></param>
/// <param name="to"></param>
public Line GetLine(int index, float halfThickness, bool hasPrev, bool hasNext)
{
Vector3 from = mLines[index];
Vector3 to = mLines[index + 1];
return new Line(from, to, halfThickness, false, false);
}
public double GetLineMag(int index)
{
return (mLines[index] - mLines[index + 1]).magnitude;
}
}
public CanvasLines()
{
}
/// <summary>
/// finds the minimum and maximum values of the currently set data
/// </summary>
void FindBoundingValues()
{
mMinX = float.PositiveInfinity;
mMinY = float.PositiveInfinity;
mMaxX = float.NegativeInfinity;
mMaxY = float.NegativeInfinity;
// this part finds the bounding box of the lines
if (mLines != null)
{
for (int i = 0; i < mLines.Count; i++)
{
LineSegement seg = mLines[i];
int totalPoints = seg.PointCount;
for (int j = 0; j < totalPoints; j++)
{
Vector3 point = seg.getPoint(j);
mMinX = Mathf.Min(mMinX, point.x);
mMinY = Mathf.Min(mMinY, point.y);
mMaxX = Mathf.Max(mMaxX, point.x);
mMaxY = Mathf.Max(mMaxY, point.y);
}
}
}
}
internal void ModifyLines(int minModifyIndex,List<Vector4> lines)
{
if (mLines.Count == 0)
{
mLines.Add(new LineSegement(lines.ToArray()));
return;
}
mMinModifyIndex = minModifyIndex;
FindBoundingValues();
mLines[0].ModifiyLines(lines);
SetVerticesDirty(); // clear previous animations
Rebuild(CanvasUpdate.PostLayout);
RefreshInputs();
}
public bool EnableOptimization { get; set; }
/// <summary>
/// sets the lines for this renderer
/// </summary>
/// <param name="lines"></param>
internal void SetLines(List<LineSegement> lines)
{
mLines = lines;
FindBoundingValues();
mMinModifyIndex = 0;
SetAllDirty();
ClearEvents(); // clear previous animations
if(EnableOptimization)
Rebuild(CanvasUpdate.PostLayout);
else
Rebuild(CanvasUpdate.PreRender);
}
protected override void UpdateMaterial()
{
base.UpdateMaterial();
canvasRenderer.SetTexture(material.mainTexture);
}
protected override void Awake()
{
base.Awake();
this.raycastTarget = false;
}
/// <summary>
/// this method inflate one point in a line with the specified distantce. This enable the graphic to control the thickness of lines
/// </summary>
/// <param name="point"></param>
/// <param name="dir"></param>
/// <param name="normal"></param>
/// <param name="dist"></param>
/// <param name="size"></param>
/// <param name="z"></param>
/// <param name="p1"></param>
/// <param name="p2"></param>
void GetSide(Vector3 point, Vector3 dir,Vector3 normal,float dist,float size,float z,out Vector3 p1,out Vector3 p2)
{
point.z = z;
point += dir * dist;
normal *= size;
p1 = point + normal;
p2 = point - normal;
}
protected override void OnDestroy()
{
base.OnDestroy();
ChartCommon.SafeDestroy(mCachedMaterial);
}
protected override void OnDisable()
{
base.OnDisable();
}
/// <summary>
/// overriding the default implementation to support materials with _ChartTiling property. This is used to tile texture along the graphic lines
/// </summary>
public override Material material
{
get
{
return base.material;
}
set
{
ChartCommon.SafeDestroy(mCachedMaterial);
if (value == null)
{
mCachedMaterial = null;
base.material = null;
return;
}
mOriginalMaterial = value;
mCachedMaterial = new Material(value);
mCachedMaterial.hideFlags = HideFlags.DontSave;
if (mCachedMaterial.HasProperty("_ChartTiling"))
mCachedMaterial.SetFloat("_ChartTiling", Tiling);
base.material = mCachedMaterial;
}
}
protected override Vector2 Min
{
get
{
return new Vector2(mMinX, mMinY);
}
}
protected override Vector2 Max
{
get
{
return new Vector2(mMaxX, mMaxY);
}
}
protected override float MouseInThreshold
{
get
{
return Mathf.Max(Thickness, mPointSize) + Sensitivity;
}
}
/// <summary>
/// sets the transform of the hover object based on the data in this graphic
/// </summary>
/// <param name="hover"></param>
/// <param name="index"></param>
protected override void SetUpHoverObject(ChartItemEffect hover, int index, int type,object data)
{
if (hover == null)
return;
if (mLines == null || mLines.Count == 0)
return;
if (index < 0)
return;
if (mPointRender)
{
if (index >= mLines[0].PointCount)
return;
Vector4 point = mLines[0].getPoint(index);
RectTransform transform = hover.GetComponent<RectTransform>();
transform.localScale = new Vector3(1f, 1f, 1f);
float size = mPointSize;
if (point.w >= 0f)
size = point.w;
transform.sizeDelta = new Vector2(size, size);
transform.anchoredPosition3D = new Vector3(point.x, point.y, 0f);
}
else
{
if (index >= mLines[0].LineCount)
return;
Vector3 from;
Vector3 to;
mLines[0].GetLine(index, out from, out to);
if (ViewRect.HasValue)
{
Vector2 vFrom = from;
Vector2 vTo = to;
TrimLine(ViewRect.Value, ref vFrom, ref vTo);
from = new Vector3(vFrom.x, vFrom.y, from.z);
to = new Vector3(vTo.x, vTo.y, to.z);
}
Vector3 dir = (to - from);
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
RectTransform transform = hover.GetComponent<RectTransform>();
transform.sizeDelta = new Vector2(dir.magnitude, Thickness);
transform.localScale = new Vector3(1f, 1f, 1f);
transform.localRotation = Quaternion.Euler(0f, 0f, angle);
Vector3 point = (from + to) * 0.5f;
transform.anchoredPosition3D = new Vector3(point.x, point.y, 0f);
}
}
protected override void Pick(Vector3 mouse, out int pickedIndex, out int pickedType, out object selectionData)
{
if (mPointRender)
PickDot(mouse, out pickedType, out pickedIndex,out selectionData);
else
PickLine(mouse, out pickedType, out pickedIndex, out selectionData);
if (pickedIndex >= 0)
pickedIndex += refrenceIndex;
}
protected override void Update()
{
base.Update();
Material mat = material;
if (mCachedMaterial != null && mat != null && mCachedMaterial.HasProperty("_ChartTiling"))
{
if (mCachedMaterial != mat)
mCachedMaterial.CopyPropertiesFromMaterial(mat);
mCachedMaterial.SetFloat("_ChartTiling", Tiling);
}
if(mOriginalMaterial != null && mCachedMaterial!=null)
{
mCachedMaterial.CopyPropertiesFromMaterial(mOriginalMaterial);
}
}
partial void ProcesssPoint(ref Vector4 point, ref float halfSize);
IEnumerable<UIVertex> getDotVeritces()
{
if (mLines == null)
yield break;
float z = 0f;
float halfSize = mPointSize * 0.5f;
for (int i = 0; i < mLines.Count; ++i)
{
LineSegement seg = mLines[i];
int total = seg.PointCount;
for (int j = mMinModifyIndex; j < total; ++j)
{
Vector4 magPoint = seg.getPoint(j);
if (magPoint.w == 0f)
continue;
Vector3 point = (Vector3)magPoint;
halfSize = mPointSize * 0.5f;
ProcesssPoint(ref magPoint, ref halfSize);
Vector3 p1 = point + new Vector3(-halfSize, -halfSize, 0f);
Vector3 p2 = point + new Vector3(halfSize, -halfSize, 0f);
Vector3 p3 = point + new Vector3(-halfSize, halfSize, 0f);
Vector3 p4 = point + new Vector3(halfSize, halfSize, 0f);
Vector2 uv1 = new Vector2(0f, 0f);
Vector2 uv2 = new Vector2(1f, 0f);
Vector2 uv3 = new Vector2(0f, 1f);
Vector2 uv4 = new Vector2(1f, 1f);
UIVertex v1 = ChartCommon.CreateVertex(p1, uv1, z);
UIVertex v2 = ChartCommon.CreateVertex(p2, uv2, z);
UIVertex v3 = ChartCommon.CreateVertex(p3, uv3, z);
UIVertex v4 = ChartCommon.CreateVertex(p4, uv4, z);
if(ClipRect.HasValue== false || ClipRect.Value.Contains(p1) || ClipRect.Value.Contains(p2) || ClipRect.Value.Contains(p3)
|| ClipRect.Value.Contains(p4))
{
yield return v1;
yield return v2;
yield return v3;
yield return v4;
}
}
}
}
Vector2 TransformUv(Vector2 uv)
{
return uv;
//if (mUvRect.HasValue == false)
// return uv;
//Rect r = mUvRect.Value;
//float x = r.x + uv.x * r.width;
//float y = r.y + uv.y * r.height;
//return new Vector2(x, y);
}
IEnumerable<UIVertex> getFillVeritces()
{
if (mLines == null)
yield break;
float z = 0f;
for (int i = 0; i < mLines.Count; ++i)
{
LineSegement seg = mLines[i];
int totalLines = seg.LineCount;
for (int j = mMinModifyIndex; j < totalLines; ++j)
{
Vector3 from;
Vector3 to;
seg.GetLine(j,out from, out to);
Vector2 toTrim = to;
Vector2 fromTrim = from;
// TrimItem(mFillRect.xMin, mFillRect.yMin, mFillRect.xMax, mFillRect.yMin, true, false, ref fromTrim, ref toTrim);
to = new Vector3(toTrim.x, toTrim.y, to.z);
from = new Vector3(fromTrim.x, fromTrim.y, from.z);
Vector3 fromBottom = from;
Vector3 toBottom = to;
fromBottom.y = mFillZero;// mFillRect.yMin;
toBottom.y = mFillZero;// mFillZero; ;// mFillRect.yMin;
float fromV = 1f;
float toV = 1f;
if (mStretchY == false)
{
fromV = Mathf.Abs((from.y - mFillZero) / mFillRect.height);
toV = Mathf.Abs((to.y - mFillZero) / mFillRect.height);
}
float fromU = ((from.x - mFillRect.xMin) / mFillRect.width);
float toU = ((to.x - mFillRect.xMin) / mFillRect.width);
Vector2 uv1 = TransformUv(new Vector2(fromU, fromV));
Vector2 uv2 = TransformUv(new Vector2(toU, toV));
Vector2 uv3 = TransformUv(new Vector2(fromU, 0f));
Vector2 uv4 = TransformUv(new Vector2(toU, 0f));
UIVertex v1 = ChartCommon.CreateVertex(from, uv1, z);
UIVertex v2 = ChartCommon.CreateVertex(to, uv2, z);
UIVertex v3 = ChartCommon.CreateVertex(fromBottom, uv3, z);
UIVertex v4 = ChartCommon.CreateVertex(toBottom, uv4, z);
if ((from.y < mFillZero) ^ (to.y < mFillZero))
{
Vector3 crossing = ChartCommon.LineCrossing(from, to, mFillZero);
float crossU = ((crossing.x - mFillRect.xMin) / mFillRect.width);
Vector2 uvCross = TransformUv(new Vector2(crossU, 0f));
UIVertex vCross = ChartCommon.CreateVertex(crossing, uvCross, z);
yield return v1;
yield return vCross;
yield return v3;
yield return v3;
yield return v2;
yield return vCross;
yield return v4;
yield return v4;
}
else
{
yield return v1;
yield return v2;
yield return v3;
yield return v4;
}
}
}
}
IEnumerable<UIVertex> getLineVertices()
{
if (mLines == null)
yield break;
float halfThickness = Thickness * 0.5f;
float z = 0f;
for (int i = 0; i < mLines.Count; ++i)
{
LineSegement seg = mLines[i];
int totalLines = seg.LineCount;
Line? peek = null;
Line? prev = null;
float tileUv = 0f;
float totalUv = 0f;
for (int j = mMinModifyIndex; j < totalLines; ++j)
totalUv += (float)seg.GetLineMag(j);
for (int j = mMinModifyIndex; j < totalLines; ++j)
{
Line line;
bool hasNext = j + 1 < totalLines;
if (peek.HasValue)
line = peek.Value;
else
line = seg.GetLine(j, halfThickness, prev.HasValue, hasNext);
peek = null;
if (j + 1 < totalLines)
peek = seg.GetLine(j + 1, halfThickness, true, j + 2 < totalLines);
Vector3 p1 = line.P1;
Vector3 p2 = line.P2;
Vector3 p3 = line.P3;
Vector3 p4 = line.P4;
Vector2 uv1 = new Vector2(tileUv * Tiling, 0f);
Vector2 uv2 = new Vector2(tileUv * Tiling, 1f);
tileUv += line.Mag / totalUv;
Vector2 uv3 = new Vector2(tileUv * Tiling, 0f);
Vector2 uv4 = new Vector2(tileUv * Tiling, 1f);
UIVertex v1 = ChartCommon.CreateVertex(p1, uv1, z);
UIVertex v2 = ChartCommon.CreateVertex(p2, uv2, z);
UIVertex v3 = ChartCommon.CreateVertex(p3, uv3, z);
UIVertex v4 = ChartCommon.CreateVertex(p4, uv4, z);
yield return v1;
yield return v2;
yield return v3;
yield return v4;
if (peek.HasValue)
{
float myZ = z + 0.2f;
Vector3 a1, a2;
GetSide(line.To, line.Dir, line.Normal, halfThickness * 0.5f, halfThickness * 0.6f, v3.position.z, out a1, out a2);
yield return v3;
yield return v4;
yield return ChartCommon.CreateVertex(a1, v3.uv0, myZ);
yield return ChartCommon.CreateVertex(a2, v4.uv0, myZ);
}
if (prev.HasValue)
{
float myZ = z + 0.2f;
Vector3 a1, a2;
GetSide(line.From, -line.Dir, line.Normal, halfThickness * 0.5f, halfThickness * 0.6f, v1.position.z, out a1, out a2);
yield return ChartCommon.CreateVertex(a1, v1.uv0, myZ);
yield return ChartCommon.CreateVertex(a2, v2.uv0, myZ);
yield return v1;
yield return v2;
}
//z -= 0.05f;
prev = line;
}
}
}
IEnumerable<UIVertex> getVerices()
{
IEnumerable<UIVertex> vertices;
if (mPointRender)
vertices = getDotVeritces();
else
{
if (mFillRender)
vertices = getFillVeritces();
else
vertices = getLineVertices();
}
return vertices;
}
Mesh mVHMesh;
List<Vector3> mPositions = new List<Vector3>();
List<Vector2> mUvs = new List<Vector2>();
List<int> mTringles = new List<int>();
void WriteTo<T> (List<T> list,int index,T val)
{
if (list.Count == index)
list.Add(val);
else
list[index] = val;
}
protected override void UpdateGeometry()
{
if (EnableOptimization == false)
{
mMinModifyIndex = 0;
base.UpdateGeometry();
return;
}
if (mVHMesh == null)
mVHMesh = new Mesh();
if (mMinModifyIndex == int.MaxValue)
mMinModifyIndex = mPositions.Count;
if (mMinModifyIndex <= 0)
{
mMinModifyIndex = 0;
mPositions.Clear();
mUvs.Clear();
mTringles.Clear();
foreach (UIVertex v in getVerices())
{
mPositions.Add(v.position);
mUvs.Add(v.uv0);
}
int quads = (mPositions.Count / 4) ;
int baseIndex = 0;
for (int i = 0; i < quads; i++)
{
mTringles.Add(baseIndex);
mTringles.Add(baseIndex + 1);
mTringles.Add(baseIndex + 3);
mTringles.Add(baseIndex + 3);
mTringles.Add(baseIndex + 2);
mTringles.Add(baseIndex);
baseIndex += 4;
}
}
else
{
// Debug.Log("adding");
int total = 0;
int index = mMinModifyIndex;
foreach (UIVertex v in getVerices())
{
// Debug.Log("extra");
WriteTo<Vector3>(mPositions, index, v.position);
WriteTo<Vector2>(mUvs, index, v.uv0);
total++;
}
int quads = total / 4;
for (int i = 0; i < quads; i++)
{
// Debug.Log("extra tring");
mTringles.Add(0);
mTringles.Add(1);
mTringles.Add(3);
mTringles.Add(3);
mTringles.Add(2);
mTringles.Add(0);
}
}
mVHMesh.Clear();
mVHMesh.SetVertices(mPositions);
mVHMesh.SetUVs(0, mUvs);
mVHMesh.SetTriangles(mTringles, 0);
//at the end
mMinModifyIndex = int.MaxValue;
GetComponent<CanvasRenderer>().SetMesh(mVHMesh);
}
#if (!UNITY_5_2_0) && (!UNITY_5_2_1)
protected override void OnPopulateMesh(VertexHelper vh)
{
base.OnPopulateMesh(vh);
vh.Clear();
int vPos = 0;
foreach (UIVertex v in getVerices())
{
mTmpVerts[vPos++] = v;
if (vPos == 4)
{
UIVertex tmp = mTmpVerts[2];
mTmpVerts[2] = mTmpVerts[3];
mTmpVerts[3] = tmp;
vPos = 0;
vh.AddUIVertexQuad(mTmpVerts);
}
}
}
#endif
#pragma warning disable 0672
#if !UNITY_2017_1_OR_NEWER
/// <summary>
/// A chart mesh used for populating the
/// </summary>
WorldSpaceChartMesh mMesh = null;
protected override void OnPopulateMesh(Mesh m)
{
if (mMesh == null)
mMesh = new WorldSpaceChartMesh(1);
else
mMesh.Clear();
int vPos = 0;
mMinModifyIndex = 0; // not supported here
foreach (UIVertex v in getVerices())
{
mTmpVerts[vPos++] = v;
if (vPos == 4)
{
vPos = 0;
mMesh.AddQuad(mTmpVerts[0], mTmpVerts[1], mTmpVerts[2], mTmpVerts[3]);
}
}
mMesh.ApplyToMesh(m);
}
#endif
void PickLine(Vector3 mouse, out int segment, out int line, out object selectionData)
{
float minDist = Mathf.Infinity;
segment = -1;
line = -1;
selectionData = null;
if (mLines == null)
{
return;
}
for (int i = 0; i < mLines.Count; ++i)
{
LineSegement seg = mLines[i];
int total = seg.LineCount;
for (int j = 0; j < total; ++j)
{
Vector3 from;
Vector3 to;
seg.GetLine(j, out from, out to);
float dist = ChartCommon.SegmentPointSqrDistance(from,to,mouse);
if (dist < minDist)
{
minDist = dist;
segment = i;
line = j;
}
}
}
float thresh = (Thickness + Sensitivity);
if ((ViewRect.HasValue && !ViewRect.Value.Contains(mouse)) || minDist > thresh * thresh)
{
segment = -1;
line = -1;
}
}
void PickDot(Vector3 mouse, out int segment , out int point, out object selectionData)
{
float minDist = Mathf.Infinity;
segment = -1;
point = -1;
selectionData = null;
if (mLines == null)
return;
float mag = mPointSize;
for (int i = 0; i < mLines.Count; ++i)
{
LineSegement seg = mLines[i];
int total = seg.PointCount;
for (int j = 0; j < total; ++j)
{
Vector4 p = seg.getPoint(j);
if (p.w == 0f)
continue;
float dist = (mouse - ((Vector3)p)).sqrMagnitude;
if(dist < minDist)
{
mag = p.w;
if (mag < 0f)
mag = mPointSize;
minDist = dist;
segment = i;
point = j;
}
}
}
float thresh = mag + Sensitivity;
if ((ViewRect.HasValue && !ViewRect.Value.Contains(mouse)) || minDist > thresh * thresh)
{
segment = -1;
point = -1;
}
}
void TrimItem(float x1, float y1 ,float x2,float y2,bool xAxis,bool oposite, ref Vector2 from, ref Vector2 to)
{
Vector2 seg1 = new Vector2(x1, y1);
Vector2 seg2 = new Vector2(x2, y2);
Vector2 point;
if (ChartCommon.SegmentIntersection(seg1, seg2, from, to, out point) == false)
return;
if(xAxis)
{
if ((to.y > from.y) ^ oposite)
from = point;
else
to = point;
return;
}
if ((to.x > from.x) ^ oposite)
from = point;
else
to = point;
}
void TrimLine(Rect r,ref Vector2 from, ref Vector2 to)
{
TrimItem(r.xMin, r.yMin, r.xMax, r.yMin, true, false, ref from, ref to);
TrimItem(r.xMin, r.yMax, r.xMax, r.yMax, true, true, ref from, ref to);
TrimItem(r.xMin, r.yMin, r.xMin, r.yMax, false, false, ref from, ref to);
TrimItem(r.xMax, r.yMin, r.xMax, r.yMax, false, true, ref from, ref to);
}
#pragma warning restore 0672
}
}