/*
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: animate.c
*
* Description: Contains routines to animate a structural dynamics problem.
* You pretty much have to set-up the animation special -
* can't be just from a previous solve - because you have to
* make sure that there are displacement records for all nodes
* in the Tx and Ty DOFs. Pushing play registers a work
* procedure that actually does the animating. Stop removes
* the work proc and leaves the drawing in its last state.
* Both 2d and 3d line drawing are supported ...
*
****************************************************************************/
# include <stdio.h>
# include <math.h>
# include <unistd.h>
# include <X11/Xos.h>
# include <X11/Intrinsic.h>
# include <X11/StringDefs.h>
# include <X11/Xaw/Command.h>
# include <X11/Xaw/Repeater.h>
# include <X11/Xaw/AsciiText.h>
# include <X11/Shell.h>
# 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"
# include "fforward.xbm"
# include "rreverse.xbm"
# include "stop.xbm"
# define INITIAL_DELAY 60000
# define DELAY_INCREMENT 5000
extern Widget toplevel;
extern XtAppContext app_context;
static unsigned DismissButton = 1;
static unsigned ForwardButton = 2;
static unsigned ReverseButton = 3;
static unsigned StopButton = 4;
static unsigned RReverseButton= 5;
static unsigned FForwardButton=6;
static Widget animateShell;
static Widget animate_dw;
static Widget step_label;
static XtWorkProcId wpid = 0;
static int delay = INITIAL_DELAY;
static unsigned step;
static unsigned nsteps = 0;
static unsigned nelts = 0;
static struct s_record {
float x;
float y;
} **s_table;
static unsigned **connect = NULL;
static unsigned *num_connections = NULL;
static char layout_string [ ] =
"vertical { \
8 \
horizontal { \
8 \
animate_dw <+inf -100% * +inf -100%> \
8 \
} \
24 \
horizontal { \
8 \
dismiss \
((width animate_dw - width dismiss - \
width step_label - 5*width stop - 16) /2 ) <+inf> \
rreverse \
4 \
reverse \
4 \
stop \
4 \
forward \
4 \
fforward \
((width animate_dw - width dismiss - \
width step_label - 5*width stop - 16) /2 ) <+inf> \
step_label \
8 \
} \
8 \
}";
static String table =
"<Key>space: AutoRepeat(off) set()\n\
<Key>Return: AutoRepeat(off) set()\n\
<KeyUp>Return: AutoRepeat(saved) unset() AnimateAction(button)\n\
<KeyUp>space: AutoRepeat(saved) unset() AnimateAction(button)";
static String repeater_table =
"<Key>space: set()\n\
<Key>Return: set()\n\
<KeyUp>Return: unset() AnimateAction(button)\n\
<KeyUp>space: unset() AnimateAction(button)";
static Boolean AnimateOneStep (client_data)
XtPointer client_data;
{
struct timeval timeout;
Point points [MaxNodesPerElement];
unsigned i,j;
int direction = *((int *) &client_data);
char buffer [20];
Arg args [1];
timeout.tv_sec = 0;
timeout.tv_usec = delay;
select (0, 0, 0, 0, &timeout);
DW_RemoveAll (animate_dw);
DW_SetAutoRedraw (animate_dw, False);
for (i = 0 ; i < nelts ; i++) {
if (num_connections [i] == 2) {
DW_DrawLine (animate_dw, s_table [step - 1][connect [i][0] - 1].x,
s_table [step - 1][connect [i][0] - 1].y,
s_table [step - 1][connect [i][1] - 1].x,
s_table [step - 1][connect [i][1] - 1].y);
}
else {
for (j = 0 ; j < num_connections [i] ; j++) {
points [j].x = s_table [step - 1][connect [i][j] - 1].x;
points [j].y = s_table [step - 1][connect [i][j] - 1].y;
}
points [num_connections [i]].x = s_table [step - 1][connect [i][0] - 1].x;
points [num_connections [i]].y = s_table [step - 1][connect [i][0] - 1].y;
DW_DrawPolygon (animate_dw, True, points, num_connections [i] + 1);
}
}
DW_SetAutoRedraw (animate_dw, True);
sprintf (buffer, "%g", (step - 1)*analysis.step);
XtSetArg (args [0], XtNstring, buffer);
XtSetValues (step_label, args, 1);
step += direction;
if (step > nsteps)
step = 1;
else if (step < 1)
step = nsteps;
return False;
}
static void ChangeSpeed (increment)
int increment;
{
delay += increment;
if (delay < 0)
delay = 0;
}
static void ButtonCallback (w, client_data, call_data)
Widget w;
XtPointer client_data,
call_data;
{
unsigned selected = *(unsigned *) client_data;
if (selected == DismissButton) {
if (wpid) {
XtRemoveWorkProc (wpid);
wpid = 0;
}
XtPopdown (animateShell);
}
else if (selected == FForwardButton)
ChangeSpeed (-DELAY_INCREMENT);
else if (selected == RReverseButton)
ChangeSpeed (DELAY_INCREMENT);
else if (selected == ForwardButton && !wpid)
wpid = XtAppAddWorkProc (app_context, AnimateOneStep, (XtPointer) 1);
else if (selected == ReverseButton && !wpid)
wpid = XtAppAddWorkProc (app_context, AnimateOneStep, (XtPointer) -1);
else if (selected == StopButton && wpid) {
XtRemoveWorkProc (wpid);
wpid = 0;
}
}
static void AnimateAction (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 CreateAnimationShell ()
{
Arg args [10];
Cardinal n;
Widget group [6];
Pixel highlight;
Widget layout;
Widget dismiss;
Widget stop, forward, reverse, fforward, rreverse;
Pixmap stop_pix, forward_pix, reverse_pix;
Pixmap fforward_pix, rreverse_pix;
XtTranslations translations;
static XtActionsRec actions [ ] = {{"AnimateAction", AnimateAction}};
n = 0;
XtSetArg (args [n], XtNtitle, "Animation"); n++;
XtSetArg (args [n], XtNiconName, "Animation"); n++;
XtSetArg (args [n], XtNallowShellResize, True); n++;
animateShell = XtCreatePopupShell ("animateShell",topLevelShellWidgetClass,
toplevel, args, n);
n = 0;
XtSetArg (args [n],XtNlayout,StringToLayout(toplevel, layout_string)); n++;
layout = XtCreateManagedWidget ("layout", layoutWidgetClass,
animateShell, args, n);
n = 0;
XtSetArg (args [n], XtNgrid, False); n++;
XtSetArg (args [n], XtNborderWidth, 3); n++;
animate_dw = XtCreateManagedWidget ("animate_dw", drawingWidgetClass,
layout, args, n);
/*
* create the control buttons
*/
dismiss = XtCreateManagedWidget ("dismiss", commandWidgetClass,
layout, NULL, 0);
stop = XtCreateManagedWidget ("stop", commandWidgetClass,
layout, NULL, 0);
forward = XtCreateManagedWidget ("forward", commandWidgetClass,
layout, NULL, 0);
fforward = XtCreateManagedWidget ("fforward", repeaterWidgetClass,
layout, NULL, 0);
reverse = XtCreateManagedWidget ("reverse", commandWidgetClass,
layout, NULL, 0);
rreverse = XtCreateManagedWidget ("rreverse", repeaterWidgetClass,
layout, NULL, 0);
/*
* create a text widget for the time read-out
*/
n = 0;
XtSetArg (args [n], XtNeditType, XawtextRead); n++;
XtSetArg (args [n], XtNwidth, 80); n++;
XtSetArg (args [n], XtNpieceSize, 32); n++;
XtSetArg (args [n], XtNdisplayCaret, False); n++;
step_label = XtCreateManagedWidget ("step_label", asciiTextWidgetClass,
layout, args, n);
/*
* add the callbacks to the individual buttons
*/
XtAddCallback (dismiss, XtNcallback, ButtonCallback, &DismissButton);
XtAddCallback (forward, XtNcallback, ButtonCallback, &ForwardButton);
XtAddCallback (reverse, XtNcallback, ButtonCallback, &ReverseButton);
XtAddCallback (fforward, XtNcallback, ButtonCallback, &FForwardButton);
XtAddCallback (rreverse, XtNcallback, ButtonCallback, &RReverseButton);
XtAddCallback (stop, XtNcallback, ButtonCallback, &StopButton);
/*
* create a tab group mechanism
*/
group [0] = dismiss;
group [1] = rreverse;
group [2] = reverse;
group [3] = stop;
group [4] = forward;
group [5] = fforward;
XtSetArg (args [0], XtNborderColor, &highlight);
XtGetValues (layout, args, 1);
CreateTabGroup (animateShell, group, 6, highlight, True);
/*
* set the bitmaps for the control buttons
*/
stop_pix = XCreateBitmapFromData (XtDisplay (toplevel),
RootWindowOfScreen (XtScreen (toplevel)),
stop_bits, stop_width, stop_height);
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);
fforward_pix = XCreateBitmapFromData (XtDisplay (toplevel),
RootWindowOfScreen (XtScreen (toplevel)),
fforward_bits,fforward_width,fforward_height);
rreverse_pix = XCreateBitmapFromData (XtDisplay (toplevel),
RootWindowOfScreen (XtScreen (toplevel)),
rreverse_bits,rreverse_width,rreverse_height);
XtSetArg (args [1], XtNlabel, "");
XtSetArg (args [0], XtNbitmap, stop_pix);
XtSetValues (stop, args, 2);
XtSetArg (args [0], XtNbitmap, forward_pix);
XtSetValues (forward, args, 2);
XtSetArg (args [0], XtNbitmap, reverse_pix);
XtSetValues (reverse, args, 2);
XtSetArg (args [0], XtNbitmap, fforward_pix);
XtSetValues (fforward, args, 2);
XtSetArg (args [0], XtNbitmap, rreverse_pix);
XtSetValues (rreverse, args, 2);
XtRealizeWidget (animateShell);
XtAppAddActions (app_context, actions, 1);
translations = XtParseTranslationTable (table);
XtOverrideTranslations (forward, translations);
XtOverrideTranslations (reverse, translations);
XtOverrideTranslations (stop, translations);
XtOverrideTranslations (dismiss, translations);
translations = XtParseTranslationTable (repeater_table);
XtOverrideTranslations (fforward, translations);
XtOverrideTranslations (rreverse, translations);
AddDeleteWindowProtocol (animateShell, "AnimateAction(delete)");
return;
}
static void SetupArrays (dtable, element, numelts, numnodes)
Matrix dtable;
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 node-time displacements
*/
if (nsteps > 0) {
for (i = 0 ; i < nsteps ; i++)
Deallocate (s_table [i]);
Deallocate (s_table);
}
nsteps = MatrixRows (dtable);
s_table = Allocate (struct s_record *, nsteps);
for (i = 0 ; i < nsteps ; i++)
s_table [i] = Allocate (struct s_record, numnodes);
return;
}
static int first_time = 1;
void AnimateStructure (dtable, node, element, numnodes, numelts)
Matrix dtable;
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) {
CreateAnimationShell ();
first_time = 0;
}
/*
* find the max and min displaced coordinates
*/
x_max = x_min = node[1] -> x +
MatrixData (dtable) [1][1]*solution -> magnify;
y_max = y_min = node[1] -> y +
MatrixData (dtable) [1][2]*solution -> magnify;
for (i = 1 ; i <= MatrixRows (dtable) ; i++) {
for (j = 1 ; j <= MatrixCols (dtable)/2 ; j++) {
x = node[j] -> x+MatrixData (dtable) [i][2*j - 1]*solution -> magnify;
y = node[j] -> y+MatrixData (dtable) [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 (animateShell, animate_dw, minX, maxX, minY, maxY,
&Xscale, &Yscale, &width, &height);
SetFocus (XtNameToWidget (animateShell, "layout.forward"));
SetupArrays (dtable, element, numelts, numnodes);
for (i = 1 ; i <= nsteps ; i++) {
for (j = 1 ; j <= numnodes ; j++) {
x = node[j] -> x +
MatrixData (dtable) [i][2*j - 1]*solution -> magnify;
y = node[j] -> y +
MatrixData (dtable) [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 (animate_dw, "black");
step = 1;
AnimateOneStep ((XtPointer) 1);
}
void AnimateStructure3D (dtable, node, element, numnodes, numelts)
Matrix dtable;
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) {
CreateAnimationShell ();
first_time = 0;
}
maxX = minX = node[1] -> x +
MatrixData (dtable) [1][1]*solution -> magnify;
maxY = minY = node[1] -> y +
MatrixData (dtable) [1][2]*solution -> magnify;
maxZ = minZ = node[1] -> z +
MatrixData (dtable) [1][3]*solution -> magnify;
for (i = 1 ; i <= MatrixRows (dtable) ; i++) {
for (j = 1 ; j <= MatrixCols (dtable) / 3 ; j++) {
x = node[j] -> x +
MatrixData (dtable) [i][3*j - 2]*solution -> magnify;
y = node[j] -> y +
MatrixData (dtable) [i][3*j - 1]*solution -> magnify;
z = node[j] -> z +
MatrixData (dtable) [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 (dtable, element, numelts, numnodes);
for (i = 1 ; i <= nsteps ; i++) {
for (j = 1 ; j <= numnodes ; j++) {
x = node[j] -> x +
MatrixData (dtable) [i][3*j - 2]*solution -> magnify;
y = node[j] -> y +
MatrixData (dtable) [i][3*j - 1]*solution -> magnify;
z = node[j] -> z +
MatrixData (dtable) [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 (minY != maxY) {
maxY += 0.05*(maxY - minY);
minY -= 0.05*(maxY - minY);
}
else {
maxY += 0.05*(maxX - minX);
minY -= 0.05*(maxX - minX);
}
InitializeDrawingShell (animateShell, animate_dw, minX, maxX, minY, maxY,
&Xscale, &Yscale, &width, &height);
SetFocus (XtNameToWidget (animateShell, "layout.forward"));
DW_SetForeground (animate_dw, "black");
step = 1;
AnimateOneStep ((XtPointer) 1);
}
syntax highlighted by Code2HTML, v. 0.9.1