#include "stdafx.h"
#include <iostream>
#include <List>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <math.h>
#include <Windows.h>
#include <cstdlib>
#include <ctime>
using namespace std;
#define Width 600
#define Height 640
typedef struct Point
{
GLint x, y;
} Point;
typedef struct RGB_type
{
float red, green, blue;
} RGB_type;
RGB_type pixels[Width*Height];
GLFWwindow* window;
bool running = true;
int mouseX, mouseY;
int oldMouseX = -1, oldMouseY = -1;
int FirstMouseX = -1, FirstMouseY = -1;
int oldY = 0, firstY1;
int figCount = 0;
bool last = false;
float r, g, b;
const double EPS = 1E-9;
struct TPoint
{
int x, y;
short mode;
int test;
TPoint() : x(0), y(0) { ; }
TPoint(int theX, int theY) : x(theX), y(theY) { ; }
bool operator< (const TPoint & p) const
{
return x < p.x - EPS || abs(x - p.x) < EPS && y < p.y - EPS;
}
bool operator>(const TPoint & p) const
{
return x > p.x - EPS || abs(x - p.x) > EPS && y > p.y - EPS;
}
bool operator== (const TPoint & p) const
{
return x == p.x && y == p.y;
}
};
struct TNode
{
TPoint point;
TNode* next;
TNode* prev;
bool operator== (const TNode & n) const
{
return point.x == n.point.x && point.y == n.point.y;
}
bool operator< (const TNode & n) const
{
return point.x < n.point.x;
}
};
TNode* mainfig = NULL;
TNode* secondfig = NULL;
struct line {
double a, b, c;
line() {}
line(TPoint p, TPoint q) {
a = p.y - q.y;
b = q.x - p.x;
c = -a * p.x - b * p.y;
norm();
}
void norm() {
double z = sqrt(a*a + b*b);
if (abs(z) > EPS)
a /= z, b /= z, c /= z;
}
double dist(TPoint p) const {
return a * p.x + b * p.y + c;
}
};
#define det(a,b,c,d) (a*d-b*c)
inline bool betw(double l, double r, double x) {
return min(l, r) <= x + EPS && x <= max(l, r) + EPS;
}
inline bool intersect_1d(double a, double b, double c, double d) {
if (a > b) swap(a, b);
if (c > d) swap(c, d);
return max(a, c) <= min(b, d) + EPS;
}
bool intersect(TPoint a, TPoint b, TPoint c, TPoint d, TPoint & left, TPoint & right) {
if (!intersect_1d(a.x, b.x, c.x, d.x) || !intersect_1d(a.y, b.y, c.y, d.y))
return false;
line m(a, b);
line n(c, d);
double zn = det(m.a, m.b, n.a, n.b);
if (abs(zn) < EPS) {
if (abs(m.dist(c)) > EPS || abs(n.dist(a)) > EPS)
return false;
if (b < a) swap(a, b);
if (d < c) swap(c, d);
left = max(a, c);
right = min(b, d);
return true;
}
else {
left.x = right.x = -det(m.c, m.b, n.c, n.b) / zn;
left.y = right.y = -det(m.a, m.c, n.a, n.c) / zn;
return betw(a.x, b.x, left.x)
&& betw(a.y, b.y, left.y)
&& betw(c.x, d.x, left.x)
&& betw(c.y, d.y, left.y);
}
}
int Size(TNode *list)
{
TNode *iter = list;
int i;
for (i = 1;; i++)
{
iter = iter->next;
if (iter == list)
break;
}
return i;
}
TNode* Push(TNode*& list, const TPoint& point)
{
TNode* node = new TNode;
node->point = point;
if (list == NULL)
{
node->next = node->prev = node;
}
else
{
node->next = list;
node->prev = list->prev;
list->prev = node;
node->prev->next = node;
}
list = node;
return list;
}
TPoint Pop(TNode*& list)
{
if (list == NULL)
{
return TPoint();
}
TPoint val(list->point);
TNode* node = list;
if ((list->next == list) || (list->prev == list))
{
list = NULL;
}
else
{
list->prev->next = list->next;
list->next->prev = list->prev;
list = list->next;
}
delete node;
return val;
}
std::ostream& operator << (std::ostream& os, const TPoint& point)
{
os << "[" << point.x << "," << point.y << "]";
return os;
}
std::ostream& operator << (std::ostream& os, const TNode* node)
{
if (node)
{
const TNode* cursor = node;
for (; cursor->next != node; cursor = cursor->next)
{
os << cursor->point << " ";
}
os << cursor->point;
}
else
{
os << "nil";
}
return os;
}
int GetIndex(int x, int y)
{
return (x + (Height - y)*Width);
}
void SetPixel(int x, int y, int c)
{
int ind = GetIndex(x, y);
pixels[ind].red = r;
pixels[ind].blue = g;
pixels[ind].green = b;
}
void Fill()
{
for (int i = 0; i < Height - 1; i++)
{
bool flag = false;
for (int j = 1; j < Width - 1; j++)
{
if (pixels[GetIndex(j, i)].blue == 1)
flag = !flag;
flag ? SetPixel(j, i, 1) : SetPixel(j, i, 0);
}
}
}
void DrawCycle(int x, int y, int d1, int d2, int s1, int s2)
{
int e2 = 2 * d1 - d2;
for (int i = 0; i < d2 + last; i++)
{
SetPixel(x, y, 1);
while (e2 >= 0)
{
x += s1;
e2 -= 2 * d2;
}
y += s2;
e2 += 2 * d1;
}
}
TNode *SearchFor(TNode *in, TNode *who)
{
TNode *iter = in;
for (;;)
{
if (iter->point == who->point)
return iter;
iter = iter->next;
if (iter == in)
break;
}
return NULL;
}
void Swap(TNode *a, TNode *b)
{
TPoint p = a->point;
a->point = b->point;
b->point = p;
}
bool Compare(TNode *a, TNode *b)
{
return a->point.x < b->point.x;
}
void SortList(TNode *list, bool order)
{
int k = Size(list);
int i, j;
TNode *n2;
for (i = 0; i < k - 1; i++)
for (n2 = list, j = 0; j < k - i - 1; j++, n2 = n2->next)
{
if (Compare(n2, n2->next))
{
Swap(n2, n2->next);
}
if (!order)
Swap(n2, n2->next);
}
}
void DrawLine(int x0, int y0, int x1, int y1)
{
TPoint p(x0, y0);
p.x = x0;
p.y = y0;
p.mode = 0;
p.test = 0;
if (figCount == 0)
{
Push(mainfig, p);
}
if (figCount == 1)
{
Push(secondfig, p);
}
if (oldY == 0)
firstY1 = y1;
int x = x0;
int y = y0;
int lastY;
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int signX = (x0 < x1) ? 1 : -1;
int signY = (y0 < y1) ? 1 : -1;
if (dy > dx)
{
int e2 = 2 * dx - dy;
for (int i = 0; i <= dy + last; i++)
{
SetPixel(x, y, 1);
while (e2 >= 0)
{
x += signX;
e2 -= 2 * dy;
}
y += signY;
e2 += 2 * dx;
}
}
else
{
int e2 = 2 * dy - dx;
for (int i = 0; i <= dx + last; i++)
{
SetPixel(x, y, 1);
while (e2 >= 0)
{
y += signY;
e2 -= 2 * dx;
}
x += signX;
e2 += 2 * dy;
}
}
}
void PostFilter()
{
RGB_type *pNew = nullptr;
pNew = new RGB_type[Width*Height];
double errR, errG, errB;
for (int y = 1; y < Height - 1; y++)
for (int x = 1; x < Width - 1; x++)
{
errR = errG = errB = 0;
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
errR += pixels[GetIndex(j + x, i + y)].red;
errG += pixels[GetIndex(j + x, i + y)].green;
errB += pixels[GetIndex(j + x, i + y)].blue;
}
}
errR /= 9; errB /= 9; errG /= 9;
pNew[GetIndex(x, y)].red = errR;
pNew[GetIndex(x, y)].green = errG;
pNew[GetIndex(x, y)].blue = errB;
}
for (int i = 0; i < Width*Height - 1; i++)
{
pixels[i].blue = pNew[i].blue;
pixels[i].red = pNew[i].red;
pixels[i].green = pNew[i].green;
}
delete[]pNew;
}
void Clear(bool full)
{
for (int i = 0; i < Width*Height; i++)
pixels[i] = { 0, 0, 0 };
oldMouseX = -1; oldMouseY = -1;
FirstMouseX = -1; FirstMouseY = -1;
last = 0;
if (full)
{
while (mainfig)
{
Pop(mainfig);
}
while (secondfig)
{
Pop(secondfig);
}
figCount = 0;
}
}
void printNode(TNode *node)
{
TNode *node1;
int i;
for (node1 = node;;)
{
cout << node1->point << " mode: " << node1->point.mode << " test: " << node1->point.test << endl;
node1 = node1->next;
if (node1 == node)
break;
}
cout << endl;
}
void PutAfter(TNode *source, TNode *add)
{
add->prev->next = source->next;
source->next->prev = add->prev;
add->prev = source;
source->next = add;
}
TNode *IntersectSearch(TNode *node1, TNode *node2, bool check)
{
TNode *inter = NULL;
TNode *iter = node2;
TNode *helper;
for (;;)
{
helper = iter->next;
TPoint p;
if (intersect(node1->point, node1->next->point, iter->point, iter->next->point, p, p))
{
TNode *n = new TNode;
p.mode = 2;
p.test = 0;
if (check)
{
n->point = p;
n->point = p;
iter->next = n;
n->prev = iter;
n->next = helper;
helper->prev = n;
}
Push(inter, p);
}
iter = helper;
if (iter == node2)
break;
}
return inter;
}
void CheckPoints(TNode *main)
{
TNode *n = NULL;
Push(n, main->point);
TPoint p = { 0, 0 };
Push(n, p);
TNode *inter = IntersectSearch(n, mainfig, false);
int flag = 0, k = 0;
if (inter != NULL)
{
k = Size(inter);
}
if (k % 2 != 0)
{
flag = 1;
main->point.mode = 1;
}
for (n = main;;)
{
if (n->point.mode == 2)
{
flag = 1 - flag;
}
else
{
n->point.mode = flag;
}
n = n->next;
if (n == main)
break;
}
n = main;
for (;;)
{
if (n->point.mode != 2)
{
flag = n->point.mode + 1;
n->point.mode = 0;
}
else
{
n->point.mode = flag;
flag = 3 - flag;
}
n = n->next;
if (n == main)
break;
}
}
void lookForIntersection()
{
TNode *iter, *helper, *inter = NULL;
iter = secondfig;
for (;;)
{
helper = iter->next;
inter = IntersectSearch(iter, mainfig, true);
if (inter != NULL)
{
if (iter->point < iter->next->point)
SortList(inter, false);
else
SortList(inter, true);
PutAfter(iter, inter);
}
iter = helper;
if (iter == secondfig)
break;
}
cout << secondfig << endl;
cout << Size(mainfig) << mainfig << endl;
}
void DisplayNode(TNode *main, bool newc)
{
if (newc)
{
r = (float)(rand() % 100) / 100;
g = (float)(rand() % 100) / 100;
b = (float)(rand() % 100) / 100;
}
TNode *n = main;
for (;;)
{
DrawLine(n->point.x, n->point.y, n->next->point.x, n->next->point.y);
n = n->next;
if (n == main)
break;
}
}
TNode *Operation(TNode *main, int mode)
{
TNode *uni = NULL, *iter = main, *n = NULL;
int flag = 0, reverse = 0;
flag = 1;
n = main;
for (n = main;;)
{
Push(uni, n->point);
cout << n->point << endl;
n->point.test = 1;
if (n->point.mode != 0)
{
if (flag)
{
if (mode == 4)
reverse = 1;
iter = mainfig;
}
else
{
if (mode == 4)
reverse = 0;
iter = secondfig;
}
flag = 1 - flag;
while (!(iter->point == n->point))
iter = iter->next;
n = iter;
}
if (reverse)
n = n->prev;
else
n = n->next;
if (n == main)
{
break;
}
}
return uni;
}
void OperationCycle(int mode)
{
Clear(false);
TNode *n = secondfig;
if (mode == 3)
{
DisplayNode(mainfig, true);
DisplayNode(secondfig, true);
return;
}
int flag = 1;
for (;;)
{
if (n->point.test == 0 && ((n->point.mode == 2 && mode == 1) || (n->point.mode == 1 && (mode == 2 || mode == 4))))
{
cout << n->point << "<==" << endl;
TNode *u = Operation(n, mode);
DisplayNode(u, false);
while (u)
Pop(u);
flag = 0;
}
else
cout << endl;
n = n->next;
if (n == secondfig)
break;
}
if (flag)
{
if (mode == 2)
{
DisplayNode(mainfig, false);
DisplayNode(secondfig, true);
}
if (mode == 4)
{
DisplayNode(secondfig, true);
}
}
for (;;)
{
n->point.test = 0;
n = n->next;
if (n == secondfig)
break;
}
}
static void keyboard_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
running = false;
if (key == GLFW_KEY_D && action == GLFW_PRESS)
{
while (secondfig)
{
TPoint n = Pop(secondfig);
cout << n << n.mode << std::endl;
}
}
if (key == GLFW_KEY_S && action == GLFW_PRESS)
PostFilter();
if (key == GLFW_KEY_E && action == GLFW_PRESS)
{
last = true;
DrawLine(oldMouseX, oldMouseY, FirstMouseX, FirstMouseY);
oldMouseX = -1, oldMouseY = -1;
FirstMouseX = -1, FirstMouseY = -1;
oldY = 0;
r = (float)(rand() % 100) / 100;
g = (float)(rand() % 100) / 100;
b = (float)(rand() % 100) / 100;
if (figCount == 1)
{
lookForIntersection();
CheckPoints(secondfig);
printNode(secondfig);
}
figCount++;
}
if (key == GLFW_KEY_C && action == GLFW_PRESS)
Clear(true);
if (key == GLFW_KEY_I && action == GLFW_PRESS)
{
OperationCycle(1);
}
if (key == GLFW_KEY_U && action == GLFW_PRESS)
{
OperationCycle(2);
}
if (key == GLFW_KEY_O && action == GLFW_PRESS)
{
OperationCycle(3);
}
if (key == GLFW_KEY_Y && action == GLFW_PRESS)
{
OperationCycle(4);
}
}
static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT && oldMouseX != mouseX && oldMouseY != mouseY)
{
if (FirstMouseX == -1)
{
FirstMouseX = mouseX;
FirstMouseY = mouseY;
}
SetPixel(mouseX, mouseY, 1);
if (oldMouseX != -1)
{
DrawLine(oldMouseX, oldMouseY, mouseX, mouseY);
}
oldMouseX = mouseX;
oldMouseY = mouseY;
}
if (button == GLFW_MOUSE_BUTTON_RIGHT)
{
}
}
static void cursor_callback(GLFWwindow* window, double x, double y)
{
mouseX = x;
mouseY = y;
}
int main()
{
if (!glfwInit())
{
cerr << "error in GLFW";
return -1;
}
window = glfwCreateWindow(Width, Height, "GL", NULL, NULL);
if (window == NULL){
cerr << "Невозможно открыть окно GLFW. Если у вас Intel GPU, то он не поддерживает версию 3.3\n";
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
cerr << "Невозможно инициализировать GLEW\n";
return -1;
}
for (int i = 0; i < Width; i++)
{
for (int j = 0; j < Height; j++)
{
SetPixel(i, Height - j, 0);
}
}
srand(time(NULL));
r = (float)(rand() % 100) / 100;
g = (float)(rand() % 100) / 100;
b = (float)(rand() % 100) / 100;
glEnable(GL_DEPTH_TEST);
glfwSetKeyCallback(window, keyboard_callback);
glfwSetMouseButtonCallback(window, mouse_callback);
glfwSetCursorPosCallback(window, cursor_callback);
while (running)
{
GLint windowWidth, windowHeight;
glfwGetWindowSize(window, &windowWidth, &windowHeight);
glMatrixMode(GL_PROJECTION);
glClearColor(0.0f, 0.0f, 0.25f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION_MATRIX);
glLoadIdentity();
glDrawPixels(Width, Height, GL_RGB, GL_FLOAT, pixels);
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}