abbr works only on full words; changes on nodes don't work
[osm-helpers.git] / osm-history.cs
blob660c9863c275d8033993c7624007ccf4cf333780
1 /*
2 * Author: Paolo Molaro
3 * Copyright (c) 2008 Paolo Molaro lupus@oddwiz.org
4 * License: MIT/X11, see the MIT.X11 file.
5 */
6 using System;
7 using System.IO;
8 using System.Net;
9 using System.Xml;
10 using System.Text;
11 using System.Collections;
12 using System.Collections.Generic;
13 using OpenStreetMap;
15 class OsmHistory {
17 static void Usage ()
19 Usage_r (1);
22 static void Usage_r (int retval)
24 Console.WriteLine ("Usage:");
25 Console.WriteLine ("\tosm-history node|way|relation id");
26 Console.WriteLine ("\tosm-history --help");
27 Environment.Exit (retval);
30 static string[] GetTags (OsmObject obj)
32 ICollection tags = obj.Tags;
33 string[] arr = new string [tags.Count];
34 tags.CopyTo (arr, 0);
35 Array.Sort (arr);
36 return arr;
39 static void CompareTags (OsmObject a, OsmObject b)
41 string[] ta = GetTags (a);
42 string[] tb = GetTags (b);
43 int i = 0;
44 int j = 0;
45 for (; i < ta.Length && j < tb.Length; i++, j++) {
46 string tag = ta [i];
47 int cmp = string.Compare (tag, tb [j], StringComparison.Ordinal);
48 if (cmp == 0) {
49 if (a [tag] != b [tag])
50 Console.WriteLine ("\tTag {0}: {1} -> {2}", tag, a [tag], b [tag]);
51 continue;
53 if (cmp < 0) {
54 Console.WriteLine ("\tTag removed: {0} (was: {1})", tag, a [tag]);
55 j--;
56 } else {
57 Console.WriteLine ("\tTag added: {0}: {1}", tb [j], b [tb [j]]);
58 i--;
61 while (i < ta.Length) {
62 Console.WriteLine ("\tTag removed: {0} (was: {1})", ta [i], a [ta [i]]);
63 i++;
65 while (j < tb.Length) {
66 Console.WriteLine ("\tTag added: {0}: {1}", tb [j], b [tb [j]]);
67 j++;
71 static void CompareNodes (Node a, Node b)
73 if (a.Latitude != b.Latitude)
74 Console.WriteLine ("\tLatitude {0} -> {1}", a.Latitude , b.Latitude);
75 if (a.Longitude != b.Longitude)
76 Console.WriteLine ("\tLongitude {0} -> {1}", a.Longitude , b.Longitude);
79 // test:
80 // way 23059696
81 // way 23059688
82 // way 23060188
83 // node node 253003550
84 // Not the most compact diff output, but good enough for most osm cases
85 static void DiffNodes (long[] an, long[] bn) {
86 int adj_pos = 0;
87 int pos = 0;
88 int bpos = 0;
89 int index_out = -2;
90 StringBuilder sb = new StringBuilder ();
91 for (; pos < an.Length; ++pos, ++adj_pos) {
92 int mpos = Array.IndexOf (bn, an [pos], bpos);
93 if (mpos == adj_pos) {
94 bpos++;
95 continue;
97 if (mpos < 0) {
98 if (index_out != adj_pos - 1) {
99 sb.AppendFormat (" {0}:", adj_pos);
100 index_out++;
102 sb.AppendFormat (" -{0}", an [pos]);
103 continue;
105 for (; bpos < mpos; bpos++) {
106 if (index_out != adj_pos - 1) {
107 sb.AppendFormat (" {0}:", adj_pos);
108 index_out++;
110 sb.AppendFormat (" +{0}", bn [bpos]);
112 bpos++;
114 for (; bpos < bn.Length; bpos++) {
115 if (index_out != adj_pos - 1) {
116 sb.AppendFormat (" {0}:", adj_pos);
117 index_out++;
119 sb.AppendFormat (" +{0}", bn [bpos]);
121 if (sb.Length > 0) {
122 Console.WriteLine ("\tNodes:{0}", sb.ToString ());
123 //Console.WriteLine ("Nodes: {0}", bn.Length);
127 static void CompareWays (Way a, Way b)
129 long[] an = a.Nodes;
130 long[] bn = b.Nodes;
131 // simple check for a reverse
132 if (an.Length == bn.Length && an.Length > 0) {
133 if (an [0] != bn [0] && an [0] == bn [bn.Length - 1]) {
134 bool failed = false;
135 for (int i = 0; i < an.Length; ++i) {
136 if (an [i] != bn [bn.Length - i - 1]) {
137 failed = true;
138 break;
141 if (!failed) {
142 Console.WriteLine ("\tNodes reversed.");
143 return;
147 DiffNodes (an, bn);
148 // we don't check the nodes coordinates: it would likely be too expensive
151 static int CompareMember (RelationMember ma, RelationMember mb) {
152 int cmp = string.Compare (ma.Type, mb.Type, StringComparison.Ordinal);
153 if (cmp != 0)
154 return cmp;
155 long diff = ma.Ref - mb.Ref;
156 if (diff < 0)
157 return -1;
158 if (diff > 0)
159 return 1;
160 return string.Compare (ma.Role, mb.Role, StringComparison.Ordinal);
163 static RelationMember[] GetMembers (Relation obj)
165 RelationMember[] members = obj.Members;
166 if (members.Length <= 1)
167 return members;
168 members = members.Clone () as RelationMember [];
169 Array.Sort (members, CompareMember);
170 return members;
173 static string MemberDesc (RelationMember m) {
174 return string.Format ("type={0} ref={1} role={2}", m.Type, m.Ref, m.Role);
177 static void CompareRelations (Relation a, Relation b)
179 RelationMember[] ta = GetMembers (a);
180 RelationMember[] tb = GetMembers (b);
181 int i = 0;
182 int j = 0;
183 for (; i < ta.Length && j < tb.Length; i++, j++) {
184 int cmp = CompareMember (ta [i], tb [j]);
185 if (cmp == 0)
186 continue;
187 if (cmp < 0) {
188 Console.WriteLine ("\tMember removed: {0}", MemberDesc (ta [i]));
189 j--;
190 } else {
191 Console.WriteLine ("\tMember added: {0}", MemberDesc (tb [j]));
192 i--;
195 while (i < ta.Length) {
196 Console.WriteLine ("\tMember removed: {0}", MemberDesc (ta [i]));
197 i++;
199 while (j < tb.Length) {
200 Console.WriteLine ("\tMember added: {0}", MemberDesc (tb [j]));
201 j++;
205 static void PrintDiff (OsmObject a, OsmObject b)
207 // FIXME: make it clear when a way/node is removed
208 if (a.Visible != b.Visible)
209 Console.WriteLine ("\tVisible = {0}", b.Visible);
210 CompareTags (a, b);
211 if (a is Node)
212 CompareNodes (a as Node, b as Node);
213 if (a is Way)
214 CompareWays (a as Way, b as Way);
215 if (a is Relation)
216 CompareRelations (a as Relation, b as Relation);
219 static int Main (string[] args)
221 string type = null;
222 long id = 0;
223 int i = 0;
224 //bool out_data = false;
226 if (args.Length > 0 && args [0] == "--help") {
227 Usage_r(0);
229 if (args.Length > 0 && args [0] == "--out") {
230 //out_data = true;
231 i++;
233 if (args.Length - i != 2)
234 Usage ();
235 type = args [i];
236 if (type != "node" && type != "way" && type != "relation")
237 Usage ();
238 try {
239 id = long.Parse (args [i + 1]);
240 } catch {
241 Usage ();
244 DataBase db = new DataBase ();
245 IEnumerable<OsmObject> list;
246 try {
247 list = db.LoadHistory (type, id);
248 } catch (Exception e) {
249 Console.WriteLine (e.Message);
250 return 1;
252 OsmObject last = null;
253 int v = 1;
254 foreach (OsmObject obj in list) {
255 Console.WriteLine ("Version: {0} User: {1}, Time: {2}", v, obj.User, obj.TimeStamp);
256 v++;
257 if (last != null)
258 PrintDiff (last, obj);
259 last = obj;
261 return 0;