我正在尝试创建一个类似于以下内容的Voronoi图(这也是我目前的输出):
,我的问题是如何进行交互。 而且,我的意思是我希望能够设置黑点,然后将其调整为地图并创建Voronoi多边形。
我的项目的代码结构包含2个标头类,一个是计算Voronoi的头文件,第二个是位图,最后一个是main.cpp。
这些类如下所示:
voronoi.h
#pragma once
#include "stdafx.h"
#include "MyBitmap.h"
#include <windows.h>
#include <vector>
#include <string>
static int DistanceSqrd(const Point& point, int x, int y) {
int xd = x - point.x;
int yd = y - point.y;
return (xd * xd) + (yd * yd);
}
class Voronoi {
public:
void Make(MyBitmap* bmp, int count) {
bmp_ = bmp;
CreatePoints(count);
CreateColors();
CreateSites();
SetSitesPoints();
}
void CreateSites() { //voronoi triangulation mathematics
int w = bmp_->width(), h = bmp_->height(), d;
for (int hh = 0; hh < h; hh++) {
for (int ww = 0; ww < w; ww++) {
int ind = -1, dist = INT_MAX;
for (size_t it = 0; it < points_.size(); it++) {
const Point& p = points_[it];
d = DistanceSqrd(p, ww, hh); //lines between points
if (d < dist) {
dist = d;
ind = it;
}
}
if (ind > -1)
SetPixel(bmp_->hdc(), ww, hh, colors_[ind]);
else
__asm nop // should never happen!
}
}
}
void SetSitesPoints() {
for (const auto& point : points_) {
int x = point.x, y = point.y;
for (int i = -1; i < 2; i++)
for (int j = -1; j < 2; j++)
SetPixel(bmp_->hdc(), x + i, y + j, 0);
}
}
void CreatePoints(int count) {
const int w = bmp_->width() - 20, h = bmp_->height() - 20;
for (int i = 0; i < count; i++) {
points_.push_back({ rand() % w + 10, rand() % h + 10 }); //where the black points are placed.
}
}
void CreateColors() {
for (size_t i = 0; i < points_.size(); i++) {
DWORD c = RGB(255, 0,0); //red
DWORD d = RGB(0, 0, 255); //blue
colors_.push_back(c);
colors_.push_back(d);
}
}
vector<Point> points_;
vector<DWORD> colors_;
MyBitmap* bmp_;
};
这负责voronoi算法。
下一步MyBitmap.h:
#pragma once
#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <string>
using namespace std;
struct Point {
int x, y;
};
class MyBitmap {
public:
MyBitmap() : pen_(nullptr) {}
~MyBitmap() {
DeleteObject(pen_);
DeleteDC(hdc_);
DeleteObject(bmp_);
}
bool Create(int w, int h) {
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biBitCount = sizeof(DWORD) * 8;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = w;
bi.bmiHeader.biHeight = -h;
void *bits_ptr = nullptr;
HDC dc = GetDC(GetConsoleWindow());
bmp_ = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, &bits_ptr, nullptr, 0);
if (!bmp_) return false;
hdc_ = CreateCompatibleDC(dc);
SelectObject(hdc_, bmp_);
ReleaseDC(GetConsoleWindow(), dc);
width_ = w;
height_ = h;
return true;
}
void SetPenColor(DWORD clr) {
if (pen_) DeleteObject(pen_);
pen_ = CreatePen(PS_SOLID, 1, clr);
SelectObject(hdc_, pen_);
}
bool SaveBitmap(const char* path) {
HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
return false;
}
BITMAPFILEHEADER fileheader;
BITMAPINFO infoheader;
BITMAP bitmap;
GetObject(bmp_, sizeof(bitmap), &bitmap);
DWORD* dwp_bits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
ZeroMemory(dwp_bits, bitmap.bmWidth * bitmap.bmHeight * sizeof(DWORD));
ZeroMemory(&infoheader, sizeof(BITMAPINFO));
ZeroMemory(&fileheader, sizeof(BITMAPFILEHEADER));
infoheader.bmiHeader.biBitCount = sizeof(DWORD) * 8;
infoheader.bmiHeader.biCompression = BI_RGB;
infoheader.bmiHeader.biPlanes = 1;
infoheader.bmiHeader.biSize = sizeof(infoheader.bmiHeader);
infoheader.bmiHeader.biHeight = bitmap.bmHeight;
infoheader.bmiHeader.biWidth = bitmap.bmWidth;
infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof(DWORD);
fileheader.bfType = 0x4D42;
fileheader.bfOffBits = sizeof(infoheader.bmiHeader) + sizeof(BITMAPFILEHEADER);
fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
GetDIBits(hdc_, bmp_, 0, height_, (LPVOID)dwp_bits, &infoheader, DIB_RGB_COLORS);
DWORD wb;
WriteFile(file, &fileheader, sizeof(BITMAPFILEHEADER), &wb, nullptr);
WriteFile(file, &infoheader.bmiHeader, sizeof(infoheader.bmiHeader), &wb, nullptr);
WriteFile(file, dwp_bits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, nullptr);
CloseHandle(file);
delete[] dwp_bits;
return true;
}
HDC hdc() { return hdc_; }
int width() { return width_; }
int height() { return height_; }
private:
HBITMAP bmp_;
HDC hdc_;
HPEN pen_;
int width_, height_;
};
最后也是最重要的main.cpp:
// Voronoi Diagram Game.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <SDL_image.h>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <SDL.h>
#include "MyBitmap.h"
#include "Voronoi.h"
//Screen dimension constants
const int SCREEN_WIDTH = 740;
const int SCREEN_HEIGHT = 550;
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//Loads individual image
SDL_Surface* loadSurface(std::string path);
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//Current displayed PNG image
SDL_Surface* gImageSurface = NULL;
SDL_Rect sourceRect;
SDL_Rect destRect;
//InputHandler * handler = new InputHandler();
int m_count = 0;
bool init()
{
//Initialization flag
bool success = true;
//where on the screen it is shown
sourceRect.x = 20;
sourceRect.y = -10;
sourceRect.w = 10;
sourceRect.y = 10;
//how big the window is that the sprite is shown in
destRect.x = 0;
destRect.y = 0;
destRect.w = 740;
destRect.h = 550;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface(gWindow);
}
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load PNG surface
gImageSurface = SDL_LoadBMP("v.bmp");
if (gImageSurface == NULL)
{
printf("Failed to load PNG image!\n");
success = false;
}
return success;
}
void close()
{
//Free loaded image
SDL_FreeSurface(gImageSurface);
gImageSurface = NULL;
//Destroy window
SDL_DestroyWindow(gWindow);
gWindow = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
SDL_Surface* loadSurface(std::string path)
{
//The final optimized image
SDL_Surface* optimizedSurface = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Convert surface to screen format
optimizedSurface = SDL_ConvertSurface(loadedSurface, gScreenSurface->format, NULL);
if (optimizedSurface == NULL)
{
printf("Unable to optimize image %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
return optimizedSurface;
}
int main(int argc, char* args[])
{
MyBitmap bmp;
Voronoi v;
srand(GetTickCount());
int clickCount = 0;
bmp.Create(512, 512); //how big the bitmap is
bmp.SetPenColor(0);
v.Make(&bmp, 50);
//Start up SDL and create window
if (!init())
{
printf("Failed to initialize!\n");
}
else
{
// create the newbmp
bmp.SaveBitmap("v.bmp");
//Load media
if (!loadMedia())
{
printf("Failed to load media!\n");
}
else
{
//Main loop flag
bool quit = false;
SDL_Event e;
while (!quit)
{
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
else if (e.type == SDL_MOUSEBUTTONDOWN) {
if (e.button.button == SDL_BUTTON_LEFT) {
//TO DO: create a black dot
//TO DO: add voronoi polygon according to the others
cout << "left button pressed" << endl;
clickCount++;
}
}
}
//BitBlt(GetDC(GetConsoleWindow()), 20, 20, 512, 512, bmp.hdc(), 0, 0, SRCCOPY); //shows it in the cmd
//Apply the image
SDL_BlitSurface(gImageSurface, &destRect, gScreenSurface, &sourceRect);
//Update the surface
SDL_UpdateWindowSurface(gWindow);
}
}
}
//Free resources and close SDL
close();
return 0;
}
总而言之,我希望能够放置能够适应其他Voronoi多边形的黑点/ Voronoi多边形,但我还没有找到一种方法。
必须通过单击鼠标和我现在正在处理的鼠标位置来完成。
如果它启动没有任何Voronoi多边形的Blanco也没关系。
我从here得到了一个很好的例子。
我对它的功能有一个大概的了解(除了MyBitmap.h),但是我从here获得了源代码。
答案 0 :(得分:0)
我终于得到了答案。 我在voronoi中制作了一个方法,该方法可以获取鼠标位置上的点,如下所示:
void GetPointsOnMousePosition() {
int x, y;
SDL_GetMouseState(&x, &y);
int d;
isClicked = true;
cout << x << " and " << y << endl;
points_.push_back({ x, y }); //where the black points are placed.
CreateColors();
CreateSites();
SetSitesPoints();
}
这将获取鼠标位置并将其设置在x和y上,并将其推入点数组。 在main.cpp中,我要求pointsOnMousePosition方法重新加载了bmp并将其保存如下:
if (e.button.button == SDL_BUTTON_LEFT) {
//bmp.~MyBitmap();
cout << "left button pressed" << endl;
v.GetPointsOnMousePosition();
//adjusts the voronoi map
bmp.SaveBitmap("v.bmp");
gImageSurface = SDL_LoadBMP("v.bmp");
cout << "points added!" << endl;
isClicked = false;
}
希望这对以后的人有所帮助。