You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改C#代码判断点是否在多环Polygon内(Azure CosmosDB场景)

支持多环Polygon的点-in-多边形判断实现

问题背景

在Azure CosmosDB中存储的Polygon数据结构如下(可能包含多个环,第一环为外环,其余为内部排除区域):

{
   ...
   "Polygon": {
       "type": "Polygon",
       "coordinates": [
       [
        -72.2811341,
        42.9275741
       ],
       [
        -72.2816062,
        42.9256955
       ],
       [
        -72.2780764,
        42.9261986
       ],
       [
        -72.2811341,
        42.9275741
       ]
     ]
   },
   ...
}

现有如下C#方法仅支持单环Polygon的点-in-多边形判断,需要修改以支持多环场景:

private bool IsPointInPolygon(Point p, Position[] polygon)
{
  double minX = polygon[0].Latitude;
  double maxX = polygon[0].Latitude;
  double minY = polygon[0].Longitude;
  double maxY = polygon[0].Longitude;
  for (int i = 1; i < polygon.Length; i++)
  {
    Position q = polygon[i];
    minX = Math.Min(q.Latitude, minX);
    maxX = Math.Max(q.Latitude, maxX);
    minY = Math.Min(q.Longitude, minY);
    maxY = Math.Max(q.Longitude, maxY);
  }
  if (p.Position.Latitude < minX || p.Position.Latitude > maxX || p.Position.Longitude < minY || p.Position.Longitude > maxY)
  {
    return false;
  }
  bool inside = false;
  for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
  {
    if ((polygon[i].Longitude > p.Position.Longitude) != (polygon[j].Longitude > p.Position.Longitude) &&
         p.Position.Latitude < (polygon[j].Latitude - polygon[i].Latitude) * (p.Position.Longitude - polygon[i].Longitude) / (polygon[j].Longitude - polygon[i].Longitude) + polygon[i].Latitude)
    {
      inside = !inside;
    }
  }
  return inside;
}

修改方案

核心逻辑:点必须在外环内部,同时不在任何一个内环(排除区)内部,才判定为在多环Polygon内。

修改后的代码

保留原单环判断逻辑作为基础方法,新增多环处理的外层方法:

// 原单环判断方法,改为私有辅助方法
private bool IsPointInSingleRing(Point p, Position[] ring)
{
  if (ring == null || ring.Length < 3)
    return false;

  double minX = ring[0].Latitude;
  double maxX = ring[0].Latitude;
  double minY = ring[0].Longitude;
  double maxY = ring[0].Longitude;
  for (int i = 1; i < ring.Length; i++)
  {
    Position q = ring[i];
    minX = Math.Min(q.Latitude, minX);
    maxX = Math.Max(q.Latitude, maxX);
    minY = Math.Min(q.Longitude, minY);
    maxY = Math.Max(q.Longitude, maxY);
  }
  // 边界盒快速排除,提升性能
  if (p.Position.Latitude < minX || p.Position.Latitude > maxX || 
      p.Position.Longitude < minY || p.Position.Longitude > maxY)
  {
    return false;
  }

  bool inside = false;
  for (int i = 0, j = ring.Length - 1; i < ring.Length; j = i++)
  {
    if ((ring[i].Longitude > p.Position.Longitude) != (ring[j].Longitude > p.Position.Longitude) &&
         p.Position.Latitude < (ring[j].Latitude - ring[i].Latitude) * (p.Position.Longitude - ring[i].Longitude) / (ring[j].Longitude - ring[i].Longitude) + ring[i].Latitude)
    {
      inside = !inside;
    }
  }
  return inside;
}

// 多环Polygon判断方法
private bool IsPointInMultiRingPolygon(Point p, Position[][] polygonRings)
{
  if (polygonRings == null || polygonRings.Length == 0)
    return false;

  // 第一步:判断是否在外环内(第一个环为外环)
  bool isInsideOuterRing = IsPointInSingleRing(p, polygonRings[0]);
  if (!isInsideOuterRing)
    return false;

  // 第二步:判断是否在任何一个内环内,若在则排除
  for (int i = 1; i < polygonRings.Length; i++)
  {
    if (IsPointInSingleRing(p, polygonRings[i]))
    {
      return false;
    }
  }

  // 在外环内且不在任何内环内,返回true
  return true;
}

关键说明

  • 原方法重命名为IsPointInSingleRing,作为复用单环判断逻辑的辅助方法。
  • 多环方法IsPointInMultiRingPolygon接收二维数组Position[][],对应Polygon的多环坐标结构。
  • 先通过外环判断快速排除不在多边形范围内的点,再遍历所有内环,只要点落在任意内环中,就判定为不在目标区域内。
  • 保留了原有的边界盒预判断,减少不必要的射线法计算,提升整体性能。

内容的提问来源于stack exchange,提问作者dasisderblyme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:55:20