用于检测一维线段交叉的Python程序

时间:2015-08-26 01:29:15

标签: python algorithm graph

我有四种颜色的线段 - 粉红色,绿色,橙色,红色 - 如下图所示。

enter image description here

例如,第一个粉红色细分具有开始和结束位置(5258,5422)

坐标存储在这个元组字典中:

mycoord = { 'pink'  :[(5258,5422), (5479,5864)],
            'green' :[(5425,5450)],
            'orange':[(5266,5770)],
            'red'   :[(5258,5864)] }

我想要做的是获取所有可能的交叉点的开始值和结束值,如下图所示:

enter image description here

因此,期望的答案是:

sect1/pink-red        : 5258,5266
sect2/pink-orange-red : 5266,5422
sect3/orange-red      : 5422,5425
sect4/green-orange-red: 5425,5450
sect5/orange-red      : 5450,5479
sect6/pink-orange-red : 5479,5770
sect7/pink-red        : 5770,5864

请注意,我想保留每个交叉点的颜色指示符(例如 pink-red)。我怎样才能用Python实现这个目标?

2 个答案:

答案 0 :(得分:1)

使用Michael Laszlo的支撑开/关概念:

>>> mycoord = { 'pink'  :[(5258,5422), (5479,5864)],
            'green' :[(5425,5450)],
            'orange':[(5266,5770)],
            'red'   :[(5258,5864)] }
>>> labeled_values=[]
# make tuples of (value, brace status (open/close), color)
>>> for color,color_ranges in mycoord.items():
        for color_range in color_ranges:
            labeled_values.append((color_range[0],True,color))
            labeled_values.append((color_range[1],False,color))

    # labeled_values are now like (5258, True, 'pink'), (5422, False, 'pink') ...
>>> sects = []
# traverse the sorted values and maintain a color-set
>>> color_set_so_far=set()
>>> range_start = -1
>>> for value,range_open,color in sorted(labeled_values):   
        if not range_open or range_start != value:
            sects.append(("-".join(color_set_so_far), range_start, value))

        if range_open:          
            color_set_so_far.add(color)
        else:       
            color_set_so_far.remove(color)      

        range_start = value

>>> sects = [s for s in sects if s[0] and s[1]!=s[2]] # filter out empty ranges
>>> sects
# [('pink-red', 5258, 5266), ('pink-orange-red', 5266, 5422), ('orange-red', 5422, 5425), ('orange-green-red', 5425, 5450), ('orange-red', 5450, 5479), ('pink-orange-red', 5479, 5770), ('pink-red', 5770, 5864)]

答案 1 :(得分:1)

我建议你按照以下步骤进行操作。

  • 对端点进行排序,记住每个端点的颜色以及它是左(开始)还是右(关闭)端点。

  • 迭代端点,使用哈希跟踪开放跨度,该哈希将每种颜色映射到该颜色的开放跨度数。打开给定颜色的跨度时递增,当关闭跨度时递减。当计数达到零时删除颜色。对于每个不同的端点,将该点上所有打开的跨度的颜色放入一个集合中。

  • 迭代连续的不同端点对。这些形成了您感兴趣的跨度的左右端点。对于每个端点,您都知道该点处的活动颜色。在跨度期间处于活动状态的颜色集是左端活动颜色的set intersection和右端活动的颜色。

注意:如果两个端点之间的颜色为空,则表示您在跨距之间找到了间隙,因此您知道应该跳过它。您可能还想跳过只有一种颜色的跨度。下面的实现没有。您可以通过修改此行轻松更改它以跳过单色跨度:

  if len(colors) > 0:

所以它写着:

  if len(colors) > 1:

如果您对查看跨距之间的差距感兴趣,可以将阈值更改为-1或完全删除条件。

实现:

mycoord = { 'pink'  :[(5258,5422), (5479,5864)],
            'green' :[(5425,5450)],
            'orange':[(5266,5770)],
            'red'   :[(5258,5864)] }

# Sort the endpoints. Remember their color and whether they open or close.
points = []
for color, spans in mycoord.items():
  for open, close in spans:
    points.append((open, 'open', color))
    points.append((close, 'close', color))
points.sort()

# Iterate over the endpoints. Keep track of open spans. Mark intersections.
active_spans = {}
intersections = []
for point, kind, color in points:
  if len(intersections) != 0 and intersections[-1][0] == point:
    intersections[-1][1].add(color)
  else:
    color_set = set([color] + list(active_spans.keys()))
    intersections.append((point, color_set))
  if kind == 'close':
    active_spans[color] -= 1
    if active_spans[color] == 0:
      del active_spans[color]
  else:
    active_spans[color] = active_spans.setdefault(color, 0) + 1

# Iterate over consecutive pairs of unique intersections. Intersect the color sets.
tab_width = sum(map(len, mycoord)) + len(mycoord) 
count = 0
for i in range(1, len(intersections)):
  a, b = intersections[i - 1], intersections[i]
  colors = sorted(a[1] & b[1])
  if len(colors) > 0:
    count += 1
    print('sect{0}/{1:<{2}}: {3},{4}'.format(count, '-'.join(colors), tab_width,
        a[0], b[0]))

结果:

sect1/pink-red              : 5258,5266
sect2/orange-pink-red       : 5266,5422
sect3/orange-red            : 5422,5425
sect4/green-orange-red      : 5425,5450
sect5/orange-red            : 5450,5479
sect6/orange-pink-red       : 5479,5770
sect7/pink-red              : 5770,5864