/* 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: vfe.c * * * * Description: This file contains the function definitions for the * * visualization of the finite element structures. * ************************************************************************/ # include # include # include # include # include # include "Drawing.h" # include "Canvas.h" # include "fe.h" # include "vfe.h" # include "error.h" # include "problem.h" # include "objects.h" # include "allocate.h" # include "globals.h" # include "procedures.h" # define Valid(x) (appearance.x != UnspecifiedValue) # define Present(x) (appearance.x != NULL) extern CanvasDialog canvas_d; static FigureAttributes attributes; /************************************************************************ * Function: DrawDisplayList * * * * Description: Draws the display list from the appearance structure. * ************************************************************************/ static void DrawDisplayList ( ) { unsigned i; unsigned j; Figure figure; Point points [1024]; FigInfo *info; /* In case no colors are fonts are specified. */ figure = NULL; if (DW_SetForeground (drawing, canvas -> tool_color) == False) DW_SetForeground (drawing, "black"); if (DW_SetFont (drawing, canvas -> tool_font) == False) DW_SetFont (drawing, "fixed"); for (i = 0; i < appearance.num_figures; i ++) { info = &appearance.figures [i]; if (info -> color) DW_SetForeground (drawing, info -> color); switch (info -> type) { case RECTANGLE: figure = DW_DrawRectangle (drawing, True, info -> x, info -> y, info -> width, info -> height); TreeInsert (figure_tree, figure); break; case POLYLINE: if (info -> num_points == 2) { figure = DW_DrawLine (drawing, info -> points [0].x, info -> points [0].y, info -> points [1].x, info -> points [1].y); } else if (info -> num_points > 2) { for (j = 0; j < info -> num_points; j ++) { points [j].x = info -> points [j].x; points [j].y = info -> points [j].y; } figure = DW_DrawPolygon (drawing, True, points, info -> num_points); } TreeInsert (figure_tree, figure); break; case TEXT: if (info -> font) DW_SetFont (drawing, info -> font); figure = DW_DrawText (drawing, True, info -> x, info -> y, info -> text); TreeInsert (figure_tree, figure); break; case ARC: figure = DW_DrawArc (drawing, True, info -> x, info -> y, info -> width, info -> height, info -> start, info -> length); TreeInsert (figure_tree, figure); break; } } } /************************************************************************ * Function: DrawProblem * * * * Description: Draw the problem. We try to present a suitable viewing * * of the problem if the appearance structure is not * * presence. If only some of the appearance structure is * * valid then we try to compromise and keep what * * information is valid. * ************************************************************************/ void DrawProblem (z) double z; { unsigned i; Node n; float xmin, xmax; float ymin, ymax; float scale; float xrange; float yrange; Dimension height; Dimension width; Cardinal count; Boolean new_limits; Arg arglist [10]; /* Compute the maximum and minimum values. */ xmin = 1; xmax = -1; ymin = 1; ymax = -1; for (i = 1; i <= problem.num_nodes; i ++) { n = problem.nodes [i]; if (n -> z == z) if (xmin > xmax) { xmin = xmax = n -> x; ymin = ymax = n -> y; } else { if (n -> x < xmin) xmin = n -> x; else if (n -> x > xmax) xmax = n -> x; if (n -> y < ymin) ymin = n -> y; else if (n -> y > ymax) ymax = n -> y; } } if (xmin > xmax && problem.num_nodes) error ("No nodes lie within the plane z = %g.", z); /* Expand the minimum and maximum a bit. */ if (xmin >= xmax) { xmin -= .1 * (ymax - ymin); xmax += .1 * (ymax - ymin); } if (ymin >= ymax) { ymin -= .1 * (xmax - xmin); ymax += .1 * (xmax - xmin); } if (xmax - xmin < ymax - ymin) canvas -> snap_size = canvas -> grid_size = (ymax - ymin) / 10; else canvas -> snap_size = canvas -> grid_size = (xmax - xmin) / 10; xrange = xmax - xmin; xmin -= .05 * xrange; xmax += .05 * xrange; xrange = xmax - xmin; yrange = ymax - ymin; ymin -= .05 * yrange; ymax += .05 * yrange; yrange = ymax - ymin; new_limits = False; /* If the x-axis limits are valid, then use them. */ if (Valid (x_min) && Valid (x_max)) if (appearance.x_min < appearance.x_max) { xmin = appearance.x_min; xmax = appearance.x_max; new_limits = True; } /* If the y-axis limits are valid, then use them. */ if (Valid (y_min) && Valid (y_max)) if (appearance.y_min < appearance.y_max) { ymin = appearance.y_min; ymax = appearance.y_max; new_limits = True; } /* Check the grid size and recompute it if necessary. */ if (Valid (grid_size)) canvas -> grid_size = appearance.grid_size; else if (new_limits) { if (xmax - xmin < ymax - ymin) canvas -> grid_size = (ymax - ymin) / 10; else canvas -> grid_size = (xmax - xmin) / 10; } /* Check the snap size and recompute it if necessary. */ if (Valid (snap_size)) canvas -> snap_size = appearance.snap_size; else if (new_limits) { if (xmax - xmin < ymax - ymin) canvas -> snap_size = (ymax - ymin) / 10; else canvas -> snap_size = (xmax - xmin) / 10; } count = 0; XtSetArg (arglist [count], XtNwidth, &width); count ++; XtSetArg (arglist [count], XtNheight, &height); count ++; XtGetValues (viewport, arglist, count); /* If the width, height, and scale are ALL valid, then use them. */ if (Valid (width) && Valid (height) && Valid (scale)) { scale = appearance.scale; width = appearance.width; height = appearance.height; } else { if (xrange / width > yrange / height) { scale = width / xrange; ymax += (xrange - yrange) / 2; ymin -= (xrange - yrange) / 2; } else { scale = height / yrange; xmax += (yrange - xrange) / 2; xmin -= (yrange - xrange) / 2; } } /* Set up the canvas dialog. */ canvas -> xmin = xmin; canvas -> xmax = xmax; canvas -> ymin = ymin; canvas -> ymax = ymax; canvas -> scale = scale; if (Valid (node_numbers)) canvas -> node_numbers = appearance.node_numbers; if (Valid (element_numbers)) canvas -> element_numbers = appearance.element_numbers; if (Present (node_color)) canvas -> node_color = strdup (appearance.node_color); if (Present (element_color)) canvas -> element_color = strdup (appearance.element_color); if (Present (label_font)) canvas -> label_font = strdup (appearance.label_font); if (Present (tool_color)) canvas -> tool_color = strdup (appearance.tool_color); if (Present (tool_font)) canvas -> tool_font = strdup (appearance.tool_font); CanvasDialogSet (canvas_d); if (Valid (grid) && appearance.grid != canvas -> grid) ToggleGridStatus ( ); if (Valid (snap) && appearance.snap != canvas -> snap) ToggleSnapStatus ( ); /* Draw the problem. */ for (i = 1; i <= problem.num_elements; i ++) if (problem.elements [i] != NULL) DrawElement (problem.elements [i], i == 1 ? True : False); for (i = 1; i <= problem.num_nodes; i ++) if (problem.nodes [i] != NULL) DrawNode (problem.nodes [i], i == 1 ? True : False); DrawDisplayList ( ); count = 0; XtSetArg (arglist [count], XtNwidth, width); count ++; XtSetArg (arglist [count], XtNheight, height); count ++; XtSetValues (viewport, arglist, count); XawViewportSetCoordinates (viewport, -appearance.x_pos, -appearance.y_pos); InitAppearance ( ); } /************************************************************************ * Function: DestroyProblem * * * * Description: Destroy the current problem invocation. * ************************************************************************/ void DestroyProblem (material_op) ItemDestructor material_op; { (void) TreeSetDestructor (problem.node_tree, (ItemDestructor) DestroyNode); (void) TreeDestroy (problem.node_tree); (void) TreeSetDestructor (problem.element_tree, (ItemDestructor) DestroyElement); (void) TreeDestroy (problem.element_tree); (void) TreeSetDestructor (problem.force_tree, (ItemDestructor) DestroyForce); (void) TreeDestroy (problem.force_tree); (void) TreeSetDestructor (problem.material_tree, (ItemDestructor) material_op); (void) TreeDestroy (problem.material_tree); (void) TreeSetDestructor (problem.constraint_tree, (ItemDestructor) DestroyConstraint); (void) TreeDestroy (problem.constraint_tree); (void) TreeSetDestructor (problem.distributed_tree, (ItemDestructor) DestroyDistributed); (void) TreeDestroy (problem.distributed_tree); } /************************************************************************ * Function: setnodenum * * * * Description: Sets the node numbering for a specified node. * ************************************************************************/ static int setnodenum (item) Item item; { static char number [10]; FigureAttributes attr; Node node; Drawn drawn; float x; float y; node = (Node) item; drawn = (Drawn) node -> aux; if (drawn -> figure == NULL) return 0; if (drawn -> label == NULL) { x = node -> x; y = node -> y; sprintf (number, " %d", node -> number); drawn -> label = DW_DrawText (drawing, True, x, y, number); attr.user_data = (char *) node; DW_SetAttributes (drawing, drawn -> label, DW_FigureUserData, &attr); } DW_SetAttributes (drawing, drawn -> label, DW_FigureVisible, &attributes); return 0; } /************************************************************************ * Function: SetNodeNumbering * * * * Description: Set the node numbering status. * ************************************************************************/ void SetNodeNumbering (value) int value; { if (DW_SetForeground (drawing, canvas -> node_color) == False) (void) DW_SetForeground (drawing, "black"); if (DW_SetFont (drawing, canvas -> label_font) == False) (void) DW_SetFont (drawing, "fixed"); attributes.visible = value; DW_SetAutoRedraw (drawing, False); (void) TreeSetIterator (problem.node_tree, setnodenum); (void) TreeIterate (problem.node_tree); DW_SetAutoRedraw (drawing, True); } /************************************************************************ * Function: setelementnum * * * * Description: Sets the element numbering for a specified element. * ************************************************************************/ static int setelementnum (item) Item item; { static char number [10]; FigureAttributes attr; Element element; Drawn drawn; float x; float y; element = (Element) item; drawn = (Drawn) element -> aux; if (drawn -> figure == NULL) return 0; if (drawn -> label == NULL) { ComputeCenter (element, &x, &y); sprintf (number, "%d", element -> number); drawn -> label = DW_DrawText (drawing, True, x, y, number); attr.user_data = (char *) element; DW_SetAttributes (drawing, drawn -> label, DW_FigureUserData, &attr); } DW_SetAttributes (drawing, drawn -> label, DW_FigureVisible, &attributes); return 0; } /************************************************************************ * Function: SetElementNumbering * * * * Description: Set the element numbering status. * ************************************************************************/ void SetElementNumbering (value) int value; { if (DW_SetForeground (drawing, canvas -> element_color) == False) (void) DW_SetForeground (drawing, "black"); if (DW_SetFont (drawing, canvas -> label_font) == False) (void) DW_SetFont (drawing, "fixed"); attributes.visible = value; DW_SetAutoRedraw (drawing, False); (void) TreeSetIterator (problem.element_tree, setelementnum); (void) TreeIterate (problem.element_tree); DW_SetAutoRedraw (drawing, True); } static int RecolorNode (item) Item item; { Node n; FigureAttributes attrib; Drawn drawn; n = (Node) item; drawn = (Drawn) n -> aux; if (n -> force && n -> force -> color) attrib.color = n -> force -> color; else if (n -> constraint -> color) attrib.color = n -> constraint -> color; else attrib.color = canvas -> node_color; if (drawn -> figure) DW_SetAttributes (drawing, drawn -> figure, DW_FigureColor, &attrib); if (drawn -> label) DW_SetAttributes (drawing, drawn -> label, DW_FigureColor, &attrib); return 0; } static int RecolorElement (item) Item item; { FigureAttributes attrib; Element e; Drawn drawn; e = (Element) item; drawn = (Drawn) e -> aux; if (e -> numdistributed && e -> distributed[1] -> color) attrib.color = e -> distributed[1] -> color; else if (e -> material -> color) attrib.color = e -> material -> color; else attrib.color = canvas -> element_color; if (drawn -> figure) DW_SetAttributes (drawing, drawn -> figure, DW_FigureColor, &attrib); if (drawn -> label) DW_SetAttributes (drawing, drawn -> label, DW_FigureColor, &attrib); return 0; } /************************************************************************ * Function: RecolorCanvas * * * * Description: Resets the color attribute of all nodes and elements * * based on possibly new values of object coloring * ************************************************************************/ void RecolorCanvas ( ) { DW_SetAutoRedraw (drawing, False); TreeSetIterator (problem.node_tree, RecolorNode); TreeIterate (problem.node_tree); TreeSetIterator (problem.element_tree, RecolorElement); TreeIterate (problem.element_tree); DW_SetAutoRedraw (drawing, True); return; }