|
|
#include <QPainter>
|
|
|
|
|
|
#include "ZxSerializer.h"
|
|
|
#include "IxPtyPano.h"
|
|
|
|
|
|
#include "ZxSubAxisX.h"
|
|
|
#include "ZxSubAxisY.h"
|
|
|
|
|
|
#include "nmObjRegion.h"
|
|
|
#include "nmObjRegionTool.h"
|
|
|
|
|
|
#include "ZxBaseUtil.h"
|
|
|
#include "ZxPlot.h"
|
|
|
|
|
|
#include "nmDataAnalyzeManager.h"
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
ZX_DEFINE_DYNAMIC(nObjRegion, nmObjRegion)
|
|
|
|
|
|
nmObjRegion::nmObjRegion()
|
|
|
{
|
|
|
m_sObjTag = "nObjRegion";
|
|
|
nmObjRegion::init("", NULL, NULL);
|
|
|
}
|
|
|
|
|
|
nmObjRegion::nmObjRegion(const QString& sName, \
|
|
|
ZxSubAxisX* pAxisX, \
|
|
|
ZxSubAxisY* pAxisY)
|
|
|
{
|
|
|
m_sObjTag = "nObjRegion";
|
|
|
nmObjRegion::init(sName, pAxisX, pAxisY);
|
|
|
}
|
|
|
|
|
|
nmObjRegion::~nmObjRegion()
|
|
|
{
|
|
|
// 复合区数据由DataManager统一释放,图元只保存引用。
|
|
|
m_regionData = nullptr;
|
|
|
|
|
|
if(m_regionMark != nullptr) {
|
|
|
m_regionMark = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::init(const QString& sName, \
|
|
|
ZxSubAxisX* pAxisX, \
|
|
|
ZxSubAxisY* pAxisY)
|
|
|
{
|
|
|
nmObjBase::init(sName, pAxisX, pAxisY);
|
|
|
|
|
|
nmObjRegion::initFlags();
|
|
|
m_oPen = QPen(QBrush(QColor(128, 128, 128)), \
|
|
|
0.3f, Qt::SolidLine);
|
|
|
m_clrBackgrd = QColor(0, 0, 0, 0);
|
|
|
|
|
|
m_regionMark = nullptr;
|
|
|
m_regionData = nullptr;
|
|
|
|
|
|
loadTempl();
|
|
|
|
|
|
// 连接图元可见性信号和槽
|
|
|
connect(this, SIGNAL(sigObjVisibleChanged(bool)),
|
|
|
this, SLOT(onObjVisibleChanged(bool)));
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::initTools()
|
|
|
{
|
|
|
m_pTool = new nmObjRegionTool();
|
|
|
|
|
|
nmObjBase::initTools();
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::initFlags()
|
|
|
{
|
|
|
setLockPos(false);
|
|
|
setLockSize(false);
|
|
|
setReadOnly(false);
|
|
|
}
|
|
|
|
|
|
bool nmObjRegion::hitTest(const QPointF& pt)
|
|
|
{
|
|
|
return nmObjBase::hitTest(pt);
|
|
|
}
|
|
|
|
|
|
bool nmObjRegion::_runHitTest(const QPointF& pt, int& nOption, int& nSubIndex)
|
|
|
{
|
|
|
if(!nmObjBase::_runHitTest(pt, nOption, nSubIndex)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nOption = -1;
|
|
|
nSubIndex = 0;
|
|
|
|
|
|
if(NULL == m_pAxisX || NULL == m_pAxisY) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
QVector<QPointF> pts = getPosOf(m_vecPoints);
|
|
|
|
|
|
// 点
|
|
|
double r = 1.f;
|
|
|
|
|
|
for(int i = 0; i < pts.count(); i++) {
|
|
|
QPointF ptTopLeft = QPointF(pts[i].x() - r,
|
|
|
pts[i].y() - r);
|
|
|
QSizeF sz = QSizeF(r * 2.f, r * 2.f);
|
|
|
|
|
|
QRectF rt = QRectF(ptTopLeft, sz);
|
|
|
bool b = rt.contains(pt);
|
|
|
|
|
|
if(b) {
|
|
|
nOption = (int)OHO_Point;
|
|
|
nSubIndex = i;
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 线
|
|
|
for(int i = 0; i < pts.count(); i++) {
|
|
|
int n1 = i;
|
|
|
int n2 = (i == pts.count() - 1 ? 0 : i + 1);
|
|
|
|
|
|
if(_isNearLine(pt, pts[n1], pts[n2], 1.f * 2)) {
|
|
|
// 判断当前线是否已经存在
|
|
|
if(m_oHitOption == OHO_Bound && m_pTool->isLeftDown()) {
|
|
|
// 添加新节点
|
|
|
pts.insert(i + 1, pt);
|
|
|
m_vecPoints.clear();
|
|
|
m_vecPoints = getValueOf(pts);
|
|
|
nOption = (int)OHO_Point;
|
|
|
nSubIndex = i + 1;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
nOption = (int)OHO_Bound;
|
|
|
nSubIndex = i;
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
nOption = (int)OHO_None;
|
|
|
nSubIndex = -1;
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
bool nmObjRegion::runMove(const QPointF& pt1,
|
|
|
const QPointF& pt2)
|
|
|
{
|
|
|
if(isLockPos()) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if(NULL == m_pAxisX || NULL == m_pAxisY) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
int nCount = m_vecPoints.count();
|
|
|
QVector<QPointF> vecPts = getPosOf(m_vecPoints); // 屏幕值
|
|
|
|
|
|
if(m_oHitOption == OHO_Point && m_nHitIndex >= 0) {
|
|
|
// 如果是点,不用计算偏移量,直接将该点移动到鼠标抬起的位置即可
|
|
|
vecPts[m_nHitIndex] = pt2;
|
|
|
return moveToPos(vecPts);
|
|
|
} else if(m_oHitOption == OHO_Bound && m_nHitIndex >= 0) {
|
|
|
for(int i = 0; i < nCount; i++) {
|
|
|
vecPts[i] = offsetPoint(vecPts[i], pt1, pt2);
|
|
|
}
|
|
|
|
|
|
m_dOffsetX = pt2.x() - pt1.x();
|
|
|
m_dOffsetY = pt2.y() - pt1.y();
|
|
|
return moveToPos(vecPts);
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::fillPtyPano(IxPtyPano* sheet)
|
|
|
{
|
|
|
nmObjBase::fillPtyPano(sheet);
|
|
|
|
|
|
ZX_PROP("ObjRect.Pen", getPen, setPen);
|
|
|
ZX_PROP("ObjRect.BackgrdColor", getBackgrdColor, setBackgrdColor);
|
|
|
|
|
|
IxPtyItem* pProp = ZX_PROP("ObjRegion.FlowModel", getRegionFlowModel, setRegionFlowModel);
|
|
|
|
|
|
if(NULL != pProp) {
|
|
|
QStringList listTags;
|
|
|
listTags << tr("Leaky") << tr("Composite Limit");
|
|
|
QList<QVariant> listIndexes;
|
|
|
listIndexes << 0 << 1 << 2;
|
|
|
pProp->getPtyPano();
|
|
|
pProp->setOptions(listTags, listIndexes);
|
|
|
}
|
|
|
|
|
|
ZX_PROP("ObjRegion.Leakage", getRegionLeakage, setRegionLeakage);
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::onSerialize(ZxSerializer* ser)
|
|
|
{
|
|
|
nmObjBase::onSerialize(ser);
|
|
|
int flowModel;
|
|
|
|
|
|
if(m_regionData->getRegionFlowModel().getValue() == tr("Leaky"))
|
|
|
flowModel = 0;
|
|
|
else
|
|
|
flowModel = 1;
|
|
|
|
|
|
ser->write("FlowModel", flowModel);
|
|
|
ser->write("Leakage", m_regionData->getRegionFlowModel().getValue().toDouble());
|
|
|
ser->write("BackgrdColor", m_clrBackgrd);
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::onDeserialize(ZxSerializer* ser)
|
|
|
{
|
|
|
nmObjBase::onDeserialize(ser);
|
|
|
int flowModel;
|
|
|
double regionLeakage;
|
|
|
ser->read("FlowModel", flowModel);
|
|
|
ser->read("Leakage", regionLeakage);
|
|
|
ser->read("BackgrdColor", m_clrBackgrd);
|
|
|
|
|
|
this->setRegionLeakage(regionLeakage);
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::onSaveTempl(ZxSerializer* ser)
|
|
|
{
|
|
|
nmObjBase::onSaveTempl(ser);
|
|
|
int flowModel;
|
|
|
|
|
|
if(m_regionData->getRegionFlowModel().getValue() == tr("Leaky"))
|
|
|
flowModel = 0;
|
|
|
else
|
|
|
flowModel = 1;
|
|
|
|
|
|
ser->write("FlowModel", flowModel);
|
|
|
ser->write("Leakage", m_regionData->getRegionFlowModel().getValue().toDouble());
|
|
|
ser->write("BackgrdColor", m_clrBackgrd);
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::onLoadTempl(ZxSerializer* ser)
|
|
|
{
|
|
|
nmObjBase::onLoadTempl(ser);
|
|
|
int flowModel;
|
|
|
double regionLeakage;
|
|
|
ser->read("FlowModel", flowModel);
|
|
|
ser->read("Leakage", regionLeakage);
|
|
|
ser->read("BackgrdColor", m_clrBackgrd);
|
|
|
|
|
|
this->setRegionLeakage(regionLeakage);
|
|
|
}
|
|
|
|
|
|
QColor nmObjRegion::getBackgrdColor() const
|
|
|
{
|
|
|
//if (m_nLineIndex)
|
|
|
//return m_vecPresType[m_nLineIndex]
|
|
|
return m_clrBackgrd;
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::setBackgrdColor(QColor color)
|
|
|
{
|
|
|
if(m_clrBackgrd != color) {
|
|
|
//m_vecPresType[m_nLineIndex] =
|
|
|
m_clrBackgrd = color;
|
|
|
update();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void nmObjRegion::paintBack(QPainter* painter, const ZxPaintParam& param)
|
|
|
{
|
|
|
if(NULL == m_pAxisX || NULL == m_pAxisY || \
|
|
|
m_pAxisX->getRangeMin() == m_pAxisX->getRangeMax() || \
|
|
|
m_pAxisY->getRangeMin() == m_pAxisY->getRangeMax()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
painter->save();
|
|
|
QVector<QPointF> pts = getPosOf(m_vecPoints);
|
|
|
|
|
|
if(m_regionData != nullptr) {
|
|
|
m_regionData->setRegionName(m_sName);
|
|
|
m_regionData->setVecPts(m_vecPoints);
|
|
|
|
|
|
if(m_regionMark == nullptr) {
|
|
|
if(m_regionData->getRegionMarkData() != nullptr)
|
|
|
m_regionData->setRegionMarkData(nullptr);
|
|
|
|
|
|
} else if(m_regionMark->getRegionMarkData() == nullptr) {
|
|
|
m_regionMark = nullptr;
|
|
|
m_regionData->setRegionMarkData(nullptr);
|
|
|
this->setBackgrdColor(QColor(0, 0, 0, 0));
|
|
|
} else {
|
|
|
m_regionData->setRegionMarkData(m_regionMark->getRegionMarkData());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 不选中的状态
|
|
|
if(!pts.empty()) {
|
|
|
|
|
|
// 填充
|
|
|
QPainterPath oPath;
|
|
|
oPath.moveTo(pts[0]);
|
|
|
|
|
|
for(int i = 1; i < pts.count(); i++) {
|
|
|
oPath.lineTo(pts[i]);
|
|
|
}
|
|
|
|
|
|
oPath.closeSubpath();
|
|
|
painter->fillPath(oPath, QBrush(m_clrBackgrd));
|
|
|
|
|
|
// 判断标记区域对象的点是否存在
|
|
|
if(m_regionMark != nullptr) {
|
|
|
QPointF ptPos = getValueOf(m_regionMark->getAllPos()[0]);
|
|
|
|
|
|
QPolygonF regionPolygon(getValueOf(this->getAllPos()));
|
|
|
|
|
|
if(!regionPolygon.containsPoint(ptPos, Qt::OddEvenFill)) {
|
|
|
this->setBackgrdColor(QColor(0, 0, 0, 0));
|
|
|
m_regionMark->setSelectRegion(false);
|
|
|
m_regionMark->getRegionMarkData()->setSelectRegion(false);
|
|
|
m_regionMark = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 区域填充
|
|
|
QPen pen = m_oPen;
|
|
|
painter->setPen(pen);
|
|
|
painter->drawPolygon(&pts[0], pts.count());
|
|
|
|
|
|
QRectF bound = getBounds();
|
|
|
|
|
|
// 绘制名称文字
|
|
|
QFont ft = qApp->font();
|
|
|
ft.setPointSize(8);
|
|
|
painter->setFont(ft);
|
|
|
painter->setPen(Qt::black);
|
|
|
ZxDrawHelper::drawText(painter,
|
|
|
bound,
|
|
|
Qt::AlignCenter | Qt::AlignVCenter,
|
|
|
m_sName);
|
|
|
}
|
|
|
|
|
|
if(isSelected()) { //选中状态下
|
|
|
|
|
|
for(int i = 0; i < pts.count(); i++) {
|
|
|
|
|
|
float w = 2.2f;
|
|
|
QPointF pt = pts[i];
|
|
|
QRectF rect(pt.x() - w * 0.5f, pt.y() - w * 0.5f, w, w);
|
|
|
|
|
|
if(m_nHitIndex == i && m_oHitOption == OHO_Point) { // 填充节点
|
|
|
QBrush br(Qt::red);
|
|
|
painter->fillRect(rect, br);
|
|
|
} else {
|
|
|
painter->setPen(QColor(0, 0, 128));
|
|
|
painter->drawRect(rect);
|
|
|
}
|
|
|
|
|
|
// 击中线
|
|
|
if(m_nHitIndex == i && m_oHitOption == OHO_Bound) {
|
|
|
|
|
|
nmDataLogFile::getInstance()->writeLog("select line " + QString::number(i));
|
|
|
QPen pen(Qt::DashLine);
|
|
|
|
|
|
painter->setPen(pen);
|
|
|
|
|
|
painter->drawPolygon(&pts[0], pts.count());
|
|
|
/*
|
|
|
for(int i = 0; i < pts.count() - 1; i++) {
|
|
|
painter->drawLine(pts[i], pts[i + 1]);
|
|
|
}
|
|
|
*/
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
painter->restore();
|
|
|
}
|
|
|
|
|
|
int nmObjRegion::getRegionFlowModel()
|
|
|
{
|
|
|
if(m_regionData->getRegionFlowModel().getValue() == tr("Leaky"))
|
|
|
return 0;
|
|
|
else
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::setRegionFlowModel(int newRegionFlowModel)
|
|
|
{
|
|
|
// 从Data中取数据
|
|
|
nmDataAttribute tempAttr = m_regionData->getRegionFlowModel();
|
|
|
|
|
|
if(newRegionFlowModel == 0) {
|
|
|
tempAttr.setValue(tr("Leaky"));
|
|
|
} else {
|
|
|
tempAttr.setValue(tr("Composite limit"));
|
|
|
}
|
|
|
|
|
|
m_regionData->setRegionFlowModel(tempAttr);
|
|
|
}
|
|
|
|
|
|
double nmObjRegion::getRegionLeakage()
|
|
|
{
|
|
|
return m_regionData->getRegionLeakage().getValue().toDouble();
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::setRegionLeakage(double newRegionLeakage)
|
|
|
{
|
|
|
// 从Data中取数据
|
|
|
nmDataAttribute tempAttr = m_regionData->getRegionLeakage();
|
|
|
tempAttr.setValue(newRegionLeakage);
|
|
|
m_regionData->setRegionLeakage(tempAttr);
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::setRegionMark(nmObjRegionMark* newRegionMark)
|
|
|
{
|
|
|
m_regionMark = newRegionMark;
|
|
|
}
|
|
|
|
|
|
nmObjRegionMark* nmObjRegion::getRegionMark() const
|
|
|
{
|
|
|
return m_regionMark;
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::setRegionData(nmDataRegion* newRegionData)
|
|
|
{
|
|
|
m_regionData = newRegionData;
|
|
|
}
|
|
|
|
|
|
nmDataRegion* nmObjRegion::getRegionData() const
|
|
|
{
|
|
|
return m_regionData;
|
|
|
}
|
|
|
|
|
|
//鞋带公式计算多边形有向面积。
|
|
|
static double calcSignedArea(const QVector<QPointF>& pts)
|
|
|
{
|
|
|
double area = 0;
|
|
|
int n = pts.size();
|
|
|
|
|
|
for(int i = 0; i < n; ++i) {
|
|
|
const QPointF &p1 = pts[i];
|
|
|
const QPointF &p2 = pts[(i + 1) % n]; // 保证闭合
|
|
|
area += (p1.x() * p2.y() - p2.x() * p1.y());
|
|
|
}
|
|
|
|
|
|
return area / 2.0;
|
|
|
}
|
|
|
|
|
|
// 新增:重新排序点,保证 m_vecPoints 中的点按照顺方向排列
|
|
|
void nmObjRegion::reorderPointsToAntiClockwise()
|
|
|
{
|
|
|
// 至少需要三个点才能形成封闭区域
|
|
|
if(m_vecPoints.size() < 3)
|
|
|
return;
|
|
|
|
|
|
// 使用 getPosOf 获取实际点的位置
|
|
|
double area = calcSignedArea(getPosOf(m_vecPoints));
|
|
|
|
|
|
// 如果面积为负,则说明点为逆时针排列,此时翻转数组
|
|
|
if(area < 0) {
|
|
|
std::reverse(m_vecPoints.begin(), m_vecPoints.end());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::afterCreated()
|
|
|
{
|
|
|
m_regionData = nmDataAnalyzeManager::getCurrentInstance()->createRegion();
|
|
|
// 初始化复合区基础数据
|
|
|
m_regionData->setRegionName(m_sName);
|
|
|
|
|
|
// 在区域创建完成后,调用重新排序函数确保点的顺序为顺时针
|
|
|
reorderPointsToAntiClockwise();
|
|
|
m_regionData->setVecPts(m_vecPoints);
|
|
|
|
|
|
// 判断复合区是否被区域标记
|
|
|
if(m_regionMark == nullptr) {
|
|
|
if(m_regionData->getRegionMarkData() != nullptr)
|
|
|
m_regionData->setRegionMarkData(nullptr);
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 添加区域标记对象
|
|
|
m_regionData->setRegionMarkData(m_regionMark->getRegionMarkData());
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::removeData()
|
|
|
{
|
|
|
if(m_regionData) {
|
|
|
// 从数据中心移除该数据
|
|
|
nmDataAnalyzeManager::getCurrentInstance()->removeRegionData(m_regionData);
|
|
|
m_regionData = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmObjRegion::onObjVisibleChanged(bool bIsVisible)
|
|
|
{
|
|
|
if(m_regionData != nullptr) {
|
|
|
m_regionData->setPlotVisible(bIsVisible);
|
|
|
}
|
|
|
}
|