Ejemplo n.º 1
0
def runTool(outLinesFC, SQLDbase, combine_corridors):
    try:

        BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2")

        ispy3 = sys.version_info >= (3, 0)

        # Derived inputs
        outGDB = os.path.dirname(
            outLinesFC)  # Must be in fgdb. Validated in tool validation.
        # Create a guid to make sure temporary outputs have unique names. They should be deleted
        # when the tool completes, but this ensures they don't conflict with any existing feature
        # classes in the gdb and makes it easier to know what they are and delete them if they
        # don't automatically get deleted.
        guid = uuid.uuid4().hex
        outStopPairsFCName = "StopPairs_" + guid
        outStopPairsFC = os.path.join(outGDB, outStopPairsFCName)

        # Get the original overwrite output setting so we can reset it at the end.
        OverwriteOutput = arcpy.env.overwriteOutput
        # It's okay to overwrite stuff in this tool
        arcpy.env.overwriteOutput = True

        conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase)

        triproute_dict = BBB_SharedFunctions.MakeTripRouteDict()

        # ----- Initialize a dictionary of stop geometry -----

        # Get the stops table (exclude parent stations and station entrances)
        c = conn.cursor()
        selectstoptablestmt = "SELECT stop_id, stop_lat, stop_lon, location_type FROM stops;"
        c.execute(selectstoptablestmt)

        # Initialize a dictionary of stop lat/lon
        # {stop_id: <stop geometry object>} in the output coordinate system
        stoplatlon_dict = {}
        for stop in c:
            stop_id = stop[0]
            stop_lat = stop[1]
            stop_lon = stop[2]
            location_type = stop[3]
            if location_type not in [0, '0', None, ""]:
                # Skip parent stations and station entrances
                continue
            pt = arcpy.Point()
            pt.X = float(stop_lon)
            pt.Y = float(stop_lat)
            # GTFS stop lat/lon is written in WGS1984
            ptGeometry = arcpy.PointGeometry(pt, BBB_SharedFunctions.WGSCoords)
            stoplatlon_dict[stop_id] = ptGeometry

    # ----- Obtain schedule info from the stop_times.txt file and convert it to a line-based model -----

        arcpy.AddMessage(
            "Obtaining and processing transit schedule and line information..."
        )
        arcpy.AddMessage("(This will take a few minutes for large datasets.)")

        # Create a line-based schedule table
        c2 = conn.cursor()
        c2.execute("DROP TABLE IF EXISTS schedules;")
        c2.execute(
            "CREATE TABLE schedules (key TEXT, start_time REAL, end_time REAL, trip_id TEXT);"
        )

        # Find pairs of directly-connected stops
        linefeature_dict = {}
        stoptimefetch = '''
        SELECT trip_id, stop_id, arrival_time, departure_time
        FROM stop_times
        ORDER BY trip_id, stop_sequence
        ;'''
        c.execute(stoptimefetch)
        current_trip = None
        previous_stop = None
        start_time = None
        end_time = None
        for st in c:
            trip_id = st[0]
            stop_id = st[1]
            arrival_time = st[2]
            departure_time = st[3]
            if trip_id != current_trip:
                current_trip = trip_id
                previous_stop = stop_id
                start_time = departure_time  # Start time of segment is the departure time from the stop
                continue
            start_stop = previous_stop
            end_stop = stop_id
            end_time = arrival_time
            SourceOIDkey = "%s , %s" % (start_stop, end_stop)
            if combine_corridors:
                # All trips between each pair of stops will be combined, regardless of route_id
                linefeature_dict[SourceOIDkey] = True
            else:
                # A separate line will be created for each separate route between the same two stops
                linefeature_dict[SourceOIDkey + " , " +
                                 triproute_dict[trip_id]] = True
            stmt = """INSERT INTO schedules (key, start_time, end_time, trip_id) VALUES ('%s', %s, %s, '%s');""" % (
                SourceOIDkey, start_time, end_time, trip_id)
            c2.execute(stmt)
            previous_stop = stop_id
            start_time = departure_time
        conn.commit()
        c2.execute(
            "CREATE INDEX schedules_index_tripsstend ON schedules (trip_id, start_time, end_time);"
        )
        conn.commit()

        # ----- Write pairs to a points feature class (this is intermediate and will NOT go into the final output) -----

        # Create a points feature class for the point pairs.
        arcpy.management.CreateFeatureclass(outGDB, outStopPairsFCName,
                                            "POINT", "", "", "",
                                            BBB_SharedFunctions.WGSCoords)
        arcpy.management.AddField(outStopPairsFC, "stop_id", "TEXT")
        arcpy.management.AddField(outStopPairsFC, "pair_id", "TEXT")
        arcpy.management.AddField(outStopPairsFC, "sequence", "SHORT")

        # Add pairs of stops to the feature class in preparation for generating line features
        badStops = []
        badkeys = []
        with arcpy.da.InsertCursor(
                outStopPairsFC,
            ["SHAPE@", "stop_id", "pair_id", "sequence"]) as cur:
            # linefeature_dict = {"start_stop , end_stop , route_type": True}
            for SourceOIDkey in linefeature_dict:
                stopPair = SourceOIDkey.split(" , ")
                # {stop_id: [stop_lat, stop_lon]}
                try:
                    stop1 = stopPair[0]
                    stop1_geom = stoplatlon_dict[stop1]
                except KeyError:
                    badStops.append(stop1)
                    badkeys.append(SourceOIDkey)
                    continue
                try:
                    stop2 = stopPair[1]
                    stop2_geom = stoplatlon_dict[stop2]
                except KeyError:
                    badStops.append(stop2)
                    badkeys.append(SourceOIDkey)
                    continue
                cur.insertRow((stop1_geom, stop1, SourceOIDkey, 1))
                cur.insertRow((stop2_geom, stop2, SourceOIDkey, 2))

        if badStops:
            badStops = list(set(badStops))
            if ispy3:
                badStops_str = str(badStops)
            else:
                badStops_str = unicode(badStops)
            arcpy.AddWarning(
                "Your stop_times.txt lists times for the following \
stops which are not included in your stops.txt file. Schedule information for \
these stops will be ignored. " + badStops_str)

        # Remove these entries from the linefeatures dictionary so it doesn't cause false records later
        if badkeys:
            badkeys = list(set(badkeys))
            for key in badkeys:
                del linefeature_dict[key]

    # ----- Generate lines between all stops (for the final output) -----

        arcpy.management.PointsToLine(outStopPairsFC, outLinesFC, "pair_id",
                                      "sequence")
        if not combine_corridors:
            arcpy.management.AddField(outLinesFC, "route_id", "TEXT")

        # We don't need the points for anything anymore, so delete them.
        arcpy.management.Delete(outStopPairsFC)

        # Clean up lines with 0 length.  They will just produce build errors and
        # are not valuable for visualization anyway.
        expression = """"Shape_Length" = 0"""
        with arcpy.da.UpdateCursor(outLinesFC, ["pair_id"],
                                   expression) as cur2:
            for row in cur2:
                del linefeature_dict[row[0]]
                cur2.deleteRow()

        if not combine_corridors:
            with arcpy.da.UpdateCursor(outLinesFC,
                                       ["pair_id", "route_id"]) as cur4:
                for row in cur4:
                    row[1] = row[0].split(" , ")[2]
                    cur4.updateRow(row)

    # ----- Finish up. -----

        conn.close()

        arcpy.AddMessage("Finished!")
        arcpy.AddMessage("Your transit lines template feature class is:")
        arcpy.AddMessage("- " + outLinesFC)

    except BBB_SharedFunctions.CustomError:
        arcpy.AddError("Failed to generate transit lines.")
        pass

    except:
        arcpy.AddError("Failed to generate transit lines.")
        raise

    finally:
        # Reset the overwrite output to the user's original setting
        arcpy.env.overwriteOutput = OverwriteOutput
def runTool(step1LinesFC, SQLDbase, linesFC, day, start_time, end_time):
    try:
        # ------ Get input parameters and set things up. -----

        BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2")

        try:
            # If it was a feature layer, it will have a data source property
            step1LinesFC = step1LinesFC.dataSource
        except:
            # Otherwise, assume it was a catalog path and use as is
            pass

        # GTFS SQL dbase - must be created ahead of time.
        BBB_SharedFunctions.ConnectToSQLDatabase(SQLDbase)

        Specific, day = BBB_SharedFunctions.CheckSpecificDate(day)
        start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds(
            start_time, end_time)

        # Does the user want to count arrivals or departures at the stops?
        DepOrArr = "departure_time"

        # ----- Prepare output file -----

        try:
            arcpy.management.Copy(step1LinesFC, linesFC)
        except:
            arcpy.AddError(
                "Error copying template lines feature class to output %s," %
                linesFC)
            raise

        # ----- Query the GTFS data to count the trips on each line segment -----
        try:
            arcpy.AddMessage(
                "Calculating the number of transit trips available during the time window..."
            )

            # Get a dictionary of {line_key: [[trip_id, start_time, end_time]]} for our time window
            linetimedict = BBB_SharedFunctions.CountTripsOnLines(
                day, start_sec, end_sec, DepOrArr, Specific)

        except:
            arcpy.AddError(
                "Error counting arrivals or departures at during time window.")
            raise

        # ----- Write to output -----
        try:
            arcpy.AddMessage("Writing output data...")

            combine_corridors = "route_id" not in [
                f.name for f in arcpy.ListFields(linesFC)
            ]

            triproute_dict = None
            if not combine_corridors:
                triproute_dict = BBB_SharedFunctions.MakeTripRouteDict()

            arcpy.management.AddField(linesFC, "NumTrips", "SHORT")
            arcpy.management.AddField(linesFC, "NumTripsPerHr", "DOUBLE")
            arcpy.management.AddField(linesFC, "MaxWaitTime", "SHORT")
            arcpy.management.AddField(linesFC, "AvgHeadway", "SHORT")

            with arcpy.da.UpdateCursor(linesFC, [
                    "pair_id", "NumTrips", "NumTripsPerHr", "MaxWaitTime",
                    "AvgHeadway"
            ]) as ucursor:
                for row in ucursor:
                    NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway = \
                                BBB_SharedFunctions.RetrieveStatsForLines(
                                    str(row[0]), linetimedict,
                                    start_sec, end_sec, combine_corridors, triproute_dict)
                    row[1] = NumTrips
                    row[2] = NumTripsPerHr
                    row[3] = MaxWaitTime
                    row[4] = AvgHeadway
                    ucursor.updateRow(row)

        except:
            arcpy.AddError("Error writing to output.")
            raise

        arcpy.AddMessage("Finished!")
        arcpy.AddMessage("Your output is located at " + linesFC)

    except BBB_SharedFunctions.CustomError:
        arcpy.AddError("Failed to count trips on lines.")
        pass

    except:
        arcpy.AddError("Failed to count trips on lines.")
        raise
Ejemplo n.º 3
0
You have ArcGIS Pro version %s." % BBB_SharedFunctions.ArcVersion)
        raise CustomError
    if BBB_SharedFunctions.ArcVersion == "10.0":
        arcpy.AddError(
            "You must have ArcGIS 10.1 or higher (or ArcGIS Pro) to run this \
tool. You have ArcGIS version %s." % BBB_SharedFunctions.ArcVersion)
        raise CustomError

# ----- Connect to SQL locally for further queries and entries -----

# Connect to the SQL database
    conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase)

    # ----- Make dictionary of {trip_id: route_id} -----

    BBB_SharedFunctions.MakeTripRouteDict()

    # ----- Initialize a dictionary of stop geometry -----

    # Get the stops table (exclude parent stations and station entrances)
    c = conn.cursor()
    selectstoptablestmt = "SELECT stop_id, stop_lat, stop_lon, location_type FROM stops;"
    c.execute(selectstoptablestmt)

    # Initialize a dictionary of stop lat/lon
    # {stop_id: <stop geometry object>} in the output coordinate system
    stoplatlon_dict = {}
    for stop in c:
        stop_id = stop[0]
        stop_lat = stop[1]
        stop_lon = stop[2]