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.
kev/Drawer/Module/GeoSigmaDraw/TableDataImporter.cpp

373 lines
10 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 "stdafx.h"
#include "TableDataImporter.h"
#include "TsvParser.h"
#include "SigmaView.h"
#include <map>
//-----------------------------------------------------------------------------
// 列名与默认值(仅本文件使用,不暴露)
//-----------------------------------------------------------------------------
namespace
{
static const CString COL_X(_T("X"));
static const CString COL_Y(_T("Y"));
static const CString COL_Z(_T("Z"));
static const CString COL_L(_T("L"));
static const CString COL_NAME(_T("名称"));
static const CString COL_LAYER(_T("图层"));
static const CString DEFAULT_LAYER(_T("0"));
/** 整表导入前校验并取绘图对象,失败返回 nullptr */
CXy* GetXyForTableImport(CSigmaView* pView, const TsvParser::TableData& tableData, const TCHAR* tracePrefix)
{
if (pView == nullptr || pView->m_pDoc == nullptr)
{
TRACE("%s - 视图或文档为空\n", tracePrefix);
return nullptr;
}
CXy* pXy = pView->m_pDoc->GetDraw();
if (pXy == nullptr)
{
TRACE("%s - 无法获取绘图对象\n", tracePrefix);
return nullptr;
}
if (tableData.IsEmpty())
{
TRACE("%s - 表格数据为空\n", tracePrefix);
return nullptr;
}
if (tableData.GetColumnIndex(COL_X) < 0 || tableData.GetColumnIndex(COL_Y) < 0)
{
TRACE("%s - 缺少必需的 X 或 Y 列\n", tracePrefix);
return nullptr;
}
return pXy;
}
/** 将单个点加入文档layerName 必填name 为空则不设置名称) */
void AddOnePointToDocument(CXy* pXy, double x, double y, double z, const CString& layerName, const CString& name)
{
CPointNameEx* pPoint = new CPointNameEx();
pPoint->x0 = x;
pPoint->y0 = y;
pPoint->z0 = z;
if (!name.IsEmpty())
pPoint->SetName(name);
CLayer* pLayer = pXy->FindAddLayer(layerName);
POSITION pos = pXy->AddElement(pPoint, DOUBLEFOX_POINT);
COne* pOne = pXy->GetAt(pos);
pOne->SetLayer(pLayer);
}
}
namespace
{
struct CurveEntry
{
double x, y, z, length;
CString name;
CString layer;
};
/** 整表曲线导入:解析 → 按图层/名称分组 → 写入文档,实现细节集中在此类 */
class CurveTableImporter
{
public:
/** @return 导入曲线条数,无有效数据返回 -1 */
int Import(CXy* pXy, const TsvParser::TableData& tableData)
{
std::vector<CurveEntry> entries = ParseTableToCurveEntries(tableData);
if (entries.empty())
return -1;
std::map<CString, std::vector<std::vector<CurveEntry>>> layerCurves = GroupEntriesByLayerAndCurveName(entries);
return AddCurvesToDocument(pXy, layerCurves);
}
private:
static std::vector<CurveEntry> ParseTableToCurveEntries(const TsvParser::TableData& tableData)
{
std::vector<CurveEntry> entries;
for (const auto& row : tableData.rows)
{
CString strX = tableData.GetValue(row, COL_X);
CString strY = tableData.GetValue(row, COL_Y);
if (strX.IsEmpty() || strY.IsEmpty())
continue;
CurveEntry entry;
entry.x = _tstof(strX);
entry.y = _tstof(strY);
entry.z = tableData.GetDoubleValue(row, COL_Z, 0.0);
entry.length = tableData.GetDoubleValue(row, COL_L, 0.0);
entry.name = tableData.GetValue(row, COL_NAME);
entry.layer = tableData.GetValue(row, COL_LAYER);
if (entry.layer.IsEmpty())
entry.layer = DEFAULT_LAYER;
entries.push_back(entry);
}
return entries;
}
/** 按图层分组,同一图层内再按“名称”连续段切分为多条曲线 */
static std::map<CString, std::vector<std::vector<CurveEntry>>> GroupEntriesByLayerAndCurveName(const std::vector<CurveEntry>& entries)
{
std::map<CString, std::vector<CurveEntry>> layerEntries;
for (const auto& entry : entries)
layerEntries[entry.layer].push_back(entry);
std::map<CString, std::vector<std::vector<CurveEntry>>> layerCurves;
for (const auto& layerPair : layerEntries)
{
const CString& layerName = layerPair.first;
const auto& layerPoints = layerPair.second;
std::vector<std::vector<CurveEntry>> curves;
std::vector<CurveEntry> currentCurve;
CString currentName;
for (const auto& entry : layerPoints)
{
if (currentCurve.empty() || currentName != entry.name)
{
if (!currentCurve.empty())
{
curves.push_back(currentCurve);
currentCurve.clear();
}
currentName = entry.name;
}
currentCurve.push_back(entry);
}
if (!currentCurve.empty())
curves.push_back(currentCurve);
layerCurves[layerName] = curves;
}
return layerCurves;
}
static int AddCurvesToDocument(CXy* pXy, const std::map<CString, std::vector<std::vector<CurveEntry>>>& layerCurves)
{
int importCount = 0;
for (const auto& layerPair : layerCurves)
{
const CString& layerName = layerPair.first;
const auto& curves = layerPair.second;
CLayer* pLayer = pXy->FindAddLayer(layerName);
for (const auto& curvePoints : curves)
{
if (curvePoints.empty())
continue;
CCurveEx* pCurve = new CCurveEx();
pCurve->SetName(curvePoints[0].name);
pCurve->Create((int)curvePoints.size());
pCurve->width = 1;
for (size_t i = 0; i < curvePoints.size(); i++)
{
pCurve->x[i] = curvePoints[i].x;
pCurve->y[i] = curvePoints[i].y;
pCurve->z[i] = curvePoints[i].z;
pCurve->l[i] = curvePoints[i].length;
}
pCurve->GetLocation();
POSITION pos = pXy->AddElement(pCurve, DOUBLEFOX_CURVE);
COne* pOne = pXy->GetAt(pos);
pOne->SetLayer(pLayer);
importCount++;
}
}
return importCount;
}
};
}
int ImportTableAsCurves(CSigmaView* pView, const TsvParser::TableData& tableData)
{
CXy* pXy = GetXyForTableImport(pView, tableData, _T("ImportTableAsCurves"));
if (pXy == nullptr)
return -1;
int importCount = CurveTableImporter().Import(pXy, tableData);
if (importCount < 0)
{
TRACE("ImportTableAsCurves - 没有有效的数据行\n");
return -1;
}
TRACE("ImportTableAsCurves - 成功导入 %d 条曲线\n", importCount);
return importCount;
}
//=============================================================================
// 流式按行导入
//=============================================================================
void BuildColumnIndexMapFromHeaders(const std::vector<CString>& headers, std::map<CString, int>& outMap)
{
outMap.clear();
for (size_t i = 0; i < headers.size(); i++)
{
CString key = headers[i];
key.MakeUpper();
key.Trim();
outMap[key] = (int)i;
}
}
CString GetRowValue(const std::vector<CString>& row, const std::map<CString, int>& columnIndexMap, const CString& columnName)
{
CString key = columnName;
key.MakeUpper();
key.Trim();
auto it = columnIndexMap.find(key);
if (it != columnIndexMap.end() && it->second >= 0 && it->second < (int)row.size())
{
CString v = row[it->second];
v.Trim();
return v;
}
return _T("");
}
double GetRowDoubleValue(const std::vector<CString>& row, const std::map<CString, int>& columnIndexMap, const CString& columnName, double defaultValue)
{
CString s = GetRowValue(row, columnIndexMap, columnName);
if (s.IsEmpty())
return defaultValue;
return _tstof(s);
}
namespace
{
/** 流式导入单行点withName 为 true 时从行中取“名称”并设置。跳过无效行返回 true不算失败。 */
bool ImportPointRowStreamImpl(CSigmaView* pView, const std::map<CString, int>& columnIndexMap, const std::vector<CString>& row, bool withName)
{
if (pView == nullptr || pView->m_pDoc == nullptr)
{
return false;
}
CXy* pXy = pView->m_pDoc->GetDraw();
if (pXy == nullptr)
{
return false;
}
CString strX = GetRowValue(row, columnIndexMap, COL_X);
CString strY = GetRowValue(row, columnIndexMap, COL_Y);
if (strX.IsEmpty() || strY.IsEmpty())
{
return true; // 跳过无效行,不算失败
}
double x = _tstof(strX);
double y = _tstof(strY);
double z = GetRowDoubleValue(row, columnIndexMap, COL_Z, 0.0);
CString layerName = GetRowValue(row, columnIndexMap, COL_LAYER);
if (layerName.IsEmpty())
{
layerName = DEFAULT_LAYER;
}
CString name;
if (withName)
{
name = GetRowValue(row, columnIndexMap, COL_NAME);
}
AddOnePointToDocument(pXy, x, y, z, layerName, name);
return true;
}
}
bool ImportPointRow(CSigmaView* pView, const std::map<CString, int>& columnIndexMap, const std::vector<CString>& row)
{
return ImportPointRowStreamImpl(pView, columnIndexMap, row, true);
}
bool ImportXyzPointRow(CSigmaView* pView, const std::map<CString, int>& columnIndexMap, const std::vector<CString>& row)
{
return ImportPointRowStreamImpl(pView, columnIndexMap, row, false);
}
// ---------------------------------------------------------------------------
// CurveStreamImporter
// ---------------------------------------------------------------------------
CurveStreamImporter::CurveStreamImporter(CSigmaView* pView)
: m_pView(pView)
{
if (pView && pView->m_pDoc)
m_pXy = pView->m_pDoc->GetDraw();
}
void CurveStreamImporter::OnRow(const std::map<CString, int>& columnIndexMap, const std::vector<CString>& row)
{
if (m_pXy == nullptr)
return;
CString strX = GetRowValue(row, columnIndexMap, COL_X);
CString strY = GetRowValue(row, columnIndexMap, COL_Y);
if (strX.IsEmpty() || strY.IsEmpty())
return;
double x = _tstof(strX);
double y = _tstof(strY);
double z = GetRowDoubleValue(row, columnIndexMap, COL_Z, 0.0);
double l = GetRowDoubleValue(row, columnIndexMap, COL_L, 0.0);
CString name = GetRowValue(row, columnIndexMap, COL_NAME);
CString layer = GetRowValue(row, columnIndexMap, COL_LAYER);
if (layer.IsEmpty())
layer = DEFAULT_LAYER;
if (!m_curX.empty() && (m_currentLayer != layer || m_currentName != name))
FlushCurrentCurve();
m_currentLayer = layer;
m_currentName = name;
m_curName = name;
m_curX.push_back(x);
m_curY.push_back(y);
m_curZ.push_back(z);
m_curL.push_back(l);
}
void CurveStreamImporter::FlushCurrentCurve()
{
if (m_pXy == nullptr || m_curX.empty())
return;
CLayer* pLayer = m_pXy->FindAddLayer(m_currentLayer);
CCurveEx* pCurve = new CCurveEx();
pCurve->SetName(m_curName);
pCurve->Create((int)m_curX.size());
pCurve->width = 1;
for (size_t i = 0; i < m_curX.size(); i++)
{
pCurve->x[i] = m_curX[i];
pCurve->y[i] = m_curY[i];
pCurve->z[i] = m_curZ[i];
pCurve->l[i] = m_curL[i];
}
pCurve->GetLocation();
POSITION pos = m_pXy->AddElement(pCurve, DOUBLEFOX_CURVE);
COne* pOne = m_pXy->GetAt(pos);
pOne->SetLayer(pLayer);
m_curX.clear();
m_curY.clear();
m_curZ.clear();
m_curL.clear();
m_importCount++;
}
void CurveStreamImporter::End()
{
FlushCurrentCurve();
}