// move all points of w, use the node with id as reference to do a relative move func (w *Way) MoveTo(id int64, p *point.Point) error { ref := w.Nodes_[id] if ref == nil { return errors.New(fmt.Sprintf("Node #%d not part of Way #%d\n", id, w.Id())) } return w.RMoveTo(point.New(ref.Position().Lat-p.Lat, ref.Position().Lon-p.Lon)) }
// Weighted centroid of all area parts // // NOTE - when a relation has node members outside of the way members, this will // probably result in a wrong point (bounding box is taken from all nodes, // not just way nodes) func (r *Relation) Centroid() (p *point.Point, err error) { if !r.IsAreaRelation() { err = errors.New("Not an area relation") return } var seen []*way.Way var bb *bbox.BBox var lat float64 var lon float64 var den float64 wayList, err := r.WayMembersAsWays() if err != nil { return } bb, err = r.BoundingBox() if err != nil { return } for _, w := range wayList { c := w.Centroid() if c == nil { err = errors.New(fmt.Sprintf("Way #%d has no centroid?!", w.Id())) return } a := w.Area() if a == -1.0 { err = errors.New(fmt.Sprintf("Way #%d has no area", w.Id())) return } count := 0 for _, s := range seen { if s.Contains(w.Nodes_[0]) { count += 1 } } seen = append(seen, w) neg := 1.0 if count%2 == 1 { neg = -1.0 } lon += a * neg * (c.Lon - bb.LowerLeft.Lon) lat += a * neg * (c.Lat - bb.LowerLeft.Lat) den += a * neg } return point.New(bb.LowerLeft.Lat+lat/den, bb.LowerLeft.Lon+lon/den), nil }
func (nl NodeList) BoundingBox() (bb *bbox.BBox, err error) { if nl == nil { err = errors.New("Empty Nodelist") return } n := []*Node(nl) llat := n[0].Position_.Lat ulat := n[0].Position_.Lat llon := n[0].Position_.Lon ulon := n[0].Position_.Lon l := len(n) for i := 1; i < l; i++ { llat = math.Min(llat, n[i].Position_.Lat) ulat = math.Max(ulat, n[i].Position_.Lat) llon = math.Min(llon, n[i].Position_.Lon) ulon = math.Max(ulon, n[i].Position_.Lon) } return &bbox.BBox{ LowerLeft: point.New(llat, llon), UpperRight: point.New(ulat, ulon), }, nil }
func (w *Way) Centroid() *point.Point { if !w.Closed() { return nil } var cx, cy, a float64 l := len(w.Nodes_) - 1 for i := 0; i < l; i++ { ap := w.Nodes_[i].Position_.Lon*w.Nodes_[i+1].Position_.Lat - w.Nodes_[i+1].Position_.Lon*w.Nodes_[i].Position_.Lat cx += (w.Nodes_[i].Position_.Lon + w.Nodes_[i+1].Position_.Lon) * ap cy += (w.Nodes_[i].Position_.Lat + w.Nodes_[i+1].Position_.Lat) * ap a += ap } cx = 2 * cx / (6 * a) cy = 2 * cy / (6 * a) return point.New(cy, cx) }
// implements the osm.Parser interface func (p *Pbf) Parse() (o *osm.OSM, err error) { d := osmpbf.NewDecoder(p.r) err = d.Start(runtime.GOMAXPROCS(-1)) if err != nil { return } o = osm.NewOSM() var v interface{} for { if v, err = d.Decode(); err == io.EOF { err = nil break } else if err != nil { return } else { switch v := v.(type) { case *osmpbf.Node: var t tags.Tags if v.Tags != nil && len(v.Tags) != 0 { t = tags.Tags(v.Tags) } o.Nodes[v.ID] = &node.Node{ Id_: v.ID, User_: user.New(int64(v.Info.Uid), v.Info.User), Position_: point.New(v.Lat, v.Lon), Timestamp_: v.Info.Timestamp, Changeset_: v.Info.Changeset, Version_: int64(v.Info.Version), Visible_: v.Info.Visible, Tags_: &t, } case *osmpbf.Way: var t tags.Tags if v.Tags != nil && len(v.Tags) != 0 { t = tags.Tags(v.Tags) } w := &way.Way{ Id_: v.ID, User_: user.New(int64(v.Info.Uid), v.Info.User), Timestamp_: v.Info.Timestamp, Changeset_: v.Info.Changeset, Version_: int64(v.Info.Version), Visible_: v.Info.Visible, Tags_: &t, } var nd []*node.Node for _, id := range v.NodeIDs { n := o.Nodes[id] if n == nil { err = errors.New(fmt.Sprintf("Missing node #%d in way #%d", id, v.ID)) o = nil return } nd = append(nd, n) } w.Nodes_ = nd o.Ways[v.ID] = w case *osmpbf.Relation: var t tags.Tags if v.Tags != nil && len(v.Tags) != 0 { t = tags.Tags(v.Tags) } r := &relation.Relation{ Id_: v.ID, User_: user.New(int64(v.Info.Uid), v.Info.User), Timestamp_: v.Info.Timestamp, Changeset_: v.Info.Changeset, Version_: int64(v.Info.Version), Visible_: v.Info.Visible, Tags_: &t, } var members []*relation.Member for _, m := range v.Members { member := &relation.Member{Role: m.Role, Id_: m.ID} switch m.Type { case osmpbf.NodeType: member.Type_ = item.TypeNode member.Ref = o.GetNode(m.ID) case osmpbf.WayType: member.Type_ = item.TypeWay member.Ref = o.GetWay(m.ID) case osmpbf.RelationType: member.Type_ = item.TypeRelation member.Ref = o.GetRelation(m.ID) } if member.Ref == nil { err = errors.New(fmt.Sprintf("Missing member #%d (%s) in way #%d", m.ID, member.Type(), v.ID)) o = nil return } members = append(members, member) } r.Members_ = members o.Relations[v.ID] = r default: log.Printf("ERROR: unknown type %T\n", v) } } } return }
func (x *DotOSM) parseItem(line string) (i item.Item, err error) { prefix, closed, m := x.parseLine(line) var ts time.Time if m["timestamp"] != "" { ts, err = time.Parse(time.RFC3339, m["timestamp"]) if err != nil { err = errors.New(fmt.Sprintf("Failed to parse timestamp '%s': %s\n", m["timestamp"], err)) return } } switch prefix { case "<node": n := &node.Node{ Id_: str2int64(m["id"]), User_: user.New(str2int64(m["uid"]), m["user"]), Position_: point.New(str2float64(m["lat"]), str2float64(m["lon"])), Timestamp_: ts, Version_: str2int64(m["version"]), Changeset_: str2int64(m["changeset"]), Visible_: str2bool(m["visible"]), } if !closed { n.Tags_ = x.parseTags("node") } // fmt.Printf("NODE=%q\n", n) return n, nil case "<way": if closed { err = errors.New(fmt.Sprintf("Way %s has no nodes\n", m["id"])) return } w := &way.Way{ Id_: str2int64(m["id"]), User_: user.New(str2int64(m["uid"]), m["user"]), Timestamp_: ts, Version_: str2int64(m["version"]), Changeset_: str2int64(m["changeset"]), Visible_: str2bool(m["visible"]), } var t *tags.Tags var nd []*node.Node t, nd, err = x.parseWay(str2int64(m["id"])) if err != nil { return } w.Tags_ = t w.Nodes_ = nd // fmt.Printf("WAY=%q\n", w) return w, nil case "<relation": if closed { err = errors.New(fmt.Sprintf("Relation %s has no members\n", m["id"])) return } rel := &relation.Relation{ Id_: str2int64(m["id"]), User_: user.New(str2int64(m["uid"]), m["user"]), Timestamp_: ts, Version_: str2int64(m["version"]), Changeset_: str2int64(m["changeset"]), Visible_: str2bool(m["visible"]), } members, tags := x.parseRelation(str2int64(m["id"])) rel.Members_ = members rel.Tags_ = tags // fmt.Printf("RELATION=%q\n", rel) return rel, nil case "<osm": // fmt.Printf("OSM=%q\n", m) case "</osm>": // fmt.Printf("/OSM\n") case "<bounds": // fmt.Printf("BOUNDS=%q\n", m) default: // fmt.Printf("OTHER=%q\n", m) } return &xmlItem{t: item.TypeUnknown}, nil }