PageRenderTime 154ms CodeModel.GetById 51ms RepoModel.GetById 0ms app.codeStats 0ms

/library/src/com/google/maps/android/kml/KmlFeatureParser.java

https://gitlab.com/spaceotechnologies/Google_Map_Clustering
Java | 313 lines | 211 code | 28 blank | 74 comment | 90 complexity | 08f7fabd3bab66b2beaeb0b30ccde90f MD5 | raw file
  1. package com.google.maps.android.kml;
  2. import com.google.android.gms.maps.model.LatLng;
  3. import com.google.android.gms.maps.model.LatLngBounds;
  4. import org.xmlpull.v1.XmlPullParser;
  5. import org.xmlpull.v1.XmlPullParserException;
  6. import java.io.IOException;
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import static org.xmlpull.v1.XmlPullParser.END_TAG;
  10. import static org.xmlpull.v1.XmlPullParser.START_TAG;
  11. /**
  12. * Parses the feature of a given KML file into a KmlPlacemark or KmlGroundOverlay object
  13. */
  14. /* package */ class KmlFeatureParser {
  15. private final static String GEOMETRY_REGEX = "Point|LineString|Polygon|MultiGeometry";
  16. private final static int LONGITUDE_INDEX = 0;
  17. private final static int LATITUDE_INDEX = 1;
  18. private final static String PROPERTY_REGEX = "name|description|drawOrder|visibility|open|address|phoneNumber";
  19. private final static String BOUNDARY_REGEX = "outerBoundaryIs|innerBoundaryIs";
  20. private final static String EXTENDED_DATA = "ExtendedData";
  21. private final static String STYLE_URL_TAG = "styleUrl";
  22. private final static String STYLE_TAG = "Style";
  23. private final static String COMPASS_REGEX = "north|south|east|west";
  24. /**
  25. * Creates a new Placemark object (created if a Placemark start tag is read by the
  26. * XmlPullParser and if a Geometry tag is contained within the Placemark tag)
  27. * and assigns specific elements read from the parser to the Placemark.
  28. */
  29. /* package */
  30. static KmlPlacemark createPlacemark(XmlPullParser parser)
  31. throws IOException, XmlPullParserException {
  32. String styleId = null;
  33. KmlStyle inlineStyle = null;
  34. HashMap<String, String> properties = new HashMap<String, String>();
  35. KmlGeometry geometry = null;
  36. int eventType = parser.getEventType();
  37. while (!(eventType == END_TAG && parser.getName().equals("Placemark"))) {
  38. if (eventType == START_TAG) {
  39. if (parser.getName().equals(STYLE_URL_TAG)) {
  40. styleId = parser.nextText();
  41. } else if (parser.getName().matches(GEOMETRY_REGEX)) {
  42. geometry = createGeometry(parser, parser.getName());
  43. } else if (parser.getName().matches(PROPERTY_REGEX)) {
  44. properties.put(parser.getName(), parser.nextText());
  45. } else if (parser.getName().equals(EXTENDED_DATA)) {
  46. properties.putAll(setExtendedDataProperties(parser));
  47. } else if (parser.getName().equals(STYLE_TAG)) {
  48. inlineStyle = KmlStyleParser.createStyle(parser);
  49. }
  50. }
  51. eventType = parser.next();
  52. }
  53. return new KmlPlacemark(geometry, styleId, inlineStyle, properties);
  54. }
  55. /**
  56. * Creates a new GroundOverlay object (created if a GroundOverlay tag is read by the
  57. * XmlPullParser) and assigns specific elements read from the parser to the GroundOverlay
  58. */
  59. /* package */
  60. static KmlGroundOverlay createGroundOverlay(XmlPullParser parser)
  61. throws IOException, XmlPullParserException {
  62. float drawOrder = 0.0f;
  63. float rotation = 0.0f;
  64. int visibility = 1;
  65. String imageUrl = null;
  66. LatLngBounds latLonBox;
  67. HashMap<String, String> properties = new HashMap<String, String>();
  68. HashMap<String, Double> compassPoints = new HashMap<String, Double>();
  69. int eventType = parser.getEventType();
  70. while (!(eventType == END_TAG && parser.getName().equals("GroundOverlay"))) {
  71. if (eventType == START_TAG) {
  72. if (parser.getName().equals("Icon")) {
  73. imageUrl = getImageUrl(parser);
  74. } else if (parser.getName().equals("drawOrder")) {
  75. drawOrder = Float.parseFloat(parser.nextText());
  76. } else if (parser.getName().equals("visibility")) {
  77. visibility = Integer.parseInt(parser.nextText());
  78. } else if (parser.getName().equals("ExtendedData")) {
  79. properties.putAll(setExtendedDataProperties(parser));
  80. } else if (parser.getName().equals("rotation")) {
  81. rotation = getRotation(parser);
  82. } else if (parser.getName().matches(PROPERTY_REGEX) || parser.getName().equals("color")) {
  83. properties.put(parser.getName(), parser.nextText());
  84. } else if (parser.getName().matches(COMPASS_REGEX)) {
  85. compassPoints.put(parser.getName(), Double.parseDouble(parser.nextText()));
  86. }
  87. }
  88. eventType = parser.next();
  89. }
  90. latLonBox = createLatLngBounds(compassPoints.get("north"), compassPoints.get("south"),
  91. compassPoints.get("east"), compassPoints.get("west"));
  92. return new KmlGroundOverlay(imageUrl, latLonBox, drawOrder, visibility, properties,
  93. rotation);
  94. }
  95. private static float getRotation(XmlPullParser parser)
  96. throws IOException, XmlPullParserException {
  97. return -Float.parseFloat(parser.nextText());
  98. }
  99. /**
  100. * Retrieves a url from the "href" tag nested within an "Icon" tag, read by
  101. * the XmlPullParser.
  102. *
  103. * @return An image url
  104. */
  105. private static String getImageUrl(XmlPullParser parser)
  106. throws IOException, XmlPullParserException {
  107. int eventType = parser.getEventType();
  108. while (!(eventType == END_TAG && parser.getName().equals("Icon"))) {
  109. if (eventType == START_TAG && parser.getName().equals("href")) {
  110. return parser.nextText();
  111. }
  112. eventType = parser.next();
  113. }
  114. return null;
  115. }
  116. /**
  117. * Creates a new KmlGeometry object (Created if "Point", "LineString", "Polygon" or
  118. * "MultiGeometry" tag is detected by the XmlPullParser)
  119. *
  120. * @param geometryType Type of geometry object to create
  121. */
  122. private static KmlGeometry createGeometry(XmlPullParser parser, String geometryType)
  123. throws IOException, XmlPullParserException {
  124. int eventType = parser.getEventType();
  125. while (!(eventType == END_TAG && parser.getName().equals(geometryType))) {
  126. if (eventType == START_TAG) {
  127. if (parser.getName().equals("Point")) {
  128. return createPoint(parser);
  129. } else if (parser.getName().equals("LineString")) {
  130. return createLineString(parser);
  131. } else if (parser.getName().equals("Polygon")) {
  132. return createPolygon(parser);
  133. } else if (parser.getName().equals("MultiGeometry")) {
  134. return createMultiGeometry(parser);
  135. }
  136. }
  137. eventType = parser.next();
  138. }
  139. return null;
  140. }
  141. /**
  142. * Adds untyped name value pairs parsed from the ExtendedData
  143. */
  144. private static HashMap<String, String> setExtendedDataProperties(XmlPullParser parser)
  145. throws XmlPullParserException, IOException {
  146. HashMap<String, String> properties = new HashMap<String, String>();
  147. String propertyKey = null;
  148. int eventType = parser.getEventType();
  149. while (!(eventType == END_TAG && parser.getName().equals(EXTENDED_DATA))) {
  150. if (eventType == START_TAG) {
  151. if (parser.getName().equals("Data")) {
  152. propertyKey = parser.getAttributeValue(null, "name");
  153. } else if (parser.getName().equals("value") && propertyKey != null) {
  154. properties.put(propertyKey, parser.nextText());
  155. propertyKey = null;
  156. }
  157. }
  158. eventType = parser.next();
  159. }
  160. return properties;
  161. }
  162. /**
  163. * Creates a new KmlPoint object
  164. *
  165. * @return KmlPoint object
  166. */
  167. private static KmlPoint createPoint(XmlPullParser parser)
  168. throws XmlPullParserException, IOException {
  169. LatLng coordinate = null;
  170. int eventType = parser.getEventType();
  171. while (!(eventType == END_TAG && parser.getName().equals("Point"))) {
  172. if (eventType == START_TAG && parser.getName().equals("coordinates")) {
  173. coordinate = convertToLatLng(parser.nextText());
  174. }
  175. eventType = parser.next();
  176. }
  177. return new KmlPoint(coordinate);
  178. }
  179. /**
  180. * Creates a new KmlLineString object
  181. *
  182. * @return KmlLineString object
  183. */
  184. private static KmlLineString createLineString(XmlPullParser parser)
  185. throws XmlPullParserException, IOException {
  186. ArrayList<LatLng> coordinates = new ArrayList<LatLng>();
  187. int eventType = parser.getEventType();
  188. while (!(eventType == END_TAG && parser.getName().equals("LineString"))) {
  189. if (eventType == START_TAG && parser.getName().equals("coordinates")) {
  190. coordinates = convertToLatLngArray(parser.nextText());
  191. }
  192. eventType = parser.next();
  193. }
  194. return new KmlLineString(coordinates);
  195. }
  196. /**
  197. * Creates a new KmlPolygon object. Parses only one outer boundary and no or many inner
  198. * boundaries containing the coordinates.
  199. *
  200. * @return KmlPolygon object
  201. */
  202. private static KmlPolygon createPolygon(XmlPullParser parser)
  203. throws XmlPullParserException, IOException {
  204. // Indicates if an outer boundary needs to be defined
  205. Boolean isOuterBoundary = false;
  206. ArrayList<LatLng> outerBoundary = new ArrayList<LatLng>();
  207. ArrayList<ArrayList<LatLng>> innerBoundaries = new ArrayList<ArrayList<LatLng>>();
  208. int eventType = parser.getEventType();
  209. while (!(eventType == END_TAG && parser.getName().equals("Polygon"))) {
  210. if (eventType == START_TAG) {
  211. if (parser.getName().matches(BOUNDARY_REGEX)) {
  212. isOuterBoundary = parser.getName().equals("outerBoundaryIs");
  213. } else if (parser.getName().equals("coordinates")) {
  214. if (isOuterBoundary) {
  215. outerBoundary = convertToLatLngArray(parser.nextText());
  216. } else {
  217. innerBoundaries.add(convertToLatLngArray(parser.nextText()));
  218. }
  219. }
  220. }
  221. eventType = parser.next();
  222. }
  223. return new KmlPolygon(outerBoundary, innerBoundaries);
  224. }
  225. /**
  226. * Creates a new KmlMultiGeometry object
  227. *
  228. * @return KmlMultiGeometry object
  229. */
  230. private static KmlMultiGeometry createMultiGeometry(XmlPullParser parser)
  231. throws XmlPullParserException, IOException {
  232. ArrayList<KmlGeometry> geometries = new ArrayList<KmlGeometry>();
  233. // Get next otherwise have an infinite loop
  234. int eventType = parser.next();
  235. while (!(eventType == END_TAG && parser.getName().equals("MultiGeometry"))) {
  236. if (eventType == START_TAG && parser.getName().matches(GEOMETRY_REGEX)) {
  237. geometries.add(createGeometry(parser, parser.getName()));
  238. }
  239. eventType = parser.next();
  240. }
  241. return new KmlMultiGeometry(geometries);
  242. }
  243. /**
  244. * Convert a string of coordinates into an array of LatLngs
  245. *
  246. * @param coordinatesString coordinates string to convert from
  247. * @return array of LatLng objects created from the given coordinate string array
  248. */
  249. private static ArrayList<LatLng> convertToLatLngArray(String coordinatesString) {
  250. ArrayList<LatLng> coordinatesArray = new ArrayList<LatLng>();
  251. // Need to trim to avoid whitespace around the coordinates such as tabs
  252. String[] coordinates = coordinatesString.trim().split("(\\s+)");
  253. for (String coordinate : coordinates) {
  254. coordinatesArray.add(convertToLatLng(coordinate));
  255. }
  256. return coordinatesArray;
  257. }
  258. /**
  259. * Convert a string coordinate from a string into a LatLng object
  260. *
  261. * @param coordinateString coordinate string to convert from
  262. * @return LatLng object created from given coordinate string
  263. */
  264. private static LatLng convertToLatLng(String coordinateString) {
  265. // Lat and Lng are separated by a ,
  266. String[] coordinate = coordinateString.split(",");
  267. Double lat = Double.parseDouble(coordinate[LATITUDE_INDEX]);
  268. Double lon = Double.parseDouble(coordinate[LONGITUDE_INDEX]);
  269. return new LatLng(lat, lon);
  270. }
  271. /**
  272. * Given a set of four latLng coordinates, creates a LatLng Bound
  273. *
  274. * @param north North coordinate of the bounding box
  275. * @param south South coordinate of the bounding box
  276. * @param east East coordinate of the bounding box
  277. * @param west West coordinate of the bounding box
  278. */
  279. private static LatLngBounds createLatLngBounds(Double north, Double south, Double east,
  280. Double west) {
  281. LatLng southWest = new LatLng(south, west);
  282. LatLng northEast = new LatLng(north, east);
  283. return new LatLngBounds(southWest, northEast);
  284. }
  285. }