Example #1
0
func (from TrackPoint) LatlongTimeBoxTo(to TrackPoint) geo.LatlongTimeBox {
	return geo.LatlongTimeBox{
		LatlongBox:   from.Latlong.BoxTo(to.Latlong),
		Start:        from.TimestampUTC,
		End:          to.TimestampUTC,
		HeadingDelta: geo.HeadingDelta(from.Heading, to.Heading),
		Source:       from.Source,
	}
}
Example #2
0
// If there are gaps in the track, this will interpolate between them.
// Will also fatten up the boxes, if they're too flat or too tall
func (t Track) AsContiguousBoxes() []geo.LatlongTimeBox {
	minSize := 0.05  // In 'latlong' units; comes out something like ~3NM (~5 vertical)
	maxSize := 0.10  // Boxes bigger than this get chopped into smaller bits
	minWidth := 0.01 // Boxes are stretched until at least this wide/tall

	boxes := []geo.LatlongTimeBox{}
	iLast := 0
	for i := 1; i < len(t); i++ {
		// i is the point we're looking at; iLast is the point at the end of the previous box.
		// should we create a box from i back to iLast ? multiple boxes ? Or skip to i+1 ?
		dist := t[iLast].Latlong.LatlongDist(t[i].Latlong)
		if dist > maxSize {
			// Need to interpolate some boxes into this gap
			nNeeded := int(dist/maxSize) + 1 // num boxes to create. int() rounds down
			len := 1.0 / float64(nNeeded)    // fraction of dist - size of each box
			sTP, eTP := t[iLast], t[i]
			for j := 0; j < nNeeded; j++ {
				startFrac := len * float64(j)
				endFrac := startFrac + len
				sITP := sTP.InterpolateTo(eTP, startFrac)
				eITP := sTP.InterpolateTo(eTP, endFrac)
				box := sITP.TrackPoint.LatlongTimeBoxTo(eITP.TrackPoint)
				box.I, box.J = iLast, i
				box.Interpolated = true
				box.RunLength = nNeeded
				centroidHeading := sITP.Latlong.BearingTowards(box.Center())
				box.CentroidHeadingDelta = geo.HeadingDelta(sITP.Heading, centroidHeading)

				box.Debug = fmt.Sprintf(
					" - src: %s\n"+
						" - sTP: %s\n - eTP: %s\n - span: %.2f-%.2f\n"+
						" - centroid: %.2f; sITP: %.2f; delta: %.2f\n"+
						" - interp: %d points\n"+
						" - sITP: %s\n - eITP: %s\n", t[0].Source, sTP, eTP, startFrac, endFrac,
					centroidHeading, sITP.Heading, box.CentroidHeadingDelta,
					nNeeded,
					sITP, eITP)
				boxes = append(boxes, box)
			}
			iLast = i

		} else if dist > minSize {
			// Grow an initial box with all the succeeding trackpoints
			box := t[iLast].LatlongTimeBoxTo(t[iLast+1])
			for j := iLast + 2; j <= i; j++ {
				box.Enclose(t[j].Latlong, t[j].TimestampUTC)
			}
			box.I, box.J = iLast, i

			centroidHeading := t[iLast].Latlong.BearingTowards(box.Center())
			box.CentroidHeadingDelta = geo.HeadingDelta(t[iLast].Heading, centroidHeading)

			boxes = append(boxes, box)
			iLast = i

		} else {
			// This point is too close to the prev; let the loop iterate to the next one
		}
	}

	// We don't want boxes that are too skinny, so we pad them out here.
	for i, _ := range boxes {
		boxes[i].EnsureMinSide(minWidth)
	}

	return boxes
}