1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 :
29 : #include <ogr_featurestyle.h>
30 :
31 : #include <kml/dom.h>
32 : #include <kml/engine.h>
33 : #include <kml/base/color32.h>
34 :
35 : using kmldom::KmlFactory;;
36 : using kmldom::ElementPtr;
37 : using kmldom::ObjectPtr;
38 : using kmldom::FeaturePtr;
39 : using kmldom::StylePtr;
40 : using kmldom::StyleMapPtr;
41 : using kmldom::STYLESTATE_NORMAL;
42 : using kmldom::STYLESTATE_HIGHLIGHT;
43 : using kmldom::StyleSelectorPtr;
44 : using kmldom::LineStylePtr;
45 : using kmldom::PolyStylePtr;
46 : using kmldom::IconStylePtr;
47 : using kmldom::IconStyleIconPtr;
48 : using kmldom::LabelStylePtr;
49 : using kmldom::HotSpotPtr;
50 : using kmlbase::Color32;
51 : using kmldom::PairPtr;
52 : using kmldom::KmlPtr;
53 :
54 : #include "ogrlibkmlstyle.h"
55 :
56 : /******************************************************************************
57 : generic function to parse a stylestring and add to a kml style
58 :
59 : args:
60 : pszStyleString the stylestring to parse
61 : poKmlStyle the kml style to add to
62 : poKmlFactory the kml dom factory
63 :
64 : returns:
65 : nothing
66 :
67 : ******************************************************************************/
68 :
69 0 : void addstylestring2kml (
70 : const char *pszStyleString,
71 : StylePtr poKmlStyle,
72 : KmlFactory * poKmlFactory,
73 : PlacemarkPtr poKmlPlacemark,
74 : OGRFeature * poOgrFeat )
75 : {
76 :
77 0 : LineStylePtr poKmlLineStyle = NULL;
78 0 : PolyStylePtr poKmlPolyStyle = NULL;
79 0 : IconStylePtr poKmlIconStyle = NULL;
80 0 : LabelStylePtr poKmlLabelStyle = NULL;
81 :
82 : /***** just bail now if stylestring is empty *****/
83 :
84 0 : if ( !pszStyleString || !*pszStyleString ) {
85 : return;
86 : }
87 :
88 : /***** create and init a style mamager with the style string *****/
89 :
90 0 : OGRStyleMgr *poOgrSM = new OGRStyleMgr;
91 :
92 0 : poOgrSM->InitStyleString ( pszStyleString );
93 :
94 : /***** loop though the style parts *****/
95 :
96 : int i;
97 :
98 0 : for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
99 0 : OGRStyleTool *poOgrST = poOgrSM->GetPart ( i, NULL );
100 :
101 0 : if ( !poOgrST ) {
102 0 : continue;
103 : }
104 :
105 0 : switch ( poOgrST->GetType ( ) ) {
106 : case OGRSTCPen:
107 : {
108 : GBool nullcheck;
109 :
110 0 : poKmlLineStyle = poKmlFactory->CreateLineStyle ( );
111 :
112 0 : OGRStylePen *poStylePen = ( OGRStylePen * ) poOgrST;
113 :
114 : /***** pen color *****/
115 :
116 : int nR,
117 : nG,
118 : nB,
119 : nA;
120 :
121 0 : const char *pszcolor = poStylePen->Color ( nullcheck );
122 :
123 0 : if ( !nullcheck
124 : && poStylePen->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
125 0 : poKmlLineStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
126 : }
127 0 : double dfWidth = poStylePen->Width ( nullcheck );
128 :
129 0 : if ( nullcheck )
130 0 : dfWidth = 1.0;
131 :
132 0 : poKmlLineStyle->set_width ( dfWidth );
133 :
134 0 : break;
135 : }
136 : case OGRSTCBrush:
137 : {
138 : GBool nullcheck;
139 :
140 0 : poKmlPolyStyle = poKmlFactory->CreatePolyStyle ( );
141 :
142 0 : OGRStyleBrush *poStyleBrush = ( OGRStyleBrush * ) poOgrST;
143 :
144 : /***** brush color *****/
145 :
146 : int nR,
147 : nG,
148 : nB,
149 : nA;
150 :
151 0 : const char *pszcolor = poStyleBrush->ForeColor ( nullcheck );
152 :
153 0 : if ( !nullcheck
154 : && poStyleBrush->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
155 0 : poKmlPolyStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
156 : }
157 :
158 :
159 0 : break;
160 : }
161 : case OGRSTCSymbol:
162 : {
163 : GBool nullcheck;
164 : GBool nullcheck2;
165 :
166 0 : OGRStyleSymbol *poStyleSymbol = ( OGRStyleSymbol * ) poOgrST;
167 :
168 : /***** id (kml icon) *****/
169 :
170 0 : const char *pszId = poStyleSymbol->Id ( nullcheck );
171 :
172 0 : if ( !nullcheck ) {
173 0 : if ( !poKmlIconStyle)
174 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
175 :
176 : /***** split it at the ,'s *****/
177 :
178 : char **papszTokens =
179 : CSLTokenizeString2 ( pszId, ",",
180 : CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES |
181 0 : CSLT_STRIPENDSPACES );
182 :
183 0 : if ( papszTokens ) {
184 :
185 : /***** for lack of a better solution just take the first one *****/
186 : //todo come up with a better idea
187 :
188 0 : if ( papszTokens[0] ) {
189 : IconStyleIconPtr poKmlIcon =
190 0 : poKmlFactory->CreateIconStyleIcon ( );
191 0 : poKmlIcon->set_href ( papszTokens[0] );
192 0 : poKmlIconStyle->set_icon ( poKmlIcon );
193 : }
194 :
195 0 : CSLDestroy ( papszTokens );
196 :
197 : }
198 :
199 :
200 : }
201 :
202 : /***** heading *****/
203 :
204 0 : double heading = poStyleSymbol->Angle ( nullcheck );
205 :
206 0 : if ( !nullcheck ) {
207 0 : if ( !poKmlIconStyle)
208 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
209 0 : poKmlIconStyle->set_heading ( heading );
210 : }
211 :
212 : /***** scale *****/
213 :
214 0 : double dfScale = poStyleSymbol->Size ( nullcheck );
215 :
216 0 : if ( !nullcheck ) {
217 0 : if ( !poKmlIconStyle)
218 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
219 :
220 0 : poKmlIconStyle->set_scale ( dfScale );
221 : }
222 :
223 : /***** color *****/
224 :
225 : int nR,
226 : nG,
227 : nB,
228 : nA;
229 :
230 0 : const char *pszcolor = poStyleSymbol->Color ( nullcheck );
231 :
232 0 : if ( !nullcheck && poOgrST->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
233 0 : poKmlIconStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
234 : }
235 :
236 : /***** hotspot *****/
237 :
238 0 : double dfDx = poStyleSymbol->SpacingX ( nullcheck );
239 0 : double dfDy = poStyleSymbol->SpacingY ( nullcheck2 );
240 :
241 0 : if ( !nullcheck && !nullcheck2 ) {
242 0 : if ( !poKmlIconStyle)
243 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
244 :
245 0 : HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot ( );
246 :
247 0 : poKmlHotSpot->set_x ( dfDx );
248 0 : poKmlHotSpot->set_y ( dfDy );
249 :
250 0 : poKmlIconStyle->set_hotspot ( poKmlHotSpot );
251 : }
252 :
253 0 : break;
254 : }
255 : case OGRSTCLabel:
256 : {
257 : GBool nullcheck;
258 : GBool nullcheck2;
259 :
260 0 : poKmlLabelStyle = poKmlFactory->CreateLabelStyle ( );
261 :
262 0 : OGRStyleLabel *poStyleLabel = ( OGRStyleLabel * ) poOgrST;
263 :
264 : /***** color *****/
265 :
266 : int nR,
267 : nG,
268 : nB,
269 : nA;
270 :
271 0 : const char *pszcolor = poStyleLabel->ForeColor ( nullcheck );
272 :
273 0 : if ( !nullcheck
274 : && poStyleLabel->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
275 0 : poKmlLabelStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
276 : }
277 :
278 : /***** scale *****/
279 :
280 0 : double dfScale = poStyleLabel->Stretch ( nullcheck );
281 :
282 0 : if ( !nullcheck ) {
283 0 : dfScale /= 100.0;
284 0 : poKmlLabelStyle->set_scale ( dfScale );
285 : }
286 :
287 : /***** heading *****/
288 :
289 0 : double heading = poStyleLabel->Angle ( nullcheck );
290 :
291 0 : if ( !nullcheck ) {
292 0 : if ( !poKmlIconStyle) {
293 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
294 0 : IconStyleIconPtr poKmlIcon = poKmlFactory->CreateIconStyleIcon ( );
295 0 : poKmlIconStyle->set_icon ( poKmlIcon );
296 : }
297 :
298 0 : poKmlIconStyle->set_heading ( heading );
299 : }
300 :
301 : /***** hotspot *****/
302 :
303 0 : double dfDx = poStyleLabel->SpacingX ( nullcheck );
304 0 : double dfDy = poStyleLabel->SpacingY ( nullcheck2 );
305 :
306 0 : if ( !nullcheck && !nullcheck2 ) {
307 0 : if ( !poKmlIconStyle) {
308 0 : poKmlIconStyle = poKmlFactory->CreateIconStyle ( );
309 0 : IconStyleIconPtr poKmlIcon = poKmlFactory->CreateIconStyleIcon ( );
310 0 : poKmlIconStyle->set_icon ( poKmlIcon );
311 : }
312 :
313 0 : HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot ( );
314 :
315 0 : poKmlHotSpot->set_x ( dfDx );
316 0 : poKmlHotSpot->set_y ( dfDy );
317 :
318 0 : poKmlIconStyle->set_hotspot ( poKmlHotSpot );
319 : }
320 :
321 : /***** label text *****/
322 :
323 0 : const char *pszText = poStyleLabel->TextString ( nullcheck );
324 :
325 0 : if ( !nullcheck ) {
326 0 : if ( poKmlPlacemark ) {
327 :
328 0 : poKmlPlacemark->set_name( pszText );
329 : }
330 : }
331 :
332 : break;
333 : }
334 : case OGRSTCNone:
335 : default:
336 : break;
337 : }
338 :
339 0 : delete poOgrST;
340 : }
341 :
342 0 : if ( poKmlLineStyle )
343 0 : poKmlStyle->set_linestyle ( poKmlLineStyle );
344 :
345 0 : if ( poKmlPolyStyle )
346 0 : poKmlStyle->set_polystyle ( poKmlPolyStyle );
347 :
348 0 : if ( poKmlIconStyle )
349 0 : poKmlStyle->set_iconstyle ( poKmlIconStyle );
350 :
351 0 : if ( poKmlLabelStyle )
352 0 : poKmlStyle->set_labelstyle ( poKmlLabelStyle );
353 :
354 0 : delete poOgrSM;
355 : }
356 :
357 : /******************************************************************************
358 : kml2pen
359 : ******************************************************************************/
360 :
361 : OGRStylePen *kml2pen (
362 : LineStylePtr poKmlLineStyle,
363 : OGRStylePen *poOgrStylePen);
364 :
365 : /******************************************************************************
366 : kml2brush
367 : ******************************************************************************/
368 :
369 : OGRStyleBrush *kml2brush (
370 : PolyStylePtr poKmlPolyStyle,
371 : OGRStyleBrush *poOgrStyleBrush);
372 :
373 : /******************************************************************************
374 : kml2symbol
375 : ******************************************************************************/
376 :
377 : OGRStyleSymbol *kml2symbol (
378 : IconStylePtr poKmlIconStyle,
379 : OGRStyleSymbol *poOgrStyleSymbol);
380 :
381 : /******************************************************************************
382 : kml2label
383 : ******************************************************************************/
384 :
385 : OGRStyleLabel *kml2label (
386 : LabelStylePtr poKmlLabelStyle,
387 : OGRStyleLabel *poOgrStyleLabel);
388 :
389 : /******************************************************************************
390 : kml2stylemgr
391 : ******************************************************************************/
392 :
393 84 : void kml2stylestring (
394 : StylePtr poKmlStyle,
395 : OGRStyleMgr * poOgrSM )
396 :
397 : {
398 :
399 : OGRStyleMgr * poOgrNewSM ;
400 84 : OGRStyleTool *poOgrST = NULL;
401 84 : OGRStyleTool *poOgrTmpST = NULL;
402 : int i;
403 :
404 84 : poOgrNewSM = new OGRStyleMgr( NULL );
405 :
406 : /***** linestyle / pen *****/
407 :
408 84 : if ( poKmlStyle->has_linestyle ( ) ) {
409 :
410 60 : poOgrNewSM->InitStyleString ( NULL );
411 :
412 60 : LineStylePtr poKmlLineStyle = poKmlStyle->get_linestyle ( );
413 :
414 60 : poOgrTmpST = NULL;
415 60 : for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
416 0 : poOgrST = poOgrSM->GetPart ( i, NULL );
417 :
418 0 : if ( !poOgrST )
419 0 : continue;
420 :
421 0 : if ( poOgrST->GetType ( ) == OGRSTCPen ) {
422 0 : poOgrTmpST = poOgrST;
423 : }
424 : else {
425 0 : poOgrNewSM->AddPart ( poOgrST );
426 0 : delete poOgrST;
427 : }
428 : }
429 :
430 : OGRStylePen *poOgrStylePen = kml2pen ( poKmlLineStyle,
431 60 : ( OGRStylePen *) poOgrTmpST);
432 :
433 60 : poOgrNewSM->AddPart ( poOgrStylePen );
434 :
435 60 : delete poOgrStylePen;
436 60 : poOgrSM->InitStyleString ( poOgrNewSM->GetStyleString(NULL) );
437 :
438 : }
439 :
440 : /***** polystyle / brush *****/
441 :
442 84 : if ( poKmlStyle->has_polystyle ( ) ) {
443 :
444 48 : poOgrNewSM->InitStyleString ( NULL );
445 :
446 48 : PolyStylePtr poKmlPolyStyle = poKmlStyle->get_polystyle ( );
447 :
448 48 : poOgrTmpST = NULL;
449 96 : for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
450 48 : poOgrST = poOgrSM->GetPart ( i, NULL );
451 :
452 48 : if ( !poOgrST )
453 0 : continue;
454 :
455 48 : if ( poOgrST->GetType ( ) == OGRSTCBrush ) {
456 0 : poOgrTmpST = poOgrST;
457 : }
458 : else {
459 48 : poOgrNewSM->AddPart ( poOgrST );
460 48 : delete poOgrST;
461 : }
462 : }
463 :
464 : OGRStyleBrush *poOgrStyleBrush = kml2brush ( poKmlPolyStyle,
465 48 : ( OGRStyleBrush *) poOgrTmpST );
466 :
467 48 : poOgrNewSM->AddPart ( poOgrStyleBrush );
468 :
469 48 : delete poOgrStyleBrush;
470 48 : poOgrSM->InitStyleString ( poOgrNewSM->GetStyleString(NULL) );
471 :
472 : }
473 :
474 : /***** iconstyle / symbol *****/
475 :
476 84 : if ( poKmlStyle->has_iconstyle ( ) ) {
477 :
478 24 : poOgrNewSM->InitStyleString ( NULL );
479 :
480 24 : IconStylePtr poKmlIconStyle = poKmlStyle->get_iconstyle ( );
481 :
482 24 : poOgrTmpST = NULL;
483 30 : for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
484 6 : poOgrST = poOgrSM->GetPart ( i, NULL );
485 :
486 6 : if ( !poOgrST )
487 0 : continue;
488 :
489 6 : if ( poOgrST->GetType ( ) == OGRSTCSymbol ) {
490 0 : poOgrTmpST = poOgrST;
491 : }
492 : else {
493 6 : poOgrNewSM->AddPart ( poOgrST );
494 6 : delete poOgrST;
495 : }
496 : }
497 :
498 : OGRStyleSymbol *poOgrStyleSymbol = kml2symbol ( poKmlIconStyle,
499 24 : ( OGRStyleSymbol *) poOgrTmpST );
500 :
501 24 : poOgrNewSM->AddPart ( poOgrStyleSymbol );
502 :
503 24 : delete poOgrStyleSymbol;
504 24 : poOgrSM->InitStyleString ( poOgrNewSM->GetStyleString(NULL) );
505 :
506 : }
507 :
508 : /***** labelstyle / label *****/
509 :
510 84 : if ( poKmlStyle->has_labelstyle ( ) ) {
511 :
512 0 : poOgrNewSM->InitStyleString ( NULL );
513 :
514 0 : LabelStylePtr poKmlLabelStyle = poKmlStyle->get_labelstyle ( );
515 :
516 0 : poOgrTmpST = NULL;
517 0 : for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
518 0 : poOgrST = poOgrSM->GetPart ( i, NULL );
519 :
520 0 : if ( !poOgrST )
521 0 : continue;
522 :
523 0 : if ( poOgrST->GetType ( ) == OGRSTCLabel ) {
524 0 : poOgrTmpST = poOgrST;
525 : }
526 : else {
527 0 : poOgrNewSM->AddPart ( poOgrST );
528 0 : delete poOgrST;
529 : }
530 : }
531 :
532 : OGRStyleLabel *poOgrStyleLabel = kml2label ( poKmlLabelStyle,
533 0 : ( OGRStyleLabel *) poOgrTmpST );
534 :
535 0 : poOgrNewSM->AddPart ( poOgrStyleLabel );
536 :
537 0 : delete poOgrStyleLabel;
538 0 : poOgrSM->InitStyleString ( poOgrNewSM->GetStyleString(NULL) );
539 :
540 : }
541 :
542 84 : delete poOgrNewSM;
543 :
544 84 : }
545 :
546 :
547 :
548 : /******************************************************************************
549 : kml2pen
550 : ******************************************************************************/
551 :
552 60 : OGRStylePen *kml2pen (
553 : LineStylePtr poKmlLineStyle,
554 : OGRStylePen *poOgrStylePen)
555 : {
556 :
557 60 : if (!poOgrStylePen)
558 60 : poOgrStylePen = new OGRStylePen ( );
559 :
560 : /***** <LineStyle> should always have a width in pixels *****/
561 :
562 60 : poOgrStylePen->SetUnit(OGRSTUPixel);
563 :
564 : /***** width *****/
565 :
566 60 : if ( poKmlLineStyle->has_width ( ) )
567 48 : poOgrStylePen->SetWidth ( poKmlLineStyle->get_width ( ) );
568 :
569 : /***** color *****/
570 :
571 60 : if ( poKmlLineStyle->has_color ( ) ) {
572 30 : Color32 poKmlColor = poKmlLineStyle->get_color ( );
573 30 : char szColor[10] = { };
574 : snprintf ( szColor, sizeof ( szColor ), "#%02X%02X%02X%02X",
575 : poKmlColor.get_red ( ),
576 : poKmlColor.get_green ( ),
577 30 : poKmlColor.get_blue ( ), poKmlColor.get_alpha ( ) );
578 30 : poOgrStylePen->SetColor ( szColor );
579 : }
580 :
581 60 : return poOgrStylePen;
582 : }
583 :
584 : /******************************************************************************
585 : kml2brush
586 : ******************************************************************************/
587 :
588 48 : OGRStyleBrush *kml2brush (
589 : PolyStylePtr poKmlPolyStyle,
590 : OGRStyleBrush *poOgrStyleBrush)
591 : {
592 :
593 48 : if (!poOgrStyleBrush)
594 48 : poOgrStyleBrush = new OGRStyleBrush ( );
595 :
596 : /***** color *****/
597 :
598 48 : if ( poKmlPolyStyle->has_color ( ) ) {
599 48 : Color32 poKmlColor = poKmlPolyStyle->get_color ( );
600 48 : char szColor[10] = { };
601 : snprintf ( szColor, sizeof ( szColor ), "#%02X%02X%02X%02X",
602 : poKmlColor.get_red ( ),
603 : poKmlColor.get_green ( ),
604 48 : poKmlColor.get_blue ( ), poKmlColor.get_alpha ( ) );
605 48 : poOgrStyleBrush->SetForeColor ( szColor );
606 : }
607 :
608 48 : return poOgrStyleBrush;
609 : }
610 :
611 : /******************************************************************************
612 : kml2symbol
613 : ******************************************************************************/
614 :
615 24 : OGRStyleSymbol *kml2symbol (
616 : IconStylePtr poKmlIconStyle,
617 : OGRStyleSymbol *poOgrStyleSymbol)
618 : {
619 :
620 24 : if (!poOgrStyleSymbol)
621 24 : poOgrStyleSymbol = new OGRStyleSymbol ( );
622 :
623 : /***** id (kml icon) *****/
624 :
625 24 : if ( poKmlIconStyle->has_icon ( ) ) {
626 24 : IconStyleIconPtr poKmlIcon = poKmlIconStyle->get_icon ( );
627 :
628 24 : if ( poKmlIcon->has_href ( ) ) {
629 24 : std::string oIcon = "\"";
630 48 : oIcon.append ( poKmlIcon->get_href ( ).c_str ( ) );
631 24 : oIcon.append ( "\"" );
632 24 : poOgrStyleSymbol->SetId ( oIcon.c_str ( ) );
633 :
634 24 : }
635 : }
636 :
637 : /***** heading *****/
638 :
639 24 : if ( poKmlIconStyle->has_heading ( ) )
640 0 : poOgrStyleSymbol->SetAngle ( poKmlIconStyle->get_heading ( ) );
641 :
642 : /***** scale *****/
643 :
644 24 : if ( poKmlIconStyle->has_scale ( ) )
645 0 : poOgrStyleSymbol->SetSize ( poKmlIconStyle->get_scale ( ) );
646 :
647 : /***** color *****/
648 :
649 24 : if ( poKmlIconStyle->has_color ( ) ) {
650 0 : Color32 poKmlColor = poKmlIconStyle->get_color ( );
651 0 : char szColor[10] = { };
652 : snprintf ( szColor, sizeof ( szColor ), "#%02X%02X%02X%02X",
653 : poKmlColor.get_red ( ),
654 : poKmlColor.get_green ( ),
655 0 : poKmlColor.get_blue ( ), poKmlColor.get_alpha ( ) );
656 0 : poOgrStyleSymbol->SetColor ( szColor );
657 : }
658 :
659 : /***** hotspot *****/
660 :
661 24 : if ( poKmlIconStyle->has_hotspot ( ) ) {
662 0 : HotSpotPtr poKmlHotSpot = poKmlIconStyle->get_hotspot ( );
663 :
664 0 : if ( poKmlHotSpot->has_x ( ) )
665 0 : poOgrStyleSymbol->SetSpacingX ( poKmlHotSpot->get_x ( ) );
666 0 : if ( poKmlHotSpot->has_y ( ) )
667 0 : poOgrStyleSymbol->SetSpacingY ( poKmlHotSpot->get_y ( ) );
668 :
669 : }
670 :
671 24 : return poOgrStyleSymbol;
672 : }
673 :
674 : /******************************************************************************
675 : kml2label
676 : ******************************************************************************/
677 :
678 0 : OGRStyleLabel *kml2label (
679 : LabelStylePtr poKmlLabelStyle,
680 : OGRStyleLabel *poOgrStyleLabel)
681 : {
682 :
683 0 : if (!poOgrStyleLabel)
684 0 : poOgrStyleLabel = new OGRStyleLabel ( );
685 :
686 : /***** color *****/
687 :
688 0 : if ( poKmlLabelStyle->has_color ( ) ) {
689 0 : Color32 poKmlColor = poKmlLabelStyle->get_color ( );
690 0 : char szColor[10] = { };
691 : snprintf ( szColor, sizeof ( szColor ), "#%02X%02X%02X%02X",
692 : poKmlColor.get_red ( ),
693 : poKmlColor.get_green ( ),
694 0 : poKmlColor.get_blue ( ), poKmlColor.get_alpha ( ) );
695 0 : poOgrStyleLabel->SetForColor ( szColor );
696 : }
697 :
698 0 : if ( poKmlLabelStyle->has_scale ( ) ) {
699 0 : double dfScale = poKmlLabelStyle->get_scale ( );
700 0 : dfScale *= 100.0;
701 :
702 0 : poOgrStyleLabel->SetStretch(dfScale);
703 : }
704 :
705 0 : return poOgrStyleLabel;
706 : }
707 :
708 : /******************************************************************************
709 : function to add a kml style to a style table
710 : ******************************************************************************/
711 :
712 84 : void kml2styletable (
713 : OGRStyleTable * poOgrStyleTable,
714 : StylePtr poKmlStyle )
715 : {
716 :
717 :
718 : /***** no reason to add it if it don't have an id *****/
719 :
720 84 : if ( poKmlStyle->has_id ( ) ) {
721 :
722 84 : OGRStyleMgr *poOgrSM = new OGRStyleMgr ( poOgrStyleTable );
723 :
724 84 : poOgrSM->InitStyleString ( NULL );
725 :
726 : /***** read the style *****/
727 :
728 168 : kml2stylestring ( poKmlStyle, poOgrSM );
729 :
730 : /***** add the style to the style table *****/
731 :
732 84 : const std::string oName = poKmlStyle->get_id ( );
733 :
734 :
735 : poOgrSM->AddStyle ( CPLString ( ).Printf ( "@%s",
736 168 : oName.c_str ( ) ), NULL );
737 :
738 : /***** cleanup the style manager *****/
739 :
740 84 : delete poOgrSM;
741 : }
742 :
743 : else {
744 : CPLError ( CE_Failure, CPLE_AppDefined,
745 0 : "ERROR Parseing kml Style: No id" );
746 : }
747 :
748 : return;
749 : }
750 :
751 : /******************************************************************************
752 : function to follow the kml stylemap if one exists
753 : ******************************************************************************/
754 :
755 0 : StyleSelectorPtr StyleFromStyleSelector(
756 : const StyleSelectorPtr& poKmlStyleSelector,
757 : OGRStyleTable * poStyleTable)
758 : {
759 :
760 : /***** is it a style? *****/
761 :
762 0 : if ( poKmlStyleSelector->IsA( kmldom::Type_Style) )
763 0 : return poKmlStyleSelector;
764 :
765 : /***** is it a style map? *****/
766 :
767 0 : else if ( poKmlStyleSelector->IsA( kmldom::Type_StyleMap) )
768 0 : return StyleFromStyleMap(kmldom::AsStyleMap(poKmlStyleSelector), poStyleTable);
769 :
770 : /***** not a style or a style map *****/
771 :
772 0 : return NULL;
773 : }
774 :
775 :
776 : /******************************************************************************
777 : function to get the container from the kmlroot
778 :
779 : Args: poKmlRoot the root element
780 :
781 : Returns: root if its a container, if its a kml the container it
782 : contains, or NULL
783 :
784 : ******************************************************************************/
785 :
786 0 : static ContainerPtr MyGetContainerFromRoot (
787 : KmlFactory *m_poKmlFactory, ElementPtr poKmlRoot )
788 : {
789 0 : ContainerPtr poKmlContainer = NULL;
790 :
791 0 : if ( poKmlRoot ) {
792 :
793 : /***** skip over the <kml> we want the container *****/
794 :
795 0 : if ( poKmlRoot->IsA ( kmldom::Type_kml ) ) {
796 :
797 0 : KmlPtr poKmlKml = AsKml ( poKmlRoot );
798 :
799 0 : if ( poKmlKml->has_feature ( ) ) {
800 0 : FeaturePtr poKmlFeat = poKmlKml->get_feature ( );
801 :
802 0 : if ( poKmlFeat->IsA ( kmldom::Type_Container ) )
803 0 : poKmlContainer = AsContainer ( poKmlFeat );
804 0 : else if ( poKmlFeat->IsA ( kmldom::Type_Placemark ) )
805 : {
806 0 : poKmlContainer = m_poKmlFactory->CreateDocument ( );
807 0 : poKmlContainer->add_feature ( kmldom::AsFeature(kmlengine::Clone(poKmlFeat)) );
808 0 : }
809 0 : }
810 : }
811 :
812 0 : else if ( poKmlRoot->IsA ( kmldom::Type_Container ) )
813 0 : poKmlContainer = AsContainer ( poKmlRoot );
814 : }
815 :
816 0 : return poKmlContainer;
817 : }
818 :
819 :
820 :
821 6 : StyleSelectorPtr StyleFromStyleURL(
822 : const StyleMapPtr& stylemap,
823 : const string styleurl,
824 : OGRStyleTable * poStyleTable)
825 : {
826 : // TODO:: Parse the styleURL
827 :
828 6 : char *pszUrl = CPLStrdup ( styleurl.c_str ( ) );
829 6 : char *pszStyleMapId = CPLStrdup ( stylemap->get_id().c_str ( ) );
830 :
831 :
832 : /***** is it an interenal style ref that starts with a # *****/
833 :
834 12 : if ( *pszUrl == '#' && poStyleTable ) {
835 :
836 : /***** searh the style table for the style we *****/
837 : /***** want and copy it back into the table *****/
838 :
839 6 : const char *pszTest = NULL;
840 6 : pszTest = poStyleTable->Find ( pszUrl + 1 );
841 6 : if ( pszTest ) {
842 6 : poStyleTable->AddStyle(pszStyleMapId, pszTest);
843 : }
844 : }
845 :
846 : /***** We have a real URL and need to go out and fetch it *****/
847 : /***** FIXME this could be a relative path in a kmz *****/
848 :
849 0 : else if ( strchr(pszUrl, '#') ) {
850 :
851 0 : const char *pszFetch = CPLGetConfigOption ( "LIBKML_EXTERNAL_STYLE", "no" );
852 0 : if ( EQUAL(pszFetch, "yes") ) {
853 :
854 : /***** Lets go out and fetch the style from the external URL *****/
855 :
856 0 : char *pszUrlTmp = CPLStrdup(pszUrl);
857 : char *pszPound;
858 0 : char *pszRemoteStyleName = NULL;
859 : // Chop off the stuff (style id) after the URL
860 0 : if ((pszPound = strchr(pszUrlTmp, '#'))) {
861 0 : *pszPound = '\0';
862 0 : pszRemoteStyleName = pszPound + 1;
863 : }
864 :
865 : /***** try it as a url then a file *****/
866 :
867 0 : VSILFILE *fp = NULL;
868 0 : if ( (fp = VSIFOpenL( CPLFormFilename( "/vsicurl/",
869 : pszUrlTmp,
870 : NULL), "r" ))
871 : || (fp = VSIFOpenL( pszUrlTmp, "r" )) )
872 : {
873 : char szbuf[1025];
874 0 : std::string oStyle = "";
875 :
876 : /***** loop, read and copy to a string *****/
877 :
878 : size_t nRead;
879 0 : do {
880 0 : nRead = VSIFReadL(szbuf, 1, sizeof(szbuf) - 1, fp);
881 0 : if (nRead == 0)
882 0 : break;
883 :
884 : /***** copy buf to the string *****/
885 :
886 0 : szbuf[nRead] = '\0';
887 0 : oStyle.append( szbuf );
888 : } while (!VSIFEofL(fp));
889 :
890 0 : VSIFCloseL(fp);
891 :
892 : /***** parse the kml into the dom *****/
893 :
894 0 : std::string oKmlErrors;
895 0 : ElementPtr poKmlRoot = kmldom::Parse ( oStyle, &oKmlErrors );
896 :
897 0 : if ( !poKmlRoot ) {
898 : CPLError ( CE_Failure, CPLE_OpenFailed,
899 : "ERROR Parseing style kml %s :%s",
900 0 : pszUrlTmp, oKmlErrors.c_str ( ) );
901 0 : CPLFree(pszUrlTmp);
902 0 : CPLFree ( pszUrl );
903 0 : CPLFree ( pszStyleMapId );
904 :
905 0 : return NULL;
906 : }
907 :
908 : /***** get the root container *****/
909 :
910 0 : ContainerPtr poKmlContainer;
911 0 : kmldom::KmlFactory* poKmlFactory = kmldom::KmlFactory::GetFactory();
912 0 : if ( !( poKmlContainer = MyGetContainerFromRoot ( poKmlFactory, poKmlRoot ) ) ) {
913 0 : CPLFree(pszUrlTmp);
914 0 : CPLFree ( pszUrl );
915 0 : CPLFree ( pszStyleMapId );
916 :
917 0 : return NULL;
918 : }
919 :
920 : /**** parse the styles into the table *****/
921 :
922 0 : ParseStyles ( AsDocument ( poKmlContainer ), &poStyleTable );
923 :
924 : /***** look for the style we leed to map to in the table *****/
925 :
926 0 : const char *pszTest = NULL;
927 0 : pszTest = poStyleTable->Find(pszRemoteStyleName);
928 :
929 : /***** if found copy it to the table as a new style *****/
930 0 : if ( pszTest )
931 0 : poStyleTable->AddStyle(pszStyleMapId, pszTest);
932 :
933 : }
934 0 : CPLFree(pszUrlTmp);
935 : }
936 : }
937 :
938 : /***** FIXME add suport here for relative links inside kml *****/
939 :
940 6 : CPLFree ( pszUrl );
941 6 : CPLFree ( pszStyleMapId );
942 :
943 6 : return NULL;
944 : }
945 :
946 6 : StyleSelectorPtr StyleFromStyleMap(
947 : const StyleMapPtr& poKmlStyleMap,
948 : OGRStyleTable * poStyleTable)
949 : {
950 :
951 : /***** check the config option to see if the *****/
952 : /***** user wants normal or highlighted mapping *****/
953 :
954 6 : const char *pszStyleMapKey = CPLGetConfigOption ( "LIBKML_STYLEMAP_KEY", "normal" );
955 6 : int nStyleMapKey = STYLESTATE_NORMAL;
956 6 : if ( EQUAL (pszStyleMapKey, "highlight"))
957 0 : nStyleMapKey = STYLESTATE_HIGHLIGHT;
958 :
959 : /***** Loop through the stylemap pairs and look for the "normal" one *****/
960 :
961 6 : for (size_t i = 0; i < poKmlStyleMap->get_pair_array_size(); ++i) {
962 6 : PairPtr myPair = poKmlStyleMap->get_pair_array_at(i);
963 :
964 : /***** is it the right one of the pair? *****/
965 :
966 6 : if ( myPair->get_key() == nStyleMapKey ) {
967 :
968 6 : if (myPair->has_styleselector())
969 0 : return StyleFromStyleSelector(myPair->get_styleselector(), poStyleTable);
970 :
971 6 : else if (myPair->has_styleurl())
972 6 : return StyleFromStyleURL(poKmlStyleMap, myPair->get_styleurl(), poStyleTable);
973 : }
974 : }
975 :
976 0 : return NULL;
977 : }
978 :
979 : /******************************************************************************
980 : function to parse a style table out of a document
981 : ******************************************************************************/
982 :
983 42 : void ParseStyles (
984 : DocumentPtr poKmlDocument,
985 : OGRStyleTable ** poStyleTable )
986 : {
987 :
988 : /***** if document is null just bail now *****/
989 :
990 42 : if ( !poKmlDocument )
991 0 : return;
992 :
993 : /***** loop over the Styles *****/
994 :
995 42 : size_t nKmlStyles = poKmlDocument->get_styleselector_array_size ( );
996 : size_t iKmlStyle;
997 :
998 : /***** Lets first build the style table. *****/
999 : /***** to begin this is just proper styles. *****/
1000 :
1001 126 : for ( iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++ ) {
1002 : StyleSelectorPtr poKmlStyle =
1003 90 : poKmlDocument->get_styleselector_array_at ( iKmlStyle );
1004 :
1005 : /***** Everything that is not a style you skip *****/
1006 :
1007 90 : if ( !poKmlStyle->IsA ( kmldom::Type_Style ) )
1008 6 : continue;
1009 :
1010 : /***** We need to check to see if this is the first style. if it *****/
1011 : /***** is we will not have a style table and need to create one *****/
1012 :
1013 84 : if ( !*poStyleTable )
1014 12 : *poStyleTable = new OGRStyleTable ( );
1015 :
1016 : /***** TODO:: Not sure we need to do this as we seem *****/
1017 : /***** to cast to element and then back to style. *****/
1018 :
1019 84 : ElementPtr poKmlElement = AsElement ( poKmlStyle );
1020 84 : kml2styletable ( *poStyleTable, AsStyle ( poKmlElement ) );
1021 : }
1022 :
1023 : /***** Now we have to loop back around and get the style maps. We *****/
1024 : /***** have to do this a second time since the stylemap might matter *****/
1025 : /***** and we are just looping reference styles that are farther *****/
1026 : /***** down in the file. Order through the XML as it is parsed. *****/
1027 :
1028 42 : for ( iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++ ) {
1029 : StyleSelectorPtr poKmlStyle =
1030 90 : poKmlDocument->get_styleselector_array_at ( iKmlStyle );
1031 :
1032 : /***** Everything that is not a stylemap you skip *****/
1033 :
1034 90 : if ( !poKmlStyle->IsA ( kmldom::Type_StyleMap ) )
1035 84 : continue;
1036 :
1037 : /***** We need to check to see if this is the first style. if it *****/
1038 : /***** is we will not have a style table and need to create one *****/
1039 :
1040 6 : if ( !*poStyleTable )
1041 0 : *poStyleTable = new OGRStyleTable ( );
1042 :
1043 : /***** copy the style the style map points to since *****/
1044 :
1045 6 : char *pszStyleMapId = CPLStrdup ( poKmlStyle->get_id().c_str ( ) );
1046 6 : poKmlStyle = StyleFromStyleMap(kmldom::AsStyleMap(poKmlStyle), *poStyleTable);
1047 6 : if (poKmlStyle == NULL) {
1048 6 : CPLFree(pszStyleMapId);
1049 6 : continue;
1050 : }
1051 0 : char *pszStyleId = CPLStrdup ( poKmlStyle->get_id().c_str ( ) );
1052 :
1053 : /***** TODO:: Not sure we need to do this as we seem *****/
1054 : /***** to cast to element and then back to style. *****/
1055 :
1056 0 : ElementPtr poKmlElement = AsElement ( poKmlStyle );
1057 0 : kml2styletable ( *poStyleTable, AsStyle ( poKmlElement ) );
1058 :
1059 : // Change the name of the new style in the style table
1060 :
1061 0 : const char *pszTest = NULL;
1062 0 : pszTest = (*poStyleTable)->Find(pszStyleId);
1063 : // If we found the style we want in the style table we...
1064 0 : if ( pszTest ) {
1065 0 : (*poStyleTable)->AddStyle(pszStyleMapId, pszTest);
1066 0 : (*poStyleTable)->RemoveStyle ( pszStyleId );
1067 : }
1068 0 : CPLFree ( pszStyleId );
1069 0 : CPLFree ( pszStyleMapId );
1070 : }
1071 :
1072 42 : return;
1073 : }
1074 :
1075 : /******************************************************************************
1076 : function to add a style table to a kml container
1077 : ******************************************************************************/
1078 :
1079 0 : void styletable2kml (
1080 : OGRStyleTable * poOgrStyleTable,
1081 : KmlFactory * poKmlFactory,
1082 : ContainerPtr poKmlContainer )
1083 : {
1084 :
1085 : /***** just return if the styletable is null *****/
1086 :
1087 0 : if ( !poOgrStyleTable )
1088 0 : return;
1089 :
1090 : /***** parse the style table *****/
1091 :
1092 0 : poOgrStyleTable->ResetStyleStringReading ( );
1093 : const char *pszStyleString;
1094 :
1095 0 : while ( ( pszStyleString = poOgrStyleTable->GetNextStyle ( ) ) ) {
1096 0 : const char *pszStyleName = poOgrStyleTable->GetLastStyleName ( );
1097 :
1098 : /***** add the style header to the kml *****/
1099 :
1100 0 : StylePtr poKmlStyle = poKmlFactory->CreateStyle ( );
1101 :
1102 0 : poKmlStyle->set_id ( pszStyleName + 1 );
1103 :
1104 : /***** parse the style string *****/
1105 :
1106 0 : addstylestring2kml ( pszStyleString, poKmlStyle, poKmlFactory, NULL, NULL );
1107 :
1108 : /***** add the style to the container *****/
1109 :
1110 0 : DocumentPtr poKmlDocument = AsDocument ( poKmlContainer );
1111 :
1112 : //ObjectPtr pokmlObject = boost::static_pointer_cast <kmldom::Object> () ;
1113 : //poKmlContainer->add_feature ( AsFeature( poKmlStyle) );
1114 0 : poKmlDocument->add_styleselector ( poKmlStyle );
1115 :
1116 : }
1117 :
1118 0 : return;
1119 : }
|