diff --git a/Software/PC_Application/Traces/smithchartdialog.ui b/Software/PC_Application/Traces/smithchartdialog.ui
index 275d458..d45bb05 100644
--- a/Software/PC_Application/Traces/smithchartdialog.ui
+++ b/Software/PC_Application/Traces/smithchartdialog.ui
@@ -6,8 +6,8 @@
0
0
- 307
- 255
+ 856
+ 259
@@ -16,86 +16,164 @@
true
-
+
-
-
-
- Display mode
-
-
-
-
-
-
- Frequency:
-
-
-
- -
-
-
-
-
- Show complete traces
+
+
-
+
+
-
+
+
+ Display mode
+
+
-
+
+
+ Frequency:
+
+
+
+ -
+
+
-
+
+ Show complete traces
+
+
+ -
+
+ Limit to current span
+
+
+
+
+ -
+
+
+ Impedance:
+
+
+
+ -
+
+
-
+
+ Show complete traces
+
+
+ -
+
+ Limit to visible area
+
+
+
+
+
+
+
+ -
+
+
+ Zoom
+
+
+
-
+
+
+ Factor:
+
+
+
+ -
+
+
+ -
+
+
+ <html><head/><body><p>|Γ| at edge:</p></body></html>
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+ Constant Lines
+
+
+
-
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ 20
+
+
+ true
+
+
+ false
+
+
+ 21
+
+
-
-
- Limit to current span
-
+
+
-
+
+
+
+
+
+
+ :/icons/add.png:/icons/add.png
+
+
+
+ -
+
+
+
+
+
+
+ :/icons/remove.png:/icons/remove.png
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
-
-
- -
-
-
- Impedance:
-
-
-
- -
-
-
-
-
- Show complete traces
-
-
- -
-
- Limit to visible area
-
-
-
-
-
-
-
- -
-
-
- Zoom
-
-
-
-
-
-
- Factor:
-
-
-
- -
-
-
- -
-
-
- <html><head/><body><p>|Γ| at edge:</p></body></html>
-
-
-
- -
-
-
-
-
+
+
+
+
-
@@ -116,7 +194,9 @@
CustomWidgets/siunitedit.h
-
+
+
+
buttonBox
diff --git a/Software/PC_Application/Traces/tracesmithchart.cpp b/Software/PC_Application/Traces/tracesmithchart.cpp
index c16b989..7c4d030 100644
--- a/Software/PC_Application/Traces/tracesmithchart.cpp
+++ b/Software/PC_Application/Traces/tracesmithchart.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
using namespace std;
@@ -35,6 +36,11 @@ nlohmann::json TraceSmithChart::toJSON()
}
}
j["traces"] = jtraces;
+ nlohmann::json jlines;
+ for(auto line : constantLines) {
+ jlines.push_back(line.toJSON());
+ }
+ j["constantLines"] = jlines;
return j;
}
@@ -57,6 +63,13 @@ void TraceSmithChart::fromJSON(nlohmann::json j)
qWarning() << "Unable to find trace with hash" << hash;
}
}
+ if(j.contains("constantLines")) {
+ for(auto jline : j["constantLines"]) {
+ SmithChartConstantLine line;
+ line.fromJSON(jline);
+ constantLines.push_back(line);
+ }
+ }
}
void TraceSmithChart::wheelEvent(QWheelEvent *event)
@@ -91,6 +104,12 @@ void TraceSmithChart::axisSetupDialog()
ui->zoomFactor->setPrecision(3);
ui->zoomReflection->setValue(edgeReflection);
ui->zoomFactor->setValue(1.0/edgeReflection);
+
+ auto model = new SmithChartContantLineModel(*this);
+ ui->lineTable->setModel(model);
+ ui->lineTable->setItemDelegateForColumn(SmithChartContantLineModel::ColIndexType, new SmithChartTypeDelegate);
+ ui->lineTable->setItemDelegateForColumn(SmithChartContantLineModel::ColIndexParam, new SmithChartParamDelegate);
+
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
limitToSpan = ui->displayModeFreq->currentIndex() == 1;
limitToEdge = ui->displayModeImp->currentIndex() == 1;
@@ -104,6 +123,48 @@ void TraceSmithChart::axisSetupDialog()
edgeReflection = ui->zoomReflection->value();
ui->zoomFactor->setValueQuiet(1.0 / edgeReflection);
});
+ connect(ui->lineTable, &QTableView::clicked, [=](const QModelIndex &index){
+ if(index.column() == SmithChartContantLineModel::ColIndexColor) {
+ auto line = &constantLines[index.row()];
+ auto newColor = QColorDialog::getColor(line->getColor(), parentWidget(), "Select color", QColorDialog::DontUseNativeDialog);
+ if(newColor.isValid()) {
+ line->setColor(newColor);
+ emit model->dataChanged(index, index);
+ triggerReplot();
+ }
+ }
+ });
+
+ auto updatePersistentEditors = [=](){
+ for(unsigned int i=0;ilineTable->openPersistentEditor(model->index(i, SmithChartContantLineModel::ColIndexType));
+ }
+ };
+
+ connect(ui->addLine, &QPushButton::clicked, [=](){
+ model->beginResetModel();
+ constantLines.push_back(SmithChartConstantLine());
+ model->endResetModel();
+ updatePersistentEditors();
+ });
+ connect(ui->removeLine, &QPushButton::clicked, [=](){
+ auto selected = ui->lineTable->selectionModel()->selectedRows();
+ // get indices of lines to delete
+ std::vector toDelete;
+ for(auto s : selected) {
+ toDelete.push_back(s.row());
+ }
+ // delete starting with highest index (this makes sure that indices are not messed up after deleting an element
+ std::sort(toDelete.begin(), toDelete.end());
+ model->beginResetModel();
+ for (auto i = toDelete.rbegin(); i != toDelete.rend(); i++) {
+ constantLines.erase(constantLines.begin() + *i);
+ }
+ model->endResetModel();
+ updatePersistentEditors();
+ });
+
+ updatePersistentEditors();
dialog->show();
}
@@ -213,7 +274,7 @@ void TraceSmithChart::draw(QPainter &p) {
transform = p.transform();
p.restore();
- auto drawArc = [&](Arc a) {
+ auto drawArc = [&](SmithChartArc a) {
a.constrainToCircle(QPointF(0,0), edgeReflection);
auto topleft = dataToPixel(complex(a.center.x() - a.radius, a.center.y() - a.radius));
auto bottomright = dataToPixel(complex(a.center.x() + a.radius, a.center.y() + a.radius));
@@ -226,7 +287,7 @@ void TraceSmithChart::draw(QPainter &p) {
auto pen = QPen(pref.Graphs.Color.axis);
pen.setCosmetic(true);
p.setPen(pen);
- drawArc(Arc(QPointF(0, 0), edgeReflection, 0, 2*M_PI));
+ drawArc(SmithChartArc(QPointF(0, 0), edgeReflection, 0, 2*M_PI));
constexpr int Circles = 6;
pen = QPen(pref.Graphs.Color.Ticks.divisions, 0.5, Qt::DashLine);
@@ -234,8 +295,8 @@ void TraceSmithChart::draw(QPainter &p) {
p.setPen(pen);
for(int i=1;i(edgeReflection,0)),dataToPixel(complex(-edgeReflection,0)));
@@ -243,8 +304,18 @@ void TraceSmithChart::draw(QPainter &p) {
for(auto z : impedanceLines) {
z /= ReferenceImpedance;
auto radius = 1.0/z;
- drawArc(Arc(QPointF(1.0, radius), radius, 0, 2*M_PI));
- drawArc(Arc(QPointF(1.0, -radius), radius, 0, 2*M_PI));
+ drawArc(SmithChartArc(QPointF(1.0, radius), radius, 0, 2*M_PI));
+ drawArc(SmithChartArc(QPointF(1.0, -radius), radius, 0, 2*M_PI));
+ }
+
+ // draw custom constant parameter lines
+ for(auto line : constantLines) {
+ pen = QPen(line.getColor(), pref.Graphs.lineWidth);
+ pen.setCosmetic(true);
+ p.setPen(pen);
+ for(auto arc : line.getArcs()) {
+ drawArc(arc);
+ }
}
for(auto t : traces) {
@@ -429,7 +500,7 @@ bool TraceSmithChart::dropSupported(Trace *t)
}
}
-TraceSmithChart::Arc::Arc(QPointF center, double radius, double startAngle, double spanAngle)
+SmithChartArc::SmithChartArc(QPointF center, double radius, double startAngle, double spanAngle)
: center(center),
radius(radius),
startAngle(startAngle),
@@ -438,7 +509,7 @@ TraceSmithChart::Arc::Arc(QPointF center, double radius, double startAngle, doub
}
-void TraceSmithChart::Arc::constrainToCircle(QPointF center, double radius)
+void SmithChartArc::constrainToCircle(QPointF center, double radius)
{
// check if arc/circle intersect
auto centerDiff = this->center - center;
@@ -502,3 +573,267 @@ void TraceSmithChart::Arc::constrainToCircle(QPointF center, double radius)
}
}
}
+
+SmithChartConstantLine::SmithChartConstantLine()
+{
+ type = Type::VSWR;
+ param = 10.0;
+ color = Qt::darkRed;
+}
+
+std::vector SmithChartConstantLine::getArcs()
+{
+ std::vector arcs;
+ switch(type) {
+ case Type::VSWR:
+ arcs.push_back(SmithChartArc(QPointF(0.0, 0.0), (param - 1.0) / (param + 1.0)));
+ break;
+ case Type::Resistance: {
+ auto circleLeft = (param / 50.0 - 1.0) / (param / 50.0 + 1.0);
+ arcs.push_back(SmithChartArc(QPointF((circleLeft + 1.0) / 2, 0.0), (1.0 - circleLeft) / 2.0));
+ }
+ break;
+ case Type::Reactance: {
+ auto radius = 1.0/(param / 50.0);
+ if(radius > 0) {
+ arcs.push_back(SmithChartArc(QPointF(1.0, radius), radius));
+ } else {
+ arcs.push_back(SmithChartArc(QPointF(1.0, radius), -radius));
+ }
+ }
+ break;
+ case Type::Q: {
+ auto center = 1.0 / param;
+ auto radius = sqrt(center*center + 1.0);
+ arcs.push_back(SmithChartArc(QPointF(0.0, center), radius));
+ arcs.push_back(SmithChartArc(QPointF(0.0, -center), radius));
+ }
+ break;
+ case Type::Last:
+ break;
+ }
+ return arcs;
+}
+
+QColor SmithChartConstantLine::getColor() const
+{
+ return color;
+}
+
+void SmithChartConstantLine::fromJSON(nlohmann::json j)
+{
+ type = TypeFromString(QString::fromStdString(j.value("type", "VSWR")));
+ if(type == Type::Last) {
+ type = Type::VSWR;
+ }
+ param = j.value("param", 1.0);
+ color = QColor(QString::fromStdString(j.value("color", "red")));
+}
+
+nlohmann::json SmithChartConstantLine::toJSON()
+{
+ nlohmann::json j;
+ j["type"] = TypeToString(type).toStdString();
+ j["param"] = param;
+ j["color"] = color.name().toStdString();
+ return j;
+}
+
+QString SmithChartConstantLine::getParamUnit()
+{
+ switch(type) {
+ case Type::VSWR: return "";
+ case Type::Resistance: return "Ω";
+ case Type::Reactance: return "Ωj";
+ case Type::Q: return "";
+ case Type::Last: break;
+ }
+ return "";
+}
+
+QString SmithChartConstantLine::TypeToString(SmithChartConstantLine::Type type)
+{
+ switch(type) {
+ case Type::VSWR: return "VSWR";
+ case Type::Resistance: return "Resistance";
+ case Type::Reactance: return "Reactance";
+ case Type::Q: return "Q";
+ case Type::Last:break;
+ }
+ // should never get here
+ return "Invalid";
+}
+
+SmithChartConstantLine::Type SmithChartConstantLine::TypeFromString(QString s)
+{
+ for(unsigned int i=0;i<(unsigned int)Type::Last;i++) {
+ if(TypeToString((Type) i) == s) {
+ return (Type) i;
+ }
+ }
+ return Type::Last;
+}
+
+void SmithChartConstantLine::setColor(const QColor &value)
+{
+ color = value;
+}
+
+double SmithChartConstantLine::getParam() const
+{
+ return param;
+}
+
+void SmithChartConstantLine::setParam(double value)
+{
+ param = value;
+}
+
+void SmithChartConstantLine::setType(const Type &value)
+{
+ type = value;
+}
+
+SmithChartConstantLine::Type SmithChartConstantLine::getType() const
+{
+ return type;
+}
+
+static constexpr int rowHeight = 21;
+
+QSize SmithChartParamDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
+{
+ return QSize(0, rowHeight);
+}
+
+QWidget *SmithChartParamDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
+{
+ auto line = static_cast(index.model())->lineFromIndex(index);
+ auto editor = new SIUnitEdit(line->getParamUnit(), "pnum kMG", 6);
+ editor->setValue(line->getParam());
+ editor->setMaximumHeight(rowHeight);
+ editor->setParent(parent);
+ connect(editor, &SIUnitEdit::valueUpdated, this, &SmithChartParamDelegate::commitData);
+ return editor;
+}
+
+void SmithChartParamDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+ auto line = ((SmithChartContantLineModel*)model)->lineFromIndex(index);
+ auto si = (SIUnitEdit*) editor;
+ line->setParam(si->value());
+}
+
+QSize SmithChartTypeDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
+{
+ return QSize(0, rowHeight);
+}
+
+QWidget *SmithChartTypeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
+{
+ auto line = static_cast(index.model())->lineFromIndex(index);
+ auto editor = new QComboBox();
+ for(unsigned int i=0;i<(unsigned int)SmithChartConstantLine::Type::Last;i++) {
+ editor->addItem(SmithChartConstantLine::TypeToString((SmithChartConstantLine::Type) i));
+ }
+ editor->setCurrentIndex((int) line->getType());
+ connect(editor, qOverload(&QComboBox::currentIndexChanged), [=](int) {
+ emit const_cast(this)->commitData(editor);
+ });
+ editor->setMaximumHeight(rowHeight);
+ editor->setParent(parent);
+ return editor;
+}
+
+void SmithChartTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+ auto line = ((SmithChartContantLineModel*)model)->lineFromIndex(index);
+ auto *cb = (QComboBox*) editor;
+ line->setType((SmithChartConstantLine::Type) cb->currentIndex());
+ // parameter unit may have changed, update model
+ auto paramIndex = model->index(index.row(), SmithChartContantLineModel::ColIndexParam);
+ emit model->dataChanged(paramIndex, paramIndex);
+}
+
+SmithChartContantLineModel::SmithChartContantLineModel(TraceSmithChart &chart, QObject *parent)
+ : chart(chart)
+{
+ Q_UNUSED(parent);
+}
+
+int SmithChartContantLineModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return chart.constantLines.size();
+}
+
+int SmithChartContantLineModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return ColIndexLast;
+}
+
+QVariant SmithChartContantLineModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if ((unsigned int) index.row() >= chart.constantLines.size())
+ return QVariant();
+
+ auto line = chart.constantLines[index.row()];
+ switch(index.column()) {
+ case ColIndexColor:
+ if (role == Qt::BackgroundColorRole) {
+ return line.getColor();
+ }
+ break;
+ case ColIndexType:
+ if (role == Qt::DisplayRole) {
+ return SmithChartConstantLine::TypeToString(line.getType());
+ }
+ break;
+ case ColIndexParam:
+ if (role == Qt::DisplayRole) {
+ return Unit::ToString(line.getParam(), line.getParamUnit(), "pnum kMG", 6);
+ }
+ break;
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+QVariant SmithChartContantLineModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ Q_UNUSED(orientation);
+ if(role == Qt::DisplayRole) {
+ switch(section) {
+ case ColIndexColor: return "Color";
+ case ColIndexType: return "Type";
+ case ColIndexParam: return "Parameter";
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags SmithChartContantLineModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ switch(index.column()) {
+ case ColIndexType:
+ case ColIndexParam:
+ flags |= Qt::ItemIsEditable;
+ break;
+ }
+ return flags;
+}
+
+SmithChartConstantLine* SmithChartContantLineModel::lineFromIndex(const QModelIndex &index) const
+{
+ if(index.isValid() && index.row() < (int) chart.constantLines.size()) {
+ return &chart.constantLines[index.row()];
+ } else {
+ return nullptr;
+ }
+}
diff --git a/Software/PC_Application/Traces/tracesmithchart.h b/Software/PC_Application/Traces/tracesmithchart.h
index 8939dc3..f83f984 100644
--- a/Software/PC_Application/Traces/tracesmithchart.h
+++ b/Software/PC_Application/Traces/tracesmithchart.h
@@ -6,10 +6,102 @@
#include
#include
#include
+#include
+
+class TraceSmithChart;
+
+class SmithChartArc
+{
+public:
+ SmithChartArc(QPointF center, double radius, double startAngle = 0.0, double spanAngle = 2*M_PI);
+ void constrainToCircle(QPointF center, double radius);
+
+ QPointF center;
+ double radius;
+ double startAngle, spanAngle;
+};
+
+class SmithChartConstantLine : public Savable
+{
+public:
+ enum class Type {
+ VSWR,
+ Resistance,
+ Reactance,
+ Q,
+ Last,
+ };
+
+ SmithChartConstantLine();
+ std::vector getArcs();
+ QColor getColor() const;
+ void setColor(const QColor &value);
+
+ void fromJSON(nlohmann::json j) override;
+ nlohmann::json toJSON() override;
+
+ QString getParamUnit();
+
+ Type getType() const;
+ void setType(const Type &value);
+
+ double getParam() const;
+ void setParam(double value);
+
+ static QString TypeToString(Type type);
+ static Type TypeFromString(QString s);
+private:
+ QColor color;
+ double param;
+ Type type;
+};
+
+class SmithChartTypeDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT;
+ QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
+ QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
+ void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
+};
+
+class SmithChartParamDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT;
+ QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
+ QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
+ void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
+};
+
+class SmithChartContantLineModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ friend TraceSmithChart;
+public:
+ SmithChartContantLineModel(TraceSmithChart &chart, QObject *parent = 0);
+
+ enum {
+ ColIndexColor,
+ ColIndexType,
+ ColIndexParam,
+ ColIndexLast,
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+// bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+
+ SmithChartConstantLine *lineFromIndex(const QModelIndex &index) const;
+private:
+ TraceSmithChart &chart;
+};
class TraceSmithChart : public TracePlot
{
Q_OBJECT
+ friend class SmithChartContantLineModel;
public:
TraceSmithChart(TraceModel &model, QWidget *parent = 0);
@@ -27,17 +119,6 @@ protected:
static constexpr double screenUsage = 0.9;
static constexpr double smithCoordMax = 4096;
- class Arc
- {
- public:
- Arc(QPointF center, double radius, double startAngle, double spanAngle);
- void constrainToCircle(QPointF center, double radius);
-
- QPointF center;
- double radius;
- double startAngle, spanAngle;
- };
-
QPoint dataToPixel(std::complex d);
QPoint dataToPixel(Trace::Data d);
std::complex pixelToData(QPoint p);
@@ -56,6 +137,7 @@ protected:
bool limitToEdge;
double edgeReflection; // magnitude of reflection coefficient at the edge of the smith chart (zoom factor)
QTransform transform;
+ std::vector constantLines;
};
#endif // TRACESMITHCHART_H