You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3014 lines
70 KiB
C++

This file contains ambiguous Unicode characters!

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

#include "stdafx.h"
#include <stack>
#include <random>
#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"
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<POSITION, POSITION> 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<double>::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<COne*> 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<std::vector<MeshPoint>>& dataGrid)
{
TiXmlDocument doc;
TiXmlElement* rootElement = new TiXmlElement("Grid");
doc.LinkEndChild(rootElement);
// 创建子元素 <metadata>
TiXmlElement* metadataElement = MetadataToXml(metadata);
rootElement->LinkEndChild(metadataElement);
// 创建坐标元素
TiXmlElement* coordinatesElement = new TiXmlElement("Coordinates");
rootElement->LinkEndChild(coordinatesElement);
std::vector<std::vector<TiXmlElement*>> dataElementGrid(metadata.rows, std::vector<TiXmlElement*>(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;
}
/// <summary>
/// 失败时返回的数据,由于是传递的引用过来,所以要用这个设置一下,防止 C# 那边写入脏数据
/// </summary>
/// <param name="metadata">网格元数据</param>
/// <param name="x">x 数组指针</param>
/// <param name="y">y 数组指针</param>
/// <param name="z">z 数组指针</param>
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<CMesh> CreateMesh(const MeshMetadata& metadata, const double* x, const double* y, const double* z)
{
auto pMesh = std::make_unique<CMesh>();
auto pDfg = std::make_unique<CDimension2D>();
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<CCurve*>* curves, vector<CString*>* 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 <typename T>
void DeleteVectorData(std::vector<T *> &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<CCurve*> pCurves;
std::vector<CString*> 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<COne>();
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<CString> 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<CLayer*> GetAllLayers(const CXy& xy)
{
CXy& mutXy = const_cast<CXy&>(xy);
std::vector<CLayer*> 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<CXy> pNewSymbol = std::make_unique<CXy>();
*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<CCurveArrow*>(pView))
{
CopyMarkTo(pSourceXy, pTargetXy, pArrow->MarkName);
}
else if (auto* pScale = dynamic_cast<CCurveScale*>(pView))
{
CopyMarkTo(pSourceXy, pTargetXy, pScale->MarkName);
}
else if (auto* pTwoMark = dynamic_cast<CCurveTwoMark*>(pView))
{
CopyMarkTo(pSourceXy, pTargetXy, pTwoMark->MarkName);
}
else if (auto* pRgn = dynamic_cast<CCurveRgn*>(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<CXy> targetXy = std::make_unique<CXy>();
if (!XyOpenFile(targetXy.get(), targetFilePath, false))
{
return;
}
std::vector<CLayer*> 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<CString> CollectValidLayerNames(CXy& xy, const std::vector<CString>& layerNames)
{
std::vector<CString> 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<COne> XyLegendCreate(CXy& xy, double x, double y, double width, int rows, LPCTSTR layerNames)
{
std::vector<CString> 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<int>(columns), validNames);
std::unique_ptr<CInsertBlock> pBlock = legend.Build();
std::unique_ptr<COne> pOne = std::make_unique<COne>();
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<COne> 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<CString> 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<int>(columns), validNames);
std::unique_ptr<CInsertBlock> 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<CGridding> pGridding = std::make_unique<CGridding>();
// 设置范围
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<CPoint3D> GeneratePoints(double x1, double y1, double x2, double y2, double step)
{
double distance = CalcDistance(x1, y1, x2, y2);
int num_steps = static_cast<int>(distance / step);
double xIncrement = (x2 - x1) / distance * step;
double yIncrement = (y2 - y1) / distance * step;
std::vector<CPoint3D> 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<CCurveEx> CreateCurveFromMesh(const CMesh &mesh, double x1, double y1, double x2, double y2)
{
CMesh& mutMesh = const_cast<CMesh&>(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<CPoint3D> 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<CCurveEx>();
pCurve->Create(static_cast<int>(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<CCurveEx> 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<CMesh>();
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<CCurveEx> pCurve = CreateCurveFromXyMesh(*pXy, x1, y1, x2, y2);
if (!pCurve)
{
TRACE("未找到空间位置匹配的网格\n");
return false;
}
CLayer* pLayer = pXy->FindAddLayer(CString(layerName));
auto pOne = std::make_unique<COne>();
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<COne*>(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<CString> 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<BYTE> 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<CPointNameEx>();
pPoint->SetName(pointName);
pPoint->x0 = x;
pPoint->y0 = y;
pPoint->z0 = z;
auto pOne = std::make_unique<COne>();
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<CCurveEx>();
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<COne>();
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<CXy>();
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<CXy>();
*pCloneDraw = *(reinterpret_cast<CXy*>(pDraw));
pXy->AddMark(pCloneDraw.release(), TRUE);
}
return false;
}
static void CCurveColor(COne &one, COLORREF color)
{
auto property = std::make_unique<CCurvePropertiesEx>();
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<int> 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<COne>();
pTempOne->ReadDML(memFile, CUR_VERSION);
memFile.Close();
SwapHowtoView(*pTempOne, *pOne);
}
ankerl::unordered_dense::set<COne*> Cache()
{
ankerl::unordered_dense::set<COne*> set;
CPtrList& values = *(m_pXy->GetValueList());
for (POSITION pos = values.GetHeadPosition(); pos != nullptr; values.GetNext(pos))
{
set.insert(reinterpret_cast<COne*>(values.GetAt(pos)));
}
return set;
}
using StackItem = std::vector<ElementEmbellish>;
using Stack = std::stack<StackItem>;
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<CXy*, ElementsEmbellishStack> 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<ElementsEmbellishManager>().SaveElementsEmbellish(pXy, select);
}
extern "C" __declspec(dllexport)
void XyRestoreElementsEmbellish(CXy* pXy)
{
GetInstace<ElementsEmbellishManager>().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<CString> vListFile;
for (int i = 0; i < count; i++)
{
CString strFile(list[i]);
vListFile.push_back(strFile);
}
CString strOutFile(filePath);
std::unique_ptr<MergePDFFile> pMerge = std::make_unique<MergePDFFile>();
bool state = pMerge->MergePDFFiles(vListFile, strOutFile);
return state;
}
static std::shared_ptr<ElementFilter> createFilterFromXml(TiXmlElement* elem)
{
if (!elem)
{
return nullptr;
}
CString elemName = elem->Value();
if (elemName == _T("TrueFilter"))
{
return std::make_shared<TrueFilter>();
}
else if (elemName == _T("FalseFilter"))
{
return std::make_shared<FalseFilter>();
}
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<LayerFilter>(layerName, includeSublayer);
}
else if (elemName == _T("TypeFilter"))
{
int type = -1;
elem->Attribute("type", &type);
return std::make_shared<TypeFilter>(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<VisibilityFilter>(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<EditableFilter>(includeNotEditable);
}
else if (elemName == _T("AndFilter"))
{
auto andFilter = std::make_shared<AndFilter>();
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<OrFilter>();
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<NotFilter>(childFilter);
}
else
{
// 没有子过滤器,默认不匹配
return std::make_shared<NotFilter>(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<NameFilter>(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<CString> 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();
}