|
|
#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();
|
|
|
}
|