如何在qcustomplot中找到交叉点



我有一个基于qt(qcustomplot(的应用程序,可以打印两个不同的图。它们有一个交点。如何找到这个点的x和y坐标?

这与绘图没有太大关系,因为您将调查底层数据。假设我们可以使用线在数据点之间进行插值,并且数据集是单值的(即,对于任何xkey坐标,只有一个值(。

下方代码的在线演示

让我们草拟一个解决方案。首先,进行一些预备工作,我们检测是否包含QCustomPlot,以便在没有它的情况下对代码进行测试-模拟必要的类:

#define _USE_MATH_DEFINES
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <optional>
#include <type_traits>
#include <vector>
//#include "qcustomplot.h"
constexpr bool debugOutput = false;
#ifndef QCP_PLOTTABLE_GRAPH_H
struct QCPGraphData { 
double key, value;
QCPGraphData() = default;
QCPGraphData(double x, double y) : key(x), value(y) {}
};
#endif
auto keyLess(const QCPGraphData &l, const QCPGraphData &r) { return l.key < r.key; }
#ifndef QCP_PLOTTABLE_GRAPH_H
template <typename T> struct QCPDataContainer : public std::vector<T> {
using std::vector<T>::vector;
void sort() { std::sort(this->begin(), this->end(), keyLess); }
};
using QCPGraphDataContainer = QCPDataContainer<QCPGraphData>;
#endif
using Point = QCPGraphData;
using Container = QCPGraphDataContainer;
static_assert(std::is_copy_constructible_v<Point>, "Point must be copy-constructible");

一些辅助功能:

std::ostream &operator<<(std::ostream &os, const Point &p) {
return os << "(" << p.key << ", " << p.value << ")";
}
template <class T> bool has_unique_keys(const T &v) {
constexpr auto keyEqual = [](const Point &l, const Point &r) { return l.key == r.key; };
return std::adjacent_find(std::begin(v), std::end(v), keyEqual) == std::end(v);
}
template <class T> bool has_valid_points(const T& v) {
constexpr auto isValid = [](const Point &p) { return std::isfinite(p.key) && std::isfinite(p.value); };
return std::all_of(std::begin(v), std::end(v), isValid);
}

线段交会探测器:

// intersection of two line segments
std::optional<Point> intersection(const Point &a1, const Point &a2, const Point &b1, const Point &b2)
{
auto p1 = a1, p2 = a2, p3 = b1, p4 = b2;
assert(p1.key <= p2.key);
assert(p3.key <= p4.key);
if (debugOutput) std::cout << p1 << "-" << p2 << ", " << p3 << "-" << p4;
auto const denom = (p1.key - p2.key)*(p3.value - p4.value)
- (p1.value - p2.value)*(p3.key - p4.key);
if (fabs(denom) > 1e-6*(p2.key - p1.key)) {
// the lines are not parallel
auto const scale = 1.0/denom;
auto const q = p1.key*p2.value - p1.value*p2.key;
auto const r = p3.key*p4.value - p3.value*p4.key;
auto const x = (q*(p3.key-p4.key) - (p1.key-p2.key)*r) * scale;
if (debugOutput) std::cout << " x=" << x << "n";
if (p1.key <= x && x <= p2.key && p3.key <= x && x <= p4.key) {
auto const y = (q*(p3.value-p4.value) - (p1.value-p2.value)*r) * scale;
return std::optional<Point>(std::in_place, x, y);
}
}
else if (debugOutput) std::cout << "n";
return std::nullopt;
}

一种算法,它遍历按升序key(x(排序的两个点列表,并从这两个列表中找到跨越连续点对的线段的所有交点:

std::vector<Point> findIntersections(const Container &a_, const Container &b_)
{
if (a_.size() < 2 || b_.size() < 2) return {};
static constexpr auto check = [](const auto &c){
assert(has_valid_points(c));
assert(std::is_sorted(c.begin(), c.end(), keyLess));
assert(has_unique_keys(c));
};
check(a_);
check(b_);
bool aFirst = a_.front().key <= b_.front().key;
const auto &a = aFirst ? a_ : b_, &b = aFirst ? b_ : a_;
assert(a.front().key <= b.front().key);
if (a.back().key < b.front().key) return {}; // the key spans don't overlap
std::vector<Point> intersections;
auto ia = a.begin(), ib = b.begin();
Point a1 = *ia++, b1 = *ib++;
while (ia->key < b1.key) a1=*ia++; // advance a until the key spans overlap
for (Point a2 = *ia, b2 = *ib;;) {
auto const ipt = intersection(a1, a2, b1, b2);
if (ipt)
intersections.push_back(*ipt);
bool advanceA = a2.key <= b2.key, advanceB = b2.key <= a2.key;
if (advanceA) {
if (++ia == a.end()) break;
a1 = a2, a2 = *ia;
}
if (advanceB) {
if (++ib == b.end()) break;
b1 = b2, b2 = *ib;
}
}
return intersections;
}

还有一个更通用的版本,也可以按key升序对点进行排序:

auto findIntersections(Container &d1, Container &d2, bool presorted)
{
if (!presorted) {
d1.sort();
d2.sort();
}
return findIntersections(d1, d2);
}

现在进行一些简单的演示:

template <typename Fun>
Container makeGraph(double start, double step, double end, Fun &&fun) {
Container result;
int i = 0;
for (auto x = start; x <= end; x = ++i * step)
result.emplace_back(x, fun(x));
return result;
}
int main()
{
for (auto step2: {0.1, 0.1151484584}) {
auto sinPlot = makeGraph(-2*M_PI, 0.1, 3*M_PI, sin);
auto cosPlot = makeGraph(0., step2, 2*M_PI, cos);
auto intersections = findIntersections(sinPlot, cosPlot);
std::cout << "Intersections:n";
for (auto &ip : intersections)
std::cout << " at " << ip << "n";
}
}

演示输出:

Intersections:
at (0.785613, 0.706509)
at (3.92674, -0.706604)
Intersections:
at (0.785431, 0.706378)
at (3.92693, -0.706732)

相关内容

  • 没有找到相关文章

最新更新