Кривая Коха и её использование

2.png

Построить фрактал Коха, менять динамически параметры фрактала.

Данная программа на основе построение кривой Коха, строит
1 - классическую кривую Коха (в основании прямая);
2 - классическая кривая и её зеркальное отражение (в основании прямая);
3 - квадрат Коха (в основании квадрат);
4 - снежинка Коха (в основании квадрат);
5 - снежинка Коха (в основании правильный треугольник);
6 - треугольник Коха (в основании правильный треугольник).

Каждую секунду увеличивается степень кривизны объекта.
Объекты переключаются клавишами цифр в таком же порядке как написано выше.
Программа написана в Linux в среде Code :: Blocks скомпилирована GNU GCC.

Алгоритм:
1 функции Коха (KOH) передаются координаты прямой;
2 по этим координатам текущую прямую разбиваем на 3 части;
3 среднюю часть закрашиваем цветом фона;
4 средняя часть — основание равностороннего треугольника, зная координаты основания
найдём координаты третьей вершины треугольника по формуле
x = (x2 + x1)/2 + h * i * sina
y = (y2 + y1)/2 - h * i * cosa

где,
(x,y) — координаты искомой вершины;
(x1,y1) — координаты начальной точки отрезка средней части ;
(x2,y2) — координаты конечной точки отрезка средней части ;
h - высота нового равностороннего треугольника
h = L /(2 * sqrt(3));
L - длина основания
L = sqrt(pow((x1 - x2),2) + pow((y1 — y2),2));
i — булевая переменная; определяет в какую сторону ляжет треугольник
(справа или слева от отрезка заданного координатами x1,y1,x2,y2);
sina, cosa - углы между линией и осью ОХ
sina = (y2 - y1)/L;
cosa = (x2 - x1)/L;
5 рисуем боковые стороны этого треугольника;
6 рекурсивно вызываем эту функцию для новых отрезков которые мы получили;
тем самым увеличивая порядок искривления.

Для построение снежинки Коха. квадрата Коха и т д.
функции KOH передаются координаты всех прямых объекта.

#include <stdio.h>
#include <math.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include <time.h>
 
typedef struct TRANSP trans;//структура передачи
struct TRANSP{
    int o;//порядок искривления
    int switcer;//переключатель кривых
    GtkWidget *window_tr;//где рисуем
};
 
 
//фун-ия дробления прямой
void KOH(GtkWidget *w, int k, int o,  int x1, int y1, int x2, int y2, int i){
    cairo_t *cr;
    cr = gdk_cairo_create (w);
    cairo_set_line_width(cr, 5);
    cairo_set_source_rgb(cr, 0, 0, 0);
    // точка на 1/3 длины
        double x3 = x1 + (x2 - x1)/3;
        double y3 = y1 + (y2 - y1)/3;
 
     // точка на 2/3 длины
        double y4 = y1 + 2 * (y2 - y1)/3;
        double x4 = x1 + 2 * (x2 - x1)/3;
    //закрашиваем среднюю треть прямой
    cairo_line_to(cr, x3, y3);
    cairo_line_to(cr, x4, y4);
    cairo_stroke (cr);
      // длина линии
        double L = sqrt(pow((x1 - x2),2) + pow((y1 - y2),2));
        // высота нового равностороннего треугольника
        double h = L /(2 * sqrt(3));
        // углы между линией и осью ОХ
        double sina = (y2 - y1)/L;
        double cosa = (x2 - x1)/L;
 
        // вершина галочки
        double x5 = (x2 + x1)/2 + h * i * sina;
        double y5 = (y2 + y1)/2 - h * i * cosa ;
 
    // рисуем "галочку"
    cairo_set_source_rgb(cr, 0, 1, 0);
    cairo_set_line_width (cr, 2);
 
    cairo_line_to(cr, x3, y3);
    cairo_line_to(cr, x5, y5);
    cairo_line_to(cr, x5, y5);
    cairo_line_to(cr, x4, y4);
    cairo_stroke (cr);
 
 
    k++;// текущий порядок кривй Коха
    if (k<o){// рекурсивно вызываем эту фи-ию пока порядок кривизны не будет равен данному
        KOH(w,  k, o,  x1, y1, x3, y3, i);
        KOH(w,  k, o,  x3, y3, x5, y5, i);
        KOH(w,  k, o,  x5, y5, x4, y4, i);
        KOH(w,  k, o,  x4, y4, x2, y2, i);
    }
    cairo_destroy(cr);
}
 
gboolean on_draw (GtkWidget *widget, GdkEventExpose *event, gpointer data){
    trans *h;
    h=(trans*)data;
 
    int o, switcer;
    o=h->o;
    switcer=h->switcer;
    cairo_t *cr;
    cr = gdk_cairo_create (widget->window);
 
    //рисуем фон
    cairo_rectangle(cr, 0, 0, widget->allocation.width, widget->allocation.height);
    cairo_set_source_rgb(cr,0,0,0);
    cairo_fill(cr);
 
    // рисуем саму кривую
    cairo_set_source_rgb(cr,0,1,0);
    switch(switcer){
 
        //обычеая кривая Коха (в основе лежит обычная прямая)
        case 1:{
            int x1=20,                          y1=widget->allocation.height/2,
                x2=widget->allocation.width-20, y2=widget->allocation.height/2;
            int k=0;
 
            cairo_line_to(cr, x1, y1);
            cairo_line_to(cr, x2, y2);
            cairo_stroke (cr);
            cairo_destroy(cr);
            if (o>0)
                KOH(widget->window, k, o, x1, y1, x2, y2, 1);
        }
        break;
 
        //Двойная кривая Коха (в основе лежит обычная прямая,
        //но функциядробления вызывается 2 раза для верхнего искривлени и внутренего)
        case 2:{
            int x1=20,                          y1=widget->allocation.height/2,
                x2=widget->allocation.width-20, y2=widget->allocation.height/2;
            int k=0;
 
            cairo_set_source_rgb(cr,0,1,0);
 
            cairo_line_to(cr, x1, y1);
            cairo_line_to(cr, x2, y2);
            cairo_stroke (cr);
            cairo_destroy(cr);
            if (o>0){
                KOH(widget->window, k, o, x1, y1, x2, y2, 1);
                KOH(widget->window, k, o, x1, y1, x2, y2, -1);
            }
        }
        break;
 
        //квадрат коха (искревление идёт во внутрь)
        case 3:{
 
            int l=50,
                x1=l,                          y1=l,
                x2=widget->allocation.width-l, y2=l,
                x3=l,                          y3=widget->allocation.height-l,
                x4=widget->allocation.width-l, y4=widget->allocation.height-l,
                k=0;
 
                cairo_line_to(cr, x1, y1);
                cairo_line_to(cr, x2, y2);
 
                cairo_line_to(cr, x1, y1);
                cairo_line_to(cr, x3, y3);
 
                cairo_line_to(cr, x3, y3);
                cairo_line_to(cr, x4, y4);
 
                cairo_line_to(cr, x2, y2);
                cairo_line_to(cr, x4, y4);
                cairo_stroke (cr);
                cairo_destroy(cr);
 
 
            if (o>0){
                KOH(widget->window, k, o, x1, y1, x2, y2, -1);
                KOH(widget->window, k, o, x1, y1, x3, y3, 1);
                KOH(widget->window, k, o, x3, y3, x4, y4, 1);
                KOH(widget->window, k, o, x2, y2, x4, y4, -1);
            }
        }
        break;
        //Снежинка Коха (в основании лежит квадрат)
        case 4:{
            int l=150,
                x1=l,                          y1=l,
                x2=widget->allocation.width-l, y2=l,
                x3=l,                          y3=widget->allocation.height-l,
                x4=widget->allocation.width-l, y4=widget->allocation.height-l,
                k=0;
 
 
            cairo_line_to(cr, x1, y1);
            cairo_line_to(cr, x2, y2);
 
            cairo_line_to(cr, x1, y1);
            cairo_line_to(cr, x3, y3);
 
            cairo_line_to(cr, x3, y3);
            cairo_line_to(cr, x4, y4);
 
            cairo_line_to(cr, x2, y2);
            cairo_line_to(cr, x4, y4);
 
            cairo_stroke (cr);
            cairo_destroy(cr);
 
            if (o>0){
                KOH(widget->window, k, o, x1, y1, x2, y2, 1);
                KOH(widget->window, k, o, x1, y1, x3, y3, -1);
                KOH(widget->window, k, o, x3, y3, x4, y4, -1);
                KOH(widget->window, k, o, x2, y2, x4, y4, 1);
            }
        }
        break;
        //Снежинка Коха (в основании лежит правильный треугольник)
        case 5:{
 
            int l=50,
                x2, y2,
                x3=l,                          y3=widget->allocation.height-l-100,
                x4=widget->allocation.width-l, y4=widget->allocation.height-l-100,
                k=0;
 
            x2=(x4-x3)*cos(-M_PI/3)+x3;
            y2=(x4-x3)*sin(-M_PI/3)+y3;
 
            cairo_line_to(cr, x3, y3);
            cairo_line_to(cr, x4, y4);
 
            cairo_line_to(cr, x3, y3);
            cairo_line_to(cr, x2, y2);
 
            cairo_line_to(cr, x2, y2);
            cairo_line_to(cr, x4, y4);
 
            cairo_stroke (cr);
            cairo_destroy(cr);
 
            if (o>0){
                KOH(widget->window, k, o, x3, y3, x4, y4, -1);
                KOH(widget->window, k, o, x3, y3, x2, y2, 1);
                KOH(widget->window, k, o, x2, y2, x4, y4, 1);
            }
        }
        break;
        //Триугольник коха ( основании лежит правильный триугольник)
        case 6:{
            int l=50,
                x2, y2,
                x3=l,                          y3=widget->allocation.height-l*2,
                x4=widget->allocation.width-l, y4=widget->allocation.height-l*2,
                k=0;
 
            x2=(x4-x3)*cos(-M_PI/3)+x3;
            y2=(x4-x3)*sin(-M_PI/3)+y3;
 
            cairo_line_to(cr, x3, y3);
            cairo_line_to(cr, x4, y4);
 
            cairo_line_to(cr, x3, y3);
            cairo_line_to(cr, x2, y2);
 
            cairo_line_to(cr, x2, y2);
            cairo_line_to(cr, x4, y4);
 
            cairo_stroke (cr);
            cairo_destroy(cr);
 
            if (o>0){
                KOH(widget->window, k, o, x3, y3, x4, y4, 1);
                KOH(widget->window, k, o, x3, y3, x2, y2, -1);
                KOH(widget->window, k, o, x2, y2, x4, y4, -1);
            }
        }
        break;
    }
    return TRUE;
}
// Функ-ия каждую секнду перерисовывает кривую увеличвая порядок искривления
gint time_step (gpointer data){
    trans *l;
    l=(trans*)data;
    //GtkWidget *widget;
    //widget=(GtkWidget*)data;
    if (l->o>=5) l->o=0 ;//если порядок искривления больше 5 то возвращаемся к исходной кривой
    else l->o++;
    gtk_widget_queue_draw(l->window_tr);
    return 1;
}
//обработка нажатия клавиш
gboolean on_press (GtkWidget *window, GdkEventKey *key, gpointer data){
    trans *l;
    l=(trans*)data;
	l->o=0;//обнуляем порядок искривления
	switch(key->keyval){
    //при нажатии клавиши 1 рисуется кривая 1
		case 49:
            l->switcer=1;
        break;
    //при нажатии клавиши 2 рисуется кривая 2
        case 50:
            l->switcer=2;
        break;
    //при нажатии клавиши 3 рисуется кривая 3
        case 51:
            l->switcer=3;
		break;
    //при нажатии клавиши 4 рисуется кривая 4
		case 52:
            l->switcer=4;
        break;
    //при нажатии клавиши 5 рисуется кривая 5
		case 53:
            l->switcer=5;
		break;
    //при нажатии клавиши 6 рисуется кривая 6
		case 54:
            l->switcer=6;
        break;
	}
 
    return 0;
}
 
 
int main (int argc, char *argv[]){
	gtk_init( &argc, &argv);//инициализация GTK
	GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);// Создаём окно
	gtk_widget_set_size_request (window, 600, 600);// Размерность окна
 
    trans fd;
    fd.o=0;
    fd.switcer=1;
    fd.window_tr=window;
 
    g_signal_connect (G_OBJECT (window), "expose_event", G_CALLBACK (on_draw),(gpointer)&fd);//при создании вы фу-ию рисования
 
    g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (on_press), (gpointer)&fd);//обработчик события нажатия клвиш
 
    g_timeout_add(1000, (GSourceFunc) time_step, (gpointer)&fd);//перирисовка фрактала
 
 
  	g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK(gtk_main_quit), NULL);//обработчик закрытия
	gtk_widget_show_all(window);// вывод окна
	gtk_main();
 
    return 0;
}

Ключевые слова: 
кривая Коха, квадрат Коха, снежинка Коха, кривая Коха, фрактал
ВложениеРазмер
KOH.zip2.63 кб