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