├── GRASS-scripts
├── v.osm.acc
│ ├── v.osm.acc.html
│ ├── Makefile
│ └── v.osm.acc.py
├── v.osm.preproc
│ ├── v.osm.preproc.html
│ ├── Makefile
│ └── v.osm.preproc.py
├── v.osm.precomp
│ ├── Makefile
│ ├── v.osm.precomp.html
│ └── v.osm.precomp.py
└── README.md
├── .gitmodules
├── README.md~
├── README.md
└── LICENSE
/GRASS-scripts/v.osm.acc/v.osm.acc.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.preproc/v.osm.preproc.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "WPS_OSM-REF-Comparison"]
2 | path = WPS_OSM-REF-Comparison
3 | url = https://github.com/GabrielePrestifilippo/WPS_OSM-REF-Comparison
4 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.acc/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_TOPDIR = ../..
2 |
3 | PGM = v.osm.acc
4 |
5 | include $(MODULE_TOPDIR)/include/Make/Script.make
6 |
7 | default: script
8 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.precomp/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_TOPDIR = ../..
2 |
3 | PGM = v.osm.precomp
4 |
5 | include $(MODULE_TOPDIR)/include/Make/Script.make
6 |
7 | default: script
8 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.preproc/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_TOPDIR = ../..
2 |
3 | PGM = v.osm.preproc
4 |
5 | include $(MODULE_TOPDIR)/include/Make/Script.make
6 |
7 | default: script
8 |
--------------------------------------------------------------------------------
/README.md~:
--------------------------------------------------------------------------------
1 | # Comparison between OSM and authoritative road network datasets
2 | This repository contains scripts for comparing road network datasets from [OpenStreetMap (OSM)](http://openstreetmap.org) and an authoritative source. The repository contains two folders:
3 | * [GRASS-scripts](https://github.com/MoniaMolinari/OSM-roads-comparison/tree/master/GRASS-scripts) provides three Python modules to perform the complete dataset comparison in [GRASS GIS](https://grass.osgeo.org/)
4 | * [WPS_OSM-REF-Comparison](https://github.com/GabrielePrestifilippo/WPS_OSM-REF-Comparison) provides the code to setup the Web Processing Service (WPS) for a preliminary comparison of the datasets
5 |
6 | Detailed instructions on how to use the tools are provided in each of the two folders.
7 |
8 | ## Related academic publications
9 | * Brovelli M. A., Minghini M., Molinari M. & Mooney P. (2015) A FOSS4G-based procedure to compare OpenStreetMap and authoritative road network datasets. *Geomatics Workbooks* 12, pp. 235-238, ISSN 1591-092X [[pdf](http://geomatica.como.polimi.it/workbooks/n12/FOSS4G-eu15_submission_70.pdf)]
10 |
--------------------------------------------------------------------------------
/GRASS-scripts/README.md:
--------------------------------------------------------------------------------
1 | # GRASS scripts
2 | This folder contains, in the corresponding subfolders, three Python modules for [GRASS GIS](https://grass.osgeo.org/) aimed at performing a geometrical comparison between two road network datasets: one from the [OpenStreetMap (OSM)](http://openstreetmap.org) project and one from an authoritative source:
3 | * [v.osm.precomp](https://github.com/MoniaMolinari/OSM-roads-comparison/tree/master/GRASS-scripts/v.osm.precomp) (Step 1) performs a preliminary comparison of the two datasets, computes global statistics and performs a sensitivity analysis to help users choosing a suitable value of the buffer parameter, which is key in Step 2
4 | * [v.osm.preproc](https://github.com/MoniaMolinari/OSM-roads-comparison/tree/master/GRASS-scripts/v.osm.preproc) (Step 2) performs a geometric preprocessing of the OSM road network dataset to extract its subset representing the same road features of the authoritative dataset
5 | * [v.osm.acc](https://github.com/MoniaMolinari/OSM-roads-comparison/tree/master/GRASS-scripts/v.osm.acc) (Step 3) evaluates the spatial accuracy of the OSM subset extracted in Step 2 using a grid-based approach
6 |
7 | The modules are independent, however users are suggested to apply them subsequently to maximize the effectiveness of the procedure.
8 |
9 | **NOTE**: current versions are tested in GRASS GIS 7.1 (development version) and NOT in previous releases. Authors will update the modules as soon as the next stable release will come out.
10 |
11 | ## Installation (Linux)
12 | * Copy the three folders in the `scripts` folder, which is inside the GRASS source code folder
13 | * Open a terminal window, enter each of the three folders and compile the code. For example, for the `v.osm.precomp` module, type:
14 | ```
15 | cd path-to-GRASS-folder/scripts/v.osm.precomp
16 | sudo make
17 | sudo make install
18 | ```
19 | ## Running the Script (Linux)
20 | To simply run the scripts without installing them:
21 | * From GRASS GIS top menu select `File`
22 | * Select `Launch Script`
23 | * Select a ".py" module such as "v.osm.precomp.py"
24 | * Select `Open`
25 |
26 | ## Related academic publications
27 | * Brovelli M. A., Minghini M., Molinari M. & Mooney P. (2015) A FOSS4G-based procedure to compare OpenStreetMap and authoritative road network datasets. *Geomatics Workbooks* 12, pp. 235-238, ISSN 1591-092X [[pdf](http://geomatica.como.polimi.it/workbooks/n12/FOSS4G-eu15_submission_70.pdf)]
28 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.precomp/v.osm.precomp.html:
--------------------------------------------------------------------------------
1 |
DESCRIPTION
2 |
3 | buffers parameter is a comma separated list of buffers to consider.
4 | All the values between 1 and 20 could be useful, but you can also extend more.
5 |
6 | roi parameter is a vector layer used to cut the input network layers.
7 |
8 | EXAMPLE
9 |
10 |
11 | wget -c -O osm_roadsmajor.geojson
12 | http://overpass-api.de/api/interpreter?data=%5Bout%3Ajson%5D%5Btimeout%3A25%5D%3B%28node%5B%22highway%22%3D%22motorway%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bway%5B%22highway%22%3D%22motorway%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Brelation%5B%22highway%22%3D%22motorway%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bnode%5B%22highway%22%3D%22motorway%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bway%5B%22highway%22%3D%22motorway%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Brelation%5B%22highway%22%3D%22motorway%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bnode%5B%22highway%22%3D%22trunk%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bway%5B%22highway%22%3D%22trunk%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Brelation%5B%22highway%22%3D%22trunk%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bnode%5B%22highway%22%3D%22trunk%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Bway%5B%22highway%22%3D%22trunk%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3Brelation%5B%22highway%22%3D%22trunk%5Flink%22%5D%2835%2E59255224089235%2C%2D78%2E88114929199219%2C35%2E905736972317364%2C%2D78%2E36616516113281%29%3B%29%3Bout%20body%3B%3E%3Bout%20skel%20qt%3B%0A
13 |
14 | v.import input=osm_roadsmajor.geojson output=osm_roadsmajor
15 |
16 | v.osm.precomp osm=osm_roadsmajor ref=roadsmajor buffers=1,5,10,15 out_graphs=precomp/ output=precomp/osm_precomp.txt
17 |
18 |
19 | SEE ALSO
20 |
21 |
22 | v.osm.acc,
23 | v.osm.preproc
24 |
25 |
26 |
27 | AUTHOR
28 |
29 | Monia Molinari, Marco Minghini (Politecnico di Milano), parallelization
30 | Luca Delucchi (Fondazione Edmund Mach)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Comparison between OSM and authoritative road network datasets
2 | This repository contains scripts for comparing road network datasets from [OpenStreetMap (OSM)](http://openstreetmap.org) and an authoritative source. The repository contains two folders:
3 | * [GRASS-scripts](https://github.com/MoniaMolinari/OSM-roads-comparison/tree/master/GRASS-scripts) provides three Python modules to perform the complete dataset comparison in [GRASS GIS](https://grass.osgeo.org/)
4 | * [WPS_OSM-REF-Comparison](https://github.com/GabrielePrestifilippo/WPS_OSM-REF-Comparison) provides the code to setup the Web Processing Service (WPS) for a preliminary comparison of the datasets
5 |
6 | Detailed instructions on how to use the tools are provided in each of the two folders.
7 |
8 | ## Related academic publications
9 |
10 | * Brovelli M.A., Minghini M. & Molinari M.E. (2016) An automated GRASS-based procedure to assess the geometrical accuracy of the OpenStreetMap Paris road network. *International Archives of the Photogrammetry, Remote Sensing and Spatial Information Sciences* Volume XLI-B2, 609-614. doi:10.5194/isprsarchives-XLI-B2-609-2016 [[pdf](http://www.int-arch-photogramm-remote-sens-spatial-inf-sci.net/XLI-B7/919/2016/isprs-archives-XLI-B7-919-2016.pdf)]
11 |
12 | * Brovelli M.A., Minghini M., Molinari M.E. & Mooney P. (2016) Towards an Automated Comparison of OpenStreetMap with Authoritative Road Datasets. *Transactions in GIS*. doi:10.1111/tgis.12182 [[pdf](https://www.researchgate.net/profile/Marco_Minghini/publication/298296464_Towards_an_Automated_Comparison_of_OpenStreetMap_with_Authoritative_Road_Datasets/links/56e7c9e108ae4c354b1d001a.pdf)]
13 |
14 | * Antunes F., Fonte C.C., Brovelli M.A., Minghini M., Molinari M.E. & Mooney P. (2015) Assessing OSM Road Positional Quality with Authoritative Data. *Proceedings of the VIII Conferência Nacional de Cartografia e Geodesia*, Lisbon (Portugal), October 29-30, 2015, ISBN 978-989-8152-10-7 [[pdf](http://geomobile.como.polimi.it/website/papers/Antunes_Fonte_Brovelli_Minghini_Molinari_Mooney_2015.pdf)]
15 |
16 | * Brovelli M.A., Minghini M., Molinari M.E. & Mooney P. (2015) A FOSS4G-based procedure to compare OpenStreetMap and authoritative road network datasets. *Geomatics Workbooks* 12, 235-238, ISSN 1591-092X [[pdf](http://geomatica.como.polimi.it/workbooks/n12/FOSS4G-eu15_submission_70.pdf)]
17 |
18 | ## Related academic presentations
19 | * Brovelli M. A., Minghini M. & Molinari M. (2016) A GRASS-based automated procedure to compare OpenStreetMap and authoritative road network datasets. Presented at the XVII Meeting of GRASS and FOSS4G Italian users, Parma (Italy), February 11-12 2016 [[pdf](http://www.slideshare.net/mingo23/a-grassbased-automated-procedure-to-compare-openstreetmap-and-authoritative-road-network-datasets)]
20 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.preproc/v.osm.preproc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding:utf-8 -*-
3 | ##############################################################################
4 | # MODULE: v.osm.preproc
5 | # AUTHOR(S): Monia Molinari, Marco Minghini
6 | # PURPOSE: Tool for extracting road features in the OSM dataset which have a correspondence in the reference dataset
7 | # COPYRIGHT: (C) 2015 by the GRASS Development Team
8 | #
9 | # This program is free software under the GNU General Public
10 | # License (>=v2). Read the file COPYING that comes with GRASS
11 | # for details.
12 | # ############################################################################
13 | #%Module
14 | #% description: Tool for extracting road features in the OSM dataset which have a correspondence in the reference dataset
15 | #% keywords: vector, OSM, preprocessing
16 | #%End
17 |
18 | #%option
19 | #% key: osm
20 | #% type: string
21 | #% gisprompt: old,vector,vector
22 | #% description: OpenStreetMap dataset
23 | #% required: yes
24 | #%end
25 |
26 | #%option
27 | #% key: ref
28 | #% type: string
29 | #% gisprompt: old,vector,input
30 | #% description: Reference dataset
31 | #% required: yes
32 | #%end
33 |
34 | #%option
35 | #% key: buffer
36 | #% type: double
37 | #% description: Buffer around reference dataset (map units)
38 | #% required: yes
39 | #%end
40 |
41 | #%option
42 | #% key: angle_thres
43 | #% type: double
44 | #% description: Threshold value for angular coefficient comparison (degrees)
45 | #% required: yes
46 | #%end
47 |
48 | #%option G_OPT_V_OUTPUT
49 | #% key: output
50 | #% description: Name for output map
51 | #% required: yes
52 | #%end
53 |
54 | #%option
55 | #% key: douglas_thres
56 | #% type: double
57 | #% description: Threshold value for Douglas-Peucker algorithm (map unit)
58 | #% required: no
59 | #%end
60 |
61 | #%option G_OPT_F_OUTPUT
62 | #% key: out_file
63 | #% description: Name for output file with statistics (if omitted or "-" output to stdout)
64 | #% required: no
65 | #%end
66 |
67 | import math
68 | import sys
69 | import shutil
70 | import time
71 | import grass.script as grass
72 |
73 | def length(data):
74 | feat_osm = int(((grass.read_command("v.info", map=data,flags="t",quiet=True)).split("\n")[2]).split("=")[1])
75 | if feat_osm>0:
76 | length_data = grass.read_command("v.to.db",map=data,option="length",flags="p")
77 | s_data=0
78 | l_data = length_data.split("\n")
79 | for item in l_data[1:-1]:
80 | s_data+=float(item.split("|")[1])
81 | else:
82 | s_data=0
83 | return s_data
84 |
85 |
86 | def GetCoeff(vect):
87 | coord_start = grass.read_command("v.to.db", map=vect, option="start", type="line",flags="p").split("\n")[1]
88 | x_start = float(coord_start.split("|")[1])
89 | y_start = float(coord_start.split("|")[2])
90 | coord_end = grass.read_command("v.to.db", map=vect, option="end", type="line",flags="p").split("\n")[1]
91 | x_end = float(coord_end.split("|")[1])
92 | y_end = float(coord_end.split("|")[2])
93 | if (x_end-x_start) <> 0:
94 | m = (y_end-y_start)/(x_end-x_start)
95 | else:
96 | m = 10**9
97 | return m
98 |
99 | def main():
100 | osm = options["osm"]
101 | ref = options["ref"]
102 | bf = options["buffer"]
103 | angle_thres = options["angle_thres"]
104 | doug = options["douglas_thres"]
105 | out = options["output"]
106 | out_file = options["out_file"]
107 |
108 | ## Check if input files exist
109 | if not grass.find_file(name=osm,element='vector')['file']:
110 | grass.fatal(_("Vector map <%s> not found") % osm)
111 |
112 | if not grass.find_file(name=ref,element='vector')['file']:
113 | grass.fatal(_("Vector map <%s> not found") % ref)
114 |
115 | ## Prepare temporary map names
116 | processid = str(time.time()).replace(".","_")
117 | ref_gen = "ref_gen_" + processid
118 | ref_split = "ref_split_" + processid
119 | osm_split = "osm_split_" + processid
120 | deg_points = "deg_points_" + processid
121 | degmin_points = "degmin_points_" + processid
122 | ref_degmin = "ref_degmin_" + processid
123 | patch = "patch_" + processid
124 | fdata = "fdata_" + processid
125 | fbuffer = "fbuffer_" + processid
126 | odata = "odata_" + processid
127 | osdata = "osdata_" + processid
128 | outbuff = "outbuff_" + processid
129 |
130 | ## Calculate length original data
131 | l_osm = length(osm)
132 | l_ref = length(ref)
133 |
134 | if l_ref == 0:
135 | grass.run_command("g.remove", type="vect", pattern="%s"%processid,flags="fr",quiet=True)
136 | grass.fatal(_("No reference data for comparison"))
137 |
138 | if l_osm == 0:
139 | grass.run_command("g.remove", type="vect", pattern="%s"%processid,flags="fr",quiet=True)
140 | grass.fatal(_("No OSM data for comparison"))
141 |
142 |
143 | ## Generalize
144 | if doug:
145 | grass.run_command("v.generalize",input=ref,output=ref_gen,method="douglas", threshold=doug,quiet=True)
146 | ref = ref_gen
147 |
148 | ## Split REF datasets
149 | grass.run_command("v.split",input=ref,output=ref_split,vertices=2,quiet=True)
150 | grass.run_command("v.out.ogr",input=ref_split,output="/tmp/%s"%ref_split,flags="s",quiet=True)
151 | grass.run_command("g.remove",type="vect",name=ref_split,flags="f",quiet=True)
152 | grass.run_command("v.in.ogr",input="/tmp/%s/%s.shp"%(ref_split,ref_split),output=ref_split,quiet=True)
153 | ref = ref_split
154 | shutil.rmtree('/tmp/%s/'%ref_split)
155 |
156 | ## Split OSM datasets
157 | grass.run_command("v.split",input=osm,output=osm_split,vertices=2,quiet=True)
158 | grass.run_command("v.out.ogr",input=osm_split,output="/tmp/%s"%osm_split,flags="s",quiet=True)
159 | grass.run_command("g.remove",type="vect",name=osm_split,flags="f",quiet=True)
160 | grass.run_command("v.in.ogr",input="/tmp/%s/%s.shp"%(osm_split,osm_split),output=osm_split,quiet=True)
161 | osm_orig = osm
162 | osm = osm_split
163 | shutil.rmtree('/tmp/%s/'%osm_split)
164 |
165 | # Calculate degree and extract REF category lines intersecting points with minimum value
166 | grass.run_command("v.net.centrality",input=ref, output=deg_points, degree="degree",flags="a",quiet=True)
167 | list_values = (grass.read_command("v.db.select",map=deg_points,columns="degree",flags="c",quiet=True)).split("\n")[0:-1]
168 | degmin = min(map(float,list_values))
169 |
170 | grass.run_command("v.extract", input=deg_points, output=degmin_points, where="degree=%s"%degmin,quiet=True)
171 | grass.run_command("v.select",ainput=ref,binput=degmin_points,output=ref_degmin,operator="overlap",quiet=True)
172 | list_lines = (grass.read_command("v.db.select",map=ref_degmin,columns="cat",flags="c",quiet=True)).split("\n")[0:-1]
173 | #print list_lines
174 |
175 | ## Create new vector map
176 | grass.run_command("v.edit",map=patch+"_0_0",tool="create",quiet=True)
177 |
178 | list_feature = grass.read_command("v.db.select",map=ref,columns="cat",flags="c",quiet=True).split("\n")[0:-1]
179 | i=0
180 | z=0
181 | #print list_feature
182 |
183 | ## Angular coefficient Comparison
184 | for f in list_feature:
185 | grass.run_command("v.extract",input=ref,output=fdata+"_%s"%f,where="cat=%s"%f,overwrite=True,quiet=True)
186 | if f in list_lines:
187 | grass.run_command("v.buffer",input=fdata+"_%s"%f,output=fbuffer+"_%s"%f,flags="c",distance=bf,overwrite=True,quiet=True)
188 | else:
189 | grass.run_command("v.buffer",input=fdata+"_%s"%f,output=fbuffer+"_%s"%f,distance=bf,overwrite=True,quiet=True)
190 |
191 | grass.run_command("v.overlay",ainput=osm, atype="line",binput=fbuffer+"_%s"%f,output=odata+"_%s"%f,operator="and",overwrite=True,quiet=True)
192 | lines = ((grass.read_command("v.info", map=odata+"_%s"%f,flags="t",quiet=True)).split("\n")[2]).split("=")[1]
193 | if int(lines)==0:
194 | grass.run_command("g.remove", type="vect", name="%s_%s,%s_%s,%s_%s"%(fdata,f,fbuffer,f,odata,f),flags="f",quiet=True)
195 | else:
196 | ## Get REF angular coefficient
197 | list_subfeature = grass.read_command("v.db.select",map=odata+"_%s"%f,columns="cat",flags="c",quiet=True).split("\n")[0:-1]
198 | m_ref = GetCoeff(fdata+"_%s"%f)
199 | #print m_ref
200 |
201 | ## Get OSM subfeatures angular coefficient
202 | for sf in list_subfeature:
203 | grass.run_command("v.extract",input=odata+"_%s"%f,output=osdata+"_%s_%s"%(f,sf),where="cat=%s"%sf,overwrite=True,quiet=True)
204 | m_osm = GetCoeff(osdata+"_%s_%s"%(f,sf))
205 |
206 |
207 | if math.degrees(abs(math.atan((m_ref-m_osm)/(1+m_ref*m_osm))))<=angle_thres:
208 | grass.run_command("v.patch",input="%s_%s_%s,%s_%s_%s"%(patch,i,z,osdata,f,sf),output=patch+"_%s_%s"%(f,sf),overwrite=True,quiet=True)
209 | grass.run_command("g.remove", type="vect", name="%s_%s_%s,%s_%s_%s"%(patch,i,z,osdata,f,sf), flags="f",quiet=True)
210 | i=f
211 | z=sf
212 | else:
213 | grass.run_command("g.remove", type="vect", name=osdata+"_%s_%s"%(f,sf), flags="f",quiet=True)
214 | grass.run_command("g.remove", type="vect", name="%s_%s,%s_%s,%s_%s"%(fdata,f,fbuffer,f,odata,f), flags="f",quiet=True)
215 |
216 | ## Clean output map
217 | l_map = grass.read_command("g.list",type="vect",quiet=True).split("\n")[0:-1]
218 | last_map = [s for s in l_map if "patch" in s]
219 | grass.run_command("v.buffer", input=last_map[0],output=outbuff, distance=0.0001,quiet=True)
220 | grass.run_command("v.overlay",ainput=osm_orig,atype="line",binput=outbuff,output=out,operator="and",flags="t",quiet=True)
221 |
222 | ## Delete all maps
223 | grass.run_command("g.remove",type="vect",name="%s,%s,%s,%s,%s,%s,%s"%(deg_points,ref_degmin,degmin_points,ref_gen,ref_split,osm_split,outbuff),flags="f",quiet=True)
224 |
225 | grass.run_command("g.remove",type="vect",name="%s"%last_map[0],flags="f",quiet=True)
226 |
227 | ## Calculate final map statistics
228 | l_osm_proc = length(out)
229 | diff_osm = l_osm - l_osm_proc
230 | diff_p_osm = diff_osm/l_osm*100
231 | diff_new = l_ref - l_osm_proc
232 | diff_p_new = diff_new/l_ref*100
233 |
234 | ## Write output file with statistics (if required)
235 | if len(out_file)>0:
236 | fil=open(out_file,"w")
237 | fil.write("REF dataset length: %s m\n"%(round(l_ref,1)))
238 | fil.write("Original OSM dataset length: %s m\n"%(round(l_osm,1)))
239 | fil.write("Processed OSM dataset length: %s m\n"%(round(l_osm_proc,1)))
240 | fil.write("Difference between OSM original and processed datasets length: %s m (%s%%)\n"%(round(diff_osm,1),round(diff_p_osm,1)))
241 | fil.write("Difference between REF dataset and processed OSM dataset length: %s m (%s%%)\n"%(round(diff_new,1),round(diff_p_new,1)))
242 | fil.close()
243 |
244 | ## Print statistics
245 | print("#####################################################################\n")
246 | print("Original OSM dataset length: %s m\n"%(round(l_osm,1)))
247 | print("Processed OSM dataset length: %s m\n"%(round(l_osm_proc,1)))
248 | print("Difference between OSM original and processed datasets length: %s m (%s%%)\n"%(round(diff_osm,1),round(diff_p_osm,1)))
249 | print("Difference between REF dataset and processed OSM dataset length: %s m (%s%%)\n"%(round(diff_new,1),round(diff_p_new,1)))
250 | print("#####################################################################\n")
251 |
252 |
253 |
254 | if __name__ == "__main__":
255 | options,flags = grass.parser()
256 | sys.exit(main())
257 |
258 |
--------------------------------------------------------------------------------
/GRASS-scripts/v.osm.acc/v.osm.acc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding:utf-8 -*-
3 | ##############################################################################
4 | # MODULE: v.osm.acc
5 | # AUTHOR(S): Monia Elisa Molinari, Marco Minghini
6 | # PURPOSE: Tool for accuracy assessment of OSM data
7 | # COPYRIGHT: (C) 2015 by the GRASS Development Team
8 | #
9 | # This program is free software under the GNU General Public
10 | # License (>=v2). Read the file COPYING that comes with GRASS
11 | # for details.
12 | # ############################################################################
13 | #%Module
14 | #% description: Tool for accuracy assessment of OSM data
15 | #% keywords: vector
16 | #% keyword: OSM
17 | #% keyword: accuracy
18 | #%End
19 | #%option G_OPT_V_INPUT
20 | #% key: osm
21 | #% label: OpenStreetMap dataset
22 | #% required : yes
23 | #%end
24 | #%option G_OPT_V_INPUT
25 | #% key: ref
26 | #% label: Reference dataset
27 | #% required : yes
28 | #%end
29 | #%option G_OPT_V_INPUT
30 | #% key: grid
31 | #% label: Vector grid for comparison
32 | #% guisection: Grid
33 | #% required: no
34 | #%end
35 | #%option
36 | #% key: ul_grid
37 | #% type: string
38 | #% guisection: Grid
39 | #% description: Coordinates of the upper left grid corner (x,y)
40 | #% required: no
41 | #%end
42 | #%option
43 | #% key: lr_grid
44 | #% type: string
45 | #% guisection: Grid
46 | #% description: Coordinates of the lower right grid corner (x,y)
47 | #% required: no
48 | #%end
49 | #%option
50 | #% key: box_grid
51 | #% type: string
52 | #% guisection: Grid
53 | #% description: Width and height for boxes in grid (map units)
54 | #% required: no
55 | #%end
56 | #%option G_OPT_V_INPUT
57 | #% key: output
58 | #% type: string
59 | #% guisection: Grid
60 | #% label: Name for the grid vector output map
61 | #% required: no
62 | #%end
63 | #%option
64 | #% key: tol_max
65 | #% type: double
66 | #% guisection: Deviation analysis
67 | #% description: Upper bound value for automated accuracy evaluation (map units)
68 | #% required: no
69 | #%end
70 | #%option
71 | #% key: perc
72 | #% type: double
73 | #% guisection: Deviation analysis
74 | #% description: Length percentage of OSM dataset to be considered for automated accuracy evaluation (%)
75 | #% required: no
76 | #% answer: 100
77 | #%end
78 | #%option
79 | #% key: tol_eval
80 | #% type: string
81 | #% guisection: Deviation analysis
82 | #% description: Threshold values for accuracy evaluation, separated by comma (map units)
83 | #% required: no
84 | #%end
85 |
86 | import sys
87 | import math
88 | import time
89 | import grass.script as grass
90 |
91 | def GetList(vect):
92 | list_vect = grass.read_command("v.db.select",map=vect,columns="cat",flags="c",quiet=True)
93 | list_v = list_vect.split("\n")[0:-1]
94 | return list_v
95 |
96 | def MakeGrid(n,w,s,e,nsres,ewres,out):
97 | rows = math.ceil(float((n-s)/nsres))
98 | cols = math.ceil(float((e-w)/ewres))
99 | grass.run_command("g.region",n=n,s=n-nsres*rows,e=w+ewres*cols,w=w,quiet=True)
100 | grass.run_command("v.mkgrid",map=out,grid="%s,%s"%(rows,cols),quiet=True)
101 |
102 | def GetRefBox(ref,ref_box,k_box,processid):
103 | N = grass.region()['n']
104 | S = grass.region()['s']
105 | E = grass.region()['e']
106 | W = grass.region()['w']
107 | grass.run_command("g.region",vect=k_box,quiet=True)
108 | ns_ext = (math.ceil(grass.region()['n']-grass.region()['s']))*10/100
109 | ew_ext = (math.ceil(grass.region()['e']-grass.region()['w']))*10/100
110 | grass.run_command("g.region",n=grass.region()['n']+ns_ext/2,s=grass.region()['s']-ns_ext/2,w=grass.region()['w']-ew_ext/2,e=grass.region()['e']+ew_ext/2,quiet=True)
111 | grass.run_command("v.in.region",output="new_box_%s"%processid,quiet=True)
112 | grass.run_command("v.overlay",ainput=ref,atype="line",binput="new_box_%s"%processid,btype="area",operator="and",output=ref_box,quiet=True)
113 | grass.run_command("g.remove",type="vect", name="new_box_%s"%processid,flags="f",quiet=True)
114 | grass.run_command("g.region",n=N,s=S,e=E,w=W,quiet=True)
115 |
116 | def AddCol(vect,t):
117 | list_c = []
118 | list_col = ((grass.read_command("db.describe",table=vect,flags="c",quiet=True)).split("\n"))[2:-1]
119 | for c in list_col:
120 | list_c.append((c.split(":")[1]).lstrip())
121 | if not "%s"%t in list_c:
122 | grass.run_command("v.db.addcolumn",map=vect,columns="%s double"%t,quiet=True)
123 |
124 | def length(data):
125 | feat_data = int(((grass.read_command("v.info", map=data,flags="t")).split("\n")[2]).split("=")[1])
126 | if feat_data>0:
127 | length_data = grass.read_command("v.to.db",map=data,option="length",flags="p")
128 | s_data=0
129 | l_data = length_data.split("\n")
130 | for item in l_data[1:-1]:
131 | s_data+=float(item.split("|")[1])
132 | else:
133 | s_data=0
134 | return s_data
135 |
136 | def CalcTol(data1,data2,value):
137 | processid = str(time.time()).replace(".","_")
138 | grass.run_command("v.buffer",input=data1,output="data1_buf_"+processid,distance=value,quiet=True)
139 | grass.run_command("v.overlay",ainput=data2,binput="data1_buf_"+processid,atype="line",btype="area",operator="and",output="data2_in_"+processid,quiet=True)
140 | val = length("data2_in_"+processid)
141 | grass.run_command("g.remove",type="vect", pattern=processid,flags="fr",quiet=True)
142 | return val
143 |
144 | def main():
145 | osm = options["osm"]
146 | ref = options["ref"]
147 | grid = options["grid"]
148 | ul_grid = options["ul_grid"]
149 | lr_grid = options["lr_grid"]
150 | box_grid = options["box_grid"]
151 | output = options["output"]
152 | tol_eval = options["tol_eval"]
153 | tol_max = options["tol_max"]
154 | perc = float(options["perc"])
155 |
156 |
157 |
158 | ## Check if input files exist
159 | if not grass.find_file(name=osm,element='vector')['file']:
160 | grass.fatal(_("Vector map <%s> not found") % osm)
161 |
162 | if not grass.find_file(name=ref,element='vector')['file']:
163 | grass.fatal(_("Vector map <%s> not found") % ref)
164 |
165 | if grass.find_file(name=output,element='vector')['file']:
166 | grass.fatal(_("Vector map <%s> already exists") % output)
167 |
168 | if len(grid)>0:
169 | if not grass.find_file(name=grid,element='vector')['file']:
170 | grass.fatal(_("Vector map <%s> not found") % grid)
171 |
172 | # Check length OSM and REF
173 | check_ref = length(ref)
174 | check_osm = length(osm)
175 |
176 | if check_ref == 0:
177 | grass.run_command("g.remove", type="vect", pattern="%s"%processid,flags="fr",quiet=True)
178 | grass.fatal(_("No reference data for comparison"))
179 |
180 | if check_osm == 0:
181 | grass.run_command("g.remove", type="vect", pattern="%s"%processid,flags="fr",quiet=True)
182 | grass.fatal(_("No OSM data for comparison"))
183 |
184 |
185 | ## Check tolerance parameters
186 | if (len(tol_eval)>0 and len(str(tol_max))>0):
187 | grass.fatal("Please specify only one between or parameters")
188 |
189 | if (len(tol_eval)==0 and len(str(tol_max))==0):
190 | grass.fatal("Please specify almost one between or parameters")
191 |
192 |
193 | ## Check grid parameters
194 | if (len(grid)>0 and (len(ul_grid)>0 or len(lr_grid)>0 or len(box_grid)>0 or len(output)>0)):
195 | grass.warning("A vector has been specified. All the others parameters will be ignored")
196 |
197 | if len(grid)==0:
198 | if (len(ul_grid)>0 or len(lr_grid)>0 or len(box_grid)>0) and (len(ul_grid)==0 or len(lr_grid)==0 or len(box_grid)==0 or len(output)==0):
199 | grass.fatal("Please specify all the required parameters for grid generation: ,, and