def find_nearby_entrance(self, ext, corr, **kwargs):
        """ Return entrance in the given corridor near by the given exit

        :type ext: pyticas.ttypes.RNodeObject
        :type corr: pyticas.ttypes.CorridorObject
        :rtype: pyticas.ttypes.RNodeObject
        """
        logger = getDefaultLogger(__name__)
        # logger.debug('find_nearby_entrance(): target_exit=%s, target_corridor=%s' %
        #              (str([ext.name, ext.label]), corr.name))

        if not ext.is_exit():
            raise ValueError('The first parameter must be exit')

        ents_info = self.ordered_by_distance(ext,
                                             [rn for rn in corr.entrances],
                                             d_limit=kwargs.get('d_limit', 1))
        if not ents_info:
            return None

        for (ent, dist) in ents_info:
            # logger.debug('find_nearby_entrance(): checking connected entrance : %s (ext corridor=%s, %s)' %
            #              (str([ent.name, ent.label]), ext.corridor.route, ext.corridor.dir))

            if ((ext.corridor.route in ent.label
                 and ext.corridor.dir in ent.label)
                    or ('CD' in ent.label and corr.route in ent.label
                        and corr.dir in ent.label)):
                # logger.debug('find_nearby_entrance():    : found')
                return ent

        return None
    def find_exit_to(self, rn, corr, **kwargs):
        """ Return tuple of exit and the connected entrance to the given corridor

        Note:
            iterate from the given `rn` to downstream only

        :type rn: pyticas.ttypes.RNodeObject
        :type corr: pyticas.ttypes.CorridorObject
        :rtype: (pyticas.ttypes.RNodeObject, pyticas.ttypes.RNodeObject)
        """
        logger = getDefaultLogger(__name__)
        # logger.debug('find_exit_to(): find exit to the corridor %s' % corr.name)
        d_limit = kwargs.get('d_limit', 2)
        cur_node = rn

        while cur_node.down_exit:
            cur_node = cur_node.down_exit
            connected_ent = self.is_connected_to(cur_node,
                                                 corr,
                                                 d_limit=d_limit)
            if connected_ent:
                return cur_node, connected_ent

        # logger.debug('find_exit_to(): Could not find by regular way....let\'s try something...')
        cur_node = rn
        while cur_node.down_exit:
            cur_node = cur_node.down_exit
            connected_ent = self.is_estimated_exit_connected_to(
                cur_node, corr, d_limit=d_limit)
            #logger.debug('-> find nearby entrance : target_exit=%s' % str([cur_node.name, cur_node.label]))
            if connected_ent:
                return (cur_node, connected_ent)
        return (None, None)
def ordered_by_distance(rnode, rnode_list, **kwargs):
    """ Return list of `RNodeObject` and distance to the given `rnode`

    :type rnode: pyticas.ttypes.RNodeObject
    :type rnode_list: list[pyticas.ttypes.RNodeObject]
    :return: list[(RNodeObject, DistanceInMile)]
    :rtype: list[(pyticas.ttypes.RNodeObject, float)]
    """
    logger = getDefaultLogger(__name__)
    d_limit = kwargs.get('d_limit', None)
    dists = {}
    # logger.debug('ordered_by_distance(): make rnode and distance list : target_rnode=%s, d_limit=%s' %
    #               (str([rnode.station_id, rnode.name, rnode.label, rnode.n_type]), str(d_limit)))

    for rn in rnode_list:
        if ((rn.is_station() and not rn.detectors)
                or (not rn.is_ramp() and not rn.station_id) or not rn.n_type):
            continue
        d = distutil.distance_in_mile(rnode, rn)
        # logger.debug('ordered_by_distance(): distance to %s = %f' % ( str([rn.station_id, rn.name, rn.label, rn.n_type]), d))
        if d_limit and d > d_limit:
            continue
        dists[d] = rn
    if dists:
        return [(dists[d], d) for d in sorted(dists)]
    else:
        return None
def print_rc(rc):
    """
    :type rc: RouteConfig
    :return:
    """
    logger = getDefaultLogger(__name__)
    logger.debug("*" * 10)
    logger.debug("RouteConfig")
    for idx, node_set in enumerate(rc.node_sets):
        logger.debug('%2d > %2.1f > %s' % (idx, node_set.mile_point, _node_to_str(node_set)))
    logger.debug("*" * 10)
    def is_connected_to(self, ext, corr, **kwargs):
        """ Return tuple of exit and the connected entrance to the given corridor
            if the given `ext` is connected to the corridor

        Note:
            iterate from the given `rn` to downstream only

        :type ext: pyticas.ttypes.RNodeObject
        :type corr: pyticas.ttypes.CorridorObject
        :rtype: pyticas.ttypes.RNodeObject
        """
        logger = getDefaultLogger(__name__)
        d_limit = kwargs.get('d_limit', 1)

        connected = self.infra.get_rnode(ext.forks[0]) if ext.forks else None

        # logger.debug('find_exit_to(): cur_exit=%s, connected=%s' % (str([ext.label, ext.name]),
        #                                               str([connected.label, connected.name]) if connected else ''))
        if connected and not connected.is_entrance():
            return None

        # case1 : connected to the target corridor
        if connected and connected.corridor.name == corr.name:
            # logger.debug('find_exit_to():     : found')
            return connected

        # case2 : connected to the CD
        if connected and connected.is_CD_entrance():
            # logger.debug('find_exit_to(): try to find exit from CD')
            (cd_exit, cd_ent) = self._exit_from_CD(connected,
                                                   corr,
                                                   d_limit=d_limit)
            if cd_ent: return cd_ent

        # some rnode is not CD type but connected to other corridor (e.g. I-35WN to I-494WB)
        if ' CD ' in ext.label or (connected and connected.is_CD_entrance()):
            # logger.debug('find_exit_to(): try to find nearby entrance (not connected by forks)')
            connected_ent = self.find_nearby_entrance(ext,
                                                      corr,
                                                      d_limit=d_limit)
            if connected_ent:
                return connected_ent

        return None
from xml.etree import ElementTree as et

from pyticas import cfg
from pyticas.logger import getDefaultLogger
from pyticas.rn.orgs import cam_org as camOrg
from pyticas.rn.orgs import corr_org as corrOrg
from pyticas.rn.orgs import det_org as detOrg
from pyticas.rn.orgs import dms_org as dmsOrg
from pyticas.rn.orgs import meter_org as metOrg
from pyticas.rn.orgs import rnode_org as rnodeOrg
from pyticas.ticas import get_path
from pyticas.tool import util

import inspect

logger = getDefaultLogger(__name__)


def load_metro(cfg_date='', **kwargs):
    """ load_data metro infrastructure

    :param cfg_date: configuration date of xml
    :return: True if succeed else False
    :rtype: (bool, Exception)
    """
    logger.debug("loading roadway network information...")
    # for caller in inspect.stack():
    #     print(caller.filename, caller.function, caller.lineno)
    if kwargs.get('download', False) and not cfg_date:
        metroFile = download_metro_file()
    elif not cfg_date:
__author__ = 'Chongmyung Park ([email protected])'

import datetime
import time
import os

from urllib import error as url_error
from pyticas import cfg, logger
from pyticas.ticas import get_path

MAX_TRY_NUM = 3
CACHE_TYPE_DET = 'det'
CACHE_TYPE_FAIL = 'fail'

logging = logger.getDefaultLogger(__name__)


def _load_testing(det_name,
                  year,
                  month,
                  day,
                  traffic_type,
                  only_download=False,
                  n_try=1):
    def _cached_data_local(detector_name, date_val, traffic_type_val):
        """
        :rtype: None or String
        """
        cache_path = _cache_path(CACHE_TYPE_DET, detector_name, date_val,
                                 traffic_type_val)
    def opposite_rnodes(self, rnodes, **kwargs):
        """ Return two list that one is rnode list and the other is opposite-direction rnode list

        Note:
            each rnode list can contain `None` if there is no opposite-direction rnode within `d_limit`

        :type rnodes: list[pyticas.ttypes.RNodeObject]
        :rtype: (list[pyticas.ttypes.RNodeObject], list[pyticas.ttypes.RNodeObject])
        """
        logger = getDefaultLogger(__name__)
        # logger.debug('opposite_rnodes(): make rnode list of the current corridor and the opposite direction')
        d_limit = kwargs.get('d_limit', 0.1)
        d_limit2 = kwargs.get('d_limit2', 0.05)
        n_type = kwargs.get('n_type', 'RNode')

        # find rnodes in the opposite direction within d_limit
        prev_corr = None
        segments = []
        sub_seg = None
        for ridx, rn in enumerate(rnodes):
            if rn.corridor != prev_corr:
                sub_seg = []
                segments.append(sub_seg)
            sub_seg.append(rn)
            prev_corr = rn.corridor

        orns = []
        for seg in segments:
            orn_s = orn_e = None
            for ridx, rn in enumerate(seg):
                nearbys = self.find_nearby_opposite_rnodes(rn,
                                                           n_type=n_type,
                                                           d_limit=d_limit)
                if not nearbys or not nearbys[0]:
                    continue
                if not orn_s:
                    orn_s = nearbys[0][0]

                if nearbys[0][1] < d_limit2:
                    orn_e = nearbys[0][0]

            # rnode list in the opposite direction
            seg_orns = ([orn_s] + [
                rn for rn in self.iter_to_upstream(
                    orn_s, lambda rn: rn.is_ramp() or
                    (rn.station_id and rn.detectors),
                    lambda rn: rn.name == orn_e.name)
            ] + [orn_e])

            orns.extend(seg_orns)

        # logger.debug('opposite_rnodes(): rnodes ---')
        # for rn in rnodes:
        #     logger.debug('opposite_rnodes():   ' + str([rn.n_type, rn.station_id, rn.name, rn.label]))
        #
        # logger.debug('opposite_rnodes(): opposite rnodes ---')
        # for rn in orns:
        #     logger.debug('opposite_rnodes():   ' + str([rn.n_type, rn.station_id, rn.name, rn.label]))

        def _nearby(trn, orns):
            """ Return rnode and distance with minimum distance to `trn`

            :type trn: pyticas.ttypes.RNodeObject
            :type orns: list[pyticas.ttypes.RNodeObject]
            :rtype: (RNodeObject, float)
            """
            min_dist = 9999
            min_rn = None
            for rn in orns:
                d = distutil.distance_in_mile(trn, rn)
                if d < min_dist:
                    min_dist = d
                    min_rn = rn
            if min_dist <= d_limit:
                return min_rn, min_dist
            else:
                return None, None

        n_rnodes = len(rnodes)
        n_orns = len(orns)

        # logger.debug('opposite_rnodes(): find synced points')
        synced = []
        for rn_idx, rn in enumerate(rnodes):
            orn, d_rn = _nearby(rn, orns) if rn else (None, None)
            if orn:
                nearby_orn, d_orn = _nearby(orn, rnodes) if rn else (None,
                                                                     None)
                if rn == nearby_orn:
                    # logger.debug('opposite_rnodes():  synced : %s -- %s' % (str([rn.n_type, rn.station_id, rn.name, rn.label]),
                    #                                      str([orn.n_type, orn.station_id, orn.name, orn.label])))
                    synced.append((rn, orn))

        res = []
        cur_rn_idx = 0
        cur_orn_idx = 0
        for sidx, (rn, orn) in enumerate(synced):
            rn_idx = rnodes.index(rn)
            orn_idx = orns.index(orn)

            # logger.debug(' cur_rn_idx=%d, rn_idx=%d, cur_orn_idx=%d, orn_idx=%d' % (cur_rn_idx, rn_idx, cur_orn_idx, orn_idx))

            should_add_rns = (cur_rn_idx < rn_idx)
            should_add_orns = (cur_orn_idx < orn_idx)

            if should_add_rns and should_add_orns:

                t_rn_idx = cur_rn_idx
                t_orn_idx = cur_orn_idx

                while t_rn_idx < rn_idx and t_orn_idx < orn_idx:
                    d_rn2rn_next = distutil.distance_in_mile(
                        rnodes[t_rn_idx],
                        rnodes[rn_idx]) if t_rn_idx > 0 else 0
                    d_orn2orn_next = distutil.distance_in_mile(
                        orns[t_orn_idx], orns[orn_idx]) if t_orn_idx > 0 else 0
                    if d_rn2rn_next < d_orn2orn_next:
                        res.append([None, orns[t_orn_idx]])
                        t_orn_idx += 1
                    else:
                        res.append([rnodes[t_rn_idx], None])
                        t_rn_idx += 1

                if t_rn_idx < rn_idx:
                    res.extend([[rnodes[idx], None]
                                for idx in range(t_rn_idx, rn_idx)])

                if t_orn_idx < orn_idx:
                    res.extend([[None, orns[idx]]
                                for idx in range(t_orn_idx, orn_idx)])

            elif should_add_rns:
                res.extend([[rnodes[idx], None]
                            for idx in range(cur_rn_idx, rn_idx)])
            elif should_add_orns:
                res.extend([[None, orns[idx]]
                            for idx in range(cur_orn_idx, orn_idx)])

            res.append([rn, orn])
            cur_rn_idx = rn_idx + 1
            cur_orn_idx = orn_idx + 1

        if cur_rn_idx < n_rnodes:
            res.extend([[rnodes[idx], None]
                        for idx in range(cur_rn_idx, n_rnodes)])
        elif cur_orn_idx < n_orns:
            res.extend([[None, orns[idx]]
                        for idx in range(cur_orn_idx, n_orns)])

        fixed = []
        n_res = len(res)
        if n_res > 3:
            sidx = 0
            while sidx < n_res - 2:
                rn1, orn1 = res[sidx]
                rn2, orn2 = res[sidx + 1]
                rn3, orn3 = res[sidx + 2]

                if rn1 == None and orn3 == None:
                    """
                  <---orn1---orn2----x----
                  ----x----rn2-----rn3------>
                  """
                    d = distutil.distance_in_mile(orn1, rn3)
                    if d < 0.15:
                        fixed.append([rn2, orn1])
                        fixed.append([rn3, orn2])
                        sidx += 3
                        continue

                elif orn1 == None and rn3 == None:
                    """
                  <----x----orn2----orn3----
                  ----rn1--rn2------x------>
                  """
                    d = distutil.distance_in_mile(rn1, orn3)
                    if d < 0.15:
                        fixed.append([rn1, orn2])
                        fixed.append([rn2, orn3])
                        sidx += 3
                        continue

                # elif ((rn1 != None and rn1.is_station())
                #       and (not rn2 or not rn2.is_station())
                #       and (not orn1 or not orn1.is_station())
                #       and (orn2 != None and orn2.is_station())):
                #
                #     d = distutil.distance_in_mile(rn2 or rn1, orn1 or orn2)
                #     if d < 0.15:
                #         fixed.append([None, orn1])
                #         fixed.append([rn1, orn2])
                #         fixed.append([rn2, None])
                #         sidx += 3
                #         continue
                #
                # elif ((rn2 != None and rn2.is_station())
                #       and (not rn1 or not rn1.is_station())
                #       and (not orn2 or not orn2.is_station())
                #       and (orn1 != None and orn1.is_station())):
                #
                #     d = distutil.distance_in_mile(rn1 or rn2, orn2 or orn1)
                #     if d < 0.15:
                #         fixed.append([rn1, None])
                #         fixed.append([rn2, orn1])
                #         fixed.append([None, orn2])
                #         sidx += 3
                #         continue

                fixed.append([rn1, orn1])
                sidx += 1

            for tidx in range(sidx, n_res):
                fixed.append(res[tidx])
        else:
            fixed = res

        # fixed = [ (v[0], v[1]) for v in fixed if v[0] and v[1] ]

        return ([r[0] for r in fixed], [r[1] for r in fixed])