You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
630 lines
17 KiB
C++
630 lines
17 KiB
C++
/***************************************************************************
|
|
* Copyright (C) gempa GmbH *
|
|
* All rights reserved. *
|
|
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
|
* *
|
|
* GNU Affero General Public License Usage *
|
|
* This file may be used under the terms of the GNU Affero *
|
|
* Public License version 3.0 as published by the Free Software Foundation *
|
|
* and appearing in the file LICENSE included in the packaging of this *
|
|
* file. Please review the following information to ensure the GNU Affero *
|
|
* Public License version 3.0 requirements will be met: *
|
|
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
|
* *
|
|
* Other Usage *
|
|
* Alternatively, this file may be used in accordance with the terms and *
|
|
* conditions contained in a signed written agreement between you and *
|
|
* gempa GmbH. *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef SEISCOMP_GUI_PICKERVIEW_H
|
|
#define SEISCOMP_GUI_PICKERVIEW_H
|
|
|
|
|
|
#include <seiscomp/gui/core/recordview.h>
|
|
#include <seiscomp/gui/core/connectionstatelabel.h>
|
|
#include <seiscomp/gui/core/utils.h>
|
|
#ifndef Q_MOC_RUN
|
|
#include <seiscomp/io/recordfilter/iirfilter.h>
|
|
#include <seiscomp/datamodel/databasequery.h>
|
|
#include <seiscomp/datamodel/origin.h>
|
|
#include <seiscomp/datamodel/pick.h>
|
|
#include <seiscomp/seismology/ttt.h>
|
|
#include <seiscomp/math/matrix3.h>
|
|
#include <seiscomp/processing/picker.h>
|
|
#endif
|
|
#include <QActionGroup>
|
|
#include <QComboBox>
|
|
#include <QPushButton>
|
|
#include <QSpinBox>
|
|
#include <QMovie>
|
|
#include <QSet>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QMainWindow>
|
|
|
|
|
|
namespace Seiscomp {
|
|
|
|
namespace DataModel {
|
|
|
|
class SensorLocation;
|
|
|
|
}
|
|
|
|
namespace Processing {
|
|
|
|
DEFINE_SMARTPOINTER(AmplitudeProcessor);
|
|
|
|
}
|
|
|
|
namespace Gui {
|
|
|
|
class TimeScale;
|
|
class PickerView;
|
|
class SpectrumWidget;
|
|
|
|
|
|
namespace PrivatePickerView {
|
|
|
|
|
|
class SC_GUI_API ThreeComponentTrace : public QObject {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
ThreeComponentTrace() = default;
|
|
~ThreeComponentTrace();
|
|
|
|
public:
|
|
void setTransformationEnabled(bool enable);
|
|
void setL2Horizontals(bool);
|
|
void setPassThrough(int component, bool enable);
|
|
void setRecordWidget(RecordWidget *);
|
|
void reset();
|
|
void setFilter(RecordWidget::Filter *);
|
|
bool transform(int comp = -1, Seiscomp::Record *rec = nullptr);
|
|
|
|
private slots:
|
|
void widgetDestroyed(QObject *obj);
|
|
|
|
public:
|
|
typedef IO::RecordIIRFilter<double> Filter;
|
|
|
|
// One component
|
|
struct Component {
|
|
std::string channelCode;
|
|
RecordSequence *raw{nullptr};
|
|
RecordSequence *transformed{nullptr};
|
|
Filter filter{nullptr};
|
|
RecordStreamThread *thread{nullptr};
|
|
bool passthrough{false};
|
|
};
|
|
|
|
Math::Matrix3d transformation;
|
|
Component traces[3];
|
|
RecordWidget *widget{nullptr};
|
|
bool enableTransformation{false};
|
|
bool enableL2Horizontals{false};
|
|
};
|
|
|
|
|
|
class SC_GUI_API PickerRecordLabel : public StandardRecordLabel {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
PickerRecordLabel(int items=3, QWidget *parent=0, const char* name = 0);
|
|
~PickerRecordLabel();
|
|
|
|
|
|
public:
|
|
void setConfigState(bool);
|
|
|
|
void setControlledItem(RecordViewItem *controlledItem);
|
|
RecordViewItem *controlledItem() const;
|
|
|
|
void setLinkedItem(bool sm);
|
|
|
|
void enabledExpandButton(RecordViewItem *controlledItem);
|
|
void disableExpandButton();
|
|
void unlink();
|
|
|
|
bool isLinkedItem() const;
|
|
bool isExpanded() const;
|
|
|
|
void setLabelColor(QColor);
|
|
void removeLabelColor();
|
|
|
|
|
|
protected:
|
|
void visibilityChanged(bool);
|
|
void resizeEvent(QResizeEvent *e);
|
|
void paintEvent(QPaintEvent *e);
|
|
|
|
|
|
public slots:
|
|
void extentButtonPressed();
|
|
|
|
private slots:
|
|
void enableExpandable(const Seiscomp::Record*);
|
|
|
|
|
|
private:
|
|
bool _isLinkedItem;
|
|
bool _isExpanded;
|
|
QPushButton *_btnExpand;
|
|
RecordViewItem *_linkedItem;
|
|
bool _hasLabelColor;
|
|
QColor _labelColor;
|
|
|
|
private:
|
|
double latitude;
|
|
double longitude;
|
|
int unit;
|
|
QString gainUnit[3];
|
|
ThreeComponentTrace data;
|
|
Math::Matrix3d orientationZNE;
|
|
Math::Matrix3d orientationZRT;
|
|
|
|
bool hasGotData;
|
|
bool isEnabledByConfig;
|
|
|
|
friend class Gui::PickerView;
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
class SC_GUI_API PickerMarkerActionPlugin : public QObject {
|
|
public:
|
|
virtual ~PickerMarkerActionPlugin() {}
|
|
|
|
public:
|
|
//! Returns the action title as added to the context menu
|
|
virtual QString title() const = 0;
|
|
|
|
virtual bool init(const DataModel::WaveformStreamID &wid,
|
|
const Core::Time &time) = 0;
|
|
|
|
//! Feed a record of the current stream (including all available
|
|
//! components)
|
|
virtual void setRecords(RecordSequence *seqZ, RecordSequence *seq1, RecordSequence *seq2) = 0;
|
|
|
|
//! Finalize the action, no more data will be fed a this point
|
|
virtual void finalize() = 0;
|
|
};
|
|
|
|
|
|
DEFINE_INTERFACE_FACTORY(PickerMarkerActionPlugin);
|
|
|
|
|
|
class SpectrumViewBase : public QWidget {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
SpectrumViewBase(QWidget *parent = 0, Qt::WindowFlags f = 0)
|
|
: QWidget(parent, f) {}
|
|
|
|
protected slots:
|
|
virtual void modeChanged(int) = 0;
|
|
virtual void windowFuncChanged(int) = 0;
|
|
virtual void windowWidthChanged(double) = 0;
|
|
};
|
|
|
|
|
|
class PickerViewPrivate;
|
|
|
|
|
|
class SC_GUI_API PickerView : public QMainWindow {
|
|
public:
|
|
struct SC_GUI_API Config {
|
|
typedef QPair<QString, QString> FilterEntry;
|
|
typedef QVector<FilterEntry> FilterList;
|
|
typedef QList<QString> StringList;
|
|
typedef StringList PhaseList;
|
|
|
|
struct PhaseGroup {
|
|
QString name;
|
|
QList<PhaseGroup> childs;
|
|
};
|
|
|
|
typedef QList<PhaseGroup> GroupList;
|
|
typedef QPair<float, float> Uncertainty;
|
|
typedef QVector<Uncertainty> UncertaintyList;
|
|
typedef QMap<QString, UncertaintyList> UncertaintyProfiles;
|
|
typedef QPair<QString, QString> ChannelMapItem;
|
|
typedef QMultiMap<QString, ChannelMapItem> ChannelMap;
|
|
|
|
QString recordURL;
|
|
ChannelMap channelMap;
|
|
|
|
FilterList filters;
|
|
|
|
QString integrationFilter;
|
|
bool onlyApplyIntegrationFilterOnce;
|
|
|
|
GroupList phaseGroups;
|
|
PhaseList favouritePhases;
|
|
|
|
PhaseList showPhases;
|
|
|
|
UncertaintyProfiles uncertaintyProfiles;
|
|
QString uncertaintyProfile;
|
|
|
|
bool showCrossHair;
|
|
|
|
bool ignoreUnconfiguredStations;
|
|
bool ignoreDisabledStations;
|
|
bool loadAllComponents;
|
|
bool loadAllPicks;
|
|
bool loadStrongMotionData;
|
|
bool usePerStreamTimeWindows;
|
|
bool limitStations;
|
|
bool showAllComponents;
|
|
bool hideStationsWithoutData;
|
|
bool hideDisabledStations;
|
|
|
|
int limitStationCount;
|
|
double allComponentsMaximumStationDistance;
|
|
double defaultAddStationsDistance;
|
|
|
|
double defaultDepth;
|
|
|
|
bool removeAutomaticStationPicks;
|
|
bool removeAutomaticPicks;
|
|
|
|
Core::TimeSpan preOffset;
|
|
Core::TimeSpan postOffset;
|
|
Core::TimeSpan minimumTimeWindow;
|
|
|
|
double alignmentPosition;
|
|
double offsetWindowStart;
|
|
double offsetWindowEnd;
|
|
|
|
QColor timingQualityLow;
|
|
QColor timingQualityMedium;
|
|
QColor timingQualityHigh;
|
|
|
|
OPT(double) repickerSignalStart;
|
|
OPT(double) repickerSignalEnd;
|
|
|
|
Config();
|
|
|
|
void addFilter(const QString &f, const QString &n) {
|
|
filters.push_back(QPair<QString, QString>(f, n));
|
|
}
|
|
|
|
void addShowPhase(const QString &ph) {
|
|
showPhases.push_back(ph);
|
|
}
|
|
|
|
void getPickPhases(StringList &phases) const;
|
|
void getPickPhases(StringList &phases, const QList<PhaseGroup> &groups) const;
|
|
};
|
|
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
//! Default c'tor
|
|
//! The mode defaults to ringbuffer with a buffer
|
|
//! size of 30 minutes
|
|
PickerView(QWidget *parent = 0, Qt::WindowFlags f = 0);
|
|
|
|
//! Creates a RecordView using a time window
|
|
PickerView(const Seiscomp::Core::TimeWindow&,
|
|
QWidget *parent = 0, Qt::WindowFlags f = 0);
|
|
|
|
//! Creates a RecordView using a timespan and
|
|
//! a ringbuffer
|
|
PickerView(const Seiscomp::Core::TimeSpan&,
|
|
QWidget *parent = 0, Qt::WindowFlags f = 0);
|
|
|
|
~PickerView();
|
|
|
|
public:
|
|
bool setConfig(const Config &c, QString *error = nullptr);
|
|
|
|
void setDatabase(Seiscomp::DataModel::DatabaseQuery*);
|
|
void activateFilter(int index);
|
|
|
|
void setBroadBandCodes(const std::vector<std::string> &codes);
|
|
void setStrongMotionCodes(const std::vector<std::string> &codes);
|
|
|
|
//! Sets an origin an inserts the traces for each arrival
|
|
//! in the view.
|
|
bool setOrigin(Seiscomp::DataModel::Origin*,
|
|
double relTimeWindowStart,
|
|
double relTimeWindowEnd);
|
|
|
|
//! Sets an origin and keeps all available traces
|
|
bool setOrigin(Seiscomp::DataModel::Origin*);
|
|
|
|
bool hasModifiedPicks() const;
|
|
void getChangedPicks(ObjectChangeList<DataModel::Pick> &list) const;
|
|
|
|
void stop();
|
|
|
|
void selectTrace(const std::string &, const std::string &);
|
|
void selectTrace(const Seiscomp::DataModel::WaveformStreamID &wid);
|
|
|
|
|
|
signals:
|
|
void requestArtificialOrigin(double lat, double lon, double depth, Seiscomp::Core::Time time);
|
|
void originCreated(Seiscomp::DataModel::Origin*);
|
|
void arrivalChanged(int id, bool state);
|
|
void arrivalEnableStateChanged(int id, bool state);
|
|
|
|
|
|
public slots:
|
|
void setDefaultDisplay();
|
|
void applyPicks();
|
|
void changeFilter(int);
|
|
void changeRotation(int);
|
|
void changeUnit(int);
|
|
void setArrivalState(int arrivalId, bool state);
|
|
void addPick(Seiscomp::DataModel::Pick* pick);
|
|
|
|
void setStationEnabled(const std::string& networkCode,
|
|
const std::string& stationCode,
|
|
bool state);
|
|
|
|
|
|
private slots:
|
|
void receivedRecord(Seiscomp::Record*);
|
|
|
|
void updateTraceInfo(RecordViewItem*, const Seiscomp::Record*);
|
|
void currentMarkerChanged(Seiscomp::Gui::RecordMarker*);
|
|
void apply(QAction*);
|
|
void setPickPhase(QAction*);
|
|
void alignOnPhase(QAction*);
|
|
void onAddedItem(const Seiscomp::Record*, Seiscomp::Gui::RecordViewItem*);
|
|
void onSelectedTime(Seiscomp::Core::Time);
|
|
void onSelectedTime(Seiscomp::Gui::RecordWidget*, Seiscomp::Core::Time);
|
|
void setAlignment(Seiscomp::Core::Time);
|
|
void acquisitionFinished();
|
|
void handleAcquisitionError(const QString &msg);
|
|
void relocate();
|
|
void modifyOrigin();
|
|
void updateTheoreticalArrivals();
|
|
void itemSelected(RecordViewItem*, RecordViewItem*);
|
|
void updateMainCursor(RecordWidget*,int);
|
|
void updateSubCursor(RecordWidget*,int);
|
|
void updateItemLabel(RecordViewItem*, char);
|
|
void updateItemRecordState(const Seiscomp::Record*);
|
|
void updateRecordValue(Seiscomp::Core::Time);
|
|
void showTraceScaleToggled(bool);
|
|
|
|
void specLogToggled(bool);
|
|
void specSmoothToggled(bool);
|
|
void specMinValue(double);
|
|
void specMaxValue(double);
|
|
void specTimeWindow(double);
|
|
void specApply();
|
|
|
|
void limitFilterToZoomTrace(bool);
|
|
|
|
void showTheoreticalArrivals(bool);
|
|
void showUnassociatedPicks(bool);
|
|
void showSpectrogram(bool);
|
|
void showSpectrum();
|
|
|
|
void toggleFilter();
|
|
void nextFilter();
|
|
void previousFilter();
|
|
void addNewFilter(const QString&);
|
|
|
|
void scaleVisibleAmplitudes();
|
|
|
|
void zoomSelectionHandleMoved(int, double, Qt::KeyboardModifiers);
|
|
void zoomSelectionHandleMoveFinished();
|
|
|
|
void changeScale(double, double);
|
|
void changeTimeRange(double, double);
|
|
|
|
void sortAlphabetically();
|
|
void sortByDistance();
|
|
void sortByAzimuth();
|
|
void sortByResidual();
|
|
void sortByPhase(const QString&);
|
|
|
|
void showAllComponents(bool);
|
|
void showZComponent();
|
|
void showNComponent();
|
|
void showEComponent();
|
|
|
|
void alignOnOriginTime();
|
|
void alignOnPArrivals();
|
|
void alignOnSArrivals();
|
|
|
|
void pickNone(bool);
|
|
void pickP(bool);
|
|
void pickS(bool);
|
|
|
|
void scaleAmplUp();
|
|
void scaleAmplDown();
|
|
void scaleTimeUp();
|
|
void scaleTimeDown();
|
|
|
|
void scaleReset();
|
|
|
|
void scrollLeft();
|
|
void scrollFineLeft();
|
|
void scrollRight();
|
|
void scrollFineRight();
|
|
|
|
void automaticRepick();
|
|
void gotoNextMarker();
|
|
void gotoPreviousMarker();
|
|
|
|
void createPick();
|
|
void setPick();
|
|
void confirmPick();
|
|
void resetPick();
|
|
void deletePick();
|
|
|
|
void setCurrentRowEnabled(bool);
|
|
void setCurrentRowDisabled(bool);
|
|
|
|
void loadNextStations();
|
|
void showUsedStations(bool);
|
|
|
|
void moveTraces(double offset);
|
|
void move(double offset);
|
|
void zoom(float factor);
|
|
void applyTimeRange(double,double);
|
|
|
|
void sortByState();
|
|
void alignByState();
|
|
void componentByState();
|
|
void updateLayoutFromState();
|
|
|
|
void firstConnectionEstablished();
|
|
void lastConnectionClosed();
|
|
|
|
void beginWaitForRecords();
|
|
void doWaitForRecords(int value);
|
|
void endWaitForRecords();
|
|
|
|
void showFullscreen(bool);
|
|
|
|
void enableAutoScale();
|
|
void disableAutoScale();
|
|
|
|
void addStations();
|
|
|
|
void searchStation();
|
|
void search(const QString&);
|
|
void nextSearch();
|
|
void abortSearchStation();
|
|
|
|
void setPickPolarity();
|
|
void setPickUncertainty();
|
|
|
|
void openContextMenu(const QPoint &p);
|
|
void openRecordContextMenu(const QPoint &p);
|
|
|
|
void previewUncertainty(QAction *);
|
|
void previewUncertainty(double lower, double upper);
|
|
|
|
void openConnectionInfo(const QPoint &);
|
|
void destroyedSpectrumWidget(QObject *);
|
|
|
|
void ttInterfaceChanged(QString);
|
|
void ttTableChanged(QString);
|
|
|
|
|
|
protected:
|
|
void showEvent(QShowEvent* event);
|
|
|
|
RecordLabel* createLabel(RecordViewItem*) const;
|
|
|
|
|
|
private:
|
|
void figureOutTravelTimeTable();
|
|
|
|
void init();
|
|
void initPhases();
|
|
bool fillTheoreticalArrivals();
|
|
bool fillRawPicks();
|
|
|
|
int loadPicks();
|
|
|
|
const TravelTime* findPhase(const TravelTimeList &list, const QString &phase, double delta);
|
|
|
|
RecordViewItem* addStream(const DataModel::SensorLocation *,
|
|
const DataModel::WaveformStreamID& streamID,
|
|
double distance,
|
|
const std::string& text,
|
|
bool showDisabled,
|
|
bool addTheoreticalArrivals,
|
|
const DataModel::Stream *base = nullptr);
|
|
|
|
RecordViewItem* addRawStream(const DataModel::SensorLocation *,
|
|
const DataModel::WaveformStreamID& streamID,
|
|
double distance,
|
|
const std::string& text,
|
|
bool addTheoreticalArrivals,
|
|
const DataModel::Stream *base = nullptr);
|
|
|
|
void queueStream(double dist, const DataModel::WaveformStreamID& streamID, char component);
|
|
|
|
void setupItem(const char comps[3], RecordViewItem*);
|
|
bool addTheoreticalArrivals(RecordViewItem*,
|
|
const std::string& netCode,
|
|
const std::string& staCode,
|
|
const std::string& locCode);
|
|
|
|
bool addRawPick(Seiscomp::DataModel::Pick*);
|
|
|
|
void resetState();
|
|
void alignOnPhase(const QString&, bool theoretical);
|
|
|
|
void diffStreamState(Seiscomp::DataModel::Origin* oldOrigin,
|
|
Seiscomp::DataModel::Origin* newOrigin);
|
|
|
|
void updateOriginInformation();
|
|
|
|
void loadNextStations(float distance);
|
|
|
|
void setCursorText(const QString&);
|
|
void setCursorPos(const Seiscomp::Core::Time&, bool always = false);
|
|
void setTimeRange(double, double);
|
|
|
|
void acquireStreams();
|
|
|
|
bool applyFilter(RecordViewItem *item = nullptr);
|
|
bool applyRotation(RecordViewItem *item, int type);
|
|
void updateRecordAxisLabel(RecordViewItem *item);
|
|
|
|
|
|
//! Makes sure that the time range [tmin, tmax] is visible.
|
|
//! When the interval is larger than the visible area
|
|
//! the time range will be left aligned.
|
|
void ensureVisibility(double &tmin, double &tmax);
|
|
void ensureVisibility(const Seiscomp::Core::Time &time, int pixelMargin);
|
|
|
|
void updatePhaseMarker(Seiscomp::Gui::RecordWidget*, const Seiscomp::Core::Time&);
|
|
void declareArrival(Seiscomp::Gui::RecordMarker *m, const QString &phase, bool);
|
|
void updateUncertaintyHandles(RecordMarker *marker);
|
|
|
|
void updateCurrentRowState();
|
|
void setMarkerState(Seiscomp::Gui::RecordWidget*, bool);
|
|
|
|
bool setArrivalState(Seiscomp::Gui::RecordWidget* w, int arrivalId, bool state);
|
|
|
|
void fetchManualPicks(std::vector<RecordMarker*>* marker = nullptr) const;
|
|
|
|
void showComponent(char componentCode);
|
|
void fetchComponent(char componentCode);
|
|
|
|
void addArrival(Seiscomp::Gui::RecordWidget*, Seiscomp::DataModel::Arrival*, int id);
|
|
void addFilter(const QString& name, const QString& filter);
|
|
|
|
void changeFilter(int, bool force);
|
|
|
|
void closeThreads();
|
|
|
|
char currentComponent() const;
|
|
|
|
void searchByText(const QString &text);
|
|
|
|
void emitPick(const Processing::Picker *, const Processing::Picker::Result &res);
|
|
|
|
|
|
private:
|
|
PickerViewPrivate *_d_ptr;
|
|
};
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#define REGISTER_PICKER_MARKER_ACTION(Class, Service) \
|
|
Seiscomp::Core::Generic::InterfaceFactory<Seiscomp::Gui::PickerMarkerActionPlugin, Class> __##Class##InterfaceFactory__(Service)
|
|
|
|
|
|
#endif
|