code: def _fine(contour, W):
      # area = cv2.contourArea(contour)
      # W = 6 if area < 200 else 8
      # TD = 0.5 if area < 200 else 0.9
      # D = TD + 0.3
      nW = W
      p_number = contour.shape[0]
      distance_list = []
      azimuth_list = []
      indexs_list = []
      for idx in range(p_number):
          current_point = contour[idx]
          next_idx = (idx + 1) % p_number
          next_point = contour[next_idx]
          distance_list.append(calc_distance(current_point, next_point))
          azimuth_list.append(_calc_azimuth(current_point, next_point))
          indexs_list.append((idx, next_idx))
      # add the direction of the longest edge to the list of main direction.
      longest_distance_idx = np.argmax(distance_list)
      main_direction_list = [azimuth_list[longest_distance_idx]]
      max_dis = distance_list[longest_distance_idx]
      if max_dis <= nW:
          nW = max_dis - 1e-6
      # Add other edges’ direction to the list of main directions
      # according to the angle threshold δ between their directions
      # and directions in the list.
      for distance, azimuth in zip(distance_list, azimuth_list):
          for mdir in main_direction_list:
              abs_dif_ang = abs(mdir - azimuth)
              if distance > nW and THETA <= abs_dif_ang <= (
                  180 - THETA
              ):
                  main_direction_list.append(azimuth)
      contour_by_lines = []
      md_used_list = [main_direction_list[0]]
      for distance, azimuth, (idx, next_idx) in zip(
          distance_list, azimuth_list, indexs_list
      ):
          p1 = contour[idx]
          p2 = contour[next_idx]
          pm = (p1 + p2) / 2
          # find long edges with threshold W that varies with building’s area.
          if distance > nW:
              rotate_ang = main_direction_list[0] - azimuth
              for main_direction in main_direction_list:
                  r_ang = main_direction - azimuth
                  if abs(r_ang) < abs(rotate_ang):
                      rotate_ang = r_ang
                      md_used_list.append(main_direction)
              abs_rotate_ang = abs(rotate_ang)
              # adjust long edges according to the list and angles.
              if abs_rotate_ang < DELTA or abs_rotate_ang > (
                  180 - DELTA
              ):
                  rp1 = _rotation(p1, pm, rotate_ang)
                  rp2 = _rotation(p2, pm, rotate_ang)
              elif (90 - DELTA) < abs_rotate_ang < (90 + DELTA):
                  rp1 = _rotation(p1, pm, rotate_ang - 90)
                  rp2 = _rotation(p2, pm, rotate_ang - 90)
              else:
                  rp1, rp2 = p1, p2
          # adjust short edges (judged by a threshold θ) according to the list and angles.
          else:
              rotate_ang = md_used_list[-1] - azimuth
              abs_rotate_ang = abs(rotate_ang)
              if abs_rotate_ang < THETA or abs_rotate_ang > (
                  180 - THETA
              ):
                  rp1 = _rotation(p1, pm, rotate_ang)
                  rp2 = _rotation(p2, pm, rotate_ang)
              else:
                  rp1 = _rotation(p1, pm, rotate_ang - 90)
                  rp2 = _rotation(p2, pm, rotate_ang - 90)
          # contour_by_lines.extend([rp1, rp2])
          contour_by_lines.append([rp1[0], rp2[0]])
      correct_points = np.array(contour_by_lines)
      # merge (or connect) parallel lines if the distance between
      # two lines is less than (or larger than) a threshold D.
      final_points = []
      final_points.append(correct_points[0][0].reshape([1, 2]))
      lp_number = correct_points.shape[0] - 1
      for idx in range(lp_number):
          next_idx = (idx + 1) if idx < lp_number else 0
          cur_edge_p1 = correct_points[idx][0]
          cur_edge_p2 = correct_points[idx][1]
          next_edge_p1 = correct_points[next_idx][0]
          next_edge_p2 = correct_points[next_idx][1]
          L1 = _line(cur_edge_p1, cur_edge_p2)
          L2 = _line(next_edge_p1, next_edge_p2)
          A1 = _calc_azimuth([cur_edge_p1], [cur_edge_p2])
          A2 = _calc_azimuth([next_edge_p1], [next_edge_p2])
          dif_azi = abs(A1 - A2)
          # find intersection point if not parallel
          if (90 - DELTA) < dif_azi < (90 + DELTA):
              point_intersection = _intersection(L1, L2)
              if point_intersection is not None:
                  final_points.append(point_intersection)
          # move or add lines when parallel
          elif dif_azi < 1e-6:
              marg = _calc_distance_between_lines(L1, L2)
              if marg < D:
                  # move
                  point_move = _calc_project_in_line(
                      next_edge_p1, cur_edge_p1, cur_edge_p2
                  )
                  final_points.append(point_move)
                  # update next
                  correct_points[next_idx][0] = point_move
                  correct_points[next_idx][1] = _calc_project_in_line(
                      next_edge_p2, cur_edge_p1, cur_edge_p2
                  )
              else:
                  # add line
                  add_mid_point = (cur_edge_p2 + next_edge_p1) / 2
                  rp1 = _calc_project_in_line(
                      add_mid_point, cur_edge_p1, cur_edge_p2
                  )
                  rp2 = _calc_project_in_line(
                      add_mid_point, next_edge_p1, next_edge_p2
                  )
                  final_points.extend([rp1, rp2])
          else:
              final_points.extend(
                  [
                      cur_edge_p1[np.newaxis, :],
                      cur_edge_p2[np.newaxis, :],
                  ]
              )
      final_points = np.array(final_points)
      return final_points
  
file_path: PaddleSeg/EISeg/eiseg/util/regularization/rs_regularization.py
imports: import math
  import cv2
  import numpy
  from .utils import calc_distance
label_desc: Use image node_id 3 for calling a global function with example usage: _fine(contour, W) and returns: final_points