From 5a5d87ebb499a3428232989223077021b9bfe4be Mon Sep 17 00:00:00 2001 From: crqiqi77 Date: Thu, 16 Apr 2026 10:22:24 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A3=82=E7=BC=9D=20=E7=94=BB=E5=9B=BE=20?= =?UTF-8?q?=E7=BD=91=E7=8A=B6=E7=BC=9D=20=E5=AD=94=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logPlus/TransparentDraggableCrackObject.cpp | 676 +++++++++++++++----- logPlus/TransparentDraggableCrackObject.h | 71 +- logPlus/qmycustomplot.cpp | 25 +- 3 files changed, 600 insertions(+), 172 deletions(-) diff --git a/logPlus/TransparentDraggableCrackObject.cpp b/logPlus/TransparentDraggableCrackObject.cpp index 09eb165..f70c615 100644 --- a/logPlus/TransparentDraggableCrackObject.cpp +++ b/logPlus/TransparentDraggableCrackObject.cpp @@ -1,56 +1,82 @@ #include "TransparentDraggableCrackObject.h" #include #include +#include #include -QList TransparentDraggableCrackObject::s_allCurves; -TransparentDraggableCrackObject* TransparentDraggableCrackObject::s_activeCurve = nullptr; +QPointer TransparentDraggableCrackObject::s_activeObject = nullptr; -TransparentDraggableCrackObject::TransparentDraggableCrackObject(QMyCustomPlot *parentPlot, +TransparentDraggableCrackObject::TransparentDraggableCrackObject(QCustomPlot *parentPlot, const QString &strUuid, - double depth) + double depth, + CurveType type) : QObject(parentPlot) , mPlot(parentPlot) + , m_type(type) + , m_uuid(strUuid) , 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) + , m_endX(mPlot->xAxis->range().upper) + , mCurve(nullptr) + , m_tracer1(nullptr) + , m_tracer2(nullptr) + , m_dragStateA(IdleA) + , m_isAddingLine(false) + , m_offsetXB(0.0), m_offsetYB(0.0) + , m_dragStateB(IdleB) + , m_draggedLineIndex(-1) + , m_curveC(nullptr) + , m_offsetXC(0.0), m_offsetYC(0.0) + , m_cFinished(false) + , m_cDragging(false) + , m_draggingPoint(false) + , m_draggedPointIndex(-1) { - mPlot->setInteraction(QCP::iRangeDrag, false); - mPlot->setInteraction(QCP::iRangeZoom, true); + // 注意:不要在这里清除全局活动对象,否则会影响已创建的其他对象 - mCurve = new QCPItemCurve(mPlot); - mCurve->setPen(QPen(Qt::black, 2)); - mCurve->setLayer("overlay"); + if (m_type == TYPE_A) { + 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_offsetXA = 0.0; + m_offsetYA = 0.0; - updateCurveFromTargets(); - updateCurvePosition(); + mCurve = new QCPItemCurve(mPlot); + mCurve->setPen(QPen(Qt::black, 2)); + mCurve->setLayer("overlay"); - 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(); + updateCurveFromTargets(); + updateCurvePosition(); - // 注册到全局列表 - s_allCurves.append(this); + 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_offsetXA, m_orig_y1 + m_offsetYA, Qt::cyan); + m_tracer2 = createTracer(m_orig_x2 + m_offsetXA, m_orig_y2 + m_offsetYA, Qt::cyan); + updateTracers(); + } + else if (m_type == TYPE_B) { + // nothing + } + else if (m_type == TYPE_C) { + m_curveC = new QCPCurve(mPlot->xAxis, mPlot->yAxis); + m_curveC->setPen(QPen(Qt::red, 2)); + m_curveC->setScatterStyle(QCPScatterStyle::ssCircle); + m_curveC->setLineStyle(QCPCurve::lsLine); + m_curveC->setLayer("overlay"); + } mPlot->installEventFilter(this); mPlot->replot(); @@ -58,28 +84,26 @@ TransparentDraggableCrackObject::TransparentDraggableCrackObject(QMyCustomPlot * TransparentDraggableCrackObject::~TransparentDraggableCrackObject() { - s_allCurves.removeAll(this); - if (s_activeCurve == this) s_activeCurve = nullptr; + if (m_type == TYPE_B) clearLines(); + if (m_type == TYPE_C) clearPolylineC(); + if (s_activeObject == this) s_activeObject = nullptr; } +// ========== 模式A辅助 ========== 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; @@ -93,16 +117,18 @@ void TransparentDraggableCrackObject::updateCurveFromTargets() 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); + if (!mCurve) return; + mCurve->start->setCoords(m_orig_startX + m_offsetXA, m_depth + m_offsetYA); + mCurve->end->setCoords(m_orig_endX + m_offsetXA, m_depth + m_offsetYA); + mCurve->startDir->setCoords(m_orig_startDirX + m_offsetXA, m_orig_startDirY + m_offsetYA); + mCurve->endDir->setCoords(m_orig_endDirX + m_offsetXA, m_orig_endDirY + m_offsetYA); } 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); + if (!m_tracer1 || !m_tracer2) return; + m_tracer1->position->setCoords(m_orig_x1 + m_offsetXA, m_orig_y1 + m_offsetYA); + m_tracer2->position->setCoords(m_orig_x2 + m_offsetXA, m_orig_y2 + m_offsetYA); } void TransparentDraggableCrackObject::setTracerHighlight(QCPItemTracer *tracer, bool highlight) @@ -118,130 +144,476 @@ void TransparentDraggableCrackObject::setTracerHighlight(QCPItemTracer *tracer, mPlot->replot(); } +// ========== 模式B辅助 ========== +void TransparentDraggableCrackObject::updateLineEndpoints(LineItem &item) +{ + item.startTracer->position->setCoords(item.startOrig.x() + m_offsetXB, item.startOrig.y() + m_offsetYB); + item.endTracer->position->setCoords(item.endOrig.x() + m_offsetXB, item.endOrig.y() + m_offsetYB); +} + +void TransparentDraggableCrackObject::updateLinesPosition() +{ + for (auto &item : m_lines) { + item.line->start->setCoords(item.startOrig.x() + m_offsetXB, item.startOrig.y() + m_offsetYB); + item.line->end->setCoords(item.endOrig.x() + m_offsetXB, item.endOrig.y() + m_offsetYB); + updateLineEndpoints(item); + } +} + +void TransparentDraggableCrackObject::clearLines() +{ + for (auto &item : m_lines) { + mPlot->removeItem(item.line); + delete item.line; + if (item.startTracer) { mPlot->removeItem(item.startTracer); delete item.startTracer; } + if (item.endTracer) { mPlot->removeItem(item.endTracer); delete item.endTracer; } + } + m_lines.clear(); + m_isAddingLine = false; + mPlot->replot(); +} + +// ========== 模式C辅助 ========== +void TransparentDraggableCrackObject::updatePolylineC(bool closed) +{ + if (!m_curveC) return; + if (m_pointsC.isEmpty()) { + m_curveC->setData(QVector(), QVector()); + return; + } + QVector xs, ys; + for (const auto &p : m_pointsC) { + xs << p.x() + m_offsetXC; + ys << p.y() + m_offsetYC; + } + if (closed && m_pointsC.size() >= 3) { + xs << m_pointsC.first().x() + m_offsetXC; + ys << m_pointsC.first().y() + m_offsetYC; + } + m_curveC->setData(xs, ys); +} + +void TransparentDraggableCrackObject::clearPolylineC() +{ + QVector labelsToDelete = m_labelsC; + m_labelsC.clear(); + for (auto label : labelsToDelete) { + if (label) { + mPlot->removeItem(label); + delete label; + } + } + m_pointsC.clear(); + if (m_curveC) { + m_curveC->setData(QVector(), QVector()); + } + m_offsetXC = m_offsetYC = 0.0; + m_cFinished = false; + m_draggingPoint = false; + m_draggedPointIndex = -1; + if (s_activeObject == this) s_activeObject = nullptr; + mPlot->replot(); +} + +// ========== 状态重置 ========== +void TransparentDraggableCrackObject::deactivate() +{ + qDebug() << "[Deactivate]" << m_uuid; + if (m_type == TYPE_A) { + setTracerHighlight(m_tracer1, false); + setTracerHighlight(m_tracer2, false); + m_dragStateA = IdleA; + } else if (m_type == TYPE_B) { + m_dragStateB = IdleB; + m_draggedLineIndex = -1; + } else if (m_type == TYPE_C) { + m_cDragging = false; + m_draggingPoint = false; + m_draggedPointIndex = -1; + } + 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; - } + bool shiftPressed = (me->modifiers() & Qt::ShiftModifier); + + // 鼠标按下 + if (event->type() == QEvent::MouseButtonPress && me->button() == Qt::LeftButton) { + bool hit = false; + + // ========== 模式B:添加直线(优先级最高) ========== + if (m_type == TYPE_B && shiftPressed) { + if (!m_isAddingLine) { + double x = mPlot->xAxis->pixelToCoord(me->pos().x()); + double y = mPlot->yAxis->pixelToCoord(me->pos().y()); + m_tempPoint = QPointF(x - m_offsetXB, y - m_offsetYB); + m_isAddingLine = true; + qDebug() << "Start adding line, point:" << m_tempPoint; 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(); + double x = mPlot->xAxis->pixelToCoord(me->pos().x()); + double y = mPlot->yAxis->pixelToCoord(me->pos().y()); + QPointF p2(x - m_offsetXB, y - m_offsetYB); + QCPItemLine *line = new QCPItemLine(mPlot); + line->setPen(QPen(Qt::blue, 2)); + line->setLayer("overlay"); + auto createTracer = [this](double x, double y, const QColor &color) -> QCPItemTracer* { + QCPItemTracer *t = new QCPItemTracer(mPlot); + t->setStyle(QCPItemTracer::tsCircle); + t->setSize(10); + t->setPen(QPen(Qt::black, 1)); + t->setBrush(QBrush(color)); + t->setSelectable(true); + t->setLayer("overlay"); + t->position->setCoords(x + m_offsetXB, y + m_offsetYB); + return t; + }; + QCPItemTracer *startTracer = createTracer(m_tempPoint.x(), m_tempPoint.y(), Qt::green); + QCPItemTracer *endTracer = createTracer(p2.x(), p2.y(), Qt::green); + LineItem item; + item.startOrig = m_tempPoint; + item.endOrig = p2; + item.line = line; + item.startTracer = startTracer; + item.endTracer = endTracer; + m_lines.append(item); + updateLinesPosition(); + m_isAddingLine = false; + mPlot->replot(); + qDebug() << "Line added from" << m_tempPoint << "to" << p2; + event->accept(); + return true; + } + } + + // ========== 模式A ========== + if (m_type == TYPE_A && !shiftPressed) { + QPointF pixel = me->localPos(); + double d1 = m_tracer1->selectTest(pixel, false); + double d2 = m_tracer2->selectTest(pixel, false); + double curveDist = mCurve->selectTest(pixel, false); + if (d1 >= 0 && d1 < 15 || d2 >= 0 && d2 < 15 || (curveDist >= 0 && curveDist < 5)) { + hit = true; + if (s_activeObject && s_activeObject != this) { + s_activeObject->deactivate(); } - return false; + s_activeObject = this; + if (d1 >= 0 && d1 < 15) { + m_dragStateA = DraggingPoint1; + setTracerHighlight(m_tracer1, true); + } else if (d2 >= 0 && d2 < 15) { + m_dragStateA = DraggingPoint2; + setTracerHighlight(m_tracer2, true); + } else { + m_dragStateA = DraggingCurveA; + m_lastDragPixelA = pixel; + } + event->accept(); + return true; } } - 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; + // ========== 模式B:拖拽(非Shift) ========== + if (m_type == TYPE_B && !shiftPressed && !m_isAddingLine) { + QPointF pixel = me->localPos(); + bool found = false; + for (int i = 0; i < m_lines.size(); ++i) { + auto &item = m_lines[i]; + if (item.startTracer->selectTest(pixel, false) >= 0 && item.startTracer->selectTest(pixel, false) < 10) { + found = true; + hit = true; + if (s_activeObject && s_activeObject != this) s_activeObject->deactivate(); + s_activeObject = this; + m_dragStateB = DraggingStartPoint; + m_draggedLineIndex = i; + m_bDragStart = pixel; + event->accept(); + return true; + } + if (item.endTracer->selectTest(pixel, false) >= 0 && item.endTracer->selectTest(pixel, false) < 10) { + found = true; + hit = true; + if (s_activeObject && s_activeObject != this) s_activeObject->deactivate(); + s_activeObject = this; + m_dragStateB = DraggingEndPoint; + m_draggedLineIndex = i; + m_bDragStart = pixel; + event->accept(); + return true; + } + } + if (!found) { + for (int i = 0; i < m_lines.size(); ++i) { + double dist = m_lines[i].line->selectTest(pixel, false); + if (dist >= 0 && dist < 3) { + hit = true; + if (s_activeObject && s_activeObject != this) s_activeObject->deactivate(); + s_activeObject = this; + m_dragStateB = DraggingLineOverall; + m_bDragStart = pixel; + event->accept(); + return true; + } + } + } + } + + // ========== 模式C ========== + // ========== 模式C ========== + if (m_type == TYPE_C) { + // 1. 左键添加点(Shift) + if (shiftPressed && me->button() == Qt::LeftButton && !m_cFinished) { + if (s_activeObject != this) { + if (s_activeObject) s_activeObject->deactivate(); + s_activeObject = this; + } + double x = mPlot->xAxis->pixelToCoord(me->pos().x()); + double y = mPlot->yAxis->pixelToCoord(me->pos().y()); + QPointF pt(x - m_offsetXC, y - m_offsetYC); + m_pointsC.append(pt); + QCPItemText *label = new QCPItemText(mPlot); + label->setText(QString::number(m_pointsC.size())); + label->setFont(QFont("Arial", 10, QFont::Bold)); + label->setColor(Qt::white); + label->setBrush(QBrush(Qt::blue)); + label->setPen(QPen(Qt::black, 1)); +// label->setPadding(2); + label->position->setCoords(x, y); + label->setPositionAlignment(Qt::AlignCenter); + label->setLayer("overlay"); + m_labelsC.append(label); + updatePolylineC(false); + mPlot->replot(); + event->accept(); + return true; + } + // 2. 左键空白闭环(非Shift,未完成时) + if (!shiftPressed && me->button() == Qt::LeftButton && !m_cFinished) { + if (m_pointsC.size() >= 3) { + m_cFinished = true; + updatePolylineC(true); + mPlot->replot(); + } else { + clearPolylineC(); + } + if (s_activeObject == this) { + s_activeObject->deactivate(); + s_activeObject = nullptr; + } + event->accept(); + return true; + } + // 3. 拖拽整体或点(已完成,非Shift左键) + if (!shiftPressed && me->button() == Qt::LeftButton && m_cFinished) { + QPointF pixel = me->localPos(); + // 优先检测是否命中某个数据点(通过标签) + int hitPointIndex = -1; + for (int i = 0; i < m_labelsC.size(); ++i) { + double dist = m_labelsC[i]->selectTest(pixel, false); + if (dist >= 0 && dist < 10) { + hitPointIndex = i; + break; + } + } + if (hitPointIndex >= 0) { + hit = true; + if (s_activeObject != this) { + if (s_activeObject) s_activeObject->deactivate(); + s_activeObject = this; + } + m_draggingPoint = true; + m_draggedPointIndex = hitPointIndex; + // 记录拖拽开始时的鼠标像素坐标和点的原始坐标(用于计算偏移) + m_cDragStart = pixel; + event->accept(); + return true; + } else { + // 未命中点,检测曲线本体 + double curveDist = m_curveC ? m_curveC->selectTest(pixel, false) : -1; + if (curveDist >= 0 && curveDist < 3) { + hit = true; + if (s_activeObject != this) { + if (s_activeObject) s_activeObject->deactivate(); + s_activeObject = this; + } + m_cDragging = true; + m_cDragStart = pixel; + event->accept(); + return true; + } else { + // 未命中任何图元,清除活动对象 + if (s_activeObject == this) { + s_activeObject->deactivate(); + s_activeObject = nullptr; + } + return false; + } + } + } + } + + // 未命中任何图元:清除全局活动对象 + if (!hit) { + if (s_activeObject) { + s_activeObject->deactivate(); + s_activeObject = nullptr; + } + return false; + } + return false; + } + + // 鼠标移动 + if (event->type() == QEvent::MouseMove) { + if (s_activeObject != this) return false; + + // 模式A移动 + if (m_type == TYPE_A) { + if (m_dragStateA == DraggingPoint1 || m_dragStateA == DraggingPoint2) { + double newY = mPlot->yAxis->pixelToCoord(me->localPos().y()); + double currentY = (m_dragStateA == DraggingPoint1) ? m_orig_y1 : m_orig_y2; + double deltaY = newY - (currentY + m_offsetYA); + if (fabs(deltaY) > 5) deltaY = (deltaY > 0 ? 5 : -5); + double newOrigY = currentY + deltaY; + double minY = m_depth - 100; + double maxY = m_depth + 100; + newOrigY = qBound(minY, newOrigY, maxY); + if (m_dragStateA == DraggingPoint1) m_orig_y1 = newOrigY; + else m_orig_y2 = newOrigY; + updateCurveFromTargets(); + updateCurvePosition(); + updateTracers(); + mPlot->replot(); + return true; + } else if (m_dragStateA == DraggingCurveA) { + QPointF current = me->localPos(); + double oldX = mPlot->xAxis->pixelToCoord(m_lastDragPixelA.x()); + double newX = mPlot->xAxis->pixelToCoord(current.x()); + double oldY = mPlot->yAxis->pixelToCoord(m_lastDragPixelA.y()); + double newY = mPlot->yAxis->pixelToCoord(current.y()); + double dx = newX - oldX; + double dy = newY - oldY; + m_offsetXA += dx; + m_offsetYA += dy; + updateCurvePosition(); + updateTracers(); + mPlot->replot(); + m_lastDragPixelA = current; + return true; + } + } + // 模式B移动 + else if (m_type == TYPE_B && m_dragStateB != IdleB) { + QPointF current = me->localPos(); + double oldX = mPlot->xAxis->pixelToCoord(m_bDragStart.x()); + double newX = mPlot->xAxis->pixelToCoord(current.x()); + double oldY = mPlot->yAxis->pixelToCoord(m_bDragStart.y()); + double newY = mPlot->yAxis->pixelToCoord(current.y()); + double dx = newX - oldX; + double dy = newY - oldY; + if (m_dragStateB == DraggingLineOverall) { + m_offsetXB += dx; + m_offsetYB += dy; + updateLinesPosition(); + } else if (m_dragStateB == DraggingStartPoint || m_dragStateB == DraggingEndPoint) { + int idx = m_draggedLineIndex; + if (idx >= 0 && idx < m_lines.size()) { + LineItem &item = m_lines[idx]; + if (m_dragStateB == DraggingStartPoint) { + item.startOrig.rx() += dx; + item.startOrig.ry() += dy; + } else { + item.endOrig.rx() += dx; + item.endOrig.ry() += dy; + } + item.line->start->setCoords(item.startOrig.x() + m_offsetXB, item.startOrig.y() + m_offsetYB); + item.line->end->setCoords(item.endOrig.x() + m_offsetXB, item.endOrig.y() + m_offsetYB); + updateLineEndpoints(item); + } } - 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(); + m_bDragStart = current; return true; } - break; + // 模式C移动 + // 模式C移动 + else if (m_type == TYPE_C) { + if (m_cDragging) { + // 整体拖拽 + QPointF current = me->localPos(); + double oldX = mPlot->xAxis->pixelToCoord(m_cDragStart.x()); + double newX = mPlot->xAxis->pixelToCoord(current.x()); + double oldY = mPlot->yAxis->pixelToCoord(m_cDragStart.y()); + double newY = mPlot->yAxis->pixelToCoord(current.y()); + double dx = newX - oldX; + double dy = newY - oldY; + m_offsetXC += dx; + m_offsetYC += dy; + for (int i = 0; i < m_pointsC.size(); ++i) { + m_labelsC[i]->position->setCoords(m_pointsC[i].x() + m_offsetXC, m_pointsC[i].y() + m_offsetYC); + } + updatePolylineC(m_cFinished && m_pointsC.size() >= 3); + mPlot->replot(); + m_cDragStart = current; + return true; + } else if (m_draggingPoint) { + // 点拖拽:支持二维移动 + QPointF current = me->localPos(); + // 计算鼠标在轴坐标系下的移动量(直接使用像素转坐标,但为了精确,计算差值) + double oldX = mPlot->xAxis->pixelToCoord(m_cDragStart.x()); + double newX = mPlot->xAxis->pixelToCoord(current.x()); + double oldY = mPlot->yAxis->pixelToCoord(m_cDragStart.y()); + double newY = mPlot->yAxis->pixelToCoord(current.y()); + double dx = newX - oldX; + double dy = newY - oldY; + // 更新点的原始坐标 + m_pointsC[m_draggedPointIndex].rx() += dx; + m_pointsC[m_draggedPointIndex].ry() += dy; + // 更新标签位置 + m_labelsC[m_draggedPointIndex]->position->setCoords(m_pointsC[m_draggedPointIndex].x() + m_offsetXC, + m_pointsC[m_draggedPointIndex].y() + m_offsetYC); + updatePolylineC(m_cFinished && m_pointsC.size() >= 3); + mPlot->replot(); + // 更新拖拽起始点 + m_cDragStart = current; + return true; + } + } - case QEvent::MouseButtonRelease: - if (me->button() == Qt::LeftButton && s_activeCurve == this) { + return false; + } + + // 鼠标释放 + if (event->type() == QEvent::MouseButtonRelease && me->button() == Qt::LeftButton) { + if (s_activeObject != this) return false; + + if (m_type == TYPE_A && m_dragStateA != IdleA) { setTracerHighlight(m_tracer1, false); setTracerHighlight(m_tracer2, false); - m_dragState = Idle; - s_activeCurve = nullptr; - mPlot->replot(); - event->accept(); + m_dragStateA = IdleA; return true; + } else if (m_type == TYPE_B && m_dragStateB != IdleB) { + m_dragStateB = IdleB; + m_draggedLineIndex = -1; + return true; + } else if (m_type == TYPE_C) { + if (m_cDragging) { + m_cDragging = false; + return true; + } else if (m_draggingPoint) { + m_draggingPoint = false; + m_draggedPointIndex = -1; + return true; + } } - break; - - default: - break; } + return false; } diff --git a/logPlus/TransparentDraggableCrackObject.h b/logPlus/TransparentDraggableCrackObject.h index e2e649b..a5e7523 100644 --- a/logPlus/TransparentDraggableCrackObject.h +++ b/logPlus/TransparentDraggableCrackObject.h @@ -2,50 +2,85 @@ #define TRANSPARENTDRAGGABLECRACKOBJECT_H #include -#include "qmycustomplot.h" -#include +#include +#include +#include "qcustomplot.h" class TransparentDraggableCrackObject : public QObject { Q_OBJECT public: - explicit TransparentDraggableCrackObject(QMyCustomPlot *parentPlot, - const QString &strUuid = "", - double depth = 0); + enum CurveType { TYPE_A, TYPE_B, TYPE_C }; + + explicit TransparentDraggableCrackObject(QCustomPlot *parentPlot, + const QString &strUuid, + double depth = 0, + CurveType type = TYPE_A); ~TransparentDraggableCrackObject(); protected: bool eventFilter(QObject *obj, QEvent *event) override; private: - static QList s_allCurves; // 所有曲线实例 - static TransparentDraggableCrackObject* s_activeCurve; // 当前活动曲线 - - QMyCustomPlot *mPlot; - QCPItemCurve *mCurve; + QCustomPlot *mPlot; + CurveType m_type; + QString m_uuid; double m_depth; double m_endX; + static QPointer s_activeObject; + + // 模式A + QCPItemCurve *mCurve; double m_orig_x1, m_orig_x2; double m_orig_y1, m_orig_y2; double m_orig_startX, m_orig_endX; double m_orig_startDirX, m_orig_startDirY; double m_orig_endDirX, m_orig_endDirY; + double m_offsetXA, m_offsetYA; + QCPItemTracer *m_tracer1, *m_tracer2; + enum DragStateA { IdleA, DraggingPoint1, DraggingPoint2, DraggingCurveA }; + DragStateA m_dragStateA; + QPointF m_lastDragPixelA; - double m_offsetX; - double m_offsetY; + // 模式B + struct LineItem { + QPointF startOrig; + QPointF endOrig; + QCPItemLine *line; + QCPItemTracer *startTracer; + QCPItemTracer *endTracer; + }; + QVector m_lines; + bool m_isAddingLine; + QPointF m_tempPoint; + double m_offsetXB, m_offsetYB; + enum DragStateB { IdleB, DraggingLineOverall, DraggingStartPoint, DraggingEndPoint }; + DragStateB m_dragStateB; + QPointF m_bDragStart; + int m_draggedLineIndex; - QCPItemTracer *m_tracer1; - QCPItemTracer *m_tracer2; - - enum DragState { Idle, DraggingPoint1, DraggingPoint2, DraggingCurve }; - DragState m_dragState = Idle; - QPointF m_lastDragPixel; + // 模式C + QCPCurve *m_curveC; + QVector m_pointsC; // 原始点(无偏移) + QVector m_labelsC; // 序号标签 + double m_offsetXC, m_offsetYC; // 整体偏移 + bool m_cFinished; // 是否已完成选点 + bool m_cDragging; // 是否正在拖拽整体 + bool m_draggingPoint; // 是否正在拖拽点 + int m_draggedPointIndex; // 拖拽的点的索引 + QPointF m_cDragStart; // 拖拽起始像素 void updateCurveFromTargets(); void updateCurvePosition(); void updateTracers(); void setTracerHighlight(QCPItemTracer *tracer, bool highlight); + void updateLinesPosition(); + void clearLines(); + void updateLineEndpoints(LineItem &item); + void updatePolylineC(bool closed); + void clearPolylineC(); + void deactivate(); }; #endif diff --git a/logPlus/qmycustomplot.cpp b/logPlus/qmycustomplot.cpp index f9408ae..464ad68 100644 --- a/logPlus/qmycustomplot.cpp +++ b/logPlus/qmycustomplot.cpp @@ -2123,9 +2123,30 @@ void QMyCustomPlot::addCrackObject() QtCommonClass *qtCommon = new QtCommonClass(this); QString strUuid = qtCommon->getUUid(); - TransparentDraggableCrackObject *t = new TransparentDraggableCrackObject(this, strUuid, -depth); +// TransparentDraggableCrackObject *t = new TransparentDraggableCrackObject(this, strUuid, -depth); +// m_mapDraggable_CrackObject[strUuid] = t; + + + if("高导缝" == type) + { + // 模式A:原有贝塞尔曲线 + auto curve = new TransparentDraggableCrackObject(this, strUuid, -depth, TransparentDraggableCrackObject::TYPE_A); + } + else if("网状缝" == type) + { + // 模式B:直线(按住Shift选两点) + auto line = new TransparentDraggableCrackObject(this, strUuid, -depth, TransparentDraggableCrackObject::TYPE_B); + } + else if("孔洞" == type) + { + // 模式C:折线(按住Shift连续选点) + auto polyline = new TransparentDraggableCrackObject(this, strUuid, -depth, TransparentDraggableCrackObject::TYPE_C); + } + + + + - m_mapDraggable_CrackObject[strUuid] = t;