1302 lines
36 KiB
C
1302 lines
36 KiB
C
/*****************************************************************************
|
|
*
|
|
* STATUSWRL.C - Nagios 3-D (VRML) Network Status View
|
|
*
|
|
* Copyright (c) 1999-2007 Ethan Galstad (egalstad@nagios.org)
|
|
* Last Modified: 07-16-2007
|
|
*
|
|
* Description:
|
|
*
|
|
* This CGI will dynamically create a 3-D VRML model of all hosts that are
|
|
* being monitored on your network.
|
|
*
|
|
* License:
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "../include/config.h"
|
|
#include "../include/common.h"
|
|
#include "../include/objects.h"
|
|
#include "../include/statusdata.h"
|
|
|
|
#include "../include/cgiutils.h"
|
|
#include "../include/getcgi.h"
|
|
#include "../include/cgiauth.h"
|
|
|
|
extern char main_config_file[MAX_FILENAME_LENGTH];
|
|
extern char url_html_path[MAX_FILENAME_LENGTH];
|
|
extern char url_images_path[MAX_FILENAME_LENGTH];
|
|
extern char url_logo_images_path[MAX_FILENAME_LENGTH];
|
|
|
|
extern char *statuswrl_include;
|
|
|
|
extern host *host_list;
|
|
extern service *service_list;
|
|
|
|
extern int default_statuswrl_layout_method;
|
|
|
|
|
|
#define NAGIOS_VRML_IMAGE "nagiosvrml.png"
|
|
|
|
#define DEFAULT_NODE_WIDTH 0.5
|
|
#define DEFAULT_HORIZONTAL_SPACING 1.0
|
|
#define DEFAULT_VERTICAL_SPACING 1.0
|
|
|
|
/* needed for auto-layout modes */
|
|
#define DEFAULT_NODE_HEIGHT 0.5
|
|
#define DEFAULT_NODE_HSPACING 1.0
|
|
#define DEFAULT_NODE_VSPACING 1.0
|
|
#define CIRCULAR_DRAWING_RADIUS 5.0
|
|
|
|
#define LAYOUT_USER_SUPPLIED 0
|
|
#define LAYOUT_COLLAPSED_TREE 2
|
|
#define LAYOUT_BALANCED_TREE 3
|
|
#define LAYOUT_CIRCULAR 4
|
|
|
|
|
|
void calculate_host_coords(void);
|
|
void calculate_world_bounds(void);
|
|
void display_world(void);
|
|
void write_global_vrml_data(void);
|
|
void draw_process_icon(void);
|
|
void draw_host(host *);
|
|
void draw_host_links(void);
|
|
void draw_host_link(host *, double, double, double, double, double, double);
|
|
void document_header(void);
|
|
int process_cgivars(void);
|
|
|
|
int number_of_host_layer_members(host *, int);
|
|
int max_child_host_layer_members(host *);
|
|
int host_child_depth_separation(host *, host *);
|
|
int max_child_host_drawing_width(host *);
|
|
|
|
void calculate_balanced_tree_coords(host *, int, int);
|
|
void calculate_circular_coords(void);
|
|
void calculate_circular_layer_coords(host *, double, double, int, int);
|
|
|
|
|
|
authdata current_authdata;
|
|
|
|
float link_radius = 0.016;
|
|
|
|
float floor_width = 0.0;
|
|
float floor_depth = 0.0;
|
|
|
|
double min_z_coord = 0.0;
|
|
double min_x_coord = 0.0;
|
|
double min_y_coord = 0.0;
|
|
double max_z_coord = 0.0;
|
|
double max_x_coord = 0.0;
|
|
double max_y_coord = 0.0;
|
|
|
|
double max_world_size = 0.0;
|
|
|
|
double nagios_icon_x = 0.0;
|
|
double nagios_icon_y = 0.0;
|
|
int draw_nagios_icon = FALSE;
|
|
|
|
double custom_viewpoint_x = 0.0;
|
|
double custom_viewpoint_y = 0.0;
|
|
double custom_viewpoint_z = 0.0;
|
|
int custom_viewpoint = FALSE;
|
|
|
|
float vertical_spacing = DEFAULT_VERTICAL_SPACING;
|
|
float horizontal_spacing = DEFAULT_HORIZONTAL_SPACING;
|
|
float node_width = DEFAULT_NODE_WIDTH;
|
|
float node_height = DEFAULT_NODE_WIDTH; /* should be the same as the node width */
|
|
|
|
char *host_name = "all";
|
|
int show_all_hosts = TRUE;
|
|
|
|
int use_textures = TRUE;
|
|
int use_text = TRUE;
|
|
int use_links = TRUE;
|
|
|
|
int layout_method = LAYOUT_USER_SUPPLIED;
|
|
|
|
int coordinates_were_specified = FALSE; /* were drawing coordinates specified with extended host info entries? */
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
int result;
|
|
|
|
/* reset internal variables */
|
|
reset_cgi_vars();
|
|
|
|
/* read the CGI configuration file */
|
|
result = read_cgi_config_file(get_cgi_config_location());
|
|
if(result == ERROR) {
|
|
document_header();
|
|
return ERROR;
|
|
}
|
|
|
|
/* defaults from CGI config file */
|
|
layout_method = default_statuswrl_layout_method;
|
|
|
|
/* get the arguments passed in the URL */
|
|
process_cgivars();
|
|
|
|
document_header();
|
|
|
|
/* read the main configuration file */
|
|
result = read_main_config_file(main_config_file);
|
|
if(result == ERROR)
|
|
return ERROR;
|
|
|
|
/* read all object configuration data */
|
|
result = read_all_object_configuration_data(main_config_file, READ_ALL_OBJECT_DATA);
|
|
if(result == ERROR)
|
|
return ERROR;
|
|
|
|
/* read all status data */
|
|
result = read_all_status_data(get_cgi_config_location(), READ_ALL_STATUS_DATA);
|
|
if(result == ERROR) {
|
|
free_memory();
|
|
return ERROR;
|
|
}
|
|
|
|
/* get authentication information */
|
|
get_authentication_information(¤t_authdata);
|
|
|
|
/* display the 3-D VRML world... */
|
|
display_world();
|
|
|
|
/* free all allocated memory */
|
|
free_memory();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
|
|
void document_header(void) {
|
|
char date_time[MAX_DATETIME_LENGTH];
|
|
time_t current_time;
|
|
time_t expire_time;
|
|
|
|
|
|
printf("Cache-Control: no-store\r\n");
|
|
printf("Pragma: no-cache\r\n");
|
|
|
|
time(¤t_time);
|
|
get_time_string(¤t_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
|
|
printf("Last-Modified: %s\r\n", date_time);
|
|
|
|
expire_time = 0L;
|
|
get_time_string(&expire_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
|
|
printf("Expires: %s\r\n", date_time);
|
|
|
|
printf("Content-Type: x-world/x-vrml\r\n\r\n");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
int process_cgivars(void) {
|
|
char **variables;
|
|
int error = FALSE;
|
|
int x;
|
|
|
|
variables = getcgivars();
|
|
|
|
for(x = 0; variables[x] != NULL; x++) {
|
|
|
|
/* do some basic length checking on the variable identifier to prevent buffer overflows */
|
|
if(strlen(variables[x]) >= MAX_INPUT_BUFFER - 1) {
|
|
x++;
|
|
continue;
|
|
}
|
|
|
|
|
|
/* we found the host argument */
|
|
else if(!strcmp(variables[x], "host")) {
|
|
x++;
|
|
if(variables[x] == NULL) {
|
|
error = TRUE;
|
|
break;
|
|
}
|
|
|
|
if((host_name = (char *)strdup(variables[x])) == NULL)
|
|
host_name = "all";
|
|
else
|
|
strip_html_brackets(host_name);
|
|
|
|
if(!strcmp(host_name, "all"))
|
|
show_all_hosts = TRUE;
|
|
else
|
|
show_all_hosts = FALSE;
|
|
}
|
|
|
|
/* we found the no textures argument*/
|
|
else if(!strcmp(variables[x], "notextures"))
|
|
use_textures = FALSE;
|
|
|
|
/* we found the no text argument*/
|
|
else if(!strcmp(variables[x], "notext"))
|
|
use_text = FALSE;
|
|
|
|
/* we found the no links argument*/
|
|
else if(!strcmp(variables[x], "nolinks"))
|
|
use_links = FALSE;
|
|
|
|
/* we found the layout method option */
|
|
else if(!strcmp(variables[x], "layout")) {
|
|
x++;
|
|
if(variables[x] == NULL) {
|
|
error = TRUE;
|
|
break;
|
|
}
|
|
layout_method = atoi(variables[x]);
|
|
}
|
|
|
|
/* we found custom viewpoint coord */
|
|
else if(!strcmp(variables[x], "viewx")) {
|
|
x++;
|
|
if(variables[x] == NULL) {
|
|
error = TRUE;
|
|
break;
|
|
}
|
|
custom_viewpoint_x = strtod(variables[x], NULL);
|
|
custom_viewpoint = TRUE;
|
|
}
|
|
else if(!strcmp(variables[x], "viewy")) {
|
|
x++;
|
|
if(variables[x] == NULL) {
|
|
error = TRUE;
|
|
break;
|
|
}
|
|
custom_viewpoint_y = strtod(variables[x], NULL);
|
|
custom_viewpoint = TRUE;
|
|
}
|
|
else if(!strcmp(variables[x], "viewz")) {
|
|
x++;
|
|
if(variables[x] == NULL) {
|
|
error = TRUE;
|
|
break;
|
|
}
|
|
custom_viewpoint_z = strtod(variables[x], NULL);
|
|
custom_viewpoint = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
/* free memory allocated to the CGI variables */
|
|
free_cgivars(variables);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
/* top-level VRML world generation... */
|
|
void display_world(void) {
|
|
host *temp_host = NULL;
|
|
|
|
/* get the url we will use to grab the logo images... */
|
|
snprintf(url_logo_images_path, sizeof(url_logo_images_path), "%slogos/", url_images_path);
|
|
url_logo_images_path[sizeof(url_logo_images_path) - 1] = '\x0';
|
|
|
|
/* calculate host drawing coordinates */
|
|
calculate_host_coords();
|
|
|
|
/* calculate world bounds */
|
|
calculate_world_bounds();
|
|
|
|
/* get the floor dimensions */
|
|
if(max_x_coord > 0)
|
|
floor_width = (float)(max_x_coord - min_x_coord) + (node_width * 2);
|
|
else
|
|
floor_width = (float)(max_x_coord + min_x_coord) + (node_width * 2);
|
|
if(max_z_coord > 0)
|
|
floor_depth = (float)(max_z_coord - min_z_coord) + (node_height * 2);
|
|
else
|
|
floor_depth = (float)(max_z_coord + min_z_coord) + (node_height * 2);
|
|
|
|
/* write global VRML data */
|
|
write_global_vrml_data();
|
|
|
|
/* no coordinates were specified, so display warning message */
|
|
if(coordinates_were_specified == FALSE) {
|
|
|
|
printf("\n");
|
|
printf("Transform{\n");
|
|
printf("translation 0.0 0.0 0.0\n");
|
|
printf("children[\n");
|
|
|
|
printf("Billboard{\n");
|
|
printf("children[\n");
|
|
printf("Shape{\n");
|
|
printf("appearance Appearance {\n");
|
|
printf("material Material {\n");
|
|
printf("diffuseColor 1 0 0\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("geometry Text {\n");
|
|
printf("string [ \"Error: You have not supplied any 3-D drawing coordinates.\", \"Read the documentation for more information on supplying\", \"3-D drawing coordinates by defining\", \"extended host information entries in your config files.\" ]\n");
|
|
printf("fontStyle FontStyle {\n");
|
|
printf("family \"TYPEWRITER\"\n");
|
|
printf("size 0.3\n");
|
|
printf("justify \"MIDDLE\"\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("]\n");
|
|
printf("}\n");
|
|
|
|
printf("]\n");
|
|
printf("}\n");
|
|
}
|
|
|
|
/* coordinates were specified... */
|
|
else {
|
|
|
|
/* draw Nagios icon */
|
|
if(layout_method != LAYOUT_USER_SUPPLIED)
|
|
draw_process_icon();
|
|
|
|
/* draw all hosts */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next)
|
|
draw_host(temp_host);
|
|
|
|
/* draw host links */
|
|
draw_host_links();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/************************ UTILITY FUNCTIONS ***********************/
|
|
/******************************************************************/
|
|
|
|
/* calculates how many "layers" separate parent and child - used by collapsed tree layout method */
|
|
int host_child_depth_separation(host *parent, host *child) {
|
|
int this_depth = 0;
|
|
int min_depth = 0;
|
|
int have_min_depth = FALSE;
|
|
host *temp_host;
|
|
|
|
if(child == NULL)
|
|
return -1;
|
|
|
|
if(parent == child)
|
|
return 0;
|
|
|
|
if(is_host_immediate_child_of_host(parent, child) == TRUE)
|
|
return 1;
|
|
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
|
|
|
|
this_depth = host_child_depth_separation(temp_host, child);
|
|
|
|
if(this_depth >= 0 && (have_min_depth == FALSE || (have_min_depth == TRUE && (this_depth < min_depth)))) {
|
|
have_min_depth = TRUE;
|
|
min_depth = this_depth;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(have_min_depth == FALSE)
|
|
return -1;
|
|
else
|
|
return min_depth + 1;
|
|
}
|
|
|
|
|
|
|
|
/* calculates how many hosts reside on a specific "layer" - used by collapsed tree layout method */
|
|
int number_of_host_layer_members(host *parent, int layer) {
|
|
int current_layer;
|
|
int layer_members = 0;
|
|
host *temp_host;
|
|
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
current_layer = host_child_depth_separation(parent, temp_host);
|
|
|
|
if(current_layer == layer)
|
|
layer_members++;
|
|
}
|
|
|
|
return layer_members;
|
|
}
|
|
|
|
|
|
|
|
/* calculate max number of members on all "layers" beneath and including parent host - used by collapsed tree layout method */
|
|
int max_child_host_layer_members(host *parent) {
|
|
int current_layer;
|
|
int max_members = 1;
|
|
int current_members = 0;
|
|
|
|
for(current_layer = 1;; current_layer++) {
|
|
|
|
current_members = number_of_host_layer_members(parent, current_layer);
|
|
|
|
if(current_members <= 0)
|
|
break;
|
|
|
|
if(current_members > max_members)
|
|
max_members = current_members;
|
|
}
|
|
|
|
return max_members;
|
|
}
|
|
|
|
|
|
|
|
/* calculate max drawing width for host and children - used by balanced tree layout method */
|
|
int max_child_host_drawing_width(host *parent) {
|
|
host *temp_host;
|
|
int child_width = 0;
|
|
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
if(is_host_immediate_child_of_host(parent, temp_host) == TRUE)
|
|
child_width += max_child_host_drawing_width(temp_host);
|
|
}
|
|
|
|
/* no children, so set width to 1 for this host */
|
|
if(child_width == 0)
|
|
return 1;
|
|
|
|
else
|
|
return child_width;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/********************* CALCULATION FUNCTIONS **********************/
|
|
/******************************************************************/
|
|
|
|
/* calculates host drawing coordinates */
|
|
void calculate_host_coords(void) {
|
|
host *this_host;
|
|
host *temp_host;
|
|
int parent_hosts = 0;
|
|
int max_layer_width = 1;
|
|
int current_parent_host = 0;
|
|
int center_x = 0;
|
|
int offset_x = DEFAULT_NODE_WIDTH / 2;
|
|
int offset_y = DEFAULT_NODE_WIDTH / 2;
|
|
int current_layer = 0;
|
|
int layer_members = 0;
|
|
int current_layer_member = 0;
|
|
int max_drawing_width = 0;
|
|
|
|
|
|
/******************************/
|
|
/***** MANUAL LAYOUT MODE *****/
|
|
/******************************/
|
|
|
|
/* user-supplied coords */
|
|
if(layout_method == LAYOUT_USER_SUPPLIED) {
|
|
|
|
/* see which hosts we should draw (only those with 3-D coords) */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
if(temp_host->have_3d_coords == TRUE)
|
|
temp_host->should_be_drawn = TRUE;
|
|
else
|
|
temp_host->should_be_drawn = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************/
|
|
/***** AUTO-LAYOUT MODES *****/
|
|
/*****************************/
|
|
|
|
/* add empty extended host info entries for all hosts that don't have any */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
/* none was found, so add a blank one */
|
|
/*
|
|
if(temp_hostextinfo==NULL)
|
|
add_hostextinfo(temp_host->name,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0.0,0.0,0.0,0,0);
|
|
*/
|
|
|
|
/* default z coord should 0 for auto-layout modes unless overridden later */
|
|
/*
|
|
else
|
|
*/
|
|
temp_host->z_3d = 0.0;
|
|
}
|
|
|
|
|
|
/***** COLLAPSED TREE MODE *****/
|
|
if(layout_method == LAYOUT_COLLAPSED_TREE) {
|
|
|
|
/* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
|
|
this_host = NULL;
|
|
|
|
/* find total number of immediate parents for this host */
|
|
parent_hosts = number_of_immediate_parent_hosts(this_host);
|
|
|
|
/* find the max layer width we have... */
|
|
max_layer_width = max_child_host_layer_members(this_host);
|
|
if(parent_hosts > max_layer_width)
|
|
max_layer_width = parent_hosts;
|
|
|
|
/* calculate center x coord */
|
|
center_x = (((DEFAULT_NODE_WIDTH * max_layer_width) + (DEFAULT_NODE_HSPACING * (max_layer_width - 1))) / 2) + offset_x;
|
|
|
|
/* coords for Nagios icon if necessary */
|
|
if(this_host == NULL || this_host->parent_hosts == NULL) {
|
|
nagios_icon_x = center_x;
|
|
nagios_icon_y = offset_y;
|
|
draw_nagios_icon = TRUE;
|
|
}
|
|
|
|
/* do we need to draw a link to parent(s)? */
|
|
if(this_host != NULL && is_host_immediate_child_of_host(NULL, this_host) == FALSE)
|
|
offset_y += DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
|
|
|
|
/* see which hosts we should draw and calculate drawing coords */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
/* this is an immediate parent of the "main" host we're drawing */
|
|
if(is_host_immediate_parent_of_host(this_host, temp_host) == TRUE) {
|
|
temp_host->should_be_drawn = TRUE;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->x_3d = center_x - (((parent_hosts * DEFAULT_NODE_WIDTH) + ((parent_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_parent_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
|
|
temp_host->y_3d = offset_y;
|
|
current_parent_host++;
|
|
}
|
|
|
|
/* this is the "main" host we're drawing */
|
|
else if(this_host == temp_host) {
|
|
temp_host->should_be_drawn = TRUE;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->x_3d = center_x;
|
|
temp_host->y_3d = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y;
|
|
}
|
|
|
|
/* else do not draw this host (we might if its a child - see below, but assume no for now) */
|
|
else {
|
|
temp_host->should_be_drawn = FALSE;
|
|
temp_host->have_3d_coords = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* TODO: REORDER CHILD LAYER MEMBERS SO THAT WE MINIMIZE LINK CROSSOVERS FROM PARENT HOSTS */
|
|
|
|
/* draw hosts in child "layers" */
|
|
for(current_layer = 1;; current_layer++) {
|
|
|
|
/* how many members in this layer? */
|
|
layer_members = number_of_host_layer_members(this_host, current_layer);
|
|
|
|
if(layer_members == 0)
|
|
break;
|
|
|
|
current_layer_member = 0;
|
|
|
|
/* see which hosts are members of this layer and calculate drawing coords */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
/* is this host a member of the current child layer? */
|
|
if(host_child_depth_separation(this_host, temp_host) == current_layer) {
|
|
temp_host->should_be_drawn = TRUE;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->x_3d = center_x - (((layer_members * DEFAULT_NODE_WIDTH) + ((layer_members - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_layer_member * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
|
|
if(this_host == NULL)
|
|
temp_host->y_3d = ((DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) * current_layer) + offset_y;
|
|
else
|
|
temp_host->y_3d = ((DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) * (current_layer + 1)) + offset_y;
|
|
current_layer_member++;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***** "BALANCED" TREE MODE *****/
|
|
else if(layout_method == LAYOUT_BALANCED_TREE) {
|
|
|
|
/* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
|
|
this_host = NULL;
|
|
|
|
/* find total number of immediate parents for this host */
|
|
parent_hosts = number_of_immediate_parent_hosts(this_host);
|
|
|
|
/* find the max drawing width we have... */
|
|
max_drawing_width = max_child_host_drawing_width(this_host);
|
|
if(parent_hosts > max_drawing_width)
|
|
max_drawing_width = parent_hosts;
|
|
|
|
/* calculate center x coord */
|
|
center_x = (((DEFAULT_NODE_WIDTH * max_drawing_width) + (DEFAULT_NODE_HSPACING * (max_drawing_width - 1))) / 2) + offset_x;
|
|
|
|
/* coords for Nagios icon if necessary */
|
|
if(this_host == NULL || this_host->parent_hosts == NULL) {
|
|
nagios_icon_x = center_x;
|
|
nagios_icon_y = offset_y;
|
|
draw_nagios_icon = TRUE;
|
|
}
|
|
|
|
/* do we need to draw a link to parent(s)? */
|
|
if(this_host != NULL && is_host_immediate_child_of_host(NULL, this_host) == FALSE)
|
|
offset_y += DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
|
|
|
|
/* see which hosts we should draw and calculate drawing coords */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
/* this is an immediate parent of the "main" host we're drawing */
|
|
if(is_host_immediate_parent_of_host(this_host, temp_host) == TRUE) {
|
|
temp_host->should_be_drawn = TRUE;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->x_3d = center_x - (((parent_hosts * DEFAULT_NODE_WIDTH) + ((parent_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_parent_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
|
|
temp_host->y_3d = offset_y;
|
|
current_parent_host++;
|
|
}
|
|
|
|
/* this is the "main" host we're drawing */
|
|
else if(this_host == temp_host) {
|
|
temp_host->should_be_drawn = TRUE;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->x_3d = center_x;
|
|
temp_host->y_3d = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y;
|
|
}
|
|
|
|
/* else do not draw this host (we might if its a child - see below, but assume no for now) */
|
|
else {
|
|
temp_host->should_be_drawn = FALSE;
|
|
temp_host->have_3d_coords = FALSE;
|
|
}
|
|
}
|
|
|
|
/* draw all children hosts */
|
|
calculate_balanced_tree_coords(this_host, center_x, DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y);
|
|
|
|
}
|
|
|
|
|
|
/***** CIRCULAR LAYOUT MODE *****/
|
|
else if(layout_method == LAYOUT_CIRCULAR) {
|
|
|
|
/* draw process icon */
|
|
nagios_icon_x = 0;
|
|
nagios_icon_y = 0;
|
|
draw_nagios_icon = TRUE;
|
|
|
|
/* calculate coordinates for all hosts */
|
|
calculate_circular_coords();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* calculate world dimensions */
|
|
void calculate_world_bounds(void) {
|
|
host *temp_host;
|
|
|
|
min_x_coord = 0.0;
|
|
min_y_coord = 0.0;
|
|
min_z_coord = 0.0;
|
|
max_x_coord = 0.0;
|
|
max_y_coord = 0.0;
|
|
max_z_coord = 0.0;
|
|
|
|
/* check all extended host entries */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
if(temp_host->have_3d_coords == FALSE) {
|
|
temp_host->should_be_drawn = FALSE;
|
|
continue;
|
|
}
|
|
|
|
if(temp_host->should_be_drawn == FALSE)
|
|
continue;
|
|
|
|
if(temp_host->x_3d < min_x_coord)
|
|
min_x_coord = temp_host->x_3d;
|
|
else if(temp_host->x_3d > max_x_coord)
|
|
max_x_coord = temp_host->x_3d;
|
|
if(temp_host->y_3d < min_y_coord)
|
|
min_y_coord = temp_host->y_3d;
|
|
else if(temp_host->y_3d > max_y_coord)
|
|
max_y_coord = temp_host->y_3d;
|
|
if(temp_host->z_3d < min_z_coord)
|
|
min_z_coord = temp_host->z_3d;
|
|
else if(temp_host->z_3d > max_z_coord)
|
|
max_z_coord = temp_host->z_3d;
|
|
|
|
coordinates_were_specified = TRUE;
|
|
}
|
|
|
|
/* no drawing coordinates were specified */
|
|
if(coordinates_were_specified == FALSE) {
|
|
min_x_coord = 0.0;
|
|
max_x_coord = 0.0;
|
|
min_y_coord = 0.0;
|
|
max_y_coord = 0.0;
|
|
min_z_coord = 0.0;
|
|
max_z_coord = 6.0;
|
|
}
|
|
|
|
max_world_size = max_x_coord - min_x_coord;
|
|
if(max_world_size < (max_y_coord - min_y_coord))
|
|
max_world_size = max_y_coord - min_y_coord;
|
|
if(max_world_size < (max_z_coord - min_z_coord))
|
|
max_world_size = max_z_coord - min_z_coord;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/*********************** DRAWING FUNCTIONS ************************/
|
|
/******************************************************************/
|
|
|
|
|
|
/* write global VRML data */
|
|
void write_global_vrml_data(void) {
|
|
host *temp_host;
|
|
float visibility_range = 0.0;
|
|
float viewpoint_z = 0.0;
|
|
|
|
/* write VRML code header */
|
|
printf("#VRML V2.0 utf8\n");
|
|
|
|
/* write world information */
|
|
printf("\n");
|
|
printf("WorldInfo{\n");
|
|
printf("title \"Nagios 3-D Network Status View\"\n");
|
|
printf("info [\"Copyright (c) 1999-2002 Ethan Galstad\"\n");
|
|
printf("\"egalstad@nagios.org\"]\n");
|
|
printf("}\n");
|
|
|
|
/* background color */
|
|
printf("\n");
|
|
printf("Background{\n");
|
|
printf("skyColor 0.1 0.1 0.15\n");
|
|
printf("}\n");
|
|
|
|
/* calculate visibility range - don't let it get too low */
|
|
visibility_range = (max_world_size * 2.0);
|
|
if(visibility_range < 25.0)
|
|
visibility_range = 25.0;
|
|
|
|
/* write fog information */
|
|
printf("\n");
|
|
printf("Fog{\n");
|
|
printf("color 0.1 0.1 0.15\n");
|
|
printf("fogType \"EXPONENTIAL\"\n");
|
|
printf("visibilityRange %2.2f\n", visibility_range);
|
|
printf("}\n");
|
|
|
|
/* custom viewpoint */
|
|
if(custom_viewpoint == TRUE) {
|
|
printf("\n");
|
|
printf("Viewpoint{\n");
|
|
printf("position %2.2f %2.2f %2.2f\n", custom_viewpoint_x, custom_viewpoint_y, custom_viewpoint_z);
|
|
printf("fieldOfView 0.78\n");
|
|
printf("description \"Entry Viewpoint\"\n");
|
|
printf("}\n");
|
|
}
|
|
|
|
/* host close-up viewpoint */
|
|
if(show_all_hosts == FALSE) {
|
|
|
|
temp_host = find_host(host_name);
|
|
if(temp_host != NULL && temp_host->have_3d_coords == TRUE) {
|
|
printf("\n");
|
|
printf("Viewpoint{\n");
|
|
printf("position %2.3f %2.3f %2.3f\n", temp_host->x_3d, temp_host->y_3d, temp_host->z_3d + 5.0);
|
|
printf("fieldOfView 0.78\n");
|
|
printf("description \"Host Close-Up Viewpoint\"\n");
|
|
printf("}\n");
|
|
}
|
|
}
|
|
|
|
/* calculate z coord for default viewpoint - don't get too close */
|
|
viewpoint_z = max_world_size;
|
|
if(viewpoint_z < 10.0)
|
|
viewpoint_z = 10.0;
|
|
|
|
/* default viewpoint */
|
|
printf("\n");
|
|
printf("Viewpoint{\n");
|
|
printf("position %2.2f %2.2f %2.2f\n", min_x_coord + ((max_x_coord - min_x_coord) / 2.0), min_y_coord + ((max_y_coord - min_y_coord) / 2.0), viewpoint_z);
|
|
printf("fieldOfView 0.78\n");
|
|
printf("description \"Default Viewpoint\"\n");
|
|
printf("}\n");
|
|
|
|
/* problem timer */
|
|
printf("DEF ProblemTimer TimeSensor{\n");
|
|
printf("loop TRUE\n");
|
|
printf("cycleInterval 5\n");
|
|
printf("}\n");
|
|
|
|
/* host text prototype */
|
|
printf("PROTO HostText[\n");
|
|
printf("field MFString the_text [\"\"]\n");
|
|
printf("field SFColor font_color 0.6 0.6 0.6");
|
|
printf("]\n");
|
|
printf("{\n");
|
|
printf("Billboard{\n");
|
|
printf("children[\n");
|
|
printf("Shape{\n");
|
|
printf("appearance Appearance {\n");
|
|
printf("material Material {\n");
|
|
printf("diffuseColor IS font_color\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("geometry Text {\n");
|
|
printf("string IS the_text\n");
|
|
printf("fontStyle FontStyle {\n");
|
|
printf("family \"TYPEWRITER\"\n");
|
|
printf("size 0.1\n");
|
|
printf("justify \"MIDDLE\"\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
printf("]\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
|
|
/* include user-defined world */
|
|
if(statuswrl_include != NULL && coordinates_were_specified == TRUE && layout_method == LAYOUT_USER_SUPPLIED) {
|
|
printf("\n");
|
|
printf("Inline{\n");
|
|
printf("url \"%s%s\"\n", url_html_path, statuswrl_include);
|
|
printf("}\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* draws a host */
|
|
void draw_host(host *temp_host) {
|
|
hoststatus *temp_hoststatus = NULL;
|
|
char state_string[16] = "";
|
|
double x, y, z;
|
|
char *vrml_safe_hostname = NULL;
|
|
int a, ch;
|
|
|
|
if(temp_host == NULL)
|
|
return;
|
|
|
|
/* make sure we have the coordinates */
|
|
if(temp_host->have_3d_coords == FALSE)
|
|
return;
|
|
else {
|
|
x = temp_host->x_3d;
|
|
y = temp_host->y_3d;
|
|
z = temp_host->z_3d;
|
|
}
|
|
|
|
/* make the host name safe for embedding in VRML */
|
|
vrml_safe_hostname = (char *)strdup(temp_host->name);
|
|
if(vrml_safe_hostname == NULL)
|
|
return;
|
|
for(a = 0; vrml_safe_hostname[a] != '\x0'; a++) {
|
|
ch = vrml_safe_hostname[a];
|
|
if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9'))
|
|
vrml_safe_hostname[a] = '_';
|
|
}
|
|
|
|
/* see if user is authorized to view this host */
|
|
if(is_authorized_for_host(temp_host, ¤t_authdata) == FALSE)
|
|
return;
|
|
|
|
/* get the status of the host */
|
|
temp_hoststatus = find_hoststatus(temp_host->name);
|
|
|
|
printf("\n");
|
|
|
|
|
|
/* host object */
|
|
printf("Anchor{\n");
|
|
printf("children[\n");
|
|
|
|
printf("Transform {\n");
|
|
printf("translation %2.2f %2.2f %2.2f\n", x, y, z);
|
|
printf("children [\n");
|
|
|
|
printf("DEF Host%s Shape{\n", vrml_safe_hostname);
|
|
printf("appearance Appearance{\n");
|
|
printf("material DEF HostMat%s Material{\n", vrml_safe_hostname);
|
|
if(temp_hoststatus == NULL)
|
|
printf("emissiveColor 0.2 0.2 0.2\ndiffuseColor 0.2 0.2 0.2\n");
|
|
else if(temp_hoststatus->status == HOST_UP)
|
|
printf("emissiveColor 0.2 1.0 0.2\ndiffuseColor 0.2 1.0 0.2\n");
|
|
else
|
|
printf("emissiveColor 1.0 0.2 0.2\ndiffuseColor 1.0 0.2 0.2\n");
|
|
printf("transparency 0.4\n");
|
|
printf("}\n");
|
|
if(use_textures == TRUE && temp_host->vrml_image != NULL) {
|
|
printf("texture ImageTexture{\n");
|
|
printf("url \"%s%s\"\n", url_logo_images_path, temp_host->vrml_image);
|
|
printf("}\n");
|
|
}
|
|
printf("}\n");
|
|
printf("geometry Box{\n");
|
|
printf("size %2.2f %2.2f %2.2f\n", node_width, node_width, node_width);
|
|
printf("}\n");
|
|
printf("}\n");
|
|
|
|
printf("]\n");
|
|
printf("}\n");
|
|
|
|
printf("]\n");
|
|
printf("description \"View status details for host '%s' (%s)\"\n", temp_host->name, temp_host->alias);
|
|
printf("url \"%s?host=%s\"\n", STATUS_CGI, temp_host->name);
|
|
printf("}\n");
|
|
|
|
|
|
/* draw status text */
|
|
if(use_text == TRUE) {
|
|
|
|
printf("\n");
|
|
printf("Transform{\n");
|
|
printf("translation %2.3f %2.3f %2.3f\n", x, y + DEFAULT_NODE_WIDTH, z);
|
|
printf("children[\n");
|
|
printf("HostText{\n");
|
|
|
|
if(temp_hoststatus != NULL) {
|
|
if(temp_hoststatus->status == HOST_UP)
|
|
printf("font_color 0 1 0\n");
|
|
else if(temp_hoststatus->status == HOST_DOWN || temp_hoststatus->status == HOST_UNREACHABLE)
|
|
printf("font_color 1 0 0\n");
|
|
}
|
|
printf("the_text [\"%s\", \"%s\", ", temp_host->name, temp_host->alias);
|
|
if(temp_hoststatus == NULL)
|
|
strcpy(state_string, "UNKNOWN");
|
|
else {
|
|
if(temp_hoststatus->status == HOST_DOWN)
|
|
strcpy(state_string, "DOWN");
|
|
else if(temp_hoststatus->status == HOST_UNREACHABLE)
|
|
strcpy(state_string, "UNREACHABLE");
|
|
else if(temp_hoststatus->status == HOST_PENDING)
|
|
strcpy(state_string, "PENDING");
|
|
else
|
|
strcpy(state_string, "UP");
|
|
}
|
|
printf("\"%s\"]\n", state_string);
|
|
|
|
printf("}\n");
|
|
printf("]\n");
|
|
printf("}\n");
|
|
}
|
|
|
|
/* host is down or unreachable, so make it fade in and out */
|
|
if(temp_hoststatus != NULL && (temp_hoststatus->status == HOST_DOWN || temp_hoststatus->status == HOST_UNREACHABLE))
|
|
printf("ROUTE ProblemTimer.fraction_changed TO HostMat%s.set_transparency\n", vrml_safe_hostname);
|
|
|
|
free(vrml_safe_hostname);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* draw links between hosts */
|
|
void draw_host_links(void) {
|
|
host *parent_host;
|
|
host *child_host;
|
|
|
|
if(use_links == FALSE)
|
|
return;
|
|
|
|
for(child_host = host_list; child_host != NULL; child_host = child_host->next) {
|
|
|
|
if(child_host->have_3d_coords == FALSE)
|
|
continue;
|
|
|
|
/* check authorization */
|
|
if(is_authorized_for_host(child_host, ¤t_authdata) == FALSE)
|
|
continue;
|
|
|
|
/* draw a link from this host to all of its parent hosts */
|
|
for(parent_host = host_list; parent_host != NULL; parent_host = parent_host->next) {
|
|
|
|
if(is_host_immediate_child_of_host(child_host, parent_host) == TRUE) {
|
|
|
|
if(parent_host->have_3d_coords == FALSE)
|
|
continue;
|
|
|
|
/* check authorization */
|
|
if(is_authorized_for_host(parent_host, ¤t_authdata) == FALSE)
|
|
continue;
|
|
|
|
/* draw the link between the child and parent hosts */
|
|
draw_host_link(parent_host, parent_host->x_3d, parent_host->y_3d, parent_host->z_3d, child_host->x_3d, child_host->y_3d, child_host->z_3d);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* draws a link from a parent host to a child host */
|
|
void draw_host_link(host *hst, double x0, double y0, double z0, double x1, double y1, double z1) {
|
|
|
|
printf("\n");
|
|
|
|
if(hst != NULL)
|
|
printf("# Host '%s' LINK\n", hst->name);
|
|
|
|
printf("Shape{\n");
|
|
|
|
printf("appearance DEF MATslategrey_0_ Appearance {\n");
|
|
printf("material Material {\n");
|
|
printf("diffuseColor 0.6 0.6 0.6\n");
|
|
printf("ambientIntensity 0.5\n");
|
|
printf("emissiveColor 0.6 0.6 0.6\n");
|
|
printf("}\n");
|
|
printf("}\n");
|
|
|
|
printf("geometry IndexedLineSet{\n");
|
|
printf("coord Coordinate{\n");
|
|
printf("point [ %2.3f %2.3f %2.3f, %2.3f %2.3f %2.3f ]\n", x0, y0, z0, x1, y1, z1);
|
|
printf("}\n");
|
|
printf("coordIndex [ 0,1,-1 ]\n");
|
|
printf("}\n");
|
|
|
|
printf("}\n");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* draw process icon */
|
|
void draw_process_icon(void) {
|
|
host *child_host;
|
|
|
|
if(draw_nagios_icon == FALSE)
|
|
return;
|
|
|
|
/* draw process icon */
|
|
printf("\n");
|
|
|
|
|
|
printf("Anchor{\n");
|
|
printf("children[\n");
|
|
|
|
printf("Transform {\n");
|
|
printf("translation %2.2f %2.2f %2.2f\n", nagios_icon_x, nagios_icon_y, 0.0);
|
|
printf("children [\n");
|
|
|
|
printf("DEF ProcessNode Shape{\n");
|
|
printf("appearance Appearance{\n");
|
|
printf("material Material{\n");
|
|
printf("emissiveColor 0.5 0.5 0.5\n");
|
|
printf("diffuseColor 0.5 0.5 0.5\n");
|
|
printf("transparency 0.2\n");
|
|
printf("}\n");
|
|
if(use_textures == TRUE) {
|
|
printf("texture ImageTexture{\n");
|
|
printf("url \"%s%s\"\n", url_logo_images_path, NAGIOS_VRML_IMAGE);
|
|
printf("}\n");
|
|
}
|
|
printf("}\n");
|
|
printf("geometry Box{\n");
|
|
printf("size %2.2f %2.2f %2.2f\n", node_width * 3.0, node_width * 3.0, node_width * 3.0);
|
|
printf("}\n");
|
|
printf("}\n");
|
|
|
|
printf("]\n");
|
|
printf("}\n");
|
|
|
|
printf("]\n");
|
|
printf("description \"View Nagios Process Information\"\n");
|
|
printf("url \"%s?type=%d\"\n", EXTINFO_CGI, DISPLAY_PROCESS_INFO);
|
|
printf("}\n");
|
|
|
|
|
|
if(use_links == FALSE)
|
|
return;
|
|
|
|
/* draw links to immediate child hosts */
|
|
for(child_host = host_list; child_host != NULL; child_host = child_host->next) {
|
|
|
|
if(child_host->have_3d_coords == FALSE)
|
|
continue;
|
|
|
|
/* check authorization */
|
|
if(is_authorized_for_host(child_host, ¤t_authdata) == FALSE)
|
|
continue;
|
|
|
|
/* draw a link to the host */
|
|
if(is_host_immediate_child_of_host(NULL, child_host) == TRUE)
|
|
draw_host_link(NULL, nagios_icon_x, nagios_icon_y, 0.0, child_host->x_3d, child_host->y_3d, child_host->z_3d);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/***************** COORDINATE CALCULATION FUNCTIONS ***************/
|
|
/******************************************************************/
|
|
|
|
/* calculates coords of a host's children - used by balanced tree layout method */
|
|
void calculate_balanced_tree_coords(host *parent, int x, int y) {
|
|
int parent_drawing_width;
|
|
int start_drawing_x;
|
|
int current_drawing_x;
|
|
int this_drawing_width;
|
|
host *temp_host;
|
|
|
|
/* calculate total drawing width of parent host */
|
|
parent_drawing_width = max_child_host_drawing_width(parent);
|
|
|
|
/* calculate starting x coord */
|
|
start_drawing_x = x - (((DEFAULT_NODE_WIDTH * parent_drawing_width) + (DEFAULT_NODE_HSPACING * (parent_drawing_width - 1))) / 2);
|
|
current_drawing_x = start_drawing_x;
|
|
|
|
|
|
/* calculate coords for children */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
|
|
|
|
/* get drawing width of child host */
|
|
this_drawing_width = max_child_host_drawing_width(temp_host);
|
|
|
|
temp_host->x_3d = current_drawing_x + (((DEFAULT_NODE_WIDTH * this_drawing_width) + (DEFAULT_NODE_HSPACING * (this_drawing_width - 1))) / 2);
|
|
temp_host->y_3d = y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->should_be_drawn = TRUE;
|
|
|
|
current_drawing_x += (this_drawing_width * DEFAULT_NODE_WIDTH) + ((this_drawing_width - 1) * DEFAULT_NODE_HSPACING) + DEFAULT_NODE_HSPACING;
|
|
|
|
/* recurse into child host ... */
|
|
calculate_balanced_tree_coords(temp_host, temp_host->x_3d, temp_host->y_3d);
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* calculate coords of all hosts in circular layout method */
|
|
void calculate_circular_coords(void) {
|
|
|
|
/* calculate all host coords, starting with first layer */
|
|
calculate_circular_layer_coords(NULL, 0.0, 360.0, 1, CIRCULAR_DRAWING_RADIUS);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* calculates coords of all hosts in a particular "layer" in circular layout method */
|
|
void calculate_circular_layer_coords(host *parent, double start_angle, double useable_angle, int layer, int radius) {
|
|
int parent_drawing_width = 0;
|
|
int this_drawing_width = 0;
|
|
int immediate_children = 0;
|
|
double current_drawing_angle = 0.0;
|
|
double this_drawing_angle = 0.0;
|
|
double available_angle = 0.0;
|
|
double clipped_available_angle = 0.0;
|
|
double average_child_angle = 0.0;
|
|
double x_coord = 0.0;
|
|
double y_coord = 0.0;
|
|
host *temp_host;
|
|
|
|
|
|
/* get the total number of immediate children to this host */
|
|
immediate_children = number_of_immediate_child_hosts(parent);
|
|
|
|
/* bail out if we're done */
|
|
if(immediate_children == 0)
|
|
return;
|
|
|
|
/* calculate total drawing "width" of parent host */
|
|
parent_drawing_width = max_child_host_drawing_width(parent);
|
|
|
|
/* calculate average angle given to each child host */
|
|
average_child_angle = (double)(useable_angle / (double)immediate_children);
|
|
|
|
/* calculate initial drawing angle */
|
|
current_drawing_angle = start_angle;
|
|
|
|
|
|
/* calculate coords for children */
|
|
for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
|
|
|
|
if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
|
|
|
|
/* get drawing width of child host */
|
|
this_drawing_width = max_child_host_drawing_width(temp_host);
|
|
|
|
/* calculate angle this host gets for drawing */
|
|
available_angle = useable_angle * ((double)this_drawing_width / (double)parent_drawing_width);
|
|
|
|
/* clip available angle if necessary */
|
|
/* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
|
|
clipped_available_angle = 360.0 / layer;
|
|
if(available_angle < clipped_available_angle)
|
|
clipped_available_angle = available_angle;
|
|
|
|
/* calculate the exact angle at which we should draw this child */
|
|
this_drawing_angle = current_drawing_angle + (available_angle / 2.0);
|
|
|
|
/* compensate for angle overflow */
|
|
while(this_drawing_angle >= 360.0)
|
|
this_drawing_angle -= 360.0;
|
|
while(this_drawing_angle < 0.0)
|
|
this_drawing_angle += 360.0;
|
|
|
|
/* calculate drawing coords of this host using good ol' geometry... */
|
|
x_coord = -(sin(-this_drawing_angle * (M_PI / 180.0)) * radius);
|
|
y_coord = -(sin((90 + this_drawing_angle) * (M_PI / 180.0)) * radius);
|
|
|
|
temp_host->x_3d = (int)x_coord;
|
|
temp_host->y_3d = (int)y_coord;
|
|
temp_host->have_3d_coords = TRUE;
|
|
temp_host->should_be_drawn = TRUE;
|
|
|
|
/* recurse into child host ... */
|
|
calculate_circular_layer_coords(temp_host, current_drawing_angle + ((available_angle - clipped_available_angle) / 2), clipped_available_angle, layer + 1, radius + CIRCULAR_DRAWING_RADIUS);
|
|
|
|
/* increment current drawing angle */
|
|
current_drawing_angle += available_angle;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|