#include "stdafx.h" #include "TableDataImporter.h" #include "TsvParser.h" #include "SigmaView.h" #include //----------------------------------------------------------------------------- // 列名与默认值(仅本文件使用,不暴露) //----------------------------------------------------------------------------- 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 entries = ParseTableToCurveEntries(tableData); if (entries.empty()) return -1; std::map>> layerCurves = GroupEntriesByLayerAndCurveName(entries); return AddCurvesToDocument(pXy, layerCurves); } private: static std::vector ParseTableToCurveEntries(const TsvParser::TableData& tableData) { std::vector 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>> GroupEntriesByLayerAndCurveName(const std::vector& entries) { std::map> layerEntries; for (const auto& entry : entries) layerEntries[entry.layer].push_back(entry); std::map>> layerCurves; for (const auto& layerPair : layerEntries) { const CString& layerName = layerPair.first; const auto& layerPoints = layerPair.second; std::vector> curves; std::vector 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>>& 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& headers, std::map& 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& row, const std::map& 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& row, const std::map& 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& columnIndexMap, const std::vector& 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& columnIndexMap, const std::vector& row) { return ImportPointRowStreamImpl(pView, columnIndexMap, row, true); } bool ImportXyzPointRow(CSigmaView* pView, const std::map& columnIndexMap, const std::vector& 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& columnIndexMap, const std::vector& 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(); }