使用 LINQ 确定 2 个图的相对位置

发布于 2024-10-06 09:21:57 字数 747 浏览 8 评论 0原文

我有两个点数组:double[] minusdouble[] plus,例如:

double[] minus = new[]
{
    24.043414306636713,
    26.521399902043807,
    23.049167719142361,
    24.473177606966754,
    18.238281854192408,
};

double[] plus = new[]
{
    8.31219054269323,
    9.5909890877229582,
    11.066525870449567,
    22.769068312057193,
    24.733540360065991,
};

我需要根据这个数字绘制 2 个图表,并确定它们相对于每个图表的位置other:是否存在交叉点,并且其中哪个在另一个下?

我怎样才能做到这一点? TIA

(请随意重新标记问题或更改主题,我不确定使用了正确的数学术语)

编辑:这是一个 Excel 图表:

https://i.sstatic.net/NEhcs.png

很容易确定哪个在上面,哪个在下面。

如何判断红色(加号)与蓝色(减号)有交集?也许使用 LINQ?

I have two arrays of points: double[] minus and double[] plus, e.g.:

double[] minus = new[]
{
    24.043414306636713,
    26.521399902043807,
    23.049167719142361,
    24.473177606966754,
    18.238281854192408,
};

double[] plus = new[]
{
    8.31219054269323,
    9.5909890877229582,
    11.066525870449567,
    22.769068312057193,
    24.733540360065991,
};

I need to plot 2 diagrams basing on this number and determine their positions relatively to each other: are there an intersection and which of them is under another?

How can I do that? TIA

(please feel free to retag the question or change the topic, I'm not sure in proper math terminology used)

Edit: Here's an Excel diagram:

https://i.sstatic.net/NEhcs.png

It's easy to determine which is above and which is under.

How to determine that red (plus) has an intersection with blue (minus)? Using maybe LINQ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦里人 2024-10-13 09:21:57

此代码可以找到所有碰撞:

double[] minus = new double[]
{
    3, 24, 26, 23, 25, 18, 5,  5,  1, 10,
};
double[] plus = new ![alt text][1]double[]
{
    3,  8,  9, 11, 22, 25, 5,  5,  3, 7
};

var collisionsBetweenIndices =
Enumerable.Range(1, minus.Length - 1)
          .Where(i => ((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
                      ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
                      ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0)))
          .ToArray();

var collisionsOnIndices =
Enumerable.Range(0, minus.Length)
          .Where(i => minus[i] == plus[i])
          .ToArray();

foreach (var idx in collisionsBetweenIndices)
    Console.WriteLine("Collision between {0} and {1}", idx - 1, idx);

foreach (var idx in collisionsOnIndices)
    Console.WriteLine("Collision on {0}", idx);

// RESULTS:
// Collision between 4 and 5
// Collision between 6 and 7
// Collision between 8 and 9
// Collision on 0
// Collision on 6
// Collision on 7

alt text

编辑:

我做了两种不同的方法来区分碰撞的类型(即索引之间或索引上),但如果您的目的只是检测是否存在碰撞,只需执行以下操作:

var collisionDetected =
Enumerable.Range(0, minus.Length).Any(i =>
{
    if (minus[i] == plus[i])
        return true;
    if (i > 0 &&
        (((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
        ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
        ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0))))
    {
        return true;
    }
    return false;
});

一旦发现碰撞,此代码就会返回,因此通常比上面的更快方法。

This code can found all collisions:

double[] minus = new double[]
{
    3, 24, 26, 23, 25, 18, 5,  5,  1, 10,
};
double[] plus = new ![alt text][1]double[]
{
    3,  8,  9, 11, 22, 25, 5,  5,  3, 7
};

var collisionsBetweenIndices =
Enumerable.Range(1, minus.Length - 1)
          .Where(i => ((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
                      ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
                      ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0)))
          .ToArray();

var collisionsOnIndices =
Enumerable.Range(0, minus.Length)
          .Where(i => minus[i] == plus[i])
          .ToArray();

foreach (var idx in collisionsBetweenIndices)
    Console.WriteLine("Collision between {0} and {1}", idx - 1, idx);

foreach (var idx in collisionsOnIndices)
    Console.WriteLine("Collision on {0}", idx);

// RESULTS:
// Collision between 4 and 5
// Collision between 6 and 7
// Collision between 8 and 9
// Collision on 0
// Collision on 6
// Collision on 7

alt text

EDIT:

I did two different methods to distinguish the type of collisions (i.e. between indices or on indices), but if your purpouse is just to detect if there's a collision or not, just do the following:

var collisionDetected =
Enumerable.Range(0, minus.Length).Any(i =>
{
    if (minus[i] == plus[i])
        return true;
    if (i > 0 &&
        (((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
        ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
        ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0))))
    {
        return true;
    }
    return false;
});

This code returns as soon as a collision is found, so it's generally faster the the above methods.

梦里泪两行 2024-10-13 09:21:57

要确定哪个更高,只需将 minus[i] 与 plus[i] 进行比较 - 较大的值就是 i 处的“较高”值。

要确定交叉点,只需跟踪哪个交叉点较高即可。当这种情况发生变化时,就会出现一个交叉点。

编辑

如果您无法跟踪历史记录,则:

if ((minus[i-1] > plus[i-1]) != (minus[i] > plus[i])) then
  // there was an intersection
else
  // there was not an intersection

To determine which is higher, just compare minus[i] to plus[i] - whichever has the greater value is the "higher" one at i.

To determine intersections, just keep track of which one is higher. When that changes, there was an intersection.

Edit

If you can't track history, then:

if ((minus[i-1] > plus[i-1]) != (minus[i] > plus[i])) then
  // there was an intersection
else
  // there was not an intersection
逆流 2024-10-13 09:21:57

一种方法是将每个系列分解为线段,然后比较两个系列中相应的(按索引)线段。

由于您特别提到了 LINQ,因此这是实现这一目标的一种方法。它不是很漂亮:

var minusPairs = minus.Zip(minus.Skip(1), (prev, next) => new { prev, next });
var plusPairs = plus.Zip(plus.Skip(1), (prev, next) => new { prev, next });

var positions = minusPairs.Zip
               (plusPairs, (mPair, pPair) =>
                mPair.prev > pPair.prev 
                     && mPair.next > pPair.next ? "MinusAbove" :
                mPair.prev < pPair.prev
                     && mPair.next < pPair.next ? "PlusAbove" :
               "Intersection");

输出:(

MinusAbove
MinusAbove
MinusAbove
Intersection

请注意,您不会获得最后一点的 PlusAbove,因为它所属的唯一线段代表一个 Intersection。您可能需要如果需要的话可以改变这种行为。)

说实话,如果您需要做任何比这更复杂的事情(例如找到交点),我会回避任何“可爱”的解决方案。这里需要良好的面向对象设计。

One way would be to break each series up into line-segments, and then compare corresponding (by index) segments from the two series.

Since you specifically mention LINQ, here's one way to achieve that. It's not very pretty:

var minusPairs = minus.Zip(minus.Skip(1), (prev, next) => new { prev, next });
var plusPairs = plus.Zip(plus.Skip(1), (prev, next) => new { prev, next });

var positions = minusPairs.Zip
               (plusPairs, (mPair, pPair) =>
                mPair.prev > pPair.prev 
                     && mPair.next > pPair.next ? "MinusAbove" :
                mPair.prev < pPair.prev
                     && mPair.next < pPair.next ? "PlusAbove" :
               "Intersection");

Output:

MinusAbove
MinusAbove
MinusAbove
Intersection

(Note that you don't get a PlusAbove for the last point because the only segment it is part of represents an Intersection. You may need to change this behaviour if desirable.)

To be honest, I would shy away from any 'cute' solution if you need to do anything even slightly more complicated than this (e.g. finding the intersection points). Good OO design is needed here.

︶ ̄淡然 2024-10-13 09:21:57

为什么你不能这样做:

for i=1...n
    if minus[i] > plus[i]
         return "Crossed over at index i"

Why can't you just do:

for i=1...n
    if minus[i] > plus[i]
         return "Crossed over at index i"
与君绝 2024-10-13 09:21:57
public string DetermineCollisionInfo(double current, double next)
{
  string currentInfo =
    current == 0.0 ? "Plus and Minus have same value" :
    current < 0.0 && next > 0.0 ? "Intersection occurs" :
    current > 0.0 && next < 0.0 ? "Intersection occurs" :
    "No Intersection";

  string nextInfo =
    next > 0.0 ? "Plus will be on top" :
    next < 0.0 ? "Minus will be on top" :
    "Plus and Minus will have same value";

  return currentInfo + ".  " + nextInfo;
}

然后,后来:

IEnumerable<double> differences = Enumerable
    .Range(0, minus.Length)
    .Select(i => plus[i] - minus[i]);

double current = differences.First();
IEnumerable<string> analysis = differences
  .Skip(1)
  .Select(next =>
  {
    string result = DetermineCollisionInfo(current, next);
    current = next;
    return result;
  });

foreach(string info in analysis)
{
  Console.WriteLine(analysis);
}
public string DetermineCollisionInfo(double current, double next)
{
  string currentInfo =
    current == 0.0 ? "Plus and Minus have same value" :
    current < 0.0 && next > 0.0 ? "Intersection occurs" :
    current > 0.0 && next < 0.0 ? "Intersection occurs" :
    "No Intersection";

  string nextInfo =
    next > 0.0 ? "Plus will be on top" :
    next < 0.0 ? "Minus will be on top" :
    "Plus and Minus will have same value";

  return currentInfo + ".  " + nextInfo;
}

Then, later:

IEnumerable<double> differences = Enumerable
    .Range(0, minus.Length)
    .Select(i => plus[i] - minus[i]);

double current = differences.First();
IEnumerable<string> analysis = differences
  .Skip(1)
  .Select(next =>
  {
    string result = DetermineCollisionInfo(current, next);
    current = next;
    return result;
  });

foreach(string info in analysis)
{
  Console.WriteLine(analysis);
}
长安忆 2024-10-13 09:21:57

如果 minusplus 是列表:

var plus1 = plus.Skip(1);
var retVal = minus
    .Skip(1)
    .Select((p,i) => new { index = i, value = (minus[i] > plus[i]) != (p > plus1[i])})
    .Where( p => !p.value);

if minus and plus are list:

var plus1 = plus.Skip(1);
var retVal = minus
    .Skip(1)
    .Select((p,i) => new { index = i, value = (minus[i] > plus[i]) != (p > plus1[i])})
    .Where( p => !p.value);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文