/* This file is part of the FElt finite element analysis package. Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /**************************************************************************** * * File: modal.c * * Description: Contains routines to draw the mode shapes for a modal * analysis problem. In a lot of ways this is like an animation * problem because we build a record for each mode (analogous * to a time-step in animation) so we can just whip quickly * through them. * ****************************************************************************/ # include # include # include # include # include # include # include # include # include "Layout.h" # include "TabGroup.h" # include "Solution.h" # include "problem.h" # include "Drawing.h" # include "util.h" # include "allocate.h" # include "draw3d.h" # include "procedures.h" # include "forward.xbm" # include "reverse.xbm" extern Widget toplevel; extern XtAppContext app_context; static unsigned DismissButton = 1; static unsigned ForwardButton = 2; static unsigned ReverseButton = 3; static unsigned SaveButton = 4; static Widget modalShell; static Widget modal_dw; static Widget mode_label; static Widget freq_label; static unsigned mode = 0; static unsigned nmodes = 0; static unsigned nelts = 0; typedef struct s_record { float x; float y; } screen_record; static screen_record **s_table; static screen_record *orig_s_table; static unsigned **connect = NULL; static unsigned *num_connections = NULL; static Matrix freq; static char layout_string [ ] = "vertical { \ 8 \ horizontal { \ 8 \ modal_dw <+inf -100% * +inf -100%> \ 8 \ } \ 24 \ horizontal { \ 8 \ dismiss \ 4 \ save \ ((width modal_dw - width dismiss - width save - width freq_label - \ width mode_label - 2*width forward - 28) /2 ) <+inf> \ reverse \ 4 \ forward \ ((width modal_dw - width dismiss - width save - width freq_label - \ width mode_label - 2*width forward - 28) /2 ) <+inf> \ mode_label \ 4 \ freq_label \ 8 \ } \ 8 \ }"; static String table = "space: AutoRepeat(off) set()\n\ Return: AutoRepeat(off) set()\n\ Return: AutoRepeat(saved) unset() ModalAction(button)\n\ space: AutoRepeat(saved) unset() ModalAction(button)"; static void ChangeDisplayedMode (direction) int direction; { Point points [MaxNodesPerElement]; unsigned i,j; char buffer [20]; Arg args [1]; DW_RemoveAll (modal_dw); DW_SetAutoRedraw (modal_dw, False); mode += direction; if (mode > nmodes) mode = 1; else if (mode < 1) mode = nmodes; if (solution -> plot_orig) { DW_SetLineStyle (modal_dw, DW_LineDashed); for (i = 0 ; i < nelts ; i++) { if (num_connections [i] == 2) { DW_DrawLine (modal_dw, orig_s_table [connect [i][0] - 1].x, orig_s_table [connect [i][0] - 1].y, orig_s_table [connect [i][1] - 1].x, orig_s_table [connect [i][1] - 1].y); } else { for (j = 0 ; j < num_connections [i] ; j++) { points [j].x = orig_s_table [connect [i][j] - 1].x; points [j].y = orig_s_table [connect [i][j] - 1].y; } points [num_connections [i]].x = orig_s_table [connect [i][0] - 1].x; points [num_connections [i]].y = orig_s_table [connect [i][0] - 1].y; DW_DrawPolygon (modal_dw, True, points, num_connections [i] + 1); } } DW_SetLineStyle (modal_dw, DW_LineSolid); } for (i = 0 ; i < nelts ; i++) { if (num_connections [i] == 2) { DW_DrawLine (modal_dw, s_table [mode - 1][connect [i][0] - 1].x, s_table [mode - 1][connect [i][0] - 1].y, s_table [mode - 1][connect [i][1] - 1].x, s_table [mode - 1][connect [i][1] - 1].y); } else { for (j = 0 ; j < num_connections [i] ; j++) { points [j].x = s_table [mode - 1][connect [i][j] - 1].x; points [j].y = s_table [mode - 1][connect [i][j] - 1].y; } points [num_connections [i]].x = s_table [mode - 1][connect [i][0] - 1].x; points [num_connections [i]].y = s_table [mode - 1][connect [i][0] - 1].y; DW_DrawPolygon (modal_dw, True, points, num_connections [i] + 1); } } DW_SetAutoRedraw (modal_dw, True); sprintf (buffer, "mode #%d", mode); XtSetArg (args [0], XtNstring, buffer); XtSetValues (mode_label, args, 1); sprintf (buffer, "freq=%g", mdata(freq,mode,1)); XtSetArg (args [0], XtNstring, buffer); XtSetValues (freq_label, args, 1); return; } static void ButtonCallback (w, client_data, call_data) Widget w; XtPointer client_data, call_data; { unsigned selected = *(unsigned *) client_data; if (selected == DismissButton) XtPopdown (modalShell); if (selected == SaveButton) DumpDrawingArea (modal_dw, "Save Mode Shape", True); else if (selected == ForwardButton) ChangeDisplayedMode (1); else if (selected == ReverseButton) ChangeDisplayedMode (-1); } static void ModalAction (w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { if (strcmp (params [0], "delete") == 0) ButtonCallback ((Widget) NULL, (XtPointer) &DismissButton, (XtPointer) NULL); else XtCallCallbacks (w, XtNcallback, NULL); } static void CreateModalShell () { Arg args [10]; Widget group [4]; Cardinal n; Widget layout; Widget dismiss; Widget save; Widget forward, reverse; Pixel highlight; Pixmap forward_pix, reverse_pix; XtTranslations translations; static XtActionsRec actions [ ] = {{"ModalAction", ModalAction}}; n = 0; XtSetArg (args [n], XtNtitle, "Mode shapes"); n++; XtSetArg (args [n], XtNiconName, "Mode shapes"); n++; XtSetArg (args [n], XtNallowShellResize, True); n++; modalShell = XtCreatePopupShell ("modalShell",topLevelShellWidgetClass, toplevel, args, n); n = 0; XtSetArg (args [n],XtNlayout,StringToLayout(toplevel, layout_string)); n++; layout = XtCreateManagedWidget ("layout", layoutWidgetClass, modalShell, args, n); n = 0; XtSetArg (args [n], XtNgrid, False); n++; XtSetArg (args [n], XtNborderWidth, 3); n++; modal_dw = XtCreateManagedWidget ("modal_dw", drawingWidgetClass, layout, args, n); /* * create the control buttons */ dismiss = XtCreateManagedWidget ("dismiss", commandWidgetClass, layout, NULL, 0); save = XtCreateManagedWidget ("save", commandWidgetClass, layout, NULL, 0); forward = XtCreateManagedWidget ("forward", commandWidgetClass, layout, NULL, 0); reverse = XtCreateManagedWidget ("reverse", commandWidgetClass, layout, NULL, 0); /* * create a text widget for the mode number display */ n = 0; XtSetArg (args [n], XtNeditType, XawtextRead); n++; XtSetArg (args [n], XtNwidth, 100); n++; XtSetArg (args [n], XtNpieceSize, 32); n++; XtSetArg (args [n], XtNdisplayCaret, False); n++; mode_label = XtCreateManagedWidget ("mode_label", asciiTextWidgetClass, layout, args, n); n = 0; XtSetArg (args [n], XtNeditType, XawtextRead); n++; XtSetArg (args [n], XtNwidth, 150); n++; XtSetArg (args [n], XtNpieceSize, 32); n++; XtSetArg (args [n], XtNdisplayCaret, False); n++; freq_label = XtCreateManagedWidget ("freq_label", asciiTextWidgetClass, layout, args, n); /* * add the callbacks to the individual buttons */ XtAddCallback (dismiss, XtNcallback, ButtonCallback, &DismissButton); XtAddCallback (save, XtNcallback, ButtonCallback, &SaveButton); XtAddCallback (forward, XtNcallback, ButtonCallback, &ForwardButton); XtAddCallback (reverse, XtNcallback, ButtonCallback, &ReverseButton); /* * set the bitmaps for the control buttons */ forward_pix = XCreateBitmapFromData (XtDisplay (toplevel), RootWindowOfScreen (XtScreen (toplevel)), forward_bits, forward_width, forward_height); reverse_pix = XCreateBitmapFromData (XtDisplay (toplevel), RootWindowOfScreen (XtScreen (toplevel)), reverse_bits, reverse_width, reverse_height); XtSetArg (args [1], XtNlabel, ""); XtSetArg (args [0], XtNbitmap, forward_pix); XtSetValues (forward, args, 2); XtSetArg (args [0], XtNbitmap, reverse_pix); XtSetValues (reverse, args, 2); /* * create a tab group for the buttons along the bottom of the shell */ group [0] = dismiss; group [1] = save; group [2] = reverse; group [3] = forward; XtSetArg (args [0], XtNborderColor, &highlight); XtGetValues (layout, args, 1); CreateTabGroup (modalShell, group, 4, highlight, True); XtRealizeWidget (modalShell); XtAppAddActions (app_context, actions, 1); translations = XtParseTranslationTable (table); XtOverrideTranslations (forward, translations); XtOverrideTranslations (reverse, translations); XtOverrideTranslations (dismiss, translations); XtOverrideTranslations (save, translations); AddDeleteWindowProtocol (modalShell, "ModalAction(delete)"); return; } static void SetupArrays (phi, element, numelts, numnodes) Matrix phi; Element *element; unsigned numelts; unsigned numnodes; { unsigned i,j; /* * create space for the connectivity table */ if (nelts > 0) { Deallocate (num_connections); for (i = 0 ; i < nelts ; i++) Deallocate (connect [i]); Deallocate (connect); } nelts = numelts; num_connections = Allocate (unsigned, numelts); connect = Allocate (unsigned *, numelts); for (i = 0 ; i < numelts ; i++) { num_connections [i] = element [i+1] -> definition -> shapenodes; connect [i] = Allocate (unsigned, num_connections [i]); for (j = 0 ; j < num_connections [i] ; j++) connect [i][j] = element[i+1] -> node[j+1] -> number; } /* * set-up the record of the nodal locations in each mode */ if (nmodes > 0) { for (i = 0 ; i < nmodes ; i++) Deallocate (s_table [i]); Deallocate (s_table); Deallocate (orig_s_table); } orig_s_table = Allocate (struct s_record, numnodes); nmodes = MatrixRows (phi); s_table = Allocate (struct s_record *, nmodes); for (i = 0 ; i < nmodes ; i++) s_table [i] = Allocate (struct s_record, numnodes); return; } static int first_time = 1; void DrawModeShapes (phi, lambda, node, element, numnodes, numelts) Matrix phi; Matrix lambda; Node *node; Element *element; unsigned numnodes; unsigned numelts; { unsigned i,j; float x_max, x_min, y_max, y_min; float maxX, minX, maxY, minY, Xscale, Yscale; float x,y; Dimension width, height; if (first_time) { CreateModalShell (); first_time = 0; } freq = CreateCopyMatrix (lambda); /* * find the max and min displaced coordinates */ x_max = x_min = node[1] -> x + MatrixData (phi) [1][1]*solution -> magnify; y_max = y_min = node[1] -> y + MatrixData (phi) [1][2]*solution -> magnify; for (i = 1 ; i <= MatrixRows (phi) ; i++) { for (j = 1 ; j <= MatrixCols (phi)/2 ; j++) { x = node[j] -> x+MatrixData (phi) [i][2*j - 1]*solution -> magnify; y = node[j] -> y+MatrixData (phi) [i][2*j]*solution -> magnify; if (x > x_max) x_max = x; else if (x < x_min) x_min = x; if (y > y_max) y_max = y; else if (y < y_min) y_min = y; } } if (x_min != x_max) { minX = x_min - 0.05*(x_max - x_min); maxX = x_max + 0.05*(x_max - x_min); } else { minX = x_min - 0.05*(y_max - y_min); maxX = x_max + 0.05*(y_max - y_min); } if (y_min != y_max) { minY = y_min - 0.05*(y_max - y_min); maxY = y_max + 0.05*(y_max - y_min); } else { minY = y_min - 0.05*(x_max - x_min); maxY = y_max + 0.05*(x_max - x_min); } InitializeDrawingShell (modalShell, modal_dw, minX, maxX, minY, maxY, &Xscale, &Yscale, &width, &height); SetFocus (XtNameToWidget (modalShell, "layout.forward")); SetupArrays (phi, element, numelts, numnodes); for (j = 1 ; j <= numnodes ; j++) { orig_s_table [node[j] -> number - 1].x = node[j] -> x; orig_s_table [node[j] -> number - 1].y = node[j] -> y; for (i = 1 ; i <= nmodes ; i++) { x = node[j] -> x + MatrixData (phi) [i][2*j - 1]*solution -> magnify; y = node[j] -> y + MatrixData (phi) [i][2*j]*solution -> magnify; s_table [i-1][node[j] -> number - 1].x = x; s_table [i-1][node[j] -> number - 1].y = y; } } DW_SetForeground (modal_dw, "black"); mode = 0; ChangeDisplayedMode (1); } void DrawModeShapes3D (phi, lambda, node, element, numnodes, numelts) Matrix phi; Matrix lambda; Element *element; Node *node; unsigned numnodes; unsigned numelts; { unsigned i,j; float maxX, minX, maxY, minY, maxZ, minZ, Xscale, Yscale; float xdiff, ydiff; float x,y,z, sx,sy; Dimension width, height; if (first_time) { CreateModalShell (); first_time = 0; } freq = CreateCopyMatrix (lambda); maxX = minX = node[1] -> x + MatrixData (phi) [1][1]*solution -> magnify; maxY = minY = node[1] -> y + MatrixData (phi) [1][2]*solution -> magnify; maxZ = minZ = node[1] -> z + MatrixData (phi) [1][3]*solution -> magnify; for (i = 1 ; i <= MatrixRows (phi) ; i++) { for (j = 1 ; j <= MatrixCols (phi) / 3 ; j++) { x = node[j] -> x + MatrixData (phi) [i][3*j - 2]*solution -> magnify; y = node[j] -> y + MatrixData (phi) [i][3*j - 1]*solution -> magnify; z = node[j] -> z + MatrixData (phi) [i][3*j]*solution -> magnify; if (x > maxX) maxX = x; else if (x < minX) minX = x; if (y > maxY) maxY = y; else if (y < minY) minY = y; if (z > maxZ) maxZ = z; else if (z < minZ) minY = z; } } Setup3D (minX,maxX,minY,maxY,minZ,maxZ); xdiff = maxX - minX; ydiff = maxY - minY; SetupArrays (phi, element, numelts, numnodes); for (j = 1 ; j <= numnodes ; j++) { Convert3Dto2D (node[j] -> x, node[j] -> y, node[j] -> z, xdiff, ydiff, &sx, &sy); orig_s_table [node[j] -> number - 1].x = sx; orig_s_table [node[j] -> number - 1].y = sy; for (i = 1 ; i <= nmodes ; i++) { x = node[j] -> x + MatrixData (phi) [i][3*j - 2]*solution -> magnify; y = node[j] -> y + MatrixData (phi) [i][3*j - 1]*solution -> magnify; z = node[j] -> z + MatrixData (phi) [i][3*j]*solution -> magnify; Convert3Dto2D (x, y, z, xdiff, ydiff, &sx, &sy); if (i == 1 && j == 1) { maxX = minX = sx; maxY = minY = sy; } else { if (sx > maxX) maxX = sx; else if (sx < minX) minX = sx; if (sy > maxY) maxY = sy; else if (sy < minY) minY = sy; } s_table [i-1][node[j] -> number - 1].x = sx; s_table [i-1][node[j] -> number - 1].y = sy; } } if (maxX != minX) { maxX += 0.05*(maxX - minX); minX -= 0.05*(maxX - minX); } else { maxX += 0.05*(maxY - minY); minX -= 0.05*(maxY - minY); } if (maxY != minY) { maxY += 0.05*(maxY - minY); minY -= 0.05*(maxY - minY); } else { maxY += 0.05*(maxX - minX); minY -= 0.05*(maxX - minX); } InitializeDrawingShell (modalShell, modal_dw, minX, maxX, minY, maxY, &Xscale, &Yscale, &width, &height); SetFocus (XtNameToWidget (modalShell, "layout.forward")); DW_SetForeground (modal_dw, "black"); mode = 0; ChangeDisplayedMode (1); }