// IsInParentList search an id in the list of parents of the taxon. func isInParentList(c *cmdapp.Command, db jdh.DB, id string, pIds []string) bool { args := new(jdh.Values) args.Add(jdh.TaxParents, id) pl, err := db.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } defer pl.Close() for { p := &jdh.Taxon{} if err := pl.Scan(p); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } for _, pid := range pIds { if p.Id == pid { return true } } } return false }
func getValidParent(c *cmdapp.Command, extId string) string { args := new(jdh.Values) args.Add(jdh.TaxParents, extId) l, err := extDB.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } defer l.Close() for { et := &jdh.Taxon{} if err := l.Scan(et); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } p := taxon(c, localDB, extDBFlag+":"+et.Id) if len(p.Id) > 0 { if p.IsValid { return p.Id } else { return p.Parent } } } return "" }
func trForceProc(c *cmdapp.Command, phy *jdh.Phylogeny) { txLs := list.New() vals := new(jdh.Values) vals.Add(jdh.TreTaxon, phy.Id) l, err := localDB.List(jdh.Trees, vals) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } for { var tId jdh.IdElement if err := l.Scan(&tId); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if len(tId.Id) == 0 { continue } txLs.PushBack(tId.Id) } if txLs.Len() == 0 { return } root := phyloNode(c, localDB, phy.Root) trForceNode(c, root, txLs) }
func txEdVal(from *jdh.Taxon) { if from.IsValid { return } vals := new(jdh.Values) vals.Add(jdh.KeyId, from.Id) vals.Add(jdh.TaxValid, "true") localDB.Exec(jdh.Set, jdh.Taxonomy, vals) }
func raLsRun(c *cmdapp.Command, args []string) { openLocal(c) var tax *jdh.Taxon if len(taxonFlag) > 0 { tax = taxon(c, localDB, taxonFlag) if len(tax.Id) == 0 { return } } else if len(args) > 0 { if len(args) > 2 { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments")) os.Exit(1) } pName := "" if len(args) > 1 { pName = args[1] } tax = pickTaxName(c, localDB, args[0], pName) if len(tax.Id) == 0 { return } } else { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong taxon name or id")) c.Usage() } vals := new(jdh.Values) if childFlag { vals.Add(jdh.RDisTaxonParent, tax.Id) } else { vals.Add(jdh.RDisTaxon, tax.Id) } l := rasList(c, localDB, vals) defer l.Close() ct := tax for { ras := &jdh.Raster{} if err := l.Scan(ras); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if machineFlag { fmt.Fprintf(os.Stdout, "%s\n", ras.Id) continue } if ras.Taxon != ct.Id { ct = taxon(c, localDB, ras.Taxon) } if verboseFlag { fmt.Fprintf(os.Stdout, "%s %s %s\t%s\t%dx%d\n", ct.Id, ct.Name, ct.Authority, ras.Id, ras.Cols, ras.Cols/2) continue } fmt.Fprintf(os.Stdout, "%s\t%s\t%dx%d\n", ct.Name, ras.Id, ras.Cols, ras.Cols/2) } }
func spPopFetch(c *cmdapp.Command, tax *jdh.Taxon, prevRank, rank jdh.Rank) { r := tax.Rank if r == jdh.Unranked { r = prevRank } defer func() { l := getTaxDesc(c, localDB, tax.Id, true) spPopNav(c, l, r, rank) l = getTaxDesc(c, localDB, tax.Id, false) spPopNav(c, l, r, rank) }() if len(tax.Id) == 0 { return } if r < rank { return } eid := searchExtern(extDBFlag, tax.Extern) if len(eid) == 0 { return } vals := new(jdh.Values) vals.Add(jdh.SpeTaxon, eid) if geoRefFlag { vals.Add(jdh.SpeGeoref, "true") } l := speList(c, extDB, vals) 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 osp := specimen(c, localDB, extDBFlag+":"+spe.Id); len(osp.Id) > 0 { continue } if len(spe.Catalog) > 0 { if osp := specimen(c, localDB, spe.Catalog); len(osp.Id) > 0 { exsp := searchExtern(extDBFlag, osp.Extern) if exsp == spe.Id { continue } fmt.Fprintf(os.Stderr, "specimen %s already in database as %s [duplicated in %s]\n", spe.Catalog, osp.Id, extDBFlag) continue } } addToSpecimens(c, spe, tax.Id) } }
func trDelNode(c *cmdapp.Command) { vals := new(jdh.Values) if colpFlag { vals.Add(jdh.NodCollapse, nodeFlag) } else { vals.Add(jdh.KeyId, nodeFlag) } if _, err := localDB.Exec(jdh.Delete, jdh.Nodes, vals); err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } localDB.Exec(jdh.Commit, "", nil) }
func setNode(nod *jdh.Node, anc *trNode, data *trData) *trNode { trn := &trNode{ id: nod.Id, taxon: nod.Taxon, parent: anc, } data.node = append(data.node, trn) if anc != nil { trn.nest = anc.nest + 1 trn.minX = float32(trn.nest) } if len(nod.Taxon) > 0 { tax := taxon(cmd, localDB, nod.Taxon) trn.name.Text = tax.Name if !tax.IsValid { val := taxon(cmd, localDB, tax.Parent) nm := fmt.Sprintf("[%s syn. of %s]", tax.Name, val.Name) trn.name.Text = nm } } vals := new(jdh.Values) vals.Add(jdh.NodChildren, nod.Id) l, err := localDB.List(jdh.Nodes, vals) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", cmd.ErrStr(err)) os.Exit(1) } for { desc := &jdh.Node{} if err := l.Scan(desc); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", cmd.ErrStr(err)) os.Exit(1) } d := setNode(desc, trn, data) trn.terms += d.terms if trn.level <= d.level { trn.level = d.level + 1 } trn.children = append(trn.children, d) } if len(trn.children) == 0 { data.terms++ trn.terms = 1 } else { sort.Sort(bySize(trn.children)) } return trn }
// GetTaxDesc return the list of descendants of a taxon. func getTaxDesc(c *cmdapp.Command, db jdh.DB, id string, valid bool) jdh.ListScanner { args := new(jdh.Values) if valid { args.Add(jdh.TaxChildren, id) } else { args.Add(jdh.TaxSynonyms, id) } l, err := db.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } return l }
func dsDelRun(c *cmdapp.Command, args []string) { if len(idFlag) == 0 { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong dataset id")) c.Usage() } openLocal(c) vals := new(jdh.Values) vals.Add(jdh.KeyId, idFlag) if _, err := localDB.Exec(jdh.Delete, jdh.Datasets, vals); err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } localDB.Exec(jdh.Commit, "", nil) }
func txEdSyn(from, to *jdh.Taxon) { if from.Id == "0" { return } if from.Id == to.Id { return } if (from.Parent == to.Id) && (!from.IsValid) { return } vals := new(jdh.Values) vals.Add(jdh.KeyId, from.Id) vals.Add(jdh.TaxSynonym, to.Id) localDB.Exec(jdh.Set, jdh.Taxonomy, vals) }
func trViewMouse(tv sparta.Widget, e interface{}) bool { dt := tv.Property(sparta.Data) if dt == nil { return true } data := dt.(*trData) ev := e.(sparta.MouseEvent) switch ev.Button { case sparta.MouseRight: if !setFlag { return true } if data.sel == nil { return true } sel := trViewNearestNode(ev.Loc, data.node) if sel == nil { return true } x, y, pos := data.x, data.y, data.pos p := tv.Property(sparta.Parent).(sparta.Widget) d := p.Property(sparta.Data).(*trList) if sel == data.sel { vals := new(jdh.Values) vals.Add(jdh.NodCollapse, sel.id) localDB.Exec(jdh.Delete, jdh.Nodes, vals) localDB.Exec(jdh.Commit, "", nil) } else if !sel.isValidSis(data.sel) { return true } else { vals := new(jdh.Values) vals.Add(jdh.KeyId, data.sel.id) vals.Add(jdh.NodSister, sel.id) localDB.Exec(jdh.Set, jdh.Nodes, vals) localDB.Exec(jdh.Commit, "", nil) } rect := tv.Property(sparta.Geometry).(image.Rectangle) data = setTree(d.phyLs[d.pos], rect) data.x, data.y, data.pos = x, y, pos tv.SetProperty(sparta.Data, data) data.putOnScreen() tv.Update() case sparta.MouseLeft: data.sel = trViewNearestNode(ev.Loc, data.node) tv.Update() case -sparta.MouseWheel: data.pos.Y -= 5 data.putOnScreen() tv.Update() case sparta.MouseWheel: data.pos.Y += 5 data.putOnScreen() tv.Update() } return true }
// TaxInDB returns true if a taxon is in the database. func taxInDB(c *cmdapp.Command, db jdh.DB, name, parent string, rank jdh.Rank, valid bool) *jdh.Taxon { args := new(jdh.Values) args.Add(jdh.TaxName, name) if len(parent) != 0 { args.Add(jdh.TaxParent, parent) } if rank != jdh.Unranked { args.Add(jdh.TaxRank, rank.String()) } l, err := db.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } defer l.Close() for { tax := &jdh.Taxon{} if err := l.Scan(tax); err != nil { if err == io.EOF { return nil } } if len(tax.Id) > 0 { if tax.IsValid == valid { return tax } } } }
// ValsFromArgs adds values from an argument list or the stdin. func valsFromArgs(id string, args []string) *jdh.Values { vals := new(jdh.Values) vals.Add(jdh.KeyId, id) if len(args) == 0 { in := bufio.NewReader(os.Stdin) for { tn, err := readLine(in) if err != nil { break } ln := strings.Join(tn, " ") if strings.Index(ln, "=") < 1 { continue } vals.Add(parseKeyValArg(ln)) } } else { for _, a := range args { if strings.Index(a, "=") < 1 { continue } vals.Add(parseKeyValArg(a)) } } return vals }
func trDelRun(c *cmdapp.Command, args []string) { openLocal(c) if len(nodeFlag) > 0 { trDelNode(c) return } if len(idFlag) == 0 { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong tree or node id")) c.Usage() } vals := new(jdh.Values) vals.Add(jdh.KeyId, idFlag) if _, err := localDB.Exec(jdh.Delete, jdh.Trees, vals); err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } localDB.Exec(jdh.Commit, "", nil) }
func trLsNodes(c *cmdapp.Command) { vals := new(jdh.Values) if ancsFlag { vals.Add(jdh.NodParent, nodeFlag) } else { vals.Add(jdh.NodChildren, nodeFlag) } l, err := localDB.List(jdh.Nodes, vals) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } for { nod := &jdh.Node{} if err := l.Scan(nod); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if machineFlag { fmt.Fprintf(os.Stdout, "%s\n", nod.Id) continue } var tax *jdh.Taxon if len(nod.Taxon) > 0 { tax = taxon(c, localDB, nod.Taxon) } if verboseFlag { fmt.Fprintf(os.Stdout, "%s\t", nod.Id) if tax != nil { fmt.Fprintf(os.Stdout, "%s [id:%s]", tax.Name, tax.Id) } fmt.Fprintf(os.Stdout, "\tlen: %d\tage: %d\n", nod.Len, nod.Age) continue } fmt.Fprintf(os.Stdout, "%s\t", nod.Id) if tax != nil { fmt.Fprintf(os.Stdout, "%s", tax.Name) } fmt.Fprintf(os.Stdout, "\n") } }
func txSyncRankSet(c *cmdapp.Command, tax *jdh.Taxon, rank jdh.Rank) { if len(tax.Id) == 0 { l := getTaxDesc(c, localDB, tax.Id, true) txSyncRankNav(c, l, rank) l = getTaxDesc(c, localDB, tax.Id, false) txSyncRankNav(c, l, rank) return } if (tax.Rank < rank) && (tax.Rank != jdh.Unranked) { l := getTaxDesc(c, localDB, tax.Id, true) txSyncRankNav(c, l, rank) l = getTaxDesc(c, localDB, tax.Id, false) txSyncRankNav(c, l, rank) return } else if tax.Rank == rank { return } eid := searchExtern(extDBFlag, tax.Extern) if len(eid) == 0 { l := getTaxDesc(c, localDB, tax.Id, true) txSyncRankNav(c, l, rank) l = getTaxDesc(c, localDB, tax.Id, false) txSyncRankNav(c, l, rank) return } pExt := txSyncRankedParent(c, eid, rank) if pExt == nil { l := getTaxDesc(c, localDB, tax.Id, true) txSyncRankNav(c, l, rank) l = getTaxDesc(c, localDB, tax.Id, false) txSyncRankNav(c, l, rank) return } // check if the potential parent is already in the database. p := taxon(c, localDB, extDBFlag+":"+pExt.Id) if len(p.Id) == 0 { p = txSyncAddToTaxonomy(c, pExt) } args := new(jdh.Values) args.Add(jdh.KeyId, tax.Id) args.Add(jdh.TaxParent, p.Id) localDB.Exec(jdh.Set, jdh.Taxonomy, args) }
func spDelRun(c *cmdapp.Command, args []string) { openLocal(c) vals := new(jdh.Values) if len(idFlag) > 0 { vals.Add(jdh.KeyId, idFlag) if _, err := localDB.Exec(jdh.Delete, jdh.Specimens, vals); err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } localDB.Exec(jdh.Commit, "", nil) return } var tax *jdh.Taxon if len(taxonFlag) > 0 { tax = taxon(c, localDB, taxonFlag) if len(tax.Id) == 0 { return } } else if len(args) > 0 { if len(args) > 2 { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments")) os.Exit(1) } pName := "" if len(args) > 1 { pName = args[1] } tax = pickTaxName(c, localDB, args[0], pName) if len(tax.Id) == 0 { return } } else { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong specimen id or taxon name or id")) c.Usage() } vals.Add(jdh.SpeTaxon, tax.Id) if _, err := localDB.Exec(jdh.Delete, jdh.Specimens, vals); err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } localDB.Exec(jdh.Commit, "", nil) }
// PickTaxName search for a unique taxon name. If there are more taxons // fullfilling the name, then it will print a list of the potential // names and finish the program. func pickTaxName(c *cmdapp.Command, db jdh.DB, name, parent string) *jdh.Taxon { args := new(jdh.Values) args.Add(jdh.TaxName, name) if len(parent) != 0 { args.Add(jdh.TaxParentName, parent) } l, err := db.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } var tax *jdh.Taxon mult := false for { ot := &jdh.Taxon{} if err := l.Scan(ot); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if tax == nil { tax = ot continue } if !mult { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("ambiguos taxon name")) fmt.Fprintf(os.Stderr, "%s\t%s\n", tax.Id, tax.Name) mult = true } fmt.Fprintf(os.Stderr, "%s\t%s\n", ot.Id, ot.Name) } if mult { os.Exit(0) } if tax == nil { return &jdh.Taxon{} } return tax }
func txLsRankNav(c *cmdapp.Command, db jdh.DB, id string, rank jdh.Rank) { args := new(jdh.Values) args.Add(jdh.TaxChildren, id) l, err := db.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } for { desc := &jdh.Taxon{} if err := l.Scan(desc); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if len(desc.Id) == 0 { continue } txLsRank(c, db, desc, rank) } }
func newSpList(tax *jdh.Taxon, db jdh.DB) *spList { ls := &spList{ db: db, sel: -1, tax: tax, } if taxonRank(cmd, db, tax) < jdh.Species { return ls } vals := new(jdh.Values) vals.Add(jdh.SpeTaxon, tax.Id) l, err := db.List(jdh.Specimens, vals) if err != nil { return ls } for { spe := &jdh.Specimen{} if err := l.Scan(spe); err != nil { break } ls.spe = append(ls.spe, spe) } return ls }
// TrInPickTax returns the id of a given taxon name. If there are more taxons // fullfilling the name, then it will print a list of the potential // names and finish the program. func trInPickTax(name, parent string) (string, error) { vals := new(jdh.Values) vals.Add(jdh.TaxName, name) if len(parent) != 0 { vals.Add(jdh.TaxParent, parent) } rank := jdh.Unranked if len(rankFlag) > 0 { rank = jdh.GetRank(rankFlag) if rank != jdh.Unranked { vals.Add(jdh.TaxRank, rankFlag) } } l, err := localDB.List(jdh.Taxonomy, vals) if err != nil { return "", err } var tax *jdh.Taxon mult := "" for { ot := &jdh.Taxon{} if err := l.Scan(ot); err != nil { if err == io.EOF { break } return "", err } if tax == nil { tax = ot continue } if len(mult) == 0 { mult = fmt.Sprintf("ambiguos taxon name\n") mult += fmt.Sprintf("%s\t%s\n", tax.Id, tax.Name) } mult += fmt.Sprintf("%s\t%s\n", ot.Id, ot.Name) } if len(mult) > 0 { return "", errors.New(mult) } if tax == nil { tax = &jdh.Taxon{ Name: name, IsValid: true, Parent: parent, Rank: rank, } return localDB.Exec(jdh.Add, jdh.Taxonomy, tax) } return tax.Id, nil }
// search for a parent of the given rank. func txSyncRankedParent(c *cmdapp.Command, id string, rank jdh.Rank) *jdh.Taxon { args := new(jdh.Values) args.Add(jdh.TaxParents, id) l, err := extDB.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } defer l.Close() for { p := &jdh.Taxon{} if err := l.Scan(p); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if p.Rank == rank { return p } } return nil }
func spInSearchNmdTaxon(c *cmdapp.Command, name, parent, txNum string, rank jdh.Rank) (bool, string) { args := new(jdh.Values) args.Add(jdh.TaxName, name) if len(parent) != 0 { args.Add(jdh.TaxParent, parent) } if rank != jdh.Unranked { args.Add(jdh.TaxRank, rank.String()) } l, err := localDB.List(jdh.Taxonomy, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } defer l.Close() var tax *jdh.Taxon mult := false for { ot := &jdh.Taxon{} if err := l.Scan(ot); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } if tax == nil { tax = ot continue } if !mult { if verboseFlag { fmt.Fprintf(os.Stdout, "WARNING:\t%s\t%s\tAmbiguos name\n", txNum) fmt.Fprintf(os.Stdout, "%s\t%s\n", tax.Id, tax.Name) } mult = true } if verboseFlag { fmt.Fprintf(os.Stderr, "%s\t%s\n", ot.Id, ot.Name) } } if mult || (tax == nil) { return mult, "" } return false, tax.Id }
func newTxList(tax *jdh.Taxon, db jdh.DB, syns bool) *txList { ls := &txList{ db: db, tax: tax, syns: syns, } id := "" if tax == nil { ls.tax = &jdh.Taxon{ Id: "0", Name: "root", } } else { id = tax.Id } vals := new(jdh.Values) vals.Add(jdh.TaxChildren, id) pl, err := db.List(jdh.Taxonomy, vals) if err != nil { return ls } for { d := &jdh.Taxon{} if err := pl.Scan(d); err != nil { break } ls.desc = append(ls.desc, d) } if !syns { return ls } vals.Reset() vals.Add(jdh.TaxSynonyms, id) pl, err = db.List(jdh.Taxonomy, vals) if err != nil { return ls } for { s := &jdh.Taxon{} if err := pl.Scan(s); err != nil { break } ls.desc = append(ls.desc, s) } return ls }
func txEdMove(from, to *jdh.Taxon) { if from.Id == "0" { return } if (from.Id == to.Id) || (from.Parent == to.Id) { return } if (to.Id == "0") && (!from.IsValid) { return } vals := new(jdh.Values) vals.Add(jdh.KeyId, from.Id) if to.Id != "0" { vals.Add(jdh.TaxParent, to.Id) } else { vals.Add(jdh.TaxParent, "") } localDB.Exec(jdh.Set, jdh.Taxonomy, vals) }
func raMkGetRas(c *cmdapp.Command, id string, size float64) *jdh.Raster { vals := new(jdh.Values) vals.Add(jdh.RDisTaxon, id) vals.Add(jdh.RDisCols, strconv.FormatInt(int64(360/size), 10)) vals.Add(jdh.RDisSource, jdh.ExplicitPoints.String()) l := rasList(c, localDB, vals) defer l.Close() for { ras := &jdh.Raster{} if err := l.Scan(ras); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } return ras } return &jdh.Raster{} }
func trForceNode(c *cmdapp.Command, nod *jdh.Node, txLs *list.List) { vals := new(jdh.Values) vals.Add(jdh.NodChildren, nod.Id) l, err := localDB.List(jdh.Nodes, vals) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } childs := 0 for { desc := &jdh.Node{} if err := l.Scan(desc); err != nil { if err == io.EOF { break } fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } trForceNode(c, desc, txLs) childs++ } if childs > 1 { return } if len(nod.Taxon) == 0 { return } tax := taxon(c, localDB, nod.Taxon) if tax.IsValid { return } par := taxon(c, localDB, tax.Parent) todel := false for e := txLs.Front(); e != nil; e = e.Next() { tId := e.Value.(string) if tId == par.Id { todel = true break } } if todel { fmt.Fprintf(os.Stdout, "%s: deleted\n", tax.Name) if !repFlag { vals.Reset() vals.Add(jdh.KeyId, nod.Id) localDB.Exec(jdh.Delete, jdh.Nodes, vals) } return } fmt.Fprintf(os.Stdout, "%s: changed to: %s\n", tax.Name, par.Name) if !repFlag { vals.Reset() vals.Add(jdh.KeyId, nod.Id) vals.Add(jdh.NodTaxon, par.Id) localDB.Exec(jdh.Set, jdh.Nodes, vals) txLs.PushBack(par.Id) } }
// TrInReadTreeNode reads a tree node in parenthetical notation. func trInReadTreeNode(in *bufio.Reader, tree, anc, pId string, taxLs map[string]string) (string, error) { nod := &jdh.Node{ Tree: tree, Parent: anc, } id, err := localDB.Exec(jdh.Add, jdh.Nodes, nod) if err != nil { return "", err } nod.Id = id last := "" for { r, _, err := in.ReadRune() if err != nil { return "", err } if unicode.IsSpace(r) { continue } if r == '(' { last, err = trInReadTreeNode(in, tree, nod.Id, pId, taxLs) if err != nil { return "", err } continue } if r == ')' { break } if r == ',' { last = "" continue } if r == ':' { if len(last) == 0 { return "", errors.New("unexpected ':' token") } v, err := trInNumber(in) if err != nil { return "", err } vals := new(jdh.Values) vals.Add(jdh.KeyId, last) vals.Add(jdh.NodLength, strconv.FormatUint(uint64(v), 10)) localDB.Exec(jdh.Set, jdh.Nodes, vals) last = "" continue } // a terminal in.UnreadRune() nm, err := trInString(in) if err != nil { return "", err } tax, ok := taxLs[nm] if !ok { tax, err = trInPickTax(nm, pId) if err != nil { return "", err } taxLs[nm] = tax } term := &jdh.Node{ Tree: tree, Parent: nod.Id, Taxon: tax, } last, err = localDB.Exec(jdh.Add, jdh.Nodes, term) if err != nil { return "", err } } return nod.Id, nil }
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)) } } } }