linq发现矩形位于彼此之上

时间:2011-04-30 15:41:03

标签: c# linq-to-xml

我使用linqtoxml来分析基本上是

形式的现有XML文件
<Projects>
  <Project ProjectName="name1">
    <ObjectType1List>
      <ObjectType1 ProjectName="name1" Idx="1">
        <Location Top="104" Left="32" Height="64" Wdth="128" />
        ...
      </ObjectType1>

      <ObjectType1 ProjectName="name1" Idx="2">
        ...
      </ObjectType1>
    </ObjectType1List>

    <ObjectType2List>
      ...
    </ObjectType2List>
  </Project>

  <Project Name ="name2">
  </Project>
  ...
</Project>

文件中有多个项目,项目中有大约10个cannonical对象类型 - 尽管每个项目可能有也可能没有所有不同的对象类型。但是在项目确实包含对象类型的情况下,将存在该对象类型的有限实例列表。

现在我要做的是找到彼此重叠的给定对象类型的所有对象(我知道我只对两种对象类型感兴趣,我假设只有相同类型的对象才会相互重叠)。但是这些物体是手工绘制和定位的,所以我不能假设这些物体具有完全相同的尺寸或位置 - 但我会假设它们会在一些非常大的尺寸差异中匹配,所以我有这种感觉我需要根据对象的中心位置,通过某种模糊要求扫描和分组对象。

“我可以养小马吗”的要求是我只想看到一个以上的对象。在给定对象类型的列表中,可能存在一组彼此重叠的对象,以及一堆不重叠的其他对象 - 我不想知道后面这些对象。

因此,对于由XDocument加载的文件,我正在考虑使用2遍方法(并且我不确定我是否具有Top et al的正确语法):

  var objects = from object in xdoc.Descendants()
    where object.Name = "ObjectType1" or object.Name = "ObjectType2" 
    select new
    {
      Project = object.Attribute("ProjectName").Value.ToString(),
      ObjectType = object.Name,
      Index = (int)object.Attribute("Idx").Value,
      Top = (int)object.Element("Location").Attribute("Top").Value,
      Left = (int)object.Element("Location").Attribute("Left").Value,
      Width = (int)object.Element("Location").Attribute("Width").Value,
      Height = (int)object.Element("Location").Attribute("Height").Value
    };


  var stacked = from object in objects
   group object by ???????

它的???????有点我不知道怎么写。我知道我想通过Project和ObjectType进行分组,然后通过Top,Left,Width和Height的一些数学函数进行分组。这是一个双重问题,因为我知道我不理解linq中的多个分组,然后对象的比较将是这样的:

abs(obj1.Left + obj1.Width/2 - obj2.Left - obj2.Width/2)<epsilon &&
abs(obj1.Top  + obj1.Height/2 - obj2.Top - obj2.Height/2)<epsilon

那么有什么建议吗?

请注意,虽然我当前的项目是.net 3.5但我没有任何限制会阻止我进入4.0

EDIT1

来自蒂姆维回答的问题。对于任何对象类型,我希望有一堆对象可以很好地位于彼此之上,但不会与不在同一堆中的其他对象重叠。因此,对于重叠的对象A,B,C,您将拥有A&amp; B重叠,B&amp; C重叠和A&amp; C不重叠。

因此A将始终与B和C重叠,B将始终与A和A重叠。 C和C总是重叠A&amp; B.然而,可能存在位于其他地方的物体D,E和F,它们不与A,B或C(或彼此)重叠,但可能存在第三(或更多)物体G,H和I组。重叠自己。

对于给定项目和给定对象类型,以及对象A,B,C(自身重叠),D,E和F(不与任何其他对象重叠)和G,H和I(它过于自我而且没有其他对象。我希望看到输出分组如下:

Project
  ObjectType1List
    Group1
      A, B, C
    Group2
      G, H, I

在实际数据中,给定的Object类型可能有许多这样的组。

2 个答案:

答案 0 :(得分:2)

如果您的输入完全由不相交的矩形组组成,并且在每个组中每个矩形与每隔一个相交,那么您需要将每个矩形与至多一个矩形进行比较来自每个小组。因此:

var groups = new Dictionary<Rectangle, List<Rectangle>>();
foreach (var rectangle in input)
{
    var key = groups.Keys.FirstOrDefault(k => k.IntersectsWith(rectangle));
    if (key.IsEmpty)
        groups[rectangle] = new List<Rectangle> { rectangle };
    else
        groups[key].Add(rectangle);
}

既然你提到你想省略只有单个矩形的组,你可以在最后过滤它们:

foreach (var pair in groups.Where(kvp => kvp.Value.Count == 1).ToList())
    groups.Remove(pair.Key);

答案 1 :(得分:0)

我无法帮助您进行分组,因为您的分组标准不够明确。如果你有三个矩形,其中A重叠B和B重叠C但A不重叠C,会发生什么?在开始为它设计算法之前,您需要弄清楚这些问题。

但是,您不需要编写数学来确定两个矩形是否相交。你可以使用System.Drawing.Rectangle

var objects = from object in xdoc.Descendants()
    where object.Name = "ObjectType1" or object.Name = "ObjectType2" 
    select new
    {
      Project = object.Attribute("ProjectName").Value.ToString(),
      ObjectType = object.Name,
      Index = (int)object.Attribute("Idx").Value,
      Rectangle = new Rectangle(
          (int)object.Element("Location").Attribute("Top").Value,
          (int)object.Element("Location").Attribute("Left").Value,
          (int)object.Element("Location").Attribute("Width").Value,
          (int)object.Element("Location").Attribute("Height").Value
      )
    };

然后你可以轻松找到重叠对:

var overlapping = from obj1 in objects
                  from obj2 in objects
                  where obj1 != obj2 && obj1.Rectangle.IntersectsWith(obj2.Rectangle)
                  select new { One = obj1, Two = obj2 };

当然这将使每个重叠对返回两次,其中一个和两个交换。