Created
March 8, 2013 16:08
-
-
Save Novakov/5117540 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "GDI+ image.h" | |
typedef boost::gil::bgr8_pixel_t Pixel; | |
typedef boost::gil::bgr8_view_t View; | |
typedef boost::gil::bgr8c_view_t ViewReadOnly; | |
typedef boost::gil::bgr8_view_t::x_iterator Iterator_X; | |
typedef boost::gil::bgr8_view_t::y_iterator Iterator_Y; | |
typedef boost::gil::bgr8_view_t::locator Iterator_XY; | |
/// READ ME FIRST | |
void TheLookAtMeFakeFunction(View& view, const unsigned short& x, const unsigned short& y) | |
{ | |
// a View is the access to image's pixels ect. | |
// pixel access, slow but easy to understand | |
view(x, y); | |
view(x, y) = Pixel(0, 0, 255); // blue, green, red channels | |
// pixel access, optimalize for small x/y increments | |
Iterator_XY position = view.xy_at(x, y); | |
*position = Pixel(0, 0, 255); | |
++position.x(); // point at pixel(x+1, y) | |
--position.y(); // point at pixel(x, y-1) | |
// pixel access, row and column interators | |
unsigned int row_number = 0; | |
unsigned int column_number = 0; | |
Iterator_X itr_x = view.row_begin(row_number); | |
Iterator_Y itr_y = view.col_begin(column_number); | |
// the Windows applications coordinates system is used in this code | |
// origin point (0, 0) in the left upper corner | |
// do not forget: pixel(b,g,r), full_red(0, 0, 255), bright_red(130, 130, 255) | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// function declarations, draw line | |
void AntiAliasingDda(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
void SymmetricDda(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
void Bresenhama(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
// function declarations, draw circle | |
void Circle1Div4(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
void MidpointCircle1(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
void MidpointCircle2(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2); | |
// function declarations, draw eliphsis | |
void Ellipsis(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& a, const unsigned short& b); | |
// function declarations, flood area | |
void BoundryFill1Div4(View& view, const unsigned short& x, const unsigned short& y, | |
const Pixel& fill_color, const Pixel& border_color); | |
void BoundryFill1Div8(View& view, const unsigned short& x, const unsigned short& y, | |
const Pixel& fill_color, const Pixel& border_color); | |
//////////////////////////////////////////////////////////////////////////////// | |
void MyDda(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
double x = x1; | |
double y = y1; | |
double M; | |
double dy = 0; | |
double dx = 0; | |
if(x2 == x1) | |
{ | |
for(y = min(y1, y2); y <= max(y1,y2); y++) | |
{ | |
view(unsigned short(x1), unsigned short(y)) = Pixel(0,0,255); | |
} | |
return; | |
} | |
if(y2 == y1) | |
{ | |
for(y = min(x1, x2); x <= max(x1,x2); x++) | |
{ | |
view(unsigned short(x), unsigned short(y1)) = Pixel(0,0,255); | |
} | |
return; | |
} | |
double delta_x = (x2-x1)/abs(x2-x1); | |
double delta_y = (y2-y1)/abs(y2-y1); | |
M = (y1 - y2) / (double)(x1 - x2); | |
if(abs(M) > 1) | |
{ | |
M *= delta_y; | |
while(y != y2) | |
{ | |
x = x1 + dx; | |
double f = x - static_cast<unsigned int>(x); | |
if(f > 0.75) | |
{ | |
view(unsigned short(x), unsigned short(y)) = Pixel(0,0,255); | |
} | |
else if(f < 0.25) | |
{ | |
view(unsigned short(x-1), unsigned short(y)) = Pixel(0,0,255); | |
} | |
else | |
{ | |
int up_color = static_cast<unsigned int>(f * 255); | |
int down_color = 255 - up_color; | |
view(unsigned short(x), unsigned short(y)) = Pixel(up_color,up_color,255); | |
view(unsigned short(x-1), unsigned short(y)) = Pixel(down_color,down_color,255); | |
} | |
y+=delta_y; | |
dx+=1/M; | |
} | |
} | |
else | |
{ | |
M *= delta_x; | |
while(x != x2) | |
{ | |
y = y1 + dy; | |
double f = y - static_cast<unsigned int>(y); | |
if(f > 0.75) | |
{ | |
view(unsigned short(x), unsigned short(y)) = Pixel(0,0,255); | |
} | |
else if(f < 0.25) | |
{ | |
view(unsigned short(x), unsigned short(y-1)) = Pixel(0,0,255); | |
} | |
else | |
{ | |
int down_color = static_cast<unsigned int>(f * 255); | |
int up_color = 255 - down_color; | |
view(unsigned short(x), unsigned short(y-1)) = Pixel(up_color,up_color,255); | |
view(unsigned short(x), unsigned short(y)) = Pixel(down_color,down_color,255); | |
} | |
x+=delta_x; | |
dy+=M; | |
} | |
} | |
} | |
/// DrawThisLine, function used in WndProc() | |
void DrawThisLine(View& view, | |
const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
// NOTE: Pixel(0, 0, 255) is red it's a BGR channel | |
//AntiAliasingDda(view, x1, y1, x2, y2); | |
//SymmetricDda(view, x1, y1, x2, y2); | |
//Bresenhama(view, x1, y1, x2, y2); | |
MyDda(view, x1, y1, x2, y2); | |
} | |
/// DrawThisCircle, function used in WndProc() | |
void DrawThisCircle(View& view, | |
const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
//Circle1Div4(view, x1, y1, x2, y2); | |
//MidpointCircle1(view, x1, y1, x2, y2); | |
MidpointCircle2(view, x1, y1, x2, y2); | |
// fail | |
//Ellipsis(view, x1, y1, 50, 35); | |
}; | |
/// FloodThisArea, function used in WndProc() | |
void FloodThisArea(View& view, const unsigned short& x, const unsigned short& y) | |
{ | |
// NOTE: both works for small areas, due to perhaps filling the heap memory with recurrence calls | |
//BoundryFill1Div4(view, x, y, Pixel(255, 0, 0), Pixel(0, 0, 255)); // works fine for small circles | |
BoundryFill1Div8(view, x, y, Pixel(255, 0, 0), Pixel(0, 0, 255)); // for know reasons ka-boom when circle | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// | |
void AntiAliasingDda(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
// coordinates variables | |
int x = x1; | |
float y = y1; | |
// y = a*x + b, linear function | |
const float a = float(y2 - y1) / float(x2 - x1); | |
const float lower_no_anti_aliasing_tolerance = 0.25f; | |
const float higher_no_anti_aliasing_tolerance = 0.75f; | |
float anti_aliasing_delta_y = 0.0f; | |
unsigned char down_color = 0, up_color = 0; | |
for (x, y; x < x2; ++x, y += a) | |
{ | |
anti_aliasing_delta_y = y - static_cast<unsigned int>(y); | |
if (anti_aliasing_delta_y < lower_no_anti_aliasing_tolerance) | |
{ | |
view(x, unsigned short(y)) = Pixel(0, 0, 255); // simplifying down | |
} | |
else if (anti_aliasing_delta_y > higher_no_anti_aliasing_tolerance) | |
{ | |
view(x, unsigned short(y)+1) = Pixel(0, 0, 255); // simplifying up | |
} | |
else | |
{ | |
down_color = static_cast<unsigned char>(anti_aliasing_delta_y * 255); | |
up_color = 255 - down_color; | |
view(x, unsigned short(y)) = Pixel(down_color, down_color, 255); | |
view(x, unsigned short(y)+1) = Pixel(up_color, up_color, 255); | |
} | |
}; | |
} | |
// | |
void SymmetricDda(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
short delta_x = x2 - x1; | |
short delta_y = y2 - y1; | |
bool positive_delta_x = delta_x >= 0; | |
bool positive_delta_y = delta_y >= 0; | |
// maximum of two absolute values | |
short max_of_deltas = std::abs(delta_x) > std::abs(delta_y) ? std::abs(delta_x) : std::abs(delta_y) ; | |
// log2(max_of_deltas) | |
short n = short(std::logf((float)max_of_deltas) / std::logf(2.0f)); | |
short pow_2_n = static_cast<short>(std::pow(2.0f, n)); | |
// the 2^(n-1) case | |
if (pow_2_n < max_of_deltas) | |
{ | |
pow_2_n = static_cast<short>(std::pow(2.0f, (++n))); | |
}; | |
float epsilon = 1.0f / pow_2_n; | |
float increment_x = epsilon * delta_x; | |
float increment_y = epsilon * delta_y; | |
float x = positive_delta_x ? (x1 + 0.5f) : (x1 - 0.5f); | |
float y = positive_delta_y ? (y1 + 0.5f) : (y1 - 0.5f); | |
for (;;) // for is faster then while | |
{ | |
if (x >= view.width() || y >= view.height() || | |
(positive_delta_x ? (x > x2) : (x < x2)) || | |
(positive_delta_y ? (y > y2) : (y < y2)) ) | |
{ | |
break; | |
}; | |
// without anti-aliasing | |
view(unsigned short(x), unsigned short(y)) = Pixel(0, 0, 255); | |
x += increment_x; | |
y += increment_y; | |
} | |
} | |
// | |
void Bresenhama(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
unsigned short delta_x = x2 - x1; | |
unsigned short delta_y = y2 - y1; | |
short delta = 2 * delta_y - delta_x; | |
short increment_e = 2 * delta_y; | |
short increment_ne = 2 * (delta_y - delta_x); | |
unsigned short x = x1, y = y1; | |
Iterator_XY position = view.xy_at(x, y); | |
*position = Pixel(0, 0, 255); | |
for (; x < x2 ; ++x, ++position.x()) | |
{ | |
if (delta <= 0) | |
{ | |
delta += increment_e; | |
//++x; ++position.x(); | |
} | |
else | |
{ | |
delta += increment_ne; | |
//++x; ++position.x(); | |
++position.y(); // going north, that is south in this coordinate system :) | |
}; | |
*position = Pixel(0, 0, 255); | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// draw 4 pixels | |
void Draw4Pixels(View& view, const unsigned short& x, const unsigned short& y, | |
const unsigned short& dx, const unsigned short& dy) | |
{ | |
unsigned short safet_variable_x, safet_variable_y; | |
safet_variable_x = x + dx; | |
if (safet_variable_x < view.width()) | |
{ | |
safet_variable_y = y + dy; | |
if (safet_variable_y < view.height()) | |
{ | |
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255); | |
} | |
safet_variable_y = y - dy; | |
if (safet_variable_y < view.height()) | |
{ | |
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255); | |
} | |
} | |
safet_variable_x = x - dx; | |
if (safet_variable_x < view.width()) | |
{ | |
safet_variable_y = y + dy; | |
if (safet_variable_y < view.height()) | |
{ | |
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255); | |
} | |
safet_variable_y = y - dy; | |
if (safet_variable_y < view.height()) | |
{ | |
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255); | |
} | |
} | |
} | |
// draw Bresenhama circle 1/4 (old lab task) | |
void Circle1Div4(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
const short radius = static_cast<short>(std::sqrt( | |
std::pow(static_cast<float>(x2-x1), 2.0f) + | |
std::pow(static_cast<float>(y2-y1), 2.0f))); | |
unsigned short x = 0; | |
unsigned short y = radius; | |
short delta = 2 - 2*radius; | |
short sigma; | |
for (;;) | |
{ | |
// draw 4 pixels | |
Draw4Pixels(view, x1, y1, x, y); | |
if ((x == radius) && (y == 0)) | |
{ | |
break; | |
}; | |
//sigma = delta + delta; | |
sigma = 2 * delta; | |
if (sigma < 0) | |
{ | |
sigma += 2*y - 1; | |
if (sigma > 0) // choice D | |
{ | |
++x; | |
--y; | |
delta += 2*(x - y + 1); | |
} | |
else // choice H | |
{ | |
++x; | |
delta += 2*x + 1; | |
} | |
} | |
else | |
{ | |
sigma += -2*x + 1; | |
if (sigma <= 0) // choise D | |
{ | |
++x; | |
--y; | |
delta += 2*(x - y + 1); | |
} | |
else // choise V | |
{ | |
--y; | |
delta += -2*y +1; | |
} | |
} | |
} | |
} | |
// | |
void MidpointCircle1(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
const short radius = static_cast<short>(std::sqrt( | |
std::pow(static_cast<float>(x2-x1), 2.0f) + | |
std::pow(static_cast<float>(y2-y1), 2.0f))); | |
unsigned short x = 0; | |
unsigned short y = radius; | |
short delta = 5 - 4*radius; | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
for (;;) | |
{ | |
if (x > y) | |
{ | |
break; | |
} | |
if (delta < 0) | |
{ | |
delta += 4*(2*x + 3); | |
} | |
else | |
{ | |
delta += 4*(2*(x - y) + 5); | |
--y; | |
} | |
++x; | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
} | |
} | |
// | |
void MidpointCircle2(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& x2, const unsigned short& y2) | |
{ | |
const short radius = static_cast<short>(std::sqrt( | |
std::pow(static_cast<float>(x2-x1), 2.0f) + | |
std::pow(static_cast<float>(y2-y1), 2.0f))); | |
unsigned short x = 0; | |
unsigned short y = radius; | |
short delta = 5 - radius * 4; | |
short delta_e = 3 * 4; | |
short delta_se = 4*(5 - 2*radius); | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
for (;;) | |
{ | |
if (x >= y) | |
{ | |
break; | |
} | |
if (delta < 0) | |
{ | |
delta += delta_e; | |
delta_e += 2 * 4; | |
delta_se += 2 * 4; | |
} | |
else | |
{ | |
delta += delta_se; | |
delta_e += 2 * 4; | |
delta_se += 4 * 4; | |
--y; | |
} | |
++x; | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// TODO correct the code | |
void Ellipsis(View& view, const unsigned short& x1, const unsigned short& y1, | |
const unsigned short& a, const unsigned short& b) | |
{ | |
unsigned short x = 0; | |
unsigned short y = b; | |
unsigned short aa = a * a; | |
unsigned short bb = b * b; | |
short delta = 4*bb - 4*b*aa + aa; | |
short condition = (aa * aa) / (aa + bb); | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
for (;;) | |
{ | |
if (x*x > condition) | |
{ | |
break; | |
} | |
if (delta < 0) | |
{ | |
delta += 4*(2*x*bb + 3*bb); | |
} | |
else | |
{ | |
delta += 4*(2*bb*(x - y) + 3*bb + 2*aa); | |
//delta += 4*(2*bb*x - 2*aa*y + 3*bb + 2*aa); | |
--y; | |
} | |
++x; | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
} | |
x = 0; | |
y = a; | |
aa = b * b; | |
bb = a * a; | |
condition = (bb * bb) / (bb + aa); | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
for (;;) | |
{ | |
if (x*x > condition) | |
{ | |
break; | |
} | |
if (delta < 0) | |
{ | |
delta += 4*(2*x*bb + 3*bb); | |
} | |
else | |
{ | |
delta += 4*(2*bb*(x - y) + 3*bb + 2*aa); | |
//delta += 4*(2*bb*x - 2*aa*y + 3*bb + 2*aa); | |
--y; | |
} | |
++x; | |
Draw4Pixels(view, x1, y1, x, y); // horizontal | |
Draw4Pixels(view, x1, y1, y, x); // vertical | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// works for small areas, due to perhaps filling the heap memory with recurrence calls | |
void BoundryFill1Div4(View& view, const unsigned short& x, const unsigned short& y, | |
const Pixel& fill_color, const Pixel& border_color) | |
{ | |
Pixel color = view(x, y); | |
if ((color != fill_color) && (color != border_color)) | |
{ | |
view(x, y) = fill_color; | |
BoundryFill1Div4(view, x+1, y, fill_color, border_color); | |
BoundryFill1Div4(view, x-1, y, fill_color, border_color); | |
BoundryFill1Div4(view, x, y+1, fill_color, border_color); | |
BoundryFill1Div4(view, x, y-1, fill_color, border_color); | |
} | |
} | |
// works for small quadratic-like areas, due to perhaps filling the heap memory with recurrence calls | |
void BoundryFill1Div8(View& view, const unsigned short& x, const unsigned short& y, | |
const Pixel& fill_color, const Pixel& border_color) | |
{ | |
// NOTE: the eight neighbourhood implementation is useless when dealing with e.g. circles | |
Pixel color = view(x, y); | |
if ((color != fill_color) && (color != border_color)) | |
{ | |
view(x, y) = fill_color; | |
BoundryFill1Div8(view, x+1, y, fill_color, border_color); | |
BoundryFill1Div8(view, x-1, y, fill_color, border_color); | |
BoundryFill1Div8(view, x, y+1, fill_color, border_color); | |
BoundryFill1Div8(view, x, y-1, fill_color, border_color); | |
BoundryFill1Div8(view, x+1, y+1, fill_color, border_color); | |
BoundryFill1Div8(view, x+1, y-1, fill_color, border_color); | |
BoundryFill1Div8(view, x-1, y+1, fill_color, border_color); | |
BoundryFill1Div8(view, x-1, y-1, fill_color, border_color); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment