我使用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类型可能有许多这样的组。
答案 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 };
当然这将使每个重叠对返回两次,其中一个和两个交换。