#include "nmDataOutline.h" #include "nmDataJsonTools.h" #include // Constructor nmDataOutline::nmDataOutline() : m_bSyncingGeometryAttributes(false) , m_sName() , m_vecPts() , m_vFlowTypeList() , m_eOutlineType(NM_Rect_Outline_Type) , m_ptCenter() , m_dRadius(0.0) , m_bPlotVisible(true) , m_dPenWidth(0.0) , m_clrBackgrd(QColor(0, 0, 255)) , m_nBackgrdAlpha(0) , m_bHasVisualProps(false) { initGeometryAttributes(); } nmDataOutline::nmDataOutline(const nmDataOutline& other) : m_bSyncingGeometryAttributes(false) { initGeometryAttributes(); *this = other; } nmDataOutline& nmDataOutline::operator=(const nmDataOutline& other) { if (this != &other) { m_dRadius = other.m_dRadius; m_vecPts = other.m_vecPts; m_vFlowTypeList = other.m_vFlowTypeList; m_eOutlineType = other.m_eOutlineType; m_ptCenter = other.m_ptCenter; m_sName = other.m_sName; m_bPlotVisible = other.m_bPlotVisible; m_dPenWidth = other.m_dPenWidth; m_clrBackgrd = other.m_clrBackgrd; m_nBackgrdAlpha = other.m_nBackgrdAlpha; m_bHasVisualProps = other.m_bHasVisualProps; syncGeometryAttributes(); } return *this; } // Destructor nmDataOutline::~nmDataOutline() { clearPointAttributes(); } // 序列化 nmDataOutline 为 RapidJSON Value rapidjson::Value nmDataOutline::ToJsonValue(rapidjson::Document::AllocatorType& allocator) const { // 创建一个 RapidJSON 对象类型的值 rapidjson::Value outlineObject(rapidjson::kObjectType); // 序列化名称 // 将 QString 转换为 UTF-8 编码的 C 字符串,并添加到 JSON 中 outlineObject.AddMember("OutlineName", rapidjson::Value(m_sName.toStdString().c_str(), allocator).Move(), allocator); // 序列化点 rapidjson::Value pointsArray(rapidjson::kArrayType); // 创建一个 RapidJSON 数组类型的值 // 遍历点列表 foreach (const QPointF& point , m_vecPts) { rapidjson::Value pointObject(rapidjson::kObjectType); // 创建一个点对象 pointObject.AddMember("x", point.x(), allocator); // 添加x坐标 pointObject.AddMember("y", point.y(), allocator); // 添加y坐标 pointsArray.PushBack(pointObject, allocator); // 将点对象推入数组 } outlineObject.AddMember("OutlinePoints", pointsArray, allocator); // 将点数组添加到JSON对象 // 边界压力类型列表 rapidjson::Value flowArry(rapidjson::kArrayType); for (int i = 0; i < m_vFlowTypeList.size(); ++i) { flowArry.PushBack(m_vFlowTypeList[i], allocator); } outlineObject.AddMember("FlowTypeList", flowArry, allocator); // 边界类型(枚举转 int) outlineObject.AddMember("OutlineType", static_cast(m_eOutlineType), allocator); // 如果是圆形,写入 Center 和 Radius if (m_eOutlineType == NM_Data_Outline_Type::NM_Round_Outline_Type) { rapidjson::Value cen(rapidjson::kObjectType); cen.AddMember("x", m_ptCenter.x(), allocator); cen.AddMember("y", m_ptCenter.y(), allocator); outlineObject.AddMember("Center", cen, allocator); outlineObject.AddMember("Radius", m_dRadius, allocator); } // 序列化图元可见性 (m_bPlotVisible) outlineObject.AddMember("PlotVisible", m_bPlotVisible, allocator); // 使用m_bPlotVisible // 序列化视觉属性 outlineObject.AddMember("PenWidth", m_dPenWidth, allocator); outlineObject.AddMember("BackgrdR", m_clrBackgrd.red(), allocator); outlineObject.AddMember("BackgrdG", m_clrBackgrd.green(), allocator); outlineObject.AddMember("BackgrdB", m_clrBackgrd.blue(), allocator); outlineObject.AddMember("BackgrdAlpha", m_nBackgrdAlpha, allocator); return outlineObject; // 返回序列化后的 RapidJSON Value } // 从 RapidJSON Value 反序列化数据到 nmDataOutline void nmDataOutline::FromJsonValue(const rapidjson::Value& jsonValue) { // 名称 if (jsonValue.HasMember("OutlineName") && jsonValue["OutlineName"].IsString()) { m_sName = QString::fromUtf8(jsonValue["OutlineName"].GetString()); } // 反序列化点 if (jsonValue.HasMember("OutlinePoints") && jsonValue["OutlinePoints"].IsArray()) { m_vecPts.clear(); // 清空当前点列表,使用m_vecPts const rapidjson::Value& pointsArray = jsonValue["OutlinePoints"]; // 获取点数组节点 // 遍历数组,将每个点对象反序列化到 m_vecPts for (rapidjson::SizeType i = 0; i < pointsArray.Size(); ++i) { if (pointsArray[i].IsObject() && pointsArray[i].HasMember("x") && pointsArray[i]["x"].IsDouble() && pointsArray[i].HasMember("y") && pointsArray[i]["y"].IsDouble()) { m_vecPts.append(QPointF(pointsArray[i]["x"].GetDouble(), pointsArray[i]["y"].GetDouble())); } } } // 压力类型列表 if (jsonValue.HasMember("FlowTypeList") && jsonValue["FlowTypeList"].IsArray()) { m_vFlowTypeList.clear(); const rapidjson::Value& flowArr = jsonValue["FlowTypeList"]; for (rapidjson::SizeType i = 0; i < flowArr.Size(); ++i) { if (flowArr[i].IsInt()) { m_vFlowTypeList.append(flowArr[i].GetInt()); } } } // 枚举类型 if (jsonValue.HasMember("OutlineType") && jsonValue["OutlineType"].IsInt()) { m_eOutlineType = static_cast(jsonValue["OutlineType"].GetInt()); } // 圆形专属字段 if (m_eOutlineType == NM_Data_Outline_Type::NM_Round_Outline_Type) { if (jsonValue.HasMember("Center") && jsonValue["Center"].IsObject()) { const rapidjson::Value& c = jsonValue["Center"]; if (c.HasMember("x") && c["x"].IsDouble() && c.HasMember("y") && c["y"].IsDouble()) { m_ptCenter = QPointF( c["x"].GetDouble(), c["y"].GetDouble()); } } if (jsonValue.HasMember("Radius") && jsonValue["Radius"].IsNumber()) { m_dRadius = jsonValue["Radius"].GetDouble(); } } // 反序列化图元可见性 (m_bPlotVisible) if (jsonValue.HasMember("PlotVisible") && jsonValue["PlotVisible"].IsBool()) { m_bPlotVisible = jsonValue["PlotVisible"].GetBool(); // 使用m_bPlotVisible } // 反序列化视觉属性 bool bHasVisual = false; if (jsonValue.HasMember("PenWidth") && jsonValue["PenWidth"].IsNumber()) { m_dPenWidth = jsonValue["PenWidth"].GetDouble(); bHasVisual = true; } int r = 0, g = 0, b = 255; if (jsonValue.HasMember("BackgrdR") && jsonValue["BackgrdR"].IsInt()) r = jsonValue["BackgrdR"].GetInt(); if (jsonValue.HasMember("BackgrdG") && jsonValue["BackgrdG"].IsInt()) g = jsonValue["BackgrdG"].GetInt(); if (jsonValue.HasMember("BackgrdB") && jsonValue["BackgrdB"].IsInt()) b = jsonValue["BackgrdB"].GetInt(); m_clrBackgrd = QColor(r, g, b); if (jsonValue.HasMember("BackgrdAlpha") && jsonValue["BackgrdAlpha"].IsInt()) { m_nBackgrdAlpha = jsonValue["BackgrdAlpha"].GetInt(); bHasVisual = true; } m_bHasVisualProps = bHasVisual; syncGeometryAttributes(); } // Getter and Setter for m_sName QString nmDataOutline::getName() { return m_sName; } void nmDataOutline::setName(const QString& sName) { m_sName = sName; } // Getter and Setter for m_vecPts QVector nmDataOutline::getOutlinePoints() { return m_vecPts; } void nmDataOutline::setOutlinePoints(const QVector& vecPts) { m_vecPts = vecPts; syncPointAttributes(); if (m_eOutlineType == NM_Rect_Outline_Type) { syncRectAttributes(); } else if (m_eOutlineType == NM_Round_Outline_Type) { syncRoundAttributes(); } } int nmDataOutline::getOutlinePointCount() const { return m_vecPts.count(); } nmDataAttribute* nmDataOutline::getPointXAttribute(int nIndex) const { if (nIndex < 0 || nIndex >= m_vPointXAttributes.count()) return nullptr; return m_vPointXAttributes[nIndex]; } nmDataAttribute* nmDataOutline::getPointYAttribute(int nIndex) const { if (nIndex < 0 || nIndex >= m_vPointYAttributes.count()) return nullptr; return m_vPointYAttributes[nIndex]; } nmDataAttribute& nmDataOutline::getLeftAttribute() { return m_left; } nmDataAttribute& nmDataOutline::getRightAttribute() { return m_right; } nmDataAttribute& nmDataOutline::getTopAttribute() { return m_top; } nmDataAttribute& nmDataOutline::getBottomAttribute() { return m_bottom; } nmDataAttribute& nmDataOutline::getCenterXAttribute() { return m_centerX; } nmDataAttribute& nmDataOutline::getCenterYAttribute() { return m_centerY; } nmDataAttribute& nmDataOutline::getRadiusAttribute() { return m_radius; } QVector nmDataOutline::getFlowTypeList() const { return m_vFlowTypeList; } void nmDataOutline::setFlowTypeList(const QVector& vecFlowTypeList) { m_vFlowTypeList = vecFlowTypeList; } // Getter for m_eOutlineType NM_Data_Outline_Type nmDataOutline::getOutlineType() const { return m_eOutlineType; } // Setter for m_eOutlineType void nmDataOutline::setOutlineType(NM_Data_Outline_Type eOutlineType) { m_eOutlineType = eOutlineType; syncGeometryAttributes(); } // Getter for m_ptCenter QPointF nmDataOutline::getCenter() const { return m_ptCenter; } // Setter for m_ptCenter void nmDataOutline::setCenter(const QPointF& ptCenter) { m_ptCenter = ptCenter; syncRoundAttributes(); } // Getter for m_dRadius double nmDataOutline::getRadius() const { return m_dRadius; } // Setter for m_dRadius void nmDataOutline::setRadius(double dRadius) { m_dRadius = dRadius; syncRoundAttributes(); } bool nmDataOutline::getPlotVisible() const{ return m_bPlotVisible; } void nmDataOutline::setPlotVisible(const bool newState) { m_bPlotVisible = newState; } // 视觉属性 getter/setter double nmDataOutline::getPenWidth() const { return m_dPenWidth; } void nmDataOutline::setPenWidth(double dWidth) { m_dPenWidth = dWidth; } QColor nmDataOutline::getBackgrdColor() const { return m_clrBackgrd; } void nmDataOutline::setBackgrdColor(const QColor& clr) { m_clrBackgrd = clr; } int nmDataOutline::getBackgrdAlpha() const { return m_nBackgrdAlpha; } void nmDataOutline::setBackgrdAlpha(int nAlpha) { m_nBackgrdAlpha = nAlpha; } bool nmDataOutline::hasVisualProps() const { return m_bHasVisualProps; } void nmDataOutline::setVisualPropsValid(bool bValid) { m_bHasVisualProps = bValid; } // 固定几何属性作为参数面板适配层,实际持久化数据仍保存在原有字段中。 void nmDataOutline::initGeometryAttributes() { QStringList lengthUnits; lengthUnits << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"; m_left = nmDataAttribute("Boundary left X", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_right = nmDataAttribute("Boundary right X", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_top = nmDataAttribute("Boundary top Y", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_bottom = nmDataAttribute("Boundary bottom Y", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_centerX = nmDataAttribute("Boundary center X", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_centerY = nmDataAttribute("Boundary center Y", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); m_radius = nmDataAttribute("Boundary radius", 0.0, "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); connect(&m_left, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_right, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_top, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_bottom, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_centerX, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_centerY, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(&m_radius, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); } void nmDataOutline::clearPointAttributes() { qDeleteAll(m_vPointXAttributes); qDeleteAll(m_vPointYAttributes); m_vPointXAttributes.clear(); m_vPointYAttributes.clear(); } // 根据边界类型,将原有几何数据同步到对应的面板绑定属性。 void nmDataOutline::syncGeometryAttributes() { syncPointAttributes(); if (m_eOutlineType == NM_Rect_Outline_Type) { syncRectAttributes(); } else if (m_eOutlineType == NM_Round_Outline_Type) { syncRoundAttributes(); } } void nmDataOutline::syncPointAttributes() { // 矩形和圆形使用固定几何属性,只有多边形需要逐点属性。 if (m_eOutlineType != NM_Polygon_Outline_Type) { if (!m_vPointXAttributes.isEmpty() || !m_vPointYAttributes.isEmpty()) { clearPointAttributes(); } return; } if (m_vPointXAttributes.count() != m_vecPts.count() || m_vPointYAttributes.count() != m_vecPts.count()) { clearPointAttributes(); QStringList lengthUnits; lengthUnits << "m" << "cm" << "mm" << "in" << "0.1 in" << "ft" << "mile" << "km"; for (int i = 0; i < m_vecPts.count(); ++i) { nmDataAttribute* pX = new nmDataAttribute(QString("Boundary point %1 X").arg(i + 1), m_vecPts[i].x(), "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); nmDataAttribute* pY = new nmDataAttribute(QString("Boundary point %1 Y").arg(i + 1), m_vecPts[i].y(), "m", UNIT_TYPE_LENGTH, QStringList(), lengthUnits); pX->setParent(this); pY->setParent(this); connect(pX, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); connect(pY, SIGNAL(sigValueChanged()), this, SLOT(onGeometryAttributeChanged()), Qt::UniqueConnection); m_vPointXAttributes.append(pX); m_vPointYAttributes.append(pY); } } m_bSyncingGeometryAttributes = true; for (int i = 0; i < m_vecPts.count(); ++i) { if (m_vPointXAttributes[i]->getValue().toDouble() != m_vecPts[i].x()) { m_vPointXAttributes[i]->setValue(m_vecPts[i].x()); } if (m_vPointYAttributes[i]->getValue().toDouble() != m_vecPts[i].y()) { m_vPointYAttributes[i]->setValue(m_vecPts[i].y()); } } m_bSyncingGeometryAttributes = false; } void nmDataOutline::syncRectAttributes() { if (m_vecPts.isEmpty()) return; double left = m_vecPts.first().x(); double right = left; double top = m_vecPts.first().y(); double bottom = top; foreach (const QPointF& pt, m_vecPts) { left = qMin(left, pt.x()); right = qMax(right, pt.x()); top = qMax(top, pt.y()); bottom = qMin(bottom, pt.y()); } m_bSyncingGeometryAttributes = true; if (m_left.getValue().toDouble() != left) m_left.setValue(left); if (m_right.getValue().toDouble() != right) m_right.setValue(right); if (m_top.getValue().toDouble() != top) m_top.setValue(top); if (m_bottom.getValue().toDouble() != bottom) m_bottom.setValue(bottom); m_bSyncingGeometryAttributes = false; } void nmDataOutline::syncRoundAttributes() { m_bSyncingGeometryAttributes = true; if (m_centerX.getValue().toDouble() != m_ptCenter.x()) m_centerX.setValue(m_ptCenter.x()); if (m_centerY.getValue().toDouble() != m_ptCenter.y()) m_centerY.setValue(m_ptCenter.y()); if (m_radius.getValue().toDouble() != m_dRadius) m_radius.setValue(m_dRadius); m_bSyncingGeometryAttributes = false; } void nmDataOutline::updateRectPointsFromAttributes() { const double left = m_left.getValue().toDouble(); const double right = m_right.getValue().toDouble(); const double top = m_top.getValue().toDouble(); const double bottom = m_bottom.getValue().toDouble(); m_vecPts.clear(); m_vecPts << QPointF(left, top) << QPointF(right, top) << QPointF(right, bottom) << QPointF(left, bottom); syncPointAttributes(); } void nmDataOutline::updateRoundPointsFromAttributes() { const QPointF center(m_centerX.getValue().toDouble(), m_centerY.getValue().toDouble()); const double radius = m_radius.getValue().toDouble(); m_ptCenter = center; m_dRadius = radius; m_vecPts.clear(); m_vecPts << center << QPointF(radius, radius) << QPointF(center.x(), center.y() - radius) << QPointF(center.x() + radius, center.y()) << QPointF(center.x(), center.y() + radius) << QPointF(center.x() - radius, center.y()); syncPointAttributes(); } // 参数面板修改几何属性后,回写边界数据并通知 Binder 更新图元。 void nmDataOutline::onGeometryAttributeChanged() { if (m_bSyncingGeometryAttributes) return; QObject* pSender = sender(); if (pSender == &m_left || pSender == &m_right || pSender == &m_top || pSender == &m_bottom) { updateRectPointsFromAttributes(); } else if (pSender == &m_centerX || pSender == &m_centerY || pSender == &m_radius) { updateRoundPointsFromAttributes(); } else { for (int i = 0; i < m_vecPts.count(); ++i) { if (pSender == m_vPointXAttributes.value(i, nullptr)) { m_vecPts[i].setX(m_vPointXAttributes[i]->getValue().toDouble()); break; } if (pSender == m_vPointYAttributes.value(i, nullptr)) { m_vecPts[i].setY(m_vPointYAttributes[i]->getValue().toDouble()); break; } } } emit sigOutlineDataChanged(); }