@@ -125,6 +125,7 @@ static KmlGroundOverlay createGroundOverlay(XmlPullParser parser)
125125 LatLngBounds latLonBox ;
126126 HashMap <String , String > properties = new HashMap <String , String >();
127127 HashMap <String , Double > compassPoints = new HashMap <String , Double >();
128+ ArrayList <LatLng > latLonQuad = null ;
128129
129130 int eventType = parser .getEventType ();
130131 while (!(eventType == END_TAG && parser .getName ().equals ("GroundOverlay" ))) {
@@ -143,16 +144,81 @@ static KmlGroundOverlay createGroundOverlay(XmlPullParser parser)
143144 properties .put (parser .getName (), parser .nextText ());
144145 } else if (parser .getName ().matches (COMPASS_REGEX )) {
145146 compassPoints .put (parser .getName (), Double .parseDouble (parser .nextText ()));
147+ } else if (parser .getName ().equals ("LatLonQuad" )) {
148+ latLonQuad = getLatLonQuad (parser );
146149 }
147150 }
148151 eventType = parser .next ();
149152 }
153+
154+ if (compassPoints .isEmpty () && latLonQuad != null && latLonQuad .size () >= 4 ) {
155+ //read coordinates from quad
156+ LatLng sw = latLonQuad .get (0 );
157+ LatLng se = latLonQuad .get (1 );
158+ LatLng ne = latLonQuad .get (2 );
159+ LatLng nw = latLonQuad .get (3 );
160+
161+ //calculate rotation from coordinates
162+ double nRot = 90 - bearing (nw , ne );
163+ double sRot = 270 - bearing (se , sw );
164+
165+ rotation = -(float )((nRot + sRot ) / 2.0 );
166+
167+ //this is an approximation that rectifies the quad in order to make it rectangular
168+ double n = (ne .latitude + nw .latitude ) / 2.0 ;
169+ double s = (se .latitude + sw .latitude ) / 2.0 ;
170+ double e = (ne .longitude + se .longitude ) / 2.0 ;
171+ double w = (nw .longitude + sw .longitude ) / 2.0 ;
172+
173+ compassPoints .put ("north" , n );
174+ compassPoints .put ("south" , s );
175+ compassPoints .put ("east" , e );
176+ compassPoints .put ("west" , w );
177+ }
150178 latLonBox = createLatLngBounds (compassPoints .get ("north" ), compassPoints .get ("south" ),
151179 compassPoints .get ("east" ), compassPoints .get ("west" ));
152180 return new KmlGroundOverlay (imageUrl , latLonBox , drawOrder , visibility , properties ,
153181 rotation );
154182 }
155183
184+ private static ArrayList <LatLng > getLatLonQuad (XmlPullParser parser )
185+ throws XmlPullParserException , IOException {
186+ ArrayList <LatLng > latLonQuad = null ;
187+ int eventType = parser .getEventType ();
188+ while (!(eventType == END_TAG && parser .getName ().equals ("LatLonQuad" ))) {
189+ if (eventType == START_TAG ) {
190+ if (parser .getName ().equals ("coordinates" )) {
191+ latLonQuad = convertToLatLngArray (parser .nextText ());
192+ }
193+ }
194+ eventType = parser .next ();
195+ }
196+ return latLonQuad ;
197+ }
198+
199+ private static double bearing (LatLng from , LatLng to ) {
200+ // formula: θ = atan2(sin(Δlong).cos(lat2), cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
201+ // source: http://www.movable-type.co.uk/scripts/latlong.html
202+
203+ double lat1 = Math .toRadians (from .latitude );
204+ double lon1 = Math .toRadians (from .longitude );
205+ double lat2 = Math .toRadians (to .latitude );
206+ double lon2 = Math .toRadians (to .longitude );
207+ double dLon = lon2 - lon1 ;
208+ double y = Math .sin (dLon ) * Math .cos (lat2 );
209+ double x = Math .cos (lat1 ) * Math .sin (lat2 ) - Math .sin (lat1 ) * Math .cos (lat2 ) * Math .cos (dLon );
210+
211+ double res = Math .toDegrees (Math .atan2 (y , x ));
212+
213+ // Since atan2 returns values in the range [-M_PI, +M_PI] (that is, [-180°, +180°]),
214+ // we need to normalise the result in the range [0°, 360°]
215+ if (res < 0 ) {
216+ res += 360 ;
217+ }
218+
219+ return res ;
220+ }
221+
156222 private static float getRotation (XmlPullParser parser )
157223 throws IOException , XmlPullParserException {
158224 return -Float .parseFloat (parser .nextText ());
0 commit comments