Skip to content

Instantly share code, notes, and snippets.

@kyontan
Last active August 29, 2015 13:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyontan/9156495 to your computer and use it in GitHub Desktop.
Save kyontan/9156495 to your computer and use it in GitHub Desktop.
Refrection and Refraction Simulator using Xwindow

反射・屈折のシミュレータ

ソースの質に関してはお察しください

コンパイル方法

  • Mac ( XQuartz が必要です。 ここからダウンロードしてください。)
clang++ reflection_reflaction.cpp -std=c++11 -I /usr/X11R6/include -L /usr/X11R6/lib -l X11
  • Linux
clang++ reflection_reflaction.cpp -std=c++11 –I /usr/include -L /usr/lib –l X11

ライセンス

CC BY 4.0

#include "reflection_reflaction.h"
using namespace std;
const string sMenu[] = { "Light", "Mirror", "Area", "Rotate (only light)", "Remove", "Move", "OK" };
int selected_obj, mode = tNoneSelected, new_mode, tmp, m_mode = mNormal;
bool isModeChanged = false, isPressed = false, isChanged = false, refleshDpy = true;
Object *pObj;
Objects objects;
int main(void) {
cout << setprecision(2);
cout.setf(ios::fixed, ios::floatfield);
string sNewArea;
double nNewArea;
setlocale(LC_ALL, "");
Display *dpy = XOpenDisplay("");
int screen = DefaultScreen(dpy);
unsigned long black, white;
white = WhitePixel(dpy, screen);
black = BlackPixel(dpy, screen);
Window root = DefaultRootWindow(dpy);
Window w = XCreateSimpleWindow(dpy, root, 100, 100, WIDTH, HEIGHT, BORDER, black, white);
XMapWindow(dpy, w);
cmap = DefaultColormap(dpy, 0);
XColor c0, c1;
for (int i=0; i<NUM_COLOR; i++) {
XAllocNamedColor(dpy, cmap, color_name[i], &c1, &c0);
nColor[i] = c1.pixel;
}
initColors(dpy, &cmap);
GC gc = XCreateGC(dpy, w, 0, NULL);
char **miss, *def;
int n_miss;
XFontSet fs = XCreateFontSet(dpy, "-*-*-medium-r-normal-*-16-*", &miss, &n_miss, &def);
Font font = XLoadFont(dpy, "*x16");
XSetFont(dpy, gc, font);
XSelectInput(dpy, w, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask );
Atom atom1 = XInternAtom(dpy, "WM_PROTOCOLS", false);
Atom wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
XSetWMProtocols(dpy, w, &wmDeleteMessage, 1);
XEvent e;
XButtonEvent btn;
Object obj;
Point p_last = Point();
KeySym key;
int current_color = 0;
XSetForeground(dpy, gc, black);
while(true) {
if (isModeChanged || refleshDpy) {
XClearWindow(dpy, w);
isModeChanged = false;
refleshDpy = true;
}
if (refleshDpy) {
objects.draw(dpy, w, gc);
for (int i=0; i<objects.size(); i++)
if (objects[i].type == tLight)
static_cast<Light *>(&objects[i])->drawRay(dpy, w, gc, objects);
XSetForeground(dpy, gc, nColor[0]);
drawMenu(m_mode, mode, dpy, w, gc);
if (mode == tSelected && objects[selected_obj].type == tArea) {
string print = "n = " + to_string(static_cast<Area *>(&objects[selected_obj])->n);
XDrawString(dpy, w, gc, 16, 16, print.c_str(), print.length());
}
if (mode == tInputN || mode == tAddArea) {
string print = "n = " + sNewArea;
XSetForeground(dpy, gc, nColor[0]);
XDrawString(dpy, w, gc, 16, 16, print.c_str(), print.length());
}
{
string print = sMode[mode];
int len = print.length();
XDrawString(dpy, w, gc, WIDTH-len*9, 16, print.c_str(), len);
}
refleshDpy = false;
}
if (!XPending(dpy)) {
usleep(5000);
continue;
}
XNextEvent(dpy, &e);
if (e.type == ClientMessage && e.xclient.data.l[0] == wmDeleteMessage) {
// XDestroyWindow(dpy, e.xclient.window);
XWithdrawWindow(dpy, w, screen);
XCloseDisplay(dpy);
break;
}
if (isButtonEvent(e) && e.xbutton.button != 1)
continue;
switch (e.type) {
case KeyPress:
if (mode != tInputN)
break;
key = XLookupKeysym(&e.xkey, 0); // get ascii code
if (key == XK_BackSpace && !sNewArea.empty()) {
sNewArea.erase(sNewArea.length()-1);
} else {
int chr = static_cast<int>(key);
if (chr == '.' || ('0' <= chr && chr <= '9'))
sNewArea += chr;
}
refleshDpy = true;
break;
case ButtonPress:
isPressed = true;
btn = e.xbutton;
if (isAddMode(mode) && (HEIGHT - MENU_HEIGHT) <= btn.y) {
new_mode = tNoneSelected;
break;
}
switch (mode) {
case tNoneSelected: {
if ((HEIGHT-MENU_HEIGHT) <= btn.y)
break;
tmp = objects.select(Point(btn.x, btn.y));
if (tmp != -1) {
new_mode = tSelected;
m_mode = mSelected;
} else
new_mode = tNoneSelected;
selected_obj = tmp;
break;
case tSelected:
// Mode select
if (btn.y < (HEIGHT-MENU_HEIGHT)) {
tmp = objects.select(Point(btn.x, btn.y));
if (tmp != -1) {
m_mode = mSelected;
if (selected_obj != tmp)
new_mode = tSelected;
} else
new_mode = tNoneSelected;
selected_obj = tmp;
refleshDpy = true;
} else {
if (btn.x < (WIDTH/2))
if (objects[selected_obj].type == tLight)
new_mode = tRotate;
}
break;
case tAddLight: {
Light *l = new Light(Point(btn.x, btn.y));
objects.add(l);
} break;
case tAddMirror: {
Mirror *m = new Mirror(Point(btn.x, btn.y), Point(btn.x, btn.y));
objects.add(m);
} break;
case tInputN:
if (sNewArea.empty())
sNewArea = "1.0";
nNewArea = atof(sNewArea.c_str());
if (nNewArea < 1.0)
nNewArea = 1.0;
sNewArea = to_string(nNewArea);
new_mode = tAddArea;
case tAddArea: {
Area *a = new Area(Point(btn.x, btn.y), Point(btn.x, btn.y), nNewArea);
objects.add(a);
} break;
case tRotate:
p_last = Point(btn.x, btn.y);
break;
}
} break;
case MotionNotify: {
if (!isPressed)
break;
XMotionEvent mtn = e.xmotion;
if (p_last.x == -1 && p_last.y == -1) {
p_last = Point(mtn.x, mtn.y);
break;
}
int dx = mtn.x - p_last.x, dy = mtn.y - p_last.y;
if (dx == 0 && dy == 0)
break;
if (isAddMode(mode)) {
pObj = &objects[objects.size()-1];
pObj->resize(dx, dy);
// printf("Resize %s, id: %d, diff: (%d, %d)\n", sObj[pObj->type], objects.size()-1, dx, dy);
}
if (mode == tSelected) { // Move object
pObj = &objects[selected_obj];
pObj->move(dx, dy);
// printf("Move %s, id: %d, diff: (%d, %d)\n", sObj[pObj->type], selected_obj, dx, dy);
m_mode = mNormal;
}
if (mode == tRotate && dx != 0) {
pObj = &objects[selected_obj];
Light *lt = static_cast<Light *>(pObj);
double angle_add = (2*M_PI) / (fmod(dx, 2*M_PI) * 96);
lt->angle = fmod(lt->angle + angle_add, 2*M_PI);
printf("angle: %6.2lf[deg]\n", lt->angle/M_PI*180);
}
refleshDpy = true;
isChanged = true;
p_last = Point(mtn.x, mtn.y);
} break;
case ButtonRelease: {
btn = e.xbutton;
if (mode == tSelected && (HEIGHT-MENU_HEIGHT) <= btn.y) {
if ((WIDTH/2) <= btn.x) { // Remove button
objects.remove(selected_obj);
printf("Remove %d\n", selected_obj);
new_mode = tNoneSelected;
refleshDpy = true;
}
}
if (mode == tRotate) {
pObj = &objects[selected_obj];
new_mode = tNoneSelected;
}
if (isAddMode(mode) && new_mode != tNoneSelected)
pObj = &objects[objects.size()-1];
if ( (new_mode == tNoneSelected && isChanged) ||
(new_mode != tNoneSelected && isAddMode(mode)) ) {
printf("Decision %s #%2d ", sObj[pObj->type], objects.size()-1);
pObj->println();
}
if (mode == tNoneSelected && (HEIGHT-MENU_HEIGHT) <= btn.y)
new_mode = tAddLight + (btn.x / (WIDTH/3));
else if (mode != tSelected || (mode == tSelected && m_mode == mNormal))
new_mode = tNoneSelected;
isPressed = false;
isChanged = false;
p_last = Point(-1, -1);
} break;
}
if (new_mode == tNoneSelected)
m_mode = mNormal;
if (new_mode != mode) {
if (new_mode == tInputN)
sNewArea = "";
refleshDpy = true;
mode = new_mode;
isModeChanged = true;
printf("Mode change: %s\n", sMode[mode]);
}
}
return 0;
}
double angleOfPoints(Point a, Point b, Point cross) {
return atan2((cross-a).cross(cross-b), (cross-a).dot(cross-b));
}
// return: Is line(a-b) intersected line(c-d)
// ret: intersection point of line(a-b) and line(c-d)
bool getIntersection(Point a, Point b, Point c, Point d, Point* ret) {
double v1 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x),
v2 = (b.x - a.x) * (d.y - a.y) - (b.y - a.y) * (d.x - a.x),
m1 = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x),
m2 = (d.x - c.x) * (b.y - c.y) - (d.y - c.y) * (b.x - c.x);
if (0 < v1*v2 || 0 < m1*m2)
return false;
double t1 = ((d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x)) / 2.0,
t2 = ((d.x - c.x) * (c.y - b.y) - (d.y - c.y) * (c.x - b.x)) / 2.0;
ret->x = a.x + (b.x - a.x) * t1 / (t1 + t2);
ret->y = a.y + (b.y - a.y) * t1 / (t1 + t2);
return true;
};
// Return: Is mode included [AddLight, AddMirror, AddArea]
bool isAddMode(int mode) {
switch (mode) {
case tAddLight:
case tAddMirror:
case tAddArea:
return true;
default:
return false;
}
};
bool isButtonEvent(XEvent e) {
switch (e.type) {
case ButtonPress:
case ButtonRelease:
return true;
default:
return false;
}
};
void drawMenu(int m_mode, int mode, Display *dpy, Window w, GC gc) {
int from, to;
XSetForeground(dpy, gc, nColor[3]);
XFillRectangle(dpy, w, gc, 0, HEIGHT-MENU_HEIGHT, WIDTH, MENU_HEIGHT);
XSetForeground(dpy, gc, nColor[0]);
XDrawLine(dpy, w, gc, 0, HEIGHT-MENU_HEIGHT, WIDTH, HEIGHT-MENU_HEIGHT);
switch (m_mode) {
case mRotate:
case mSelected:
from = 3, to = 5;
break;
default:
from = 0, to = 3;
}
int num = to - from;
XSetForeground(dpy, gc, nColor[1]); {
int left = -1;
if (isAddMode(mode) || mode == tInputN) {
if (mode == tAddArea)
mode = tInputN;
left = (mode-2)*(WIDTH/num);
} else if (mode == tRotate)
left = 0;
if (0 <= left)
XFillRectangle(dpy, w, gc, left+1, HEIGHT-MENU_HEIGHT+1, WIDTH/num, MENU_HEIGHT);
} XSetForeground(dpy, gc, nColor[0]);
for (int i=0; i<num; i++) {
if (0 < i)
XDrawLine(dpy, w, gc, WIDTH/num * i, HEIGHT-MENU_HEIGHT, WIDTH/num*i, HEIGHT);
int str_len = sMenu[i+from].length(),
left = WIDTH/num * i + WIDTH/(num*2) - str_len*4;
XDrawString(dpy, w, gc, left, HEIGHT-6, sMenu[i+from].c_str(), str_len);
}
};
Point selectAnotherPoint(Point base, Point cross, Point **points, int size) {
Point ret;
double min_angle = M_PI, tmp;
for (int i=0; i<size; i++) {
tmp = abs(angleOfPoints(base, *points[i], cross));
if (tmp < min_angle)
ret = *points[i], min_angle = tmp;
}
return ret;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <memory>
#include <string>
#include <vector>
using namespace std;
const int BORDER = 2;
const int WIDTH = 640;
const int HEIGHT = 480;
const int MENU_HEIGHT = 24;
const int LIGHT_RADIUS = 7;
const int MAX_REFLECT = 48;
enum tObj { tLight, tMirror, tArea };
char sObj[][16] = { "Light", "Mirror", "Area" };
enum tMode { tNoneSelected, tSelected, tAddLight, tAddMirror, tInputN, tAddArea, tRotate };
char sMode[][16] =
{ "Not Selected", "Selected", "Add Light", "Add Mirror", "Input n", "Add Area", "Rotate" };
enum mMode { mNormal, mSelected, mRotate };
const int NUM_COLOR = 5;
char color_name[NUM_COLOR][10] = { "Black", "Gainsboro", "Red", "White", "DarkGray" };
unsigned long nColor[NUM_COLOR];
static Colormap cmap;
unsigned long reds[MAX_REFLECT], grays[100];
struct Point {
double x = 0.0;
double y = 0.0;
Point() {};
Point(double _x, double _y) : x(_x), y(_y) {};
double len();
double dist(Point p);
double dot(Point p);
double cross(Point p);
Point midpoint(Point p);
void print();
void println();
Point operator+(Point p);
Point operator-(Point p);
Point& operator+=(Point p);
Point& operator-=(Point p);
bool operator==(Point p);
};
Point Point::operator+(Point p) {
return Point(x + p.x, y + p.y);
};
Point Point::operator-(Point p) {
return Point(x - p.x, y - p.y);
};
Point& Point::operator+=(Point p) {
x += p.x;
y += p.y;
return *this;
};
Point& Point::operator-=(Point p) {
x -= p.x;
y -= p.y;
return *this;
};
bool Point::operator==(Point p) {
return x == p.x && y == p.y;
};
double Point::len() {
return sqrt(x*x + y*y);
};
double Point::dist(Point p) {
double a = x - p.x,
b = y - p.y;
return sqrt(a*a + b*b);
};
double Point::dot(Point p) {
return x * p.x + y * p.y;
};
double Point::cross(Point p) {
return x * p.y - y * p.x;
};
Point Point::midpoint(Point p) {
return Point((x + p.x)/2, (y + p.y) / 2);
}
class Objects;
class Object {
public:
int type;
Point p1, p2;
virtual void draw(Display *dpy, Window w, GC gc);
virtual void move(double dx, double dy);
virtual void resize(double dx, double dy);
virtual void print();
virtual void println();
};
class Light : public Object {
public:
double angle = 0.0;
Light(Point p, double a) { type = tLight; p1 = p; angle = fmod(a, 2*M_PI); };
Light(Point p) : Light(p, 0.0) {};
void draw(Display *dpy, Window w, GC gc);
void move(double dx, double dy);
void resize(double dx, double dy);
void print();
void drawRay(Display *dpy, Window w, GC gc, Objects objects,
int recursive_count = 0, Point not_reflect = Point(), int lightness = 0);
};
class Mirror : public Object {
public:
Mirror(Point _p1, Point _p2) { type = tMirror; p1 = _p1; p2 = _p2; };
void draw(Display *dpy, Window w, GC gc);
void move(double dx, double dy);
void resize(double dx, double dy);
void print();
Point** getPoints();
};
class Area : public Object {
public:
double n = 1.0; // Refractive index
Area(Point _p1, Point _p2, double _n) { type = tArea; p1 = _p1; p2 = _p2; n = _n; };
Area(Point _p1, Point _p2) : Area(_p1, _p2, 1.0) {};
void draw(Display *dpy, Window w, GC gc);
void move(double dx, double dy);
void resize(double dx, double dy);
void print();
Point** getPoints();
bool isInside(Point p);
};
class Objects {
Object** objects;
public:
void add(Light *l);
void add(Mirror *m);
void add(Area *a);
void remove(int index);
int select(Point p, bool only_area = false);
double n(Point p);
void draw(Display *dpy, Window w, GC gc);
Object& operator[](int index);
int size();
private:
int _size = 0;
void resize(int size);
};
bool getIntersection(Point a, Point b, Point c, Point d, Point* ret);
double angleOfPoints(Point a, Point b, Point cross);
bool isAddMode(int mode);
bool isButtonEvent(XEvent e);
void drawMenu(int m_mode, int mode, Display *dpy, Window w, GC gc);
Point selectAnotherPoint(Point base, Point cross, Point **points, int size);
void initColors(Display *dpy, Colormap *cmap);
void Object::draw(Display *dpy, Window w, GC gc) { };
void Object::move(double dx, double dy) {};
void Object::resize(double dx, double dy) {};
void Light::draw(Display *dpy, Window w, GC gc) {
Point p = Point(p1.x - (LIGHT_RADIUS/2), p1.y - (LIGHT_RADIUS/2));
XFillArc(dpy, w, gc, p.x, p.y, LIGHT_RADIUS, LIGHT_RADIUS, 0, 360*64);
};
void Mirror::draw(Display *dpy, Window w, GC gc) {
XDrawLine(dpy, w, gc, p1.x, p1.y, p2.x, p2.y);
};
void Area::draw(Display *dpy, Window w, GC gc) {
int color = round(log10(n) * 100);
if (100 <= color)
color = 99;
XSetForeground(dpy, gc, grays[color]); // gainsboro
Point lt = Point(min(p1.x, p2.x), min(p1.y, p2.y));
Point rb = Point(max(p1.x, p2.x), max(p1.y, p2.y));
XFillRectangle(dpy, w, gc, lt.x, lt.y, rb.x - lt.x, rb.y - lt.y);
XSetForeground(dpy, gc, nColor[0]); // black
};
void Light::move(double dx, double dy) {
p1.x += dx; p1.y += dy;
};
void Mirror::move(double dx, double dy) {
p1.x += dx; p1.y += dy;
p2.x += dx; p2.y += dy;
};
void Area::move(double dx, double dy) {
p1.x += dx; p1.y += dy;
p2.x += dx; p2.y += dy;
};
void Light::resize(double dx, double dy) {
p1.x += dx; p1.y += dy;
};
void Mirror::resize(double dx, double dy) {
p2.x += dx; p2.y += dy;
};
void Area::resize(double dx, double dy) {
p2.x += dx; p2.y += dy;
};
void Point::print() {
printf("(%6.2lf, %6.2lf)", x, y);
};
void Point::println() {
print();
cout << endl;
};
void Object::print() {
printf("(%6.2lf, %6.2lf), (%6.2lf, %6.2lf)", p1.x, p1.y, p2.x, p2.y);
};
void Object::println() {
print();
cout << endl;
};
void Light::print() {
printf("(%6.2lf, %6.2lf), Angle: %6.2lf", p1.x, p1.y, angle);
};
void Mirror::print() {
printf("(%6.2lf, %6.2lf), (%6.2lf, %6.2lf)", p1.x, p1.y, p2.x, p2.y);
};
void Area::print() {
printf("(%6.2lf, %6.2lf), (%6.2lf, %6.2lf), n: %5.2lf", p1.x, p1.y, p2.x, p2.y, n);
};
Point** Mirror::getPoints() {
Point** points = (Point **)malloc(sizeof(Point *) * 2);
points[0] = &p1;
points[1] = &p2;
return points;
};
Point** Area::getPoints() {
Point** points = (Point **)malloc(sizeof(Point *) * 4);
points[0] = new Point(max(p1.x, p2.x), max(p1.y, p2.y));
points[1] = new Point(max(p1.x, p2.x), min(p1.y, p2.y));
points[2] = new Point(min(p1.x, p2.x), min(p1.y, p2.y));
points[3] = new Point(min(p1.x, p2.x), max(p1.y, p2.y));
return points;
};
bool Area::isInside(Point p) {
if (min(p1.x, p2.x) <= p.x && p.x <= max(p1.x, p2.x) &&
min(p1.y, p2.y) <= p.y && p.y <= max(p1.y, p2.y))
return true;
return false;
}
void Light::drawRay(Display *dpy, Window w, GC gc,
Objects objects, int recursive_count, Point not_reflect, int lightness) {
if (MAX_REFLECT <= recursive_count || MAX_REFLECT <= lightness)
return;
Point dir = Point(p1.x + 1000 * cos(angle), p1.y + 1000 * sin(angle));
Point cross, cross_near, tmp;
Object *obj, *collision_to;
bool isCross = false;
double dist = 32768; // inf
Point _not_reflect = not_reflect;
for (int i=0; i<objects.size(); i++) {
obj = &objects[i];
switch (obj->type) {
case tLight:
break;
case tMirror:
if (getIntersection(p1, dir, obj->p1, obj->p2, &tmp)) {
if (tmp.dist(not_reflect) < 0.1)
break;
if (tmp.x < 0 || WIDTH < tmp.x || tmp.y < 0 || HEIGHT < tmp.y)
break;
if (p1.dist(tmp) <= dist) {
cross = tmp;
dist = p1.dist(cross);
cross_near = selectAnotherPoint(p1, cross, static_cast<Mirror *>(obj)->getPoints(), 2);
_not_reflect = cross;
collision_to = obj;
}
isCross = true;
}
break;
case tArea:
Area *area = static_cast<Area *>(obj);
Point **points = area->getPoints(),
**points2 = (Point **)malloc(sizeof(Point *) * 2);
for (int j=0; j<4; j++) {
points2[0] = points[j%4];
points2[1] = points[(j+1)%4];
if (getIntersection(p1, dir, *points2[0], *points2[1], &tmp)) {
if (tmp.dist(not_reflect) < 0.1)
continue;
if (tmp.x < 0 || WIDTH < tmp.x || tmp.y < 0 || HEIGHT < tmp.y)
continue;
if (p1.dist(tmp) <= dist) {
cross = tmp;
dist = p1.dist(cross);
cross_near = selectAnotherPoint(p1, cross, points2, 2);
_not_reflect = cross;
collision_to = obj;
}
isCross = true;
}
}
free(points);
free(points2);
break;
}
}
if (isCross) {
XSetForeground(dpy, gc, nColor[4]);
XFillArc(dpy, w, gc, cross.x-2, cross.y-2, 4, 4, 0, 360*64);
XSetForeground(dpy, gc, reds[lightness]);
XDrawLine(dpy, w, gc, p1.x, p1.y, cross.x, cross.y);
XSetForeground(dpy, gc, nColor[0]); // black
double theta_i = M_PI/2 - fmod(abs(angleOfPoints(p1, cross_near, cross)), M_PI/2);
if (theta_i == M_PI/2)
theta_i = 0;
cout << "#" << setw(2) << recursive_count << " ";
cout << "Intersects: ";
cross.print(); cout << " ";
cout << "angle: " << setw((int)log10(objects.size())+1);
cout << setw(7) << angle/M_PI*180 << "[deg] ";
cout << "i = " << setw(7) << theta_i/M_PI*180 << "[deg] ";
bool isRefraction = true;
// Refraction
if (collision_to->type == tArea) {
double n1 = objects.n(p1), n2;
if (&objects[objects.select(p1, true)] == collision_to)
n2 = 1.0;
else
n2 = static_cast<Area *>(collision_to)->n;
double theta_r = asin(sin(theta_i) * (n1 / n2));
if (isnan(theta_r) || (n1 > n2 && theta_r > asin(n2/n1)))
isRefraction = false;
if (isRefraction) {
cout << "r = " << setw(7) << theta_r/M_PI*180 << "[deg] " << endl;
Light r = Light(Point(cross.x, cross.y), fmod(theta_r + angle - theta_i, 2*M_PI));
r.drawRay(dpy, w, gc, objects, recursive_count+1, _not_reflect, lightness + 1);
}
}
// Refrection
// if (collision_to->type == tMirror)
if (!isRefraction || collision_to->type == tMirror) {
double theta_i = M_PI/2 - fmod(angleOfPoints(p1, cross_near, cross), M_PI/2);
double theta_j = angle - theta_i * 2;
if (theta_i != M_PI/2)
theta_j += M_PI;
Light j = Light(Point(cross.x, cross.y), fmod(theta_j, 2*M_PI));
j.drawRay(dpy, w, gc, objects, recursive_count+1, _not_reflect, lightness + 1);
}
} else {
XSetForeground(dpy, gc, reds[lightness]);
XDrawLine(dpy, w, gc, p1.x, p1.y, p1.x + 1000*cos(angle), p1.y + 1000*sin(angle));
XSetForeground(dpy, gc, nColor[0]);
}
};
void Objects::add(Light *l) {
resize(_size+1);
objects[_size-1] = l;
printf("Add: Light ");
l->println();
};
void Objects::add(Mirror *m) {
resize(_size+1);
objects[_size-1] = m;
printf("Add: Mirror ");
m->println();
};
void Objects::add(Area *a) {
resize(_size+1);
objects[_size-1] = a;
printf("Add: Area ");
a->println();
};
void Objects::remove(int index) {
for (int i=index+1; i<_size; i++)
objects[i-1] = objects[i];
resize(_size-1);
};
int Objects::select(Point p, bool only_area) {
int selected = -1;
Object *obj;
// Select Area
for (int i=0; i<_size; i++) {
obj = objects[i];
if (obj->type == tArea) {
Point p1 = obj->p1, p2 = obj->p2;
double top = min(p1.y, p2.y), bottom = max(p1.y, p2.y),
left = min(p1.x, p2.x), right = max(p1.x, p2.x);
if (left <= p.x && p.x <= right && top <= p.y && p.y <= bottom)
selected = i;
}
}
if (only_area)
return selected;
// Select Mirror
for (int i=0; i<_size; i++) {
obj = objects[i];
if (obj->type == tMirror) {
Point p1 = obj->p1;
Point p2 = obj->p2;
if ((p2.x-p1.x) != 0) {
double a = (p2.y-p1.y) / (p2.x-p1.x);
double d = p1.y - a*p1.x;
if (abs(p.y - (a*p.x+d)) <= 5 &&
(min(p1.x, p2.x) - 5) <= p.x && p.x <= (max(p1.x, p2.x) + 5) &&
(min(p1.y, p2.y) - 5) <= p.y && p.y <= (max(p1.y, p2.y) + 5))
selected = i;
} else {
if (abs(p.x - p1.x) <= 5 || p1.dist(p) <= 5 || p2.dist(p) <= 5)
selected = i;
}
}
}
// Select Light
for (int i=0; i<_size; i++) {
obj = objects[i];
if (obj->type == tLight && p.dist(obj->p1) <= LIGHT_RADIUS + 5)
selected = i;
}
if (selected != -1)
printf("Select object: id: %d, type: %s\n", selected, sObj[objects[selected]->type]);
return selected;
};
double Objects::n(Point p) {
int index = select(p, true);
if (index == -1)
return 1.0;
else
return static_cast<Area *>(objects[index])->n;
}
void Objects::draw(Display *dpy, Window w, GC gc) {
for (int i=0; i<_size; i++)
if (objects[i]->type == tArea)
objects[i]->draw(dpy, w, gc);
for (int i=0; i<_size; i++)
if (objects[i]->type == tMirror)
objects[i]->draw(dpy, w, gc);
for (int i=0; i<_size; i++)
if (objects[i]->type == tLight)
objects[i]->draw(dpy, w, gc);
};
Object& Objects::operator[](int index) {
// if (index < 0)
// index = _size + index;
return *objects[index];
};
int Objects::size() {
return _size;
};
void Objects::resize(int size) {
printf("Objects resize from %d to %d\n", _size, size);
objects = (Object **)realloc(objects, sizeof(Object *) * size);
if (objects == nullptr)
exit(-1);
_size = size;
};
void initColors(Display *dpy, Colormap *cmap) {
XColor red, gray;
red.red = 0xffff;
red.green = 0;
red.blue = 0;
gray.red = gray.green = gray.blue = 0xf000;
for(int i=0; i<MAX_REFLECT; i++) {
red.green += 0xffff / MAX_REFLECT;
red.blue += 0xffff / MAX_REFLECT;
XAllocColor(dpy, *cmap, &red);
reds[i] = red.pixel;
}
for(int i=0; i<100; i++) {
gray.red = gray.green = gray.blue = gray.red - 0xffff / 200;
XAllocColor(dpy, *cmap, &gray);
grays[i] = gray.pixel;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment