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