給定兩個坐標串列(作為雙三坐標)
var reference =
new List<(double x, double y, double z) ()
{(10,10,10) 。
(15,15,15) }。
和一組現實世界的坐標,如
var coords =
new List<(double x, double y, double z) ()
{(9.97,10.02,10) 。
(15.01,14.98,15) 。
(12.65,18.69,0) }。
我需要coords的專案,其中數值的偏差在 /-0.1之內,所以預期的結果是:
res = {coords[0, coords[1]}。//resp.the items of course.。
兩個串列都可以有幾千個條目,所以Where/Contains似乎不是一個好的選擇。
uj5u.com熱心網友回復:
首先你將需要一個函式來比較距離。我將使用Vector3而不是一個值元組,因為它更容易寫:
public bool IsAlmostEqual(Vector3 a。Vector3 b, float epsilon){
return DistanceSquared(a, b) < (epsilon * epsilon)
}
public double DistanceSquared(Vector3 a, Vector3 b){
var c = a - b。
return c.x * c.x c.y * c.y c.z * c.z ;
如果你只想檢查每個坐標的對應索引,你只需寫一個回圈:
如果你只想檢查每個坐標的對應索引,你只需寫一個回圈:
for(var i = 0; i < coords.Count; i ){
if(IsAlmostEqual(coords[i], reference[i], 0.1) {
...
}
else{
...
}
如果你想檢查Coords和參考位置的每個組合,你只需添加一個回圈。這并不能很好地擴展,但是1000個專案將導致內回圈的大約500000次迭代,而我希望這將花費大約一毫秒。
如果你需要處理更大的坐標集,你應該研究某種搜索結構,如KD樹。
uj5u.com熱心網友回復:
我想你是想在一個與目標點相匹配的點的串列中尋找匹配。另外,你也可以在一個串列中與所有的點匹配。
首先,我創建了一個通用的比較類 ApproxEqual 來比較集合和圖元。
接下來,我在ApproxFind()
見下面的示例代碼:
class Program
{
static void Main(string[] args)?
{
var actual_points = new List<(float, float, float) > ()
{
(9.97f,10.02f,10) 。
(15.01f,14.98f,15) 。
(12.65f,18.69f,0) 。
(10.03f,9.98f,10) 。
};
var target = (10f, 10f, 10f) 。
var match = ApproxFind( actual_points, target, 0.1f);
foreach (var item in match)
{
Console.WriteLine(item)。
// (9.97, 10.02, 10)
// (10.03, 9.98, 10)。
}
var targetAll = new[] { (10f, 10f, 10f), (15f, 15f, 15f) };
var matchAll = ApproxFind( actual_points, targetAll , 0.1f);
foreach (var item in matchAll)
{
Console.WriteLine(item)。
// (9.97, 10.02, 10)
// (10.03, 9.98, 10)
// (15.01, 14.98, 15)
}
}
// <summary>/span>
// 尋找<paramref name="list"/> 中靠近<paramref name="target"/>的公差<paramref name="tolerance"/>
// </summary>/span>
public static IEnumerable< (float, float, float) > ApproxFind(IEnumerable< (float, float, float) > list, (float, float, float) target, float tolerance)
{
var comp = new ApproxEqual(tolerance);
foreach (var item in list)
{
if (comp.Compare(item, target) == 0)
{
yield return item。
}
}
}
// <summary>
// 查找<paramref name="list"/> <paramref name="target"/>中靠近<paramref name="tolerance"/>中任何一個專案的公差<paramref name="tolerance"
// </summary>/span>
public static IEnumerable< (float, float, float) > ApproxFind(IEnumerable< (float, float, float) > list, IEnumerable< (float, float, float)> targets, float tolerance)
{
var comp = new ApproxEqual(tolerance);
foreach (var other in targets)
{
foreach (var item in list)
{
if (comp.Compare(item, other) == 0)
{
yield return item。
}
}
}
}
}
// <summary>
//實作圖元和集合的近似比較。
// </summary>
public class ApproxEqual :
IComparer<ICollection<float> >。
IComparer<ValueTuple< float,float,float> >。
System.Collections.IComparer[/span]。
{
public ApproxEqual(float tolerance)。
{
公差 = 公差。
}
public float Tolerance { get; }
int System.Collections.IComparer.Compare(object x,object y)
{
if (x is ICollection<float> x_arr && y is ICollection<float> y_arr)
{
return Compare(x_arr, y_arr);
}
if (x is ValueTuple<float, float, float> x_tuple && y is ValueTuple<float, float, float> y_tuple)
{
return Compare(x_tuple, y_tuple)。
}
return -1;
}
public int Compare(ICollection< float> x, ICollection<float> y)
{
if (x.Count == y.Count)
{
foreach (var delta in x.Zip(y, (xi,yi)=> Math.Abs(xi-yi))
{
if (delta > Tolerance) return -1;
}
return 0;
}
return 1;
}
public int Compare((float, float。浮動) x, (浮動, float, float>) y)
{
if (Math.Abs(x.Item1 - y.Item1) > Tolerance) return -1;
if (Math.Abs(x.Item2 - y.Item2) > Tolerance) return -1。
if (Math.Abs(x.Item3 - y.Item3) > Tolerance) return -1;
return 0;
}
PS. 我使用浮點數是因為我想使用System.Numerics而被卡住了。將上述內容轉換為支持double也很容易。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/322812.html
標籤:
