Source code for tracktable.filter.trajectory

#
# Copyright (c) 2014-2021 National Technology and Engineering
# Solutions of Sandia, LLC. Under the terms of Contract DE-NA0003525
# with National Technology and Engineering Solutions of Sandia, LLC,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""tracktable.filter.trajectory - Filters that take trajectories as input
"""

import logging

from tracktable.core import geomath
from tracktable.core.geomath import subset_during_interval

[docs]class ClipToTimeWindow(object): """Truncate trajectories to fit within a time window Given an iterable of Trajectory objects, return those portions of each trajectory that fit within the specified time window. Interpolate endpoints as necessary. Attributes: input (iterable): Source of Trajectory objects start_time (datetime): Beginning time for window of interest end_time (datetime): End time for window of interest """ def __init__(self): """Initialize ClipToTimeWindow with no input and no begin/end time.""" self.input = None self.start_time = None self.end_time = None
[docs] def trajectories(self): """Return sub-trajectories within window. Note: Since this is a generator, you can only traverse the sequence once unless you collect it in a list yourself. Yields: Trajectories derived from input trajectories. Each trajectory is guaranteed to fall entirely within the window specified by self.start_time and self.end_time. If one of the input trajectories extends beyond that boundary, a new endpoint will be interpolated so that it begins or ends precisely at the boundary. Trajectories entirely outside the boundary will be returned as empty trajectories with 0 points. """ if (self.input is None): raise ValueError("ClipToTimeWindow: No input source! Set 'input' to a valid trajectory source.") if self.start_time is None or self.end_time is None: raise ValueError("ClipToTimeWindow: Incomplete time window! You must set both 'start_time' and 'end_time'. The current time window is ({}, {}).".format(self.start_time, self.end_time)) for trajectory in self.input: subset = geomath.subset_during_interval(trajectory, self.start_time, self.end_time) if len(subset) > 0: yield(subset)
# ----------------------------------------------------------------------
[docs]class FilterByBoundingBox(object): """FilterByBoundingBox: Eliminate trajectories that don't intersect a given box Given a source that produces Trajectories, return only those trajectories that intersect the specified bounding box. No clipping or subsetting is performed: if at least one point is within the desired region you will get the entire trajectory back. Attributes: input (iterable): Sequence of Trajectory objects box (tuple): Bounding box """ def __init__(self): """Initialize the filter with a bounding box that covers the whole world. """ self.input = None self.box = None
[docs] def trajectories(self): """Return just those trajectories that intersect the bounding box Yields: Trajectory objects with at least one point inside the bounding box """ if self.box is None: logging.getLogger(__name__).warning( "FilterByBoundingBox: Box is not set.") for trajectory in self.input: if self.box is None: yield(trajectory) elif geomath.intersects(self.box, trajectory): yield(trajectory)
# ----------------------------------------------------------------------
[docs]class FilterByAltitude(object): """Filter out trajectories that don't intersect an interval of altitude Given a source that produces Trajectories, return only those trajectories that have at least one point between min_altitude and max_altitude. Like FilterByBoundingBox, no clipping will take place. If a trajectory crosses the specified interval at all then you will get the whole thing back. Attributes: input (iterable): Iterable containing Trajectory objects min_altitude (float): Minimum altitude for acceptance max_altitude (float): Maximum altitude for acceptance """ def __init__(self): """Initialize the filter with a bounding box that covers the whole world. """ self.input = None self.min_altitude = None self.max_altitude = None
[docs] def trajectories(self): """Return just the trajectories that intersect the bounding box Yields: Trajectory objects that fall within the altitude region """ point_below = False point_above = False for trajectory in self.input: for point in trajectory: altitude = point.properties['altitude'] if altitude >= self.min_altitude and altitude <= self.max_altitude: yield(trajectory) else: # If the trajectory has points below and above the # interval then it must by definition intersect # the interval. if altitude < self.min_altitude: point_below = True if altitude > self.max_altitude: point_above = True if point_below and point_above: yield(trajectory)