# In a new file, e.g., arguslib/misc/interpolation.pyimportnumpyasnpfromtypingimportList,Dict,Anyimportdatetimeasdt
[docs]definterpolate_to_intersection(offsets:np.ndarray,coords_to_interpolate:Dict[str,np.ndarray],data_to_interpolate:Dict[str,np.ndarray],)->List[Dict[str,Any]]:""" Finds where a path crosses a plane (where offset is zero) and linearly interpolates associated coordinate and data values at that point. Args: offsets: An array of distances from the intersection plane. The function looks for sign changes in this array. coords_to_interpolate: A dictionary of coordinate arrays (e.g., {'x': xs, 'y': ys}) that define the path's position in some space. data_to_interpolate: A dictionary of other data arrays (e.g., {'time': times}) associated with the path. Returns: A list of dictionaries, where each dictionary represents one intersection and contains the interpolated values for all provided coordinates and data. """intersections=[]# Find indices *before* a sign change in the offsetshift_indices=np.where(np.diff(np.sign(offsets))!=0)[0]foridxinshift_indices:# The segment that crosses the plane is between idx and idx + 1offset1,offset2=offsets[idx],offsets[idx+1]# Skip if data is invalid (e.g., NaN)ifnp.isnan(offset1)ornp.isnan(offset2)oroffset1==offset2:continue# Calculate interpolation fraction 't' where the offset is 0# t = 0 corresponds to point1, t = 1 corresponds to point2t=offset1/(offset1-offset2)# We only want to interpolate if the crossing is within the segmentifnot(0<=t<=1):continueintersection_point={}# Interpolate coordinatesforkey,valuesincoords_to_interpolate.items():val1,val2=values[idx],values[idx+1]intersection_point[key]=val1+t*(val2-val1)# Interpolate other data (e.g., time)forkey,valuesindata_to_interpolate.items():val1,val2=values[idx],values[idx+1]# Check for invalid values first. np.isnan doesn't work on datetimes.is_val1_nan=isinstance(val1,float)andnp.isnan(val1)is_val2_nan=isinstance(val2,float)andnp.isnan(val2)ifis_val1_nanoris_val2_nan:intersection_point[key]=np.nancontinue# Handle datetimesifisinstance(val1,dt.datetime)andisinstance(val2,dt.datetime):val1_ts,val2_ts=val1.timestamp(),val2.timestamp()interpolated_ts=val1_ts+t*(val2_ts-val1_ts)tz=(getattr(val1,"tzinfo",None)orgetattr(val2,"tzinfo",None)ordt.timezone.utc)intersection_point[key]=dt.datetime.fromtimestamp(interpolated_ts,tz=tz)# Handle numeric typeselifisinstance(val1,(int,float))andisinstance(val2,(int,float)):intersection_point[key]=val1+t*(val2-val1)# Handle mixed or other unsupported types by assigning NaNelse:intersection_point[key]=np.nanintersections.append(intersection_point)returnintersections