////////////////////////////////////////////////////////////////////////////// //文件 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 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 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> cache; cache.reserve(posSize); { int index = 0; POSITION pos = value.GetHeadPosition(); while (pos != nullptr) { COne* pOne = reinterpret_cast(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(); }