#include "TransparentDraggableCrackObject.h" #include #include #include QList 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(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; }