KdTree 3D transform

2022. 11. 29. 14:29학교수업

source.cpp

#include <iostream>
#include "GL\glut.h"
#include "Vec3.h"
#include "Particle.h"
#include "HashTable.h"
#include "QuadTree.h"
#include "KdTree.h"
#include "KdTree3D.h"
#include <vector>

using namespace std;

#define NUM_PARTICLE 10000

//#define HASH_TABLE
//#define QUAD_TREE
//#define KD_TREE
#define KD_TREE_3D

bool userDraw = true;

vector<Particle*> m_Particles;
HashTable* m_Hashing;
QuadTree* m_QuadTree;
KdTree* m_KdTree;
KdTree3D* m_KdTree3d;

#ifdef KD_TREE_3D
	float _zoom = 15.0f; // 화면 확대,축소
	float _rot_x = 0.0f; // x축 회전
	float _rot_y = 0.001f; // y축 회전
	float _trans_x = 0.0f; // x축 이동
	float _trans_y = 0.0f; // y축 이동
	int _last_x = 0; // 이전 마우스 클릭 x위치
	int _last_y = 0; // 이전 마우스 클릭 y위치
unsigned char _buttons[3] = { 0 }; // 마우스 상태(왼쪽,오른쪽,휠 버튼)
#endif

void InitParticles(void)
{
	for (int i = 0; i < NUM_PARTICLE; i++) {
		double x = (double)(rand()) / RAND_MAX;
		double y = (double)(rand()) / RAND_MAX;
		double sdf1 = x * x + y * y - 0.4 * 0.4;
		double sdf2 = (1.0 - x) * (1.0 - x) + (1.0 - y) * (1.0 - y) - 0.4 * 0.4;
		double sdf3 = (0.5 - x) * (0.5 - x) + (0.5 - y) * (0.5 - y) - 0.3 * 0.3;
		double sdf = fmin(fmin(sdf1, sdf2), sdf3);
		if (sdf <= 0.0) {
			m_Particles.push_back(new Particle(false, Vec3<double>(x, y, 0.0)));
		}
	}
}

void InitParticles3D(void)
{
	for (int i = 0; i < NUM_PARTICLE; i++) {
		double x = (double)(rand()) / RAND_MAX;
		double y = (double)(rand()) / RAND_MAX;
		double z = (double)(rand()) / RAND_MAX;
		double sdf1 = x * x + y * y + z * z - 0.3 * 0.3;
		double sdf2 = (1.0 - x) * (1.0 - x) + (1.0 - y) * (1.0 - y) + (1.0 - z) * (1.0 - z) - 0.4 * 0.4;
		double sdf3 = (0.5 - x) * (0.5 - x) + (0.5 - y) * (0.5 - y) + (0.5 - z) * (0.5 - z) - 0.3 * 0.3;
		double sdf = fmin(fmin(sdf1, sdf2), sdf3);
		if (sdf <= 0.0) {
			m_Particles.push_back(new Particle(false, Vec3<double>(x, y, z)));
		}
	}
}

void InitFlag(void)
{
	for (auto p : m_Particles) {
		p->m_Active = false;
		p->m_Collision = false;
	}
}

void Init(void)
{
	glEnable(GL_DEPTH_TEST);

#ifdef QUAD_TREE
	InitParticles();
	m_QuadTree = new QuadTree(7, 2);
	m_QuadTree->BuildTree(m_Particles);
	m_QuadTree->Query(m_Particles, 0.08, 33);
#endif

#ifdef HASH_TABLE
	InitParticles();
	m_Hashing = new HashTable(30);
	m_Hashing->Sort(m_Particles);
	m_Hashing->Query(m_Particles, 0.08, 33);
#endif

#ifdef KD_TREE
	InitParticles();
	m_KdTree = new KdTree(100);
	m_KdTree->BuildTree(m_Particles);
	m_KdTree->Query(m_Particles, 0.08, 33);
#endif

#ifdef KD_TREE_3D
	InitParticles3D();
	m_KdTree3d = new KdTree3D(50);
	m_KdTree3d->BuildTree(m_Particles);
	m_KdTree3d->Query(m_Particles, 0.08, 33);
#endif
}

void Rendering(void)
{
	if (userDraw) {
#ifdef QUAD_TREE
		m_QuadTree->Darw();
#endif

#ifdef HASH_TABLE
		m_Hashing->Draw();
#endif

#ifdef KD_TREE
		m_KdTree->Darw();
#endif
#ifdef KD_TREE_3D
		m_KdTree3d->Draw();
#endif
	}

	glPushMatrix();
	glDisable(GL_LIGHTING);
	glPushMatrix();
	glPointSize(2.0);
	glEnable(GL_POINT_SMOOTH);
	glBegin(GL_POINTS);
	for (auto p : m_Particles) {
		glColor3f(0.0f, 0.0f, 0.0f);
		if (p->m_Active) {
			glColor3f(1.0f, 0.0f, 0.0f);
		}
		if (p->m_Collision) {
			glColor3f(1.0f, 1.0f, 0.0f);
		}
		auto pos = p->m_Pos;
		glVertex3f((float)pos.x(), (float)pos.y(), (float)pos.z());
	}
	glEnd();
	glPopMatrix();
	glEnable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 1.0f);
	glPopMatrix();


}

void Display(void)
{
	glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glTranslatef(0, 0, -_zoom);
	glTranslatef(_trans_x, _trans_y, 0);
	glRotatef(_rot_x, 1, 0, 0);
	glRotatef(_rot_y, 0, 1, 0);
	////glTranslatef(0.3, 0, 0);
	//glTranslatef(0, -0.3, 0);
	//glRotatef(45.0f, 1, 0, 0);
	//glRotatef(45.0f, 0, 1, 0);

	Rendering();
	glutSwapBuffers();
}

void Reshape(int w, int h)
{
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	double r = (float)w / h;
	double xw = 1.0 * r;
	double yw = 1.0 / r;
	if (w < h) {
		glOrtho(-0.0, 1.0, -(yw - 1) / 2, (yw + 1) / 2, -10, 100);
	}
	else {
		glOrtho(-(xw - 1) / 2, (xw + 1) / 2, -0.0, 1.0, -10, 100);
	}
	glMatrixMode(GL_MODELVIEW);
	glutPostRedisplay();
}

void Keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 'Q':
	case 'q':
		exit(0);
	case 's':
	case 'S':
		InitFlag();
#ifdef QUAD_TREE
		m_QuadTree->Query(m_Particles, 0.08, rand() % m_Particles.size());
#endif

#ifdef HASH_TABLE
		m_Hashing->Query(m_Particles, 0.08, rand() % m_Particles.size());
#endif

#ifdef KD_TREE
		m_KdTree->Query(m_Particles, 0.08, rand() % m_Particles.size());
#endif
#ifdef KD_TREE_3D
		m_KdTree3d->Query(m_Particles, 0.08, rand() % m_Particles.size());
#endif
		break;
	case 'd':
	case 'D':
		userDraw = !userDraw;
		break;
	}
	glutPostRedisplay();
}

#ifdef KD_TREE_3D
void Mouse(int button, int state, int x, int y)
{
	// 이전 마우스 클릭 위치
	_last_x = x;
	_last_y = y;

	switch (button)
	{
	case GLUT_LEFT_BUTTON:
		_buttons[0] = state == GLUT_DOWN ? 1 : 0;
		break;
	case GLUT_MIDDLE_BUTTON:
		_buttons[1] = state == GLUT_DOWN ? 1 : 0;
		break;
	case GLUT_RIGHT_BUTTON:
		_buttons[2] = state == GLUT_DOWN ? 1 : 0;
		break;
	default:
		break;
	}
	glutPostRedisplay(); // 화면갱신
}

void Motion(int x, int y)
{
	int diff_x = x - _last_x;
	int diff_y = y - _last_y;
	_last_x = x;
	_last_y = y;

	if (_buttons[2]) {
		_zoom -= (float)0.02f * diff_x;
	}
	else if (_buttons[1]) {
		_trans_x += (float)0.02f * diff_x;
		_trans_y -= (float)0.02f * diff_y;
	}
	else if (_buttons[0]) {
		_rot_x += (float)0.2f * diff_y;
		_rot_y += (float)0.2f * diff_x;
	}
	glutPostRedisplay(); // 화면갱신
}
#endif

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Multi-Resolution Grids: HashTable, QuadTree, KdTree");
	glutDisplayFunc(Display);
	glutReshapeFunc(Reshape);
#ifdef KD_TREE_3D
	glutMouseFunc(Mouse); // 마우스 클릭 이벤트	
	glutMotionFunc(Motion); // 마우스 이동 이벤트
#endif
	glutKeyboardFunc(Keyboard);
	Init();
	glutMainLoop();
}

kdTree3D.h

#ifndef __KD_TREE3D_H__
#define __KD_TREE3D_H__

#pragma once
#include "Particle.h"
#include "Vec3.h"
#include <vector>
#include <algorithm>

using namespace std;

class KdNode3D
{
public:
	Vec3<double>		m_Min;
	Vec3<double>		m_Max;
	vector<Particle*>	m_Particles;
	KdNode3D* m_ChildNodes[2];
public:
	KdNode3D(void);
	KdNode3D(Vec3<double> min, Vec3<double> max);
	KdNode3D(int depth, Vec3<double> min, Vec3<double> max);
	~KdNode3D(void) {}
public:
	inline Vec3<double> GetCenter(void) { return (m_Max + m_Min) / 2.0; }
public:
	bool	IsEmpty(void);
	bool	IsContain(Vec3<double> p);
	bool	IsContain(Vec3<double> p, double r);
	bool	IsIntersect(Vec3<double> p, double r);
	void	Subdivide(void);
};

class KdTree3D
{
public:
	int					m_Bucket;
	KdNode3D* m_Root;
	vector<KdNode3D*>	m_DrawNodes; //render
public:
	KdTree3D();
	KdTree3D(int bucket)
	{
		m_Bucket = bucket;
	}
	~KdTree3D();
public:
	void	BuildTree(vector<Particle*>& particles);
	void	Query(vector<Particle*>& particles, double r, int index);
public:
	void	Draw(void);
};

#endif

KdTree3D.cpp

#include "KdTree3D.h"
#include "GL\glut.h"

KdNode3D::KdNode3D(void)
{
	for (int i = 0; i < 2; i++) {
		m_ChildNodes[i] = nullptr;
	}
}

KdNode3D::KdNode3D(Vec3<double> min, Vec3<double> max)
{
	m_Min = min;
	m_Max = max;
	for (int i = 0; i < 2; i++) {
		m_ChildNodes[i] = nullptr;
	}
}

KdNode3D::KdNode3D(int depth, Vec3<double> min, Vec3<double> max)
{
	m_Min = min;
	m_Max = max;
	for (int i = 0; i < 2; i++) {
		m_ChildNodes[i] = nullptr;
	}
}

bool KdNode3D::IsContain(Vec3<double> p)
{
	if (p.x() >= m_Min.x() && p.x() <= m_Max.x() && p.y() >= m_Min.y() && p.y() <= m_Max.y() && p.z() >= m_Min.z() && p.z() <= m_Max.z()) {
		return true;
	}
	return false;
}

bool KdNode3D::IsIntersect(Vec3<double> p, double r)
{
	double dist = 0.0;
	for (int i = 0; i < 2; i++) {
		if (p(i) < m_Min(i)) {
			double d = m_Min(i) - p(i);
			dist += d * d;
		}
		else if (p(i) > m_Max(i)) {
			double d = p(i) - m_Max(i);
			dist += d * d;
		}
	}
	return dist <= r * r;
}

bool KdNode3D::IsEmpty(void)
{
	return m_ChildNodes[0] == nullptr;
}

bool KdNode3D::IsContain(Vec3<double> p, double r)
{
	double minx = p.x() - r;
	double maxx = p.x() + r;
	double miny = p.y() - r;
	double maxy = p.y() + r;
	double minz = p.z() - r;
	double maxz = p.z() + r;
	return (minx >= m_Min.x() && maxx <= m_Max.x() && miny >= m_Min.y() && maxy <= m_Max.y() && minz >= m_Min.z() && maxz <= m_Max.z());
}

void KdNode3D::Subdivide(void)
{
	for (int i = 0; i < 2; i++) {
		m_ChildNodes[i] = new KdNode3D();
	}

	auto corssVec = m_Max - m_Min;
	int mid = m_Particles.size() / 2;
	int splitAxis;
	if (corssVec.x() >= corssVec.y())
	{
		if (corssVec.x() >= corssVec.z())
		{
			splitAxis = 0;
		}
		else
		{
			splitAxis = 2;
		}
	}
	else
	{
		if (corssVec.y() >= corssVec.z())
		{
			splitAxis = 1;
		}
		else
		{
			splitAxis = 2;
		}
	}
	nth_element(m_Particles.begin(), m_Particles.begin() + mid, m_Particles.end(), [splitAxis](Particle* a, Particle* b) {return a->m_Pos(splitAxis) < b->m_Pos(splitAxis); });

	auto separation = m_Particles[mid]->m_Pos(splitAxis);
	auto localMin = m_Min;
	auto localMax = m_Max;
	localMin[splitAxis] = separation;
	localMax[splitAxis] = separation;

	m_ChildNodes[0]->m_Min = m_Min;
	m_ChildNodes[0]->m_Max = localMax;
	m_ChildNodes[1]->m_Min = localMin;
	m_ChildNodes[1]->m_Max = m_Max;

	// Transfer particles
	m_ChildNodes[0]->m_Particles.clear();
	m_ChildNodes[0]->m_Particles.assign(m_Particles.begin(), m_Particles.begin() + mid);
	m_ChildNodes[1]->m_Particles.clear();
	m_ChildNodes[1]->m_Particles.assign(m_Particles.begin() + mid, m_Particles.end());
	m_Particles.clear();
}

KdTree3D::KdTree3D()
{
}

KdTree3D::~KdTree3D()
{
}

void KdTree3D::BuildTree(vector<Particle*>& particles)
{
	m_Root = new KdNode3D(1, Vec3<double>(-0.05, -0.05, -0.05), Vec3<double>(1.05, 1.05, 1.05));

	// Transfer particles
	for (auto p : particles) {
		m_Root->m_Particles.push_back(p);
	}

	vector<KdNode3D*> queue;
	queue.push_back(m_Root);

	int debug = 0;

	while (queue.size() != 0) {
		auto node = queue[0];
		m_DrawNodes.push_back(node);
		queue.erase(queue.begin());
		if (node->m_Particles.size() > m_Bucket) {
			node->Subdivide();
			for (int i = 0; i < 2; i++) {
				queue.push_back(node->m_ChildNodes[i]);
			}
		}
	}
	printf("KdTree : build tree!\n");
}

void KdTree3D::Query(vector<Particle*>& particles, double r, int index)
{
	auto pos = particles[index]->m_Pos;

	vector<KdNode3D*> queue;
	queue.push_back(m_Root);

	while (queue.size() != 0) {
		auto node = queue[0];
		queue.erase(queue.begin());
		bool contain = node->IsContain(pos, r);
		bool intersect = node->IsIntersect(pos, r);
		if (contain == true || intersect == true) {
			for (auto p : node->m_Particles) {
				p->m_Active = true;
				double sdf = (p->m_Pos.x() - pos.x()) * (p->m_Pos.x() - pos.x()) + (p->m_Pos.y() - pos.y()) * (p->m_Pos.y() - pos.y()) + (p->m_Pos.z() - pos.z()) * (p->m_Pos.z() - pos.z()) - r * r;
				if (sdf <= 0.0) {
					p->m_Collision = true;
				}
			}
			if (node->IsEmpty() == false) {
				for (int i = 0; i < 2; i++) {
					queue.push_back(node->m_ChildNodes[i]);
				}
			}
		}
	}
}

void KdTree3D::Draw(void)
{
	glLineWidth(1.0);
	glDisable(GL_LIGHTING);
	glPushMatrix();
	for (auto n : m_DrawNodes) {
		glColor3f(0.0f, 0.0f, 1.0f);
		glBegin(GL_LINES);
		glVertex3f(n->m_Min.x(), n->m_Min.y(), n->m_Min.z());
		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Min.z());

		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Min.z());
		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Min.z());

		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Min.z());
		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Min.z());

		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Min.z());
		glVertex3f(n->m_Min.x(), n->m_Min.y(), n->m_Min.z());

		glVertex3f(n->m_Min.x(), n->m_Min.y(), n->m_Min.z());
		glVertex3f(n->m_Min.x(), n->m_Min.y(), n->m_Max.z());

		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Min.z());
		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Max.z());

		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Min.z());
		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Max.z());

		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Min.z());
		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Max.z());

		glVertex3f(n->m_Min.x(), n->m_Min.y(), n->m_Max.z());
		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Max.z());

		glVertex3f(n->m_Max.x(), n->m_Min.y(), n->m_Max.z());
		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Max.z());

		glVertex3f(n->m_Max.x(), n->m_Max.y(), n->m_Max.z());
		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Max.z());

		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Max.z());
		glVertex3f(n->m_Min.x(), n->m_Max.y(), n->m_Max.z());

		glEnd();
	}
	glPopMatrix();
	glEnable(GL_LIGHTING);
	glLineWidth(1.0);
}

'학교수업' 카테고리의 다른 글

데이터베이스 14주차  (0) 2022.12.06
컴퓨터 그래픽스 응용 13주차  (0) 2022.11.30
컴퓨터 그래픽스 응용 12주차  (0) 2022.11.23
데이터베이스 12주차  (0) 2022.11.22
컴퓨터그래픽스응용 11주차  (0) 2022.11.16