Exemple #1
0
/**
 * @brief KmlExport::createTimespanPlacemark Creates a timespan placemark, which allows the
 * trajectory to be played forward in time. The placemark also contains pertinent data about
 * the vehicle's state at that timespan
 * @param timestampPoint
 * @param lastPlacemarkTime
 * @param newPlacemarkTime
 * @return Returns the placemark containing the timespan
 */
PlacemarkPtr KmlExport::createTimespanPlacemark(const LLAVCoordinates &timestampPoint, quint32 lastPlacemarkTime, quint32 newPlacemarkTime)
{
    // Create coordinates
    CoordinatesPtr coordinates = factory->CreateCoordinates();
    coordinates->add_latlngalt(timestampPoint.latitude, timestampPoint.longitude, timestampPoint.altitude);

    // Create point, using previous coordinates
    PointPtr point = factory->CreatePoint();
    point->set_extrude(true); // Extrude to ground
    point->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
    point->set_coordinates(coordinates);

    // Create the timespan
    TimeSpanPtr timeSpan = factory->CreateTimeSpan();
    QDateTime startTime = QDateTime::currentDateTimeUtc().addMSecs(lastPlacemarkTime); // FIXME: Make it a function of the realtime preferably gotten from the GPS
    QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
    timeSpan->set_begin(startTime.toString(dateTimeFormat).toStdString());
    timeSpan->set_end(endTime.toString(dateTimeFormat).toStdString());

    // Create an icon style. This arrow icon will be rotated and colored to represent velocity
    AttitudeActual::DataFields attitudeActualData = attitudeActual->getData();
    AirspeedActual::DataFields airspeedActualData = airspeedActual->getData();
    IconStylePtr iconStyle = factory->CreateIconStyle();
    iconStyle->set_color(mapVelocity2Color(airspeedActualData.CalibratedAirspeed));
    iconStyle->set_heading(attitudeActualData.Yaw + 180); //Adding 180 degrees because the arrow art points down, i.e. south.

    // Create a line style. This defines the style for the "legs" connecting the points to the ground.
    LineStylePtr lineStyle = factory->CreateLineStyle();
    lineStyle->set_color(mapVelocity2Color(timestampPoint.groundspeed));

    // Link the style to the icon
    StylePtr style = factory->CreateStyle();
    style->set_linestyle(lineStyle);
    style->set_iconstyle(iconStyle);

    // Generate the placemark with all above attributes
    PlacemarkPtr placemark = factory->CreatePlacemark();
    placemark->set_geometry(point);
    placemark->set_timeprimitive(timeSpan);
    placemark->set_name(QString("%1").arg(timeStamp / 1000.0).toStdString());
    placemark->set_visibility(true);

    // Set the placemark to use the custom rotated arrow style
    placemark->set_styleurl("#directiveArrowStyle");
    placemark->set_styleselector(style);

    // Add a nice description to the placemark
    placemark->set_description(informationString.toStdString());

    return placemark;
}
Exemple #2
0
void addstylestring2kml (
    const char *pszStyleString,
    StylePtr poKmlStyle,
    KmlFactory * poKmlFactory,
    PlacemarkPtr poKmlPlacemark,
    OGRFeature * poOgrFeat )
{

    LineStylePtr poKmlLineStyle = NULL;
    PolyStylePtr poKmlPolyStyle = NULL;
    IconStylePtr poKmlIconStyle = NULL;
    LabelStylePtr poKmlLabelStyle = NULL;
    
    /***** just bail now if stylestring is empty *****/

    if ( !pszStyleString || !*pszStyleString ) {
        return;
    }

    /***** create and init a style mamager with the style string *****/

    OGRStyleMgr *poOgrSM = new OGRStyleMgr;

    poOgrSM->InitStyleString ( pszStyleString );

    /***** loop though the style parts *****/

    int i;

    for ( i = 0; i < poOgrSM->GetPartCount ( NULL ); i++ ) {
        OGRStyleTool *poOgrST = poOgrSM->GetPart ( i, NULL );

        if ( !poOgrST ) {
            continue;
        }
        
        switch ( poOgrST->GetType (  ) ) {
        case OGRSTCPen:
            {
                GBool nullcheck;

                poKmlLineStyle = poKmlFactory->CreateLineStyle (  );

                OGRStylePen *poStylePen = ( OGRStylePen * ) poOgrST;

                /***** pen color *****/

                int nR,
                    nG,
                    nB,
                    nA;

                const char *pszcolor = poStylePen->Color ( nullcheck );

                if ( !nullcheck
                     && poStylePen->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
                    poKmlLineStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
                }
                double dfWidth = poStylePen->Width ( nullcheck );

                if ( nullcheck )
                    dfWidth = 1.0;

                poKmlLineStyle->set_width ( dfWidth );
                
                break;
            }
        case OGRSTCBrush:
            {
                GBool nullcheck;

                poKmlPolyStyle = poKmlFactory->CreatePolyStyle (  );

                OGRStyleBrush *poStyleBrush = ( OGRStyleBrush * ) poOgrST;

                /***** brush color *****/

                int nR,
                    nG,
                    nB,
                    nA;

                const char *pszcolor = poStyleBrush->ForeColor ( nullcheck );

                if ( !nullcheck
                     && poStyleBrush->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
                    poKmlPolyStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
                }
                

                break;
            }
        case OGRSTCSymbol:
            {
                GBool nullcheck;
                GBool nullcheck2;

                OGRStyleSymbol *poStyleSymbol = ( OGRStyleSymbol * ) poOgrST;

                /***** id (kml icon) *****/

                const char *pszId = poStyleSymbol->Id ( nullcheck );

                if ( !nullcheck ) {
                    if ( !poKmlIconStyle)
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );

                    /***** split it at the ,'s *****/

                    char **papszTokens =
                        CSLTokenizeString2 ( pszId, ",",
                                             CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES |
                                             CSLT_STRIPENDSPACES );

                    if ( papszTokens ) {

                        /***** for lack of a better solution just take the first one *****/
                        //todo come up with a better idea

                        if ( papszTokens[0] ) {
                            IconStyleIconPtr poKmlIcon =
                                poKmlFactory->CreateIconStyleIcon (  );
                            poKmlIcon->set_href ( papszTokens[0] );
                            poKmlIconStyle->set_icon ( poKmlIcon );
                        }

                        CSLDestroy ( papszTokens );

                    }


                }

                /***** heading *****/

                double heading = poStyleSymbol->Angle ( nullcheck );

                if ( !nullcheck ) {
                    if ( !poKmlIconStyle)
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );
                    poKmlIconStyle->set_heading ( heading );
                }

                /***** scale *****/

                double dfScale = poStyleSymbol->Size ( nullcheck );

                if ( !nullcheck ) {
                    if ( !poKmlIconStyle)
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );

                    poKmlIconStyle->set_scale ( dfScale );
                }

                /***** color *****/

                int nR,
                    nG,
                    nB,
                    nA;

                const char *pszcolor = poStyleSymbol->Color ( nullcheck );

                if ( !nullcheck && poOgrST->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
                    poKmlIconStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
                }

                /***** hotspot *****/

                double dfDx = poStyleSymbol->SpacingX ( nullcheck );
                double dfDy = poStyleSymbol->SpacingY ( nullcheck2 );

                if ( !nullcheck && !nullcheck2 ) {
                    if ( !poKmlIconStyle)
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );

                    HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot (  );

                    poKmlHotSpot->set_x ( dfDx );
                    poKmlHotSpot->set_y ( dfDy );

                    poKmlIconStyle->set_hotspot ( poKmlHotSpot );
                }
                
                break;
            }
        case OGRSTCLabel:
            {
                GBool nullcheck;
                GBool nullcheck2;
                
                poKmlLabelStyle = poKmlFactory->CreateLabelStyle (  );

                OGRStyleLabel *poStyleLabel = ( OGRStyleLabel * ) poOgrST;

                /***** color *****/

                int nR,
                    nG,
                    nB,
                    nA;

                const char *pszcolor = poStyleLabel->ForeColor ( nullcheck );

                if ( !nullcheck
                     && poStyleLabel->GetRGBFromString ( pszcolor, nR, nG, nB, nA ) ) {
                    poKmlLabelStyle->set_color ( Color32 ( nA, nB, nG, nR ) );
                }

                /***** scale *****/

                double dfScale = poStyleLabel->Stretch ( nullcheck );

                if ( !nullcheck ) {
                    dfScale /= 100.0;
                    poKmlLabelStyle->set_scale ( dfScale );
                }
                
                /***** heading *****/

                double heading = poStyleLabel->Angle ( nullcheck );

                if ( !nullcheck ) {
                    if ( !poKmlIconStyle) {
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );
                        IconStyleIconPtr poKmlIcon = poKmlFactory->CreateIconStyleIcon (  );
                        poKmlIconStyle->set_icon ( poKmlIcon );
                    }
                    
                    poKmlIconStyle->set_heading ( heading );
                }

                /***** hotspot *****/

                double dfDx = poStyleLabel->SpacingX ( nullcheck );
                double dfDy = poStyleLabel->SpacingY ( nullcheck2 );

                if ( !nullcheck && !nullcheck2 ) {
                    if ( !poKmlIconStyle) {
                        poKmlIconStyle = poKmlFactory->CreateIconStyle (  );
                        IconStyleIconPtr poKmlIcon = poKmlFactory->CreateIconStyleIcon (  );
                        poKmlIconStyle->set_icon ( poKmlIcon );
                    }
                    
                    HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot (  );

                    poKmlHotSpot->set_x ( dfDx );
                    poKmlHotSpot->set_y ( dfDy );

                    poKmlIconStyle->set_hotspot ( poKmlHotSpot );
                }

                /***** label text *****/

                const char *pszText = poStyleLabel->TextString ( nullcheck );

                if ( !nullcheck ) {
                    if ( poKmlPlacemark ) {

                        poKmlPlacemark->set_name( pszText );
                    }
                }
                    
                break;
            }
        case OGRSTCNone:
        default:
            break;
        }

        delete poOgrST;
    }

    if ( poKmlLineStyle )
        poKmlStyle->set_linestyle ( poKmlLineStyle );

    if ( poKmlPolyStyle )
        poKmlStyle->set_polystyle ( poKmlPolyStyle );

    if ( poKmlIconStyle )
        poKmlStyle->set_iconstyle ( poKmlIconStyle );

    if ( poKmlLabelStyle )
        poKmlStyle->set_labelstyle ( poKmlLabelStyle );
    
    delete poOgrSM;
}
Exemple #3
0
/**
 * @brief KmlExport::exportToKML Triggers logfile export to KML.
 */
bool KmlExport::exportToKML()
{
    bool ret = open();
    if (!ret) {
        qDebug () << "Logfile failed to open during KML export";
        return false;
    }

    // Parses logfile and generates KML document
    ret = preparseLogFile();
    if (!ret) {
        qDebug () << "Logfile preparsing failed";
        return false;
    }

    // Call parser.
    parseLogFile();

    // Add track to <Document>
    document->add_feature(trackFolder);

    // Add timespans to <Document>
    document->add_feature(timestampFolder);

    // Add ground track to <Document>
    {
        LineStringPtr linestring = factory->CreateLineString();
        linestring->set_extrude(false); // Do not extrude to ground
        linestring->set_altitudemode(kmldom::ALTITUDEMODE_CLAMPTOGROUND);
        linestring->set_coordinates(wallAxes[0]);

        MultiGeometryPtr multiGeometry = factory->CreateMultiGeometry();
        multiGeometry->add_geometry(linestring);

        PlacemarkPtr placemark = factory->CreatePlacemark();
        placemark->set_geometry(multiGeometry);
        placemark->set_styleurl("#ts_2_tb");
        placemark->set_name("Ground track");

        document->add_feature(placemark);
    }

    // Add wall axes to <Document>
    FolderPtr folder = factory->CreateFolder();
    for (int i=0; i<numberOfWallAxes; i++) {
        LineStringPtr linestring = factory->CreateLineString();
        linestring->set_extrude(false); // Do not extrude to ground
        linestring->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
        linestring->set_coordinates(wallAxes[i]);

        MultiGeometryPtr multiGeometry = factory->CreateMultiGeometry();
        multiGeometry->add_geometry(linestring);

        PlacemarkPtr placemark = factory->CreatePlacemark();
        placemark->set_geometry(multiGeometry);
        placemark->set_styleurl("#ts_1_tb");

        folder->add_feature(placemark);
        folder->set_name("Wall axes");
    }
    document->add_feature(folder);

    // Create <kml> and give it <Document>.
    KmlPtr kml = factory->CreateKml();
    kml->set_feature(document);  // kml takes ownership.

    // Serialize to XML
    std::string kml_data = kmldom::SerializePretty(kml);

    // Save to file
    if (QFileInfo(outputFileName).suffix().toLower() == "kmz") {
        if (!kmlengine::KmzFile::WriteKmz(outputFileName.toStdString().c_str(), kml_data)) {
            qDebug() << "KMZ write failed: " << outputFileName;
            QMessageBox::critical(new QWidget(),"KMZ write failed", "Failed to write KMZ file.");
            return false;
        }
    } else if (QFileInfo(outputFileName).suffix().toLower() == "kml") {
        if (!kmlbase::File::WriteStringToFile(kml_data, outputFileName.toStdString())) {
            qDebug() << "KML write failed: " << outputFileName;
            QMessageBox::critical(new QWidget(),"KML write failed", "Failed to write KML file.");
            return false;
        }
    } else {
        qDebug() << "Write failed. Invalid file name:" << outputFileName;
        QMessageBox::critical(new QWidget(),"Write failed", "Failed to write file. Invalid filename");
        return false;
    }


    return true;
}
Exemple #4
0
/**
 * @brief KmlExport::CreateLineStringPlacemark Adds a line segment which is colored according to the
 * vehicle's speed.
 * @param startPoint Beginning point along line
 * @param endPoint End point point along line
 * @return Returns the placemark containing the line segment
 */
PlacemarkPtr KmlExport::CreateLineStringPlacemark(const LLAVCoordinates &startPoint, const LLAVCoordinates &endPoint, quint32 newPlacemarkTime)
{
    CoordinatesPtr coordinates = factory->CreateCoordinates();
    coordinates->add_latlngalt(startPoint.latitude, startPoint.longitude, startPoint.altitude);
    coordinates->add_latlngalt(endPoint.latitude,   endPoint.longitude,   endPoint.altitude);

    LineStringPtr linestring = factory->CreateLineString();
    linestring->set_extrude(true); // Extrude to ground
    linestring->set_altitudemode(kmldom::ALTITUDEMODE_ABSOLUTE);
    linestring->set_coordinates(coordinates);

    StyleMapPtr styleMap = factory->CreateStyleMap();


    // Add custom balloon style (gets rid of "Directions to here...")
    // https://groups.google.com/forum/?fromgroups#!topic/kml-support-getting-started/2CqF9oiynRY
    BalloonStylePtr balloonStyle = factory->CreateBalloonStyle();
    balloonStyle->set_text("$[description]");

    {
        double currentVelocity = (startPoint.groundspeed + endPoint.groundspeed)/2;

        // Set the linestyle. The color is a function of speed.
        LineStylePtr lineStyle = factory->CreateLineStyle();
        lineStyle->set_color(mapVelocity2Color(currentVelocity));

        PolyStylePtr polyStyle = factory->CreatePolyStyle();
        polyStyle->set_color(mapVelocity2Color(currentVelocity, 100));

        // Link the style to the icon
        StylePtr style = factory->CreateStyle();
        style->set_balloonstyle(balloonStyle);
        style->set_linestyle(lineStyle);
        style->set_polystyle(polyStyle);

        PairPtr pair = factory->CreatePair();
        pair->set_styleselector(style);
        pair->set_key(kmldom::STYLESTATE_NORMAL);

        styleMap->add_pair(pair);
    }

    {
        double currentVelocity = (startPoint.groundspeed + endPoint.groundspeed)/2;

        // Set the linestyle. The color is a function of speed.
        LineStylePtr lineStyle = factory->CreateLineStyle();
        lineStyle->set_color(mapVelocity2Color(currentVelocity));

        PolyStylePtr polyStyle = factory->CreatePolyStyle();
        polyStyle->set_color(mapVelocity2Color(currentVelocity, 100));
        polyStyle->set_fill(false);

        // Link the style to the icon
        StylePtr style = factory->CreateStyle();
        style->set_balloonstyle(balloonStyle);
        style->set_linestyle(lineStyle);
        style->set_polystyle(polyStyle);

        PairPtr pair = factory->CreatePair();
        pair->set_styleselector(style);
        pair->set_key(kmldom::STYLESTATE_HIGHLIGHT);

        styleMap->add_pair(pair);
    }

    PlacemarkPtr placemark = factory->CreatePlacemark();
    placemark->set_geometry(linestring);
    placemark->set_styleselector(styleMap);
    placemark->set_visibility(true);

    // Create the timespan
    TimeSpanPtr timeSpan = factory->CreateTimeSpan();
    QDateTime startTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime); // FIXME: Make this a function of the true time, preferably gotten from the GPS
    QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime);
    timeSpan->set_begin(startTime.toString(dateTimeFormat).toStdString());
    timeSpan->set_end(endTime.toString(dateTimeFormat).toStdString());

    // Set the name
    QDateTime trackTime = QDateTime::currentDateTimeUtc().addMSecs(newPlacemarkTime); // FIXME: Make it a function of the realtime preferably gotten from the GPS
    placemark->set_name(trackTime.toString(dateTimeFormat).toStdString());

    // Add a nice description to the track placemark
    placemark->set_description(informationString.toStdString());

    // Set the timespan
    placemark->set_timeprimitive(timeSpan);

    return placemark;
}
void field2kml (
    OGRFeature * poOgrFeat,
    OGRLIBKMLLayer * poOgrLayer,
    KmlFactory * poKmlFactory,
    PlacemarkPtr poKmlPlacemark )
{
    int i;

    SchemaDataPtr poKmlSchemaData = poKmlFactory->CreateSchemaData (  );
    SchemaPtr poKmlSchema = poOgrLayer->GetKmlSchema (  );

    /***** set the url to the schema *****/

    if ( poKmlSchema && poKmlSchema->has_id (  ) ) {
        std::string oKmlSchemaID = poKmlSchema->get_id (  );


        std::string oKmlSchemaURL = "#";
        oKmlSchemaURL.append ( oKmlSchemaID );

        poKmlSchemaData->set_schemaurl ( oKmlSchemaURL );
    }

    const char *namefield = CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
    const char *descfield =
        CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
    const char *tsfield =
        CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
    const char *beginfield =
        CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
    const char *endfield = CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
    const char *altitudeModefield =
        CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
    const char *tessellatefield =
        CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
    const char *extrudefield =
        CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
    const char *visibilityfield =
        CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );

    TimeSpanPtr poKmlTimeSpan = NULL;

    int nFields = poOgrFeat->GetFieldCount (  );
    int iSkip1 = -1;
    int iSkip2 = -1;

    for ( i = 0; i < nFields; i++ ) {

        /***** if the field is set to skip, do so *****/

        if ( i == iSkip1 || i == iSkip2 )
            continue;

        /***** if the field isn't set just bail now *****/

        if ( !poOgrFeat->IsFieldSet ( i ) )
            continue;

        OGRFieldDefn *poOgrFieldDef = poOgrFeat->GetFieldDefnRef ( i );
        OGRFieldType type = poOgrFieldDef->GetType (  );
        const char *name = poOgrFieldDef->GetNameRef (  );

        SimpleDataPtr poKmlSimpleData = NULL;
        int year,
            month,
            day,
            hour,
            min,
            sec,
            tz;

        switch ( type ) {

        case OFTString:        //     String of ASCII chars
            {
                char* pszUTF8String = OGRLIBKMLSanitizeUTF8String(
                                        poOgrFeat->GetFieldAsString ( i ));
                /***** name *****/

                if ( EQUAL ( name, namefield ) ) {
                    poKmlPlacemark->set_name ( pszUTF8String );
                    CPLFree( pszUTF8String );
                    continue;
                }

                /***** description *****/

                else if ( EQUAL ( name, descfield ) ) {
                    poKmlPlacemark->set_description ( pszUTF8String );
                    CPLFree( pszUTF8String );
                    continue;
                }

                /***** altitudemode *****/

                else if ( EQUAL ( name, altitudeModefield ) ) {
                    const char *pszAltitudeMode = pszUTF8String ;

                    int isGX = FALSE;
                    int iAltitudeMode = kmldom::ALTITUDEMODE_CLAMPTOGROUND;

                    if ( EQUAL ( pszAltitudeMode, "clampToGround" ) )
                        iAltitudeMode = kmldom::ALTITUDEMODE_CLAMPTOGROUND;

                    else if ( EQUAL ( pszAltitudeMode, "relativeToGround" ) )
                        iAltitudeMode = kmldom::ALTITUDEMODE_RELATIVETOGROUND;

                    else if ( EQUAL ( pszAltitudeMode, "absolute" ) )
                        iAltitudeMode = kmldom::ALTITUDEMODE_ABSOLUTE;

                    else if ( EQUAL ( pszAltitudeMode, "relativeToSeaFloor" ) ) {
                        iAltitudeMode =
                            kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR;
                        isGX = TRUE;
                    }

                    else if ( EQUAL ( pszAltitudeMode, "clampToSeaFloor" ) ) {
                        iAltitudeMode =
                            kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR;
                        isGX = TRUE;
                    }


                    if ( poKmlPlacemark->has_geometry (  ) ) {
                        GeometryPtr poKmlGeometry =
                            poKmlPlacemark->get_geometry (  );

                        ogr2altitudemode_rec ( poKmlGeometry, iAltitudeMode,
                                               isGX );

                    }

                    CPLFree( pszUTF8String );

                    continue;
                }
                
                /***** timestamp *****/

                else if ( EQUAL ( name, tsfield ) ) {

                    TimeStampPtr poKmlTimeStamp =
                        poKmlFactory->CreateTimeStamp (  );
                    poKmlTimeStamp->set_when ( pszUTF8String  );
                    poKmlPlacemark->set_timeprimitive ( poKmlTimeStamp );

                    CPLFree( pszUTF8String );

                    continue;
                }

                /***** begin *****/

                if ( EQUAL ( name, beginfield ) ) {

                    if ( !poKmlTimeSpan ) {
                        poKmlTimeSpan = poKmlFactory->CreateTimeSpan (  );
                        poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
                    }

                    poKmlTimeSpan->set_begin ( pszUTF8String );

                    CPLFree( pszUTF8String );

                    continue;

                }

                /***** end *****/

                else if ( EQUAL ( name, endfield ) ) {

                    if ( !poKmlTimeSpan ) {
                        poKmlTimeSpan = poKmlFactory->CreateTimeSpan (  );
                        poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
                    }

                    poKmlTimeSpan->set_end ( pszUTF8String );

                    CPLFree( pszUTF8String );

                    continue;
                }
                
                /***** other *****/

                poKmlSimpleData = poKmlFactory->CreateSimpleData (  );
                poKmlSimpleData->set_name ( name );
                poKmlSimpleData->set_text ( pszUTF8String );

                CPLFree( pszUTF8String );

                break;
            }

        case OFTDate:          //   Date
            {
                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
                                                &hour, &min, &sec, &tz );

                int iTimeField;

                for ( iTimeField = i + 1; iTimeField < nFields; iTimeField++ ) {
                    if ( iTimeField == iSkip1 || iTimeField == iSkip2 )
                        continue;

                    OGRFieldDefn *poOgrFieldDef2 =
                        poOgrFeat->GetFieldDefnRef ( i );
                    OGRFieldType type2 = poOgrFieldDef2->GetType (  );
                    const char *name2 = poOgrFieldDef2->GetNameRef (  );

                    if ( EQUAL ( name2, name ) && type2 == OFTTime &&
                         ( EQUAL ( name, tsfield ) ||
                           EQUAL ( name, beginfield ) ||
                           EQUAL ( name, endfield ) ) ) {

                        int year2,
                            month2,
                            day2,
                            hour2,
                            min2,
                            sec2,
                            tz2;

                        poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
                                                        &month2, &day2, &hour2,
                                                        &min2, &sec2, &tz2 );

                        hour = hour2;
                        min = min2;
                        sec = sec2;
                        tz = tz2;

                        if ( 0 > iSkip1 )
                            iSkip1 = iTimeField;
                        else
                            iSkip2 = iTimeField;
                    }
                }

                goto Do_DateTime;

            }


        case OFTTime:          //   Time
            {
                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
                                                &hour, &min, &sec, &tz );

                int iTimeField;

                for ( iTimeField = i + 1; iTimeField < nFields; iTimeField++ ) {
                    if ( iTimeField == iSkip1 || iTimeField == iSkip2 )
                        continue;

                    OGRFieldDefn *poOgrFieldDef2 =
                        poOgrFeat->GetFieldDefnRef ( i );
                    OGRFieldType type2 = poOgrFieldDef2->GetType (  );
                    const char *name2 = poOgrFieldDef2->GetNameRef (  );

                    if ( EQUAL ( name2, name ) && type2 == OFTTime &&
                         ( EQUAL ( name, tsfield ) ||
                           EQUAL ( name, beginfield ) ||
                           EQUAL ( name, endfield ) ) ) {

                        int year2,
                            month2,
                            day2,
                            hour2,
                            min2,
                            sec2,
                            tz2;

                        poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
                                                        &month2, &day2, &hour2,
                                                        &min2, &sec2, &tz2 );

                        year = year2;
                        month = month2;
                        day = day2;

                        if ( 0 > iSkip1 )
                            iSkip1 = iTimeField;
                        else
                            iSkip2 = iTimeField;
                    }
                }

                goto Do_DateTime;

            }

        case OFTDateTime:      //  Date and Time
            {
                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
                                                &hour, &min, &sec, &tz );

              Do_DateTime:
                /***** timestamp *****/

                if ( EQUAL ( name, tsfield ) ) {

                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
                                                        min, sec, tz );

                    TimeStampPtr poKmlTimeStamp =
                        poKmlFactory->CreateTimeStamp (  );
                    poKmlTimeStamp->set_when ( timebuf );
                    poKmlPlacemark->set_timeprimitive ( poKmlTimeStamp );
                    CPLFree( timebuf );

                    continue;
                }

                /***** begin *****/

                if ( EQUAL ( name, beginfield ) ) {

                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
                                                        min, sec, tz );

                    if ( !poKmlTimeSpan ) {
                        poKmlTimeSpan = poKmlFactory->CreateTimeSpan (  );
                        poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
                    }

                    poKmlTimeSpan->set_begin ( timebuf );
                    CPLFree( timebuf );

                    continue;

                }

                /***** end *****/

                else if ( EQUAL ( name, endfield ) ) {

                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
                                                        min, sec, tz );


                    if ( !poKmlTimeSpan ) {
                        poKmlTimeSpan = poKmlFactory->CreateTimeSpan (  );
                        poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
                    }

                    poKmlTimeSpan->set_end ( timebuf );
                    CPLFree( timebuf );

                    continue;
                }

                /***** other *****/

                poKmlSimpleData = poKmlFactory->CreateSimpleData (  );
                poKmlSimpleData->set_name ( name );
                poKmlSimpleData->set_text ( poOgrFeat->
                                            GetFieldAsString ( i ) );

                break;
            }

        case OFTInteger:       //    Simple 32bit integer

            /***** extrude *****/

            if ( EQUAL ( name, extrudefield ) ) {

                if ( poKmlPlacemark->has_geometry (  )
                     && -1 < poOgrFeat->GetFieldAsInteger ( i ) ) {
                    GeometryPtr poKmlGeometry =
                        poKmlPlacemark->get_geometry (  );
                    ogr2extrude_rec ( poOgrFeat->GetFieldAsInteger ( i ),
                                      poKmlGeometry );
                }
                continue;
            }

            /***** tessellate *****/


            if ( EQUAL ( name, tessellatefield ) ) {

                if ( poKmlPlacemark->has_geometry (  )
                     && -1 < poOgrFeat->GetFieldAsInteger ( i ) ) {
                    GeometryPtr poKmlGeometry =
                        poKmlPlacemark->get_geometry (  );
                    ogr2tessellate_rec ( poOgrFeat->GetFieldAsInteger ( i ),
                                         poKmlGeometry );
                }

                continue;
            }


            /***** visibility *****/

            if ( EQUAL ( name, visibilityfield ) ) {
                if ( -1 < poOgrFeat->GetFieldAsInteger ( i ) )
                    poKmlPlacemark->set_visibility ( poOgrFeat->
                                                     GetFieldAsInteger ( i ) );

                continue;
            }

            /***** other *****/

            poKmlSimpleData = poKmlFactory->CreateSimpleData (  );
            poKmlSimpleData->set_name ( name );
            poKmlSimpleData->set_text ( poOgrFeat->GetFieldAsString ( i ) );

            break;

        case OFTReal:          //   Double Precision floating point
        {
            poKmlSimpleData = poKmlFactory->CreateSimpleData (  );
            poKmlSimpleData->set_name ( name );

            char* pszStr = CPLStrdup( poOgrFeat->GetFieldAsString ( i ) );
            /* Use point as decimal separator */
            char* pszComma = strchr(pszStr, ',');
            if (pszComma)
                *pszComma = '.';
            poKmlSimpleData->set_text ( pszStr );
            CPLFree(pszStr);

            break;
        }

        case OFTStringList:    //     Array of strings
        case OFTIntegerList:   //    List of 32bit integers
        case OFTRealList:   //    List of doubles
        case OFTBinary:        //     Raw Binary data
        case OFTWideStringList:    //     deprecated
        default:

        /***** other *****/

            poKmlSimpleData = poKmlFactory->CreateSimpleData (  );
            poKmlSimpleData->set_name ( name );
            poKmlSimpleData->set_text ( poOgrFeat->GetFieldAsString ( i ) );

            break;
        }
        poKmlSchemaData->add_simpledata ( poKmlSimpleData );
    }

    /***** dont add it to the placemark unless there is data *****/

    if ( poKmlSchemaData->get_simpledata_array_size (  ) > 0 ) {
        ExtendedDataPtr poKmlExtendedData =
            poKmlFactory->CreateExtendedData (  );
        poKmlExtendedData->add_schemadata ( poKmlSchemaData );
        poKmlPlacemark->set_extendeddata ( poKmlExtendedData );
    }

    return;
}