#include "stdafx.h" #include #include #include "DrawOperator/XyIO.h" #include "TinyXml/tinyxml.h" #include "ActionDeleteItem.h" #include "DrawOperator/Net.h" #include "DrawOperator/LibraryManager.h" #include "DrawOperator\FileUtility.h" #include "DrawOperator/unordered_dense.h" #include "DrawOperator\MergePDFFile.h" #include "Util.h" #include "Legend.h" #include "UndecidedZone.h" #include "KEDAlgorithm.h" #include "FaciesLegend.h" void XyDeSerialize(CXy* pXy, CArchive& ar); extern "C" __declspec(dllexport) void* XyCreate() { CXy* pXy = new CXy; AfxGetPublicFunction()->EnableJudgeRange(TRUE); return pXy; } extern "C" __declspec(dllexport) bool DestroyXy(CXy* pXy) { if (pXy != nullptr) { delete pXy; pXy = nullptr; } return true; } extern "C" __declspec(dllexport) bool XyOpenFile(CXy* pXy, LPCTSTR lpszFileName, bool realTimeDraw) { if (pXy != NULL) { pXy->Clear(); } else { pXy = new CXy; } return pXy->OpenFile(lpszFileName, realTimeDraw); //pXy->m_bRealTimeDraw = realTimeDraw; //if (pXy->ReadOtherWithExtension(lpszFileName)) //{ // return TRUE; //} //CString path(lpszFileName); //CString tempFileName = PreprocessFile(path); //if (tempFileName.IsEmpty()) //{ // return FALSE; //} //CFile file; //if (file.Open(tempFileName, CFile::modeRead)) //{ // CArchive ar(&file, CArchive::load); // XyDeSerialize(pXy, ar); // ar.Close(); // file.Close(); //} //CFileStatus status; //// 注意:如果 tempFileName 和 path 相同,说明原文件没有加密,这时的 tempFileName 就是原文件的路径,不能删除 //if (CFile::GetStatus(tempFileName, status) && tempFileName != path) //{ // CFile::Remove(tempFileName); //} //return TRUE; } extern "C" __declspec(dllexport) bool XyDrawFile(CXy* pXy, HDC hdcMem, int left, int top, int width, int height) { CRect client; client.left = left; client.bottom = top; client.top = height + top; client.right = width + left; CRect8 rect(1e100, -1e100, -1e100, 1e100); if (pXy->GetCount() > 0) { pXy->GetRange(rect); pXy->m_range = rect; } else { return false; } CDC* pDC = CDC::FromHandle(hdcMem); CXyDC m_xyDC; m_xyDC.Create(pDC); // m_xyDC.SetViewRect(client); 629612432 m_xyDC.Extend(rect, client, EXTEND_MODE_CENTER); pXy->Draw(m_xyDC, false); return true; } extern "C" __declspec(dllexport) void XyEnableMeshPackage(CXy* pXy, bool enable) { pXy->EnableMeshPackage(enable); } //////////////////////////////////////////////////////////////////////////////////////////// // 从内存块读取数据生成图片 //////////////////////////////////////////////////////////////////////////////////////////// extern "C" __declspec(dllexport) HBITMAP GetBitmap(CXy* pXy, int width, int height, int inflate) { if (pXy == NULL) return FALSE; CDC dc; dc.CreateCompatibleDC(NULL); CXyDC pDC; pDC.Create(&dc, false); //pDC.SetAntiAlias(true); CSize sz(width, height); CRect rt(0, 0, width, height); int planes = dc.GetDeviceCaps(PLANES); int bpp = dc.GetDeviceCaps(BITSPIXEL); CBitmap* pBitmap, * pOldBitmap; pBitmap = new CBitmap(); pBitmap->CreateBitmap(sz.cx, sz.cy, planes, bpp, NULL); pOldBitmap = dc.SelectObject(pBitmap); dc.FillSolidRect(0, 0, sz.cx, sz.cy, RGB(255, 255, 255)); CRect8 rect(1e100, -1e100, -1e100, 1e100); if (pXy->GetCount() > 0) { pXy->GetRange(rect); pXy->m_range = rect; rt.InflateRect(-inflate, -inflate, -inflate, -inflate); pDC.Extend(rect, rt, EXTEND_MODE_CENTER); pDC.SetViewRect(rt); pXy->Draw(pDC); } dc.SelectObject(pOldBitmap); HBITMAP hBit = (HBITMAP)pBitmap->Detach(); pBitmap->DeleteObject(); dc.DeleteDC(); delete pBitmap; return hBit; } extern "C" __declspec(dllexport) bool GetMapSize(CXy* pXy, double& xMin, double& yMin, double& xMax, double& yMax) { CRect8 rect(1e100, -1e100, -1e100, 1e100); pXy->GetRange(rect, false); xMin = rect.left; yMin = rect.bottom; xMax = rect.right; yMax = rect.top; return true; } extern "C" __declspec(dllexport) void DeleteHBITMAP(HBITMAP hBmp) { DeleteObject(hBmp); } void XyDeSerialize(CXy* pXy, CArchive& ar) { //CPublicFunction& pf = *AfxGetPublicFunction(); if (pXy == NULL) pXy = new CXy; //BeginProgress(IDS_STRING_OpenFile); CString name = ar.GetFile()->GetFileName(); name.MakeLower(); CSplitPath sp(name); CString ext = sp.GetExtension(); //ar.m_pDocument = this; // set back-pointer in archive if (ext == _T(".dfb") || ext == _T(".dft")) { pXy->m_version = pXy->DFB_ReadVersion(ar); pXy->DFB_ReadEncrypt(ar, pXy->m_version); if (pXy->IsEncrypted()) { //if (!VerifyPassword(GetDraw())) //{ // m_bCancelRead = TRUE; // EndProgress(); // return; //} } pXy->DFB_Serialize(ar, pXy->m_version); } else if (ext == ".dml" || ext == ".xml") pXy->DML_Read2(*(ar.GetFile())); else if (ext == ".pcg") pXy->PCG_Read2(*(ar.GetFile())); else pXy->DFD_Read2(*(ar.GetFile())); //// 断层边缘补丁 //m_pXy->CreateMeshPackage(); //EndProgress(); } bool XySerialize(CXy* pXy, CArchive& ar, int docTypeID,int version=-1) { short ver = version; switch (docTypeID) { default: //当前缺省版本 pXy->DFD_Write2(*(ar.GetFile()), ver, TRUE); break; case DF_FORMAT_DFT: //双狐模板格式 case DF_FORMAT_BINARY: //双狐二进制格式 pXy->DFB_SerializeWrite(ar, ver, TRUE); break; case DF_FORMAT_DML: pXy->DML_WriteAll(*(ar.GetFile()), ver, TRUE); break; case DF_FORMAT_PCG: pXy->PCG_WriteAll(*(ar.GetFile()), 2, TRUE); break; case DF_FORMAT_OLD_ASCII: //老版本-不再写老版本 //pXy->DFD_Write2(*(ar.GetFile()), 2004, TRUE); pXy->DFD_Write2(*(ar.GetFile()), ver, TRUE); break; case DF_FORMAT_DXF: //pxy->ToDxf(&GetDC(), *(ar.GetFile())); //xy.ToDxf(&GetDC(), *(ar.GetFile())); break; case DF_FORMAT_CGM: //pf.SetExportDPI(::GetPreferences().WorkaroundSave.m_nExportModeDPI, ::GetPreferences().WorkaroundSave.m_dExportDPI); //pxy->ToCgm(&GetDC(), *(ar.GetFile())); //xy.ToCgm(&GetDC(), *(ar.GetFile())); break; case DF_FORMAT_EPS: //pf.SetExportDPI(::GetPreferences().WorkaroundSave.m_nExportModeDPI, ::GetPreferences().WorkaroundSave.m_dExportDPI); //pxy->ToEps(&GetDC(), *(ar.GetFile())); //xy.ToEps(&GetDC(), *(ar.GetFile())); break; case DF_FORMAT_PDF: //pf.SetExportDPI(::GetPreferences().WorkaroundSave.m_nExportModeDPI, ::GetPreferences().WorkaroundSave.m_dExportDPI); //pxy->ToPdf(&GetDC(), *(ar.GetFile())); //xy.ToPdf(&GetDC(), *(ar.GetFile())); break; case DF_FORMAT_UMAP_ASC: //pxy->ToUmap(&GetDC(), *(ar.GetFile())); //xy.ToUmap(&GetDC(), *(ar.GetFile())); break; case DF_FORMAT_MAPGIS_W: //pxy->ToMapGisAsc(&GetDC(), *(ar.GetFile()), FALSE); //xy.ToMapGisAsc(&GetDC(), *(ar.GetFile()), FALSE); break; case DF_FORMAT_KML: //pxy->ToKML(*(ar.GetFile())); //xy.ToKML(*(ar.GetFile())); break; case DF_FORMAT_GEOMAP: //pxy->ToGeoMap(&GetDC(), *(ar.GetFile())); //xy.ToGeoMap(&GetDC(), *(ar.GetFile())); break; } return TRUE; } // 将图形数据插入到最下层 extern "C" __declspec(dllexport) bool XyInsertDataBottom(CXy* pXy, BYTE* data, int dataLen, LPCTSTR newLayer) { CXy* pxyMerge = new CXy; bool bOpen = pxyMerge->ReadMemory(data, dataLen, 1); if (bOpen == false) { delete pxyMerge; return FALSE; } // 全部装入一个新图层 if (strlen(newLayer) != 0) { CString strNamePre = newLayer; strNamePre += "\\"; CClassList* pClassList = pxyMerge->GetClassList(); for (POSITION posClass = pClassList->GetHeadPosition(); posClass != nullptr; pClassList->GetNext(posClass)) { CLayerList* pLayerList = pClassList->GetAt(posClass); for (POSITION posLayer = pLayerList->GetHeadPosition(); posLayer != nullptr; pLayerList->GetNext(posLayer)) { CLayer* pLayer = pLayerList->GetAt(posLayer); CString strNameOld = pLayer->GetName(); CString strNewName = strNamePre + strNameOld; pLayer->SetName(strNewName); } } } if (!pxyMerge->GetProjection().IsEmpty() && !pXy->GetProjection().IsEmpty()) pxyMerge->ChangeToProjection(pXy->GetProjection()); CPositionList select; pXy->MoveInBottom(pxyMerge, select); delete pxyMerge; return TRUE; } extern "C" __declspec(dllexport) bool XyInsertFileAfter(CXy* pXy, LPCTSTR mergeFile, POSITION pos) { CXy* pxyMerge = new CXy; //pxyMerge->m_bRealTimeDraw = FALSE; bool bOpen = XyOpenFile(pxyMerge, mergeFile, FALSE); if (bOpen == false) { delete pxyMerge; return FALSE; } if (!pxyMerge->GetProjection().IsEmpty() && !pXy->GetProjection().IsEmpty()) pxyMerge->ChangeToProjection(pXy->GetProjection()); CPositionList select; pXy->MoveIn(pxyMerge, select, pos, 0, 0, true, true); delete pxyMerge; return TRUE; } ///合并另一个文件 extern "C" __declspec(dllexport) bool XyMerge(CXy* pXy, LPCTSTR mergeFile) { return XyInsertFileAfter(pXy, mergeFile, 0); //CString name, strExt; //CSplitPath sp(mergeFile); //strExt = sp.GetExtension(); //strExt.MakeLower(); // //CXy* pxyMerge = new CXy; ////pxyMerge->m_bRealTimeDraw = FALSE; //bool bOpen = XyOpenFile(pxyMerge, mergeFile, FALSE); //if (bOpen == false) { // delete mergeFile; // return FALSE; //} //if (!pxyMerge->GetProjection().IsEmpty() && !pXy->GetProjection().IsEmpty()) // pxyMerge->ChangeToProjection(pXy->GetProjection()); //CPositionList select; //pXy->MoveIn(pxyMerge, select, 0, 0, 0, true, true); //delete pxyMerge; //return TRUE; } extern "C" __declspec(dllexport) bool XySaveAs(CXy* pxy, LPCTSTR saveFile,int version=-1) { CString newName = saveFile; if (newName.IsEmpty()) { return false; } int docTypeID = 0; CString ext = AfxGetPublicFunction()->GetSplitPath(newName, "ext"); if (ext.MakeLower() == _T(".xyz")) { docTypeID = NFormatType::DF_FORMAT_XYZ; } else { CDocType DocType; docTypeID = DocType.GetIndexFromExt(AfxGetPublicFunction()->GetSplitPath(newName, "ext")); docTypeID = DocType.GetIDFromIndex(docTypeID); } CFile file; CFileException fileException; if (file.Open(newName, CFile::modeCreate | CFile::modeWrite, &fileException)) { if (version < 0) { version = pxy->m_version; } CArchive ar(&file, CArchive::store); XySerialize(pxy, ar, docTypeID, version); ar.Close(); file.Close(); PostProcessFile(newName); return TRUE; } return FALSE; } extern "C" __declspec(dllexport) bool XyFindPointByName(CXy* pxy, LPCTSTR eleName, BYTE*& buffElement, int& buffLen) { CString strNameFind(eleName); CPositionList posList; POSITION posCur = pxy->GetValueList()->GetHeadPosition(); CString name; COne* pOne; while (true) { pxy->GetValueList()->GetNext(posCur); if (posCur == 0) { break; } pOne = pxy->GetAt(posCur); if (pOne->GetType() == DOUBLEFOX_POINT) { // if(pOne->IsCanEdit()) CPointNameEx* pPoint = (CPointNameEx*)pOne->GetValue(); if (pPoint->GetName() == strNameFind) { posList.AddTail(posCur); } } } if (posList.GetCount() == 0) { buffLen = 0; return false; } return pxy->WriteMemory(buffElement, buffLen, posList, 3, 0); } extern "C" __declspec(dllexport) bool XyFindPointByInfo(CXy* pxy, POSITION& posFind , LPCTSTR elementName, double x, double y, LPCTSTR layerName) { posFind = 0; if (pxy == 0) { return FALSE; } CString strLayerFind(layerName); POSITION posCur = pxy->GetValueList()->GetHeadPosition(); COne* pOne; CString name; CString strlayer; while (true) { pxy->GetValueList()->GetNext(posCur); if (posCur == 0) { break; } pOne = pxy->GetAt(posCur); name = pOne->GetName(); if (elementName != name) { continue; } strlayer = pOne->GetLayer()->GetName(); if (strLayerFind.GetLength() > 0 && strLayerFind != strlayer) { continue; } int eleType = pOne->GetType(); if (eleType == DOUBLEFOX_POINT || eleType == DOUBLEFOX_XYZ) { CPointNameEx* pPoint = (CPointNameEx*)pOne->GetValue(); if (abs(pPoint->x0 - x) > 1E-10 || abs(pPoint->y0 - y) > 1E-10) { continue; } } else if (eleType == DOUBLEFOX_TEXT) { CText* pPoint = (CText*)pOne->GetValue(); if (abs(pPoint->x0 - x) > 1E10 && abs(pPoint->y0 - y) > 1E10) { continue; } } posFind = posCur; break; } if (posFind > 0) { return true; } return false; } extern "C" __declspec(dllexport) BOOL XyGetElementByPosition(CXy* pxy, BYTE*& buffElement, int& buffLen, POSITION elementPtr) { if (pxy == 0) return FALSE; COne* pOne = (COne*)(pxy->GetAt(elementPtr)); if (pOne == 0) return FALSE; if (pOne->GetType() == DOUBLEFOX_MESH) { ((CMesh*)(pOne->value))->WriteElementDML(buffElement, buffLen); return TRUE; } else if (pOne->GetType() == DOUBLEFOX_TEXT) { ((CText*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else if (pOne->GetType() == DOUBLEFOX_ELLIPSE) { ((CEllipse*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else if (pOne->GetType() == DOUBLEFOX_CIRCLE) { ((CCircle*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else if (pOne->GetType() == DOUBLEFOX_ARC) { ((CArc*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else if (pOne->GetType() == DOUBLEFOX_SCALERULER) { ((CScaleRuler*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else if (pOne->GetType() == DOUBLEFOX_PROPORTION) { ((CProportion*)(pOne->value))->color = pOne->color; return pOne->WriteMemory(buffElement, 0, buffLen, 3); } else { return pOne->WriteMemory(buffElement, 0, buffLen, 3); } } extern "C" __declspec(dllexport) BOOL XySetElement(CXy* pxy, BYTE* buffElement, int buffLen, POSITION elementPtr) { BOOL bEdited = FALSE; POSITION pos; pos = (POSITION)elementPtr; COne* pOne = (COne*)(pxy->GetAt(pos)); if (pOne->GetType() == DOUBLEFOX_SECTION) { ((CSection*)(pOne->value))->ReadElementDML(buffElement, -1, buffLen); bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_MESH) { CMesh* pMesh = (CMesh*)(pOne->value); pMesh->m_bRealTimeDraw = false; pMesh->ReadElementDML(buffElement, -1, buffLen); pMesh->SetM(pMesh->m_pRuler->zmin, pMesh->m_pRuler->zmax); pMesh->GetBitmap(); bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_TEXT) { pOne->ReadMemory(buffElement, -1, buffLen, 3); CText* pText = (CText*)(pOne->value); pText->color = pOne->color; bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_ELLIPSE) { pOne->ReadMemory(buffElement, 0, buffLen, 3); ((CEllipse*)(pOne->value))->color = pOne->color; bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_CIRCLE) { pOne->ReadMemory(buffElement, 0, buffLen, 3); ((CCircle*)(pOne->value))->color = pOne->color; bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_ARC) { pOne->ReadMemory(buffElement, 0, buffLen, 3); ((CArc*)(pOne->value))->color = pOne->color; TRACE(_T("CArc Width:"), ((CArc*)(pOne->value))->m_dCurveWidth); bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_PROPORTION) { pOne->ReadMemory(buffElement, 0, buffLen, 3); ((CProportion*)(pOne->value))->color = pOne->color; bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_SCALERULER) { pOne->ReadMemory(buffElement, 0, buffLen, 3); ((CScaleRuler*)(pOne->value))->color = pOne->color; bEdited = true; } else if (pOne->GetType() == DOUBLEFOX_CURVE) { CHowToViewCurve* pHWCOld = pOne->HowToViewCurve; if (pHWCOld != NULL) { pHWCOld->Empty(); } pOne->ReadMemory(buffElement, 0, buffLen, 3); bEdited = true; } else { if (pOne->HowToViewCurve != NULL) { pOne->HowToViewCurve->Empty(); } pOne->ReadMemory(buffElement, -1, buffLen, 3); bEdited = true; } return bEdited; } extern "C" __declspec(dllexport) int XyDeleteLayerElement(CXy* pxy, LPCTSTR layerName, BOOL childNode) { CList select; if (childNode) { pxy->GetElement(layerName, select, TRUE); } else { pxy->GetElement(layerName, select, FALSE); } if (select.IsEmpty()) { return 0; } POSITION pos = select.GetHeadPosition(); POSITION pt; while (pos) { pt = select.GetNext(pos); pxy->RemoveAt(pt); } return select.GetCount(); } /** * 添加图层 * * \param pXy 图件对象 * \param layerName 图层名 * \return 成功、失败,如果相同层名已经存在,将不会创建新的图层,并返回成功 */ extern "C" __declspec(dllexport) bool XyAddLayer(CXy* pXy, LPCTSTR layerName) { return pXy->FindAddLayer(layerName) != nullptr; } /** * 统计边框数量 * * \param pXy 图件对象 */ extern "C" __declspec(dllexport) int XyBorderCount(CXy* pXy) { CPositionList select; return pXy->GetElement(DOUBLEFOX_GRID, select); } /** * 获取图元范围 * * \param pXy 图件 * \param pos 图元的 position * \param left * \param top * \param right * \param bottom * \return 成功,失败 */ extern "C" __declspec(dllexport) bool XyGetRange(CXy* pXy, POSITION pos, double* left, double* top, double* right, double* bottom) { if (pXy == nullptr || pos == nullptr) { return false; } COne* pOne = pXy->GetAt(pos); if (pOne == nullptr) { return false; } CRect8 range = pOne->GetRect(); *left = range.left; *right = range.right; *top = range.top; *bottom = range.bottom; return true; } extern "C" __declspec(dllexport) bool XyGetElementsRange(CXy* pXy, POSITION* posArray, int elementCount, double* minX, double* minY, double* maxX, double* maxY) { CRect8 range(1e100, -1e100, -1e100, 1e100); for (int i = 0; i < elementCount; i++) { COne* pOne = pXy->GetAt(posArray[i]); pOne->GetRange(range); } *minX = range.left; *minY = range.bottom; *maxX = range.right; *maxY = range.top; return true; } /** * 给图件添加默认边框 * * \param pXy 图件对象 */ extern "C" __declspec(dllexport) void XyCreateDefaultBorder(CXy* pXy) { CLayer* pLayer = pXy->FindAddLayer("坐标框"); double nan = std::numeric_limits::quiet_NaN(); double minX = nan; double minY = nan; double maxX = nan; double maxY = nan; CPtrList* value = pXy->GetValueList(); for (POSITION pos = value->GetHeadPosition(); pos != nullptr; value->GetNext(pos)) { COne* pOne = (COne*)value->GetAt(pos); if (!pOne->GetLayer()->IsViewAndEdit()) { continue; } CRect8 range = pOne->GetRect(); if (std::isnan(minX)) { minX = range.left; maxX = range.right; minY = range.bottom; maxY = range.top; } if (range.left < minX) { minX = range.left; } if (range.right > maxX) { maxX = range.right; } if (range.top > maxY) { maxY = range.top; } if (range.bottom < minY) { minY = range.bottom; } } TRACE("minX = %lf, maxX = %lf, minY = %lf, maxY = %lf\n", minX, maxX, minY, maxY); CGridding* pGrid = new CGridding; pGrid->m_step.SetSize(1000, 10); //自动根据单位设置文字大小 //step=GetDoc()->GetCurrentUnitScale(); pGrid->ScaleProperty(1000, 1000); pGrid->SetRect(minX, minY, maxX, maxY); pGrid->SetProjection(&(pXy->m_ExchangeXYZ)); pGrid->SetDisplayMode(CNet::showNull); POSITION pos = pXy->AddElement(pGrid, DOUBLEFOX_GRID); //pXy->SetElementColor(pos, color); COne* pOne = pXy->GetAt(pos); pOne->SetLayer(pLayer); } /** * 根据条件筛选获取图元 * * \param pXy * \param filter 筛选条件 * \return 以 "," 分割的 position 字符串 */ extern "C" __declspec(dllexport) BSTR XyGetElementByFilter(CXy* pXy, string filter) { return CString("").AllocSysString(); } /** * 修改网格 z 有效范围 * \param pXy * \param minZValue 范围最小 z 值 * \param maxZValue 范围最大 z 值 * \param mode 1 无效化,2 抹平 */ extern "C" __declspec(dllexport) void XyMapMeshValueRange(CXy* pXy, double minZValue, double maxZValue, int mode) { if (pXy == nullptr) { return; } // 将网格 z 值小于 0 的设置为 0 POSITION meshPos = pXy->FindFirstElement(DOUBLEFOX_MESH); if (meshPos == nullptr) { return; } COne* pOne = pXy->GetAt(meshPos); CMesh* pMesh = (CMesh*)(pOne->GetValue()); pMesh->SetM(minZValue, maxZValue); CDimension3D* pDfg = pMesh->GetDfg(); long numx = 0; long numy = 0; pMesh->GetNumber(numx, numy); int nIndexZ = 0; if (pMesh->GetMeshType() == MESH_FXY && pDfg->n >= 3) { nIndexZ = pMesh->m_nFxyIndexZ; } const double invalidZ = -1E300; #pragma omp parallel for for (long x = 0; x < numx; x++) { for (long y = 0; y < numy; y++) { double z = pDfg->Value(x, y, nIndexZ); if (IsUnvalidValue(z)) { continue; } if (OutOfRange(z, minZValue, maxZValue)) { if (mode == 1) // 无效性 { pDfg->SetValue(x, y, invalidZ); } else { pDfg->SetValue(x, y, Flatten(z, minZValue, maxZValue)); } } } } } /** * 过滤网格和等值线,将等值线 z 值超出范围的剔除 * \param pXy * \param outputName 输出的文件名 * \param layerName 等值线所在的图层名,(会包含子层) * \param minValue 等值线最小 z 值 * \param maxValue 等值线最大 z 值 */ extern "C" __declspec(dllexport) void XyFilterContourLines(CXy* pXy, wchar_t* layerName, double minZValue, double maxZValue) { if (pXy == nullptr) { return; } // 将 z 轴小于 minValue 或 小于 maxValue 的等值线剔除掉 NBase::CPositionList selected; std::vector needRemoveCones; CXyElementFilter filter; filter.addLayer(CString(layerName), true) .addType(DOUBLEFOX_CURVE); pXy->GetElement(filter, selected); for (POSITION pos = selected.GetHeadPosition(); pos != nullptr; selected.GetNext(pos)) { POSITION pt = selected.GetAt(pos); COne* pOne = pXy->GetAt(pt); CCurveEx* pCurve = (CCurveEx*)pOne->GetValue(); if (pCurve->name == nullptr) { continue; } try { double z = std::stod(pCurve->name); // 对于等值线来说,它的名字就是 z 值 if (z < minZValue || z > maxZValue) { needRemoveCones.push_back(pOne); } } catch (std::invalid_argument&) { // FIXME: 如果它的名字不是数字,暂不处理 } } for (COne* pOne : needRemoveCones) { pXy->RemoveAt(pOne); } } /** * 获取图件存储的当前显示范围,暂时不提供设置的接口,即使设置了它,用户在画布上操作之后再保存,这个会重新获取 * * \param pXy * \param left * \param top * \param right * \param bottom */ extern "C" __declspec(dllexport) void XyGetDisplay(CXy* pXy, double& left, double& top, double& right, double& bottom) { left = pXy->m_display.left; top = pXy->m_display.top; right = pXy->m_display.right; bottom = pXy->m_display.bottom; } /** * 获取版本号 * * \param pXy * \return 版本号 */ short XyGetVersion(CXy* pXy) { return pXy->m_version; } static TiXmlElement* CreateSimpleElement(const std::string_view& key, double value) { TiXmlElement* childElement = new TiXmlElement(key.data()); std::string str = std::to_string(value); childElement->LinkEndChild(new TiXmlText(str.data())); return childElement; } static TiXmlElement* CreateSimpleElement(const std::string_view& key, const std::string_view& value) { TiXmlElement* childElement = new TiXmlElement(key.data()); childElement->LinkEndChild(new TiXmlText(value.data())); return childElement; } struct MeshMetadata { int rows = 0; int columns = 0; double minX = 0.0f; double maxX = 0.0f; double minY = 0.0f; double maxY = 0.0f; double dx = 0.0f; double dy = 0.0f; double minZ = 0.0f; double maxZ = 0.0f; }; struct MeshPoint { double x = 0.0f; double y = 0.0f; double z = 0.0f; }; static TiXmlElement* MetadataToXml(const MeshMetadata& metadata) { TiXmlElement* metadataElement = new TiXmlElement("Metadata"); metadataElement->LinkEndChild(CreateSimpleElement("Rows", metadata.rows)); metadataElement->LinkEndChild(CreateSimpleElement("Columns", metadata.columns)); metadataElement->LinkEndChild(CreateSimpleElement("MinX", metadata.minX)); metadataElement->LinkEndChild(CreateSimpleElement("MaxX", metadata.maxX)); metadataElement->LinkEndChild(CreateSimpleElement("MinY", metadata.minY)); metadataElement->LinkEndChild(CreateSimpleElement("MaxY", metadata.maxY)); metadataElement->LinkEndChild(CreateSimpleElement("DX", metadata.dx)); metadataElement->LinkEndChild(CreateSimpleElement("DY", metadata.dy)); return metadataElement; } static std::string GridToXml(const MeshMetadata& metadata, const std::vector>& dataGrid) { TiXmlDocument doc; TiXmlElement* rootElement = new TiXmlElement("Grid"); doc.LinkEndChild(rootElement); // 创建子元素 TiXmlElement* metadataElement = MetadataToXml(metadata); rootElement->LinkEndChild(metadataElement); // 创建坐标元素 TiXmlElement* coordinatesElement = new TiXmlElement("Coordinates"); rootElement->LinkEndChild(coordinatesElement); std::vector> dataElementGrid(metadata.rows, std::vector(metadata.columns)); #pragma omp parallel for for (int i = 0; i < metadata.rows; i++) { for (int j = 0; j < metadata.columns; j++) { TiXmlElement* dataElement = new TiXmlElement("Data"); dataElement->SetAttribute("Row", i); dataElement->SetAttribute("Col", j); const auto& point = dataGrid[i][j]; dataElement->SetAttribute("X", point.x); dataElement->SetAttribute("Y", point.y); std::string value = std::to_string(point.z); dataElement->LinkEndChild(new TiXmlText(value.c_str())); dataElementGrid[i][j] = dataElement; } } for (int i = 0; i < metadata.rows; i++) { for (int j = 0; j < metadata.columns; j++) { coordinatesElement->LinkEndChild(dataElementGrid[i][j]); } } TiXmlPrinter printer; doc.Accept(&printer); std::string result = printer.CStr(); return result; } static CMesh* GetMesh(CXy* pXy) { if (pXy == nullptr) { return nullptr; } CPositionList select; int nCount = pXy->GetElement(DOUBLEFOX_MESH, select); if (nCount <= 0) { return nullptr; } return (CMesh*)pXy->GetAtValue(select.GetHead()); } /** * 根据坐标获取 z 值 * \param pXy * \param x x坐标 * \param y y坐标 * \param z 出参,z 值 * \param size x y z 两个数组的长度,这两个数组长度必须一致 */ extern "C" __declspec(dllexport) bool XyGetMeshZValue(CXy* pXy, double* x, double* y, double* z, int size) { CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return false; } #pragma omp parallel for for (int i = 0; i < size; i++) { z[i] = pMesh->GetValue(x[i], y[i]); } return true; } /// /// 失败时返回的数据,由于是传递的引用过来,所以要用这个设置一下,防止 C# 那边写入脏数据 /// /// 网格元数据 /// x 数组指针 /// y 数组指针 /// z 数组指针 static void SetMetadataToDefault(MeshMetadata& metadata, double** x, double** y, double** z) { metadata.rows = 0; metadata.columns = 0; *x = nullptr; *y = nullptr; *z = nullptr; } /** * 设置网格元数据 * * \param metadata * \param pDfg */ static void SetMeshMetadata(MeshMetadata& metadata, CDimension2D* pDfg) { metadata.rows = pDfg->num[0]; metadata.columns = pDfg->num[1]; metadata.dx = pDfg->delt[0]; metadata.dy = pDfg->delt[1]; metadata.minX = pDfg->xmin(); metadata.maxX = pDfg->xmax(); metadata.minY = pDfg->ymin(); metadata.maxY = pDfg->ymax(); metadata.minZ = pDfg->range[0]; metadata.maxZ = pDfg->range[1]; } /** * 获取网格数据 * \param pXy * \return 网格数据的 xml 格式 */ extern "C" __declspec(dllexport) bool XyGetMesh(CXy* pXy, MeshMetadata& metadata, double** x, double** y, double** z) { CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { SetMetadataToDefault(metadata, x, y, z); return false; } CDimension2D* pDfg = (CDimension3D*)(pMesh->GetMesh()); SetMeshMetadata(metadata, pDfg); if (metadata.rows <= 0 || metadata.columns <= 0) { SetMetadataToDefault(metadata, x, y, z); return false; } *x = new double[metadata.rows]; *y = new double[metadata.columns]; *z = new double[metadata.rows * metadata.columns]; for (int i = 0; i < metadata.rows; i++) { (*x)[i] = pDfg->x(i); } for (int i = 0; i < metadata.columns; i++) { (*y)[i] = pDfg->y(i); } #pragma omp parallel for for (int i = 0; i < metadata.rows; i++) { for (int j = 0; j < metadata.columns; j++) { int index = i * metadata.columns + j; (*z)[index] = pDfg->Value(i, j); } } return true; } static std::unique_ptr CreateMesh(const MeshMetadata& metadata, const double* x, const double* y, const double* z) { auto pMesh = std::make_unique(); auto pDfg = std::make_unique(); int numx = metadata.rows; int numy = metadata.columns; double dx = metadata.dx; double dy = metadata.dy; double xmin = metadata.minX; double ymin = metadata.minY; double zmin = metadata.minZ; double zmax = metadata.maxZ; pDfg->Create(numx, numy, xmin, ymin, dx, dy); pDfg->range[0] = zmin; pDfg->range[1] = zmax; for (int i = 0; i < numx; i++) { for (int j = 0; j < numy; j++) { pDfg->SetValue(i, j, z[i * numy + j]); } } pMesh->SetMesh(pDfg.release(), MESH_DFG, FALSE); pMesh->EnableUpdateRuler(TRUE); pMesh->UpdateColorRuler(); return pMesh; } static void AddContourCurve(CXy* pXy, vector* curves, vector* layer) { for (size_t i = 0; i < curves->size(); i++) { CCurve* pCurve = curves->at(i); if (pCurve == NULL) continue; CCurveEx *ce = new CCurveEx(pCurve->num); for (int i = 0; i < ce->num; i++) { ce->x[i] = pCurve->x[i]; ce->y[i] = pCurve->y[i]; ce->z[i] = pCurve->z[i]; } ce->nPoint = pCurve->nPoint; ce->GetLocation(); POSITION pos = NULL; if (pCurve->name) ce->SetName(pCurve->name); pos = pXy->AddElement(ce, DOUBLEFOX_CURVE); CString* pName = layer->at(i); pXy->SetElementLayer(pos, *pName); } } template void DeleteVectorData(std::vector &vec) { for (auto* p : vec) { delete p; } vec.clear(); } /// /// 曲线平滑 /// extern "C" __declspec(dllexport) void XyMeshSmooth(CXy* pXy, POSITION posMesh, double smoothFactor, int smoothTimes = 2) { if (smoothFactor < 1e-10) { return; } CMesh* pMeshNew = (CMesh*)(pXy->GetAt(posMesh)->value); CGrid* pGrid = pMeshNew->GetMesh(); int numx = pGrid->xnum(); int numy = pGrid->ynum(); double dZMin = pGrid->range[0] - 0.001; double dZMax = pGrid->range[1] + 0.001; for (int i = 1; i < numx - 1; i++) { double dSigma = 0; double dPtX = 0, dPtY = 0, dOtherX = 0, dOtherY = 0; for (int j = 1; j < numy - 1; j++) { double dValueCur = pGrid->Value(i, j); if (dValueCur< dZMin || dValueCur>dZMax) { continue; } //dPtX = ConvertX2Int(pGrid->x(i), ptOO); //dPtY = ConvertY2Int(pGrid->y(j), ptOO); dSigma = 0; int nCount = 0; double dValueTmp = pGrid->Value(i - 1, j - 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i - 1), ptOO), ConvertY2Int(pGrid->y(j - 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i, j - 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i), ptOO), ConvertY2Int(pGrid->y(j - 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i + 1, j - 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i + 1), ptOO), ConvertY2Int(pGrid->y(j - 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i - 1, j); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i - 1), ptOO), ConvertY2Int(pGrid->y(j), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i + 1, j); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i + 1), ptOO), ConvertY2Int(pGrid->y(j), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i - 1, j + 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i - 1), ptOO), ConvertY2Int(pGrid->y(j + 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i, j + 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i), ptOO), ConvertY2Int(pGrid->y(j + 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } dValueTmp = pGrid->Value(i + 1, j + 1); if (dValueTmp >= dZMin && dValueTmp <= dZMax) { //if (!intersectHelp->Intersects(LineSegment(Point64(dPtX, dPtY) // , Point64(ConvertX2Int(pGrid->x(i + 1), ptOO), ConvertY2Int(pGrid->y(j + 1), ptOO))))) //{ dSigma += dValueTmp; nCount++; //} } if (nCount == 0) { return; } double dAverage = dSigma / nCount; double dValueNew = (dValueCur + dAverage * smoothFactor) / (1.0 + smoothFactor); pGrid->SetValue(i, j, dValueNew); //TRACE("i:%d, j:%d, %lf\r\n", i, j, dValueNew); } } } extern "C" __declspec(dllexport) void XyCreateContour(CXy* pXy, POSITION posMesh, double contourStep, int contourMarkStep) { CMesh* pMeshNew = (CMesh*)(pXy->GetAt(posMesh)->value); CString strLayerMark = _T("Layer:\\等值线\\标注"); CString strLayerOther = _T("Layer:\\等值线\\无标注"); CString curLayerName = pXy->GetCurrentLayer()->GetPathName(); CLayer* pMarkLayer = pXy->FindLayer(strLayerMark); CLayer* pOtherLayer = pXy->FindLayer(strLayerOther); if (pMarkLayer == nullptr) { pMarkLayer = pXy->FindAddLayer(strLayerMark); pMarkLayer->HowToViewCurve = new CHowToViewCurve(); pMarkLayer->HowToViewCurve->EnableDrawSourceCurve(FALSE); CCurveInName* pInName = new CCurveInName(); CRect8 rect = pMeshNew->GetRect(); pInName->text_h = rect.Width() / 300; pInName->m_size.cx = pInName->text_h*0.06; pInName->color = RGB(0, 0, 0); pMarkLayer->HowToViewCurve->Add(pInName); } if (pOtherLayer == nullptr) { pOtherLayer = pXy->FindAddLayer(strLayerOther); pOtherLayer->HowToViewCurve = new CHowToViewCurve(); pOtherLayer->HowToViewCurve->EnableDrawSourceCurve(FALSE); CCurveProperties* pview = new CCurveProperties(); pview->color = RGB(0, 0, 0); pOtherLayer->HowToViewCurve->Add(pview); } std::vector pCurves; std::vector pLayers; CGrid* pDfg = pMeshNew->GetMesh(); pMeshNew->ContourCreate(&pCurves, &pLayers, contourStep, contourMarkStep, strLayerMark, strLayerOther, pDfg->range[0], pDfg->range[1]); AddContourCurve(pXy, &pCurves, &pLayers); DeleteVectorData(pCurves); DeleteVectorData(pLayers); } extern "C" __declspec(dllexport) POSITION XyCreateMesh(CXy* pXy, LPCTSTR layerName, const float* values, double xMin, double yMin, int xCount, int yCount, double stepX, double stepY, double zMin, double zMax) { auto *pDfg = new CDimension2D(); pDfg->Create(xCount, yCount, xMin, yMin, stepX, stepY); for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { pDfg->SetValue(i, j, values[yCount*i + j]); } } pDfg->range[0] = zMin; pDfg->range[1] = zMax; // 添加网格 CMesh* pMeshNew = new CMesh(); // 网格类 CLayer* pLayer = pXy->FindAddLayer("背景"); POSITION posNew = pXy->AddElement(pMeshNew, DOUBLEFOX_MESH); pXy->SetElementLayer(posNew, pLayer); pMeshNew->SetMesh(pDfg, MESH_DFG, FALSE); //pMeshNew->GetMesh(); //// 生成等值线 //CreateContourLines(pXy, pMeshNew, pDfg, contourStep, contourMarkStep); pMeshNew->EnableUpdateRuler(TRUE); pMeshNew->UpdateColorRuler(); return posNew; } /** * 通过数据添加网格 * * \param pXy 图件 * \param layerName 要添加到的目标图层名称 * \param metadata 网格元数据 * \param x x 坐标集合 * \param y y 坐标集合 * \param z 所有点的 z 值 * \return 成功返回 true,失败返回 false */ extern "C" __declspec(dllexport) bool XyAddMesh(CXy* pXy, const LPCTSTR layerName, const MeshMetadata* metadata, const double* x, const double* y, const double* z) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return false; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr\n"); return false; } if (metadata == nullptr) { TRACE("metadata 不能为 nullptr\n"); return false; } auto pMesh = CreateMesh(*metadata, x, y, z); CLayer* pLayer = pXy->FindAddLayer(layerName); auto pOne = std::make_unique(); pOne->SetLayer(pLayer); pOne->SetValueSafe(pMesh.release()); pXy->AddTailOne(pOne.release()); //pXy->SaveAsWithExtension("E:\\output.dfd"); return true; } extern "C" __declspec(dllexport) bool XyGetMeshInfo(CXy* pXy, BYTE*& buffElement, int& buffLen) { CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return false; } pMesh->WriteElementDML(buffElement, buffLen); return true; } extern "C" __declspec(dllexport) bool XySetMeshInfo(CXy* pXy, LPCTSTR infoData) { CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return false; } pMesh->m_bRealTimeDraw = false; CString strInforData(infoData); CMemFile memFile((BYTE*)strInforData.GetString(), strInforData.GetLength()); pMesh->ReadElementDML(memFile, -1); pMesh->SetM(pMesh->m_pRuler->zmin, pMesh->m_pRuler->zmax); //pMesh->GetBitmap(); return true; } extern "C" __declspec(dllexport) bool XyGetMeshData(CXy* pXy, double& xMin, double& yMin, int& xNum, int& yNum, double& xStep, double& yStep, double*& pValue, double &zMin, double& zMax) { CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return false; } CDimension2D* pDfg = (CDimension3D*)(pMesh->GetMesh()); xNum = pDfg->num[0]; yNum = pDfg->num[1]; xStep = pDfg->delt[0]; yStep = pDfg->delt[1]; xMin = pDfg->xmin(); yMin = pDfg->ymin(); pValue = pDfg->u; zMin = pDfg->range[0]; zMax = pDfg->range[1]; return true; } /** * 图层元素置顶 (让它的图元显示在最上层),由于默认排序规则是后加入的元素显示在上面,所以我们将这些元素放到末尾即可 * * \param pXy CXy 指针 * \param layer 图层名 * \param bWithSubLayer 是否连带子层图元一起置顶 * */ extern "C" __declspec(dllexport) void XyLayerElementOrderTop(CXy* pXy, const wchar_t* layer, bool bWithSubLayer) { assert(pXy != nullptr); CPositionList list; pXy->GetElement(CString(layer), list, bWithSubLayer, true); for (POSITION p = list.GetHeadPosition(); p != nullptr; list.GetNext(p)) { POSITION pos = list.GetAt(p); if (pos != nullptr) { pos = pXy->MoveToFront(pos); // 直接将结果赋给pos if (pos != nullptr) { list.SetAt(p, pos); } } } } /** * 图层元素置底 (让它的图元显示在最下层) * * \param pXy CXy 指针 * \param layer 图层名 * \param bWithSubLayer 是否连带子层图元一起置顶 * */ extern "C" __declspec(dllexport) void XyLayerElementOrderBottom(CXy* pXy, const wchar_t* layer, bool bWithSubLayer) { assert(pXy != nullptr); CPositionList list; pXy->GetElement(CString(layer), list, bWithSubLayer, true); for (POSITION p = list.GetTailPosition(); p != nullptr; list.GetPrev(p)) { POSITION pos = list.GetAt(p); if (pos != nullptr) { pos = pXy->MoveToBack(pos); if (pos != nullptr) { list.SetAt(p, pos); } } } } /** * 图层元素上移一层 * * \param pXy CXy 指针 * \param layer 图层名 * \param bWithSubLayer 是否连带子层图元一起置顶 * */ extern "C" __declspec(dllexport) void XyLayerElementOrderUp(CXy* pXy, const wchar_t* layer, bool bWithSubLayer) { assert(pXy != nullptr); CPositionList list; pXy->GetElement(CString(layer), list, bWithSubLayer, true); for (POSITION p = list.GetTailPosition(); p != nullptr; list.GetPrev(p)) { POSITION pos = list.GetAt(p); if (pos != nullptr) { pos = pXy->MoveForward(pos); if (pos != nullptr) { list.SetAt(p, pos); } } } } /** * 图层元素下移一层 * * \param pXy CXy 指针 * \param layer 图层名 * \param bWithSubLayer 是否连带子层图元一起置顶 * */ extern "C" __declspec(dllexport) void XyLayerElementOrderDown(CXy* pXy, const wchar_t* layer, bool bWithSubLayer) { assert(pXy != nullptr); CPositionList list; pXy->GetElement(CString(layer), list, bWithSubLayer, true); for (POSITION p = list.GetHeadPosition(); p != nullptr; list.GetNext(p)) { POSITION pos = list.GetAt(p); if (pos != nullptr) { pos = pXy->MoveBackward(pos); if (pos != nullptr) { list.SetAt(p, pos); } } } } /** * 列出图层所有 position * * \param pXy * \return */ extern "C" __declspec(dllexport) BSTR XyListAllElements(CXy* pXy) { assert(pXy != nullptr); std::vector positions; CPtrList* pValueList = pXy->GetValueList(); for (POSITION pos = pValueList->GetHeadPosition(); pos != nullptr; pValueList->GetNext(pos)) { CString str; str.Format("%I64d", pos); positions.push_back(str); } return JoinStrings(positions, ",").AllocSysString(); } static std::vector GetAllLayers(const CXy& xy) { CXy& mutXy = const_cast(xy); std::vector result; CClassList* pClassList = mutXy.GetClassList(); for (POSITION classPos = pClassList->GetHeadPosition(); classPos != nullptr; pClassList->GetNext(classPos)) { CLayerList* pLayerList = pClassList->GetAt(classPos); for (POSITION layerPos = pLayerList->GetHeadPosition(); layerPos != nullptr; pLayerList->GetNext((layerPos))) { result.push_back(pLayerList->GetAt(layerPos)); } } return result; } static void CopyHowtoViewCurve(const CLayer* pSourceLayer, CLayer* pTargetLayer) { if (pTargetLayer->HowToViewCurve != nullptr) { delete pTargetLayer->HowToViewCurve; pTargetLayer->HowToViewCurve = nullptr; } if (pSourceLayer->HowToViewCurve != nullptr) { pTargetLayer->HowToViewCurve = new CHowToViewCurve(); *pTargetLayer->HowToViewCurve = *pSourceLayer->HowToViewCurve; } } static void CopyHowtoViewPoint(const CLayer* pSourceLayer, CLayer* pTargetLayer) { if (pTargetLayer->HowToViewPoint != nullptr) { delete pTargetLayer->HowToViewPoint; pTargetLayer->HowToViewPoint = nullptr; } if (pSourceLayer->HowToViewPoint != nullptr) { pTargetLayer->HowToViewPoint = new CHowToViewPoint(); *pTargetLayer->HowToViewPoint = *pSourceLayer->HowToViewPoint; } } static void CopyMarkTo(CXy* pSourceXy, CXy* pTargetXy, const CString& symbolName) { assert(pSourceXy != nullptr); assert(pTargetXy != nullptr); if (symbolName.IsEmpty()) { return; } CMapStringToPtrNoCase* pMarks = pSourceXy->GetMark(); void* pDraw; if (pMarks->Lookup(symbolName, pDraw)) { CXy* pOldSymbol = (CXy*)pDraw; std::unique_ptr pNewSymbol = std::make_unique(); *pNewSymbol = *pOldSymbol; pNewSymbol->m_strName = symbolName; pTargetXy->AddMark(pNewSymbol.release(), true); } } static void CopyHowtoViewMarkTo(CXy* pSourceXy, CHowToViewCurve* pHowToViewCurve, CHowToViewPoint* pHowToViewPoint, CXy* pTargetXy) { if (pHowToViewPoint != nullptr) { CopyMarkTo(pSourceXy, pTargetXy, pHowToViewPoint->MarkName); } if (pHowToViewCurve != nullptr) { for (int i = 0; i < pHowToViewCurve->GetCount(); i++) { CCurveView* pView = pHowToViewCurve->GetAt(i); if (auto* pArrow = dynamic_cast(pView)) { CopyMarkTo(pSourceXy, pTargetXy, pArrow->MarkName); } else if (auto* pScale = dynamic_cast(pView)) { CopyMarkTo(pSourceXy, pTargetXy, pScale->MarkName); } else if (auto* pTwoMark = dynamic_cast(pView)) { CopyMarkTo(pSourceXy, pTargetXy, pTwoMark->MarkName); } else if (auto* pRgn = dynamic_cast(pView)) { CopyMarkTo(pSourceXy, pTargetXy, pRgn->MarkName); } } } } /** * 复制样式到其它图件中 * * \param pXy * \param targetFilePath 目标图件 */ extern "C" __declspec(dllexport) void XyApplyStyleToFile(CXy* pXy, LPCTSTR targetFilePath) { assert(pXy != nullptr); std::unique_ptr targetXy = std::make_unique(); if (!XyOpenFile(targetXy.get(), targetFilePath, false)) { return; } std::vector layers = GetAllLayers(*pXy); for (CLayer* pLayer : layers) { CString pathName = pLayer->GetPathName(); CLayer* pTargetLayer = targetXy->FindLayer(pathName, FALSE); if (pTargetLayer == nullptr) { continue; } CopyHowtoViewCurve(pLayer, pTargetLayer); CopyHowtoViewPoint(pLayer, pTargetLayer); CopyHowtoViewMarkTo(pXy, pLayer->HowToViewCurve, pLayer->HowToViewPoint, targetXy.get()); } targetXy->SaveAsWithExtension(targetFilePath); } static std::vector CollectValidLayerNames(CXy& xy, const std::vector& layerNames) { std::vector validNames; for (const CString& name: layerNames) { CString layerPath = CLayerName(name).GetFullPathNameA(); for (CLayer* pLayer : CollectAllLayers(xy)) { if (pLayer->GetPathName() == layerPath) { validNames.push_back(name); break; } } } return validNames; } std::unique_ptr XyLegendCreate(CXy& xy, double x, double y, double width, int rows, LPCTSTR layerNames) { std::vector validNames = CollectValidLayerNames(xy, SplitString(layerNames, _T(","))); if (validNames.size() == 0) { TRACE("没有合法的图层,无法生成图例\n"); return nullptr; } // 计算列数,向上取整 size_t columns = (validNames.size() + rows - 1) / rows; Legend legend(xy, x, y, width, _T("图例"), static_cast(columns), validNames); std::unique_ptr pBlock = legend.Build(); std::unique_ptr pOne = std::make_unique(); CLayer* pLayer = xy.FindAddLayer(_T("图例")); pOne->SetValueSafe(pBlock.release()); pOne->SetLayer(pLayer); return pOne; } /** * 添加图例 * * \param pXy 要添加图例的图件 * \param x 要添加的图例 x 坐标 * \param y 要添加的图例 y 坐标 * \param width 图例宽度 * \param rows 设置成多少行 * \param layerNames 哪些图层要生成图例 */ extern "C" __declspec(dllexport) void XyLegendAdd(CXy* pXy, double x, double y, double width, int rows, LPCTSTR layerNames) { if (pXy == nullptr) { TRACE("pXy: 图件是空指针\n"); return; } if (rows <= 0) { TRACE("rows: 行数必须大小0\n"); return; } if (layerNames == nullptr) { TRACE("layerNames: 图层名不能是空指针\n"); return; } std::unique_ptr pOne = XyLegendCreate(*pXy, x, y, width, rows, layerNames); if (pOne) { pXy->AddTailOne(pOne.release()); } } /** * * 测量图例空间占用 * * \param pXy 要添加图例的图件 * \param x 要添加的图例 x 坐标 * \param y 要添加的图例 y 坐标 * \param rows 设置成多少行 * \param layerNames 哪些图层要生成图例 */ extern "C" __declspec(dllexport) BSTR XyLegendMeasure(CXy* pXy, double width, int rows, LPCTSTR layerNames) { CString error; error.Format("%lf,%lf", 0.0, 0.0); if (pXy == nullptr) { TRACE("pXy: 图件是空指针\n"); return error.AllocSysString(); } if (rows <= 0) { TRACE("rows: 行数必须大小0\n"); return error.AllocSysString(); } if (layerNames == nullptr) { TRACE("layerNames: 图层名不能是空指针\n"); return error.AllocSysString(); } std::vector validNames = CollectValidLayerNames(*pXy, SplitString(layerNames, _T(","))); if (validNames.size() == 0) { TRACE("没有任何合法图层\n"); return error.AllocSysString(); } // 计算列数,向上取整 size_t columns = (validNames.size() + rows - 1) / rows; Legend legend(*pXy, 0, 0, width, _T("图例"), static_cast(columns), validNames); std::unique_ptr pBlock = legend.Build(); CString str; str.Format("%lf,%lf", legend.GetWidth(), legend.GetHeight()); return str.AllocSysString(); } /** * 给图件添加边框 * * \param pXy 要添加边框的图件 * \param layerName 要将边框添加到的图件名 * \param clip 边框向内收多少 */ extern "C" __declspec(dllexport) void XyBorderAdd(CXy* pXy, LPCTSTR layerName, double clip) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr"); return; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr"); return; } CRect8 range(1e100, -1e100, -1e100, 1e100); pXy->GetRange(range); double left = range.left - clip; double top = range.top + clip; double right = range.right + clip; double bottom = range.bottom - clip; std::unique_ptr pGridding = std::make_unique(); // 设置范围 pGridding->SetRect(left, top, right, bottom); pGridding->m_step.cx = std::trunc(abs(right - left) * (1.0 / 4.0)); // 先把宽高步长固定死为图件内容的 1/4 pGridding->m_step.cy = std::trunc(abs(top - bottom) * (1.0 / 4.0)); pGridding->m_szText.cx = 12; pGridding->m_szText.cy = 30; pGridding->m_nFlags = 29263; pGridding->m_ptBase.x0 = 0.0; pGridding->m_ptBase.y0 = 0.0; pGridding->m_szCoefficient.cx = 1.0; pGridding->m_szCoefficient.cy = 1.0; // 获取外边框 CFrame* pm = pGridding->GetOutFrame(); pm->thickness = 10; pm->m_nFlags = 2309; CLayer* pLayer = pXy->FindAddLayer(CString(layerName)); COne* pOne = new COne(); pOne->SetValueSafe(pGridding.release()); pOne->SetLayer(pLayer); pOne->SetColor(RGB(0, 0, 0)); pXy->AddTailOne(pOne); } /** * 生成 x1, y1 到 x2, y2 的中间点 * * \param x1 第一个点的 x 坐标 * \param y1 第一个点的 y 坐标 * \param x2 第二个点的 x 坐标 * \param y2 第二个点的 y 坐标 * \param step 步长,则一步在这个方向上移动多远距离 * \return */ static std::vector GeneratePoints(double x1, double y1, double x2, double y2, double step) { double distance = CalcDistance(x1, y1, x2, y2); int num_steps = static_cast(distance / step); double xIncrement = (x2 - x1) / distance * step; double yIncrement = (y2 - y1) / distance * step; std::vector result; for (int i = 0; i < num_steps + 1; i++) { double x = x1 + i * xIncrement; double y = y1 + i * yIncrement; result.push_back({ x, y, -1e300 }); } CPoint2D lastPoint = result[result.size() - 1]; if (lastPoint.x0 != x2 || lastPoint.y0 != y2) { result.push_back({ x2, y2, -1e300 }); } return result; } /** * 根据网格为两点的连线生成 z 值 * * \param mesh 背景网格 * \param x1 第一个点 x 坐标 * \param y1 第一个点 y 坐标 * \param x2 第二个点 x 坐标 * \param y2 第二个点 y 坐标 */ static std::unique_ptr CreateCurveFromMesh(const CMesh &mesh, double x1, double y1, double x2, double y2) { CMesh& mutMesh = const_cast(mesh); double dx = 0.0; double dy = 0.0; mutMesh.GetDelt(dx, dy); // 一步走网格横宽最短的长度,我们暂时设置为网格最短的边长 double step = min(dx, dy); CRect8 range(1e300, -1e300, -1e300, 1e300); mutMesh.GetRange(range); std::vector points = GeneratePoints(x1, y1, x2, y2, step); for (CPoint3D& point : points) { if (point.x0 >= range.left && point.x0 <= range.right && point.y0 >= range.bottom && point.y0 <= range.top) { point.z0 = mutMesh.GetValue(point.x0, point.y0); } } auto pCurve = std::make_unique(); pCurve->Create(static_cast(points.size())); pCurve->nPoint = 3; for (size_t i = 0; i < points.size(); i++) { pCurve->x[i] = points[i].x0; pCurve->y[i] = points[i].y0; pCurve->z[i] = points[i].z0; } return pCurve; } /** * 根据网格创建曲线,其实就是填充线段经过网格点 z 值 * * \param xy 图件对象 * \param x1 第一个点 x 坐标 * \param y1 第一个点 y 坐标 * \param x2 第二个点 x 坐标 * \param y2 第二个点 y 坐标 * \return 成功返回生成的曲线,失败返回 nullptr */ std::unique_ptr CreateCurveFromXyMesh(CXy& xy, double x1, double y1, double x2, double y2) { CPositionList select; xy.GetElement(DOUBLEFOX_MESH, select); CRect8 range1(min(x1, x2), max(y1, y2), max(x1, x2), min(y1, y2)); for (POSITION pos = select.GetHeadPosition(); pos != nullptr; select.GetNext(pos)) { POSITION pt = select.GetAt(pos); COne* pOne = xy.GetAt(pt); CMesh* pMesh = pOne->GetValueSafe(); CRect8 range2(1e300, -1e300, -1e300, 1e300); pMesh->GetRange(range2); if (IsIntersecting(range1, range2)) { return CreateCurveFromMesh(*pMesh, x1, y1, x2, y2); } } return nullptr; } /** * 创建曲线,使用网格的 z 值填充曲线的 z 值 * * \param pXy 图件对象指针 * \param layerName 图层名称 * \param x1 第一个点 x 坐标 * \param y1 第一个点 y 坐标 * \param x2 第二个点 x 坐标 * \param y2 第二个点 y 坐标 * \return */ extern "C" __declspec(dllexport) bool XyCreateCurveFillZ(CXy* pXy, LPCTSTR layerName, double x1, double y1, double x2, double y2) { if (pXy == nullptr) { TRACE("pXy 不能为 null\n"); return false; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr\n"); return false; } std::unique_ptr pCurve = CreateCurveFromXyMesh(*pXy, x1, y1, x2, y2); if (!pCurve) { TRACE("未找到空间位置匹配的网格\n"); return false; } CLayer* pLayer = pXy->FindAddLayer(CString(layerName)); auto pOne = std::make_unique(); pOne->SetLayer(pLayer); pOne->SetValueSafe(pCurve.release()); pXy->AddTailOne(pOne.release()); return true; } static bool ExistLayerOrSubLayer(CXy& xy, const CString& layerName) { CString layerPath = CLayerName(layerName).GetFullPathNameA(); CClassList* pClassList = xy.GetClassList(); for (POSITION classListPos = pClassList->GetHeadPosition(); classListPos != nullptr; pClassList->GetNext(classListPos)) { CLayerList* pLayerList = pClassList->GetAt(classListPos); for (POSITION layerPos = pLayerList->GetHeadPosition(); layerPos != nullptr; pLayerList->GetNext(layerPos)) { CLayer* pLayer = pLayerList->GetAt(layerPos); CString currentPath = pLayer->GetPathName(); if (StartsWith(currentPath, layerPath)) { return true; } } } return false; } static void MergeLayerElements(CXy& xy, CLayer& pSourceLayer, CLayer& pTargetLayer) { CPtrList* pValueList = xy.GetValueList(); for (POSITION pos = pValueList->GetHeadPosition(); pos != nullptr; pValueList->GetNext(pos)) { COne* pOne = reinterpret_cast(pValueList->GetAt(pos)); if (pOne != nullptr && pOne->GetLayer() == &pSourceLayer) { pOne->SetLayer(&pTargetLayer); } } } // 判断是否为子图层 (如果是同一图层也返回 true) static bool IsSubLayerOf(const CString& layerPath, const CString& parentPath) { return StartsWith(layerPath, parentPath) && (layerPath.GetLength() == parentPath.GetLength() || layerPath[parentPath.GetLength()] == _T('\\')); } /** * 将图层移动到目标图层之下 * * \param pXy 图件对象 * \param currentLayer 当前图层名 * \param targetLayer 目标图层名 * \return */ extern "C" __declspec(dllexport) bool XyMoveLayerUnderTargetLayer(CXy* pXy, LPCTSTR layer , LPCTSTR parentLayer) { if (pXy == nullptr || layer == nullptr || parentLayer == nullptr) { TRACE("pXy layer parentLayer 都不能为 nullptr\n"); return false; } // 情况1、被移动的图层及子图层都不存在 if (!ExistLayerOrSubLayer(*pXy, layer)) { TRACE("要移动的图层 %s 不存在\n", layer); return false; } // 情况2、要移动到的目标层及子层都不存在 if (!ExistLayerOrSubLayer(*pXy, parentLayer)) { TRACE("要移动到的图层 %s 不存在\n", parentLayer); return false; } CString sourceFullPath = CLayerName(layer).GetFullPathNameA(); CString parentFullPath = CLayerName(parentLayer).GetFullPathNameA(); int pos = CString(_T("Layer:")).GetLength(); std::vector layersToRemove; CClassList* pClassList = pXy->GetClassList(); for (POSITION classListPos = pClassList->GetHeadPosition(); classListPos != nullptr; pClassList->GetNext(classListPos)) { CLayerList* pLayerList = pClassList->GetAt(classListPos); for (POSITION layerPos = pLayerList->GetHeadPosition(); layerPos != nullptr; pLayerList->GetNext(layerPos)) { CLayer* pLayer = pLayerList->GetAt(layerPos); CString layerPath = pLayer->GetPathName(); if (IsSubLayerOf(layerPath, sourceFullPath)) { CString newLayerPath = parentFullPath + _T("\\") + CLayerName(layerPath).GetPathName(); CLayer* pFindLayer = pXy->FindLayer(newLayerPath); if (pFindLayer == nullptr) // 情况3、如果新的图层不存在,直接将当前图层改名 { pLayer->SetName(CLayerName(newLayerPath).GetPathName()); } else // 情况4、如果新的图层本身就存在,合并图层元素 { MergeLayerElements(*pXy, *pLayer, *pFindLayer); layersToRemove.push_back(layerPath); } } } } for (const CString& layerName : layersToRemove) { pXy->RemoveLayer(layerName); } return true; } /** * 将图层转换 dfd 字符串 * * \param pXy 图件对象 * \return dfd 字符串 */ extern "C" __declspec(dllexport) BSTR XyToDfdString(CXy* pXy) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr"); return CString().AllocSysString(); } const UINT MB = 1024 * 1024; const UINT blockSize = 16 * MB; CMemFile memFile(blockSize); int ret = pXy->DFD_Write(memFile, CUR_VERSION, true); DWORD size = memFile.GetLength(); std::vector buffer(size + 1); memFile.SeekToBegin(); memFile.Read(buffer.data(), size); buffer[size] = '\0'; CString result{ buffer.data() }; return result.AllocSysString(); } /** * 将图件中指定图层内容保存到另一图件中 * * \param pXy 图件 * \param filePath 要保存的文件路径 * \param layerName 要保存的图层名 * \return */ extern "C" __declspec(dllexport) extern bool XySaveLayer(CXy* pXy, LPCTSTR filePath, LPCTSTR layerName) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return false; } if (filePath == nullptr) { TRACE("filePath 不能为 nullptr\n"); return false; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr\n"); return false; } CFileHelper fileHelper(filePath, CFile::modeCreate | CFile::modeWrite); if (fileHelper.IsOpen()) { CPositionList select; pXy->GetElement(layerName, select, FALSE, TRUE); pXy->DFD_Write(fileHelper.GetFile(), select); return true; } return false; } extern "C" __declspec(dllexport) bool XyAddPoint(CXy* pXy, LPCTSTR layerName, LPCTSTR pointName, double x, double y, double z) { if (pXy == nullptr || layerName == nullptr || pointName == nullptr) { TRACE("pXy layerName 和 pointName 均不能为 nullptr\n"); return false; } CLayer* pLayer = pXy->FindAddLayer(layerName); if (pLayer == nullptr) { TRACE("查找或添加图层失败\n"); return false; } auto pPoint = std::make_unique(); pPoint->SetName(pointName); pPoint->x0 = x; pPoint->y0 = y; pPoint->z0 = z; auto pOne = std::make_unique(); pOne->SetValueSafe(pPoint.release()); pOne->SetLayer(pLayer); pXy->AddTailOne(pOne.release()); return true; } /** * 添加曲线 * * \param pXy 图件对象 * \param layerName 图层名称 * \param curveName 曲线名称 * \param x x坐标数组 * \param y y坐标数组 * \param z z坐标数组 * \param hasZ 是否有 z 值 * \param pointCount 曲线点个数 * \return 成功,失败 */ extern "C" __declspec(dllexport) extern bool XyCurveAdd(CXy* pXy, LPCTSTR layerName, LPCTSTR curveName, const double* x, const double* y, const double* z, bool hasZ, int pointCount) { if (pXy == nullptr || layerName == nullptr || curveName == nullptr) { TRACE("pXy layerName 和 curveName 均不能为 nullptr\n"); return false; } CLayer* pLayer = pXy->FindAddLayer(layerName); if (pLayer == nullptr) { TRACE("查找或添加图层失败\n"); return false; } auto pCurve = std::make_unique(); pCurve->SetName(curveName); pCurve->Create(pointCount); for (int i = 0; i < pointCount; i++) { pCurve->x[i] = x[i]; pCurve->y[i] = y[i]; if (hasZ) { pCurve->z[i] = z[i]; } } auto pOne = std::make_unique(); pOne->color = Color::Black; pOne->SetValueSafe(pCurve.release()); pOne->SetLayer(pLayer); pXy->AddTailOne(pOne.release()); return true; } /** * 将文件里面的符号复制到当前图件 * * \param pXy 当前图件 * \param filePath 从这个图件去拷贝符号 * \return */ extern "C" __declspec(dllexport) bool XyMergeSymbol(CXy* pXy, LPCTSTR filePath) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return false; } if (filePath == nullptr) { TRACE("filePath 不能为 nullptr\n"); return false; } CMapStringToPtrNoCase& mark = pXy->mark; auto pTargetXy = std::make_unique(); if (!pTargetXy->OpenFile(filePath, true)) { return false; } CMapStringToPtrNoCase& targetMark = pTargetXy->mark; POSITION pos = targetMark.GetStartPosition(); while (pos != nullptr) { CString name; void* pDraw = nullptr; targetMark.GetNextAssoc(pos, name, pDraw); auto pCloneDraw = std::make_unique(); *pCloneDraw = *(reinterpret_cast(pDraw)); pXy->AddMark(pCloneDraw.release(), TRUE); } return false; } static void CCurveColor(COne &one, COLORREF color) { auto property = std::make_unique(); property->color = color; // 这个功能目前是给断层处理用的,为了避免用户点击重新着色时不断增加曲线属性条目(即曲线里出现多个“常规”),这里直接把原来的清理掉 SafeDelete(one.HowToViewCurve); one.HowToViewCurve = new CHowToViewCurve(); one.HowToViewCurve->Add(property.release()); } extern "C" __declspec(dllexport) void XyClearLayerElementsEmbellish(CXy* pXy, LPCTSTR layerName, bool includeSubLayer) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr\n"); return; } CPositionList select; CXyElementFilter filter; filter.addLayer(layerName, includeSubLayer); pXy->GetElement(filter, select); POSITION pos = select.GetHeadPosition(); while (pos != nullptr) { POSITION pt = select.GetNext(pos); COne* pOne = pXy->GetAt(pt); SafeDelete(pOne->HowToViewCurve); SafeDelete(pOne->HowToViewPoint); } } extern "C" __declspec(dllexport) bool XyCurveMappingRandColor(CXy* pXy, LPCTSTR layerName, bool includeSubLayer) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return false; } if (layerName == nullptr) { TRACE("layerName 不能为 nullptr\n"); return false; } CPositionList select; CXyElementFilter filter; filter.addLayer(layerName, includeSubLayer); filter.addType(DOUBLEFOX_CURVE); pXy->GetElement(filter, select); // 故意用一个固定的随机数种,确保相同的图件,每次打开随机颜色都一样 std::mt19937 gen(123); std::uniform_int_distribution dist(30, 235); // 30 - 235,把一些接近黑色和接近白色的排除掉 // 颜色生成参数 const int MIN_BRIGHTNESS = 60; const int MIN_SATURATION_DIFF = 50; for (POSITION pos = select.GetHeadPosition(); pos != nullptr; select.GetNext(pos)) { POSITION pt = select.GetAt(pos); COne* pOne = pXy->GetAt(pt); if (pOne != nullptr) { while (true) { int r = dist(gen); int g = dist(gen); int b = dist(gen); // 排除低亮度 double brightness = 0.299 * r + 0.587 * g + 0.114 * b; if (brightness < 60) { continue; } #pragma push_macro("min") #pragma push_macro("max") #undef min #undef max // 检查饱和度(颜色差异),饱和度太低的排除掉 int maxVal = std::max({r, g, b}); int minVal = std::min({r, g, b}); if (maxVal - minVal < MIN_SATURATION_DIFF) { continue; } #pragma pop_macro("min") #pragma pop_macro("max") CCurveColor(*pOne, RGB(r, g, b)); break; } } } return true; } struct ElementEmbellish { COne *pOne; CString DML; }; class ElementsEmbellishStack { public: ElementsEmbellishStack() = default; ElementsEmbellishStack(CXy* pXy) { m_pXy = pXy; } void Save(const CPositionList& positions) { StackItem item; for (POSITION pos = positions.GetHeadPosition(); pos != nullptr; positions.GetNext(pos)) { POSITION pt = positions.GetAt(pos); COne* pOne = m_pXy->GetAt(pt); CString text = GetOneEmbellish(pOne); ElementEmbellish embellish{ pOne, text }; item.push_back(embellish); } m_stack.push(item); } void Restore() { if (m_stack.empty()) { return; } StackItem& item = m_stack.top(); auto set = Cache(); for (auto &embellish : item) { if (set.contains(embellish.pOne)) { SetOneEmbellish(embellish.pOne, embellish.DML); } } m_stack.pop(); } bool IsEmpty() const { return m_stack.empty(); } private: CString GetOneEmbellish(COne* pOne) const { CMemFile memFile; pOne->WriteDML(memFile, CUR_VERSION, 0); memFile.SeekToBegin(); auto length = memFile.GetLength(); int nChars = length / sizeof(TCHAR); CString result; result.GetBufferSetLength(nChars); memFile.Read(result.GetBuffer(), length); result.ReleaseBuffer(); memFile.Close(); return result; } void SetOneEmbellish(COne* pOne, const CString& text) { CMemFile memFile; memFile.Write(text.GetString(), text.GetLength() * sizeof(TCHAR)); memFile.SeekToBegin(); auto pTempOne = std::make_unique(); pTempOne->ReadDML(memFile, CUR_VERSION); memFile.Close(); SwapHowtoView(*pTempOne, *pOne); } ankerl::unordered_dense::set Cache() { ankerl::unordered_dense::set set; CPtrList& values = *(m_pXy->GetValueList()); for (POSITION pos = values.GetHeadPosition(); pos != nullptr; values.GetNext(pos)) { set.insert(reinterpret_cast(values.GetAt(pos))); } return set; } using StackItem = std::vector; using Stack = std::stack; Stack m_stack; CXy* m_pXy = nullptr; }; /** * 统一的元素修饰管理器,目前仅用于断层处理结束时暂时原来的修饰 */ class ElementsEmbellishManager { public: void SaveElementsEmbellish(CXy* pXy, CPositionList& select) { std::lock_guard locker(m_mutex); auto it = m_map.find(pXy); if (it == m_map.end()) { m_map[pXy] = ElementsEmbellishStack(pXy); } m_map[pXy].Save(select); } void RestoreElementsEmbellish(CXy* pXy) { std::lock_guard locker(m_mutex); auto it = m_map.find(pXy); if (it != m_map.end()) { it->second.Restore(); } } private: ankerl::unordered_dense::map m_map; std::mutex m_mutex; }; extern "C" __declspec(dllexport) void XySaveElementsEmbellish(CXy* pXy, LPCTSTR layerName, bool includeSubLayer) { CPositionList select; pXy->GetElement(layerName, select, includeSubLayer); GetInstace().SaveElementsEmbellish(pXy, select); } extern "C" __declspec(dllexport) void XyRestoreElementsEmbellish(CXy* pXy) { GetInstace().RestoreElementsEmbellish(pXy); } /** * 保存pdf文件 * * \param pXy 当前图件 * \param filePath 文件保存全路径 * \param paperType pdf纸张大小 0-A3 1-A4 2-A5 3-B4 * \param cType 0居中 1拉伸 * \param dType 0自适应, 1为纵向, 2横向 * \param left pdf边距 * \param right * \param top * \param bottom * \return */ extern "C" __declspec(dllexport) bool SavePDFFile(CXy* pXy, LPCTSTR filePath, int paperType, int cType, int dType, double left, double right, double top, double bottom, int num) { if (pXy == NULL || filePath == "") return FALSE; NBase::CRect8 rect(1e100, -1e100, -1e100, 1e100); rect = pXy->m_range; double dx = rect.Width(); double dy = rect.Height(); if (dx < 1e-20 || dy < 1e-20) { return FALSE; } NBase::CRect8 pRect(left, top, right, bottom); CDC dc; dc.CreateCompatibleDC(NULL); CRect rt(0, 0, dx, dy); CXyDC *pDc = new CXyDC; pDc->Extend(rect, rt, EXTEND_MODE_STRECH); pDc->SetViewRect(rt); pDc->SetPdfPrintState(TRUE); pDc->SetFilePath(filePath); pDc->Create(&dc, false); pDc->SetPdfData(pXy, pRect, paperType, cType, dType, num); pXy->Draw(*(CXyDC*)pDc, true); pDc->CloseFile(); delete pDc; return TRUE; } /** * 合并pdf文件 * * \param list 需要合并的pdf文件路径(合并顺序按照列表顺序) * \param count * \param filePath 合并后的文件 * \return */ extern "C" __declspec(dllexport) bool MergePDFFiles(const wchar_t** list, int count, const wchar_t* filePath) { std::vector vListFile; for (int i = 0; i < count; i++) { CString strFile(list[i]); vListFile.push_back(strFile); } CString strOutFile(filePath); std::unique_ptr pMerge = std::make_unique(); bool state = pMerge->MergePDFFiles(vListFile, strOutFile); return state; } static std::shared_ptr createFilterFromXml(TiXmlElement* elem) { if (!elem) { return nullptr; } CString elemName = elem->Value(); if (elemName == _T("TrueFilter")) { return std::make_shared(); } else if (elemName == _T("FalseFilter")) { return std::make_shared(); } else if (elemName == _T("LayerFilter")) { CString layerName = CA2T(elem->Attribute("layerName")); bool includeSublayer = false; const char* includeAttr = elem->Attribute("includeSublayer"); if (includeAttr) { includeSublayer = (strcmp(includeAttr, "true") == 0); } return std::make_shared(layerName, includeSublayer); } else if (elemName == _T("TypeFilter")) { int type = -1; elem->Attribute("type", &type); return std::make_shared(type); } else if (elemName == _T("VisibilityFilter")) { bool includeHidden = false; const char* attr = elem->Attribute("includeHidden"); if (attr) { includeHidden = (strcmp(attr, "true") == 0); } return std::make_shared(includeHidden); } else if (elemName == _T("EditableFilter")) { bool includeNotEditable = false; const char* attr = elem->Attribute("includeNotEditable"); if (attr) { includeNotEditable = (strcmp(attr, "true") == 0); } return std::make_shared(includeNotEditable); } else if (elemName == _T("AndFilter")) { auto andFilter = std::make_shared(); for (TiXmlElement* child = elem->FirstChildElement(); child; child = child->NextSiblingElement()) { auto childFilter = createFilterFromXml(child); if (childFilter) { andFilter->addFilter(childFilter); } } return andFilter; } else if (elemName == _T("OrFilter")) { auto orFilter = std::make_shared(); for (TiXmlElement* child = elem->FirstChildElement(); child; child = child->NextSiblingElement()) { auto childFilter = createFilterFromXml(child); if (childFilter) { orFilter->addFilter(childFilter); } } return orFilter; } else if (elemName == _T("NotFilter")) { TiXmlElement* child = elem->FirstChildElement(); if (child) { auto childFilter = createFilterFromXml(child); return std::make_shared(childFilter); } else { // 没有子过滤器,默认不匹配 return std::make_shared(nullptr); } } else if (elemName == _T("NameFilter")) { CString nameValue; bool ignoreCase = true; bool matchAll = true; // name if (const char* attr = elem->Attribute("name")) { nameValue = CA2T(attr); } // ignoreCase if (const char* attr = elem->Attribute("ignoreCase")) { ignoreCase = (strcmp(attr, "true") == 0); } // matchAll if (const char* attr = elem->Attribute("matchAll")) { matchAll = (strcmp(attr, "true") == 0); } return std::make_shared(nameValue, ignoreCase, matchAll); } return nullptr; } extern "C" __declspec(dllexport) BSTR XyGetElement(CXy* pXy, LPCTSTR filterXml) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return CString().AllocSysString(); } if (filterXml == nullptr) { TRACE("filterXml 不能为 nullptr\n"); return CString().AllocSysString(); } TiXmlDocument doc; doc.Parse(filterXml); TiXmlElement* pRoot = doc.RootElement(); auto pFilter = createFilterFromXml(pRoot); if (pFilter == nullptr) { TRACE("解析 xml 失败\n"); return CString().AllocSysString(); } CPositionList select; pXy->GetElement(pFilter, select); std::vector positions; for (POSITION pos = select.GetHeadPosition(); pos != nullptr; select.GetNext(pos)) { POSITION pt = select.GetAt(pos); CString str; str.Format("%I64d", pt); positions.push_back(str); } return JoinStrings(positions, ",").AllocSysString(); } typedef void(__stdcall* FaciesGenerationProgressCallback)(int done, int total); static std::future g_faciesFuture; static std::shared_ptr g_kedFacies; /** * 沉积相生成 IDW * * \param csvPath * \param kevPath * \return */; extern "C" __declspec(dllexport) KEDAlgorithm* KedCSVIDWGenerateFacies(const wchar_t* csvPath, const wchar_t* kevPath, const wchar_t* borderPath, double grid_interval, int subBlockCount, int IDWNeighbors, int IDWPower, bool isFaciesBorder, FaciesGenerationProgressCallback progressCallback) { // 防止重复调用导致资源冲突(可根据需求加锁) if (g_faciesFuture.valid() && g_faciesFuture.wait_for(std::chrono::seconds(0)) == std::future_status::timeout) { // 上一个任务仍在运行 TRACE("上一个沉积相生成任务仍在运行,请稍后再试。\n"); return nullptr; } CString csvFilePath = CString(csvPath); CString kevFilePath = CString(kevPath); CString borderFilePath = CString(borderPath); g_kedFacies = std::make_shared(); // 启动异步任务 //g_faciesFuture = std::async(std::launch::async, [=]() { // return g_kedFacies->KEDMeshAlgorithm(csvFilePath, kevFilePath, // grid_interval, bandwidth, beta, anchor_radius, progressCallback); // }); g_faciesFuture = std::async(std::launch::async, [=]() { return g_kedFacies->IDWMeshAlgorithm(csvFilePath, kevFilePath, borderFilePath, grid_interval, subBlockCount, IDWNeighbors, IDWPower, true, true, isFaciesBorder, progressCallback); }); return g_kedFacies.get(); } /** * 沉积相生成 NN * * \param csvPath * \param kevPath * \return */; extern "C" __declspec(dllexport) KEDAlgorithm* KedCSVNNGenerateFacies(const wchar_t* csvPath, const wchar_t* kevPath, const wchar_t* borderPath, double grid_interval, double NNSigma, int NNOpenIter, int NNCloseIter, bool isFaciesBorder, FaciesGenerationProgressCallback progressCallback) { // 防止重复调用导致资源冲突(可根据需求加锁) if (g_faciesFuture.valid() && g_faciesFuture.wait_for(std::chrono::seconds(0)) == std::future_status::timeout) { // 上一个任务仍在运行 TRACE("上一个沉积相生成任务仍在运行,请稍后再试。\n"); return nullptr; } CString csvFilePath = CString(csvPath); CString kevFilePath = CString(kevPath); CString borderFilePath = CString(borderPath); g_kedFacies = std::make_shared(); g_faciesFuture = std::async(std::launch::async, [=]() { return g_kedFacies->NNMeshAlgorithm(csvFilePath, kevFilePath, borderFilePath, grid_interval, NNSigma, NNOpenIter, NNOpenIter, isFaciesBorder, progressCallback); }); return g_kedFacies.get(); } /** * 停止生成沉积相 * * \param * \return */ extern "C" __declspec(dllexport) void StopGenerateFacies(KEDAlgorithm* pKed) { if (pKed == nullptr) return; pKed->StopTask(); } struct FaciesItem { const char* name; int id; }; extern "C" __declspec(dllexport) FaciesItem* GetFaciesTypeMap(KEDAlgorithm* pKed, int* count) { if (!pKed || !count) return nullptr; const auto& map = pKed->GetDepositionalMap(); *count = static_cast(map.size()); FaciesItem* items = new FaciesItem[*count]; int i = 0; for (const auto& kv : map) { items[i].name = _strdup(kv.first.c_str()); // 分配内存 items[i].id = kv.second; ++i; } return items; } extern "C" __declspec(dllexport) void FreeFaciesTypeMap(FaciesItem* items, int count) { if (!items) return; for (int i = 0; i < count; ++i) { free((void*)items[i].name); // 释放 strdup 分配的字符串 } delete[] items; } std::unique_ptr XyFaciesLegendCreate(CXy& xy, double x, double y, double width, std::vector> items) { // 计算列数 size_t columns = (items.size() + 3 - 1) / 3; FaciesLegend legend(xy, x, y, _T("相类图例"), items, width, static_cast(columns)); std::unique_ptr pBlock = legend.Build(); std::unique_ptr pOne = std::make_unique(); CLayer* pLayer = xy.FindAddLayer(_T("相类图例")); pOne->SetValueSafe(pBlock.release()); pOne->SetLayer(pLayer); return pOne; } /** * 添加相类图例 * * \param pXy 要添加图例的图件 * \param x 要添加的图例 x 坐标 * \param y 要添加的图例 y 坐标 * \param layerNames 哪些图层要生成图例 */ extern "C" __declspec(dllexport) void XyFaciesLegendAdd(CXy* pXy, double width, const FaciesItem* items, int count) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return; } CRect8 rect = pXy->GetRange(); double x = rect.left; double y = rect.bottom; CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return; } std::vector> legendItems; legendItems.reserve(count); for (int i = 0; i < count; ++i) { CString name(items[i].name); int color = static_cast(pMesh->color.GetColor(items[i].id)); legendItems.emplace_back(name, color); } std::unique_ptr pOne = XyFaciesLegendCreate(*pXy, x, y, width, legendItems); if (pOne) { COne* ptr = pOne.release(); pXy->AddTailOne(ptr); } } extern "C" __declspec(dllexport) void FaciesEnableDrawRuler(CXy* pXy, bool state) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return; } CRect8 rect = pXy->GetRange(); double x = rect.left; double y = rect.bottom; CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return; } pMesh->EnableDrawRuler(state); } extern "C" __declspec(dllexport) FaciesItem* FindFaciesLegend(CXy* pXy, int* count) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return nullptr; } FaciesItem* items = nullptr; CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) return nullptr; pMesh->color; CArray ColorList; pMesh->color.GetColor(ColorList); int nCount = 0; CPtrList* plist = pXy->GetValueList(); POSITION pos; COne* pOne; pos = plist->GetHeadPosition(); while (pos) { pOne = (COne*)plist->GetNext(pos); if (pOne->GetType() != DOUBLEFOX_BLOCK)continue; CInsertBlock* pBlock = ((CInsertBlock*)pOne->value); CXy* pXyBlock = (CXy*)pBlock->GetXy(); CLayer* pLayerBlock = pXyBlock->FindLayer("相类图列"); if (pLayerBlock != nullptr) { NBase::CPositionList posList1; nCount = pXyBlock->GetElement(pLayerBlock, posList1, DOUBLEFOX_TEXT); if (nCount == 0) { return nullptr; } // *count = nCount - 1; items = new FaciesItem[nCount - 1]; int i = 0; CListForEach(pos, posList1) { POSITION pt = posList1.GetAt(pos); COne* pOne = pXyBlock->GetAt(pt); CText* pText = (CText*)(pOne->value); if (pText->GetName() != "相 类") { //这里id设置成无效 最后在网格时处理 items[i].id = i; items[i].name = _strdup(pText->GetName()); // 分配内存 ++i; } } } } return items; } extern "C" __declspec(dllexport) KEDAlgorithm* KedProcessExistingGrd(CXy* pXy, const wchar_t* grdPath, const wchar_t* kevPath, FaciesGenerationProgressCallback progressCallback) { if (pXy == nullptr) { TRACE("pXy 不能为 nullptr\n"); return nullptr; } CString grdFilePath = CString(grdPath); CString kevFilePath = CString(kevPath); CMesh* pMesh = GetMesh(pXy); if (pMesh == nullptr) { return nullptr; } CSize size = pMesh->size(); //获取原来网格颜色色标 CColorBase colorBase = pMesh->color; std::vector grid_data; grid_data.reserve(size.cx * size.cy); // 提取网格数据 for (int j = 0; j < size.cy; ++j) { for (int i = 0; i < size.cx; ++i) { double v = ((CMeshBase*)pMesh)->GetValue(i, j); grid_data.push_back(static_cast(v)); } } // 获取坐标范围 double xMin = pMesh->GetMesh()->xmin(); double xMax = pMesh->GetMesh()->xmax(); double yMin = pMesh->GetMesh()->ymin(); double yMax = pMesh->GetMesh()->ymax(); // 计算 z 范围(与 Python / WriteDSAAFromGrid 一致) double zmin = pMesh->GetMesh()->range[0]; double zmax = pMesh->GetMesh()->range[1]; // 写入 Surfer DSAA 文件 std::ofstream out(CT2A(grdFilePath, CP_ACP)); if (!out.is_open()) { return false; } out << "DSAA\n"; out << size.cx << " " << size.cy << "\n"; out << xMin << " " << xMax << "\n"; out << yMin << " " << yMax << "\n"; out << zmin << " " << zmax << "\n"; // 与 WriteDSAAFromGrid 一致:从上到下反写(源数据最后一行在文件最前) for (int j = 0; j < size.cy; ++j) { int src_row = j; for (int i = 0; i < size.cx; ++i) { size_t index = static_cast(src_row) * size.cx + i; out << grid_data[index] << " "; if ((i + 1) % 10 == 0) out << "\n"; } out << "\n"; } out.close(); // 防止重复调用导致资源冲突(可根据需求加锁) if (g_faciesFuture.valid() && g_faciesFuture.wait_for(std::chrono::seconds(0)) == std::future_status::timeout) { // 上一个任务仍在运行 TRACE("上一个沉积相生成任务仍在运行,请稍后再试。\n"); return nullptr; } g_kedFacies = std::make_shared(); // 启动异步任务 g_faciesFuture = std::async(std::launch::async, [=]() { return g_kedFacies->ProcessExistingGrd(grdFilePath, kevFilePath, colorBase, progressCallback); }); return g_kedFacies.get(); }