diff options
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/v3/gps.go')
-rw-r--r-- | vendor/github.com/dsoprea/go-exif/v3/gps.go | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/v3/gps.go b/vendor/github.com/dsoprea/go-exif/v3/gps.go new file mode 100644 index 000000000..7a61cd94d --- /dev/null +++ b/vendor/github.com/dsoprea/go-exif/v3/gps.go @@ -0,0 +1,117 @@ +package exif + +import ( + "errors" + "fmt" + "time" + + "github.com/dsoprea/go-logging" + "github.com/golang/geo/s2" + + "github.com/dsoprea/go-exif/v3/common" +) + +var ( + // ErrGpsCoordinatesNotValid means that some part of the geographic data was + // unparseable. + ErrGpsCoordinatesNotValid = errors.New("GPS coordinates not valid") +) + +// GpsDegrees is a high-level struct representing geographic data. +type GpsDegrees struct { + // Orientation describes the N/E/S/W direction that this position is + // relative to. + Orientation byte + + // Degrees is a simple float representing the underlying rational degrees + // amount. + Degrees float64 + + // Minutes is a simple float representing the underlying rational minutes + // amount. + Minutes float64 + + // Seconds is a simple float representing the underlying ration seconds + // amount. + Seconds float64 +} + +// NewGpsDegreesFromRationals returns a GpsDegrees struct given the EXIF-encoded +// information. The refValue is the N/E/S/W direction that this position is +// relative to. +func NewGpsDegreesFromRationals(refValue string, rawCoordinate []exifcommon.Rational) (gd GpsDegrees, err error) { + defer func() { + if state := recover(); state != nil { + err = log.Wrap(state.(error)) + } + }() + + if len(rawCoordinate) != 3 { + log.Panicf("new GpsDegrees struct requires a raw-coordinate with exactly three rationals") + } + + gd = GpsDegrees{ + Orientation: refValue[0], + Degrees: float64(rawCoordinate[0].Numerator) / float64(rawCoordinate[0].Denominator), + Minutes: float64(rawCoordinate[1].Numerator) / float64(rawCoordinate[1].Denominator), + Seconds: float64(rawCoordinate[2].Numerator) / float64(rawCoordinate[2].Denominator), + } + + return gd, nil +} + +// String provides returns a descriptive string. +func (d GpsDegrees) String() string { + return fmt.Sprintf("Degrees<O=[%s] D=(%g) M=(%g) S=(%g)>", string([]byte{d.Orientation}), d.Degrees, d.Minutes, d.Seconds) +} + +// Decimal calculates and returns the simplified float representation of the +// component degrees. +func (d GpsDegrees) Decimal() float64 { + decimal := float64(d.Degrees) + float64(d.Minutes)/60.0 + float64(d.Seconds)/3600.0 + + if d.Orientation == 'S' || d.Orientation == 'W' { + return -decimal + } + + return decimal +} + +// Raw returns a Rational struct that can be used to *write* coordinates. In +// practice, the denominator are typically (1) in the original EXIF data, and, +// that being the case, this will best preserve precision. +func (d GpsDegrees) Raw() []exifcommon.Rational { + return []exifcommon.Rational{ + {Numerator: uint32(d.Degrees), Denominator: 1}, + {Numerator: uint32(d.Minutes), Denominator: 1}, + {Numerator: uint32(d.Seconds), Denominator: 1}, + } +} + +// GpsInfo encapsulates all of the geographic information in one place. +type GpsInfo struct { + Latitude, Longitude GpsDegrees + Altitude int + Timestamp time.Time +} + +// String returns a descriptive string. +func (gi *GpsInfo) String() string { + return fmt.Sprintf("GpsInfo<LAT=(%.05f) LON=(%.05f) ALT=(%d) TIME=[%s]>", + gi.Latitude.Decimal(), gi.Longitude.Decimal(), gi.Altitude, gi.Timestamp) +} + +// S2CellId returns the cell-ID of the geographic location on the earth. +func (gi *GpsInfo) S2CellId() s2.CellID { + latitude := gi.Latitude.Decimal() + longitude := gi.Longitude.Decimal() + + ll := s2.LatLngFromDegrees(latitude, longitude) + cellId := s2.CellIDFromLatLng(ll) + + if cellId.IsValid() == false { + panic(ErrGpsCoordinatesNotValid) + } + + return cellId +} |