248 lines
8.7 KiB
C++
248 lines
8.7 KiB
C++
#include "TransparentDraggableCrackObject.h"
|
|
#include <QMouseEvent>
|
|
#include <QWheelEvent>
|
|
#include <cmath>
|
|
|
|
QList<TransparentDraggableCrackObject*> TransparentDraggableCrackObject::s_allCurves;
|
|
TransparentDraggableCrackObject* TransparentDraggableCrackObject::s_activeCurve = nullptr;
|
|
|
|
TransparentDraggableCrackObject::TransparentDraggableCrackObject(QMyCustomPlot *parentPlot,
|
|
const QString &strUuid,
|
|
double depth)
|
|
: QObject(parentPlot)
|
|
, mPlot(parentPlot)
|
|
, m_depth(depth)
|
|
, m_endX(mPlot->m_iX2)
|
|
, m_orig_x1(m_endX * 0.18)
|
|
, m_orig_x2(m_endX * 0.82)
|
|
, m_orig_y1(depth + 1.0)
|
|
, m_orig_y2(depth - 1.0)
|
|
, m_orig_startX(0)
|
|
, m_orig_endX(m_endX)
|
|
, m_orig_startDirX(m_endX * 0.3)
|
|
, m_orig_endDirX(m_endX * 0.7)
|
|
, m_offsetX(0.0)
|
|
, m_offsetY(0.0)
|
|
{
|
|
mPlot->setInteraction(QCP::iRangeDrag, false);
|
|
mPlot->setInteraction(QCP::iRangeZoom, true);
|
|
|
|
mCurve = new QCPItemCurve(mPlot);
|
|
mCurve->setPen(QPen(Qt::black, 2));
|
|
mCurve->setLayer("overlay");
|
|
|
|
updateCurveFromTargets();
|
|
updateCurvePosition();
|
|
|
|
auto createTracer = [this](double x, double y, const QColor &color) -> QCPItemTracer* {
|
|
QCPItemTracer *t = new QCPItemTracer(mPlot);
|
|
t->setStyle(QCPItemTracer::tsCircle);
|
|
t->setSize(12);
|
|
t->setPen(QPen(Qt::black, 1));
|
|
t->setBrush(QBrush(color));
|
|
t->setSelectable(true);
|
|
t->setLayer("overlay");
|
|
t->position->setCoords(x, y);
|
|
return t;
|
|
};
|
|
m_tracer1 = createTracer(m_orig_x1, m_orig_y1, Qt::cyan);
|
|
m_tracer2 = createTracer(m_orig_x2, m_orig_y2, Qt::cyan);
|
|
updateTracers();
|
|
|
|
// 注册到全局列表
|
|
s_allCurves.append(this);
|
|
|
|
mPlot->installEventFilter(this);
|
|
mPlot->replot();
|
|
}
|
|
|
|
TransparentDraggableCrackObject::~TransparentDraggableCrackObject()
|
|
{
|
|
s_allCurves.removeAll(this);
|
|
if (s_activeCurve == this) s_activeCurve = nullptr;
|
|
}
|
|
|
|
void TransparentDraggableCrackObject::updateCurveFromTargets()
|
|
{
|
|
double t1 = m_orig_x1 / m_endX;
|
|
double t2 = m_orig_x2 / m_endX;
|
|
double u1 = 1 - t1, u2 = 1 - t2;
|
|
|
|
double P0x = 0, P0y = m_depth;
|
|
double P3x = m_endX, P3y = m_depth;
|
|
double P1x = m_orig_x1, P2x = m_orig_x2;
|
|
|
|
double a11 = 3 * u1 * u1 * t1;
|
|
double a12 = 3 * u1 * t1 * t1;
|
|
double b1 = m_orig_y1 - (u1*u1*u1 * P0y + t1*t1*t1 * P3y);
|
|
|
|
double a21 = 3 * u2 * u2 * t2;
|
|
double a22 = 3 * u2 * t2 * t2;
|
|
double b2 = m_orig_y2 - (u2*u2*u2 * P0y + t2*t2*t2 * P3y);
|
|
|
|
double det = a11 * a22 - a12 * a21;
|
|
if (fabs(det) > 1e-6) {
|
|
double P1y = (b1 * a22 - a12 * b2) / det;
|
|
double P2y = (a11 * b2 - b1 * a21) / det;
|
|
m_orig_startDirX = P1x;
|
|
m_orig_startDirY = P1y;
|
|
m_orig_endDirX = P2x;
|
|
m_orig_endDirY = P2y;
|
|
}
|
|
}
|
|
|
|
void TransparentDraggableCrackObject::updateCurvePosition()
|
|
{
|
|
mCurve->start->setCoords(m_orig_startX + m_offsetX, m_depth + m_offsetY);
|
|
mCurve->end->setCoords(m_orig_endX + m_offsetX, m_depth + m_offsetY);
|
|
mCurve->startDir->setCoords(m_orig_startDirX + m_offsetX, m_orig_startDirY + m_offsetY);
|
|
mCurve->endDir->setCoords(m_orig_endDirX + m_offsetX, m_orig_endDirY + m_offsetY);
|
|
}
|
|
|
|
void TransparentDraggableCrackObject::updateTracers()
|
|
{
|
|
m_tracer1->position->setCoords(m_orig_x1 + m_offsetX, m_orig_y1 + m_offsetY);
|
|
m_tracer2->position->setCoords(m_orig_x2 + m_offsetX, m_orig_y2 + m_offsetY);
|
|
}
|
|
|
|
void TransparentDraggableCrackObject::setTracerHighlight(QCPItemTracer *tracer, bool highlight)
|
|
{
|
|
if (!tracer) return;
|
|
if (highlight) {
|
|
tracer->setPen(QPen(Qt::red, 2));
|
|
tracer->setBrush(QBrush(Qt::red));
|
|
} else {
|
|
tracer->setPen(QPen(Qt::black, 1));
|
|
tracer->setBrush(QBrush(Qt::cyan));
|
|
}
|
|
mPlot->replot();
|
|
}
|
|
|
|
bool TransparentDraggableCrackObject::eventFilter(QObject *obj, QEvent *event)
|
|
{
|
|
if (obj != mPlot) return false;
|
|
if (event->type() == QEvent::Wheel) return false;
|
|
|
|
QMouseEvent *me = static_cast<QMouseEvent*>(event);
|
|
switch (event->type()) {
|
|
case QEvent::MouseButtonPress:
|
|
if (me->button() == Qt::LeftButton) {
|
|
QPointF pixel = me->localPos();
|
|
// 找出所有曲线中命中距离最近的那个
|
|
TransparentDraggableCrackObject* bestCurve = nullptr;
|
|
double bestDist = 1e9;
|
|
int hitType = -1; // 0:point1, 1:point2, 2:curve
|
|
for (auto *curve : s_allCurves) {
|
|
double d1 = curve->m_tracer1->selectTest(pixel, false);
|
|
double d2 = curve->m_tracer2->selectTest(pixel, false);
|
|
double dCurve = curve->mCurve->selectTest(pixel, false);
|
|
if (d1 >= 0 && d1 < 15 && d1 < bestDist) {
|
|
bestDist = d1;
|
|
bestCurve = curve;
|
|
hitType = 0;
|
|
}
|
|
if (d2 >= 0 && d2 < 15 && d2 < bestDist) {
|
|
bestDist = d2;
|
|
bestCurve = curve;
|
|
hitType = 1;
|
|
}
|
|
if (dCurve >= 0 && dCurve < 20 && dCurve < bestDist) {
|
|
bestDist = dCurve;
|
|
bestCurve = curve;
|
|
hitType = 2;
|
|
}
|
|
}
|
|
if (bestCurve) {
|
|
// 清除当前活动曲线的高亮
|
|
if (s_activeCurve && s_activeCurve != bestCurve) {
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer1, false);
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer2, false);
|
|
s_activeCurve->m_dragState = Idle;
|
|
}
|
|
s_activeCurve = bestCurve;
|
|
if (hitType == 0) {
|
|
s_activeCurve->m_dragState = DraggingPoint1;
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer1, true);
|
|
} else if (hitType == 1) {
|
|
s_activeCurve->m_dragState = DraggingPoint2;
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer2, true);
|
|
} else {
|
|
s_activeCurve->m_dragState = DraggingCurve;
|
|
s_activeCurve->m_lastDragPixel = pixel;
|
|
}
|
|
event->accept();
|
|
return true;
|
|
} else {
|
|
// 未命中任何曲线,清除活动曲线
|
|
if (s_activeCurve) {
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer1, false);
|
|
s_activeCurve->setTracerHighlight(s_activeCurve->m_tracer2, false);
|
|
s_activeCurve->m_dragState = Idle;
|
|
s_activeCurve = nullptr;
|
|
mPlot->replot();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case QEvent::MouseMove:
|
|
if (s_activeCurve != this) return false;
|
|
if (m_dragState == DraggingPoint1 || m_dragState == DraggingPoint2) {
|
|
double newY = mPlot->yAxis->pixelToCoord(me->localPos().y());
|
|
double currentAbsY1 = m_orig_y1 + m_offsetY;
|
|
double deltaY = newY - currentAbsY1;
|
|
if (m_dragState == DraggingPoint1) {
|
|
m_orig_y1 += deltaY;
|
|
m_orig_y2 -= deltaY;
|
|
} else {
|
|
m_orig_y2 += deltaY;
|
|
m_orig_y1 -= deltaY;
|
|
}
|
|
updateCurveFromTargets();
|
|
updateCurvePosition();
|
|
updateTracers();
|
|
mPlot->replot();
|
|
event->accept();
|
|
return true;
|
|
} else if (m_dragState == DraggingCurve) {
|
|
QPointF currentPixel = me->localPos();
|
|
double oldX = mPlot->xAxis->pixelToCoord(m_lastDragPixel.x());
|
|
double newX = mPlot->xAxis->pixelToCoord(currentPixel.x());
|
|
double oldY = mPlot->yAxis->pixelToCoord(m_lastDragPixel.y());
|
|
double newY = mPlot->yAxis->pixelToCoord(currentPixel.y());
|
|
|
|
double deltaX = newX - oldX;
|
|
double deltaY = newY - oldY;
|
|
|
|
if (fabs(deltaX) > 1e-6) m_offsetX += deltaX;
|
|
if (fabs(deltaY) > 1e-6) m_offsetY += deltaY;
|
|
|
|
updateCurvePosition();
|
|
updateTracers();
|
|
mPlot->replot();
|
|
|
|
m_lastDragPixel = currentPixel;
|
|
event->accept();
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case QEvent::MouseButtonRelease:
|
|
if (me->button() == Qt::LeftButton && s_activeCurve == this) {
|
|
setTracerHighlight(m_tracer1, false);
|
|
setTracerHighlight(m_tracer2, false);
|
|
m_dragState = Idle;
|
|
s_activeCurve = nullptr;
|
|
mPlot->replot();
|
|
event->accept();
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|