partial line drawing for smith/polar charts
This commit is contained in:
parent
0f22bd1287
commit
75ebed2b5d
@ -13,6 +13,7 @@ TracePolar::TracePolar(TraceModel &model, QWidget *parent)
|
|||||||
limitToSpan = true;
|
limitToSpan = true;
|
||||||
limitToEdge = true;
|
limitToEdge = true;
|
||||||
edgeReflection = 1.0;
|
edgeReflection = 1.0;
|
||||||
|
dx = 0;
|
||||||
initializeTraceInfo();
|
initializeTraceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +237,71 @@ void TracePolar::updateContextMenu()
|
|||||||
finishContextMenu();
|
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)
|
PolarArc::PolarArc(QPointF center, double radius, double startAngle, double spanAngle)
|
||||||
: center(center),
|
: center(center),
|
||||||
radius(radius),
|
radius(radius),
|
||||||
|
@ -43,6 +43,11 @@ protected:
|
|||||||
virtual void updateContextMenu() override;
|
virtual void updateContextMenu() override;
|
||||||
virtual bool supported(Trace *t) override {Q_UNUSED(t) return false;};
|
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 limitToSpan;
|
||||||
bool limitToEdge;
|
bool limitToEdge;
|
||||||
double edgeReflection; // magnitude of reflection coefficient at the edge of the polar chart (zoom factor)
|
double edgeReflection; // magnitude of reflection coefficient at the edge of the polar chart (zoom factor)
|
||||||
|
@ -157,13 +157,18 @@ void TracePolarChart::draw(QPainter &p) {
|
|||||||
last = dataAddDx(last);
|
last = dataAddDx(last);
|
||||||
now = dataAddDx(now);
|
now = dataAddDx(now);
|
||||||
|
|
||||||
|
// scale to size of smith diagram
|
||||||
|
QPointF p1 = dataToPixel(last);
|
||||||
|
QPointF p2 = dataToPixel(now);
|
||||||
|
|
||||||
if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) {
|
if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) {
|
||||||
// outside of visible area
|
// partially outside of visible area, constrain
|
||||||
|
if(!TracePolar::constrainLineToCircle(p1, p2, transform.map(QPointF(0,0)), polarCoordMax * scale)) {
|
||||||
|
// completely out of visible area
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// scale to size of diagram
|
}
|
||||||
auto p1 = dataToPixel(last);
|
|
||||||
auto p2 = dataToPixel(now);
|
|
||||||
// draw line
|
// draw line
|
||||||
p.drawLine(p1, p2);
|
p.drawLine(p1, p2);
|
||||||
}
|
}
|
||||||
@ -215,9 +220,6 @@ void TracePolarChart::draw(QPainter &p) {
|
|||||||
|
|
||||||
bool TracePolarChart::dropSupported(Trace *t)
|
bool TracePolarChart::dropSupported(Trace *t)
|
||||||
{
|
{
|
||||||
if(!t->isReflection()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch(t->outputType()) {
|
switch(t->outputType()) {
|
||||||
case Trace::DataType::Frequency:
|
case Trace::DataType::Frequency:
|
||||||
return true;
|
return true;
|
||||||
|
@ -247,13 +247,18 @@ void TraceSmithChart::draw(QPainter &p) {
|
|||||||
last = dataAddDx(last);
|
last = dataAddDx(last);
|
||||||
now = dataAddDx(now);
|
now = dataAddDx(now);
|
||||||
|
|
||||||
|
// scale to size of smith diagram
|
||||||
|
QPointF p1 = dataToPixel(last);
|
||||||
|
QPointF p2 = dataToPixel(now);
|
||||||
|
|
||||||
if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) {
|
if(limitToEdge && (abs(last.y) > edgeReflection || abs(now.y) > edgeReflection)) {
|
||||||
// outside of visible area
|
// partially outside of visible area, constrain
|
||||||
|
if(!TracePolar::constrainLineToCircle(p1, p2, transform.map(QPointF(0,0)), polarCoordMax * scale)) {
|
||||||
|
// completely out of visible area
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// scale to size of smith diagram
|
}
|
||||||
auto p1 = dataToPixel(last);
|
|
||||||
auto p2 = dataToPixel(now);
|
|
||||||
// draw line
|
// draw line
|
||||||
p.drawLine(p1, p2);
|
p.drawLine(p1, p2);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user