Ejemplo n.º 1
0
OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
                                 OGRSpatialReference * poSpatialRef,
                                 OGRwkbGeometryType eGType,
                                 OGRLIBKMLDataSource * poOgrDS,
                                 ElementPtr poKmlRoot,
                                 ContainerPtr poKmlContainer,
                                 UpdatePtr poKmlUpdate,
                                 const char *pszFileName,
                                 int bNew,
                                 int bUpdateIn )
{

    m_poStyleTable = NULL;
    iFeature = 0;
    nFeatures = 0;
    nFID = 1;

    this->bUpdate = bUpdateIn;
    bUpdated = FALSE;
    m_pszName = CPLStrdup ( pszLayerName );
    m_pszFileName = CPLStrdup ( pszFileName );
    m_poOgrDS = poOgrDS;

    m_poOgrSRS = new OGRSpatialReference ( NULL );
    m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );

    m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
    SetDescription( m_poOgrFeatureDefn->GetName() );
    m_poOgrFeatureDefn->Reference (  );
    m_poOgrFeatureDefn->SetGeomType ( eGType );
    if( m_poOgrFeatureDefn->GetGeomFieldCount() != 0 )
        m_poOgrFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poOgrSRS);

    /***** store the root element pointer *****/

    m_poKmlLayerRoot = poKmlRoot;

    /***** store the layers container *****/

    m_poKmlLayer = poKmlContainer;

    /* update container */
    m_poKmlUpdate = poKmlUpdate;

    m_poKmlSchema = NULL;

    /***** related to Region *****/

    m_bWriteRegion = FALSE;
    m_bRegionBoundsAuto = FALSE;
    m_dfRegionMinLodPixels = 0;
    m_dfRegionMaxLodPixels = -1;
    m_dfRegionMinFadeExtent = 0;
    m_dfRegionMaxFadeExtent = 0;
    m_dfRegionMinX = 200;
    m_dfRegionMinY = 200;
    m_dfRegionMaxX = -200;
    m_dfRegionMaxY = -200;


    m_bReadGroundOverlay = CPLTestBool(
        CPLGetConfigOption("LIBKML_READ_GROUND_OVERLAY", "YES"));
    m_bUseSimpleField = CPLTestBool(
        CPLGetConfigOption("LIBKML_USE_SIMPLEFIELD", "YES"));

    m_bUpdateIsFolder = FALSE;

    /***** was the layer created from a DS::Open *****/

    if ( !bNew ) {

        /***** get the number of features on the layer *****/

        nFeatures = static_cast<int>(m_poKmlLayer->get_feature_array_size (  ));

        /***** get the field config *****/

        struct fieldconfig oFC;
        get_fieldconfig( &oFC );

        /***** name field *****/

        OGRFieldDefn oOgrFieldName ( oFC.namefield,OFTString );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );

        /***** description field *****/

        OGRFieldDefn oOgrFieldDesc ( oFC.descfield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDesc );

        /***** timestamp field *****/

        OGRFieldDefn oOgrFieldTs ( oFC.tsfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTs );

        /*****  timespan begin field *****/

        OGRFieldDefn oOgrFieldBegin ( oFC.beginfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldBegin );

        /*****  timespan end field *****/

        OGRFieldDefn oOgrFieldEnd ( oFC.endfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldEnd );

        /*****  altitudeMode field *****/

        OGRFieldDefn oOgrFieldAltitudeMode ( oFC.altitudeModefield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldAltitudeMode );

        /***** tessellate field *****/

        OGRFieldDefn oOgrFieldTessellate ( oFC.tessellatefield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTessellate );

        /***** extrude field *****/

        OGRFieldDefn oOgrFieldExtrude ( oFC.extrudefield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldExtrude );

        /***** visibility field *****/

        OGRFieldDefn oOgrFieldVisibility ( oFC.visibilityfield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldVisibility );

        /***** draw order field *****/

        OGRFieldDefn oOgrFieldDrawOrder ( oFC.drawOrderfield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDrawOrder );

        /***** icon field *****/

        OGRFieldDefn oOgrFieldIcon ( oFC.iconfield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldIcon );

        /***** get the styles *****/

        if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) )
            ParseStyles ( AsDocument ( m_poKmlLayer ), &m_poStyleTable );

        /***** get the schema if the layer is a Document *****/

        if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
            DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );

            if ( poKmlDocument->get_schema_array_size (  ) ) {
                m_poKmlSchema = poKmlDocument->get_schema_array_at ( 0 );
                kml2FeatureDef ( m_poKmlSchema, m_poOgrFeatureDefn );
            }
        }

        /***** the schema is somewhere else *****/

        if (m_poKmlSchema == NULL) {

            /***** try to find the correct schema *****/

            int bHasHeading = FALSE, bHasTilt = FALSE, bHasRoll = FALSE;
            int bHasSnippet = FALSE;
            FeaturePtr poKmlFeature;

            /***** find the first placemark *****/

            do {
                if ( iFeature >= nFeatures )
                    break;

                poKmlFeature =
                    m_poKmlLayer->get_feature_array_at ( iFeature++ );

                if( poKmlFeature->Type() == kmldom::Type_Placemark )
                {
                    PlacemarkPtr poKmlPlacemark = AsPlacemark ( poKmlFeature );
                    if( !poKmlPlacemark->has_geometry (  ) &&
                        poKmlPlacemark->has_abstractview (  ) &&
                        poKmlPlacemark->get_abstractview()->IsA( kmldom::Type_Camera) )
                    {
                        const CameraPtr& camera = AsCamera(poKmlPlacemark->get_abstractview());
                        if( camera->has_heading() && !bHasHeading )
                        {
                            bHasHeading = TRUE;
                            OGRFieldDefn oOgrField ( oFC.headingfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                        }
                        if( camera->has_tilt() && !bHasTilt )
                        {
                            bHasTilt = TRUE;
                            OGRFieldDefn oOgrField ( oFC.tiltfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                        }
                        if( camera->has_roll() && !bHasRoll )
                        {
                            bHasRoll = TRUE;
                            OGRFieldDefn oOgrField ( oFC.rollfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                        }
                    }
                }
                if( !bHasSnippet && poKmlFeature->has_snippet() )
                {
                    bHasSnippet = TRUE;
                    OGRFieldDefn oOgrField ( oFC.snippetfield, OFTString );
                    m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                }
            } while ( poKmlFeature->Type (  ) != kmldom::Type_Placemark );

            if ( iFeature <= nFeatures && poKmlFeature &&
                 poKmlFeature->Type (  ) == kmldom::Type_Placemark &&
                 poKmlFeature->has_extendeddata (  ) ) {

                ExtendedDataPtr poKmlExtendedData = poKmlFeature->
                    get_extendeddata (  );

                if ( poKmlExtendedData->get_schemadata_array_size (  ) > 0 ) {
                    SchemaDataPtr poKmlSchemaData = poKmlExtendedData->
                        get_schemadata_array_at ( 0 );

                    if ( poKmlSchemaData->has_schemaurl (  ) ) {

                        std::string oKmlSchemaUrl = poKmlSchemaData->
                            get_schemaurl (  );
                        if ( ( m_poKmlSchema =
                               m_poOgrDS->FindSchema ( oKmlSchemaUrl.
                                                       c_str (  ) ) ) ) {
                            kml2FeatureDef ( m_poKmlSchema,
                                             m_poOgrFeatureDefn );
                        }
                    }
                }
                else if ( poKmlExtendedData->get_data_array_size() > 0 )
                {
                    /* Use the <Data> of the first placemark to build the feature definition */
                    /* If others have different fields, too bad... */
                    int bLaunderFieldNames =
                        CPLTestBool(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())
                        {
                            CPLString osName = data->get_name();
                            if (bLaunderFieldNames)
                                osName = LaunderFieldNames(osName);
                            OGRFieldDefn oOgrField ( osName,
                                                    OFTString );
                            m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                        }
                    }
                }
            }

            iFeature = 0;

        }



        /***** check if any features are another layer *****/

        m_poOgrDS->ParseLayers ( m_poKmlLayer, poSpatialRef );

    }

    /***** it was from a DS::CreateLayer *****/

    else {

        /***** mark the layer as updated *****/

        bUpdated = TRUE;
    }

}
Ejemplo n.º 2
0
OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
                                 OGRSpatialReference * poSpatialRef,
                                 OGRwkbGeometryType eGType,
                                 OGRLIBKMLDataSource * poOgrDS,
                                 ElementPtr poKmlRoot,
                                 ContainerPtr poKmlContainer,
                                 const char *pszFileName,
                                 int bNew,
                                 int bUpdate )
{

    m_poStyleTable = NULL;
    iFeature = 0;
    nFeatures = 0;
    nFID = 1;

    this->bUpdate = bUpdate;
    m_pszName = CPLStrdup ( pszLayerName );
    m_pszFileName = CPLStrdup ( pszFileName );
    m_poOgrDS = poOgrDS;

    m_poOgrSRS = new OGRSpatialReference ( NULL );
    m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );

    m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
    m_poOgrFeatureDefn->Reference (  );
    m_poOgrFeatureDefn->SetGeomType ( eGType );

    /***** store the root element pointer *****/

    m_poKmlLayerRoot = poKmlRoot;
    
    /***** store the layers container *****/

    m_poKmlLayer = poKmlContainer;

    /***** was the layer created from a DS::Open *****/

    if ( !bNew ) {

        /***** get the number of features on the layer *****/

        nFeatures = m_poKmlLayer->get_feature_array_size (  );

        /***** add the name and desc fields *****/

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

        OGRFieldDefn oOgrFieldName (
    namefield,
    OFTString );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );

        OGRFieldDefn oOgrFieldDesc (
    descfield,
    OFTString );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDesc );

        OGRFieldDefn oOgrFieldTs (
    tsfield,
    OFTDateTime );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTs );

        OGRFieldDefn oOgrFieldBegin (
    beginfield,
    OFTDateTime );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldBegin );

        OGRFieldDefn oOgrFieldEnd (
    endfield,
    OFTDateTime );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldEnd );

        OGRFieldDefn oOgrFieldAltitudeMode (
    altitudeModefield,
    OFTString );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldAltitudeMode );

        OGRFieldDefn oOgrFieldTessellate (
    tessellatefield,
    OFTInteger );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTessellate );

        OGRFieldDefn oOgrFieldExtrude (
    extrudefield,
    OFTInteger );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldExtrude );

        OGRFieldDefn oOgrFieldVisibility (
    visibilityfield,
    OFTInteger );

        m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldVisibility );

        /***** get the styles *****/

        if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) )
            ParseStyles ( AsDocument ( m_poKmlLayer ), &m_poStyleTable );

        /***** get the schema if the layer is a Document *****/

        m_poKmlSchema = NULL;

        if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
            DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );

            if ( poKmlDocument->get_schema_array_size (  ) ) {
                m_poKmlSchema = poKmlDocument->get_schema_array_at ( 0 );
                kml2FeatureDef ( m_poKmlSchema, m_poOgrFeatureDefn );
            }
        }

        /***** the schema is somewhere else *****/

        if (m_poKmlSchema == NULL) {

            /***** try to find the correct schema *****/

            FeaturePtr poKmlFeature;

            /***** find the first placemark *****/

            do {
                if ( iFeature >= nFeatures )
                    break;

                poKmlFeature =
                    m_poKmlLayer->get_feature_array_at ( iFeature++ );

            } while ( poKmlFeature->Type (  ) != kmldom::Type_Placemark );

            if ( iFeature <= nFeatures && poKmlFeature &&
                 poKmlFeature->Type (  ) == kmldom::Type_Placemark &&
                 poKmlFeature->has_extendeddata (  ) ) {

                ExtendedDataPtr poKmlExtendedData = poKmlFeature->
                    get_extendeddata (  );

                if ( poKmlExtendedData->get_schemadata_array_size (  ) > 0 ) {
                    SchemaDataPtr poKmlSchemaData = poKmlExtendedData->
                        get_schemadata_array_at ( 0 );

                    if ( poKmlSchemaData->has_schemaurl (  ) ) {

                        std::string oKmlSchemaUrl = poKmlSchemaData->
                            get_schemaurl (  );
                        if ( ( m_poKmlSchema =
                               m_poOgrDS->FindSchema ( oKmlSchemaUrl.
                                                       c_str (  ) ) ) ) {
                            kml2FeatureDef ( m_poKmlSchema,
                                             m_poOgrFeatureDefn );
                        }
                    }
                }
                else if ( poKmlExtendedData->get_data_array_size() > 0 )
                {
                    /* Use the <Data> of the first placemark to build the feature definition */
                    /* If others have different fields, too bad... */
                    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())
                        {
                            CPLString osName = data->get_name();
                            if (bLaunderFieldNames)
                                osName = LaunderFieldNames(osName);
                            OGRFieldDefn oOgrField ( osName,
                                                    OFTString );
                            m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
                        }
                    }
                }
            }

            iFeature = 0;

        }



        /***** check if any features are another layer *****/

        m_poOgrDS->ParseLayers ( m_poKmlLayer, poSpatialRef );

    }

    /***** it was from a DS::CreateLayer *****/

    else {

        /***** mark the layer as updated *****/

        bUpdated = TRUE;

        /***** create a new schema *****/

        KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory (  );

        m_poKmlSchema = poKmlFactory->CreateSchema (  );

        /***** set the id on the new schema *****/

        std::string oKmlSchemaID = m_pszName;
        oKmlSchemaID.append ( ".schema" );
        m_poKmlSchema->set_id ( oKmlSchemaID );
    }




}
Ejemplo n.º 3
0
OGRLIBKMLLayer::OGRLIBKMLLayer( const char *pszLayerName,
                                OGRwkbGeometryType eGType,
                                OGRLIBKMLDataSource * poOgrDS,
                                ElementPtr poKmlRoot,
                                ContainerPtr poKmlContainer,
                                UpdatePtr poKmlUpdate,
                                const char *pszFileName,
                                int bNew,
                                int bUpdateIn ) :
    bUpdate(CPL_TO_BOOL(bUpdateIn)),
    nFeatures(0),
    iFeature(0),
    nFID(1),
    m_pszName(CPLStrdup(pszLayerName)),
    m_pszFileName(CPLStrdup(pszFileName)),
    m_poKmlLayer(poKmlContainer),  // Store the layers container.
    m_poKmlLayerRoot(poKmlRoot),  // Store the root element pointer.
    m_poKmlUpdate(poKmlUpdate),
    m_poOgrDS(poOgrDS),
    m_poOgrFeatureDefn(new OGRFeatureDefn(pszLayerName)),
    m_poKmlSchema(nullptr),
    m_poOgrSRS(new OGRSpatialReference(nullptr)),
    m_bReadGroundOverlay(CPLTestBool(
        CPLGetConfigOption("LIBKML_READ_GROUND_OVERLAY", "YES"))),
    m_bUseSimpleField(CPLTestBool(
        CPLGetConfigOption("LIBKML_USE_SIMPLEFIELD", "YES"))),
    m_bWriteRegion(false),
    m_bRegionBoundsAuto(false),
    m_dfRegionMinLodPixels(0),
    m_dfRegionMaxLodPixels(-1),
    m_dfRegionMinFadeExtent(0),
    m_dfRegionMaxFadeExtent(0),
    m_dfRegionMinX(200),
    m_dfRegionMinY(200),
    m_dfRegionMaxX(-200),
    m_dfRegionMaxY(-200),
    m_bUpdateIsFolder(false)
{
    m_poStyleTable = nullptr;
    m_poOgrSRS->SetWellKnownGeogCS( "WGS84" );
    m_poOgrSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);

    SetDescription( m_poOgrFeatureDefn->GetName() );
    m_poOgrFeatureDefn->Reference();
    m_poOgrFeatureDefn->SetGeomType( eGType );
    if( m_poOgrFeatureDefn->GetGeomFieldCount() != 0 )
        m_poOgrFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poOgrSRS);

    /***** was the layer created from a DS::Open *****/
    if( !bNew )
    {
        /***** get the number of features on the layer *****/
        nFeatures = static_cast<int>(m_poKmlLayer->get_feature_array_size());

        /***** get the field config *****/
        struct fieldconfig oFC;
        get_fieldconfig( &oFC );

        /***** name field *****/
        OGRFieldDefn oOgrFieldName( oFC.namefield,OFTString );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldName );

        /***** description field *****/
        OGRFieldDefn oOgrFieldDesc( oFC.descfield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldDesc );

        /***** timestamp field *****/
        OGRFieldDefn oOgrFieldTs( oFC.tsfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldTs );

        /*****  timespan begin field *****/
        OGRFieldDefn oOgrFieldBegin( oFC.beginfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldBegin );

        /*****  timespan end field *****/
        OGRFieldDefn oOgrFieldEnd( oFC.endfield, OFTDateTime );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldEnd );

        /*****  altitudeMode field *****/
        OGRFieldDefn oOgrFieldAltitudeMode( oFC.altitudeModefield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldAltitudeMode );

        /***** tessellate field *****/
        OGRFieldDefn oOgrFieldTessellate( oFC.tessellatefield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldTessellate );

        /***** extrude field *****/
        OGRFieldDefn oOgrFieldExtrude( oFC.extrudefield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldExtrude );

        /***** visibility field *****/
        OGRFieldDefn oOgrFieldVisibility( oFC.visibilityfield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldVisibility );

        /***** draw order field *****/
        OGRFieldDefn oOgrFieldDrawOrder( oFC.drawOrderfield, OFTInteger );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldDrawOrder );

        /***** icon field *****/
        OGRFieldDefn oOgrFieldIcon( oFC.iconfield, OFTString );
        m_poOgrFeatureDefn->AddFieldDefn( &oOgrFieldIcon );

        /***** get the styles *****/
        if( m_poKmlLayer->IsA( kmldom::Type_Document ) )
            ParseStyles( AsDocument ( m_poKmlLayer ), &m_poStyleTable );

        bool bCanSetKmlSchema = true;

        /***** get the schema if the layer is a Document *****/
        if( m_poKmlLayer->IsA( kmldom::Type_Document ) )
        {
            DocumentPtr poKmlDocument = AsDocument( m_poKmlLayer );

            if( poKmlDocument->get_schema_array_size() )
            {
                for(size_t i = 0; i < poKmlDocument->get_schema_array_size(); i++ )
                {
                    auto schema = poKmlDocument->get_schema_array_at( i );
                    if( bCanSetKmlSchema && !m_poKmlSchema )
                    {
                        m_poKmlSchema = schema;
                        bCanSetKmlSchema = false;
                    }
                    else
                    {
                        m_poKmlSchema = nullptr;
                    }
                    kml2FeatureDef( schema, m_poOgrFeatureDefn );
                }
            }
        }

        /***** the schema is somewhere else *****/
        if( bCanSetKmlSchema )
        {
            /***** try to find the correct schema *****/
            bool bHasHeading = false;
            bool bHasTilt = false;
            bool bHasRoll = false;
            bool bHasSnippet = false;
            FeaturePtr poKmlFeature = nullptr;
            const bool bLaunderFieldNames =
                CPLTestBool(CPLGetConfigOption(
                    "LIBKML_LAUNDER_FIELD_NAMES", "YES"));
            std::set<std::string> oSetSchemaAlreadyVisited;

            /***** find the first placemark *****/
            for( iFeature = 0; iFeature < nFeatures; iFeature++ )
            {
                poKmlFeature =
                    m_poKmlLayer->get_feature_array_at( iFeature );

                if( poKmlFeature->Type() == kmldom::Type_Placemark )
                {
                    PlacemarkPtr poKmlPlacemark = AsPlacemark( poKmlFeature );
                    if( !poKmlPlacemark->has_geometry() &&
                        poKmlPlacemark->has_abstractview() &&
                        poKmlPlacemark->get_abstractview()->
                            IsA( kmldom::Type_Camera) )
                    {
                        const CameraPtr& camera =
                            AsCamera(poKmlPlacemark->get_abstractview());
                        if( camera->has_heading() && !bHasHeading )
                        {
                            bHasHeading = true;
                            OGRFieldDefn oOgrField( oFC.headingfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn( &oOgrField );
                        }
                        if( camera->has_tilt() && !bHasTilt )
                        {
                            bHasTilt = true;
                            OGRFieldDefn oOgrField( oFC.tiltfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn( &oOgrField );
                        }
                        if( camera->has_roll() && !bHasRoll )
                        {
                            bHasRoll = true;
                            OGRFieldDefn oOgrField( oFC.rollfield, OFTReal );
                            m_poOgrFeatureDefn->AddFieldDefn( &oOgrField );
                        }
                    }

                    if( poKmlFeature->has_extendeddata() )
                    {
                        const ExtendedDataPtr poKmlExtendedData =
                            poKmlFeature->get_extendeddata();

                        if( poKmlExtendedData->get_schemadata_array_size() > 0 )
                        {
                            const SchemaDataPtr poKmlSchemaData =
                                poKmlExtendedData->get_schemadata_array_at( 0 );

                            if( poKmlSchemaData->has_schemaurl() )
                            {
                                std::string oKmlSchemaUrl =
                                    poKmlSchemaData->get_schemaurl();
                                if( oSetSchemaAlreadyVisited.find(
                                        oKmlSchemaUrl) ==
                                            oSetSchemaAlreadyVisited.end() )
                                {
                                    oSetSchemaAlreadyVisited.insert(
                                        oKmlSchemaUrl);
                                    auto schema = m_poOgrDS->FindSchema(
                                            oKmlSchemaUrl.c_str() );
                                    if( schema )
                                    {
                                        if( bCanSetKmlSchema && !m_poKmlSchema )
                                        {
                                            m_poKmlSchema = schema;
                                            bCanSetKmlSchema = false;
                                        }
                                        else
                                        {
                                            m_poKmlSchema = nullptr;
                                        }
                                        kml2FeatureDef( schema, m_poOgrFeatureDefn );
                                    }
                                }
                            }
                        }
                        else if( poKmlExtendedData->get_data_array_size() > 0 )
                        {
                            const 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() )
                                {
                                    CPLString osName = std::string(data->get_name());
                                    if( bLaunderFieldNames )
                                        osName = LaunderFieldNames(osName);
                                    if( m_poOgrFeatureDefn->GetFieldIndex(osName) < 0 )
                                    {
                                        OGRFieldDefn oOgrField( osName, OFTString );
                                        m_poOgrFeatureDefn->AddFieldDefn( &oOgrField );
                                    }
                                }
                            }
                        }
                    }
                }
                if( !bHasSnippet && poKmlFeature->has_snippet() )
                {
                    bHasSnippet = true;
                    OGRFieldDefn oOgrField( oFC.snippetfield, OFTString );
                    m_poOgrFeatureDefn->AddFieldDefn( &oOgrField );
                }
            }

            iFeature = 0;
        }
    }
}