Skip to content

Commit

Permalink
Use absolute value of decimal degrees and validate range of decimal d…
Browse files Browse the repository at this point in the history
…egrees
  • Loading branch information
KingAkeem committed Sep 24, 2023
1 parent 2873de0 commit 9c7d298
Showing 1 changed file with 27 additions and 32 deletions.
59 changes: 27 additions & 32 deletions dms/dms.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,44 @@ package dms

import (
"fmt"
"math"
)

type LatLon struct {
// DecimalDegrees represent latitude/longitude of geographic coordinates as decimal frations of a degree.
type DecimalDegrees struct {
Latitude float64
Longitude float64
}

// LatLonError is used for errors with lat/lon values
type LatLonError struct {
err string
}

func (e *LatLonError) Error() string {
return e.err
}

// Position is a single coordinate within a DMS location
type Position struct {
// DMSAngle represents a single angle for degrees, miutes, seconds measurements
type DMSAngle struct {
degrees int
minutes int
seconds float64
direction string
}

func (p Position) String() string {
return fmt.Sprintf(`%d°%d'%v" %s`, p.degrees, p.minutes, p.seconds, p.direction)
func (d DMSAngle) String() string {
return fmt.Sprintf(`%d°%d'%v" %s`, d.degrees, d.minutes, d.seconds, d.direction)
}

// DMS coordinate
type DMS struct {
Latitude Position
Longitude Position
Latitude DMSAngle
Longitude DMSAngle
}

func (d DMS) String() string {
return fmt.Sprintf(`%s %s`, d.Latitude, d.Longitude)
}

func newPosition(decimalDegrees float64, direction string) Position {
degrees := uint8(decimalDegrees)
minutes := uint8((decimalDegrees - float64(degrees)) * 60)
seconds := (decimalDegrees - float64(degrees) - float64(minutes)/60) * 3600
func newDMSAngle(decimalDegreeAngle float64, direction string) DMSAngle {
decimalDegreeAngle = math.Abs(decimalDegreeAngle)
degrees := uint8(decimalDegreeAngle)
minutes := uint8((decimalDegreeAngle - float64(degrees)) * 60)
seconds := (decimalDegreeAngle - float64(degrees) - float64(minutes)/60) * 3600

return Position{
return DMSAngle{
degrees: int(degrees),
minutes: int(minutes),
seconds: seconds,
Expand All @@ -54,16 +48,9 @@ func newPosition(decimalDegrees float64, direction string) Position {
}

// New generates a DMS position from a set of decimal degree coordinates (latitude/longitude)
func New(latlon LatLon) (*DMS, error) {
func NewDMS(latlon DecimalDegrees) (*DMS, error) {
lat, lon := latlon.Latitude, latlon.Longitude

if lat < 0 || lon < 0 {
return nil, &LatLonError{"latitude or longitude must be positive"}
}
if lat > 90 || lon > 180 {
return nil, &LatLonError{"latitude must be less than 90 and longitude must be less than 180"}
}

var latDirection, lonDirection string
if lat > 0 {
latDirection = "N"
Expand All @@ -77,8 +64,16 @@ func New(latlon LatLon) (*DMS, error) {
lonDirection = "W"
}

dmsLat := newPosition(lat, latDirection)
dmsLon := newPosition(lon, lonDirection)
if lat < -90 || lat > 90 {
return nil, fmt.Errorf("latitude must be in range of -90 and 90, found %f", lat)
}

if lon < -180 || lon > 180 {
return nil, fmt.Errorf("longitude must be in range of -180 and 180, foujnd %f", lon)
}

latitude := newDMSAngle(lat, latDirection)
longitude := newDMSAngle(lon, lonDirection)

return &DMS{Latitude: dmsLat, Longitude: dmsLon}, nil
return &DMS{Latitude: latitude, Longitude: longitude}, nil
}

0 comments on commit 9c7d298

Please sign in to comment.