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, } }
// 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 }