mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 18:02:25 -05:00 
			
		
		
		
	* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
		
			
				
	
	
		
			117 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package exif
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/dsoprea/go-logging"
 | |
| 	"github.com/golang/geo/s2"
 | |
| 
 | |
| 	"github.com/dsoprea/go-exif/v2/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
 | |
| }
 |