.net 4 vs2010 winform c#
を使用していくつかのポイントを追加しました
chart1.Series[0].Points.AddXY(x,y);
チャートをクリックすると、カーソルがポイントに落ちないことがあります。最も近い点を返す関数はありますか? (y を忘れて、x 距離だけです。) それとも、独自のバイナリ検索関数を作成する必要がありますか?
.net 4 vs2010 winform c#
を使用していくつかのポイントを追加しました
chart1.Series[0].Points.AddXY(x,y);
チャートをクリックすると、カーソルがポイントに落ちないことがあります。最も近い点を返す関数はありますか? (y を忘れて、x 距離だけです。) それとも、独自のバイナリ検索関数を作成する必要がありますか?
private void Chart_MouseClick(object sender, MouseButtonEventArgs e)
{
LineSeries line = (LineSeries)mychart.Series[0];
Point point = e.GetPosition(line);
Int32? selectIndex = FindNearestPointIndex(line.Points, point);
// ...
}
private Int32? FindNearestPointIndex(PointCollection points, Point point)
{
if ((points == null || (points.Count == 0))
return null;
Func<Point, Point, Double> getLength = (p1, p2) => Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); // C^2 = A^2 + B^2
List<Points> results = points.Select((p,i) => new { Point = p, Length = getLength(p, point), Index = i }).ToList();
Int32 minLength = results.Min(i => i.Length);
return results.First(i => (i.Length == minLength)).Index;
}
一連の順序付けられていないポイントで最も近いポイントを見つけるには、それらすべてを反復処理し、最小距離を追跡する必要があります。これは O(n) の時間計算量を持っています。
より組織化されたデータ構造 ( R ツリーなど) でポイントを維持することにより、これを大幅に改善できます。独自のライブラリを実装したくない場合は、サードパーティのライブラリを利用できます。多くのデータベースは、空間インデックスの R ツリーを既にサポートしています。
最も近い X 座標を持つポイントのみを検索したい場合は、ソートされたコレクション ( など) にポイントを格納しSortedList<TKey, TValue>
、バイナリ検索 (SortedList<TKey, TValue>.IndexOfKey
既に実装されています) を実行することで、さらに単純化できます。
/*My Fuzzy Binary Search*/
private int FindNearestId(System.Windows.Forms.DataVisualization.Charting.DataPointCollection p, uint ClickedX)
{
int ret = 0;
int low = 0;
int high = p.Count - 1;
bool bLoop = true;
while (bLoop)
{
ret = (low + high) / 2;
switch (FindNearestId_Match(p, ClickedX, ret))
{
case 0:
high = ret+1;
break;
case 1:
bLoop = false;
break;
case 2:
low = ret-1;
break;
}
}
return ret+1;
}
private int FindNearestId_Match(System.Windows.Forms.DataVisualization.Charting.DataPointCollection p, uint ClickedX, int id)
{
uint id0 = Convert.ToUInt32(p[id].XValue);
uint id1 = Convert.ToUInt32(p[id+1].XValue);
if ( (id0 <= ClickedX) && (ClickedX < id1) )
{
return 1;
}
else if ((id0 < ClickedX) && (ClickedX > id1))
{
return 2;
}
else
{
return 0;
}
}