Beispiel #1
0
    def to_fields(selected_fields: Optional[List[str]]) -> QgsFields:
        """
        Returns station fields
        """
        from ..fields import FIELD_TYPE_MAP  # pylint: disable=import-outside-toplevel

        fields = QgsFields()
        settings = QgsSettings()

        short_field_names = settings.value(
            '/plugins/qquake/output_short_field_names', True, bool)
        field_config_key = 'field_short' if short_field_names else 'field_long'

        for group in ['general', 'network', 'station']:
            for f in SERVICE_MANAGER.get_field_config(
                    SERVICE_MANAGER.FDSNSTATION
            )['field_groups'][group]['fields']:
                if f.get('skip'):
                    continue

                if f.get('one_to_many'):
                    continue

                path = f['source']
                if selected_fields:
                    selected = path in selected_fields
                else:
                    path = path[len('FDSNStationXML>'):].replace('§',
                                                                 '>').replace(
                                                                     '>', '_')
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(path), True,
                        bool)
                if not selected:
                    continue

                fields.append(
                    QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))
        return fields
    def __init__(
            self,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            service_type: str,
            service_id: str,
            initial_fields: List[str],
            parent=None):
        """Constructor."""
        super().__init__(parent)
        self.setupUi(self)
        self.service_type = service_type
        self.service_id = service_id

        service_config = SERVICE_MANAGER.service_details(
            service_type, service_id)

        self.setWindowTitle(self.tr('Output Table Options'))

        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        QgsGui.enableAutoGeometryRestore(self)
        self.default_fields = None

        s = QgsSettings()

        short_field_names = s.value('/plugins/qquake/output_short_field_names',
                                    True, bool)
        if short_field_names:
            self.radio_short_fields.setChecked(True)
        else:
            self.radio_long_fields.setChecked(True)

        self.radio_short_fields.toggled.connect(self.change_field_names)

        nodes = []
        for _, settings in SERVICE_MANAGER.get_field_config(
                self.service_type)['field_groups'].items():
            if self.service_type != SERVICE_MANAGER.FDSNSTATION and settings[
                    'label'] == 'station':
                continue
            if self.service_type == SERVICE_MANAGER.FDSNSTATION and settings[
                    'label'] not in ('station', 'general', 'network'):
                continue

            parent_node = ModelNode([settings['label']])
            for f in settings['fields']:
                if f.get('skip'):
                    continue

                if f['source'] is not None:
                    if f['source'].startswith('eventParameters'):
                        path = f['source'][len('eventParameters>event>'):]
                    elif f['source'].startswith('macroseismicParameters'):
                        path = f['source'][len('macroseismicParameters>'):]
                    else:
                        path = f['source'][len('FDSNStationXML>'):]
                else:
                    path = ''

                if initial_fields:
                    checked = f['source'] in initial_fields
                else:
                    checked = s.value(
                        '/plugins/qquake/output_field_{}'.format(
                            path.replace('>', '_')), True, bool)

                parent_node.addChild(
                    ModelNode([
                        'checked', f['field_short' if short_field_names else
                                     'field_long'], path
                    ],
                              checked,
                              user_data=f))
            nodes.append(parent_node)

        self.field_model = SimpleNodeModel(
            nodes,
            headers=[
                self.tr('Include'),
                self.tr('Field Name'),
                self.tr('StationML Source') if service_type
                == SERVICE_MANAGER.FDSNSTATION else self.tr('QuakeML Source')
            ])
        self.fields_tree_view.setModel(self.field_model)
        self.fields_tree_view.expandAll()

        for r in range(self.field_model.rowCount(QModelIndex())):
            self.fields_tree_view.setFirstColumnSpanned(r, QModelIndex(), True)

        self.output_preferred_origins_only_check.setVisible(
            self.service_type in (SERVICE_MANAGER.MACROSEISMIC,
                                  SERVICE_MANAGER.FDSNEVENT))
        self.output_preferred_origins_only_check.setEnabled(
            service_config['settings'].get('queryincludeallorigins', False))

        self.output_preferred_magnitudes_only_check.setVisible(
            self.service_type in (SERVICE_MANAGER.MACROSEISMIC,
                                  SERVICE_MANAGER.FDSNEVENT))
        self.output_preferred_magnitudes_only_check.setEnabled(
            service_config['settings'].get('queryincludeallmagnitudes', False))

        self.check_include_event_params_in_mdp.setVisible(
            self.service_type == SERVICE_MANAGER.MACROSEISMIC)
        self.check_include_event_params_in_mdp.setEnabled(
            self.service_type == SERVICE_MANAGER.MACROSEISMIC)

        self.output_preferred_mdp_only_check.setVisible(
            self.service_type == SERVICE_MANAGER.MACROSEISMIC)

        self.output_features_group_box.setVisible(
            self.service_type in (SERVICE_MANAGER.MACROSEISMIC,
                                  SERVICE_MANAGER.FDSNEVENT))

        preferred_origins_only_checked = s.value(
            '/plugins/qquake/output_preferred_origins', True, bool)
        self.output_preferred_origins_only_check.setChecked(
            preferred_origins_only_checked)
        preferred_magnitudes_only_checked = s.value(
            '/plugins/qquake/output_preferred_magnitude', True, bool)
        self.output_preferred_magnitudes_only_check.setChecked(
            preferred_magnitudes_only_checked)
        preferred_mdp_only_checked = s.value(
            '/plugins/qquake/output_preferred_mdp', True, bool)
        self.output_preferred_mdp_only_check.setChecked(
            preferred_mdp_only_checked)

        include_quake_details_in_mdp = s.value(
            '/plugins/qquake/include_quake_details_in_mdp', True, bool)
        self.check_include_event_params_in_mdp.setChecked(
            include_quake_details_in_mdp)

        self.reset_fields_button.clicked.connect(self.reset_fields)
        self.check_all_button.clicked.connect(lambda: self._check_all(True))
        self.uncheck_all_button.clicked.connect(lambda: self._check_all(False))
        self.reset_fields_button.setVisible(False)

        if 'fields' in SERVICE_MANAGER.service_details(service_type,
                                                       service_id)['default']:
            self.set_default_fields(
                SERVICE_MANAGER.service_details(
                    service_type, service_id)['default']['fields'])
Beispiel #3
0
    def create_mdp_features(
            self,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            selected_fields: Optional[List[str]],
            preferred_mdp_set_only: bool) -> QgsFeature:
        """
        Yields MDP features
        """
        settings = QgsSettings()

        short_field_names = settings.value(
            '/plugins/qquake/output_short_field_names', True, bool)
        field_config_key = 'field_short' if short_field_names else 'field_long'
        field_config = SERVICE_MANAGER.get_field_config(
            SERVICE_MANAGER.MACROSEISMIC)

        include_quake_details_in_mdp = settings.value(
            '/plugins/qquake/include_quake_details_in_mdp', True, bool)

        fields = self.create_mdp_fields(selected_fields)
        for _, m in self.mdps.items():
            if m.placeReference in self.macro_places:
                place = self.macro_places[m.placeReference]
            else:
                place = None

            event_reference = m.eventReference
            # try to get macroseismicEvent
            macro_events = [
                m for m in self.macro_events.values()
                if m.eventReference == event_reference
            ]
            macro_event = macro_events[0] if macro_events else None

            mdpset = self.mdp_set_for_mdp(m)

            is_preferred_mdp_set = False
            if macro_event is not None:
                preferred_mdp_set_id = macro_event.preferredMDPSetID
                is_preferred_mdp_set = mdpset.publicID == preferred_mdp_set_id

            if preferred_mdp_set_only and not is_preferred_mdp_set:
                # not in the preferred mdp set, so skip
                continue

            f = QgsFeature(fields)

            if selected_fields:
                output_is_preferred_mdpset = '!IsPrefMdpset' in selected_fields
            else:
                output_is_preferred_mdpset = settings.value(
                    '/plugins/qquake/output_field_!IsPrefMdpset', False, bool)
            if output_is_preferred_mdpset:
                dest_field = [
                    f for f in field_config['field_groups']['basic_event_info']
                    ['fields'] if f['source'] == '!IsPrefMdpset'
                ][0]
                f[dest_field[field_config_key]] = is_preferred_mdp_set or NULL

            for dest_field in field_config['field_groups']['basic_event_info'][
                    'fields']:
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                if not include_quake_details_in_mdp and '>event>' in dest_field[
                        'source'] and dest_field[
                            'source'] != 'eventParameters>event§publicID':
                    continue

                if dest_field['source'].startswith('!'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')

                assert source[0] == 'eventParameters'
                source = source[1:]
                assert source[0] == 'event'
                source = source[1:]

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)

                if not selected:
                    continue

                source_obj = [
                    e for e in self.events if e.publicID == m.eventReference
                ][0]
                for s in source:
                    if source_obj is None:
                        source_obj = NULL
                        break
                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)

                f[dest_field[field_config_key]] = source_obj

            if include_quake_details_in_mdp:

                if selected_fields:
                    output_is_preferred_origin = '!IsPrefOrigin' in selected_fields
                else:
                    output_is_preferred_origin = settings.value(
                        '/plugins/qquake/output_field_!IsPrefOrigin', False,
                        bool)
                if output_is_preferred_origin:
                    dest_field = [
                        f for f in field_config['field_groups']
                        ['basic_event_info']['fields']
                        if f['source'] == '!IsPrefOrigin'
                    ][0]
                    f[dest_field[field_config_key]] = True

                for dest_field in field_config['field_groups']['origin'][
                        'fields']:
                    if dest_field.get('skip'):
                        continue

                    if dest_field.get('one_to_many'):
                        continue

                    source = dest_field['source'].replace('§', '>').split('>')
                    assert source[0] == 'eventParameters'
                    source = source[1:]
                    assert source[0] == 'event'
                    source = source[1:]
                    assert source[0] == 'origin'
                    source = source[1:]

                    if selected_fields:
                        selected = dest_field['source'] in selected_fields
                    else:
                        selected = settings.value(
                            '/plugins/qquake/output_field_{}'.format(
                                '_'.join(source)), True, bool)

                    if not selected:
                        continue

                    event = [
                        e for e in self.events
                        if e.publicID == m.eventReference
                    ][0]
                    origin = self.origins[event.preferredOriginID]

                    source_obj = origin

                    for s in source:
                        if source_obj is None:
                            source_obj = NULL
                            break
                        assert hasattr(source_obj, s)
                        source_obj = getattr(source_obj, s)

                    f[dest_field[field_config_key]] = source_obj

            if include_quake_details_in_mdp:

                if selected_fields:
                    output_is_preferred_mag = '!IsPrefMag' in selected_fields
                else:
                    output_is_preferred_mag = settings.value(
                        '/plugins/qquake/output_field_!IsPrefMag', False, bool)
                if output_is_preferred_mag:
                    dest_field = [
                        f for f in CONFIG_FIELDS['field_groups']
                        ['basic_event_info']['fields']
                        if f['source'] == '!IsPrefMag'
                    ][0]
                    f[dest_field[field_config_key]] = True

                for dest_field in field_config['field_groups']['magnitude'][
                        'fields']:
                    if dest_field.get('skip'):
                        continue

                    if dest_field.get('one_to_many'):
                        continue

                    source = dest_field['source'].replace('§', '>').split('>')
                    assert source[0] == 'eventParameters'
                    source = source[1:]
                    assert source[0] == 'event'
                    source = source[1:]
                    assert source[0] == 'magnitude'
                    source = source[1:]

                    if selected_fields:
                        selected = dest_field['source'] in selected_fields
                    else:
                        selected = settings.value(
                            '/plugins/qquake/output_field_{}'.format(
                                '_'.join(source)), True, bool)

                    if not selected:
                        continue

                    event = [
                        e for e in self.events
                        if e.publicID == m.eventReference
                    ][0]
                    source_obj = self.magnitudes[event.preferredMagnitudeID]
                    for s in source:
                        if source_obj is None:
                            source_obj = NULL
                            break
                        assert hasattr(source_obj, s)
                        source_obj = getattr(source_obj, s)

                    f[dest_field[field_config_key]] = source_obj

            for dest_field in field_config['field_groups'].get('mdp', {}).get(
                    'fields', []):
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')
                assert source[0] == 'macroseismicParameters'
                source = source[1:]
                assert source[0] == 'mdp'
                source = source[1:]

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)

                if not selected:
                    continue

                source_obj = m
                for s in source:
                    if source_obj is None:
                        source_obj = NULL
                        break

                    if s == 'class':
                        # reserved keyword, can't use!
                        s = '_class'

                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)

                f[dest_field[field_config_key]] = source_obj

            for dest_field in field_config['field_groups'].get(
                    'place', {}).get('fields', []):
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')
                assert source[0] == 'macroseismicParameters'
                source = source[1:]
                assert source[0] == 'place'
                source = source[1:]

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)

                if not selected:
                    continue

                source_obj = place
                for s in source:
                    if source_obj is None:
                        source_obj = NULL
                        break
                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)

                f[dest_field[field_config_key]] = source_obj

            for dest_field in field_config['field_groups'].get(
                    'macro_basic_event_info', {}).get('fields', []):
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')
                assert source[0] == 'macroseismicParameters'
                source = source[1:]
                assert source[0] == 'macroseismicEvent'
                source = source[1:]

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)

                if not selected:
                    continue

                source_obj = macro_event
                if source_obj is None:
                    continue

                for s in source:
                    if source_obj is None:
                        source_obj = NULL
                        break
                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)

                f[dest_field[field_config_key]] = source_obj

            for dest_field in field_config['field_groups'].get(
                    'mdpSet', {}).get('fields', []):
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')
                assert source[0] == 'macroseismicParameters'
                source = source[1:]
                assert source[0] == 'mdpSet'
                source = source[1:]

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)

                if not selected:
                    continue

                source_obj = mdpset
                for s in source:
                    if source_obj is None:
                        source_obj = NULL
                        break

                    if s == 'class':
                        # reserved keyword, can't use!
                        s = '_class'

                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)

                f[dest_field[field_config_key]] = source_obj

            if place and place.referenceLongitude and place.referenceLatitude:
                geom = QgsPoint(x=place.referenceLongitude.value,
                                y=place.referenceLatitude.value)
                f.setGeometry(QgsGeometry(geom))

            yield f
Beispiel #4
0
def get_service_fields(
    service_type: str,  # pylint: disable=too-many-branches,too-many-statements
    selected_fields: Optional[List[str]]
) -> QgsFields:
    """
    Gets the field configuration for a service
    """
    fields = QgsFields()
    settings = QgsSettings()
    short_field_names = settings.value(
        '/plugins/qquake/output_short_field_names', True, bool)
    field_config_key = 'field_short' if short_field_names else 'field_long'

    include_quake_details_in_mdp = settings.value(
        '/plugins/qquake/include_quake_details_in_mdp', True, bool)

    field_config = SERVICE_MANAGER.get_field_config(service_type)
    for f in field_config['field_groups'].get('basic_event_info',
                                              {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if service_type == SERVICE_MANAGER.MACROSEISMIC and not include_quake_details_in_mdp and '>event' in path and path != 'eventParameters>event§publicID':
            continue

        if selected_fields:
            # use specified fields
            selected = path in selected_fields
        else:
            # use default settings
            path = path[len('eventParameters>event>'):].replace('§',
                                                                '>').replace(
                                                                    '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)

        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('origin', {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if service_type == SERVICE_MANAGER.MACROSEISMIC and not include_quake_details_in_mdp:
            continue

        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('eventParameters>event>'):].replace('§',
                                                                '>').replace(
                                                                    '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('magnitude',
                                              {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        if service_type == SERVICE_MANAGER.MACROSEISMIC and not include_quake_details_in_mdp:
            continue

        path = f['source']
        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('eventParameters>event>'):].replace('§',
                                                                '>').replace(
                                                                    '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('macro_basic_event_info',
                                              {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('macroseismicParameters>'):].replace('§',
                                                                 '>').replace(
                                                                     '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('mdpSet', {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('macroseismicParameters>'):].replace('§',
                                                                 '>').replace(
                                                                     '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('mdp', {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('macroseismicParameters>'):].replace('§',
                                                                 '>').replace(
                                                                     '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    for f in field_config['field_groups'].get('place', {}).get('fields', []):
        if f.get('skip'):
            continue

        if f.get('one_to_many'):
            continue

        path = f['source']
        if selected_fields:
            selected = path in selected_fields
        else:
            path = path[len('macroseismicParameters>'):].replace('§',
                                                                 '>').replace(
                                                                     '>', '_')
            selected = settings.value(
                '/plugins/qquake/output_field_{}'.format(path), True, bool)
        if not selected:
            continue

        fields.append(QgsField(f[field_config_key], FIELD_TYPE_MAP[f['type']]))

    return fields
Beispiel #5
0
    def to_station_features(
        self, selected_fields: Optional[List[str]]
    ) -> List[QgsFeature]:  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
        """
        Converts the network to a list of station features
        """
        features = []
        settings = QgsSettings()

        short_field_names = settings.value(
            '/plugins/qquake/output_short_field_names', True, bool)
        field_config_key = 'field_short' if short_field_names else 'field_long'

        general_feature = QgsFeature(Station.to_fields(selected_fields))

        for dest_field in SERVICE_MANAGER.get_field_config(
                SERVICE_MANAGER.FDSNSTATION
        )['field_groups']['general']['fields']:
            if dest_field.get('skip'):
                continue

            if dest_field.get('one_to_many'):
                continue

            source = dest_field['source'].replace('§', '>').split('>')
            assert source[0] == 'FDSNStationXML'
            source = source[1:]
            source_obj = self

            if selected_fields:
                selected = dest_field['source'] in selected_fields
            else:
                selected = settings.value(
                    '/plugins/qquake/output_field_{}'.format('_'.join(source)),
                    True, bool)
            if not selected:
                continue

            for s in source:
                assert hasattr(source_obj, s)
                source_obj = getattr(source_obj, s)
                if source_obj is None:
                    break

            general_feature[dest_field[field_config_key]] = source_obj

        for network in self.networks:
            network_feature = QgsFeature(general_feature)

            for dest_field in SERVICE_MANAGER.get_field_config(
                    SERVICE_MANAGER.FDSNSTATION
            )['field_groups']['network']['fields']:
                if dest_field.get('skip'):
                    continue

                if dest_field.get('one_to_many'):
                    continue

                source = dest_field['source'].replace('§', '>').split('>')
                assert source[0] == 'FDSNStationXML'
                source = source[1:]
                assert source[0] == 'Network'
                source = source[1:]
                source_obj = network

                if selected_fields:
                    selected = dest_field['source'] in selected_fields
                else:
                    selected = settings.value(
                        '/plugins/qquake/output_field_{}'.format(
                            '_'.join(source)), True, bool)
                if not selected:
                    continue

                for s in source:
                    assert hasattr(source_obj, s)
                    source_obj = getattr(source_obj, s)
                    if source_obj is None:
                        break

                network_feature[dest_field[field_config_key]] = source_obj

            for o in network.stations:
                f = QgsFeature(network_feature)
                for dest_field in SERVICE_MANAGER.get_field_config(
                        SERVICE_MANAGER.FDSNSTATION
                )['field_groups']['station']['fields']:
                    if dest_field.get('skip'):
                        continue

                    if dest_field.get('one_to_many'):
                        continue

                    source = dest_field['source'].replace('§', '>').split('>')
                    assert source[0] == 'FDSNStationXML'
                    source = source[1:]
                    assert source[0] == 'Network'
                    source = source[1:]
                    source_obj = self

                    if source[0] == 'Station':
                        source_obj = o
                        source = source[1:]

                    if selected_fields:
                        selected = dest_field['source'] in selected_fields
                    else:
                        selected = settings.value(
                            '/plugins/qquake/output_field_{}'.format(
                                '_'.join(source)), True, bool)
                    if not selected:
                        continue

                    for s in source:
                        assert hasattr(source_obj, s)
                        source_obj = getattr(source_obj, s)
                        if source_obj is None:
                            break

                    f[dest_field[field_config_key]] = source_obj

                geom = QgsPoint(x=o.Longitude, y=o.Latitude, z=o.Elevation)
                f.setGeometry(QgsGeometry(geom))

                features.append(f)

        return features