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

194 lines
4.3 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.

//////////////////////////////////////////////////////////////////////////////
//文件 ActionDeleteItem.cpp
//主要功能:
//
//程序编写: 2006-12-07
/////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include ".\actiondeleteitem.h"
#include "SigmaDoc.h"
#include "SigmaView.h"
#include "Visitor.h"
#include "Util.h"
CActionDeleteItem::CActionDeleteItem(CSigmaDoc * ppDoc, UINT actionType)
: CActionItem(ppDoc, actionType)
, m_bDeleted(false)
, m_bPerformOperation(FALSE)
{
}
NAction::CActionDeleteItem::CActionDeleteItem()
: CActionItem(nullptr, 0)
{
}
CActionDeleteItem::CActionDeleteItem(CSigmaDoc * ppDoc, UINT actionType, const CPositionList& list)
: CActionItem(ppDoc, actionType)
, m_bDeleted(false)
, m_bPerformOperation(FALSE)
{
long num=(long)list.GetCount();
if(num>0)
{
POSITION pt;
POSITION pos = list.GetHeadPosition();
std::vector<POSITION> positions;
positions.reserve(list.GetSize());
while (pos != NULL)
{
pt = list.GetNext(pos);
COne *pOne=GetDoc()->GetDraw()->GetAt(pt);
value.AddTail(pOne);
positions.push_back(pt);
}
GetDoc()->GetDraw()->GetElementIndexs(positions, m_pos);
}
}
CActionDeleteItem::~CActionDeleteItem(void)
{
Clear();
}
void NAction::CActionDeleteItem::Clear(void)
{
//Delete all objects in the m_list
if(m_bDeleted)//清除所有数据
{
CActionItem::Clear(value);
}
}
void NAction::CActionDeleteItem::accept(CActionVisitor& visitor)
{
visitor.visit(*this);
}
void CActionDeleteItem::Finish(void)
{
if(!m_bPerformOperation)
RemoveOperation();
CActionItem::Finish();
}
void CActionDeleteItem::RemoveOperation()
{
GetDoc()->ClearSelection();
m_bDeleted=true;
if(value.IsEmpty()) return;
// 注意pOne->GetRange 会查找符号,而 AfxGetGlobalMark()->BackupMark() 获取的是一个 threadlocal 对象,
// 这时候里面当前符号表指针很可能已经指向别的图件的符号表了,所以需要重新设置,用完之后再还原
auto* pMark = &(GetDoc()->GetDraw()->mark);
AfxGetGlobalMark()->BackupMark();
AfxGetGlobalMark()->SetMark(pMark);
FinalAction finalAction([]() { AfxGetGlobalMark()->RestoreMark(); });
COne* pOne;
int n=0;
CRect8 range(1e100,-1e100,-1e100,1e100);
std::vector<COne*> pOnes;
pOnes.reserve(value.GetCount());
POSITION pos = value.GetTailPosition();
while (pos != NULL)
{
pOne = (COne*)value.GetPrev(pos);
pOne->GetRange(range);
pOnes.push_back(pOne);
}
RemoveAtNoClear(pOnes);
Invalidate(range);
//GetDoc()->Modified();
}
void CActionDeleteItem::AddOperation()
{
//add back all the objects according its position in the CDrawDoc::m_objects.
m_bDeleted=false;
if (value.IsEmpty())
{
return;
}
size_t posSize = m_pos.size();
size_t valueSize = value.GetCount();
ASSERT(posSize == valueSize);
// 缓存下标和被删除的 COne* 映射关系,必须由小到大排列
std::vector<std::pair<int, COne*>> cache;
cache.reserve(posSize);
{
int index = 0;
POSITION pos = value.GetHeadPosition();
while (pos != nullptr)
{
COne* pOne = reinterpret_cast<COne*>(value.GetNext(pos));
cache.emplace_back(m_pos[index++], pOne);
}
std::sort(cache.begin(), cache.end(), [](auto& pair1, auto& pair2)
{
return pair1.first < pair2.first;
});
}
{
// 性能优化65万个散点的文件能够由一分钟缩短成几秒钟
// 注意这里,我们先遍历图件中的图元,然后标记当前下标,再判断 cache 中的下标和当前下标是否相同,如果相同,当前就是要插入的位置
// 我们前面对 cache 元素按下标排列的意义就来了,我们每次只用和 cache 的一个迭代器进行比较,如果这个元素插入到了原图件中,
// 就把迭代器向后移动一下就行,避免了大量循环
CPtrList* pValues = GetDoc()->GetDraw()->GetValueList();
int index = 0;
auto cacheIt = cache.begin();
POSITION pos = pValues->GetHeadPosition();
while (pos != nullptr)
{
// 如果缓存中的数据处理完了,整个操作就结束了
if (cacheIt == cache.end())
{
break;
}
// 如果找到正确的位置
if (index == cacheIt->first)
{
pos = GetDoc()->GetDraw()->InsertElementBefore(pos, cacheIt->second); // 这里注意要把 pos 接上
cacheIt++;
}
pValues->GetNext(pos);
index++;
}
// 如果删除的图元在图件的末尾,还得把这部分添加回去
while (cacheIt != cache.end())
{
GetDoc()->GetDraw()->AddTailOne(cacheIt->second);
cacheIt++;
}
}
}
void CActionDeleteItem::Undo()
{
CActionItem::Undo();
AddOperation();
}
void CActionDeleteItem::Redo()
{
CActionItem::Redo();
RemoveOperation();
}