docs: def connect_node(node, node_shp, mv_grid, target_obj, proj, graph, conn_dist_ring_mod, debug):
      """ Connects `node` to `target_obj`.
  
      Args
      ----
      node: LVLoadAreaCentreDing0, i.e.
          Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0)
      node_shp: :shapely:`Shapely Point object<points>`
          Shapely Point object of origin node
      target_obj: type
          object that node shall be connected to
      proj: :pyproj:`pyproj Proj object< >`
          equidistant CRS to conformal CRS (e.g. ETRS -> WGS84)
      graph: :networkx:`NetworkX Graph Obj< >`
          NetworkX graph object with nodes and newly created branches
      conn_dist_ring_mod: float
          Max. distance when nodes are included into route instead of creating a 
          new line.
      debug: bool
          If True, information is printed during process.
  
      Returns
      -------
      :obj:`LVLoadAreaCentreDing0`
          object that node was connected to.
          
          (instance of :obj:`LVLoadAreaCentreDing0` or :obj:`MVCableDistributorDing0`.
          
          If node is included into line instead of creating a new line (see arg
          `conn_dist_ring_mod`), `target_obj_result` is None.
                             
      See Also
      --------
      ding0.grid.mv_grid.mv_connect : for details on the `conn_dist_ring_mod` parameter.
      """
  
      target_obj_result = None
  
      # MV line is nearest connection point
      if isinstance(target_obj['shp'], LineString):
  
          adj_node1 = target_obj['obj']['adj_nodes'][0]
          adj_node2 = target_obj['obj']['adj_nodes'][1]
  
          # find nearest point on MV line
          conn_point_shp = target_obj['shp'].interpolate(target_obj['shp'].project(node_shp))
          conn_point_shp = transform(proj, conn_point_shp)
  
          # target MV line does currently not connect a load area of type aggregated
          if not target_obj['obj']['branch'].connects_aggregated:
  
              # Node is close to line
              # -> insert node into route (change existing route)
              if (target_obj['dist'] < conn_dist_ring_mod):
                  # backup kind and type of branch
                  branch_type = graph.adj[adj_node1][adj_node2]['branch'].type
                  branch_kind = graph.adj[adj_node1][adj_node2]['branch'].kind
                  branch_ring = graph.adj[adj_node1][adj_node2]['branch'].ring
  
                  # check if there's a circuit breaker on current branch,
                  # if yes set new position between first node (adj_node1) and newly inserted node
                  circ_breaker = graph.adj[adj_node1][adj_node2]['branch'].circuit_breaker
                  if circ_breaker is not None:
                      circ_breaker.geo_data = calc_geo_centre_point(adj_node1, node)
  
                  # split old ring main route into 2 segments (delete old branch and create 2 new ones
                  # along node)
                  graph.remove_edge(adj_node1, adj_node2)
  
                  branch_length = calc_geo_dist_vincenty(adj_node1, node)
                  branch = BranchDing0(length=branch_length,
                                       circuit_breaker=circ_breaker,
                                       kind=branch_kind,
                                       type=branch_type,
                                       ring=branch_ring)
                  if circ_breaker is not None:
                      circ_breaker.branch = branch
                  graph.add_edge(adj_node1, node, branch=branch)
  
                  branch_length = calc_geo_dist_vincenty(adj_node2, node)
                  graph.add_edge(adj_node2, node, branch=BranchDing0(length=branch_length,
                                                                     kind=branch_kind,
                                                                     type=branch_type,
                                                                     ring=branch_ring))
  
                  target_obj_result = 're-routed'
  
                  if debug:
                      logger.debug('Ring main route modified to include '
                                   'node {}'.format(node))
  
              # Node is too far away from route
              # => keep main route and create new line from node to (cable distributor on) route.
              else:
  
                  # create cable distributor and add it to grid
                  cable_dist = MVCableDistributorDing0(geo_data=conn_point_shp,
                                                       grid=mv_grid)
                  mv_grid.add_cable_distributor(cable_dist)
  
                  # check if there's a circuit breaker on current branch,
                  # if yes set new position between first node (adj_node1) and newly created cable distributor
                  circ_breaker = graph.adj[adj_node1][adj_node2]['branch'].circuit_breaker
                  if circ_breaker is not None:
                      circ_breaker.geo_data = calc_geo_centre_point(adj_node1, cable_dist)
  
                  # split old branch into 2 segments (delete old branch and create 2 new ones along cable_dist)
                  # ===========================================================================================
  
                  # backup kind and type of branch
                  branch_kind = graph.adj[adj_node1][adj_node2]['branch'].kind
                  branch_type = graph.adj[adj_node1][adj_node2]['branch'].type
                  branch_ring = graph.adj[adj_node1][adj_node2]['branch'].ring
  
                  graph.remove_edge(adj_node1, adj_node2)
  
                  branch_length = calc_geo_dist_vincenty(adj_node1, cable_dist)
                  branch = BranchDing0(length=branch_length,
                                       circuit_breaker=circ_breaker,
                                       kind=branch_kind,
                                       type=branch_type,
                                       ring=branch_ring)
                  if circ_breaker is not None:
                      circ_breaker.branch = branch
                  graph.add_edge(adj_node1, cable_dist, branch=branch)
  
                  branch_length = calc_geo_dist_vincenty(adj_node2, cable_dist)
                  graph.add_edge(adj_node2, cable_dist, branch=BranchDing0(length=branch_length,
                                                                           kind=branch_kind,
                                                                           type=branch_type,
                                                                           ring=branch_ring))
  
                  # add new branch for satellite (station to cable distributor)
                  # ===========================================================
  
                  # get default branch kind and type from grid to use it for new branch
                  branch_kind = mv_grid.default_branch_kind
                  branch_type = mv_grid.default_branch_type
  
                  branch_length = calc_geo_dist_vincenty(node, cable_dist)
                  graph.add_edge(node, cable_dist, branch=BranchDing0(length=branch_length,
                                                                      kind=branch_kind,
                                                                      type=branch_type,
                                                                      ring=branch_ring))
                  target_obj_result = cable_dist
  
                  # debug info
                  if debug:
                      logger.debug('Nearest connection point for object {0} '
                                   'is branch {1} (distance={2} m)'.format(
                          node, target_obj['obj']['adj_nodes'], target_obj['dist']))
  
      # node ist nearest connection point
      else:
  
          # what kind of node is to be connected? (which type is node of?)
          #   LVLoadAreaCentreDing0: Connect to LVLoadAreaCentreDing0 only
          #   LVStationDing0: Connect to LVLoadAreaCentreDing0, LVStationDing0 or MVCableDistributorDing0
          #   GeneratorDing0: Connect to LVLoadAreaCentreDing0, LVStationDing0, MVCableDistributorDing0 or GeneratorDing0
          if isinstance(node, LVLoadAreaCentreDing0):
              valid_conn_objects = LVLoadAreaCentreDing0
          elif isinstance(node, LVStationDing0):
              valid_conn_objects = (LVLoadAreaCentreDing0, LVStationDing0, MVCableDistributorDing0)
          elif isinstance(node, GeneratorDing0):
              valid_conn_objects = (LVLoadAreaCentreDing0, LVStationDing0, MVCableDistributorDing0, GeneratorDing0)
          else:
              raise ValueError('Oops, the node you are trying to connect is not a valid connection object')
  
          # if target is Load Area centre or LV station, check if it belongs to a load area of type aggregated
          # (=> connection not allowed)
          if isinstance(target_obj['obj'], (LVLoadAreaCentreDing0, LVStationDing0)):
              target_is_aggregated = target_obj['obj'].lv_load_area.is_aggregated
          else:
              target_is_aggregated = False
  
          # target node is not a load area of type aggregated
          if isinstance(target_obj['obj'], valid_conn_objects) and not target_is_aggregated:
  
              # get default branch kind and type from grid to use it for new branch
              branch_kind = mv_grid.default_branch_kind
              branch_type = mv_grid.default_branch_type
  
              # get branch ring obj
              branch_ring = mv_grid.get_ring_from_node(target_obj['obj'])
  
              # add new branch for satellite (station to station)
              branch_length = calc_geo_dist_vincenty(node, target_obj['obj'])
              graph.add_edge(node, target_obj['obj'], branch=BranchDing0(length=branch_length,
                                                                         kind=branch_kind,
                                                                         type=branch_type,
                                                                         ring=branch_ring))
              target_obj_result = target_obj['obj']
  
              # debug info
              if debug:
                  logger.debug('Nearest connection point for object {0} is station {1} '
                        '(distance={2} m)'.format(
                      node, target_obj['obj'], target_obj['dist']))
  
      return target_obj_result