Is it possible to calculate the timestamp, when a moving point (car) intersects a line based on just timestamps? (see picture in post)

1503
8
09-27-2022 09:25 AM
Labels (1)
Adam1
by
New Contributor II

Hello. I think the example in the following picture clarifies my confusing question. The two points represent a car that happened to be at the shown points at the shown time with the shown speed (orange number; just to know I don't need to calculate the speed, already have it).

It would be great if there is a tool or if you know a(n easy) way to calculate/estimate the (date and) timestamp when the car crossed the yellow'ish line. Of course it is possible "by hand" with just measuring the distance and calculating the mean speed, but I have around 39,000 unique trips with around 3,700,000 points travelling a distance up to around 25km and around 30 cross sections over a span of 2 weeks.

exampleexample

I am on Windows 10 and I use ArcGIS Pro 3.0.1.

Thank you in advance for taking your time to read and in the best case answer my question.

0 Kudos
8 Replies
AyanPalit
Esri Regular Contributor

@Adam1 Interesting problem - the picture helps. You can try using the Generate Near Table geoprocessing tool to get the distance of the points from the line. Looks like you have the speed and time stamp values available to incorporate some calculations using the Near Table generated. The table can be exported as Excel using  Table To Excel for ease of using formulas if you prefer spreadsheets as output. 

Ayan Palit | Principal Consultant Esri
0 Kudos
Adam1
by
New Contributor II

Hello, thank you for your suggestion. I had a look at it and tried it, but I am not really sure how to go on after using that tool. I will try the other idea first, but I will keep this one in mind! Thanks!

0 Kudos
JohannesLindner
MVP Frequent Contributor

This seems like a good job for Python.

This script assumes velocity in m/s and constant acceleration between the points. It outputs a table that lists each trip with all crossed lines with crossing time and velocity.

To run it:

  • open the Python window
    JohannesLindner_0-1664385057022.png
  • copy and paste the script below
  • edit the input and output variables (you don't need to change anything below line 16)
  • hit enter

 

import arcpy, datetime

# define inputs
in_points = "Path/to/points"
trip_field = "TripID"
time_field = "Time"
velocity_field = "Velocity"

in_cross_sections = "Path/to/cross_sections"
cross_section_field = "CrossSectionID"

# define outputs
# for your huge amount of data, I recommend saving into RAM, so it runs faster
# don't forget to export the table afterwards!
out_folder = "memory"
out_name = "result"



# function for calculating the time and velocity at which the vehicle hits the point of interest
# this assumes constant acceleration!
# v0: start velocity in [m/s]
# a: acceleration in [m/s/s]
# s: distance from start to point of interest in [m]
# returns a tuple of (seconds, velocity)
def calc_time_and_velocity(v0, a, s):
    # for constant acceleration:
    # v(t) = a * t  +  v0
    # s(t) = 0.5 * a * t^2  +  v0 * t
    # ==>  t(s) = -v0/a +- sqrt( (v0 / a)^2  +  2 * s / a )
    t = -v0 / a - math.sqrt( math.pow(v0 / a, 2) + 2 * s / a)
    if t <= 0:
        t = -v0 / a + math.sqrt( math.pow(v0 / a, 2) + 2 * s / a)
    v = a * t + v0
    return (t, v)




# create output table
out_table = arcpy.management.CreateTable(out_folder, out_name)
arcpy.management.AddField(out_table, "Trip", "LONG")
arcpy.management.AddField(out_table, "CrossSection", "LONG")
arcpy.management.AddField(out_table, "Time", "DATE")
arcpy.management.AddField(out_table, "Velocity", "FLOAT")

# read input data
points = [row for row in arcpy.da.SearchCursor(in_points, ["SHAPE@", trip_field, time_field, velocity_field])]
cross_sections = [row for row in arcpy.da.SearchCursor(in_cross_sections, ["SHAPE@", cross_section_field])]
sr = points[0][0].spatialReference

# get all trips
trips = list({p[1] for p in points})

# start writing into the output table
with arcpy.da.InsertCursor(out_table, ["Trip", "CrossSection", "Time", "Velocity"]) as cursor:
    # loop through the trips
    for trip in trips:
        # extract the points of that trip
        trip_points = [p for p in points if p[1] == trip]
        # sort by time
        trip_points.sort(key=lambda p: p[2])
        # loop through point pairs
        for i in range(1, len(trip_points)):
            p1 = trip_points[i-1]
            p2 = trip_points[i]
            line = arcpy.Polyline(arcpy.Array([p1[0].firstPoint, p2[0].firstPoint]), sr)            
            # find intersecting cross sections
            intersecting_cs = [cs for cs in cross_sections if not line.disjoint(cs[0])]
            # loop through those cross_sections
            for cs in intersecting_cs:
                # get the intersection point
                p = line.intersect(cs[0], 1)
                # calculate time and velocity
                dv = p2[3] - p1[3]
                dt = (p2[2] - p1[2]).seconds
                a = dv / dt
                s = p1[0].distanceTo(p)
                t, v = calc_time_and_velocity(p1[3], a, s)
                time = p1[2] + datetime.timedelta(seconds=t)
                # write into the output table
                cursor.insertRow([trip, cs[1], time, v])

 

 

Results for some made-up test data:

JohannesLindner_2-1664385285282.png

 

JohannesLindner_1-1664385244927.png

 

 

Again, this script assumes velocity values given in meters per second, so you have to calculate that from your values (I'm assuming these are km/h).


Have a great day!
Johannes
Adam1
by
New Contributor II

Hello, thank you so much for your huge effort!

I tried it with two different datasets but unfortunately I got some errors. 
With the first dataset I got this error:

Traceback (most recent call last):
File "<string>", line 48, in <module>
File "<string>", line 48, in <listcomp>
RuntimeError: A column was specified that does not exist.

This probably has to do something with how I altered my data and somehow did something wrong/weird to the "SHAPE"/geometry attributes of it?

Then I tried it with a "clean" dataset which I have not worked with before and got this error:

Traceback (most recent call last):
File "<string>", line 62, in <module>
TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'

Do you have an idea why this is?

Thank you.

0 Kudos
JohannesLindner
MVP Frequent Contributor

First one is wrong column names. Second one tries to sort empty date values.

Can you send me a small subset of your points, either here or in a private message? In most cases, it's easier to troubleshoot that way.


Have a great day!
Johannes
Adam1
by
New Contributor II

So I don't really know why, but I don't get those errors anymore, I just tried another different dataset (Initial data was in 650 files, which I first merged together into 5 files and then those 5 again into one file).

Instead I first had a division by zero error when "a" was zero when both velocities were the same. I fixed that by including this to your code:

 

# for constant acceleration:
    # v(t) = a * t  +  v0
    # s(t) = 0.5 * a * t^2  +  v0 * t
    # ==>  t(s) = -v0/a +- sqrt( (v0 / a)^2  +  2 * s / a )
if a != 0:
        t = -v0 / a - math.sqrt(math.pow(v0 / a, 2) + 2 * s / a)
        if t <= 0:
            t = -v0 / a + math.sqrt(math.pow(v0 / a, 2) + 2 * s / a)
        v = a * t + v0
    else:
        t = s / v0
        v = v0
    return (t, v)

 

 

Now I get a ValueError: math domain error. I included some prints in your code to see what values cause that error:

 

Trip: 1292665561
p2[2] - p1[2]
2019-09-19 08:12:59 - 2019-09-19 08:12:44.000001
dt: 14
-

p2[3] - p1[3]
0.2777777777777778 - 5.277777777777778
dv: -5.0
-

a: -0.35714285714285715
-

distToCross: 56.91868192594062

v0: 5.277777777777778
a: -0.35714285714285715
s: 56.91868192594062
Traceback (most recent call last):
  File "<string>", line 121, in <module>
  File "<string>", line 38, in calc_time_and_velocity
ValueError: math domain error

 

 (and don't ask me why this one datetime has an added .000001)

The situation looks like in the following picture, if it helps. The actual point is just right at the tip of the arrow, so it is just a tad behind the cross-section.

Adam1_0-1664413461812.png

 

0 Kudos
Adam1
by
New Contributor II

So I changed the code a bit and it worked on this one dataset without errors now. I tink the data sometimes is just a bit odd. I added that if the ValueError occurs, instead of using the given speed values, the calculation should use speed and acceleration values that are calculated from the distance and time between the two individual tracks. I'll see if it will work on all the data.

Edit: Oh and sorry about not getting back to you about sending you a small sample of my data, but I think sadly I am not allowed to, even just a small snippet, sorry!

0 Kudos
Adam1
by
New Contributor II

So now it worked how it should. Thank you so much for your help! I will post the final code that worked for me here soon.

0 Kudos