1 /*  pdnmesh - a 2D finite element solver
2  *
3     Copyright (C) 2001-2005 Sarod Yatawatta <sarod@users.sf.net>
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8 
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17   $Id: surfmesh.c,v 1.4 2005/03/11 21:58:11 sarod Exp $
18 */
19 
20 /**********************************************************************/
21 /* mesh grid routines */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #ifndef WIN32
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtkgl.h>
34 #include <gdk/gdkglglext.h> /* for gdk_gl_glPoly* */
35 #endif/*WIN32*/
36 #ifdef WIN32
37 #include <windows.h>
38 #endif/*!WIN32*/
39 #include <GL/gl.h>
40 #include <GL/glu.h>
41 
42 #include "types.h"
43 
44 /* a mesh grid will be drawn on a new window */
45 
46 #ifndef WIN32
47 #define MAXGRID 5
48 static int beginX, beginY;
49 
50 static float sphi=90.0;
51 static float stheta=45.0;
52 static float sdepth=5.0/4.0 * (MAXGRID/2);
53 static float zNear=(MAXGRID/2)/10.0;
54 static float zFar=(MAXGRID/2)*3.0;
55 static float aspect=4.1/4.0;
56 
57 /* to keep track of mesh grid window */
58 GtkWidget *global_surf_mesh_window=NULL;
59 
60 static gboolean
motion_notify_event_meshgrid(GtkWidget * widget,GdkEventMotion * event,gpointer data)61 motion_notify_event_meshgrid(GtkWidget *widget,
62 								GdkEventMotion *event,
63 								gpointer data)
64 {
65 	 gboolean redraw=FALSE;
66 	 if ( event->state & GDK_BUTTON1_MASK) {
67 					sphi+=(float)(event->x-beginX)/4.0;
68 					stheta+=(float)(beginY-event->y)/4.0;
69 					redraw=TRUE;
70 	}
71 	if (event->state & GDK_BUTTON2_MASK ) {
72 			sdepth-=((event->y-beginY)/(widget->allocation.height))*(MAXGRID/2);
73 			redraw=TRUE;
74 	}
75 
76 	beginX=event->x;
77 	beginY=event->y;
78 	if (redraw)
79 				gtk_widget_queue_draw(widget);
80 
81 	return(TRUE);
82 }
83 
84 static gboolean
button_press_event_meshgrid(GtkWidget * widget,GdkEventButton * event,gpointer data)85 button_press_event_meshgrid(GtkWidget *widget,
86 								GdkEventButton *event,
87 								gpointer data)
88 {
89 			if (event->button==1) {
90 					beginX=event->x;
91 					beginY=event->y;
92 					return(TRUE);
93 			}
94 			if (event->button==2) {
95 					beginX=event->x;
96 					beginY=event->y;
97 					return(FALSE);
98 			}
99 			return(FALSE);
100 }
101 
102 static gboolean
button_press_event_popup_menu_meshgrid(GtkWidget * widget,GdkEventButton * event,gpointer data)103 button_press_event_popup_menu_meshgrid(GtkWidget *widget,
104 								GdkEventButton *event,
105 								gpointer data)
106 {
107 		if (event->button==3){
108 						gtk_menu_popup(GTK_MENU(widget), NULL,NULL,NULL,NULL,
109 												event->button,event->time);
110 			return(TRUE);
111 		}
112 		return(FALSE);
113 }
114 
115 /* calculate unit normal vector to given triangle */
116 /*static void
117 triangle_normal(double x1, double y1, double z1, double x2, double y2, double z2,
118          double x3, double y3, double z3) {
119  double v1,v2,v3,u1,u2,u3,n1,n2,n3;
120  extern int errno;
121  u1=x2-x1;u2=y2-y1;u3=z2-z1;
122  v1=x3-x1;v2=y3-y1;v3=z3-z1;
123 
124  n1=v2*u3-u2*v3;n2=u1*v3-v1*u3;n3=v1*u2-u1*v2;
125  errno=0;
126  v1=sqrt(ABS(n1*n1+n2*n2+n3*n3));
127 #ifdef DEBUG
128  if ( !errno )
129   printf("error\n");
130  printf("normal> %lf %lf %lf :%lf\n",n1,n2,n3,v1);
131 #endif
132  if(v1 != 0.0) {
133   n1/=v1;n2/=v1;n3/=v1;
134   glNormal3f(-(GLfloat)n1,-(GLfloat)n2,-(GLfloat)n3);
135 #ifdef DEBUG
136  printf("normal>> %lf %lf %lf\n",n1,n2,n3);
137 #endif
138  }
139 } */
140 
141 static void
draw_mesh_grid(void)142 draw_mesh_grid(void)
143 {
144   triangle *rec;
145 	int i;
146  GLfloat r,g,b;
147 	double elevation;
148 	if ( ABS(g_maxpot)<ABS(g_minpot) ) {
149      elevation=ABS(1.1*g_minpot);
150 	} else {
151      elevation=ABS(1.1*g_maxpot);
152 	}
153 
154 	glLineWidth(1.0);
155 /*  glColor3f(0.3,0.3,0.1); */
156   DAG_traverse_list_reset(&dt);
157 	rec=DAG_traverse_prune_list(&dt);
158 	while (rec) {
159      if (rec &&rec->status==LIVE) {
160        glBegin(GL_TRIANGLES);
161        i=(int)((Mzz(rec->p0,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels);
162       get_colour(&r,&g,&b,i, contour_levels);
163 	/* set the colour */
164 	   glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b);
165 					glVertex3f( (GLfloat)Mx(rec->p0,M), (GLfloat) My(rec->p0,M),(GLfloat)Mzz(rec->p0,current_plotting_contour,M)/elevation);
166        i=(int)((Mzz(rec->p1,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels);
167       get_colour(&r,&g,&b,i, contour_levels);
168 	/* set the colour */
169 	   glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b);
170 
171 					glVertex3f( (GLfloat)Mx(rec->p1,M), (GLfloat) My(rec->p1,M),(GLfloat)Mzz(rec->p1,current_plotting_contour,M)/elevation);
172        i=(int)((Mzz(rec->p2,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels);
173       get_colour(&r,&g,&b,i, contour_levels);
174 	/* set the colour */
175 	   glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b);
176 					glVertex3f( (GLfloat)Mx(rec->p2,M), (GLfloat) My(rec->p2,M),(GLfloat)Mzz(rec->p2,current_plotting_contour,M)/elevation);
177      /* normal vector */
178 /*     triangle_normal(Mx(rec->p0),My(rec->p0),Mzz(rec->p0,current_plotting_contour)/elevation,Mx(rec->p1),My(rec->p1),Mzz(rec->p1,current_plotting_contour)/elevation,Mx(rec->p2),My(rec->p2),Mzz(rec->p2,current_plotting_contour)/elevation); */
179        glEnd();
180 			}
181 		/*rt.print_record(rec); */
182    rec=DAG_traverse_prune_list(&dt);
183 	}
184 
185  plot_contour_all_in_3d(M);
186 
187 	glLineWidth(2.0);
188  /* plot boundaries */
189           glBegin(GL_LINES);
190  for (i=0; i<nedges; i++){
191   if ( edge_array[i].type==DR ) {
192 	   glColor3f(0.9f, 1.0f, 0.4f);
193 		} else {
194 			glColor3f(0.1f, 1.0f, 0.9f);
195 		}
196 
197 	         glVertex3f((GLfloat)Mx(edge_array[i].p1,M), (GLfloat)My(edge_array[i].p1,M), (GLfloat)0);
198 	         glVertex3f((GLfloat)Mx(edge_array[i].p2,M), (GLfloat)My(edge_array[i].p2,M), (GLfloat)0);
199  }
200 
201 					glEnd();
202 }
203 
204 static void
close_window_meshgrid(GtkWidget * widget,gpointer data)205 close_window_meshgrid(GtkWidget *widget, gpointer data)
206 {
207 	 gtk_widget_destroy(GTK_WIDGET(data));
208    /* set global flag to 0 */
209    global_surf_mesh_window= NULL;
210 }
211 
212 static void
close_window(GtkWidget * widget)213 close_window(GtkWidget *widget)
214 {
215    if(widget !=NULL) {
216 	  gtk_widget_destroy(GTK_WIDGET(widget));
217    }
218    /* set global flag to 0 */
219    global_surf_mesh_window= NULL;
220 }
221 
222 
223 /* used when degree of freedom of points > 1 */
224 static void
switch_to_next_eigenmode(GtkWidget * widget,gpointer data)225 switch_to_next_eigenmode(GtkWidget *widget, gpointer data)
226 {
227  GtkWidget *w=GTK_WIDGET(data); /* main window drawing area */
228  /* switch to next eigenmode */
229   if (solve_equation== POISSON || solve_equation == POISSON_SPARSE ) {
230    current_plotting_contour=0;
231   } else if (solve_equation == HELMHOLTZ ) {
232    current_plotting_contour++;
233   if ( current_plotting_contour >=degree_of_freedom )
234    current_plotting_contour=0;
235   } else if ((solve_equation == HELMHOLTZ_INHOMO)
236      || (solve_equation == HELMHOLTZ_FREQ)
237      || (solve_equation == HELMHOLTZ_BETA)) {
238    current_plotting_contour++;
239   if ( current_plotting_contour >=3*degree_of_freedom )
240    current_plotting_contour=0;
241   }
242 
243 
244 #ifdef DEBUG
245   g_print("%s: parent %s\" %d th eigenmode\"\n",gtk_widget_get_name(widget), gtk_widget_get_name(w), current_plotting_contour);
246 #endif
247 
248  gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE);
249  /* send redraw to main drawing area as well */
250  gdk_window_invalidate_rect(w->window, &w->allocation,TRUE);
251 }
252 
253 static GtkWidget *
create_popup_menu_meshgrid(GtkWidget * drawing_area,GtkWidget * window,GtkWidget * main_drawing_area)254 create_popup_menu_meshgrid(GtkWidget *drawing_area,GtkWidget *window, GtkWidget *main_drawing_area)
255 {
256 	GtkWidget *menu;
257 	GtkWidget *menu_item;
258 
259 	menu=gtk_menu_new();
260 	/* only for Helmholtz equation */
261   menu_item=gtk_menu_item_new_with_label("Next Eigenmode");
262   gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
263   g_signal_connect(G_OBJECT(menu_item),"activate",
264          G_CALLBACK(switch_to_next_eigenmode),(gpointer)main_drawing_area);
265   gtk_widget_show(menu_item);
266 
267 	/* Close Window */
268 	menu_item=gtk_menu_item_new_with_label("Close Window");
269 	gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
270 	g_signal_connect(G_OBJECT(menu_item), "activate",
271 									G_CALLBACK(close_window_meshgrid), window);
272 	gtk_widget_show(menu_item);
273 
274 	return(menu);
275 }
276 
277 static void
realize_meshgrid(GtkWidget * widget,gpointer data)278 realize_meshgrid (GtkWidget *widget,
279 								gpointer data)
280 {
281   /* material properties */
282   GLfloat mat_specular[]={0.4,0.4,0.4,1.0};
283   GLfloat mat_shininess[]={40.0};
284   GLfloat lightPosition[4]={0.0,0.0,1.0,1.0};
285 
286 		GdkGLContext *glcontext=gtk_widget_get_gl_context(widget);
287 		GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget);
288 
289 		GdkGLProc proc=NULL;
290 
291 
292 		if (!gdk_gl_drawable_gl_begin(gldrawable,glcontext))
293 					return;
294     /* glPolygonOffsetEXT */
295 		proc=gdk_gl_get_glPolygonOffsetEXT();
296 		if (proc==NULL) {
297 				proc=gdk_gl_get_proc_address("glPolygonOffset");
298 				if (proc==NULL) {
299 						g_print("Sorry, glPolygonOffset() is not supported by this renderer.\n");
300 						exit(1);
301 				}
302 		}
303 
304 		glEnable(GL_DEPTH_TEST);
305 		glDepthFunc(GL_LEQUAL);
306 		glClearColor(0.0,0.0,0.0,0.0);
307 		gdk_gl_glPolygonOffsetEXT(proc, 1.0, 1.0);
308 
309 		glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
310 		glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
311 		glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
312 		glShadeModel(GL_SMOOTH);
313     glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
314     glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
315 		glLightfv(GL_LIGHT0,GL_POSITION,lightPosition);
316     glColorMaterial(GL_FRONT,GL_DIFFUSE);
317 		glEnable(GL_CULL_FACE);
318 		glEnable(GL_LIGHT0);
319 		glEnable(GL_COLOR_MATERIAL);
320 		glEnable(GL_LIGHTING);
321 
322 		/* intialize mesh */
323     /* intial mesh ? */
324 
325 		gdk_gl_drawable_gl_end(gldrawable);
326 
327 		return;
328 }
329 
330 static gboolean
configure_event_meshgrid(GtkWidget * widget,GdkEventConfigure * event,gpointer data)331 configure_event_meshgrid(GtkWidget *widget,
332 								GdkEventConfigure *event,
333 								gpointer data)
334 {
335 		GdkGLContext *glcontext=gtk_widget_get_gl_context(widget);
336 		GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget);
337 
338 		GLfloat w=widget->allocation.width;
339 		GLfloat h=widget->allocation.height;
340 
341 		if(!gdk_gl_drawable_gl_begin(gldrawable,glcontext))
342 						return(FALSE);
343 		aspect=(float)w/(float)h;
344 		glViewport(0,0,w,h);
345 		gdk_gl_drawable_gl_end(gldrawable);
346 
347 		return(TRUE);
348 }
349 
350 
351 static gboolean
expose_event_meshgrid(GtkWidget * widget,GdkEventExpose * event,gpointer data)352 expose_event_meshgrid(GtkWidget *widget,
353 								GdkEventExpose *event,
354 								gpointer data)
355 {
356 			GdkGLContext *glcontext=gtk_widget_get_gl_context(widget);
357 			GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget);
358 
359 			if (!gdk_gl_drawable_gl_begin(gldrawable,glcontext))
360 							return(FALSE);
361 			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
362 			glMatrixMode(GL_PROJECTION);
363 			glLoadIdentity();
364 			gluPerspective(64.0,aspect,zNear,zFar);
365 			glMatrixMode(GL_MODELVIEW);
366 			glLoadIdentity();
367 
368 			glTranslatef(0.0,0.0,-sdepth);
369 			glRotatef(-stheta,1.0,0.0,0.0);
370 			glRotatef(sphi,0.0,0.0,1.0);
371 
372 			draw_mesh_grid();
373 
374 			if ( gdk_gl_drawable_is_double_buffered(gldrawable))
375 							gdk_gl_drawable_swap_buffers(gldrawable);
376 			else
377 						 glFlush();
378 
379 
380 			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
381 			gdk_gl_drawable_gl_end(gldrawable);
382 
383 			return(TRUE);
384 
385 }
386 
387 static GtkWidget *
create_mesh_grid_window(GdkGLConfig * glconfig,GtkWidget * main_area)388 create_mesh_grid_window(GdkGLConfig *glconfig, GtkWidget *main_area)
389 {
390 	GtkWidget *window;
391 	GtkWidget *vbox;
392 	GtkWidget *drawing_area;
393 	GtkWidget *menu;
394 
395 	window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
396 	gtk_window_set_title(GTK_WINDOW(window),"Surf Mesh");
397 
398 	gtk_container_set_reallocate_redraws(GTK_CONTAINER(window),FALSE);
399 	/* default signal handler */
400   g_signal_connect_swapped(GTK_OBJECT(window),"delete_event",
401    G_CALLBACK(close_window),NULL);
402 
403 	vbox=gtk_vbox_new(FALSE,0);
404 	gtk_container_add(GTK_CONTAINER(window),vbox);
405 	gtk_widget_show(vbox);
406 
407 	drawing_area=gtk_drawing_area_new();
408 	gtk_widget_set_size_request(drawing_area,DEFAULT_WIDTH,DEFAULT_HEIGHT);
409 	gtk_widget_set_gl_capability(drawing_area,
410 									glconfig,
411 									NULL,
412 									TRUE,
413 									GDK_GL_RGBA_TYPE);
414 
415 	gtk_widget_add_events(drawing_area,
416      GDK_BUTTON1_MOTION_MASK |
417 		 GDK_BUTTON2_MOTION_MASK |
418 		 GDK_BUTTON_PRESS_MASK |
419 		 GDK_VISIBILITY_NOTIFY_MASK);
420 
421 	g_signal_connect_after(G_OBJECT(drawing_area), "realize",
422 									G_CALLBACK(realize_meshgrid),NULL);
423 	g_signal_connect(G_OBJECT(drawing_area), "configure_event",
424 									G_CALLBACK(configure_event_meshgrid), NULL);
425 	g_signal_connect(G_OBJECT(drawing_area), "expose_event",
426 									G_CALLBACK(expose_event_meshgrid), NULL);
427 
428   g_signal_connect(G_OBJECT(drawing_area),"motion_notify_event",
429 									G_CALLBACK(motion_notify_event_meshgrid), NULL);
430 	g_signal_connect(G_OBJECT(drawing_area),"button_press_event",
431 									G_CALLBACK(button_press_event_meshgrid), NULL);
432 	/* more events */
433 
434 	gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE,TRUE,0);
435 	gtk_widget_show(drawing_area);
436 
437 	/* menu */
438   menu=create_popup_menu_meshgrid(drawing_area,window,main_area);
439 	g_signal_connect_swapped(G_OBJECT(drawing_area), "button_press_event",
440 									G_CALLBACK(button_press_event_popup_menu_meshgrid),menu);
441 
442 	return(window);
443 
444 }
445 
446 static GdkGLConfig *
configure_mesh_grid_window(void)447 configure_mesh_grid_window(void)
448 {
449   GdkGLConfig *glconfig;
450   /* try double buffered */
451 	glconfig=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB|
452 									GDK_GL_MODE_DEPTH |
453 									GDK_GL_MODE_DOUBLE);
454 	if (glconfig== NULL) {
455 		g_print("\n*** Cannot find the double buffered visual.\n");
456 		g_print("\n*** Trying single-buffered visual.\n");
457 
458 		/* single bufferd visual */
459 		glconfig=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB|
460 										GDK_GL_MODE_DEPTH);
461 	  if ( glconfig==NULL) {
462 				g_print("*** No appropriate OpenGL capable visual found.\n");
463 				exit(1);
464 		}
465  }
466 
467 	return(glconfig);
468 }
469 
470 /* display 3d view */
471 void
display_mesh_grid(GtkWidget * widget,gpointer data)472 display_mesh_grid(GtkWidget *widget, gpointer data)
473 {
474  /* widget we get as parameter is the drawing_area */
475 		GtkWidget *window;
476 		GdkGLConfig *glconfig;
477     if( global_surf_mesh_window==NULL ) {
478 		 glconfig=configure_mesh_grid_window();
479 		 window=create_mesh_grid_window(glconfig, GTK_WIDGET(data));
480      /* copy window address back to gloabal variable */
481      /* or set flag to 1 */
482      global_surf_mesh_window=window;
483 		 gtk_widget_show(window);
484     }
485 
486 }
487 #endif /* WIN32 */
488