View Javadoc
1   /*******************************************************************************
2    *   Gisgraphy Project 
3    * 
4    *   This library is free software; you can redistribute it and/or
5    *   modify it under the terms of the GNU Lesser General Public
6    *   License as published by the Free Software Foundation; either
7    *   version 2.1 of the License, or (at your option) any later version.
8    * 
9    *   This library is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   *   Lesser General Public License for more details.
13   * 
14   *   You should have received a copy of the GNU Lesser General Public
15   *   License along with this library; if not, write to the Free Software
16   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
17   * 
18   *  Copyright 2008  Gisgraphy project 
19   *  David Masclet <davidmasclet@gisgraphy.com>
20   *  
21   *  
22   *******************************************************************************/
23  package com.gisgraphy.importer;
24  
25  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_AND_ADM1CODE;
26  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_AND_ADM2CODE;
27  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_AND_ADM3CODE;
28  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_AND_ADM4CODE;
29  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_AND_ADM5CODE;
30  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_OR_ADM1CODE;
31  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_OR_ADM2CODE;
32  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_OR_ADM3CODE;
33  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_OR_ADM4CODE;
34  import static com.gisgraphy.importer.MunicipalityDetector.MunicipalityDetectionStrategy.POPULATION_OR_ADM5CODE;
35  
36  import java.util.HashMap;
37  import java.util.Map;
38  
39  import org.springframework.stereotype.Service;
40  
41  import com.gisgraphy.domain.geoloc.entity.GisFeature;
42  import com.gisgraphy.domain.valueobject.GISSource;
43  
44  /**
45   * @author david masclet
46   * geonames classify features with some code. there is no real definition of City. city are populated place
47   * without any distinction. this class try to detect if the place is a city. to do this we search for population administrative division code (one or the other or both
48   * and apply a strategy depends on country. for each country we have search for the number of city and search what is the best fields to look to see if it is a city.
49   * e.g : for France there is about 36000 city. in geonames there is about 58000 place. if we look at the adm4 code and the population (both) we identify 36875 city.
50   * <br/>
51   * it is not deterministic but probabilistic approach.if you got better idea to identify city, please let us know. This can seems tricky but this works well and improve geocoding 
52   * when we fill the is_in fields,we have a city and not a quater)
53   *
54   *this code is for the moment replace by the osm  conditionsthis seems to be more reliable, but we
55   *keep this code for some country specificities based on user feedbacks
56   */
57  @Service
58  public class MunicipalityDetector implements IMunicipalityDetector {
59  	public enum MunicipalityOSMDetectionStrategy{
60  		ALL,
61  		OSM,
62  		R,//R and W
63  		R_AND_N_CITY_VILLAGE_TOWN,// R and W
64  		N,
65  		N_CITY_VILLAGE_TOWN,
66  		N_CITY_TOWN
67  	}
68  	
69  	public final static Map<String, MunicipalityOSMDetectionStrategy> countrycodeToCityOSMDetectionStrategy = new HashMap<String, MunicipalityDetector.MunicipalityOSMDetectionStrategy>(){
70  		{
71  			put("IT",MunicipalityOSMDetectionStrategy.R);
72  			put("DE",MunicipalityOSMDetectionStrategy.R);
73  			put("CN",MunicipalityOSMDetectionStrategy.OSM);
74  			put("FR",MunicipalityOSMDetectionStrategy.R);
75  			put("IN",MunicipalityOSMDetectionStrategy.ALL);
76  			put("ID",MunicipalityOSMDetectionStrategy.N);
77  			put("BR",MunicipalityOSMDetectionStrategy.R);
78  			put("US",MunicipalityOSMDetectionStrategy.R);
79  			put("LU",MunicipalityOSMDetectionStrategy.R);
80  			put("AR",MunicipalityOSMDetectionStrategy.N);
81  			put("SK",MunicipalityOSMDetectionStrategy.R_AND_N_CITY_VILLAGE_TOWN);
82  			put("BE",MunicipalityOSMDetectionStrategy.OSM);
83  			put("NG",MunicipalityOSMDetectionStrategy.ALL);
84  			put("RU",MunicipalityOSMDetectionStrategy.ALL);
85  			put("JP",MunicipalityOSMDetectionStrategy.R);
86  			put("FI",MunicipalityOSMDetectionStrategy.OSM);
87  			put("CA",MunicipalityOSMDetectionStrategy.ALL);
88  			put("MX",MunicipalityOSMDetectionStrategy.OSM);
89  			put("EG",MunicipalityOSMDetectionStrategy.ALL);
90  			put("TR",MunicipalityOSMDetectionStrategy.N_CITY_VILLAGE_TOWN);
91  			put("GB",MunicipalityOSMDetectionStrategy.ALL);
92  			put("KR",MunicipalityOSMDetectionStrategy.N_CITY_TOWN);
93  			put("SP",MunicipalityOSMDetectionStrategy.R);
94  			put("UA",MunicipalityOSMDetectionStrategy.OSM);
95  			put("CO",MunicipalityOSMDetectionStrategy.R);
96  			put("PL",MunicipalityOSMDetectionStrategy.OSM);
97  			put("DZ",MunicipalityOSMDetectionStrategy.ALL);
98  			put("MA",MunicipalityOSMDetectionStrategy.R);
99  			put("PE",MunicipalityOSMDetectionStrategy.R);
100 			put("IQ",MunicipalityOSMDetectionStrategy.ALL);
101 			put("TW",MunicipalityOSMDetectionStrategy.N_CITY_TOWN);
102 			put("SY",MunicipalityOSMDetectionStrategy.R);
103 			put("RO",MunicipalityOSMDetectionStrategy.OSM);
104 			put("AT",MunicipalityOSMDetectionStrategy.R);
105 			put("AU",MunicipalityOSMDetectionStrategy.ALL);
106 			put("CL",MunicipalityOSMDetectionStrategy.ALL);
107 			put("NL",MunicipalityOSMDetectionStrategy.R);
108 			put("EC",MunicipalityOSMDetectionStrategy.R);
109 			put("PT",MunicipalityOSMDetectionStrategy.OSM);
110 			put("CZ",MunicipalityOSMDetectionStrategy.R);
111 			put("BO",MunicipalityOSMDetectionStrategy.N);
112 			put("HU",MunicipalityOSMDetectionStrategy.R);
113 			put("BY",MunicipalityOSMDetectionStrategy.ALL);
114 			put("SE",MunicipalityOSMDetectionStrategy.R);
115 			put("CH",MunicipalityOSMDetectionStrategy.R);
116 			put("IL",MunicipalityOSMDetectionStrategy.ALL);
117 			put("BG",MunicipalityOSMDetectionStrategy.N);
118 			put("PY",MunicipalityOSMDetectionStrategy.N);
119 			put("DK",MunicipalityOSMDetectionStrategy.OSM);
120 			put("NO",MunicipalityOSMDetectionStrategy.OSM);
121 			put("HR",MunicipalityOSMDetectionStrategy.OSM);
122 			put("NZ",MunicipalityOSMDetectionStrategy.N);
123 			put("LT",MunicipalityOSMDetectionStrategy.ALL);
124 			put("AL",MunicipalityOSMDetectionStrategy.N);
125 			put("LV",MunicipalityOSMDetectionStrategy.ALL);
126 			put("SI",MunicipalityOSMDetectionStrategy.R);
127 			put("EE",MunicipalityOSMDetectionStrategy.ALL);
128 			put("IS",MunicipalityOSMDetectionStrategy.ALL);
129 			put("NC",MunicipalityOSMDetectionStrategy.ALL);
130 			
131 		}
132 	};
133 	
134 	
135 
136 	public boolean isMunicipality(String countryCode,String placetype,String nodeType,GISSource source){
137 		if (countryCode==null || "".equals(countryCode)){
138 			return true;
139 		}
140 		MunicipalityOSMDetectionStrategy strategy = countrycodeToCityOSMDetectionStrategy.get(countryCode.toUpperCase());
141 		if (strategy == null ||	strategy == MunicipalityOSMDetectionStrategy.ALL){
142 			return true;
143 		}
144 		if (source == GISSource.OSM){
145 			if (strategy == MunicipalityOSMDetectionStrategy.OSM){
146 				return true;
147 			}
148 			if ("R".equalsIgnoreCase(nodeType)|| "W".equalsIgnoreCase(nodeType)){
149 				if (strategy == MunicipalityOSMDetectionStrategy.R || strategy == MunicipalityOSMDetectionStrategy.R_AND_N_CITY_VILLAGE_TOWN){
150 					return true;
151 				}
152 			}
153 			else if ("N".equalsIgnoreCase(nodeType) ){
154 				if ( strategy == MunicipalityOSMDetectionStrategy.N){
155 					return true;
156 				}
157 				if ( strategy == MunicipalityOSMDetectionStrategy.N_CITY_VILLAGE_TOWN || strategy == MunicipalityOSMDetectionStrategy.R_AND_N_CITY_VILLAGE_TOWN){
158 					if ("city".equalsIgnoreCase(placetype) || "village".equalsIgnoreCase(placetype) || "town".equalsIgnoreCase(placetype)){
159 						return true;
160 					}
161 				}
162 				if (strategy == MunicipalityOSMDetectionStrategy.N_CITY_TOWN){
163 					if ("city".equalsIgnoreCase(placetype) || "town".equalsIgnoreCase(placetype)){
164 						return true;
165 					}
166 
167 				}
168 
169 			}
170 
171 		}
172 		return false;
173 	}
174 
175 	/*---------------------------------------------GEONAMES ALGORYTHME--(Obsolete should be replaced by OSM ONE--------------------------*/
176 
177 	public final static Map<String, MunicipalityDetectionStrategy> countrycodeToCityDetectionStrategy = new HashMap<String, MunicipalityDetector.MunicipalityDetectionStrategy>(){
178 		{
179 			put("IT",MunicipalityDetectionStrategy.POPULATION);
180 			put("DE",MunicipalityDetectionStrategy.ADM2CODE);
181 			put("FR",MunicipalityDetectionStrategy.POPULATION_OR_ADM4CODE);
182 			put("US",MunicipalityDetectionStrategy.POPULATION);
183 			put("AR",MunicipalityDetectionStrategy.POPULATION);
184 			put("BE",MunicipalityDetectionStrategy.POPULATION);
185 			put("VN",MunicipalityDetectionStrategy.POPULATION_OR_ADM1CODE);
186 			put("UK",MunicipalityDetectionStrategy.POPULATION);
187 			put("TW",MunicipalityDetectionStrategy.POPULATION_OR_ADM2CODE);//maybe we should take all
188 			put("RO",MunicipalityDetectionStrategy.POPULATION);
189 			put("AU",MunicipalityDetectionStrategy.POPULATION);
190 			/*put("",cityDetectionStrategy.POPULATION);
191 			put("",cityDetectionStrategy.POPULATION);
192 			put("",cityDetectionStrategy.POPULATION);
193 			put("",cityDetectionStrategy.POPULATION);
194 			put("",cityDetectionStrategy.POPULATION);
195 			put("",cityDetectionStrategy.POPULATION);*/
196 		}
197 	};
198 	
199 	
200 	/* (non-Javadoc)
201 	 * @see com.gisgraphy.importer.IMunicipalityDetector#isMunicipality(java.lang.String, com.gisgraphy.domain.geoloc.entity.GisFeature)
202 	 */
203 	public boolean isMunicipalityByGisFeature(String countrycode,GisFeature gisFeature ){
204 		if (countrycode==null || "".equals(countrycode) || gisFeature ==null){
205 			return false;
206 		}
207 		MunicipalityDetectionStrategy strategy = countrycodeToCityDetectionStrategy.get(countrycode.toUpperCase());
208 		if (strategy == null){
209 			return false;
210 		}
211 		else {
212 			return isMunicipality_internal(strategy, gisFeature.getPopulation(), gisFeature.getAdm1Code(), gisFeature.getAdm2Code(), gisFeature.getAdm3Code(), gisFeature.getAdm4Code(), gisFeature.getAdm5Code());
213 		}
214 	}
215 	
216 	
217 	public enum MunicipalityDetectionStrategy{
218 		//0
219 		NO_STRATEGY,
220 		//1
221 		POPULATION,
222 		//2
223 		ADM1CODE,
224 		ADM2CODE,
225 		ADM3CODE,
226 		ADM4CODE,
227 		ADM5CODE,
228 		//3
229 		POPULATION_OR_ADM1CODE,
230 		POPULATION_OR_ADM2CODE,
231 		POPULATION_OR_ADM3CODE,
232 		POPULATION_OR_ADM4CODE,
233 		POPULATION_OR_ADM5CODE,
234 		//4
235 		POPULATION_AND_ADM1CODE,
236 		POPULATION_AND_ADM2CODE,
237 		POPULATION_AND_ADM3CODE,
238 		POPULATION_AND_ADM4CODE,
239 		POPULATION_AND_ADM5CODE,
240 		
241 	}
242 
243 	protected boolean isMunicipality_internal(MunicipalityDetectionStrategy strategy, Integer population, String adm1code, String adm2code, String adm3code, String adm4code, String adm5code) {
244 		if (population != null && population!=0){//population is not null
245 			if (strategy==MunicipalityDetectionStrategy.POPULATION || strategy ==POPULATION_OR_ADM1CODE ||  strategy == POPULATION_OR_ADM2CODE || strategy == POPULATION_OR_ADM3CODE || strategy == POPULATION_OR_ADM4CODE || strategy == POPULATION_OR_ADM5CODE){
246 				return true;
247 			} else if ((strategy== POPULATION_AND_ADM1CODE || strategy== MunicipalityDetectionStrategy.ADM1CODE ) && !isNullOrEmpty(adm1code)){
248 				return true;
249 			}
250 			else if ((strategy== POPULATION_AND_ADM2CODE || strategy== MunicipalityDetectionStrategy.ADM2CODE ) && !isNullOrEmpty(adm2code)){
251 				return true;
252 			}
253 			else if ((strategy== POPULATION_AND_ADM3CODE || strategy== MunicipalityDetectionStrategy.ADM3CODE ) && !isNullOrEmpty(adm3code)){
254 				return true;
255 			}
256 			else if ((strategy== POPULATION_AND_ADM4CODE || strategy== MunicipalityDetectionStrategy.ADM4CODE ) && !isNullOrEmpty(adm4code)){
257 				return true;
258 			}
259 			else if ((strategy== POPULATION_AND_ADM5CODE || strategy== MunicipalityDetectionStrategy.ADM5CODE ) && !isNullOrEmpty(adm5code)){
260 				return true;
261 			}
262 		} else {//population is null 
263 			if (strategy==POPULATION_AND_ADM1CODE || strategy ==POPULATION_AND_ADM2CODE || strategy== POPULATION_AND_ADM3CODE ||strategy==POPULATION_AND_ADM4CODE || strategy ==POPULATION_AND_ADM5CODE){
264 				return false;
265 			} else if ((strategy== POPULATION_OR_ADM1CODE || strategy== MunicipalityDetectionStrategy.ADM1CODE )&& !isNullOrEmpty(adm1code)){
266 				return true;
267 			}
268 			else if ((strategy== POPULATION_OR_ADM2CODE || strategy== MunicipalityDetectionStrategy.ADM2CODE ) && !isNullOrEmpty(adm2code)){
269 				return true;
270 			}
271 			else if ((strategy== POPULATION_OR_ADM3CODE || strategy== MunicipalityDetectionStrategy.ADM3CODE ) && !isNullOrEmpty(adm3code)){
272 				return true;
273 			}
274 			else if ((strategy== POPULATION_OR_ADM4CODE || strategy== MunicipalityDetectionStrategy.ADM4CODE )&& !isNullOrEmpty(adm4code)){
275 				return true;
276 			}
277 			else if ((strategy== POPULATION_OR_ADM5CODE|| strategy== MunicipalityDetectionStrategy.ADM5CODE ) && !isNullOrEmpty(adm5code)){
278 				return true;
279 			}
280 		}
281 		return false;
282 	}
283 	
284 	private boolean isNullOrEmpty(String str){
285 		return str==null || "".equals(str);
286 	}
287 
288 	
289 }