#include #include #include #include #include #include #include #include #include #include #include "MemRdWt.h" #include "PickFrac.h" #include "qmycustomplot.h" #include "geometryutils.h" // ==================== CPickFrac 实现 ==================== CPickFrac::CPickFrac(QMyCustomPlot *myCustomPlot, QString strSlfName, QString csCurve, int iMyWidth) : m_myCustomPlot(myCustomPlot), m_iMyWidth(iMyWidth) { m_currentSlfName = strSlfName; m_currentTableName = csCurve.isEmpty() ? "Frac_Hole.Table" : csCurve; ReadFracDef(); for (int i = 0; i < iFracType2; i++) m_bTypeDraw[i] = true; myCustomPlot->m_bDrawCore_PHYSICS = true; ReadData(strSlfName, csCurve); } CPickFrac::~CPickFrac() { qDeleteAll(m_items); m_FracDef.clear(); } void CPickFrac::setDraggingEnabled(bool enabled) { m_draggingEnabled = enabled; if (!enabled) { for (auto item : m_items) item->deactivate(); } } void CPickFrac::ReadFracDef() { m_FracDef.clear(); QString fracFilePath = GetConfPath() + "FRAC.CFG"; FRAC_DEF_Crack fd; char str[512], name[512]; int r, g, b; FILE *fp = fopen(fracFilePath.toStdString().c_str(), "r"); if (fp) { fgets(str, 256, fp); while (!feof(fp)) { fgets(str, 256, fp); QString qs = str; qs.trimmed(); if (qs.length() < 8) break; sscanf(str, "%d %s %d %d %d %d %d", &fd.iCode, name, &fd.iType, &r, &g, &b, &fd.nLineWidth); fd.crColor = QColor(r, g, b); fd.csName = name; fd.csName = fd.csName.trimmed(); fd.bDraw = 0; m_FracDef.append(fd); if (feof(fp)) break; } fclose(fp); } else { sprintf(name, "打开裂缝参数配置文件错误:%s!", str); QMessageBox::information(nullptr, "读取文件失败", name); } } void CPickFrac::ReadData(QString strSlfName, QString csCurve) { if (strSlfName.isEmpty()) return; if (csCurve == "AC" || csCurve.isEmpty()) csCurve = "Frac_Hole.Table"; CMemRdWt mrw; if (!mrw.Open(strSlfName.toStdString().c_str())) return; int iIndex = mrw.OpenTable(csCurve.toStdString().c_str()); if (iIndex < 0) { mrw.Close(); return; } int nField = mrw.GetTableFieldCount(iIndex); int nCount = mrw.GetTableRecordCount(iIndex); for (int i = 0; i < nCount; ++i) { FRAC_TABLE_Crack frac; if (nField == 7) { FRAC_TABLE_OLD_Crack fracold; mrw.ReadTable(iIndex, i+1, &fracold); frac.AorX = fracold.AorX; frac.DEP = fracold.DEP; frac.DIPorS = fracold.DIPorS; frac.DIR = fracold.DIR; frac.W = fracold.W; frac.ID = fracold.ID; frac.XETAorH = fracold.XETAorH; frac.NUM = 0; for (int j=0; j<16; ++j) frac.point[j].x = frac.point[j].y = 0; } else { mrw.ReadTable(iIndex, i+1, &frac); } for (int j=0; jsetCrackCode(frac.ID); connect(item, &DraggableCrackItem::dataChanged, this, &CPickFrac::saveToFile); connect(item, &DraggableCrackItem::removeMe, this, &CPickFrac::onRemoveCrackItem); m_items.append(item); if (iType == 1) { double h = frac.AorX / 2.0; double oy = -(frac.DEP + h); double xScale = 360.0 / m_iMyWidth; double endX = 360.0 / xScale; item->setSineData(oy, h, frac.XETAorH, xScale, endX); } else if (iType == 2) { QVector points; int n = frac.NUM; for (int j=0; jsetPolylineData(points); } else if (iType == 3) { QVector points; int n = frac.NUM; for (int j=0; jsetClosedData(points); } } bool CPickFrac::eventFilter(QObject *watched, QEvent *event) { return QObject::eventFilter(watched, event); } bool CPickFrac::saveToFile() { static bool isRunning = false; if (isRunning) return false; if (m_currentSlfName.isEmpty()) return false; isRunning = true; CMemRdWt *logio = new CMemRdWt(); if (!logio->Open(m_currentSlfName.toStdString().c_str(), CSlfIO::modeReadWrite)) { delete logio; QMessageBox::information(nullptr, "提示", "SLF文件打开失败,请检查!", QMessageBox::Yes); isRunning = false; return false; } QString tableName = m_currentTableName; int iIndex = logio->OpenTable(tableName.toStdString().c_str()); if (iIndex < 0) { delete logio; QMessageBox::information(nullptr, "提示", QString("裂缝表 %1 不存在,无法保存!").arg(tableName), QMessageBox::Yes); isRunning = false; return false; } // 如果没有裂缝,清空表记录 if (m_items.isEmpty()) { logio->SetTableRecordCount(iIndex, 0); logio->CloseTable(iIndex); delete logio; isRunning = false; return true; } // 按深度排序 QMap sortedMap; for (DraggableCrackItem *item : m_items) { double depth = item->getDepthForSort(); sortedMap[depth] = item; } logio->SetTableRecordCount(iIndex, sortedMap.size()); int recordIndex = 1; for (auto it = sortedMap.begin(); it != sortedMap.end(); ++it) { FRAC_TABLE_Crack fracData; it.value()->getCurrentFracData(fracData); logio->WriteTable(iIndex, recordIndex, &fracData); recordIndex++; } logio->CloseTable(iIndex); delete logio; isRunning = false; return true; } void CPickFrac::onRemoveCrackItem(DraggableCrackItem *item) { if (!item) return; if (m_items.removeOne(item)) { // 立即从画布移除所有图形项 item->cleanupFromPlot(); // 失活并清空静态指针 if (DraggableCrackItem::getActiveItem() == item) { item->deactivate(); } // 断开信号 disconnect(item, nullptr, this, nullptr); // 直接删除,不再延迟 delete item; // 强制重绘 m_myCustomPlot->replot(); // 保存文件 saveToFile(); } } void DraggableCrackItem::cleanupFromPlot() { if (m_type == TypeA_Sine) { if (m_curve) m_plot->removeItem(m_curve); if (m_tracer1) m_plot->removeItem(m_tracer1); if (m_tracer2) m_plot->removeItem(m_tracer2); } else if (m_type == TypeB_Polyline) { for (auto &item : m_lines) { if (item.line) m_plot->removeItem(item.line); if (item.startTracer) m_plot->removeItem(item.startTracer); if (item.endTracer) m_plot->removeItem(item.endTracer); } m_lines.clear(); } else if (m_type == TypeC_Closed) { if (m_curveC) { m_plot->removePlottable(m_curveC); m_curveC = nullptr; } for (auto label : m_labelsC) { if (label) m_plot->removeItem(label); } m_labelsC.clear(); m_pointsC.clear(); } } // ==================== DraggableCrackItem 实现 ==================== QPointer DraggableCrackItem::s_activeItem = nullptr; DraggableCrackItem::DraggableCrackItem(QCustomPlot *plot, Type type, const QColor &color, int lineWidth) : QObject(plot), m_plot(plot), m_type(type), m_color(color), m_lineWidth(lineWidth) { if (m_type == TypeA_Sine) { m_curve = new QCPItemCurve(m_plot); m_curve->setPen(QPen(m_color, m_lineWidth)); m_curve->setLayer("overlay"); auto createTracer = [this](double x, double y) -> QCPItemTracer* { QCPItemTracer *t = new QCPItemTracer(m_plot); t->setStyle(QCPItemTracer::tsSquare); t->setSize(8); t->setPen(QPen(Qt::black, 1)); t->setBrush(QBrush(Qt::black)); t->setSelectable(true); t->setLayer("overlay"); t->position->setCoords(x, y); t->setVisible(false); return t; }; m_tracer1 = createTracer(0,0); m_tracer2 = createTracer(0,0); m_plot->installEventFilter(this); } else if (m_type == TypeB_Polyline) { m_plot->installEventFilter(this); } else if (m_type == TypeC_Closed) { m_curveC = new QCPCurve(m_plot->xAxis, m_plot->yAxis); m_curveC->setPen(QPen(m_color, m_lineWidth)); m_curveC->setScatterStyle(QCPScatterStyle::ssCircle); m_curveC->setLineStyle(QCPCurve::lsLine); m_curveC->setLayer("overlay"); m_plot->installEventFilter(this); } } DraggableCrackItem::~DraggableCrackItem() { if (m_type == TypeA_Sine) { if (m_tracer1) m_plot->removeItem(m_tracer1); if (m_tracer2) m_plot->removeItem(m_tracer2); if (m_curve) m_plot->removeItem(m_curve); } else if (m_type == TypeB_Polyline) { clearLines(); } else if (m_type == TypeC_Closed) { clearPolylineC(); } if (s_activeItem == this) s_activeItem = nullptr; } void DraggableCrackItem::setVisible(bool visible) { if (m_pendingDelete) return; if (m_type == TypeA_Sine) { if (m_curve) m_curve->setVisible(visible); if (m_tracer1) m_tracer1->setVisible(visible && (s_activeItem == this)); if (m_tracer2) m_tracer2->setVisible(visible && (s_activeItem == this)); } else if (m_type == TypeB_Polyline) { for (auto &item : m_lines) { if (item.line) item.line->setVisible(visible); bool show = visible && (s_activeItem == this); if (item.startTracer) item.startTracer->setVisible(show); if (item.endTracer) item.endTracer->setVisible(show); } } else if (m_type == TypeC_Closed) { if (m_curveC) m_curveC->setVisible(visible); bool show = visible && (s_activeItem == this); for (auto label : m_labelsC) label->setVisible(show); } m_plot->replot(); } void DraggableCrackItem::deactivate() { if (m_type == TypeA_Sine) { setTracerHighlight(m_tracer1, false); setTracerHighlight(m_tracer2, false); m_dragStateA = IdleA; setDragPointsVisible(false); } else if (m_type == TypeB_Polyline) { m_dragStateB = IdleB; m_draggedLineIndex = -1; setDragPointsVisible(false); } else if (m_type == TypeC_Closed) { m_cDragging = false; m_draggingPoint = false; m_draggedPointIndex = -1; setDragPointsVisible(false); } if (s_activeItem == this) { s_activeItem = nullptr; } m_plot->replot(); } void DraggableCrackItem::setDragPointsVisible(bool visible) { if (m_pendingDelete) return; if (m_type == TypeA_Sine) { if (m_tracer1) m_tracer1->setVisible(visible); if (m_tracer2) m_tracer2->setVisible(visible); } else if (m_type == TypeB_Polyline) { for (auto &item : m_lines) { if (item.startTracer) item.startTracer->setVisible(visible); if (item.endTracer) item.endTracer->setVisible(visible); } } else if (m_type == TypeC_Closed) { for (auto label : m_labelsC) { if (label) label->setVisible(visible); } } m_plot->replot(); } void DraggableCrackItem::startEditing() { if (m_pendingDelete) return; m_editingMode = true; if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); if (m_type == TypeB_Polyline) { clearLines(); m_isAddingLine = false; } else if (m_type == TypeC_Closed) { clearPolylineC(); m_cFinished = false; } m_plot->replot(); } void DraggableCrackItem::finishEditing() { if (!m_editingMode) return; m_editingMode = false; if (s_activeItem == this) { deactivate(); } emit dataChanged(); } // ---------- 模式A ---------- void DraggableCrackItem::setSineData(double depth, double amplitude, double phase, double xScale, double width) { m_depth = depth; m_endX = width; m_originalXETAorH = phase; m_originalAorX = amplitude * 2.0; m_orig_x1 = m_endX * 0.18; m_orig_x2 = m_endX * 0.82; m_orig_y1 = depth + amplitude; m_orig_y2 = depth - amplitude; m_orig_startX = 0; m_orig_endX = m_endX; m_orig_startDirX = m_endX * 0.3; m_orig_endDirX = m_endX * 0.7; updateCurveFromTargets(); updateCurvePosition(); updateTracers(); } void DraggableCrackItem::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 DraggableCrackItem::updateCurvePosition() { if (!m_curve) return; m_curve->start->setCoords(m_orig_startX + m_offsetXA, m_depth + m_offsetYA); m_curve->end->setCoords(m_orig_endX + m_offsetXA, m_depth + m_offsetYA); m_curve->startDir->setCoords(m_orig_startDirX + m_offsetXA, m_orig_startDirY + m_offsetYA); m_curve->endDir->setCoords(m_orig_endDirX + m_offsetXA, m_orig_endDirY + m_offsetYA); } void DraggableCrackItem::updateTracers() { 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 DraggableCrackItem::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::black)); } m_plot->replot(); } // ---------- 模式B ---------- void DraggableCrackItem::setPolylineData(const QVector &points, double scaleX, double flipY) { clearLines(); if (points.size() < 2) return; auto createTracer = [this](double x, double y, const QColor &color) -> QCPItemTracer* { QCPItemTracer *t = new QCPItemTracer(m_plot); t->setStyle(QCPItemTracer::tsSquare); t->setSize(10); t->setPen(QPen(Qt::black, 1)); t->setBrush(QBrush(color)); t->setSelectable(true); t->setLayer("overlay"); t->position->setCoords(x, y); t->setVisible(false); return t; }; for (int i = 0; i < points.size() - 1; ++i) { QPointF p1 = points[i]; QPointF p2 = points[i+1]; QCPItemLine *line = new QCPItemLine(m_plot); line->setPen(QPen(m_color, m_lineWidth)); line->setLayer("overlay"); QCPItemTracer *startTracer = createTracer(p1.x(), p1.y(), Qt::black); QCPItemTracer *endTracer = createTracer(p2.x(), p2.y(), Qt::black); LineItem item; item.startOrig = p1; item.endOrig = p2; item.line = line; item.startTracer = startTracer; item.endTracer = endTracer; m_lines.append(item); } updateLinesPosition(); } void DraggableCrackItem::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 DraggableCrackItem::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 DraggableCrackItem::clearLines() { for (auto &item : m_lines) { if (item.line) { m_plot->removeItem(item.line); } if (item.startTracer) { m_plot->removeItem(item.startTracer); } if (item.endTracer) { m_plot->removeItem(item.endTracer); } } m_lines.clear(); m_plot->replot(); } // ---------- 模式C ---------- void DraggableCrackItem::setClosedData(const QVector &points, double scaleX, double flipY) { clearPolylineC(); if (points.size() < 3) return; m_pointsC = points; for (int i = 0; i < m_pointsC.size(); ++i) { QCPItemText *label = new QCPItemText(m_plot); label->setText(" "); label->setFont(QFont("Arial", 6, QFont::Bold)); label->setColor(Qt::black); label->setBrush(QBrush(Qt::black)); label->setPen(QPen(Qt::black, 1)); label->position->setCoords(m_pointsC[i].x(), m_pointsC[i].y()); label->setPositionAlignment(Qt::AlignCenter); label->setLayer("overlay"); label->setVisible(false); m_labelsC.append(label); } m_cFinished = true; updatePolylineC(true); } void DraggableCrackItem::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 DraggableCrackItem::clearPolylineC() { for (auto label : m_labelsC) { if (label) { m_plot->removeItem(label); } } m_labelsC.clear(); m_pointsC.clear(); if (m_curveC) m_curveC->setData(QVector(), QVector()); m_offsetXC = m_offsetYC = 0.0; m_cFinished = false; m_cDragging = false; m_draggingPoint = false; m_draggedPointIndex = -1; m_plot->replot(); } // ---------- 保存辅助 ---------- double DraggableCrackItem::getDepthForSort() const { if (m_type == TypeA_Sine) return m_depth + m_offsetYA; else if (m_type == TypeB_Polyline && !m_lines.isEmpty()) return m_lines.first().startOrig.y() + m_offsetYB; else if (m_type == TypeC_Closed && !m_pointsC.isEmpty()) return m_pointsC.first().y() + m_offsetYC; return 0.0; } void DraggableCrackItem::getCurrentFracData(FRAC_TABLE_Crack &data) const { memset(&data, 0, sizeof(FRAC_TABLE_Crack)); data.ID = m_crackCode; if (m_type == TypeA_Sine) { double centerY = (m_orig_y1 + m_orig_y2) / 2.0 + m_offsetYA; double halfHeight = (m_orig_y1 - m_orig_y2) / 2.0; double savedDEP = -centerY - halfHeight; double savedAorX = halfHeight * 2.0; data.DEP = savedDEP; data.AorX = savedAorX; data.XETAorH = m_originalXETAorH; data.NUM = 0; } else if (m_type == TypeB_Polyline) { QVector allPoints; for (const LineItem &item : m_lines) { QPointF p1 = item.startOrig + QPointF(m_offsetXB, m_offsetYB); QPointF p2 = item.endOrig + QPointF(m_offsetXB, m_offsetYB); allPoints.append(p1); allPoints.append(p2); } QVector uniquePoints; for (const QPointF &p : allPoints) { if (uniquePoints.isEmpty() || uniquePoints.last() != p) uniquePoints.append(p); } data.NUM = uniquePoints.size(); for (int i = 0; i < uniquePoints.size() && i < 16; ++i) { data.point[i].x = uniquePoints[i].x() * 8.0f; data.point[i].y = -uniquePoints[i].y(); } if (uniquePoints.size() > 0) data.DEP = uniquePoints[0].y(); } else if (m_type == TypeC_Closed) { QVector finalPoints; for (const QPointF &p : m_pointsC) { finalPoints.append(p + QPointF(m_offsetXC, m_offsetYC)); } data.NUM = finalPoints.size(); for (int i = 0; i < finalPoints.size() && i < 16; ++i) { data.point[i].x = finalPoints[i].x() * 8.0f; data.point[i].y = -finalPoints[i].y(); } if (finalPoints.size() > 0) data.DEP = finalPoints[0].y(); } } // ---------- 事件过滤器 ---------- bool DraggableCrackItem::eventFilter(QObject *obj, QEvent *event) { if (obj != m_plot) return false; if (m_pendingDelete) return false; // 已标记删除,忽略所有事件 // 右键菜单处理 if (event->type() == QEvent::ContextMenu) { QContextMenuEvent *ce = static_cast(event); if (s_activeItem == this) { QMenu menu; QAction *deleteAction = menu.addAction("删除裂缝"); QAction *selectedAction = menu.exec(ce->globalPos()); if (selectedAction == deleteAction) { m_pendingDelete = true; deactivate(); // 清空全局激活指针 emit removeMe(this); // 触发删除 } return true; // 阻止事件继续传递 } return false; } QMouseEvent *me = static_cast(event); if (event->type() == QEvent::MouseButtonPress && me->button() == Qt::LeftButton) { bool shiftPressed = (me->modifiers() & Qt::ShiftModifier); // ===== 模式B:添加线段(Shift) ===== if (m_type == TypeB_Polyline && shiftPressed) { if (!m_isAddingLine) { double x = m_plot->xAxis->pixelToCoord(me->pos().x()); double y = m_plot->yAxis->pixelToCoord(me->pos().y()); m_tempPoint = QPointF(x - m_offsetXB, y - m_offsetYB); m_isAddingLine = true; return true; } else { double x = m_plot->xAxis->pixelToCoord(me->pos().x()); double y = m_plot->yAxis->pixelToCoord(me->pos().y()); QPointF p2(x - m_offsetXB, y - m_offsetYB); QCPItemLine *line = new QCPItemLine(m_plot); line->setPen(QPen(m_color, m_lineWidth)); line->setLayer("overlay"); auto createTracer = [this](double x, double y, const QColor &color) -> QCPItemTracer* { QCPItemTracer *t = new QCPItemTracer(m_plot); t->setStyle(QCPItemTracer::tsSquare); 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); t->setVisible(false); return t; }; QCPItemTracer *startTracer = createTracer(m_tempPoint.x(), m_tempPoint.y(), Qt::black); QCPItemTracer *endTracer = createTracer(p2.x(), p2.y(), Qt::black); 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; m_plot->replot(); return true; } } // ===== 模式C:添加点(Shift,未完成) ===== if (m_type == TypeC_Closed && shiftPressed && !m_cFinished) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); double x = m_plot->xAxis->pixelToCoord(me->pos().x()); double y = m_plot->yAxis->pixelToCoord(me->pos().y()); QPointF pt(x - m_offsetXC, y - m_offsetYC); m_pointsC.append(pt); QCPItemText *label = new QCPItemText(m_plot); label->setText(" "); label->setFont(QFont("Arial", 6, QFont::Bold)); label->setColor(Qt::black); label->setBrush(QBrush(Qt::black)); label->setPen(QPen(Qt::black, 1)); label->position->setCoords(x, y); label->setPositionAlignment(Qt::AlignCenter); label->setLayer("overlay"); label->setVisible(true); m_labelsC.append(label); updatePolylineC(false); m_plot->replot(); return true; } // ===== 模式C:完成封闭(非Shift,未完成) ===== if (m_type == TypeC_Closed && !shiftPressed && !m_cFinished) { if (m_pointsC.size() >= 3) { m_cFinished = true; updatePolylineC(true); m_plot->replot(); if (m_editingMode) { finishEditing(); } } else { clearPolylineC(); } if (s_activeItem == this) { s_activeItem->deactivate(); s_activeItem = nullptr; } return true; } // ===== 编辑模式下,模式B:非Shift左键点击空白结束编辑 ===== if (m_type == TypeB_Polyline && !shiftPressed && m_editingMode && !m_isAddingLine) { finishEditing(); return true; } // ===== 模式A:拖拽点或曲线 ===== if (m_type == TypeA_Sine && !shiftPressed) { QPointF pixel = me->localPos(); double d1 = m_tracer1->selectTest(pixel, false); double d2 = m_tracer2->selectTest(pixel, false); double curveDist = m_curve->selectTest(pixel, false); if (d1 >= 0 && d1 < 15 || d2 >= 0 && d2 < 15 || (curveDist >= 0 && curveDist < 5)) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); 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; } return true; } } // ===== 模式B:拖拽端点或整体(非编辑模式) ===== if (m_type == TypeB_Polyline && !shiftPressed && !m_editingMode && !m_isAddingLine) { QPointF pixel = me->localPos(); 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) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); m_dragStateB = DraggingStartPoint; m_draggedLineIndex = i; m_bDragStart = pixel; return true; } if (item.endTracer->selectTest(pixel, false) >= 0 && item.endTracer->selectTest(pixel, false) < 10) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); m_dragStateB = DraggingEndPoint; m_draggedLineIndex = i; m_bDragStart = pixel; return true; } } for (int i = 0; i < m_lines.size(); ++i) { double dist = m_lines[i].line->selectTest(pixel, false); if (dist >= 0 && dist < 3) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); m_dragStateB = DraggingLineOverall; m_bDragStart = pixel; return true; } } } // ===== 模式C:拖拽点或整体(已完成,非编辑模式) ===== if (m_type == TypeC_Closed && !shiftPressed && m_cFinished && !m_editingMode) { QPointF pixel = me->localPos(); int hitPoint = -1; for (int i = 0; i < m_labelsC.size(); ++i) { if (m_labelsC[i]->selectTest(pixel, false) >= 0 && m_labelsC[i]->selectTest(pixel, false) < 10) { hitPoint = i; break; } } if (hitPoint >= 0) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); m_draggingPoint = true; m_draggedPointIndex = hitPoint; m_cDragStart = pixel; return true; } else { double curveDist = m_curveC ? m_curveC->selectTest(pixel, false) : -1; if (curveDist >= 0 && curveDist < 3) { if (s_activeItem && s_activeItem != this) s_activeItem->deactivate(); s_activeItem = this; setDragPointsVisible(true); m_cDragging = true; m_cDragStart = pixel; return true; } else { if (s_activeItem == this) { s_activeItem->deactivate(); s_activeItem = nullptr; } } } } } // 鼠标移动 if (event->type() == QEvent::MouseMove) { if (s_activeItem != this) return false; if (m_type == TypeA_Sine) { if (m_dragStateA == DraggingPoint1 || m_dragStateA == DraggingPoint2) { double newY = m_plot->yAxis->pixelToCoord(me->localPos().y()); double currentY = (m_dragStateA == DraggingPoint1) ? m_orig_y1 : m_orig_y2; double deltaY = newY - (currentY + m_offsetYA); double newOrigY = currentY + deltaY; newOrigY = qBound(m_depth - 100, newOrigY, m_depth + 100); if (m_dragStateA == DraggingPoint1) m_orig_y1 = newOrigY; else m_orig_y2 = newOrigY; updateCurveFromTargets(); updateCurvePosition(); updateTracers(); m_plot->replot(); return true; } else if (m_dragStateA == DraggingCurveA) { QPointF current = me->localPos(); double oldX = m_plot->xAxis->pixelToCoord(m_lastDragPixelA.x()); double newX = m_plot->xAxis->pixelToCoord(current.x()); double oldY = m_plot->yAxis->pixelToCoord(m_lastDragPixelA.y()); double newY = m_plot->yAxis->pixelToCoord(current.y()); double dx = newX - oldX; double dy = newY - oldY; m_offsetXA += dx; m_offsetYA += dy; updateCurvePosition(); updateTracers(); m_plot->replot(); m_lastDragPixelA = current; return true; } } else if (m_type == TypeB_Polyline && m_dragStateB != IdleB) { QPointF current = me->localPos(); double oldX = m_plot->xAxis->pixelToCoord(m_bDragStart.x()); double newX = m_plot->xAxis->pixelToCoord(current.x()); double oldY = m_plot->yAxis->pixelToCoord(m_bDragStart.y()); double newY = m_plot->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); } } m_plot->replot(); m_bDragStart = current; return true; } else if (m_type == TypeC_Closed) { if (m_cDragging) { QPointF current = me->localPos(); double oldX = m_plot->xAxis->pixelToCoord(m_cDragStart.x()); double newX = m_plot->xAxis->pixelToCoord(current.x()); double oldY = m_plot->yAxis->pixelToCoord(m_cDragStart.y()); double newY = m_plot->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(true); m_plot->replot(); m_cDragStart = current; return true; } else if (m_draggingPoint) { QPointF current = me->localPos(); double oldX = m_plot->xAxis->pixelToCoord(m_cDragStart.x()); double newX = m_plot->xAxis->pixelToCoord(current.x()); double oldY = m_plot->yAxis->pixelToCoord(m_cDragStart.y()); double newY = m_plot->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(true); m_plot->replot(); m_cDragStart = current; return true; } } } // 鼠标释放:发射 dataChanged 信号(仅非编辑模式) if (event->type() == QEvent::MouseButtonRelease && me->button() == Qt::LeftButton) { if (s_activeItem == this && !m_editingMode) { if (m_type == TypeA_Sine && m_dragStateA != IdleA) { setTracerHighlight(m_tracer1, false); setTracerHighlight(m_tracer2, false); m_dragStateA = IdleA; emit dataChanged(); return true; } else if (m_type == TypeB_Polyline && m_dragStateB != IdleB) { m_dragStateB = IdleB; m_draggedLineIndex = -1; emit dataChanged(); return true; } else if (m_type == TypeC_Closed) { if (m_cDragging) { m_cDragging = false; emit dataChanged(); return true; } else if (m_draggingPoint) { m_draggingPoint = false; m_draggedPointIndex = -1; emit dataChanged(); return true; } } } if (s_activeItem == this) { s_activeItem->deactivate(); s_activeItem = nullptr; return true; } } return false; } // ==================== 新建裂缝 ==================== bool CPickFrac::createNewCrack(int iType, double depth) { // 从配置文件中查找第一个匹配 iType 的定义,获取颜色和线宽 FRAC_DEF_Crack def; bool found = false; for (const FRAC_DEF_Crack &d : m_FracDef) { if (d.iType == iType) { def = d; found = true; break; } } if (!found) { def.iType = iType; def.crColor = QColor(255, 0, 0); def.nLineWidth = 2; } if (!m_myCustomPlot) return false; double xMin = m_myCustomPlot->xAxis->range().lower; double xMax = m_myCustomPlot->xAxis->range().upper; double xCenter = (xMin + xMax) / 2.0; double xWidth = xMax - xMin; double yPos = -depth; DraggableCrackItem *item = nullptr; if (iType == 1) { item = new DraggableCrackItem(m_myCustomPlot, DraggableCrackItem::TypeA_Sine, def.crColor, def.nLineWidth); double amplitude = 0.5; double phase = 0.0; double width = xWidth * 0.8; double xScale = 360.0 / width; double centerY = -(depth + amplitude); item->setSineData(centerY, amplitude, phase, xScale, width); item->setCrackCode(def.iCode); connect(item, &DraggableCrackItem::dataChanged, this, &CPickFrac::saveToFile); connect(item, &DraggableCrackItem::removeMe, this, &CPickFrac::onRemoveCrackItem); m_items.append(item); bool saved = saveToFile(); m_myCustomPlot->replot(); return saved; } else if (iType == 2) { item = new DraggableCrackItem(m_myCustomPlot, DraggableCrackItem::TypeB_Polyline, def.crColor, def.nLineWidth); item->setCrackCode(def.iCode); connect(item, &DraggableCrackItem::dataChanged, this, &CPickFrac::saveToFile); connect(item, &DraggableCrackItem::removeMe, this, &CPickFrac::onRemoveCrackItem); m_items.append(item); item->startEditing(); m_myCustomPlot->replot(); return true; } else if (iType == 3) { item = new DraggableCrackItem(m_myCustomPlot, DraggableCrackItem::TypeC_Closed, def.crColor, def.nLineWidth); item->setCrackCode(def.iCode); connect(item, &DraggableCrackItem::dataChanged, this, &CPickFrac::saveToFile); connect(item, &DraggableCrackItem::removeMe, this, &CPickFrac::onRemoveCrackItem); m_items.append(item); item->startEditing(); m_myCustomPlot->replot(); return true; } return false; }