1. 定义
轨迹分段:对去噪后的轨迹,根据驻留点信息或者相邻GPS点之间的时间间隔,将其划分成多个连续的GPS子序列,这些子序列便是分段后的子轨迹。
图1 轨迹分段示意图
2. 算法概述
2.1 基于驻留点的轨迹分段
利用驻留点检测技术,检测出轨迹中的所有驻留点,然后从轨迹中剔除驻留点, 得到多个轨迹。
2.2 基于时间间隔的轨迹分段
如果轨迹中两个相邻GPS点的时间间隔大于指定的阈值t,则将轨迹从这两个点之间截断,得到两条子轨迹。
3. 代码实现
完整的Scala代码实现请参考我的GitHub
3.1 接口定义
trait AbstractTrajectorySegment {
/**
* Segment trajectory
*
* @param trajectory raw long trajectory
* @return segmented sub-trajectories
*/
def segment(trajectory: Trajectory): Array[Trajectory]
}
3.2 基于驻留点的轨迹分段
class StayPointBasedSegment(detector: AbstractStayPointDetector) extends AbstractTrajectorySegment {
/**
* Segment trajectory
*
* @param trajectory raw long trajectory
* @return segmented sub-trajectories
*/
override def segment(trajectory: Trajectory): Array[Trajectory] = {
val gpsCoordinates = trajectory.getCoordinatesGPS
val stayPointBounds = detector.calStayPointBounds(gpsCoordinates)
var trajStartIndex = 0
val subTrajectories = new ArrayBuffer[Trajectory]()
for ((stayPointStartIndex, stayPointEndIndex) <- stayPointBounds) yield {
if (trajStartIndex < stayPointStartIndex - 1) {
val subCoordinates = gpsCoordinates.slice(trajStartIndex, stayPointStartIndex)
subTrajectories += new Trajectory(trajectory.oid, subCoordinates)
} else {
//coordinate number is less than 2, can't build a trajectory
}
trajStartIndex = stayPointEndIndex + 1
}
if (trajStartIndex < gpsCoordinates.length - 1) {
//don't forget the last sub trajectory
subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(trajStartIndex, gpsCoordinates.length))
}
subTrajectories.toArray
}
}
3.3 基于时间间隔的轨迹分段
class TimeIntervalSegment(maxTimeIntervalInSec: Double) extends AbstractTrajectorySegment {
/**
* Segment trajectory
*
* @param trajectory raw long trajectory
* @return segmented sub-trajectories
*/
override def segment(trajectory: Trajectory): Array[Trajectory] = {
val gpsCoordinates = trajectory.getCoordinatesGPS
var trajStartIndex = 0
val subTrajectories = new ArrayBuffer[Trajectory]()
for (index <- gpsCoordinates.indices.dropRight(1)) {
val timeInterval = gpsCoordinates(index).time.toInstant.getEpochSecond -
gpsCoordinates(index + 1).time.toInstant.getEpochSecond
if (timeInterval > maxTimeIntervalInSec) {
if (trajStartIndex < index) {
subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(trajStartIndex, index + 1))
} else {
//coordinate number is less than 2, can't build a trajectory
}
trajStartIndex = index + 1
}
}
if (trajStartIndex < gpsCoordinates.length - 1) {
//don't forget the last sub trajectory
subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(trajStartIndex, gpsCoordinates.length))
}
subTrajectories.toArray
}
}
4. 总结
轨迹分段就是将整条轨迹在卡点的地方截断,形成多条子轨迹。卡点可以是轨迹的驻留点,也可以是两个时间间隔很大的GPS点对。