Esempio n. 1
0
// Locate returns the point and uncertainty associated with a location as
// interpreted by the geolocation service. Uncertainty indicates the maximum
// uncertainty (in meters) accepted for the point (with 0 any uncertainty
// will be accepted).
func (s *service) Locate(l *geography.Location, locality string, uncertainty uint) (geography.Georeference, error) {
	ls, err := s.List(l, locality, uncertainty)
	if err != nil {
		return geography.Georeference{Point: geography.InvalidPoint()}, err
	}
	if len(ls) == 1 {
		return ls[0], nil
	}
	if len(ls) == 0 {
		return geography.Georeference{Point: geography.InvalidPoint()}, geography.ErrNotInDB
	}
	u := uncertainty
	if u == 0 {
		u = 200000
	}
	// set a mid point
	var sLon, sLat float64
	unc := uint(0)
	for _, p := range ls {
		sLon += p.Point.Lon
		sLat += p.Point.Lat
		if unc < p.Uncertainty {
			unc = p.Uncertainty
		}
	}
	den := float64(len(ls))
	lon, lat := sLon/den, sLat/den
	if !(geography.IsLon(lon) && geography.IsLat(lat)) {
		return geography.Georeference{Point: geography.InvalidPoint()}, geography.ErrAmbiguous
	}
	max := uint(0)
	for _, p := range ls {
		d := p.Point.Distance(lon, lat)
		if d > max {
			max = d
			if (d + unc) > u {
				break
			}
		}
	}
	p := ls[0]
	p.Uncertainty = max + unc
	if (p.Uncertainty > u) || (!p.IsValid()) {
		return geography.Georeference{Point: geography.InvalidPoint()}, geography.ErrAmbiguous
	}
	p.Point = geography.Point{lon, lat}
	return p, nil
}
Esempio n. 2
0
func spGrefProc(c *cmdapp.Command, tax *jdh.Taxon, gzt geography.Gazetter) {
	defer func() {
		l := getTaxDesc(c, localDB, tax.Id, true)
		spGrefNav(c, l, gzt)
		l = getTaxDesc(c, localDB, tax.Id, false)
		spGrefNav(c, l, gzt)
	}()
	if len(tax.Id) == 0 {
		return
	}
	vals := new(jdh.Values)
	vals.Add(jdh.SpeTaxon, tax.Id)
	if !addFlag {
		vals.Add(jdh.SpeGeoref, "true")
	}
	l := speList(c, localDB, vals)
	defer l.Close()
	for {
		spe := &jdh.Specimen{}
		if err := l.Scan(spe); err != nil {
			if err == io.EOF {
				break
			}
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err))
			os.Exit(1)
		}
		if len(spe.Georef.Validation) > 0 {
			continue
		}
		if !spe.Geography.IsValid() {
			fmt.Fprintf(os.Stdout, "%s: location without valid country\n", spe.Id)
			continue
		}
		u := uint(uncertFlag)
		if u == 0 {
			if u = spe.Georef.Uncertainty; u == 0 {
				// 200 km is the maximum validation
				u = 200000
			}
		}
		if !spe.Georef.IsValid() {
			if !addFlag {
				fmt.Fprintf(os.Stdout, "%s: invalid georeference\n", spe.Id)
				continue
			}
			p, err := gzt.Locate(&spe.Geography, spe.Locality, uint(uncertFlag))
			if err != nil {
				fmt.Fprintf(os.Stdout, "%s: unable to add: %v\n", spe.Id, err)
				if verboseFlag {
					if err == geography.ErrAmbiguous {
						pts, err := gzt.List(&spe.Geography, spe.Locality, uint(uncertFlag))
						if err != nil {
							fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err))
							continue
						}
						for _, p := range pts {
							fmt.Fprintf(os.Stderr, "\t%.5f %.5f\t%d\n", p.Point.Lon, p.Point.Lat, p.Uncertainty)
						}
					}
				}
				continue
			}
			vals := new(jdh.Values)
			vals.Add(jdh.KeyId, spe.Id)
			vals.Add(jdh.GeoLonLat, strconv.FormatFloat(p.Point.Lon, 'g', -1, 64)+","+strconv.FormatFloat(p.Point.Lat, 'g', -1, 64))
			vals.Add(jdh.GeoUncertainty, strconv.FormatInt(int64(p.Uncertainty), 10))
			vals.Add(jdh.GeoSource, p.Source)
			vals.Add(jdh.GeoValidation, p.Validation)
			localDB.Exec(jdh.Set, jdh.Specimens, vals)
			continue
		}
		pts, err := gzt.List(&spe.Geography, spe.Locality, u)
		if err != nil {
			fmt.Fprintf(os.Stdout, "%s: %v\n", spe.Id, err)
			continue
		}
		if len(pts) == 0 {
			fmt.Fprintf(os.Stdout, "%s: location not found\n", spe.Id)
			continue
		}
		lon, lat := spe.Georef.Point.Lon, spe.Georef.Point.Lat
		val := false
		gr := geography.Georeference{
			Point:       geography.InvalidPoint(),
			Uncertainty: geography.EarthRadius * 10, // a distance large enough
		}
		for _, p := range pts {
			d := p.Point.Distance(lon, lat)
			if d <= u {
				val = true
				if (d + p.Uncertainty) < gr.Uncertainty {
					gr = p
					gr.Uncertainty += d
				}
			}
		}
		if val {
			vals := new(jdh.Values)
			vals.Add(jdh.KeyId, spe.Id)
			if spe.Georef.Uncertainty == 0 {
				vals.Add(jdh.GeoUncertainty, strconv.FormatInt(int64(gr.Uncertainty), 10))
			}
			vals.Add(jdh.GeoValidation, gr.Validation)
			localDB.Exec(jdh.Set, jdh.Specimens, vals)
			continue
		}
		if !corrFlag {
			fmt.Fprintf(os.Stdout, "%s: location not found\n", spe.Id)
			if verboseFlag {
				fmt.Fprintf(os.Stderr, "\t%.5f %.5f\t\t[current georeference]\n", lon, lat)
				for _, p := range pts {
					fmt.Fprintf(os.Stderr, "\t%.5f %.5f\t%d\t%d\n", p.Point.Lon, p.Point.Lat, p.Uncertainty, p.Point.Distance(lon, lat))
				}
			}
			continue
		}
		gr = geography.Georeference{
			Point:       geography.InvalidPoint(),
			Uncertainty: geography.EarthRadius * 10, // a distance large enough
		}
		val = false
		for _, p := range pts {
			// invert lon-lat
			lt, ln := lon, lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}

			// lon with wrong sign
			ln, lt = -lon, lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}

			// lat with wrong sing
			ln, lt = lon, -lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}

			// invert lon-lat, wrong sings
			lt, ln = -lon, -lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}

			// invert lon-lat, lon with wrong sing
			lt, ln = lon, -lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}

			// invert lon-lat, lat with wrong sing
			lt, ln = -lon, lat
			if geography.IsLon(ln) && geography.IsLat(lt) {
				d := p.Point.Distance(lon, lat)
				if d <= u {
					val = true
					gr = p
					gr.Point = geography.Point{Lon: ln, Lat: lt}
					gr.Uncertainty += d
					break
				}
			}
		}
		if val {
			vals := new(jdh.Values)
			vals.Add(jdh.KeyId, spe.Id)
			vals.Add(jdh.GeoLonLat, strconv.FormatFloat(gr.Point.Lon, 'g', -1, 64)+","+strconv.FormatFloat(gr.Point.Lat, 'g', -1, 64))
			vals.Add(jdh.GeoUncertainty, strconv.FormatInt(int64(gr.Uncertainty), 10))
			vals.Add(jdh.GeoSource, gr.Source)
			vals.Add(jdh.GeoValidation, gr.Validation)
			localDB.Exec(jdh.Set, jdh.Specimens, vals)
			continue
		}
		fmt.Fprintf(os.Stdout, "%s: not corrected\n", spe.Id)
		if verboseFlag {
			fmt.Fprintf(os.Stderr, "\t%.5f %.5f\t\t[current georeference]\n", lon, lat)
			for _, p := range pts {
				fmt.Fprintf(os.Stderr, "\t%.5f %.5f\t%d\t%d\n", p.Point.Lon, p.Point.Lat, p.Uncertainty, p.Point.Distance(lon, lat))
			}
		}
	}
}