Files
computer-graphics/StraightLine/StraightLine/StraightLineView.cpp
T
2024-09-19 15:49:35 +08:00

434 lines
13 KiB
C++

// StraightLineView.cpp : implementation of the CStraightLineView class
//
#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "StraightLine.h"
#endif
#include "StraightLineDoc.h"
#include "StraightLineView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CStraightLineView
IMPLEMENT_DYNCREATE(CStraightLineView, CView)
BEGIN_MESSAGE_MAP(CStraightLineView, CView)
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
// CStraightLineView construction/destruction
CStraightLineView::CStraightLineView() noexcept {
// TODO: add construction code here
m_bDraw = FALSE;
}
CStraightLineView::~CStraightLineView() {
}
BOOL CStraightLineView::PreCreateWindow(CREATESTRUCT &cs) {
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CStraightLineView drawing
void CStraightLineView::OnDraw(CDC *pDC) {
CStraightLineDoc *pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// 获取客户端矩形区域
GetClientRect(&m_rect);
// 创建内存设备上下文和兼容位图
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap NewBitmap, *pOldBitmap;
NewBitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
pOldBitmap = memDC.SelectObject(&NewBitmap);
// 设置内存设备上下文的映射模式和视口
memDC.SetMapMode(MM_ANISOTROPIC);
memDC.SetWindowExt(m_rect.Width(), m_rect.Height());
memDC.SetViewportExt(m_rect.Width(), -m_rect.Height());
memDC.SetViewportOrg(m_rect.Width() / 2, m_rect.Height() / 2);
m_rect.OffsetRect(-m_rect.Width() / 2, -m_rect.Height() / 2);
// 填充背景颜色并绘制坐标轴
memDC.FillSolidRect(&m_rect, RGB(255, 255, 255));
memDC.MoveTo(-m_rect.Width() / 2, 0);
memDC.LineTo(m_rect.Width() / 2, 0);
memDC.LineTo(m_rect.Width() / 2 - 10, -5);
memDC.MoveTo(m_rect.Width() / 2, 0);
memDC.LineTo(m_rect.Width() / 2 - 10, 5);
memDC.MoveTo(0, -m_rect.Height() / 2);
memDC.LineTo(0, m_rect.Height() / 2);
memDC.LineTo(-5, m_rect.Height() / 2 - 10);
memDC.MoveTo(0, m_rect.Height() / 2);
memDC.LineTo(5, m_rect.Height() / 2 - 10);
// 绘制坐标轴标签
memDC.TextOutW(10, 25, _T("O"));
memDC.TextOutW(m_rect.Width() / 2 - 10, 25, _T("x"));
memDC.TextOutW(10, m_rect.Height() / 2, _T("y"));
// 调用Bresenham算法绘制直线
// BresenhamLine(&memDC);
WuLine(&memDC);
// 设置显示设备上下文的映射模式和视口
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(m_rect.Width(), m_rect.Height());
pDC->SetViewportExt(m_rect.Width(), -m_rect.Height());
pDC->SetViewportOrg(m_rect.Width() / 2, m_rect.Height() / 2);
// 将内存设备上下文中的位图拷贝到显示设备上下文中
pDC->BitBlt(-m_rect.Width() / 2, -m_rect.Height() / 2, m_rect.Width(), m_rect.Height(), &memDC, -m_rect.Width() / 2, -m_rect.Height() / 2, SRCCOPY);
// 恢复旧位图并删除对象
memDC.SelectObject(pOldBitmap);
NewBitmap.DeleteObject();
memDC.DeleteDC();
}
// CStraightLineView printing
BOOL CStraightLineView::OnPreparePrinting(CPrintInfo *pInfo) {
// default preparation
return DoPreparePrinting(pInfo);
}
void CStraightLineView::OnBeginPrinting(CDC * /*pDC*/, CPrintInfo * /*pInfo*/) {
// TODO: add extra initialization before printing
}
void CStraightLineView::OnEndPrinting(CDC * /*pDC*/, CPrintInfo * /*pInfo*/) {
// TODO: add cleanup after printing
}
// CStraightLineView diagnostics
#ifdef _DEBUG
void CStraightLineView::AssertValid() const {
CView::AssertValid();
}
void CStraightLineView::Dump(CDumpContext &dc) const {
CView::Dump(dc);
}
CStraightLineDoc *CStraightLineView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CStraightLineDoc)));
return (CStraightLineDoc *)m_pDocument;
}
#endif //_DEBUG
// CStraightLineView message handlers
void CStraightLineView::BresenhamLine(CDC *pDC) {
// 定义起始颜色和结束颜色
COLORREF startColor = RGB(0, 82, 217);
COLORREF endColor = RGB(236, 189, 101);
// 获取起点和终点坐标
CPoint ptOrigin = m_ptOrigin, ptEnd = m_ptEnd, ptTemp;
LONG dx = ptEnd.x - ptOrigin.x, dy = ptEnd.y - ptOrigin.y;
int totalSteps = max(abs(dx), abs(dy));
// 定义颜色插值函数
auto interpolateColor = [](COLORREF start, COLORREF end, DOUBLE factor) -> COLORREF {
BYTE r = static_cast<BYTE>(GetRValue(start) + factor * (GetRValue(end) - GetRValue(start)));
BYTE g = static_cast<BYTE>(GetGValue(start) + factor * (GetGValue(end) - GetGValue(start)));
BYTE b = static_cast<BYTE>(GetBValue(start) + factor * (GetBValue(end) - GetBValue(start)));
return RGB(r, g, b);
};
// 处理垂直线的情况
if (ptOrigin.x == ptEnd.x) {
if (ptOrigin.y > ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (int y = ptOrigin.y; y <= ptEnd.y; y++) {
DOUBLE factor = (DOUBLE)(y - ptOrigin.y) / totalSteps;
COLORREF color = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptOrigin.x, y, color);
}
}
else {
// 计算斜率
DOUBLE k = (DOUBLE)dy / dx;
DOUBLE d;
// 处理斜率在[0, 1]之间的情况
if (k >= 0 && k <= 1) {
d = 0.5 - k;
if (ptOrigin.x > ptEnd.x) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin; ptTemp.x <= ptEnd.x; ptTemp.x++) {
DOUBLE factor = (DOUBLE)(ptTemp.x - ptOrigin.x) / totalSteps;
COLORREF color = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, color);
if (d < 0) {
d += 1 - k;
ptTemp.y++;
}
else {
d -= k;
}
}
}
// 处理斜率大于1的情况
else if (k > 1) {
d = 0.5 - 1 / k;
if (ptOrigin.y > ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin; ptTemp.y <= ptEnd.y; ptTemp.y++) {
DOUBLE factor = (DOUBLE)(ptTemp.y - ptOrigin.y) / totalSteps;
COLORREF color = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, color);
if (d < 0) {
d += 1 - 1 / k;
ptTemp.x++;
}
else {
d -= 1 / k;
}
}
}
// 处理斜率在[-1, 0]之间的情况
else if (k < 0 && k >= -1) {
d = 0.5 + k;
if (ptOrigin.x > ptEnd.x) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin; ptTemp.x <= ptEnd.x; ptTemp.x++) {
DOUBLE factor = (DOUBLE)(ptTemp.x - ptOrigin.x) / totalSteps;
COLORREF color = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, color);
if (d < 0) {
d += 1 + k;
ptTemp.y--;
}
else {
d += k;
}
}
}
// 处理斜率小于-1的情况
else {
d = 0.5 + 1 / k;
if (ptOrigin.y < ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin; ptTemp.y >= ptEnd.y; ptTemp.y--) {
DOUBLE factor = (DOUBLE)(ptOrigin.y - ptTemp.y) / totalSteps;
COLORREF color = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, color);
if (d < 0) {
d += 1 + 1 / k;
ptTemp.x++;
}
else {
d += 1 / k;
}
}
}
}
}
void CStraightLineView::WuLine(CDC *pDC) {
COLORREF startColor = RGB(0, 82, 217);
COLORREF endColor = RGB(236, 189, 101);
COLORREF backColor = RGB(255, 255, 255);
// 获取起点和终点坐标
CPoint ptOrigin = m_ptOrigin, ptEnd = m_ptEnd, ptTemp;
LONG dx = ptEnd.x - ptOrigin.x, dy = ptEnd.y - ptOrigin.y;
int totalSteps = max(abs(dx), abs(dy));
// 定义颜色插值函数
auto interpolateColor = [](COLORREF start, COLORREF end, DOUBLE factor) -> COLORREF {
BYTE r = static_cast<BYTE>(GetRValue(start) + factor * (GetRValue(end) - GetRValue(start)));
BYTE g = static_cast<BYTE>(GetGValue(start) + factor * (GetGValue(end) - GetGValue(start)));
BYTE b = static_cast<BYTE>(GetBValue(start) + factor * (GetBValue(end) - GetBValue(start)));
return RGB(r, g, b);
};
// 上方像素颜色
auto downPixelColor = [&](COLORREF foreColor, DOUBLE e) -> COLORREF {
BYTE r = static_cast<BYTE>((GetRValue(backColor) - GetRValue(foreColor)) * e + GetRValue(foreColor));
BYTE g = static_cast<BYTE>((GetGValue(backColor) - GetGValue(foreColor)) * e + GetGValue(foreColor));
BYTE b = static_cast<BYTE>((GetBValue(backColor) - GetBValue(foreColor)) * e + GetBValue(foreColor));
return RGB(r, g, b);
};
// 下方像素颜色
auto upPixelColor = [&](COLORREF foreColor, DOUBLE e) -> COLORREF {
BYTE r = static_cast<BYTE>((GetRValue(backColor) - GetRValue(foreColor)) * (1 - e) + GetRValue(foreColor));
BYTE g = static_cast<BYTE>((GetGValue(backColor) - GetGValue(foreColor)) * (1 - e) + GetGValue(foreColor));
BYTE b = static_cast<BYTE>((GetBValue(backColor) - GetBValue(foreColor)) * (1 - e) + GetBValue(foreColor));
return RGB(r, g, b);
};
// 处理垂直线的情况
if (ptOrigin.x == ptEnd.x) {
if (ptOrigin.y > ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (int y = ptOrigin.y; y < ptEnd.y; y++) {
DOUBLE factor = (DOUBLE)(y - ptOrigin.y) / totalSteps;
COLORREF foreColor = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptOrigin.x, y, foreColor);
}
}
else {
// 计算斜率
DOUBLE k = (DOUBLE)dy / dx;
// DOUBLE d;
DOUBLE e;
// 处理斜率在[0, 1]之间的情况
if (k >= 0.0 && k <= 1.0) {
if (ptOrigin.x > ptEnd.x) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin, e = k; ptTemp.x < ptEnd.x; ptTemp.x++) {
DOUBLE factor = (DOUBLE)(ptTemp.x - ptOrigin.x) / totalSteps;
COLORREF foreColor = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, downPixelColor(foreColor, e));
pDC->SetPixelV(ptTemp.x, ptTemp.y + 1, upPixelColor(foreColor, e));
e += k;
if (e >= 1.0) {
ptTemp.y++;
e--;
}
}
}
// 处理斜率在(1, ∞)之间的情况
else if (k > 1.0) {
if (ptOrigin.y > ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
// d = 0.5 - 1 / k;
for (ptTemp = ptOrigin, e = 1 / k; ptTemp.y < ptEnd.y; ptTemp.y++) {
DOUBLE factor = (DOUBLE)(ptTemp.y - ptOrigin.y) / totalSteps;
COLORREF foreColor = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, downPixelColor(foreColor, e));
pDC->SetPixelV(ptTemp.x + 1, ptTemp.y, upPixelColor(foreColor, e));
e += 1 / k;
if (e >= 1.0) {
ptTemp.x++;
e--;
}
}
}
// 处理斜率在[-1, 0)之间的情况
else if (k < 0.0 && k >= -1.0) {
if (ptOrigin.x > ptEnd.x) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin, e = -k; ptTemp.x < ptEnd.x; ptTemp.x++) {
DOUBLE factor = (DOUBLE)(ptTemp.x - ptOrigin.x) / totalSteps;
COLORREF foreColor = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, downPixelColor(foreColor, e));
pDC->SetPixelV(ptTemp.x, ptTemp.y - 1, upPixelColor(foreColor, e));
e -= k;
if (e >= 1.0) {
ptTemp.y--;
e--;
}
}
}
// 处理斜率在(-∞, -1)之间的情况
else {
if (ptOrigin.y < ptEnd.y) {
ptTemp = ptOrigin;
ptOrigin = ptEnd;
ptEnd = ptTemp;
}
for (ptTemp = ptOrigin, e = -1 / k; ptTemp.y > ptEnd.y; ptTemp.y--) {
DOUBLE factor = (DOUBLE)(ptOrigin.y - ptTemp.y) / totalSteps;
COLORREF foreColor = interpolateColor(startColor, endColor, factor);
pDC->SetPixelV(ptTemp.x, ptTemp.y, downPixelColor(foreColor, e));
pDC->SetPixelV(ptTemp.x + 1, ptTemp.y, upPixelColor(foreColor, e));
e -= 1 / k;
if (e >= 1.0) {
ptTemp.x++;
e--;
}
}
}
}
}
void CStraightLineView::OnLButtonDown(UINT nFlags, CPoint point) {
// 记录起点坐标并转换为视图坐标系
m_ptOrigin = CPoint(point.x - m_rect.Width() / 2, m_rect.Height() / 2 - point.y);
// 设置绘制标志为真
m_bDraw = TRUE;
CView::OnLButtonDown(nFlags, point);
}
void CStraightLineView::OnMouseMove(UINT nFlags, CPoint point) {
// 如果正在绘制,更新终点坐标并转换为视图坐标系
if (m_bDraw) {
m_ptEnd = CPoint(point.x - m_rect.Width() / 2, m_rect.Height() / 2 - point.y);
// 使视图无效以触发重绘
Invalidate(FALSE);
}
CView::OnMouseMove(nFlags, point);
}
void CStraightLineView::OnLButtonUp(UINT nFlags, CPoint point) {
// 设置绘制标志为假
m_bDraw = FALSE;
// 更新终点坐标并转换为视图坐标系
m_ptEnd = CPoint(point.x - m_rect.Width() / 2, m_rect.Height() / 2 - point.y);
// 使视图无效以触发重绘
Invalidate(FALSE);
CView::OnLButtonUp(nFlags, point);
}