c++ - 特定位置的 C++ 缩放图像 - 居中
问题描述
所以我想为地图添加纹理,但问题是我无法完全理解为什么在使用不同缩放大小进行缩放时它没有到达正确的位置。
我通常会尝试将背景上的纹理位置设置为我的位置,使自己居中于框架中:例如,我的纹理大小为 1500x1600,我位于该图片中的 X140、Y590(是的,坐标是在我使用控制台检查时正确检索),放大一些值并缩放纹理并将其位置设置为我所在的位置。
代码如下:
if (!areTexturesInit) {
InitiateTextures();
areTexturesInit = true;
}
wxBitmap bit(imageTest);
wxPaintDC dc(this);
double zoomSize = 0.9; // here I'm applying the zooming proportions ( 0.1 - bigger size of the texture, 0.9 - more zoomed in )
this->SetSize(wxSize(386, 386)); // size of the main frame
backgroundSize.x = GetSize().x; // get the size of the main frame
backgroundSize.y = GetSize().y;
middlePoint.x = (backgroundSize.x / 2); // calculate the middle point of the frame
middlePoint.y = (backgroundSize.y / 2);
mapSizeX = 25600 / -zoomSize; // scale vs zoom size
mapSizeY = 25600 / zoomSize;
Vector3 myPosition;
GetPlayerPosition(&myPosition); // gets my location
float TextureCoordinateX = middlePoint.x + (myPosition.x / mapSizeX) * backgroundSize.x;
float TextureCoordinateY = middlePoint.y - (myPosition.y / mapSizeY) * backgroundSize.y;
dc.DrawBitmap(bit, TextureCoordinateX, TextureCoordinateY);
Vector3 myPosOnMap = PositionToMapPosition(myPosition, myPosition); // calculates my position on the map vs mapSizeX and Y & rotates vector
dc.SetPen(wxPen(wxColor(255, 0, 0), 4));
dc.DrawRectangle(wxRect(myPosOnMap.x, myPosOnMap.y, 2, 2)); // draws me on the map with a red square
问题是我认为我在某处搞砸了缩放部分,但我已经挠头 2 天了,我无法弄清楚我做错了什么/我必须做些什么来解决这个问题.
如果有人对我应该做什么有任何想法,我将不胜感激。
非常感谢!
我附上了一些演示,所以你可以看到我在说什么:https ://imgur.com/a/U2GWSQ8
- 第一个图像的“zoomSize”为 0.9;
- 第二张图片的“zoomSize”为 0.67 - 这很有效,但我需要将其更改为不同的 zoomSize,这就是问题所在。
解决方案
平移和缩放 dc 非常复杂。它需要使用 3 个独立的坐标系,并且很容易意外地在错误的坐标系中工作。
这是我不久前写的一个例子,它展示了如何进行计算,以使 dc 可以平移和缩放。
听起来您对 pan 部分不感兴趣,因此您可以忽略所有允许用户设置自己的 pan 的东西。但是,仍然需要使用平移矢量来进行缩放,以便将缩放中心定位在正确的位置。
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/graphics.h>
#include <wx/dcbuffer.h>
class PanAndZoomCanvas:public wxWindow
{
public:
PanAndZoomCanvas(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxPoint &pos=wxDefaultPosition,
const wxSize &size=wxDefaultSize,
long style=0,
const wxString &name="PanAndZoomCanvas");
wxRect2DDouble GetUntransformedRect() const;
protected:
void DoDrawCanvas(wxGraphicsContext*);
private:
void OnPaint(wxPaintEvent&);
void OnMouseWheel(wxMouseEvent&);
void OnLeftDown(wxMouseEvent&);
void OnMotion(wxMouseEvent&);
void OnLeftUp(wxMouseEvent&);
void OnCaptureLost(wxMouseCaptureLostEvent&);
void ProcessPan(const wxPoint&,bool);
void FinishPan(bool);
int m_zoomFactor;
wxPoint2DDouble m_panVector;
wxPoint2DDouble m_inProgressPanVector;
wxPoint m_inProgressPanStartPoint;
bool m_panInProgress;
};
PanAndZoomCanvas::PanAndZoomCanvas(wxWindow *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size,
long style, const wxString &name)
:wxWindow(parent, id, pos, size, style, name)
{
Bind(wxEVT_PAINT,&PanAndZoomCanvas::OnPaint,this);
Bind(wxEVT_MOUSEWHEEL,&PanAndZoomCanvas::OnMouseWheel,this);
Bind(wxEVT_LEFT_DOWN,&PanAndZoomCanvas::OnLeftDown,this);
SetBackgroundStyle(wxBG_STYLE_PAINT);
m_zoomFactor = 100;
m_panVector = wxPoint2DDouble(0,0);
m_inProgressPanStartPoint = wxPoint(0,0);
m_inProgressPanVector = wxPoint2DDouble(0,0);
m_panInProgress = false;
}
void PanAndZoomCanvas::DoDrawCanvas(wxGraphicsContext* gc)
{
gc->SetPen(*wxBLACK_PEN);
wxGraphicsPath path = gc->CreatePath();
path.MoveToPoint(100,100);
path.AddLineToPoint(300,100);
path.AddLineToPoint(300,300);
path.CloseSubpath();
gc->StrokePath(path);
}
void PanAndZoomCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxAutoBufferedPaintDC dc(this);
dc.Clear();
wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
if ( gc )
{
double a = m_zoomFactor / 100.0;
wxPoint2DDouble totalPan = m_panVector + m_inProgressPanVector;
gc->Translate(-totalPan.m_x, -totalPan.m_y);
gc->Scale(a, a);
DoDrawCanvas(gc);
delete gc;
}
}
void PanAndZoomCanvas::OnMouseWheel(wxMouseEvent& event)
{
if ( m_panInProgress )
{
FinishPan(false);
}
int rot = event.GetWheelRotation();
int delta = event.GetWheelDelta();
int oldZoom = m_zoomFactor;
m_zoomFactor += 10*(rot/delta);
if ( m_zoomFactor<10 )
{
m_zoomFactor = 10;
}
if ( m_zoomFactor>800)
{
m_zoomFactor = 800;
}
double a = oldZoom / 100.0;
double b = m_zoomFactor / 100.0;
// Set the panVector so that the point below the cursor in the new
// scaled/panned cooresponds to the same point that is currently below it.
wxPoint2DDouble uvPoint = event.GetPosition();
wxPoint2DDouble stPoint = uvPoint + m_panVector;
wxPoint2DDouble xypoint = stPoint/a;
wxPoint2DDouble newSTPoint = b * xypoint;
m_panVector = newSTPoint - uvPoint;
Refresh();
}
void PanAndZoomCanvas::ProcessPan(const wxPoint& pt, bool refresh)
{
m_inProgressPanVector = m_inProgressPanStartPoint - pt;
if ( refresh )
{
Refresh();
}
}
void PanAndZoomCanvas::FinishPan(bool refresh)
{
if ( m_panInProgress )
{
SetCursor(wxNullCursor);
if ( HasCapture() )
{
ReleaseMouse();
}
Unbind(wxEVT_LEFT_UP, &PanAndZoomCanvas::OnLeftUp, this);
Unbind(wxEVT_MOTION, &PanAndZoomCanvas::OnMotion, this);
Unbind(wxEVT_MOUSE_CAPTURE_LOST, &PanAndZoomCanvas::OnCaptureLost, this);
m_panVector += m_inProgressPanVector;
m_inProgressPanVector = wxPoint2DDouble(0,0);
m_panInProgress = false;
if ( refresh )
{
Refresh();
}
}
}
wxRect2DDouble PanAndZoomCanvas::GetUntransformedRect() const
{
double a = m_zoomFactor / 100.0;
wxSize sz = GetSize();
wxPoint2DDouble zero = m_panVector/a;
return wxRect2DDouble(zero.m_x, zero.m_y, sz.GetWidth()/a, sz.GetHeight()/a);
}
void PanAndZoomCanvas::OnLeftDown(wxMouseEvent& event)
{
wxCursor cursor(wxCURSOR_HAND);
SetCursor(cursor);
m_inProgressPanStartPoint = event.GetPosition();
m_inProgressPanVector = wxPoint2DDouble(0,0);
m_panInProgress = true;
Bind(wxEVT_LEFT_UP, &PanAndZoomCanvas::OnLeftUp, this);
Bind(wxEVT_MOTION, &PanAndZoomCanvas::OnMotion, this);
Bind(wxEVT_MOUSE_CAPTURE_LOST, &PanAndZoomCanvas::OnCaptureLost, this);
CaptureMouse();
}
void PanAndZoomCanvas::OnMotion(wxMouseEvent& event)
{
ProcessPan(event.GetPosition(), true);
}
void PanAndZoomCanvas::OnLeftUp(wxMouseEvent& event)
{
ProcessPan(event.GetPosition(), false);
FinishPan(true);
}
void PanAndZoomCanvas::OnCaptureLost(wxMouseCaptureLostEvent&)
{
FinishPan(true);
}
class MyFrame : public wxFrame
{
public:
MyFrame(wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE );
};
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos
, wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
PanAndZoomCanvas* canvas = new PanAndZoomCanvas(this);
}
class myApp : public wxApp
{
public:
virtual bool OnInit()
{
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(myApp);
在 Windows 上,这看起来像这样:
推荐阅读
- c++ - 为什么导入 Mixed Native/CLR lib/dll 的本机 C++ 应用程序不会在混合 lib/dll 中的外部变量上调用 ctor/dtor
- javascript - Shopping Cart calculation with JQuery
- mysql - 编写语句以使用 group by 而不是 group by 表达式创建报告错误
- javascript - 诺克测试的正则表达式匹配失败
- excel - 使用powershell过滤和删除excel中的行
- python - 在 Django 模板中将长 {% with %} 分配分成多行
- c - 谁能弄清楚为什么我的将句子拆分为单词的程序(在 C 中)不起作用?
- regex - 正则表达式在匹配字符的行中查找第一次出现的字符
- typescript - 如何创建嵌套的 d.ts 文件?
- akka-stream - 如何从服务器端终止 akka websocket 连接?