Вращение объекта заданога координатами в 3d Формат файл: в данной задачи использовались следующие алгоритмы: 2. Получение матрицы поворота: 3. После получения новых координат проверяем каждую грань на видимость (параметр viz) ((x1-x0)*(y2-y0)-(y1-y0)*(x2-x0))*fig->c 4. После того как мы имеем новые координаты и определили для каждой грани видимость перерисовываем наш объект вызвав функцию Сначала задаём 2 вида кисти (сплошная прямая и пунктир) static const double dashed1[] = {4.0, 15.0}; static const double dashed2[] = {4.0, 0.0}; после затем строим, объект по граням: библиотека #ifndef CUBE_H_INCLUDED #define CUBE_H_INCLUDED #include <stdio.h> #include <stdlib.h> #include <math.h> #include <gtk/gtk.h> typedef struct POINT point;// точка struct POINT{ double x, y, z; }; typedef struct VERG verg;//грань struct VERG{ int size,//количество точек на грани viz,//видимость грани *mas;//массив точек }; typedef struct FIGURE figure;// фигура struct FIGURE{ int size_points;//кол-во точек в фигуре point *mas_points;// массив точек int size_verges;//кол-во граней в фигуре verg *mas_verges;//массив грней double matrix[4][4];// матрица поворота int c;// растояние до куба }; typedef struct TRANSP trans;//структура передачи struct TRANSP{ figure fig_tr; GtkWidget *window_tr; }; int get_data (char *file, figure *fig); void get_matrix(figure *fig); void MatrixMul(double *matrix1, figure *fig); void proverka (figure *fig); #endif // CUBE_H_INCLUDED файл обработки даных #include "cube.h" //считываем информацию из файла int get_data (char *file, figure *fig){ FILE *data; if ((data=fopen("//home//onimus//main_cube//cube.txt", "r"))==NULL){ printf("error"); return(1); } int i, j; //точки fscanf(data,"%d",&fig->size_points);//считали количество точек с файла fig->mas_points=(point*)malloc(fig->size_points*sizeof(point));// массив точек for (i=0;i<fig->size_points;i++){ fscanf(data, "%lf", &fig->mas_points[i].x); fscanf(data, "%lf", &fig->mas_points[i].y); fscanf(data, "%lf", &fig->mas_points[i].z); } //грани fscanf(data,"%d",&fig->size_verges);// кол-во граней fig->mas_verges=(verg*)malloc(fig->size_verges*sizeof(verg)); for (i=0;i<fig->size_verges;i++){ fig->mas_verges[i].viz=1; fscanf(data,"%d ",&fig->mas_verges[i].size);//кол-во точек в грани fig->mas_verges[i].mas=(int*)malloc(fig->mas_verges[i].size*sizeof(int)); for(j=0;j<fig->mas_verges[i].size;j++) fscanf(data,"%d", &fig->mas_verges[i].mas[j]); } fig->c=1; return 0; } //полчаем матрицу пофорота void get_matrix(figure *fig){ double angle= 1*M_PI/180; int k=4; double x=fig->mas_points[k].x; double y=fig->mas_points[k].y; double z=fig->mas_points[k].z; double norma= sqrt(x*x+y*y+z*z); x/=norma; y/=norma; z/=norma; fig->matrix[0][0]=(1-cos(angle))*(x*x-1)+1; fig->matrix[0][1]=sin(angle)*z+(1-cos(angle))*x*y; fig->matrix[0][2]=(1-cos(angle))*x*z-sin(angle)*y; fig->matrix[0][3]=0; fig->matrix[1][0]=(1-cos(angle))*x*y-sin(angle)*z; fig->matrix[1][1]=(1-cos(angle))*(y*y-1)+1; fig->matrix[1][2]=(1-cos(angle))*y*z+sin(angle)*x; fig->matrix[1][3]=0; fig->matrix[2][0]=(1-cos(angle))*x*z+sin(angle)*y; fig->matrix[2][1]=(1-cos(angle))*y*z-sin(angle)*x; fig->matrix[2][2]=(1-cos(angle))*(z*z-1)+1; fig->matrix[2][3]=0; fig->matrix[3][0]=0; fig->matrix[3][1]=0; fig->matrix[3][2]=0; fig->matrix[3][3]=1; } //умножение матрицы на вектор void MatrixMul(double *matrix1, figure *fig){ int i,j,n; double Ret[4]; double Sum; for (j = 0; j < 4; j++){ Sum = 0; for (n = 0; n < 4; n++){ Sum += matrix1[n] * fig->matrix[n][j]; } Ret[j] = Sum; } for (i=0;i<4;i++) matrix1[i]=Ret[i]; } //проверка видимых граней void proverka (figure *fig){ int x0, y0, z0, x1, y1, z1, x2, y2, z2, i; for(i=0;i<fig->size_verges;i++){ x0=fig->mas_points[fig->mas_verges[i].mas[1]].x; y0=fig->mas_points[fig->mas_verges[i].mas[1]].y; z0=fig->mas_points[fig->mas_verges[i].mas[1]].z; x1=fig->mas_points[fig->mas_verges[i].mas[0]].x; y1=fig->mas_points[fig->mas_verges[i].mas[0]].y; z1=fig->mas_points[fig->mas_verges[i].mas[0]].z; x2=fig->mas_points[fig->mas_verges[i].mas[2]].x; y2=fig->mas_points[fig->mas_verges[i].mas[2]].y; z2=fig->mas_points[fig->mas_verges[i].mas[2]].z; int k= ((x1-x0)*(y2-y0)-(y1-y0)*(x2-x0))*fig->c; if (k>0) fig->mas_verges[i].viz=1; else fig->mas_verges[i].viz=0; } } файл main.c #include "cube.h" GtkWidget *edit_metrs=NULL;//поле ввода дистанции double metr; //кубик не закрашеный с нивидмыми линиями с перспективой gboolean on_draw_4 (GtkWidget *widget, GdkEventExpose *event, gpointer data){ //fon GdkGC * gc = widget->style->fg_gc[GTK_WIDGET_STATE (widget)]; GdkColor *clr = malloc(sizeof(GdkColor)); gdk_color_parse("black", clr); gdk_gc_set_rgb_fg_color( gc, clr ); gdk_draw_rectangle(widget->window, gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_source_rgb(cr, 0, 0, 1); cairo_set_line_width (cr, 2); static const double dashed1[] = {4.0, 15.0}; static int len1 = sizeof(dashed1) / sizeof(dashed1[0]); static const double dashed2[] = {4.0, 0.0}; static int len2 = sizeof(dashed2) / sizeof(dashed2[0]); trans *t; t=(trans*)data; figure *cub; cub=&t->fig_tr; int i, j, l; int x1ee, y1ee, x2ee, y2ee; double x1, y1, z1, x2, y2, z2, x1t, y1t, x2t, y2t; float x0r=-200, y0r=-200, x1r=200, y1r=200 ; int x0e=0, y0e=0, x1e=widget->allocation.width, y1e=widget->allocation.height ; gdk_color_parse("blue", clr); gdk_gc_set_rgb_fg_color( gc, clr ); //считываем растояние до кубика char *metr_c=NULL; metr_c = (char*)gtk_entry_get_text(GTK_ENTRY(edit_metrs)); metr= atof(metr_c ); //по координатам вершин стрим каждую грань cub->c=metr; for(i=0;i<cub->size_verges;i++){ if(cub->mas_verges[i].viz){ cairo_set_dash(cr, dashed2, len2, 0); for (j=0;j<cub->mas_verges[i].size-1;j++){ x1=cub->mas_points[cub->mas_verges[i].mas[j]].x; y1=cub->mas_points[cub->mas_verges[i].mas[j]].y; z1=cub->mas_points[cub->mas_verges[i].mas[j]].z; x1t=x1/(1-(z1/cub->c)); y1t=y1/(1-(z1/cub->c)); x1ee = x0e+(x1e-x0e)/(x1r-x0r)*(x1t-x0r); y1ee = y0e+(y1e-y0e)/(y1r-y0r)*(y1t-y0r); x2=cub->mas_points[cub->mas_verges[i].mas[j+1]].x; y2=cub->mas_points[cub->mas_verges[i].mas[j+1]].y; z2=cub->mas_points[cub->mas_verges[i].mas[j+1]].z; x2t=x2/(1-(z2/cub->c)); y2t=y2/(1-(z2/cub->c)); x2ee = x0e+(x1e-x0e)/(x1r-x0r)*(x2t-x0r); y2ee = y0e+(y1e-y0e)/(y1r-y0r)*(y2t-y0r); cairo_line_to(cr, x1ee, y1ee); cairo_line_to(cr, x2ee, y2ee); cairo_stroke (cr); } l=0; x1=cub->mas_points[cub->mas_verges[i].mas[l]].x; y1=cub->mas_points[cub->mas_verges[i].mas[l]].y; z1=cub->mas_points[cub->mas_verges[i].mas[l]].z; x1t=x1/(1-(z1/cub->c)); y1t=y1/(1-(z1/cub->c)); x1ee = x0e+(x1e-x0e)/(x1r-x0r)*(x1t-x0r); y1ee = y0e+(y1e-y0e)/(y1r-y0r)*(y1t-y0r); l=cub->mas_verges[i].size-1; x2=cub->mas_points[cub->mas_verges[i].mas[l]].x; y2=cub->mas_points[cub->mas_verges[i].mas[l]].y; z2=cub->mas_points[cub->mas_verges[i].mas[l]].z; x2t=x2/(1-(z2/cub->c)); y2t=y2/(1-(z2/cub->c)); x2ee = x0e+(x1e-x0e)/(x1r-x0r)*(x2t-x0r); y2ee = y0e+(y1e-y0e)/(y1r-y0r)*(y2t-y0r); cairo_line_to(cr, x1ee, y1ee); cairo_line_to(cr, x2ee, y2ee); cairo_stroke (cr); } else{ cairo_set_dash(cr, dashed1, len1, 0); for (j=0;j<cub->mas_verges[i].size-1;j++){ x1=cub->mas_points[cub->mas_verges[i].mas[j]].x; y1=cub->mas_points[cub->mas_verges[i].mas[j]].y; z1=cub->mas_points[cub->mas_verges[i].mas[j]].z; x1t=x1/(1-(z1/cub->c)); y1t=y1/(1-(z1/cub->c)); x1ee = x0e+(x1e-x0e)/(x1r-x0r)*(x1t-x0r); y1ee = y0e+(y1e-y0e)/(y1r-y0r)*(y1t-y0r); x2=cub->mas_points[cub->mas_verges[i].mas[j+1]].x; y2=cub->mas_points[cub->mas_verges[i].mas[j+1]].y; z2=cub->mas_points[cub->mas_verges[i].mas[j+1]].z; x2t=x2/(1-(z2/cub->c)); y2t=y2/(1-(z2/cub->c)); x2ee = x0e+(x1e-x0e)/(x1r-x0r)*(x2t-x0r); y2ee = y0e+(y1e-y0e)/(y1r-y0r)*(y2t-y0r); cairo_line_to(cr, x1ee, y1ee); cairo_line_to(cr, x2ee, y2ee); cairo_stroke (cr); } l=0; x1=cub->mas_points[cub->mas_verges[i].mas[l]].x; y1=cub->mas_points[cub->mas_verges[i].mas[l]].y; z1=cub->mas_points[cub->mas_verges[i].mas[l]].z; x1t=x1/(1-(z1/cub->c)); y1t=y1/(1-(z1/cub->c)); x1ee = x0e+(x1e-x0e)/(x1r-x0r)*(x1t-x0r); y1ee = y0e+(y1e-y0e)/(y1r-y0r)*(y1t-y0r); l=cub->mas_verges[i].size-1; x2=cub->mas_points[cub->mas_verges[i].mas[l]].x; y2=cub->mas_points[cub->mas_verges[i].mas[l]].y; z2=cub->mas_points[cub->mas_verges[i].mas[l]].z; x2t=x2/(1-(z2/cub->c)); y2t=y2/(1-(z2/cub->c)); x2ee = x0e+(x1e-x0e)/(x1r-x0r)*(x2t-x0r); y2ee = y0e+(y1e-y0e)/(y1r-y0r)*(y2t-y0r); cairo_line_to(cr, x1ee, y1ee); cairo_line_to(cr, x2ee, y2ee); cairo_stroke (cr); } } cairo_destroy(cr); return TRUE; } //функция пересчёта координата и перерисовки при повороте gint time_step (gpointer data){ trans *l; l=(trans*)data; GtkWidget *widget; widget=l->window_tr; int i; double vector[4]={0,0,0,0}; for (i=0;i<l->fig_tr.size_points;i++){ vector[0]=l->fig_tr.mas_points[i].x; vector[1]=l->fig_tr.mas_points[i].y; vector[2]=l->fig_tr.mas_points[i].z; MatrixMul(vector, &l->fig_tr); proverka(&l->fig_tr); l->fig_tr.mas_points[i].x=vector[0]; l->fig_tr.mas_points[i].y=vector[1]; l->fig_tr.mas_points[i].z=vector[2]; } gtk_widget_queue_draw(widget); return 1; } void show (int argc, char *argv[]){ figure fig; char *path="//home//onimus//tests//main_cube//cube.txt"; if (get_data(path, &fig)) exit(1); get_matrix(&fig); gtk_init( &argc, &argv); GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request (window, 400, 400); trans fd;//хранит окно, массив точек и грани fd.window_tr=window; fd.fig_tr=fig; g_signal_connect (G_OBJECT (window), "expose_event", G_CALLBACK (on_draw_4),(gpointer)&fd);//рисуем объект g_timeout_add(10, (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(); } int main (int argc, char *argv[]){ GtkWidget *window=NULL,//окно для ввода *hbox=NULL,//контейнер хранящий поля ввода, подписи и кнопку *button=NULL, //кнопка *label_metrs=NULL;//подпись для растояния до мишени gtk_init(&argc, &argv); //окно полей ввода window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_resize(GTK_WINDOW(window), 300, 100); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_title (GTK_WINDOW (window), "Входные даные:"); gtk_container_set_border_width (GTK_CONTAINER (window), 20); //кнопка button = gtk_button_new_with_label (("рисуем куб")); //поля ввода edit_metrs=gtk_entry_new(); //метки label_metrs = gtk_label_new ("Расстояние "); //"контейнер" содержащий объекты hbox = gtk_vbox_new(FALSE, 9); gtk_container_add(GTK_CONTAINER (window), hbox); //---------------------------------------------------------- gtk_container_add(GTK_CONTAINER (hbox), label_metrs); gtk_container_add(GTK_CONTAINER (hbox), edit_metrs); gtk_container_add(GTK_CONTAINER (hbox), button); //при нажатии кнопки g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (show), NULL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
Ключевые слова:
вращение, трехмерный объект, чтение из файла
|
|||||||