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.

361 lines
6.9 KiB
C++

1 month ago
#include "stdafx.h"
#include "ItemEraser.h"
#include "SigmaDoc.h"
#include "SigmaView.h"
#include "ActionListItem.h"
#include "ActionComboItem.h"
#include "ActionAddItem.h"
#include "ActionDeleteItem.h"
#include "clipper2/clipper.h"
1 month ago
#include "json.hpp"
1 month ago
#undef min
#undef max
CItemEraser::CItemEraser(CSigmaDoc* ppDoc)
: CItem(ppDoc)
{
m_nodeDrawer = std::make_unique<CurveNodeDrawer>(ppDoc);
1 month ago
m_connection = ppDoc->GetView()->viewChanged.ConnectScoped([this] { isViewChanged = true; });
1 month ago
}
CItemEraser::~CItemEraser()
{
}
void CItemEraser::OnLButtonDblClk(UINT nFlags, CPoint point)
{
}
void CItemEraser::DrawAssistant(CDC* pDC, int mouseX, int mouseY)
{
if (isViewChanged)
{
DrawCurveNode(pDC);
isViewChanged = false;
}
DrawEraser(pDC, mouseX, mouseY, m_eraseRadius);
}
void CItemEraser::OnLButtonDown(CDC *pDC, UINT nFlags, CPoint point, int vk)
{
m_start = true;
m_path.clear();
}
void CItemEraser::OnLButtonUp(CDC* pDC, UINT nFlags, CPoint point, int vk)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>Ҫɾ<D2AA><C9BE><EFBFBD>뵱ǰ<EBB5B1><C7B0><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> m_path Ϊ<>գ<EFBFBD><D5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱֻ<CAB1><D6BB>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>浽 m_path <20>м<EFBFBD><D0BC><EFBFBD>
if (m_path.empty())
{
CPoint2D realPoint = GetDC()->GetReal(point);
m_path.push_back(realPoint);
}
Erase();
DrawCurveNode(pDC);
DrawEraser(pDC, point.x, point.y, m_eraseRadius);
m_start = false;
}
void CItemEraser::OnRButtonDown(UINT nFlags, CPoint point)
{
}
BOOL CItemEraser::OnRButtonUp(UINT nFlags, CPoint point)
{
return TRUE;
}
void CItemEraser::OnMouseWheel(uint32_t button, int32_t clicks, int32_t x, int32_t y, int32_t delta)
{
ResetLast(-1, -1, -1);
}
int CItemEraser::OnMouseMove(CDC* pDC, UINT nFlags, CPoint point)
{
auto realPoint = GetDC()->GetReal(point);
if (m_start)
{
m_path.push_back(realPoint);
1 month ago
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Relink ģʽ<C4A3><CABD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5>û<EFBFBD><C3BB>ɿ<EFBFBD><C9BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ſ<EFBFBD>ʼɾ<CABC><C9BE>
if (m_mode != EraserMode::Relink && m_path.size() > 5)
1 month ago
{
Erase();
// <20><><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>˫<EFBFBD><CBAB><EFBFBD>·Ż<C2B7>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD><EFBFBD>ܻᵼ<DCBB><E1B5BC><EFBFBD><EFBFBD>һС<D2BB><D0A1>ֱ<EFBFBD>ӱ<EFBFBD><D3B1><EFBFBD><EFBFBD><EFBFBD>
CPoint2D last = m_path[m_path.size() - 1];
m_path.clear();
m_path.push_back(last);
}
}
DrawAssistant(pDC, point.x, point.y);
return 0;
}
BOOL CItemEraser::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
return FALSE;
}
BOOL CItemEraser::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_OEM_COMMA:
ZoomEraseRadius(-ZOOM_VALUE);
ResetLast(-1, -1, -1);
Redraw();
break;
case VK_OEM_PERIOD:
ZoomEraseRadius(ZOOM_VALUE);
ResetLast(-1, -1, -1);
Redraw();
break;
}
return FALSE;
}
void CItemEraser::OnDraw(CXyDC* pXyDC, CDC* pDC)
{
}
void CItemEraser::OnCancel(void)
{
}
EraserMode CItemEraser::GetEraserMode() const
{
return m_mode;
}
void CItemEraser::SetEraserMode(EraserMode mode)
{
m_mode = mode;
}
int CItemEraser::GetEraserRadius() const
{
return m_eraseRadius;
}
void CItemEraser::SetEraserRadius(int radius)
{
if (radius <= 0)
{
return;
}
m_eraseRadius = radius;
}
void CItemEraser::Erase()
{
CSigmaDoc* pDoc = GetDoc();
CXy* pXy = pDoc->GetDraw();
std::unique_ptr<CCurveEx> pCurve = GetEraserPath();
if (pCurve == nullptr)
{
return;
}
Eraser eraser;
eraser.SetMode(m_mode);
eraser.SetXY(pXy);
eraser.Cut(*pCurve);
SetAction(eraser.m_plAdd, eraser.m_plDel);
Redraw();
}
void CItemEraser::SetAction(const CPositionList& plAdd, const CPositionList& plDel)
{
CSigmaDoc* pDoc = GetDoc();
auto pAction = std::make_unique<CActionComboItem>(pDoc, 0);
if (plDel.GetCount() > 0)
{
auto pDelAction = std::make_unique<CActionDeleteItem>(pDoc, IDS_STRING_ACTION_DELETE, plDel);
pDelAction->Do();
pAction->AddAction(pDelAction.release());
}
if (plAdd.GetCount() > 0)
{
auto pAddAction = std::make_unique<CActionAddItem>(pDoc, IDS_STRING_ACTION_ADD, plAdd);
pAddAction->Do();
pAction->AddAction(pAddAction.release());
}
if (pAction->GetCount() > 0)
{
pDoc->SetActionItem(pAction.release());
}
}
void CItemEraser::Redraw()
{
1 month ago
nlohmann::json eventObject
{
{"event", "redraw" },
};
std::string event = eventObject.dump();
CString strEvent = CA2T(event.c_str());
GetView()->Notify(strEvent);
1 month ago
}
void CItemEraser::DrawCircle(CDC* pDC, int centerX, int centerY, int radius)
{
CRect rect;
rect.left = centerX - radius;
rect.top = centerY - radius;
rect.right = centerX + radius;
rect.bottom = centerY + radius;
CPen pen(PS_SOLID, 3, m_penColor);
CPen* pOldPen = pDC->SelectObject(&pen);
pDC->Rectangle(rect);
pDC->SelectObject(pOldPen);
}
void CItemEraser::DrawEraser(CDC* pDC, int centerX, int centerY, int radius)
{
int nOldROP2 = pDC->SetROP2(R2_NOTXORPEN);
if (m_lastX > 0 && m_lastY > 0)
{
DrawCircle(pDC, m_lastX, m_lastY, m_lastRadius);
ResetLast(-1, -1, -1);
}
DrawCircle(pDC, centerX, centerY, radius);
ResetLast(centerX, centerY, radius);
pDC->SetROP2(nOldROP2);
}
void CItemEraser::DrawCurveNode(CDC* pDC)
{
CXyElementFilter filter;
filter.addType(DOUBLEFOX_CURVE);
CXy* pXy = GetDoc()->m_pXy;
CPositionList select;
pXy->GetElement(filter, select);
m_nodeDrawer->Draw(pDC, select);
}
void CItemEraser::ResetLast(int x, int y, int radius)
{
m_lastX = x;
m_lastY = y;
m_lastRadius = radius;
}
RTree<POSITION, double, 2>* CItemEraser::GetSpatialTree()
{
if (m_rtree == nullptr)
{
CXyElementFilter filter;;
filter.addType(DOUBLEFOX_CURVE);
m_rtree = BuildRTree(*GetDoc()->m_pXy, filter);
}
return m_rtree.get();
}
std::unique_ptr<CCurveEx> CItemEraser::GetEraserPath() const
{
using Clipper2Lib::PathD;
using Clipper2Lib::PathsD;
using Clipper2Lib::JoinType;
using Clipper2Lib::EndType;
using Clipper2Lib::InflatePaths;
using Clipper2Lib::MakePathD;
using Clipper2Lib::SimplifyPaths;
if (m_path.empty())
{
return nullptr;
}
PathD originalPath;
for (const auto& point : m_path)
{
originalPath.emplace_back(point.x0, point.y0);
}
PathsD subject{ std::move(originalPath) };
PathsD simplified = SimplifyPaths(subject, 1.5);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>û<EFBFBD><C3BB>ʿ<EFBFBD><CABF>ȶ<EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>
double delta = GetDC()->GetRealWidth(static_cast<double>(m_eraseRadius));
//<2F><><EFBFBD><EFBFBD>
PathsD solution = InflatePaths(simplified, delta, JoinType::Miter, EndType::Square);
if (solution.empty())
{
return nullptr;
}
// ֻʹ<D6BB>ý<EFBFBD><C3BD><EFBFBD><EFBFBD>еĵ<D0B5>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
PathD& expandedPath = solution[0];
if (expandedPath.empty())
{
return nullptr;
}
auto pCurve = std::make_unique<CCurveEx>();
pCurve->Create((int)expandedPath.size() + 1);
size_t i = 0;
for (; i < expandedPath.size(); i++)
{
pCurve->x[i] = expandedPath[i].x;
pCurve->y[i] = expandedPath[i].y;
}
pCurve->x[i] = expandedPath[0].x;
pCurve->y[i] = expandedPath[0].y;
pCurve->GetLocation();
return pCurve;
}
std::vector<CPoint> CItemEraser::GetScreenPoints(const std::vector<CPoint2D>& points) const
{
std::vector<CPoint> screenPoints;
screenPoints.reserve(points.size());
CXyDC *pXyDC = GetDC();
for (CPoint2D point : points)
{
screenPoints.emplace_back(pXyDC->GetScreen(point));
}
return screenPoints;
}
void CItemEraser::ZoomEraseRadius(int radius)
{
m_eraseRadius = std::clamp(m_eraseRadius + radius, MIN_ERASE_RADIUS, MAX_ERASE_RADIUS);
}