You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmData/nmDataOutline.cpp

511 lines
17 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmDataOutline.h"
#include "nmDataJsonTools.h"
#include <QtAlgorithms>
// 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<int>(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<NM_Data_Outline_Type>(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<QPointF> nmDataOutline::getOutlinePoints() {
return m_vecPts;
}
void nmDataOutline::setOutlinePoints(const QVector<QPointF>& 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<int> nmDataOutline::getFlowTypeList() const {
return m_vFlowTypeList;
}
void nmDataOutline::setFlowTypeList(const QVector<int>& 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();
}