2

我想知道将此 C# 方法转换为 Scala 函数的最佳方法,似乎使用 scala 的语法可以更简洁。

bool IsPointInPolygon(List<Loc> poly, Loc point)
{
    int i, j;
    bool c = false;
    for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
    {
        if ((((poly[i].Lt <= point.Lt) && (point.Lt < poly[j].Lt)) ||
            ((poly[j].Lt <= point.Lt) && (point.Lt < poly[i].Lt))) &&
            (point.Lg < (poly[j].Lg - poly[i].Lg) * (point.Lt - poly[i].Lt) /
            (poly[j].Lt - poly[i].Lt) + poly[i].Lg))
                c = !c;
    }
    return c;
}
4

2 回答 2

1

怎么样:

sealed case class Loc(lat: Double, long: Double)

def isPointInPolygon(poly: List[Loc], x: Loc): Boolean = {
  (poly.last :: poly).sliding(2).foldLeft(false) { case (c, List(i, j)) =>
    val cond = {
      (
        (i.lat <= x.lat && x.lat < j.lat) ||
        (j.lat <= x.lat && x.lat < i.lat)
      ) &&
      (x.long < (j.long - i.long) * (x.lat - i.lat) / (j.lat - i.lat) + i.long)
    }

    if (cond) !c else c
  }
}
于 2014-10-10T01:16:50.133 回答
1

假设您的算法是正确的,您可以观察到boolean每次满足特定条件时通过切换获得结果。因此,您可以计算这些条件。

此外,您正在成对地迭代这些点(j基本上i - 1,如果我理解代码正确,除了j必须回绕到的初始迭代poly.Count - 1)。

要获得对,如果polyscala.List

val pairs = (poly.last :: poly).sliding(2, 1)

在与 形成对之前,将最后一个元素添加到列表中sliding,例如

val x = List("a", "b", "c")
(x.last :: x).sliding(2,1).toList // gives List(List(c, a), List(a, b), List(b, c))

(严格来说,last这不是一个非常有效的方法scala.List,但它有效)

那么你会有

pairs.count { case Seq(pi, pj) => checkCondition } % 2 == 1

那里case Seq(pi, pj)再次为你提取相邻点,并% 2 == 1询问你是否计算了奇数次。


滑动的替代方法是使用该foldLeft方法。这可能更具表现力,因为没有创建嵌套集合,但更多的是一个聪明的解决方案。诀窍是绕过前一点当前结果(c在您的原始代码中):

poly.foldLeft(poly.last -> false) { case ((pj, c), pi) => pi -> (c ^ checkCondition)}

这再次使用模式匹配 ( case ...) 来优雅地解包折叠的参数。

于 2012-07-25T00:10:22.203 回答