// ############### DAFINICJA INTERFEJSU KLAS DZIEDZICZĄCYCH ###############
class i_dr_obj{ // i - interface; dr - draving; obj - object (interfejs rysowanego obiektu)
protected:
bool selected;
int pen_index; // index pędzla rysowania
int brush_index; // index wypełnienia rysowania
public:
i_dr_obj(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush, pen &p, brush &b):selected(false), pen_index(-1), brush_index(-1){
for(int i = 0; i < tPen.size(); i++){ // dla każdego elementu kontenera tPen
if((pen)tPen[i] == p){ // sprawdzam, czy nie ma już utworzonego pióra o takich samych parametrach
pen_index = i; // jeżeli jest takie pióro to zapamiętuję jego index
break; // i kończę zabawę z iterowaniem
}
}
if(pen_index == -1){ // jak pen_index jest równe -1 to znaczy, że nie ma w tPen takiego pióra więc
pen_index = tPen.size(); // przypisuję index ostatniego elementu
hpen hp(p); // tworzę nową definicję pióra
tPen.push_back(hp); // dodaję definicję pióra
}
for(int i = 0; i < tBrush.size(); i++){ // dla każdego elementu kontenera tBrush
if((brush)tBrush[i] == b){ // sprawdzam, czy nie ma już utworzonego pędzla o takich samych parametrach
brush_index = i; // jeżeli taki pędzel już istnieje to zapamiętuję jego index
break; // i kończę zabawę z iterowaniem
}
}
if(brush_index == -1){ // jak brush_index jest równy -1 to znaczy, że w tBrush nie ma takiego pędzla
brush_index = tBrush.size(); // więc przypisuję index ostatniego elementu kontenera (który zaraz dodam)
hbrush hbr(b); // tworzę ten element
tBrush.push_back(hbr); // i dodaję go do kontenera
}
};
virtual std::wstring toString(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const = 0; // każda definicja klasy musi obsługiwać tę metodę
virtual void Draw(HDC &hdc, std::vector<hpen> &tPen, std::vector<hbrush> &tbrush) const = 0; // każda definicja klasy musi obsługiwać tę metodę
virtual void DrawSelect(HDC &hdc) const = 0; // rysowanie zaznaczenia
virtual void WmLButtonDown(POINT &mp) = 0;
virtual void WmLButtonUp(POINT &mp) = 0;
virtual RECT GetRect() const = 0;
bool Selected() const {return selected;}; // określa, czy obiekt został zaznaczony
void Unselect() { selected = false;};
virtual bool Select(POINT &ps) = 0; // każda definicja klasy musi obługiwać tę metodą
virtual bool Select(RECT &r) = 0;
virtual bool CursorOnObject(POINT &mp) const = 0; // sprawdza, czy kursor jest nad obiektem
virtual ~i_dr_obj(){};
};
// ######################### DEFINICJA KLASY LINE (LINIA) ########################
class line : public i_dr_obj{
POINT begin;
POINT end;
public:
line(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush, pen &p, brush &b):i_dr_obj(tPen, tBrush, p, b){begin.x = begin.y = end.x = end.y = 0;};
virtual std::wstring toString(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
std::wstring str;
wchar_t buffor[100];
wsprintf(buffor, L"line %i %i; %i %i", begin.x, begin.y, end.x, end.y);
str = buffor;
str += L" ";
str += tPen[this->pen_index].toString();
str += L" ";
str += tBrush[this->brush_index].toString();
return str;
}
virtual void Draw(HDC &hdc, std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
tPen[pen_index].SelectPen(hdc);
tBrush[brush_index].SelectBrush(hdc);
MoveToEx(hdc, begin.x, begin.y, NULL);
LineTo(hdc, end.x, end.y);
}
virtual void DrawSelect(HDC &hdc) const {
Rectangle(hdc, begin.x - ZN_SIZE, begin.y - ZN_SIZE, begin.x + ZN_SIZE, begin.y + ZN_SIZE);
Rectangle(hdc, end.x - ZN_SIZE, end.y - ZN_SIZE, end.x + ZN_SIZE, end.y + ZN_SIZE);
}
virtual void WmLButtonDown(POINT &mp){
begin = mp;
end = mp;
}
virtual void WmLButtonUp(POINT &mp){
end = mp;
}
virtual bool Select(POINT &ps){
if(CursorOnObject(ps)){
selected = true;
return true;
}
return false;
}
virtual bool Select(RECT &r){
if(PtInRect(&r, begin) && PtInRect(&r, end)){
selected = true;
return true;
}
return false;
}
virtual RECT GetRect() const {
RECT r;
SetRect(&r, min(begin.x, end.x), min(begin.y, end.y), max(begin.x, end.x), max(begin.y, end.y));
return r;
}
virtual bool CursorOnObject(POINT &ps) const {
if(begin.x == end.x && begin.y == end.y){ // gdy punkty się pokrywają
if((begin.x - ps.x) * (begin.x - ps.x) > ZN_SIZE * ZN_SIZE){ // oraz kwadrat odległości od kursora od punktu jest większa od zadanej tolerancji
return false; // to zwracaj fałsz bo obiket jest poza zasięgiem zaznaczenia
}
return true; // w przeciwnym razie zwracaj prawdę
}
float u = float((ps.x - begin.x)*(end.x -begin.x)+(ps.y-begin.y)*(end.y-begin.y)) / (pow(begin.x - end.x, 2.f) + pow(begin.y - end.y, 2.f)); // współrzynnik umożliwiający znalezienie punktu zrzutowanego na linię
POINT pt; // zmienna punktu zrzutowanego na linię
pt.x = begin.x + (end.x - begin.x) * u; // współrzędna x zrzutowanego punktu
pt.y = begin.y + (end.y - begin.y) * u; // współrzędna y zrzutowanego punktu
if(pt.x >= min(begin.x, end.x) && pt.x <= max(begin.x, end.x) && pt.y >= min(begin.y, end.y) && pt.y <= max(begin.y, end.y)){ // jak punkt zawiera się w zadanym zakresie wartości to
if((pt.x - ps.x) * (pt.x - ps.x) + (pt.y - ps.y) * (pt.y - ps.y) <= ZN_SIZE * ZN_SIZE){ // jak kwadrat odległości jest mniejszy lub równy kwadratowi maksymalnego odchylenia to
return true; // zwracaj prawdę
}
}
return false; // w przeciwnym przypadku zwracaj fałsz
}
};
// ######################### DEFINICJA KLASY CIRCLE (OKRĄG) ########################
class circle : public i_dr_obj{
POINT begin;
POINT end;
public:
circle(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush, pen &p, brush &b):i_dr_obj(tPen, tBrush, p, b){begin.x = begin.y = end.x = end.y = 0;};
POINT GetCenterPoint() const {
POINT pt;
pt.x = (begin.x + end.x) * 0.5;
pt.y = (begin.y + end.y) * 0.5;
return pt;
}
virtual std::wstring toString(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
std::wstring str;
wchar_t buffor[100];
wsprintf(buffor, L"circle %i %i; %i %i", begin.x, begin.y, end.x, end.y);
str = buffor;
str += L" ";
str += tPen[this->pen_index].toString();
str += L" ";
str += tBrush[this->brush_index].toString();
return str;
}
virtual void Draw(HDC &hdc, std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
tPen[pen_index].SelectPen(hdc);
tBrush[brush_index].SelectBrush(hdc);
Ellipse(hdc, begin.x, begin.y, end.x, end.y);
}
virtual void DrawSelect(HDC &hdc) const {
Rectangle(hdc, begin.x - ZN_SIZE, begin.y - ZN_SIZE, begin.x + ZN_SIZE, begin.y + ZN_SIZE);
Rectangle(hdc, end.x - ZN_SIZE, end.y - ZN_SIZE, end.x + ZN_SIZE, end.y + ZN_SIZE);
}
virtual void WmLButtonDown(POINT &mp){
begin = mp;
end = mp;
}
virtual void WmLButtonUp(POINT &mp){
end = mp;
if(abs(begin.x - end.x) < abs(begin.y - end.y)){
end.y = begin.y + abs(begin.x - end.x) * ( begin.y < end.y ? 1 : -1);
}else{
end.x = begin.x + abs(begin.y - end.y) * ( begin.x < end.x ? 1 : -1);
}
}
virtual bool Select(POINT &ps){
if(CursorOnObject(ps)){
selected = true;
return true;
}
return false;
}
virtual bool Select(RECT &r){
if(PtInRect(&r, begin) && PtInRect(&r, end)){
selected = true;
return true;
}
return false;
}
virtual bool CursorOnObject(POINT &ps) const {
POINT cp = GetCenterPoint(); // metoda zwracająca współrzędne punktu centralnego
UINT ray = abs(begin.x - end.x) * 0.5; // promień okręgu
if((cp.x - ps.x) * (cp.x - ps.x) + (cp.y - ps.y) * (cp.y - ps.y) > ray * ray){ // jak kwadrat odległości kursora od punktu centralnego jest większy od kwadratu promienia okręgu to
return false; // zwracaj fałsz
}
return true; // w przeciwnym przypadku zwracaj prawdę
}
virtual RECT GetRect() const {
RECT r;
SetRect(&r, min(begin.x, end.x), min(begin.y, end.y), max(begin.x, end.x), max(begin.y, end.y));
return r;
}
};
// ######################### DEFINICJA KLASY RECTANGLE (PROSTOKĄT) ########################
class rectangle : public i_dr_obj{
POINT begin;
POINT end;
public:
rectangle(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush, pen &p, brush &b):i_dr_obj(tPen, tBrush, p, b){begin.x = begin.y = end.x = end.y = 0;};
virtual std::wstring toString(std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
std::wstring str;
wchar_t buffor[100];
wsprintf(buffor, L"rectangle %i %i; %i %i", begin.x, begin.y, end.x, end.y);
str = buffor;
str += L" ";
str += tPen[this->pen_index].toString();
str += L" ";
str += tBrush[this->brush_index].toString();
return str;
}
virtual void Draw(HDC &hdc, std::vector<hpen> &tPen, std::vector<hbrush> &tBrush) const {
tPen[pen_index].SelectPen(hdc);
tBrush[brush_index].SelectBrush(hdc);
Rectangle(hdc, begin.x, begin.y, end.x, end.y);
}
virtual void DrawSelect(HDC &hdc) const {
Rectangle(hdc, begin.x - ZN_SIZE, begin.y - ZN_SIZE, begin.x + ZN_SIZE, begin.y + ZN_SIZE);
Rectangle(hdc, end.x - ZN_SIZE, end.y - ZN_SIZE, end.x + ZN_SIZE, end.y + ZN_SIZE);
}
virtual void WmLButtonDown(POINT &mp){
begin = mp;
end = mp;
}
virtual void WmLButtonUp(POINT &mp){
end = mp;
}
virtual bool Select(POINT &ps){
if(CursorOnObject(ps)){
selected = true;
return true;
}
return false;
}
virtual bool Select(RECT &r){
if(PtInRect(&r, begin) && PtInRect(&r, end)){
selected = true;
return true;
}
return false;
}
virtual bool CursorOnObject(POINT &ps) const {
RECT r; // zmienna pomocnicza
SetRect(&r, min(begin.x, end.x), min(begin.y, end.y), max(begin.x, end.x), max(begin.y, end.y)); // ustawienie prostokąta
return PtInRect(&r, ps); // zwraca prawdę, gdy punkt jest w prostokącie a fałsz gdy nie jest
}
virtual RECT GetRect() const {
RECT r;
SetRect(&r, min(begin.x, end.x), min(begin.y, end.y), max(begin.x, end.x), max(begin.y, end.y));
return r;
}
};