diff --git a/Software/PC_Application/Traces/tracepolar.cpp b/Software/PC_Application/Traces/tracepolar.cpp index 61e5d2c..942e643 100644 --- a/Software/PC_Application/Traces/tracepolar.cpp +++ b/Software/PC_Application/Traces/tracepolar.cpp @@ -13,6 +13,7 @@ TracePolar::TracePolar(TraceModel &model, QWidget *parent) limitToSpan = true; limitToEdge = true; edgeReflection = 1.0; + dx = 0; initializeTraceInfo(); } @@ -77,7 +78,7 @@ QPoint TracePolar::dataToPixel(std::complex d) return transform.map(QPoint(d.real() * polarCoordMax * (1.0 / edgeReflection), -d.imag() * polarCoordMax * (1.0 / edgeReflection))); } -QPoint TracePolar::dataToPixel(Trace::Data d) +QPoint TracePolar:: dataToPixel(Trace::Data d) { return dataToPixel(d.y); } @@ -236,6 +237,71 @@ void TracePolar::updateContextMenu() finishContextMenu(); } +bool TracePolar::constrainLineToCircle(QPointF &a, QPointF &b, QPointF center, double radius) +{ + auto distance = [](const QPointF &a, const QPointF &b) { + auto dx = b.x() - a.x(); + auto dy = b.y() - a.y(); + return sqrt(dx*dx + dy*dy); + }; + + if(distance(a, center) <= radius && distance(b, center) <= radius) { + // both points are completely contained within the circle, no adjustment necessary + return true; + } + + // shift points, the formulas assume center = (0,0) + a -= center; + b -= center; + + // according to https://mathworld.wolfram.com/Circle-LineIntersection.html + auto dx = b.x() - a.x(); + auto dy = b.y() - a.y(); + auto dr = sqrt(dx*dx+dy*dy); + auto D = a.x()*b.y() - b.x()*a.y(); + // check intersection + auto delta = radius*radius * dr*dr - D*D; + if(delta <= 0) { + // line does not intersect the circle + return false; + } + // line intersects the circle, calculate intersection points + auto x1 = (D*dy+copysign(1.0, dy) * dx*sqrt(delta)) / (dr*dr); + auto x2 = (D*dy-copysign(1.0, dy) * dx*sqrt(delta)) / (dr*dr); + auto y1 = (-D*dx+abs(dy)*sqrt(delta)) / (dr*dr); + auto y2 = (-D*dx-abs(dy)*sqrt(delta)) / (dr*dr); + + auto inter1 = QPointF(x1, y1); + auto inter2 = QPointF(x2, y2); + + bool inter1betweenPoints = false; + bool inter2betweenPoints = false; + if(abs(distance(a, inter1) + distance(b, inter1) - distance(a, b)) < 0.000001) { + inter1betweenPoints = true; + } + if(abs(distance(a, inter2) + distance(b, inter2) - distance(a, b)) < 0.000001) { + inter2betweenPoints = true; + } + if(inter1betweenPoints && inter2betweenPoints) { + // adjust both points, order does not matter + a = inter1; + b = inter2; + } else { + // exactly one intersection point must lie between the two line points, otherwise we would have returned already + auto inter = inter1betweenPoints ? inter1 : inter2; + if(distance(a, QPointF(0,0)) < radius) { + // point is in the circle and can remain unchanged. Use inter as new point b + b = inter; + } else { + // the other way around + a = inter; + } + } + a += center; + b += center; + return true; +} + PolarArc::PolarArc(QPointF center, double radius, double startAngle, double spanAngle) : center(center), radius(radius), diff --git a/Software/PC_Application/Traces/tracepolar.h b/Software/PC_Application/Traces/tracepolar.h index 1865e32..2d878a4 100644 --- a/Software/PC_Application/Traces/tracepolar.h +++ b/Software/PC_Application/Traces/tracepolar.h @@ -43,6 +43,11 @@ protected: virtual void updateContextMenu() override; virtual bool supported(Trace *t) override {Q_UNUSED(t) return false;}; + // given two points and a circle, the two points are adjusted in such a way that the line they describe + // is constrained within the circle. Returns true if there is a remaining line segment in the circle, false + // if the line lies completely outside of the circle (or is tangent to the circle) + static bool constrainLineToCircle(QPointF &a, QPointF &b, QPointF center, double radius); + bool limitToSpan; bool limitToEdge; double edgeReflection; // magnitude of reflection coefficient at the edge of the polar chart (zoom factor) diff --git a/Software/PC_Application/Traces/tracepolarchart.cpp b/Software/PC_Application/Traces/tracepolarchart.cpp index 48e60f0..7fd0c97 100644 --- a/Software/PC_Application/Traces/tracepolarchart.cpp +++ b/Software/PC_Application/Traces/tracepolarchart.cpp @@ -157,13 +157,18 @@ void TracePolarChart::draw(QPainter &p) { last = dataAddDx(last); now = dataAddDx(now); - if (limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) { - // outside of visible area - continue; + // scale to size of smith diagram + QPointF p1 = dataToPixel(last); + QPointF p2 = dataToPixel(now); + + if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) { + // partially outside of visible area, constrain + if(!TracePolar::constrainLineToCircle(p1, p2, transform.map(QPointF(0,0)), polarCoordMax * scale)) { + // completely out of visible area + continue; + } } - // scale to size of diagram - auto p1 = dataToPixel(last); - auto p2 = dataToPixel(now); + // draw line p.drawLine(p1, p2); } @@ -215,9 +220,6 @@ void TracePolarChart::draw(QPainter &p) { bool TracePolarChart::dropSupported(Trace *t) { - if(!t->isReflection()) { - return false; - } switch(t->outputType()) { case Trace::DataType::Frequency: return true; diff --git a/Software/PC_Application/Traces/tracesmithchart.cpp b/Software/PC_Application/Traces/tracesmithchart.cpp index 35d4180..735d397 100644 --- a/Software/PC_Application/Traces/tracesmithchart.cpp +++ b/Software/PC_Application/Traces/tracesmithchart.cpp @@ -247,13 +247,18 @@ void TraceSmithChart::draw(QPainter &p) { last = dataAddDx(last); now = dataAddDx(now); - if (limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) { - // outside of visible area - continue; - } // scale to size of smith diagram - auto p1 = dataToPixel(last); - auto p2 = dataToPixel(now); + QPointF p1 = dataToPixel(last); + QPointF p2 = dataToPixel(now); + + if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) { + // partially outside of visible area, constrain + if(!TracePolar::constrainLineToCircle(p1, p2, transform.map(QPointF(0,0)), polarCoordMax * scale)) { + // completely out of visible area + continue; + } + } + // draw line p.drawLine(p1, p2); }