1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "kml/convenience/convenience.h"
27 #include "boost/scoped_ptr.hpp"
28 #include "kml/base/attributes.h"
29 #include "kml/base/date_time.h"
30 #include "kml/base/math_util.h"
31 #include "kml/engine/bbox.h"
32 #include "kml/engine/clone.h"
33 #include "kml/engine/feature_view.h"
34 #include "kml/engine/location_util.h"
35 
36 using kmlbase::Attributes;
37 using kmlbase::DateTime;
38 using kmlbase::Vec3;
39 using kmldom::AbstractViewPtr;
40 using kmldom::CameraPtr;
41 using kmldom::ChangePtr;
42 using kmldom::CoordinatesPtr;
43 using kmldom::DataPtr;
44 using kmldom::ExtendedDataPtr;
45 using kmldom::FeaturePtr;
46 using kmldom::GxAnimatedUpdatePtr;
47 using kmldom::GxFlyToPtr;
48 using kmldom::GxWaitPtr;
49 using kmldom::KmlFactory;
50 using kmldom::LatLonAltBoxPtr;
51 using kmldom::LodPtr;
52 using kmldom::LookAtPtr;
53 using kmldom::OuterBoundaryIsPtr;
54 using kmldom::PlacemarkPtr;
55 using kmldom::PointPtr;
56 using kmldom::PolygonPtr;
57 using kmldom::RegionPtr;
58 using kmldom::TimeStampPtr;
59 using kmldom::UpdatePtr;
60 
61 namespace kmlconvenience {
62 
AddExtendedDataValue(const string & name,const string & value,FeaturePtr feature)63 void AddExtendedDataValue(const string& name, const string& value,
64                           FeaturePtr feature) {
65   if (!feature) {
66     return;
67   }
68   if (!feature->has_extendeddata()) {
69     feature->set_extendeddata(KmlFactory::GetFactory()->CreateExtendedData());
70   }
71   feature->get_extendeddata()->add_data(CreateDataNameValue(name, value));
72 }
73 
CreateAnimatedUpdateChangePoint(const string & target_id,const kmlbase::Vec3 & vec3,double duration)74 kmldom::GxAnimatedUpdatePtr CreateAnimatedUpdateChangePoint(
75     const string& target_id, const kmlbase::Vec3& vec3, double duration) {
76   KmlFactory* factory = KmlFactory::GetFactory();
77   PlacemarkPtr placemark = factory->CreatePlacemark();
78   placemark->set_targetid(target_id);
79   placemark->set_geometry(CreatePointFromVec3(vec3));
80   ChangePtr change = factory->CreateChange();
81   change->add_object(placemark);
82   UpdatePtr update = factory->CreateUpdate();
83   update->add_updateoperation(change);
84   update->set_targethref("");
85   GxAnimatedUpdatePtr animated_update = factory->CreateGxAnimatedUpdate();
86   animated_update->set_update(update);
87   animated_update->set_gx_duration(duration);
88   return animated_update;
89 }
90 
CreateBasicPolygonPlacemark(const kmldom::LinearRingPtr & lr)91 PlacemarkPtr CreateBasicPolygonPlacemark(
92     const kmldom::LinearRingPtr& lr) {
93   KmlFactory* factory = KmlFactory::GetFactory();
94   OuterBoundaryIsPtr obi = factory->CreateOuterBoundaryIs();
95   obi->set_linearring(lr);
96   PolygonPtr poly = factory->CreatePolygon();
97   poly->set_outerboundaryis(obi);
98   PlacemarkPtr placemark = factory->CreatePlacemark();
99   placemark->set_geometry(poly);
100   return placemark;
101 }
102 
CreateCamera(double latitude,double longitude,double altitude,double heading,double tilt,double roll,int altitudemode)103 CameraPtr CreateCamera(double latitude, double longitude, double altitude,
104                        double heading, double tilt, double roll,
105                        int altitudemode) {
106   CameraPtr camera = KmlFactory::GetFactory()->CreateCamera();
107   camera->set_longitude(longitude);
108   camera->set_latitude(latitude);
109   camera->set_altitude(altitude);
110   camera->set_heading(heading);
111   camera->set_tilt(tilt);
112   camera->set_roll(roll);
113   camera->set_altitudemode(altitudemode);
114   return camera;
115 }
116 
CreateCoordinatesCircle(double lat,double lng,double radius,size_t segments)117 CoordinatesPtr CreateCoordinatesCircle(double lat, double lng,
118                                        double radius, size_t segments) {
119   CoordinatesPtr coords = KmlFactory::GetFactory()->CreateCoordinates();
120   for (size_t i = 0; i < segments; ++i) {
121     coords->add_vec3(kmlbase::LatLngOnRadialFromPoint(
122         lat, lng, radius, static_cast<double>(i)));
123   }
124   return coords;
125 }
126 
CreateDataNameValue(const string & name,const string & value)127 DataPtr CreateDataNameValue(const string& name, const string& value) {
128   DataPtr data = KmlFactory::GetFactory()->CreateData();
129   data->set_name(name);
130   data->set_value(value);
131   return data;
132 }
133 
CreateLookAt(double latitude,double longitude,double altitude,double heading,double tilt,double range,int altitudemode)134 LookAtPtr CreateLookAt(double latitude, double longitude, double altitude,
135                        double heading, double tilt, double range,
136                        int altitudemode) {
137   LookAtPtr lookat = KmlFactory::GetFactory()->CreateLookAt();
138   lookat->set_longitude(longitude);
139   lookat->set_latitude(latitude);
140   lookat->set_altitude(altitude);
141   lookat->set_heading(heading);
142   lookat->set_tilt(tilt);
143   lookat->set_range(range);
144   lookat->set_altitudemode(altitudemode);
145   return lookat;
146 }
147 
CreatePointFromLatLonAtts(const char ** atts)148 PointPtr CreatePointFromLatLonAtts(const char** atts) {
149   boost::scoped_ptr<Attributes> attributes(Attributes::Create(atts));
150   if (attributes.get()) {
151     double latitude;
152     double longitude;
153     if (attributes->GetValue("lat", &latitude) &&
154         attributes->GetValue("lon", &longitude)) {
155       return CreatePointLatLon(latitude, longitude);
156     }
157   }
158   return NULL;
159 }
160 
CreatePointFromVec3(const Vec3 & vec)161 PointPtr CreatePointFromVec3(const Vec3& vec) {
162   KmlFactory* factory = KmlFactory::GetFactory();
163   CoordinatesPtr coordinates = factory->CreateCoordinates();
164   if (vec.has_altitude()) {
165     coordinates->add_latlngalt(vec.get_latitude(), vec.get_longitude(),
166                                vec.get_altitude());
167   } else {
168     coordinates->add_latlng(vec.get_latitude(), vec.get_longitude());
169   }
170   PointPtr point = factory->CreatePoint();
171   point->set_coordinates(coordinates);
172   return point;
173 }
174 
CreatePointLatLon(double lat,double lon)175 PointPtr CreatePointLatLon(double lat, double lon) {
176   KmlFactory* factory = KmlFactory::GetFactory();
177   CoordinatesPtr coordinates = factory->CreateCoordinates();
178   coordinates->add_latlng(lat, lon);
179   PointPtr point = factory->CreatePoint();
180   point->set_coordinates(coordinates);
181   return point;
182 }
183 
184 // This is a convenience function to create a Point Placemark.
CreatePointPlacemark(const string & name,double lat,double lon)185 PlacemarkPtr CreatePointPlacemark(const string& name, double lat,
186                                   double lon) {
187   PlacemarkPtr placemark = KmlFactory::GetFactory()->CreatePlacemark();
188   placemark->set_name(name);
189   placemark->set_geometry(CreatePointLatLon(lat, lon));
190   return placemark;
191 }
192 
193 // This creates a Region at the given bounding box with the given Lod range.
CreateRegion2d(double north,double south,double east,double west,double minlodpixels,double maxlodpixels)194 RegionPtr CreateRegion2d(double north, double south, double east, double west,
195                          double minlodpixels, double maxlodpixels) {
196   KmlFactory* factory = KmlFactory::GetFactory();
197   RegionPtr region = factory->CreateRegion();
198   LatLonAltBoxPtr latlonaltbox = factory->CreateLatLonAltBox();
199   latlonaltbox->set_north(north);
200   latlonaltbox->set_south(south);
201   latlonaltbox->set_east(east);
202   latlonaltbox->set_west(west);
203   LodPtr lod = factory->CreateLod();
204   lod->set_minlodpixels(minlodpixels);
205   lod->set_maxlodpixels(maxlodpixels);
206   region->set_latlonaltbox(latlonaltbox);
207   region->set_lod(lod);
208   return region;
209 }
210 
CreateFlyTo(const AbstractViewPtr & abstractview,double duration)211 GxFlyToPtr CreateFlyTo(const AbstractViewPtr& abstractview, double duration) {
212   GxFlyToPtr flyto = KmlFactory::GetFactory()->CreateGxFlyTo();
213   flyto->set_gx_duration(duration);
214   AbstractViewPtr av = kmldom::AsAbstractView(kmlengine::Clone(abstractview));
215   flyto->set_abstractview(av);
216   return flyto;
217 }
218 
CreateFlyToForFeature(const FeaturePtr & feature,double duration)219 GxFlyToPtr CreateFlyToForFeature(const FeaturePtr& feature, double duration) {
220   if (!feature) {
221     return NULL;
222   }
223   if (feature->has_abstractview()) {
224     return CreateFlyTo(feature->get_abstractview(), duration);
225   }
226   LookAtPtr lookat = kmlengine::ComputeFeatureLookAt(feature);
227   if (!lookat) {
228     return NULL;
229   }
230   return CreateFlyTo(lookat, duration);
231 }
232 
CreateWait(double duration)233 GxWaitPtr CreateWait(double duration) {
234   GxWaitPtr wait = KmlFactory::GetFactory()->CreateGxWait();
235   wait->set_gx_duration(duration);
236   return wait;
237 }
238 
GetExtendedDataValue(const FeaturePtr & feature,const string & name,string * value)239 bool GetExtendedDataValue(const FeaturePtr& feature,
240                           const string& name,
241                           string* value) {
242   if (value && feature->has_extendeddata()) {
243     ExtendedDataPtr extendeddata = feature->get_extendeddata();
244     for (size_t i = 0; i < extendeddata->get_data_array_size(); ++i) {
245       DataPtr data = extendeddata->get_data_array_at(i);
246       if (data->has_name() && name == data->get_name()) {
247         *value = data->get_value();
248         return true;
249       }
250     }
251   }
252   return false;
253 }
254 
SetExtendedDataValue(const string & name,const string & value,FeaturePtr feature)255 void SetExtendedDataValue(const string& name, const string& value,
256                           FeaturePtr feature) {
257   if (!feature) {
258     return;
259   }
260   feature->set_extendeddata(KmlFactory::GetFactory()->CreateExtendedData());
261   AddExtendedDataValue(name, value, feature);
262 }
263 
CreatePointPlacemarkWithTimeStamp(const PointPtr & point,const DateTime & date_time,const char * style_id)264 PlacemarkPtr CreatePointPlacemarkWithTimeStamp(const PointPtr& point,
265                                                const DateTime& date_time,
266                                                const char* style_id) {
267   KmlFactory* kml_factory = KmlFactory::GetFactory();
268   PlacemarkPtr placemark = kml_factory->CreatePlacemark();
269   // <name>
270   placemark->set_name(date_time.GetXsdTime());
271   // <styleUrl>
272   placemark->set_styleurl(string("#") + style_id);
273   // <TimeStamp>
274   TimeStampPtr time_stamp = kml_factory->CreateTimeStamp();
275   time_stamp->set_when(date_time.GetXsdDateTime());
276   placemark->set_timeprimitive(time_stamp);
277   // <ExtendedData>
278   AddExtendedDataValue("date", date_time.GetXsdDate(), placemark);
279   AddExtendedDataValue("time", date_time.GetXsdTime(), placemark);
280   // <Point>
281   placemark->set_geometry(point);
282   return placemark;
283 }
284 
SimplifyCoordinates(const CoordinatesPtr & src,CoordinatesPtr dest,double merge_tolerance)285 void SimplifyCoordinates(const CoordinatesPtr& src,
286                          CoordinatesPtr dest, double merge_tolerance) {
287   if (!src || !dest) {
288     return;
289   }
290   // Remember the last coordinate.
291   Vec3 last_vec;
292   for (size_t i = 0; i < src->get_coordinates_array_size(); ++i) {
293     // If this is the first tuple, just append it to the result vec.
294     if (i == 0) {
295       dest->add_vec3(src->get_coordinates_array_at(i));
296       last_vec = src->get_coordinates_array_at(i);
297       continue;
298     }
299     // If the distance between the position of the last point and the current
300     // point is greater than merge_tolerance, do not append it to the vector.
301     if (merge_tolerance > 0.0) {
302       Vec3 this_vec = src->get_coordinates_array_at(i);
303       if (merge_tolerance >= kmlbase::DistanceBetweenPoints3d(
304             last_vec.get_latitude(), last_vec.get_longitude(),
305             last_vec.get_altitude(), this_vec.get_latitude(),
306             this_vec.get_longitude(), this_vec.get_altitude())) {
307         last_vec = src->get_coordinates_array_at(i);
308         continue;
309       }
310     }
311     last_vec = src->get_coordinates_array_at(i);
312     dest->add_vec3(src->get_coordinates_array_at(i));
313   }
314 }
315 
316 }  // end namespace kmlconvenience
317