Back to all posts

Script tool: Check existence of duplicate entities

This script tool checks the existence of duplicate entities in a model layer or background layer. You can print, shift, or delete the duplicates.

This script requires the user interface template script, which should have been saved under the name ui_template in your PCSWMM scripts. Please check the revision date of the template (found in the comment lines at the top of the script) to ensure you are using the latest version.


# tags: Article,UI
# 2020-03-05
from ui_template import *
def get_key(entity):
  # create a key for each entity
  key = ''
  for vert in entity.Geometry.Vertices:
    key += '%.3f-%.3f' % (vert.X, vert.Y)    # create a key with three decimals of each vertex X and Y
  return key
def find_duplicates(entities):
  # --- create a dictionary of the entities
  dict_entity = {}
  for entity in entities:
    key = get_key(entity)
    if not key in dict_entity: dict_entity[key] = []
  return dict_entity
def shift_duplicates(dict_entity, shift_distance):
  # shift the duplicate entities so you can easily select and edit them
  for key, value in dict_entity.iteritems():
    if len(value) > 1:   # value is a list of PyEntity objects
      for i in range(1, len(value)):    # no need to shift the first PyEntity (index 0)
        distance = i * shift_distance   # actual distance if multiple duplicates exist
        # the first and last vertices are not shifted
        vertices = list(value[i].Geometry.Vertices)
        new_vertices = []
        if len(vertices) == 1:
          new_vertices.append(pcpy.Vertex(vertices[0].X+distance, vertices[0].Y+distance))
          new_vertices.append( vertices[0] )
          new_vertices.append(pcpy.Vertex(vertices[0].X+distance, vertices[0].Y+distance))
          for k in range(1, len(vertices)-1):
            new_vertices.append(pcpy.Vertex(vertices[k].X+distance, vertices[k].Y+distance))
          new_vertices.append(pcpy.Vertex(vertices[-1].X+distance, vertices[-1].Y+distance))
          new_vertices.append( vertices[-1] )
        value[i].Geometry.Vertices = new_vertices

def remove_duplicates(dict_entity, layer):
  # --- remove duplicates and only the first one will be left.
  for key, value in dict_entity.iteritems():
    if len(value) > 1:
      for i in range(1, len(value)):
def print_duplicates(dict_entity, attr_name):
  has_duplicate = False
  index = 1
  for key, value in dict_entity.iteritems():
    if len(value) > 1:
      has_duplicate = True
      value[0].Selected = True
      names = [ entity[attr_name] for entity in value ]
      print '[{0}] {1} duplicate entities in layer {2}: {3}'.format(index, 
        len(names), ui.get_text('Select layer to check'), names)
      index += 1
  if not has_duplicate:
    print 'There are no duplicate entities'
def run():
  layer = pcpy.Map.Layer[ ui.get_text('Select layer to check') ]
  attr_name = ui.get_text('Input attribute name for printing duplicates')
  to_print = ui.get_checked_state('To select and print the duplicates')
  to_shift = ui.get_checked_state('To shift the duplicates')
  to_remove = ui.get_checked_state('To remove the duplicates')
  entities = layer.get_entities()
  dict_entry = find_duplicates(entities)
  if to_print:  print_duplicates(dict_entry, attr_name)
  if to_shift:  shift_duplicates(dict_entry, 25)
  if to_remove: remove_duplicates(dict_entry, layer)
layer_names = [ layer.Name for layer in pcpy.Map.Layers ]
ui = UserForm('Identify duplicate entities', run)
ui.add_combobox('Select layer to check', layer_names)
ui.add_textbox('Input attribute name for printing duplicates', 'GIS_UID')
ui.add_radiobutton('To select and print the duplicates', True)
ui.add_radiobutton('To shift the duplicates', False)
ui.add_radiobutton('To remove the duplicates', False)