/* pdnmesh - a 2D finite element solver Copyright (C) 2001-2005 Sarod Yatawatta This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id: dxf.c,v 1.24 2005/03/15 19:48:26 sarod Exp $ */ #include #include #include #include #include #include "types.h" extern Mesh M; extern poly_edge *edge_array; extern int nedges; /* array of poins in the DXF file */ point * dxf_point_array; /* size will be 3 more than actual no of points * to include outer triangle */ int dxf_points; /* current edge closest to cursor */ MY_INT current_edge_number; /* array to keep edges of triangles overlapping boundary edges */ MY_INT **triangle_edge_array; /* point closest to the mouse cursor in mesh */ MY_INT current_point_number; /* polygon list for boundary */ boundary_list blist; /* current selected polygon for editing */ dxf_polygon *current_polygon; /* filename for output */ char *output_cord_filename=0; typedef struct dxfedge_ { int p1; /* fist point */ int p2; /* next point */ } edge; /* data for list of edges - used in delaunay triangulation*/ typedef struct dxfelist_ { edge data; struct dxfelist_ *next; } elist; /* global no for current boundary */ unsigned long int boundary_no; /* function to get an edge from list */ /* __LOCAL__ */ static elist * E_get (elist * Lhead, edge * tt) { elist *temp; if (Lhead == 0) { tt = 0; return (0); } /* NULL */ *tt = Lhead->data; temp = Lhead; Lhead = Lhead->next; free (temp); return (Lhead); } /* function to insert an edge to list -- a queue */ static elist * E_insert (elist * Lhead, edge Ldata) { elist *temp, *tail; temp = (elist *) malloc (sizeof (elist)); temp->data.p1 = Ldata.p1; temp->data.p2 = Ldata.p2; /* first the null case */ if (Lhead == NULL) { temp->next = Lhead; Lhead = temp; return (Lhead); } /* list is not null */ /* find tha tail of the list */ tail = Lhead; while (tail->next) tail = tail->next; /* now we reach the last element */ temp->next = NULL; tail->next = temp; return (Lhead); } /* if edge (p0-p1) is on a boundary, return boundary number. * else return -1 */ static MY_INT is_this_edge_on_a_boundary(p0,p1) { /* find the ratio using x=(x1+lambda. x2)/(1+lambda) */ /* if x is on (x1-x2), lambda >0 , equal to y */ /* try to do robust computations */ int i; double xp0,xp1,xn0,xn1,yp0,yp1,yn0,yn1; xp0=Mx(p0,M); yp0=My(p0,M); xp1=Mx(p1,M); yp1=My(p1,M); #ifdef DEBUG printf("is_this_edge_on_a_boundary:consider points(%d,%d)\n",p0,p1); #endif for (i=0; i< nedges; i++) { xn0=Mx(edge_array[i].p1,M); yn0=My(edge_array[i].p1,M); xn1=Mx(edge_array[i].p2,M); yn1=My(edge_array[i].p2,M); #ifdef DEBUG printf("is_this_edge_on_a_boundary: edge %d\n",i); #endif if ( IS_ZERO((xn0-xp0)*(yp0-yn1)-(yn0-yp0)*(xp0-xn1)) /* ratio is equal magnitude, check sign */ && ( ((yn0-yp0)*(yp0-yn1)>0) /* if true, equal and +ve lambda. stop */ || (IS_ZERO((yn0-yp0)*(yp0-yn1)) && (xn0-xp0)*(xp0-xn1) >= 0))){ /* if we are here, point p0 is on line */ /* do the same check for point p1 */ #ifdef DEBUG printf("is_this_edge_on_a_boundary: point %d is on line %d\n",p0,i); #endif if ( IS_ZERO((xn0-xp1)*(yp1-yn1)-(yn0-yp1)*(xp1-xn1)) /* ratio is equal magnitude, check sign */ && ( ((yn0-yp1)*(yp1-yn1)>0) /* if true, equal and +ve lambda. stop */ || (IS_ZERO((yn0-yp1)*(yp1-yn1)) && (xn0-xp1)*(xp1-xn1) >= 0))){ return(i); } } } return(-1); /* not found */ } static int read_2_lines_at_a_time (FILE * fp, int *line1, char *line2, int line2_length) { int flag; int c, count; flag = fscanf (fp, "%d", line1); if (flag == EOF) { return (flag); } /*printf("read_:%d\n",*line1); */ /* skip rest of line */ do { if ((c = getc (fp)) == EOF) return (EOF); } while (c != '\n'); count = 0; do { if ((c = getc (fp)) == EOF) { return (EOF); } if (c == '\n') { line2[count] = '\0'; break; } if (!isblank((int)c)) { line2[count++] = c; } /*printf("read (%c) ",c); */ } while (count line2_length-1 we have overstepped buffer*/ if(count==line2_length-1) { line2[count] = '\0'; /* read out the rest of the line */ do { if ((c=getc(fp))==EOF) { return(EOF); } } while (c!='\n'); } #ifdef DEBUG printf(">>>>>>read_:%d and %s\n",*line1,line2); #endif return (count); } /* read DXF file */ int read_dxf_file_and_triangulate (const char *filename) { FILE *fp; int line1; char line2[20]; int flag; point p0, p1; edge etmp; double xmax, xmin, ymax, ymin; int pn; unsigned int i; triangle *tg; DAG_node *current_dag_node, *parent_dag_node; polygon temp_polygon; poly_edge e; elist *list = 0; Mesh G={0,0,0,0}; p0.z = p1.z = 0; BIT_init(&G, 10); /* global edges */ nedges=0; fp = fopen (filename, "r"); if (fp == NULL) { fprintf (stderr, "%s: %d: could not open file %s\n", __FILE__, __LINE__, filename); exit (1); } flag = 1; /* global edge array size */ while (flag != EOF) { flag = read_2_lines_at_a_time (fp, &line1, line2,20); if ((flag != EOF) && (line1 == 0) && !strcmp (line2, "LINE")) { #ifdef DEBUG printf("++++++++++++++++++++++++\n"); #endif /* new line def found */ do { flag = read_2_lines_at_a_time (fp, &line1, line2,20); } while ((flag != EOF) && (line1 != 10)); if (flag == EOF) { fprintf (stderr, "%s: %d: could not read file\n", __FILE__, __LINE__); break; } p0.x = strtod (line2, 0); #ifdef DEBUG printf("x0=%lf from %s\n",p0.x,line2); #endif do { flag = read_2_lines_at_a_time (fp, &line1, line2,20); } while ((flag != EOF) && (line1 != 20)); if (flag == EOF) { fprintf (stderr, "%s: %d: could not read file\n", __FILE__, __LINE__); break; } p0.y = strtod (line2, 0); #ifdef DEBUG printf("y0=%lf from %s\n",p0.y,line2); #endif do { flag = read_2_lines_at_a_time (fp, &line1, line2,20); } while ((flag != EOF) && (line1 != 11)); if (flag == EOF) { fprintf (stderr, "%s: %d: could not read file\n", __FILE__, __LINE__); break; } p1.x = strtod (line2, 0); #ifdef DEBUG printf("x1=%lf\n",p1.x); #endif do { flag = read_2_lines_at_a_time (fp, &line1, line2,20); } while ((flag != EOF) && (line1 != 21)); if (flag == EOF) { fprintf (stderr, "%s: %d: could not read file\n", __FILE__, __LINE__); break; } p1.y = strtod (line2, 0); #ifdef DEBUG printf("y1=%lf\n",p1.y); printf ("new line found: (%lf,%lf)--(%lf,%lf)\n", p0.x, p0.y, p1.x,p1.y); #endif etmp.p1 = BIT_insert (&G, p0); etmp.p2 = BIT_insert (&G, p1); /* sanity check. if we have an edge with zero length, * we do not insert it to the edge list. we consider that as a point */ if ( etmp.p1 != etmp.p2 ) { #ifdef DEBUG printf ("points inserted (%d)--(%d)\n", etmp.p1, etmp.p2); #endif /* insert edge to list */ list = E_insert (list, etmp); nedges++; } } } if (!fp) fclose (fp); xmax = -1000; xmin = 1000; ymax = -1000; ymin = 1000; for (i = 0; i < G.count; i++) { if (xmin > *((G.Narray[i])->xp)) { xmin = *((G.Narray[i])->xp); } if (xmax < *((G.Narray[i])->xp)) { xmax = *((G.Narray[i])->xp); } if (ymin > (G.Narray[i])->y) { ymin = (G.Narray[i])->y; } if (ymax < (G.Narray[i])->y) { ymax = (G.Narray[i])->y; } } g_xoff = -(xmax + xmin) * 0.5; g_yoff = -(ymax + ymin) * 0.5; /* now find the maximum value of coordinates */ ymax = ABS (ymax); xmax = ABS (xmax); xmin = ABS (xmin); ymin = ABS (ymin); if (xmax < ymax) xmax = ymax; if (xmax < ymin) xmax = ymin; if (xmax < xmin) xmax = xmin; g_xscale = xmax; g_yscale = xmax; /* allocate for point array */ dxf_points=G.count+3; if ((dxf_point_array=(point*)malloc((size_t)(dxf_points)*sizeof(point)))==0) { fprintf (stderr, "%s: %d: no free memory", __FILE__, __LINE__); exit (1); } /* boundary points */ if ((tg = (triangle *) malloc (sizeof (triangle))) == 0) { fprintf (stderr, "%s: %d: no free memory", __FILE__, __LINE__); exit (1); } p1.x = -3; p1.y = -3; if ((p1.z = (MY_DOUBLE *) malloc ((size_t) (degree_of_freedom) * sizeof (MY_DOUBLE))) == 0) { fprintf (stderr, "%s: %d: no free memory\n", __FILE__, __LINE__); exit (1); } p1.z[0] = 0; p1.val = FX; /* we dont care they are FX or not */ #ifdef DEBUG printf ("inserting point %d " MDF "," MDF "\n", 0, p1.x, p1.y); #endif tg->p0 = BIT_insert (&M, p1); p1.x = 3; p1.y = 0; if ((p1.z = (MY_DOUBLE *) malloc ((size_t) (degree_of_freedom) * sizeof (MY_DOUBLE))) == 0) { fprintf (stderr, "%s: %d: no free memory\n", __FILE__, __LINE__); exit (1); } p1.z[0] = 0; p1.val = FX; #ifdef DEBUG printf ("inserting point %d " MDF "," MDF "\n", 1, p1.x, p1.y); #endif tg->p1 = BIT_insert (&M, p1); p1.x = 0; p1.y = 3; if ((p1.z = (MY_DOUBLE *) malloc ((size_t) (degree_of_freedom) * sizeof (MY_DOUBLE))) == 0) { fprintf (stderr, "%s: %d: no free memory\n", __FILE__, __LINE__); exit (1); } p1.z[0] = 0; p1.val = FX; #ifdef DEBUG printf ("inserting point %d " MDF "," MDF "\n", 2, p1.x, p1.y); #endif tg->p2 = BIT_insert (&M, p1); tg->n = 0; /* triangle is alive */ tg->status = LIVE; /* make neighbours -1 */ tg->t0 = tg->t1 = tg->t2 = -1; ntriangles = 1; RBT_insert ((void *) tg, &rt); parent_dag_node = dt.root; current_dag_node = DAG_insert (&dt, parent_dag_node, (void *) tg); /* set pointer to dag */ tg->dag_p = current_dag_node; /* we have inserted the outer triangle */ /* now process the remaining points */ for (i = 0; i < G.count; i++) { p1.x = *((G.Narray[i])->xp); p1.y = (G.Narray[i])->y; p1.x += g_xoff; p1.x /= xmax; p1.y += g_yoff; p1.y /= xmax; if ((p1.z = (MY_DOUBLE *) malloc ((size_t) (1) * sizeof (MY_DOUBLE))) == 0) { fprintf (stderr, "%s: %d: no free memory\n", __FILE__, __LINE__); exit (1); } p1.z[0] = 0; p1.val=P_UNKNOWN; /* insert it to mesh */ pn = insert_point_to_mesh (p1); /* insert to point array too */ dxf_point_array[i+3].x=p1.x; dxf_point_array[i+3].y=p1.y; dxf_point_array[i+3].z=p1.z; dxf_point_array[i+3].val=p1.val; } /* remove intersections with edges */ /* create a temporary polygon with all edges */ init_poly(&temp_polygon); /* global edge storage */ if ((edge_array =(poly_edge *)malloc((size_t)nedges*sizeof(poly_edge)))==0){ fprintf(stderr, "%s: %d: no free memory\n", __FILE__,__LINE__); exit(1); } i=0; while (list) { list = E_get (list, &etmp); #ifdef DEBUG printf ("read_dxf: list edge (%d)--(%d)\n", etmp.p1, etmp.p2); #endif /* increment point number by 3 */ e.p1=etmp.p1+3; e.p2=etmp.p2+3; e.type=DR; /* arbitrary type */ insert_edge_to_poly(&temp_polygon,&e); /* also insert this to edge array */ edge_array[i].p1=e.p1; edge_array[i].p2=e.p2; edge_array[i++].type=E_UNKNOWN; } remove_polygon_mesh_intersections(&temp_polygon); destroy_polygon(&temp_polygon); BIT_free (&G); /* now construct an array, ntriangles by 3 * type int**. Each row corresponds to a triangle (including hidden). * live triangles will have 3 columns each row. (p0-p1),(p1-p2),(p2-p0) * edges on any boundary edge, each element of row will * give that edge number. if not -1 */ #ifdef DEBUG printf("total triangles=%d\n",ntriangles); #endif if ((triangle_edge_array =(MY_INT**)calloc((size_t)ntriangles,sizeof(MY_INT*)))==0){ fprintf(stderr, "%s: %d: no free memory\n", __FILE__,__LINE__); exit(1); } DAG_traverse_list_reset(&dt); tg=DAG_traverse_prune_list(&dt); while(tg) { if ( tg&&tg->status==LIVE) { #ifdef DEBUG printf("considering triangle %d for edges\n",tg->n); #endif /* add record to triangle_edge_array */ if ((triangle_edge_array[tg->n]=(MY_INT*)malloc((size_t)3*sizeof(MY_INT)))==0) { fprintf(stderr, "%s: %d: no free memory\n", __FILE__,__LINE__); exit(1); } /* now check each edge of triangle is on a boundary edge */ triangle_edge_array[tg->n][0]=is_this_edge_on_a_boundary(tg->p0,tg->p1); triangle_edge_array[tg->n][1]=is_this_edge_on_a_boundary(tg->p1,tg->p2); triangle_edge_array[tg->n][2]=is_this_edge_on_a_boundary(tg->p2,tg->p0); #ifdef DEBUG printf("edges (%d,%d,%d)\n",triangle_edge_array[tg->n][0], triangle_edge_array[tg->n][1], triangle_edge_array[tg->n][2]); #endif } tg=DAG_traverse_prune_list(&dt); } current_edge_number=-1; #ifdef DEBUG for (i=0;idata; if ( p ) { fprintf(outfd,"%d %d "MDF" "MDF"\n",p->nedges,(p->hollow?0:1),p->mu,p->rho); pint=p->head; while(pint) { fprintf(outfd,"%d\n",pint->n); pint=pint->next; } } } b=b->next; } fclose(outfd); } /********** below is mostly GTK stuff */ #ifndef WIN32 /* temp globals */ MY_DOUBLE temp_scratch_point_z; /* NOTE: we use the following for edge type as well */ int temp_scratch_point_type; /* callbacks for point edit */ static void edit_current_point_cb_update(GtkWidget *widget, gpointer data) { /* update the values of current point */ Mz(current_point_number,M)=temp_scratch_point_z; Mval(current_point_number,M)=temp_scratch_point_type; gtk_widget_destroy(GTK_WIDGET(data)); } static void edit_current_point_cb_cancel(GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } static void edit_current_point_cb_get_z( GtkWidget *widget, GtkWidget *entry ) { const gchar *entry_text; entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); temp_scratch_point_z=(MY_DOUBLE)strtod(entry_text,0); #ifdef DEBUG printf ("Entry contents: %s="MDF"\n", entry_text,temp_scratch_point_z); #endif } static void edit_current_point_cb_get_type(GtkWidget *widget,gpointer data) { temp_scratch_point_type=GPOINTER_TO_INT(data); } /* utility functions */ static GtkWidget * make_menu_item(gchar *name, GCallback callback, gpointer data) { GtkWidget *item; item=gtk_menu_item_new_with_label(name); g_signal_connect(G_OBJECT(item),"activate", callback,(gpointer)data); gtk_widget_show(item); return(item); } /* edit the properties of the point, given by current_point_number * which is a valid point */ static void edit_current_point_properties(void) { GtkWidget *window,*box1,*box2,*label,*button,*entry; GtkWidget *opt,*menu,*item; static gchar buf[30]; /* initialize temp globals */ temp_scratch_point_z=Mz(current_point_number,M); temp_scratch_point_type=Mval(current_point_number,M); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window),"delete_event", G_CALLBACK(gtk_main_quit),NULL); gtk_window_set_title(GTK_WINDOW(window),"Edit Point"); gtk_window_set_modal(GTK_WINDOW(window),TRUE); box1=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(window),box1); gtk_widget_show(box1); box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); sprintf(buf,"X["MIF"]=",current_point_number); label=gtk_label_new(buf); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); /* uneditable text */ entry = gtk_entry_new(); gtk_entry_set_max_length (GTK_ENTRY(entry), 50); sprintf(buf,MDF,Mx(current_point_number,M)); gtk_entry_set_text (GTK_ENTRY (entry), buf); gtk_editable_set_editable (GTK_EDITABLE(entry), FALSE); gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); gtk_widget_show(entry); box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); sprintf(buf,"Y["MIF"]=",current_point_number); label=gtk_label_new(buf); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); /* editable text */ entry = gtk_entry_new(); gtk_entry_set_max_length (GTK_ENTRY(entry), 50); sprintf(buf,MDF,My(current_point_number,M)); gtk_entry_set_text (GTK_ENTRY (entry), buf); gtk_editable_set_editable (GTK_EDITABLE(entry), FALSE); gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); gtk_widget_show(entry); /* editable parameters */ box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); sprintf(buf,"Z["MIF"]=",current_point_number); label=gtk_label_new(buf); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); /* editable text */ /* z value of a point */ entry = gtk_entry_new(); gtk_entry_set_max_length (GTK_ENTRY(entry), 50); sprintf(buf,MDF,Mz(current_point_number,M)); gtk_entry_set_text (GTK_ENTRY (entry), buf); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(edit_current_point_cb_get_z), (gpointer)entry); gtk_editable_set_editable (GTK_EDITABLE(entry), TRUE); gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); gtk_widget_show(entry); /* point type */ box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); label=gtk_label_new("Point Type:"); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); opt=gtk_option_menu_new(); menu=gtk_menu_new(); item=make_menu_item("variable", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(VAR)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); item=make_menu_item("fixed", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(FX)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); item=make_menu_item("unknown", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(P_UNKNOWN)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt),menu); if ( Mval(current_point_number,M)==VAR) { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),0); } else if ( Mval(current_point_number,M)==FX) { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),1); } else { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),2); } gtk_box_pack_start(GTK_BOX(box2),opt,TRUE,TRUE,0); gtk_widget_show(opt); /* cancel, update buttons */ box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); button=gtk_button_new_with_label("OK"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(edit_current_point_cb_update), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(button); button=gtk_button_new_with_label("Cancel"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(edit_current_point_cb_cancel), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); gtk_widget_show(button); gtk_widget_show(window); } /* callbacks for edge edit */ static void edit_current_edge_cb_update(GtkWidget *widget, gpointer data) { /* update the values of current point */ edge_array[current_edge_number].type=temp_scratch_point_type; gtk_widget_destroy(GTK_WIDGET(data)); } /* edit the properties of the edge, given by current_edge_number * which is a valid edge */ static void edit_current_edge_properties(void) { GtkWidget *window,*box1,*box2,*label,*button; GtkWidget *opt,*menu,*item; /* store default */ temp_scratch_point_type=edge_array[current_edge_number].type; window=gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window),"delete_event", G_CALLBACK(gtk_main_quit),NULL); gtk_window_set_title(GTK_WINDOW(window),"Edit Edge"); gtk_window_set_modal(GTK_WINDOW(window),TRUE); box1=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(window),box1); gtk_widget_show(box1); box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); label=gtk_label_new("Edge Type:"); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); opt=gtk_option_menu_new(); menu=gtk_menu_new(); item=make_menu_item("Neumann", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(VAR)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); item=make_menu_item("Dirichlet", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(FX)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); item=make_menu_item("unknown", G_CALLBACK(edit_current_point_cb_get_type), GINT_TO_POINTER(P_UNKNOWN)); gtk_menu_shell_append(GTK_MENU_SHELL(menu),item); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt),menu); if ( edge_array[current_edge_number].type==NU) { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),0); } else if ( edge_array[current_edge_number].type==DR) { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),1); } else { gtk_option_menu_set_history(GTK_OPTION_MENU(opt),2); } gtk_box_pack_start(GTK_BOX(box2),opt,TRUE,TRUE,0); gtk_widget_show(opt); /* cancel, update buttons */ box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); button=gtk_button_new_with_label("OK"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(edit_current_edge_cb_update), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(button); button=gtk_button_new_with_label("Cancel"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(edit_current_point_cb_cancel), window); /* NOTE: we use callback of edit_current_point_properties above */ gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); gtk_widget_show(button); gtk_widget_show(window); } static void display_boundary_edit_window(void); static void boundary_edit_add_boundary(GtkWidget *widget,gpointer data) { dxf_polygon *p; if ((p=(dxf_polygon*)malloc(sizeof(dxf_polygon)))==0) { fprintf(stderr,"%s: %d: no free memory",__FILE__,__LINE__); exit(1); } p->head=0; p->nedges=0; /* set default values */ p->hollow=0; p->rho=0; /* FIXME:this can be a string */ p->mu=1.0; insert_poly_to_boundary(&blist,p); /* untrack events */ mouse_responce_flag=MENU_0; /* close and reopen the window */ gtk_widget_destroy(GTK_WIDGET(data)); /* reopen */ display_boundary_edit_window(); } /* edit current boundary edge list */ static void boundary_edit_edit_boundary(GtkWidget *widget,gpointer data) { /* edit current polygon */ /* track closest edges */ mouse_responce_flag=MENU_ADD_EDGE; } static void boundary_edit_cancel(GtkWidget *widget,gpointer data) { /* untrack events */ mouse_responce_flag=MENU_0; /* sort all polygons of boundaries */ if ( sort_edges_in_polygons(&blist)== -1 ) { generic_dialog("At least One boundary is not closed. You may need to check them again.","Warning!"); } /* close the window */ gtk_widget_destroy(GTK_WIDGET(data)); } /* change edit status of texy entry field */ static void entry_toggle_editable( GtkWidget *button, GtkWidget *entry ) { gtk_editable_set_editable(GTK_EDITABLE (entry), GTK_TOGGLE_BUTTON (button)->active); } /* callback to record which button is being toggled */ static void record_toggle_button(GtkWidget *button, gpointer data) { /* untrack events */ mouse_responce_flag=MENU_0; #ifdef DEBUG printf("button %d on\n",GPOINTER_TO_INT(data)); #endif current_polygon=lookup_poly_from_boundary(&blist,GPOINTER_TO_INT(data)); } static void entry_get_hollow( GtkWidget *widget, GtkWidget *entry ) { const gchar *entry_text; entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); if ( current_polygon ) { current_polygon->hollow=atoi(entry_text); } #ifdef DEBUG printf ("Entry contents: %s=\n", entry_text); #endif } static void entry_get_mu( GtkWidget *widget, GtkWidget *entry ) { const gchar *entry_text; entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); if ( current_polygon ) { current_polygon->mu=(MY_DOUBLE)strtod(entry_text,0); } #ifdef DEBUG printf ("Entry contents: %s="MDF"\n", entry_text, current_polygon->mu); #endif } static void entry_get_rho( GtkWidget *widget, GtkWidget *entry ) { const gchar *entry_text; entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); if ( current_polygon ) { current_polygon->rho=(MY_DOUBLE)strtod(entry_text,0); } #ifdef DEBUG printf ("Entry contents: %s="MDF"\n", entry_text, current_polygon->rho); #endif } /* edit boundaries */ static void display_boundary_edit_window(void) { GtkWidget *window,*box1,*box2; GtkWidget *label,*button,*separator; GtkWidget *entry; /* array of buttons for the radio buttons */ GtkWidget **buttons=0; static gchar buf[30]; int i; poly_list *cp; window=gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window),"delete_event", G_CALLBACK(gtk_main_quit),NULL); gtk_window_set_title(GTK_WINDOW(window),"Boundary List"); gtk_window_set_modal(GTK_WINDOW(window),FALSE); box1=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(window),box1); gtk_widget_show(box1); /* traverse the boundary list */ cp=blist.head; /* allocate memory for button array */ if ((buttons=(GtkWidget **)malloc(sizeof(GtkWidget*)*(size_t)blist.count))==0) { fprintf (stderr, "%s: %d: no free memory", __FILE__, __LINE__); exit (1); } for (i=0;idata&&(cp->data->hollow==1)) { gtk_entry_set_text (GTK_ENTRY (entry), "1"); } else { gtk_entry_set_text (GTK_ENTRY (entry), "0"); } gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); /* connect signal to radio button */ if (!i) { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), TRUE); } else { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), FALSE); } g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_get_hollow), (gpointer)entry); gtk_widget_show(entry); label=gtk_label_new("mu="); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); /* create text entry */ entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry), 10); if (cp->data) { sprintf(buf,MDF,cp->data->mu); gtk_entry_set_text (GTK_ENTRY (entry), buf); } else { gtk_entry_set_text (GTK_ENTRY (entry), "???"); } gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); /* connect signal to radio button */ if (!i) { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), TRUE); } else { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), FALSE); } g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_get_mu), (gpointer)entry); gtk_widget_show(entry); label=gtk_label_new("rho="); gtk_box_pack_start(GTK_BOX(box2),label,FALSE,FALSE,0); gtk_widget_show(label); /* create text entry */ entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry), 10); if (cp->data) { sprintf(buf,MDF,cp->data->rho); gtk_entry_set_text (GTK_ENTRY (entry), buf); } else { gtk_entry_set_text (GTK_ENTRY (entry), "???"); } gtk_box_pack_start (GTK_BOX(box2), entry, FALSE, FALSE, 0); /* connect signal to radio button */ if (!i) { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), TRUE); } else { g_signal_connect (G_OBJECT (buttons[i]), "toggled", G_CALLBACK(entry_toggle_editable), (gpointer) entry); gtk_editable_set_editable (GTK_EDITABLE(entry), FALSE); } g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_get_rho), (gpointer)entry); gtk_widget_show(entry); g_signal_connect(G_OBJECT(buttons[i]),"pressed", G_CALLBACK(record_toggle_button),GINT_TO_POINTER(i)); cp=cp->next; } /* free buttons */ free(buttons); current_polygon=lookup_poly_from_boundary(&blist,0); /* seperator */ separator = gtk_hseparator_new(); gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); gtk_widget_show (separator); /* buttons */ box2=gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(box2),10); gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,0); gtk_widget_show(box2); button=gtk_button_new_with_label("New Boundary"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(boundary_edit_add_boundary), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(button); button=gtk_button_new_with_label("Add Edges"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(boundary_edit_edit_boundary), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(button); button=gtk_button_new_with_label("Done"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(boundary_edit_cancel), window); gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,0); gtk_widget_show(button); gtk_widget_show(window); } static void draw_circle(float x, float y, float radius) { float ang; glPushMatrix(); glTranslatef(x, y, 0); glBegin(GL_LINE_LOOP); for( ang=0; ang <= 2*M_PI; ang += 0.1) glVertex2f( radius * cos(ang), radius * sin(ang)); glEnd(); glPopMatrix(); } static void realize (GtkWidget *widget, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); /*** OpenGL BEGIN ***/ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) return; /*** Fill in the details here. ***/ gdk_gl_drawable_gl_end (gldrawable); /*** OpenGL END ***/ } static gboolean configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); GLfloat w = widget->allocation.width; GLfloat h = widget->allocation.height; /*g_print ("%s: \"configure_event\"\n", gtk_widget_get_name (widget)); */ /*** OpenGL BEGIN ***/ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) return FALSE; /*** Fill in the details here. ***/ glViewport (0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-1,1,-1,1); glMatrixMode(GL_MODELVIEW); gdk_gl_drawable_gl_end (gldrawable); /*** OpenGL END ***/ return TRUE; } static gboolean expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data) { int i; dxf_int *hh; GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); #ifdef DEBUG g_print ("%s: \"expose_event\"\n", gtk_widget_get_name (widget)); #endif /*** OpenGL BEGIN ***/ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) return FALSE; glClear (GL_COLOR_BUFFER_BIT); glLineWidth(1.0); /* triangle *rec; glColor3f(0.6f,0.3f,0.1f); DAG_traverse_list_reset(&dt); rec=DAG_traverse_prune_list(&dt); while(rec) { if ( rec&&rec->status==LIVE) { glBegin(GL_LINE_LOOP); glVertex2f((GLfloat)Mx(rec->p0),(GLfloat)My(rec->p0)); glVertex2f((GLfloat)Mx(rec->p1),(GLfloat)My(rec->p1)); glVertex2f((GLfloat)Mx(rec->p2),(GLfloat)My(rec->p2)); glEnd(); } rec=DAG_traverse_prune_list(&dt); } */ /* chosen triangle */ /* if ( chosen_triangle ) { glColor3f(1.0f, 0.3f, 1.0f); glLineWidth(1.0); glBegin(GL_LINE_LOOP); glVertex2f( (GLfloat)Mx(chosen_triangle->p0), (GLfloat)My(chosen_triangle->p0)); glVertex2f( (GLfloat)Mx(chosen_triangle->p1), (GLfloat)My(chosen_triangle->p1)); glVertex2f( (GLfloat)Mx(chosen_triangle->p2), (GLfloat)My(chosen_triangle->p2)); glEnd(); } */ if ( mouse_responce_flag==MENU_EDIT_POINT ) { /* points in the triangulation */ for (i=3;i2) && (current_point_number< dxf_points) ) { glColor3f(1.0f, 1.0f, 1.0f); glGetDoublev(GL_MODELVIEW_MATRIX,current_mat); draw_circle((float)Mx(current_point_number,M),(float)My(current_point_number,M),0.03f/current_mat[0]); } } /* edge array */ for ( i=0; i< nedges; i++ ) { if ( edge_array[i].type== DR ) { glColor3f(0.9f, 1.0f, 0.4f); } else if (edge_array[i].type== NU ) { glColor3f(0.4f,0.5f,0.9f); } else { glColor3f(1.0f,1.0f,1.0f); } glBegin(GL_LINE_LOOP); glVertex2f((GLfloat)Mx(edge_array[i].p1,M),(GLfloat)My(edge_array[i].p1,M)); glVertex2f((GLfloat)Mx(edge_array[i].p2,M),(GLfloat)My(edge_array[i].p2,M)); glEnd(); } /* closest edge */ if ( mouse_responce_flag==MENU_EDIT_EDGE || mouse_responce_flag==MENU_ADD_EDGE ) { if ( current_edge_number != -1 ) { glColor3f(0.1f,1.0f,0.9f); glLineWidth(2.0); glBegin(GL_LINES); glVertex2f((GLfloat)Mx(edge_array[current_edge_number].p1,M), (GLfloat)My(edge_array[current_edge_number].p1,M)); glVertex2f((GLfloat)Mx(edge_array[current_edge_number].p2,M), (GLfloat)My(edge_array[current_edge_number].p2,M)); glEnd(); } } /* draw current polygon while adding edges to it */ if ( mouse_responce_flag==MENU_ADD_EDGE ) { if ( current_polygon ) { hh=current_polygon->head; glColor3f(0.5f,0.3f,0.5f); glLineWidth(2.0); while(hh) { glBegin(GL_LINES); glVertex2f((GLfloat)Mx(edge_array[hh->n].p1,M), (GLfloat)My(edge_array[hh->n].p1,M)); glVertex2f((GLfloat)Mx(edge_array[hh->n].p2,M), (GLfloat)My(edge_array[hh->n].p2,M)); glEnd(); hh=hh->next; } } } /* zoom window */ /* draw zoom window */ if ( mouse_responce_flag == MENU_ZOOM_END ) { /* first point has been selected */ glBegin(GL_LINE_STRIP); glColor3f(0.0f, 1.0f, 1.0f); glVertex2f( (GLfloat)zoom_x1, (GLfloat)zoom_y1 ); glVertex2f( (GLfloat)zoom_x1, (GLfloat)zoom_y2 ); glVertex2f( (GLfloat)zoom_x2, (GLfloat)zoom_y2 ); glVertex2f( (GLfloat)zoom_x2, (GLfloat)zoom_y1 ); glVertex2f( (GLfloat)zoom_x1, (GLfloat)zoom_y1 ); glEnd(); } /*** Fill in the details here. ***/ /* Swap buffers */ if (gdk_gl_drawable_is_double_buffered (gldrawable)) gdk_gl_drawable_swap_buffers (gldrawable); else glFlush (); gdk_gl_drawable_gl_end (gldrawable); /*** OpenGL END ***/ return TRUE; } /* find the closet vertex of triangle t to * the point (x,y) */ static MY_INT find_closest_point(triangle *t,MY_DOUBLE x,MY_DOUBLE y) { double l0,l1,l2; if (t) { l0=LENGTH1(t->p0,x,y,M); l1=LENGTH1(t->p1,x,y,M); l2=LENGTH1(t->p2,x,y,M); return(((l0<=l1)&&(l0<=l2)?t->p0: (l1<=l2?t->p1:t->p2))); } return(0); } static double distance_to_line_from_point(MY_DOUBLE x,MY_DOUBLE y, MY_INT p0, MY_INT p1) { double a,b,c; if ( p0 > M.count || p1>M.count ) { printf("error: %d,%d > %d\n",p0,p1,M.count); abort(); } a=My(p1,M)-My(p0,M); b=Mx(p0,M)-Mx(p1,M); c=-a*Mx(p0,M)-b*My(p0,M); if ( a==0 && b== 0) return(sqrt((x-Mx(p0,M))*(x-Mx(p0,M))+(y-My(p0,M))*(y-My(p0,M)))); return(ABS((a*x+b*y+c)/sqrt(a*a+b*b))); } /* find the edge on the edge array, lying on an edge of * the triangle t, closest to point (x,y). point is inside t. * returns -1 if none found. */ static MY_INT find_closest_edge(triangle *t,MY_DOUBLE x,MY_DOUBLE y) { double d1,d2,d3; /* consider each vertex of the triangle */ /* check if they are on any of the edges. get the edge number */ /* finally, two of these edges must have be common * for a triangle edge to be on that edge. */ if (!triangle_edge_array[t->n] ||( triangle_edge_array[t->n][0]==-1 && triangle_edge_array[t->n][1]==-1 && triangle_edge_array[t->n][2]==-1 )) { return(-1); } #ifdef DEBUG printf("triangle %d, (%d,%d,%d)\n",t->n,t->p0,t->p1,t->p2); #endif /* if we are here, there is at least one boundary edge */ if (triangle_edge_array[t->n][0]==-1) { d1=10000; /* large value */ } else { #ifdef DEBUG printf("triangle edges %d,%d\n",triangle_edge_array[t->n][0],triangle_edge_array[t->n][0]); #endif d1=distance_to_line_from_point(x,y, edge_array[triangle_edge_array[t->n][0]].p1, edge_array[triangle_edge_array[t->n][0]].p2); } if (triangle_edge_array[t->n][1]==-1) { d2=10000; /* large value */ } else { #ifdef DEBUG printf("triangle edges %d,%d\n",triangle_edge_array[t->n][1],triangle_edge_array[t->n][1]); #endif d2=distance_to_line_from_point(x,y, edge_array[triangle_edge_array[t->n][1]].p1, edge_array[triangle_edge_array[t->n][1]].p2); } if (triangle_edge_array[t->n][2]==-1) { d3=10000; /* large value */ } else { #ifdef DEBUG printf("triangle edges %d,%d\n",triangle_edge_array[t->n][2],triangle_edge_array[t->n][2]); #endif d3=distance_to_line_from_point(x,y, edge_array[triangle_edge_array[t->n][2]].p1, edge_array[triangle_edge_array[t->n][2]].p2); } if (d1n][0]); if (d2n][1]); return(triangle_edge_array[t->n][2]); } /*** *** The "motion_notify_event" signal handler. Any processing required when *** the OpenGL-capable drawing area is under drag motion should be done here. ***/ static gboolean motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer data) { GLfloat mx,my; point p; DAG_node *current_dag_node; triangle *dxf_chosen_triangle; #ifdef DEBUG g_print ("%s: \"motion_notify_event\": button", gtk_widget_get_name (widget)); #endif mx=widget->allocation.width; my=widget->allocation.height; p.x=2*(double)event->x/(double)mx -1.0; p.y=-2*(double)event->y/(double)my +1.0; glGetDoublev(GL_MODELVIEW_MATRIX,current_mat); p.x=(p.x-current_mat[12])/current_mat[0]; p.y=(p.y-current_mat[13])/current_mat[5]; current_dag_node=DAG_find(&dt,(void*)&p,(void*)&M); if ( current_dag_node ) { dxf_chosen_triangle=(triangle*)current_dag_node->rec; /* find closest vertex of this triangle */ current_point_number=find_closest_point(dxf_chosen_triangle,p.x,p.y); /* out of the 3 edges of triangle, return the edge number * liying on the boundary edges. boundary edge number will be returned */ current_edge_number=find_closest_edge(dxf_chosen_triangle,p.x,p.y); gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); } if ( mouse_responce_flag==MENU_ZOOM_END ) { zoom_x2 = (2*( double )event->x/( double ) mx-1.0); zoom_y2 = -2*( double )event->y/( double ) my+1.0; /* convert back to world coords */ glGetDoublev(GL_MODELVIEW_MATRIX,current_mat); zoom_x2=(zoom_x2-current_mat[12])/current_mat[0]; zoom_y2=(zoom_y2-current_mat[13])/current_mat[5]; gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); return(TRUE); } return FALSE; } /*** *** The "button_press_event" signal handler. Any processing required when *** mouse buttons (only left and middle buttons) are pressed on the OpenGL- *** capable drawing area should be done here. ***/ static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data) { GLfloat mx,my; double temp; if (event->button == 1) { /*** Fill in the details here. ***/ if ( mouse_responce_flag==MENU_ZOOM_START) { mx=widget->allocation.width; my=widget->allocation.height; /* get click point coordinates */ zoom_x1 = (2*( double )event->x/( double ) mx-1.0); zoom_y1 = -2*( double )event->y/( double ) my+1.0; /* convert back to world coords */ glGetDoublev(GL_MODELVIEW_MATRIX,current_mat); zoom_x1=(zoom_x1-current_mat[12])/current_mat[0]; zoom_y1=(zoom_y1-current_mat[13])/current_mat[5]; /* eliminate previous zoom window */ zoom_x2=zoom_x1; zoom_y2=zoom_y1; #ifdef DEBUG g_print (" zoom start %lf %lf",zoom_x1,zoom_y1); #endif mouse_responce_flag=MENU_ZOOM_END; return(TRUE); } else if (mouse_responce_flag==MENU_ZOOM_END) { /* get click point coordinates */ mx=widget->allocation.width; my=widget->allocation.height; zoom_x2 = (2*( double )event->x/( double ) mx-1.0); zoom_y2 = -2*( double )event->y/( double ) my+1.0; /* convert back to world coords */ glGetDoublev(GL_MODELVIEW_MATRIX,current_mat); zoom_x2=(zoom_x2-current_mat[12])/current_mat[0]; zoom_y2=(zoom_y2-current_mat[13])/current_mat[5]; if ( zoom_x1 != zoom_x2 ) { /* first arrange points in zoom window */ if ( zoom_x1 > zoom_x2 ) { temp=zoom_x1; zoom_x1=zoom_x2; zoom_x2=temp; } if ( zoom_y1 < zoom_y2 ) { temp=zoom_y1; zoom_y1=zoom_y2; zoom_y2=temp; } /* now keep same aspect ratio as the figure */ zoom_y2=-(double)my/(double)mx*(zoom_x2-zoom_x1)+zoom_y1; glPushMatrix(); /* first zoom all */ glLoadIdentity(); /* then do the real zoom */ glScalef(-2.0/(zoom_x1-zoom_x2),2.0/(zoom_y1-zoom_y2),1.0); glTranslatef(-0.5*(zoom_x1+zoom_x2),-0.5*(zoom_y1+zoom_y2),0); /* redisplay */ gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); } #ifdef DEBUG g_print (" zoom end %lf %lf",zoom_x2,zoom_y2); #endif mouse_responce_flag=MENU_ZOOM_START; return(TRUE); } else if (mouse_responce_flag==MENU_EDIT_POINT) { /* this is the place where we handle editing point properties */ /* only edit a valid point */ if ((current_point_number>2) && (current_point_number< dxf_points) ) { edit_current_point_properties(); } return TRUE; } else if (mouse_responce_flag==MENU_EDIT_EDGE) { /* this is the place where we handle editing edge properties */ if (current_edge_number!=-1) { edit_current_edge_properties(); } return TRUE; } else if ( mouse_responce_flag==MENU_ADD_EDGE) { if ( current_edge_number!=-1 && current_polygon ) { #ifdef DEBUG g_print ("adding edge %d to polygon with edges %d\n",current_edge_number,current_polygon->nedges); #endif insert_remove_from_polygon(current_polygon,current_edge_number); } return(TRUE); } return TRUE; } return FALSE; } /* For popup menu. */ static gboolean button_press_event_popup_menu (GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->button == 3) { /* Popup menu. */ gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } return FALSE; } static void close_edit_window(GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); /*gdk_window_destroy(GDK_WINDOW(widget->window)); */ } static void switch_to_zoom_start(GtkWidget *widget) { mouse_responce_flag=MENU_ZOOM_START; } static void switch_to_edit_point(GtkWidget *widget) { mouse_responce_flag=MENU_EDIT_POINT; } static void switch_to_edit_edge(GtkWidget *widget) { mouse_responce_flag=MENU_EDIT_EDGE; } static void switch_to_edit_bound(GtkWidget *widget) { display_boundary_edit_window(); } static void switch_to_zoom_all(GtkWidget *widget) { glLoadIdentity(); gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); } static void switch_to_zoom_back(GtkWidget *widget) { glPopMatrix(); gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); } /* save as a coord file */ static void save_coord_file(GtkWidget *widget, gpointer data) { GtkWidget *file_selector=(GtkWidget*)data; const gchar *tempnm; tempnm=gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_selector)); output_cord_filename=(char*)realloc((void*)output_cord_filename,sizeof(char)*(size_t)(strlen((char*)tempnm)+1)); if ( output_cord_filename == 0 ) { fprintf(stderr,"%s: %d: no free memory",__FILE__,__LINE__); exit(1); } strcpy(output_cord_filename,(char*)tempnm); #ifdef DEBUG g_print("menubar_file_open: filename %s\n",output_cord_filename); #endif /* call the true save function */ write_to_output_cord_file(output_cord_filename); } static void get_save_coord_filename(GtkWidget *widget) { GtkWidget *file_selector; file_selector=gtk_file_selection_new("Please select a file"); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->ok_button), "clicked", G_CALLBACK(save_coord_file), (gpointer)file_selector); g_signal_connect_swapped(GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->ok_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)file_selector); g_signal_connect_swapped(GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)file_selector); gtk_widget_show(file_selector); } /*** *** Creates the popup menu to be displayed. ***/ static GtkWidget * create_popup_menu (GtkWidget *drawing_area) { GtkWidget *menu; GtkWidget *menu_item; menu = gtk_menu_new (); /* edit point */ menu_item=gtk_menu_item_new_with_label("Edit Points"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_edit_point),drawing_area); gtk_widget_show(menu_item); /* edit edge */ menu_item=gtk_menu_item_new_with_label("Edit Edges"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_edit_edge),drawing_area); gtk_widget_show(menu_item); /* edit boundaries */ menu_item=gtk_menu_item_new_with_label("Edit Boundaries"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_edit_bound),drawing_area); gtk_widget_show(menu_item); /* Zooming */ menu_item=gtk_menu_item_new_with_label("Zoom Window"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_zoom_start),drawing_area); gtk_widget_show(menu_item); menu_item=gtk_menu_item_new_with_label("Zoom Back"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_zoom_back),drawing_area); gtk_widget_show(menu_item); menu_item=gtk_menu_item_new_with_label("Zoom All"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_zoom_all),drawing_area); gtk_widget_show(menu_item); /* Save as coord file */ menu_item=gtk_menu_item_new_with_label("Save"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); g_signal_connect_swapped(G_OBJECT(menu_item),"activate", G_CALLBACK(get_save_coord_filename),drawing_area); gtk_widget_show(menu_item); /* Quit */ menu_item = gtk_menu_item_new_with_label ("Close"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (close_edit_window), drawing_area->parent->parent); gtk_widget_show (menu_item); return menu; } /*** *** Creates the simple application window with one *** drawing area that has an OpenGL-capable visual. ***/ static GtkWidget * create_edit_window (GdkGLConfig *glconfig, const char *title) { GtkWidget *window; GtkWidget *vbox; GtkWidget *drawing_area; GtkWidget *menu; /* * Top-level window. */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), title); /* Get automatically redrawn if any of their children changed allocation. */ gtk_container_set_reallocate_redraws (GTK_CONTAINER (window), TRUE); /* Connect signal handlers to the window */ g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL); /* * VBox. */ vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); /* * Drawing area to draw OpenGL scene. */ drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (drawing_area, DEFAULT_WIDTH, DEFAULT_HEIGHT); /* Set OpenGL-capability to the widget */ gtk_widget_set_gl_capability (drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_widget_add_events (drawing_area, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | /* any pointer motion */ GDK_VISIBILITY_NOTIFY_MASK); /* Connect signal handlers to the drawing area */ g_signal_connect_after (G_OBJECT (drawing_area), "realize", G_CALLBACK (realize), NULL); g_signal_connect (G_OBJECT (drawing_area), "configure_event", G_CALLBACK (configure_event), NULL); g_signal_connect (G_OBJECT (drawing_area), "expose_event", G_CALLBACK (expose_event), NULL); /* g_signal_connect (G_OBJECT (drawing_area), "unrealize", G_CALLBACK (unrealize), NULL); */ g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event", G_CALLBACK (motion_notify_event), NULL); g_signal_connect (G_OBJECT (drawing_area), "button_press_event", G_CALLBACK (button_press_event), NULL); gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); gtk_widget_show (drawing_area); /* * Popup menu. */ menu = create_popup_menu (drawing_area); g_signal_connect_swapped (G_OBJECT (drawing_area), "button_press_event", G_CALLBACK (button_press_event_popup_menu), menu); return window; } /*** *** Configure the OpenGL framebuffer. ***/ static GdkGLConfig * configure_edit_window (void) { GdkGLConfig *glconfig; /* Try double-buffered visual */ glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE); if (glconfig == NULL) { g_print ("\n*** Cannot find the double-buffered visual.\n"); g_print ("\n*** Trying single-buffered visual.\n"); /* Try single-buffered visual */ glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH); if (glconfig == NULL) { g_print ("*** No appropriate OpenGL-capable visual found.\n"); exit (1); } } return glconfig; } /* display edit window */ void display_edit_window( const char *title) { GtkWidget *window; GdkGLConfig *glconfig; glconfig=configure_edit_window(); window=create_edit_window(glconfig,title); gtk_widget_show(window); /* display dialog on to proceed with * defining point/edge proporties */ generic_dialog("DXF file has been sucessfully read!!. Now you must define properties of all points,\nedges and boundaries in the DXF file.","Next Step"); } /* generic dialog */ void generic_dialog(const gchar *msg,const gchar *title) { GtkWidget *dialog,*label; dialog=gtk_dialog_new_with_buttons(title, NULL, GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL); label=gtk_label_new(msg); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); gtk_widget_show_all(dialog); } #endif /*WIN32 */