logplus/logPlus/PickFrac.cpp
2026-04-23 16:42:00 +08:00

1306 lines
46 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <math.h>
#include <QDebug>
#include <QMouseEvent>
#include <QContextMenuEvent>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QMap>
#include <QTimer>
#include <algorithm>
#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 = QString::fromLocal8Bit(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; j<m_FracDef.count(); ++j) {
if (m_FracDef[j].iCode == frac.ID) {
drawOne(frac, m_FracDef[j].iType, m_FracDef[j].nLineWidth, m_FracDef[j].crColor, m_FracDef[j].csName);
break;
}
}
}
mrw.CloseTable(iIndex);
mrw.Close();
}
void CPickFrac::drawOne(FRAC_TABLE_Crack frac, int iType, int nLineWidth, QColor crColor, QString csName)
{
qDebug() << "========== READ FRAC ==========";
qDebug() << "DEP:" << frac.DEP << "AorX:" << frac.AorX << "XETAorH:" << frac.XETAorH
<< "ID:" << frac.ID << "iType:" << iType;
DraggableCrackItem::Type type;
if (iType == 1) type = DraggableCrackItem::TypeA_Sine;
else if (iType == 2) type = DraggableCrackItem::TypeB_Polyline;
else if (iType == 3) type = DraggableCrackItem::TypeC_Closed;
else return;
DraggableCrackItem *item = new DraggableCrackItem(m_myCustomPlot, type, crColor, nLineWidth);
item->setCrackCode(frac.ID);
item->csName = csName;
item->DIPorS = frac.DIPorS;
item->DIR = frac.DIR;
item->setLabelInfo(csName, frac.DIPorS, frac.DIR);
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<QPointF> points;
int n = frac.NUM;
for (int j=0; j<n; ++j) {
points.append(QPointF(frac.point[j].x / 8.0, -frac.point[j].y));
}
item->setPolylineData(points);
}
else if (iType == 3) {
QVector<QPointF> points;
int n = frac.NUM;
for (int j=0; j<n; ++j) {
points.append(QPointF(frac.point[j].x / 8.0, -frac.point[j].y));
}
item->setClosedData(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<double, DraggableCrackItem*> 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();
}
}
void DraggableCrackItem::setShow(bool flag)
{
setVisible(flag);
}
// ==================== DraggableCrackItem 实现 ====================
QPointer<DraggableCrackItem> 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);
}
// 创建文本标签
m_labelText = new QCPItemText(m_plot);
m_labelText->setFont(QFont("微软雅黑", 7));
m_labelText->setColor(Qt::black);
m_labelText->setPositionAlignment(Qt::AlignCenter);
m_labelText->setLayer("overlay");
m_labelText->setVisible(false);
}
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::setLabelInfo(const QString &name, double angle, double angle2, int digitCapacity)
{
QString text = name;
if (angle >= 0) {
text += QString(" %1").arg(angle, 0, 'f', digitCapacity) + "-" + QString("%1").arg(angle2, 0, 'f', digitCapacity);
}
if (m_labelText) {
m_labelText->setText(text);
}
updateLabelPosition();
}
void DraggableCrackItem::updateLabelPosition()
{
if (!m_labelText) return;
QPointF pos;
if (m_type == TypeA_Sine) {
// 曲线中心点(起点和终点的中点)
double centerX = (m_orig_startX + m_orig_endX) / 2.0 + m_offsetXA;
double centerY = m_depth + m_offsetYA;
pos = QPointF(centerX, centerY);
} else if (m_type == TypeB_Polyline) {
if (!m_lines.isEmpty()) {
// 取第一条线段的中点
QPointF p1 = m_lines.first().startOrig + QPointF(m_offsetXB, m_offsetYB);
QPointF p2 = m_lines.first().endOrig + QPointF(m_offsetXB, m_offsetYB);
pos = (p1 + p2) / 2.0;
}
} else if (m_type == TypeC_Closed) {
if (!m_pointsC.isEmpty()) {
// 取第一个点
pos = m_pointsC.first() + QPointF(m_offsetXC, m_offsetYC);
}
}
m_labelText->position->setCoords(pos.x(), pos.y());
}
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();
updateLabelPosition();
}
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<QPointF> &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);
i++;
}
updateLinesPosition();
updateLabelPosition();
}
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<QPointF> &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);
updateLabelPosition();
}
void DraggableCrackItem::updatePolylineC(bool closed)
{
if (!m_curveC) return;
if (m_pointsC.isEmpty()) {
m_curveC->setData(QVector<double>(), QVector<double>());
return;
}
QVector<double> 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) {
if (m_plot) m_plot->removeItem(label);
}
}
m_labelsC.clear();
m_pointsC.clear();
// 仅当曲线对象仍然存在于 plot 中时才清空数据
if (m_curveC && m_plot && m_plot->plottableCount() > 0) {
// 检查 m_curveC 是否还在 plot 的 plottable 列表中
bool found = false;
for (int i = 0; i < m_plot->plottableCount(); ++i) {
if (m_plot->plottable(i) == m_curveC) {
found = true;
break;
}
}
if (found) {
m_curveC->setData(QVector<double>(), QVector<double>());
}
}
m_offsetXC = m_offsetYC = 0.0;
m_cFinished = false;
m_cDragging = false;
m_draggingPoint = false;
m_draggedPointIndex = -1;
if (m_plot) 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<QPointF> 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<QPointF> 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<QPointF> 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<QContextMenuEvent*>(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<QMouseEvent*>(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;
updateLabelPosition();
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();
updateLabelPosition();
} 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;
updateLabelPosition();
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(double depth, QString type)
{
int iType = 1;
QColor m_lineColor;
QString m_typeName;
if("高导缝" == type)
{
iType = 1;
m_lineColor.setNamedColor("#FF0000");
m_typeName = "高导缝";
}
else if("高阻缝" == type)
{
iType = 1;
m_lineColor.setNamedColor("#400040");
m_typeName = "高阻缝";
}
else if("诱导缝" == type)
{
iType = 1;
m_lineColor.setNamedColor("#00FFFF");
m_typeName = "诱导缝";
}
else if("层理" == type)
{
iType = 1;
m_lineColor.setNamedColor("#00FF00");
m_typeName = "层理";
}
else if("侵蚀面" == type)
{
iType = 1;
m_lineColor.setNamedColor("#409600");
m_typeName = "侵蚀面";
}
else if("断层" == type)
{
iType = 1;
m_lineColor.setNamedColor("#A65300");
m_typeName = "断层";
}
else if("自定义1" == type)
{
iType = 1;
m_lineColor.setNamedColor("#000000");
m_typeName = "自定义1";
}
else if("自定义2" == type)
{
iType = 1;
m_lineColor.setNamedColor("#000000");
m_typeName = "自定义2";
}
else if("网状缝" == type)
{
iType = 2;
m_lineColor.setNamedColor("#808000");
m_typeName = "网状缝";
}
else if("垂直缝" == type)
{
iType = 2;
m_lineColor.setNamedColor("#FF0000");
m_typeName = "垂直缝";
}
else if("孔洞" == type)
{
iType = 3;
m_lineColor.setNamedColor("#FF8064");
m_typeName = "孔洞";
}
else if("气孔" == type)
{
iType = 3;
m_lineColor.setNamedColor("#FFFF00");
m_typeName = "气孔";
}
else if("砾石" == type)
{
iType = 3;
m_lineColor.setNamedColor("#000096");
m_typeName = "砾石";
}
else if("结核" == type)
{
iType = 3;
m_lineColor.setNamedColor("#A65300");
m_typeName = "结核";
}
else if("团块" == type)
{
iType = 3;
m_lineColor.setNamedColor("#000000");
m_typeName = "团块";
}
// int iType,
// QString type
// 从配置文件中查找第一个匹配 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 = m_lineColor;
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;
def.crColor = m_lineColor;
def.csName = m_typeName;
if (iType == 1) {
item = new DraggableCrackItem(m_myCustomPlot, DraggableCrackItem::TypeA_Sine, def.crColor, def.nLineWidth);
item->csName = m_typeName;
item->setLabelInfo(m_typeName, 0);
double amplitude = 0.5;
double phase = 0.0;
double width = xWidth;
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->csName = m_typeName;
item->setLabelInfo(m_typeName, 0);
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->csName = m_typeName;
item->setLabelInfo(m_typeName, 0);
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;
}
void CPickFrac::setShowHide(QString names, int nameShow, int angleShow, int digitCapacity)
{
for (DraggableCrackItem* item : m_items)
{
if(names.contains(item->csName))
{
item->setShow(true);
item->m_labelText->setVisible(false);
if(angleShow == 0 && nameShow == 1)
{
item->setLabelInfo(item->csName, -1, -1, digitCapacity);
item->m_labelText->setVisible(true);
}
if(angleShow == 1 && nameShow == 0)
{
item->setLabelInfo("", item->DIPorS, item->DIR, digitCapacity);
item->m_labelText->setVisible(true);
}
if(angleShow == 1 && nameShow == 1)
{
item->setLabelInfo(item->csName, item->DIPorS, item->DIR, digitCapacity);
item->m_labelText->setVisible(true);
}
}
else
{
item->setShow(false);
item->m_labelText->setVisible(false);
}
}
m_myCustomPlot->replot();
}