示例#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;
}
示例#2
0
void kml2field (
    OGRFeature * poOgrFeat,
    PlacemarkPtr poKmlPlacemark )
{

    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" );

    /***** name *****/

    if ( poKmlPlacemark->has_name (  ) ) {
        const std::string oKmlName = poKmlPlacemark->get_name (  );
        int iField = poOgrFeat->GetFieldIndex ( namefield );

        if ( iField > -1 )
            poOgrFeat->SetField ( iField, oKmlName.c_str (  ) );
    }

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

    if ( poKmlPlacemark->has_description (  ) ) {
        const std::string oKmlDesc = poKmlPlacemark->get_description (  );
        int iField = poOgrFeat->GetFieldIndex ( descfield );

        if ( iField > -1 )
            poOgrFeat->SetField ( iField, oKmlDesc.c_str (  ) );
    }

    if ( poKmlPlacemark->has_timeprimitive (  ) ) {
        TimePrimitivePtr poKmlTimePrimitive =
            poKmlPlacemark->get_timeprimitive (  );

        /***** timestamp *****/

        if ( poKmlTimePrimitive->IsA ( kmldom::Type_TimeStamp ) ) {
            TimeStampPtr poKmlTimeStamp = AsTimeStamp ( poKmlTimePrimitive );

            if ( poKmlTimeStamp->has_when (  ) ) {
                const std::string oKmlWhen = poKmlTimeStamp->get_when (  );


                int iField = poOgrFeat->GetFieldIndex ( tsfield );

                if ( iField > -1 ) {
                    int nYear,
                        nMonth,
                        nDay,
                        nHour,
                        nMinute,
                        nTZ;
                    float fSecond;

                    if ( OGRParseXMLDateTime
                         ( oKmlWhen.c_str (  ), &nYear, &nMonth, &nDay, &nHour,
                           &nMinute, &fSecond, &nTZ ) )
                        poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
                                              nHour, nMinute, ( int )fSecond,
                                              nTZ );
                }
            }
        }

        /***** timespan *****/

        if ( poKmlTimePrimitive->IsA ( kmldom::Type_TimeSpan ) ) {
            TimeSpanPtr poKmlTimeSpan = AsTimeSpan ( poKmlTimePrimitive );

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

            if ( poKmlTimeSpan->has_begin (  ) ) {
                const std::string oKmlWhen = poKmlTimeSpan->get_begin (  );


                int iField = poOgrFeat->GetFieldIndex ( beginfield );

                if ( iField > -1 ) {
                    int nYear,
                        nMonth,
                        nDay,
                        nHour,
                        nMinute,
                        nTZ;
                    float fSecond;

                    if ( OGRParseXMLDateTime
                         ( oKmlWhen.c_str (  ), &nYear, &nMonth, &nDay, &nHour,
                           &nMinute, &fSecond, &nTZ ) )
                        poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
                                              nHour, nMinute, ( int )fSecond,
                                              nTZ );
                }
            }

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

            if ( poKmlTimeSpan->has_end (  ) ) {
                const std::string oKmlWhen = poKmlTimeSpan->get_end (  );


                int iField = poOgrFeat->GetFieldIndex ( endfield );

                if ( iField > -1 ) {
                    int nYear,
                        nMonth,
                        nDay,
                        nHour,
                        nMinute,
                        nTZ;
                    float fSecond;

                    if ( OGRParseXMLDateTime
                         ( oKmlWhen.c_str (  ), &nYear, &nMonth, &nDay, &nHour,
                           &nMinute, &fSecond, &nTZ ) )
                        poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
                                              nHour, nMinute, ( int )fSecond,
                                              nTZ );
                }
            }
        }
    }


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

        /***** altitudeMode *****/


        int bIsGX = FALSE;
        int nAltitudeMode = -1;

        int iField = poOgrFeat->GetFieldIndex ( altitudeModefield );

        if ( iField > -1 ) {

            if ( kml2altitudemode_rec ( poKmlGeometry,
                                        &nAltitudeMode, &bIsGX ) ) {

                if ( !bIsGX ) {

                    switch ( nAltitudeMode ) {
                    case kmldom::ALTITUDEMODE_CLAMPTOGROUND:
                        poOgrFeat->SetField ( iField, "clampToGround" );
                        break;

                    case kmldom::ALTITUDEMODE_RELATIVETOGROUND:
                        poOgrFeat->SetField ( iField, "relativeToGround" );
                        break;

                    case kmldom::ALTITUDEMODE_ABSOLUTE:
                        poOgrFeat->SetField ( iField, "absolute" );
                        break;

                    }
                }

                else {
                    switch ( nAltitudeMode ) {
                    case kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR:
                        poOgrFeat->SetField ( iField, "relativeToSeaFloor" );
                        break;

                    case kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR:
                        poOgrFeat->SetField ( iField, "clampToSeaFloor" );
                        break;
                    }

                }
            }

        }

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

        int nTessellate = -1;

        kml2tessellate_rec ( poKmlGeometry, &nTessellate );

        iField = poOgrFeat->GetFieldIndex ( tessellatefield );
        if ( iField > -1 )
            poOgrFeat->SetField ( iField, nTessellate );

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

        int nExtrude = -1;

        kml2extrude_rec ( poKmlGeometry, &nExtrude );

        iField = poOgrFeat->GetFieldIndex ( extrudefield );
        if ( iField > -1 )
            poOgrFeat->SetField ( iField, nExtrude );

    }

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

    int nVisibility = -1;

    if ( poKmlPlacemark->has_visibility (  ) )
        nVisibility = poKmlPlacemark->get_visibility (  );

    int iField = poOgrFeat->GetFieldIndex ( visibilityfield );

    if ( iField > -1 )
        poOgrFeat->SetField ( iField, nVisibility );

    ExtendedDataPtr poKmlExtendedData = NULL;

    if ( poKmlPlacemark->has_extendeddata (  ) ) {
        poKmlExtendedData = poKmlPlacemark->get_extendeddata (  );

        /***** loop over the schemadata_arrays *****/

        size_t nSchemaData = poKmlExtendedData->get_schemadata_array_size (  );

        size_t iSchemaData;

        for ( iSchemaData = 0; iSchemaData < nSchemaData; iSchemaData++ ) {
            SchemaDataPtr poKmlSchemaData =
                poKmlExtendedData->get_schemadata_array_at ( iSchemaData );

            /***** loop over the simpledata array *****/

            size_t nSimpleData =
                poKmlSchemaData->get_simpledata_array_size (  );

            size_t iSimpleData;

            for ( iSimpleData = 0; iSimpleData < nSimpleData; iSimpleData++ ) {
                SimpleDataPtr poKmlSimpleData =
                    poKmlSchemaData->get_simpledata_array_at ( iSimpleData );

                /***** find the field index *****/

                int iField = -1;

                if ( poKmlSimpleData->has_name (  ) ) {
                    const string oName = poKmlSimpleData->get_name (  );
                    const char *pszName = oName.c_str (  );

                    iField = poOgrFeat->GetFieldIndex ( pszName );
                }

                /***** if it has trxt set the field *****/

                if ( iField > -1 && poKmlSimpleData->has_text (  ) ) {
                    string oText = poKmlSimpleData->get_text (  );

                    /* SerializePretty() adds a new line before the data */
                    /* ands trailing spaces. I believe this is wrong */
                    /* as it breaks round-tripping */

                    /* Trim trailing spaces */
                    while (oText.size() != 0 && oText[oText.size()-1] == ' ')
                        oText.resize(oText.size()-1);

                    /* Skip leading newline and spaces */
                    const char* pszText = oText.c_str (  );
                    if (pszText[0] == '\n')
                        pszText ++;
                    while (pszText[0] == ' ')
                        pszText ++;

                    poOgrFeat->SetField ( iField, pszText );
                }
            }
        }

        if (nSchemaData == 0 &&  poKmlExtendedData->get_data_array_size() > 0 )
        {
            int bLaunderFieldNames =
                        CSLTestBoolean(CPLGetConfigOption("LIBKML_LAUNDER_FIELD_NAMES", "YES"));
            size_t nDataArraySize = poKmlExtendedData->get_data_array_size();
            for(size_t i=0; i < nDataArraySize; i++)
            {
                const DataPtr& data = poKmlExtendedData->get_data_array_at(i);
                if (data->has_name() && data->has_value())
                {
                    CPLString osName = data->get_name();
                    if (bLaunderFieldNames)
                        osName = OGRLIBKMLLayer::LaunderFieldNames(osName);
                    int iField = poOgrFeat->GetFieldIndex ( osName );
                    if (iField >= 0)
                    {
                        poOgrFeat->SetField ( iField, data->get_value().c_str() );
                    }
                }
            }
        }
    }

}
示例#3
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;
}
示例#4
0
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;
}