import java.applet.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import javax.swing.*; import com.genlogic.*; ////////////////////////////////////////////////////////////////////////// // This demo uses Glg as a bean and may be used in a browser or stand-alone. ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// public class GlgMapDemo extends GlgJBean implements ActionListener { ////////////////////////////////////////////////////////////////////////// // The main demo class ////////////////////////////////////////////////////////////////////////// boolean debug = false; GlgObject Drawing = null, LinkTemplate = null, IconArray = null, FacilitiesGroup = null, LinksGroup = null, SelectedColorIndex = null, SelectedObject = null, flow_display_obj = null, MapViewport = null; double IconScale = 0.5, // Icon size GlgMinX, GlgMaxX, GlgMinY, GlgMaxY, // GLG extent in world coordinates MapMinX, MapMaxX, MapMinY, MapMaxY; // Map extent in degrees, mapped to // the GLG extent. GlgPoint // Create tmp points once point = new GlgPoint(), world_point = new GlgPoint(), lat_lon = new GlgPoint(), xy = new GlgPoint(), /* Calculated values */ MapCenter = new GlgPoint(), MapExtent = new GlgPoint(); int UpdateN = 4, // Update on every N-th iteration of the simulated data ColorScheme = 0, counter = 0; // Used to control update frequency. boolean IsReady = false, DoUpdate = true, // Controls dynamic update ShowFlow = true, // Animate flow with "moving ants" dynamics. // Not available in Java1. Stretch, stream_error = false; static boolean StandAlone = false; String // Default parameter values to display US map if no arguments. drawing_file = "map_demo.g", map_file = "us_map.g", facilities_file = "facilities_s", links_file = "links_s", palette_file = "palette.g"; byte buffer[] = new byte[ 100 ]; int buffer_length; Timer timer = null; ////////////////////////////////////////////////////////////////////////// public GlgMapDemo() { super(); SetDResource( "$config/GlgSwingUsage", 1. ); SetDResource( "$config/GlgMouseTooltipTimeout", 0.05 ); // Activate Trace callback. AddListener( GlgObject.TRACE_CB, this ); } ////////////////////////////////////////////////////////////////////////// // // main() method for using as a stand-alone java demo // ////////////////////////////////////////////////////////////////////////// // Optional arguments (supplied as applet parameters when used as an // applet, or as command-line arguments when used as a stand-alone program). // // -drawing drawing_file Drawing template to use (map_demo.g). // -map map_file Map drawing to load (us_map.g or world_map.g). // -facilities data_file Facilities data file, lists the nodes to add // to the map drawing. // -links data_file Link data file, lists the links between nodes // to be added. // -palette palette_file Palette drawing of facility icons // -icon_scale scale Scale factor for the the added icons (set via // the icon's "IconScale" resource). // -show_flow Animate flow with "moving ants" ////////////////////////////////////////////////////////////////////////// public static void main( final String arg[] ) { SwingUtilities. invokeLater( new Runnable(){ public void run() { Main( arg ); } } ); } ////////////////////////////////////////////////////////////////////////// public static void Main( final String arg[] ) { class DemoQuit extends WindowAdapter { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } GlgMapDemo.StandAlone = true; JFrame frame = new JFrame(); frame.setResizable( true ); frame.setSize( 800, 600 ); frame.setLocation( 20, 20 ); GlgMapDemo map_demo = new GlgMapDemo(); // Use getContentPane() for GlgJBean frame.getContentPane().add( map_demo ); frame.addWindowListener( new DemoQuit() ); frame.show(); int argc = Array.getLength( arg ); // Scan options int skip; for( skip = 0; skip < argc; ++skip ) { if( arg[ skip ].equals( "-drawing" ) ) { ++skip; if( argc <= skip ) error( "No drawing file.", true ); map_demo.drawing_file = arg[ skip ]; } else if( arg[ skip ].equals( "-map" ) ) { ++skip; if( argc <= skip ) error( "No drawing file.", true ); map_demo.map_file = arg[ skip ]; } else if( arg[ skip ].equals( "-facilities" ) ) { ++skip; if( argc <= skip ) error( "No facilities file.", true ); map_demo.facilities_file = arg[ skip ]; } else if( arg[ skip ].equals( "-links" ) ) { ++skip; if( argc <= skip ) error( "No links file.", true ); map_demo.links_file = arg[ skip ]; } else if( arg[ skip ].equals( "-palette" ) ) { ++skip; if( argc <= skip ) error( "No icon palette file.", true ); map_demo.palette_file = arg[ skip ]; } else if( arg[ skip ].equals( "-show_flow" ) ) map_demo.ShowFlow = true; else if( arg[ skip ].equals( "-icon_scale" ) ) { ++skip; if( argc <= skip ) error( "No icon scale.", true ); try { map_demo.IconScale = new Double( arg[ skip ] ).doubleValue(); } catch( NumberFormatException e ) { error( "No icon scale.", true ); } } else break; } // The ReadyCallback which start updates when the drawing is loaded. map_demo.SetDrawingName( map_demo.drawing_file ); } ////////////////////////////////////////////////////////////////////////// // Initializes the drawing and starts updates. ////////////////////////////////////////////////////////////////////////// public void ReadyCallback() { super.ReadyCallback(); if( !StandAlone ) { // Get parameters map_file = GetParameter( "map_file", map_file ); facilities_file = GetParameter( "facilities", facilities_file ); links_file = GetParameter( "links", links_file ); palette_file = GetParameter( "palette", palette_file ); ShowFlow = GetBoolParameter( "show_flow", ShowFlow ); IconScale = GetDoubleParameter( "icon_scale", IconScale ); } Initialize(); IsReady = true; } ////////////////////////////////////////////////////////////////////////// void Initialize() { Drawing = GetViewport(); if( GetDResource( "$config/GlgSwingUsage" ) == 1. ) { Update(); // Prevents Swing/Java crash SetDResource( "SelectionDialog/ShellType", GlgObject.DIALOG_SHELL ); } LoadMap(); Update(); StartUpdates(); } ////////////////////////////////////////////////////////////////////////// // Load new map file as specified by the map_file parameter. ////////////////////////////////////////////////////////////////////////// void LoadMap() { // Load the map viewport MapViewport = GlgObject.LoadWidget( GetFullPath( map_file ), StandAlone ? GlgObject.FILE : GlgObject.URL ); if( MapViewport == null ) error( "Can't load map viewport.", true ); // Set name and position. MapViewport.SetSResource( "Name", "MapArea" ); MapViewport.SetGResource( "Point1", -990., 890., 0. ); MapViewport.SetGResource( "Point2", 990., -990., 0. ); Drawing.AddObjectToTop( MapViewport ); // Query extent info from the map. GetExtentInfo( MapViewport ); // Extract node icons from the palette IconArray = ReadPalette( palette_file ); // Read facilities info and creates facilities group (used as a layer). FacilitiesGroup = ReadFacilities( facilities_file ); if( FacilitiesGroup != null ) { // Create connection links (creates a group used as a layer) LinksGroup = ConnectFacilities( links_file ); if( LinksGroup != null ) // Add link group to the drawing MapViewport.AddObjectToBottom( LinksGroup ); // Add facilities last to be in front of links. MapViewport.AddObjectToBottom( FacilitiesGroup ); // Set the icon size of the facility nodes SetIconSize(); } // Uncomment to save generated drawing. // Drawing.SaveObject( "out.g" ); // Set initial visibility of the value display labels to on. Drawing.SetDResource( "MapArea/Icon0/Group/ValueLabel/Visibility", 1. ); Drawing.SetDResource( "MapArea/Link0/ValueLabel/Visibility", 1. ); // Set initial color sheme. Drawing.SetDResource( "MapArea/ColorIndex", (double) ColorScheme ); Drawing.SetDResource( "MapArea/Icon0/Group/ColorIndex", (double) ColorScheme ); // Add selection dialog on top of the map (no way to reorder in AWT). GlgObject dialog = Drawing.GetResourceObject( "SelectionDialog" ); dialog.SetDResource( "Visibility", 0. ); // Erase the dialog if displayed Drawing.DeleteObject( dialog ); Drawing.AddObjectToBottom( dialog ); Update(); } ////////////////////////////////////////////////////////////////////////// void UnloadMap() { FacilitiesGroup = null; LinksGroup = null; LinkTemplate = null; IconArray = null; flow_display_obj = null; SelectedColorIndex = null; SelectedObject = null; // Delete the old map drawing. Drawing.DeleteObject( MapViewport ); MapViewport = null; } ////////////////////////////////////////////////////////////////////////// void SetIconSize() { /* Adjust icon size by a specified factor. */ if( IconScale > 0. ) Drawing.SetDResource( "MapArea/Icon0/Template/IconScale", IconScale ); } ////////////////////////////////////////////////////////////////////////// // Reads icon palette and returns an array of icons to use for nodes. ////////////////////////////////////////////////////////////////////////// GlgObject ReadPalette( String palette_file ) { GlgObject icon_array = null, palette_drawing, palette; int i; if( palette_file == null ) return null; // No palette specified: don't generate icons. // Load palette drawing palette_drawing = GlgObject.LoadObject( GetFullPath( palette_file ), StandAlone ? GlgObject.FILE : GlgObject.URL ); if( palette_drawing == null ) error( "Can't load icon palette.", true ); // Get palette object named "Icons" palette = palette_drawing.GetResourceObject( "Icons" ); if( palette == null ) error( "Can't find palette object.", true ); // Find link template and store it for creating links. LinkTemplate = palette.GetResourceObject( "Link" ); if( !ShowFlow ) // Set line type to solid line if not supported LinkTemplate.SetDResource( "Line/LineType", 0. ); GlgObject zoom_factor = Drawing.GetResourceObject( "MapArea/ZoomFactor" ); for( i=0; ; ++i ) { // Get icon[i] GlgObject icon = palette.GetResourceObject( "Icon" + i ); if( icon != null ) { if( icon_array == null ) // First icon: create icon array icon_array = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); // Wire up the constraints to make icon keeping its size when // zooming in. GlgObject coeff = icon.GetResourceObject( "Group/DivideXform/XformAttr1" ); coeff.ConstrainObject( zoom_factor ); icon_array.AddObjectToBottom( icon ); } else { if( i == 0 ) // First time: can't find any icons! error( "Can't find facilities icons.", true ); // Done reading icons. System.out.println( "Scanned " + icon_array.GetSize() + " icon(s)" ); break; } } return icon_array; } ////////////////////////////////////////////////////////////////////////// // Reads facilities data file and generates an array of facility objects // using the facility palette. ////////////////////////////////////////////////////////////////////////// GlgObject ReadFacilities( String facilities_file ) { GlgObject facility_group = null, icon; if( facilities_file == null ) return null; // No facilities file: already on the map? if( IconArray == null ) { error( "No icon palette.", true ); return null; } BufferedInputStream stream = OpenStream( facilities_file ); if( stream == null ) { error( "Can't open facilities URL: " + facilities_file, true ); return null; } int num_icons = IconArray.GetSize(); int num_facilities = 0; while( true ) { stream_error = false; // Read facility record String facility_name = ReadName( stream ); if( facility_name == null ) break; double y = ReadDouble( stream ); char y_char = ReadChar( stream ); double x = ReadDouble( stream ); char x_char = ReadChar( stream ); if( stream_error ) { error( "Syntax error reading facilities file.", true ); break; } ++num_facilities; if( debug ) System.out.println( "facility: " + num_facilities + " " + facility_name ); if( x_char == 'W' || x_char == 'w' ) x = 180. + ( 180. - x ); if( y_char == 'S' || x_char == 's' ) y = -y; if( facility_group == null ) // First time: create. { facility_group = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); facility_group.SetSResource( "Name", "Facilities" ); } // Add named icon. String icon_name = "Icon" + ( num_facilities - 1 ); icon = AddNode( facility_group, icon_name, x, y ); // Set facility display label and value. icon.SetSResource( "Template/Label/String", facility_name ); icon.SetDResource( "Template/Value", Rand( 10., 300. ) ); } try { stream.close(); } catch( IOException e ) {} System.out.println( "Scanned " + num_facilities + " facilities" ); return facility_group; } ////////////////////////////////////////////////////////////////////////// GlgObject AddNode( GlgObject container, String obj_name, double lon, double lat ) { // Always use the first icon. Subdrawing dynamics is used to change // shapes GlgObject icon = (GlgObject) IconArray.GetElement( 0 ); // Create a copy of it. icon = icon.CloneObject( GlgObject.STRONG_CLONE ); // Set object name icon.SetSResource( "Name", obj_name ); icon.SetSResource( "TooltipString", obj_name ); // Set position lat_lon.x = lon; lat_lon.y = lat; lat_lon.z = 0.; GetXY( lat_lon, xy ); icon.SetGResource( "Position", xy ); container.AddObjectToBottom( icon ); return icon; } ////////////////////////////////////////////////////////////////////////// // Reads connectivity info from a data file and creates links to connect // facilities. ////////////////////////////////////////////////////////////////////////// GlgObject ConnectFacilities( String links_file ) { GlgObject link_group = null; if( links_file == null || FacilitiesGroup == null ) return null; if( LinkTemplate == null ) { error( "Can't find link template.", true ); return null; } BufferedInputStream stream = OpenStream( links_file ); if( stream == null ) { error( "Can't open links file.", true ); return null; } int size = FacilitiesGroup.GetSize(); int num_links = 0; while( true ) { stream_error = false; // Read link record int from_node = ReadInt( stream ); if( stream_error ) break; int to_node = ReadInt( stream ); if( stream_error ) { error( "Syntax error reading links file.", true ); break; } ++num_links; if( debug ) System.out.println( "Link= " + from_node + " : " + to_node ); if( from_node < 0 || to_node < 0 || from_node >= size || to_node >= size ) { error( "Invalid link index.", true ); return null; } if( link_group == null ) // First time: create. { link_group = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); link_group.SetSResource( "Name", "Connections" ); } GlgObject link = AddLink( link_group, from_node, to_node, "Link" + (num_links-1) ); // Set flow attribute and color. double flow = Rand( 1., 9. ); double color = (double) ( ( (int) flow ) / 2 ); link.SetDResource( "Line/LineWidth", flow ); link.SetDResource( "Line/LineColorIndex", color ); link.SetDResource( "Value", (double)flow ); } System.out.println( "Scanned " + num_links + " links" ); return link_group; } ////////////////////////////////////////////////////////////////////////// GlgObject AddLink( GlgObject container, int from_node, int to_node, String name ) { GlgObject icon_point, link_point, xform_point; // Create an instance of the link template (polygon and label). GlgObject link = LinkTemplate.CloneObject( GlgObject.STRONG_CLONE ); link.SetSResource( "Name", name ); link.SetSResource( "TooltipString", name ); // Constrain the end points to facility nodes. Constrain the link // polygon end points, and also the point of the path xform used // to keep the label in the middle of the link. GlgObject link_polygon = link.GetResourceObject( "Line" ); GlgObject xform_pt_array = link.GetResourceObject( "PathXform/XformAttr1" ); // First point GlgObject icon = (GlgObject) FacilitiesGroup.GetElement( from_node ); icon_point = icon.GetResourceObject( "Point" ); link_point = (GlgObject) link_polygon.GetElement( 0 ); xform_point = (GlgObject) xform_pt_array.GetElement( 0 ); link_point.ConstrainObject( icon_point ); xform_point.ConstrainObject( icon_point ); // Second point. icon = (GlgObject) FacilitiesGroup.GetElement( to_node ); icon_point = icon.GetResourceObject( "Point" ); link_point = (GlgObject) link_polygon.GetElement( 1 ); xform_point = (GlgObject) xform_pt_array.GetElement( 1 ); link_point.ConstrainObject( icon_point ); xform_point.ConstrainObject( icon_point ); container.AddObjectToBottom( link ); return link; } ////////////////////////////////////////////////////////////////////////// // Query the extend info from the generated map. The map drawing has named // custom properties attached to it which keep the extent information. The // map was generated in such a way that map's extent in lat/lon degrees // (MapMinX, MapMinY, MapMaxX and MapMaxY) was mapped to the full GLG extent // of +-1000. This information is used later to convert from lat/lon to x/y // and vice versa. ////////////////////////////////////////////////////////////////////////// void GetExtentInfo( GlgObject drawing ) { // Query map extent from the loaded map drawing (kept as named custom // properties attached to the drawing). MapMinX = drawing.GetDResource( "MinX" ).doubleValue(); MapMaxX = drawing.GetDResource( "MaxX" ).doubleValue(); MapMinY = drawing.GetDResource( "MinY" ).doubleValue(); MapMaxY = drawing.GetDResource( "MaxY" ).doubleValue(); // Calculate center and extent, used in coordinate conversion. MapCenter.x = ( MapMinX + MapMaxX ) / 2.; MapCenter.y = ( MapMinY + MapMaxY ) / 2.; MapCenter.z = 0.; MapExtent.x = MapMaxX - MapMinX; MapExtent.y = MapMaxY - MapMinY; MapExtent.z = 0.; // Full Glg extent is used for the map, hardcoded. Stretch must be TRUE. GlgMinX = -1000.; GlgMaxX = 1000.; GlgMinY = -1000.; GlgMaxY = 1000.; // Query if the drawing preserves X/Y ratio. double stretch = drawing.GetDResource( "Stretch" ).doubleValue(); Stretch = ( stretch != 0. ); } ////////////////////////////////////////////////////////////////////////// // Handle user interaction. ////////////////////////////////////////////////////////////////////////// public void InputCallback( GlgObject vp, GlgObject message_obj ) { String origin, format, action, subaction; super.InputCallback( vp, message_obj ); origin = message_obj.GetSResource( "Origin" ); format = message_obj.GetSResource( "Format" ); action = message_obj.GetSResource( "Action" ); subaction = message_obj.GetSResource( "SubAction" ); // Handle window closing. if( format.equals( "Window" ) ) { if( action.equals( "DeleteWindow" ) ) if( origin.equals( "SelectionDialog" ) ) { // Close selection dialog Drawing.SetDResource( "SelectionDialog/Visibility", 0. ); Drawing.Update(); return; } else // Closing main window when stand-alone: exit. System.exit( 0 ); return; } if( format.equals( "Button" ) ) { if( !action.equals( "Activate" ) ) return; if( origin.equals( "CloseDialog" ) ) { Drawing.SetDResource( "SelectionDialog/Visibility", 0. ); Drawing.Update(); } else if( origin.equals( "ZoomIn" ) ) MapViewport.SetZoom( null, 'i', 0. ); else if( origin.equals( "ZoomOut" ) ) MapViewport.SetZoom( null, 'o', 0. ); else if( origin.equals( "ZoomReset" ) ) MapViewport.SetZoom( null, 'n', 0. ); else if( origin.equals( "ZoomTo" ) ) MapViewport.SetZoom( null, 't', 0. ); else if( origin.equals( "ColorScheme" ) ) { ColorScheme ^= 1; // Toggle between 0 and 1 Drawing.SetDResource( "MapArea/ColorIndex", (double) ColorScheme ); Drawing.SetDResource( "MapArea/Icon0/Group/ColorIndex", (double) ColorScheme ); Drawing.Update(); } else if( origin.equals( "Connections" ) ) { ToggleResource( Drawing, "MapArea/Connections/Visibility" ); } else if( origin.equals( "ValueDisplay" ) ) { // Visibility of all labels is constrained, set just one. ToggleResource( Drawing, "MapArea/Icon0/Group/ValueLabel/Visibility" ); ToggleResource( Drawing, "MapArea/Link0/ValueLabel/Visibility" ); } else if( origin.equals( "Map" ) ) { ToggleResource( Drawing, "MapArea/MapGroup/Visibility" ); } else if( origin.equals( "Update" ) ) { DoUpdate = !DoUpdate; } else if( origin.equals( "MapType" ) ) // Togle US and world map { if( map_file.equals( "us_map.g" ) ) { map_file = "world_map.g"; facilities_file = "facilities_w"; links_file = "links_w"; } else { map_file = "us_map.g"; facilities_file = "facilities_s"; links_file = "links_s"; } StopUpdates(); UnloadMap(); // Delete the old map. LoadMap(); // Load new map. Update(); StartUpdates(); return; } } else if( format.equals( "CustomEvent" ) && action.equals( "MouseClick" ) ) { if( MapViewport.GetDResource( "ZoomToMode" ).intValue() != 0 ) return; // Don't handle selection in ZoomTo mode. if( message_obj.GetDResource( "ButtonIndex" ).intValue() != 1 ) return; // Ignore middle and right mouse button clicks String label = null, visibility_name = null; boolean has_data = false; GlgObject highlight_obj = null; double data = 0.; String icon_name; String custom_event = message_obj.GetSResource( "EventLabel" ); if( custom_event.equals( "BackgroundVP" ) ) { // The background viewport is selection is reported only if there // are no other selections: erase the highlight. Highlight( Drawing, null ); Update(); return; } // Process state selection on the US map. else if( custom_event.equals( "MapSelection" ) ) { label = "None"; // The selection is reported for the MapGroup. The OrigObject is // used to get the object ID of the selected lower level state // polygon. highlight_obj = message_obj.GetResourceObject( "OrigObject" ); icon_name = highlight_obj.GetSResource( "Name" ); has_data = false; visibility_name = "MapArea/MapGroup/Visibility"; // Location is set to the mouse click by the preceding TraceCB. } else if( custom_event.equals( "Node" ) ) { GlgObject node = message_obj.GetResourceObject( "Object" ); icon_name = node.GetSResource( "Name" ); SelectedObject = node; // Query the label of the selected node label = node.GetSResource( "Group/Label/String" ); // Query node location. GlgPoint position = node.GetGResource( "Position" ); // Convert world coordinates to lat/lon GetLatLon( position, lat_lon ); // Generate a location info string by converting +- sign info // into the N/S, E/W suffixes. String location_str = CreateLocationString( lat_lon ); // Display position info in the dialog Drawing.SetSResource( "SelectionDialog/Location", location_str); data = node.GetDResource( "Group/Value" ).doubleValue(); has_data = true; visibility_name = "MapArea/Icon0/Visibility"; } else if( custom_event.equals( "Link" ) ) { GlgObject link = message_obj.GetResourceObject( "Object" ); icon_name = link.GetSResource( "Name" ); SelectedObject = link; label = "None"; data = link.GetDResource( "Value" ).doubleValue(); has_data = true; visibility_name = "MapArea/Connections/Visibility"; // Location is set to the mouse click by the preceding TraceCB. } else return; // No selection // Check if this layer is visible. double visibility_value = Drawing.GetDResource( visibility_name ).doubleValue(); if( visibility_value == 1. ) { if( icon_name == null ) icon_name = ""; // Display the icon name, label and data in the dialog. Drawing.SetSResource( "SelectionDialog/ID", icon_name ); Drawing.SetSResource( "SelectionDialog/Facility", label ); if( has_data ) Drawing.SetDResource( "SelectionDialog/Data", data ); Drawing.SetDResource( "SelectionDialog/DataLabel/Visibility", has_data ? 1. : 0. ); // Graph's Visibility is constrained to the DataLabel's Visibility if( has_data ) // Reset the graph by setting all datasamples to 0 Drawing.SetDResource( "SelectionDialog/Graph/DataGroup/Points/DataSample%/Value", 0. ); Drawing.SetDResource( "SelectionDialog/Visibility", 1. ); Highlight( Drawing, highlight_obj ); } } Update(); } ////////////////////////////////////////////////////////////////////////// // Used to obtain coordinates of the mouse click. ////////////////////////////////////////////////////////////////////////// public void TraceCallback( GlgObject viewport, GlgTraceData trace_info ) { // Use the MapArea's events only. if( !IsReady || trace_info.viewport != MapViewport ) return; int event_type = trace_info.event.getID(); switch( event_type ) { case ComponentEvent.COMPONENT_RESIZED: Component widget = (Component) MapViewport.GetResource( "Widget" ); int width = widget.getSize().width; int height = widget.getSize().height; // If Stretch is not NO, the drawing is stretched if it is not square. // The ScaleX parameter of the icon controls the ScaleX transformation // attached to it, and may be used to to adjust the X/Y ratio of the // icon to prevent distortion. if( Stretch ) MapViewport.SetDResource( "Icon0/Template/IconScaleX", height / (double) width ); return; case MouseEvent.MOUSE_PRESSED: if( GetButton( trace_info.event ) != 1 ) return; // Use the left button clicks only. point.x = (double) ((MouseEvent)trace_info.event).getX(); point.y = (double) ((MouseEvent)trace_info.event).getY(); break; default: return; } if( MapViewport.GetDResource( "ZoomToMode" ).intValue() != 0 ) return; // Ignore clicks in zoom mode. viewport.ScreenToWorld( true, point, world_point ); // Generate a location info string by converting +- sign info into the // N/S, E/W suffixes. String location_str = CreateLocationString( world_point ); Drawing.SetSResource( "SelectionDialog/Location", location_str ); // Set facility to "None" for now: will be set by the Select callback // if any selected. Drawing.SetSResource( "SelectionDialog/ID", "None" ); Drawing.SetSResource( "SelectionDialog/Facility", "None" ); // Not an icon or link: no associated data. Drawing.SetDResource( "SelectionDialog/DataLabel/Visibility", 0. ); Drawing.SetDResource( "SelectionDialog/Visibility", 1. ); Drawing.Update(); } ////////////////////////////////////////////////////////////////////////// // Highlight or unhighlight selected map polygon. // Changes the index of the color list transform attached to the object's // FillColor. ////////////////////////////////////////////////////////////////////////// void Highlight( GlgObject viewport, GlgObject sel_object ) { // Restore the color of the prev. highlighted object. if( SelectedColorIndex != null ) { SelectedColorIndex.SetDResource( null, 0. ); SelectedColorIndex = null; } // Highlight new object by changing its color if( sel_object != null ) { SelectedColorIndex = sel_object.GetResourceObject( "SelectColorIndex" ); if( SelectedColorIndex != null ) SelectedColorIndex.SetDResource( null, 1. ); } } ////////////////////////////////////////////////////////////////////////// // Converts Lat/Lon to X/Y in GLG world coordinates. ////////////////////////////////////////////////////////////////////////// void GetXY( GlgPoint lat_lon, GlgPoint xy ) { GlgObject.GlmConvert( GlgObject.RECTANGULAR_PROJECTION, Stretch, GlgObject.OBJECT_COORD, /*coord_to_lat_lon*/ false, MapCenter, MapExtent, 0., GlgMinX, GlgMaxX, GlgMinY, GlgMaxY, lat_lon, xy ); } ////////////////////////////////////////////////////////////////////////// // Converts Lat/Lon to X/Y in GLG world coordinates. ////////////////////////////////////////////////////////////////////////// void GetLatLon( GlgPoint xy, GlgPoint lat_lon ) { GlgObject.GlmConvert( GlgObject.RECTANGULAR_PROJECTION, Stretch, GlgObject.OBJECT_COORD, /*coord_to_lat_lon*/ true, MapCenter, MapExtent, 0., GlgMinX, GlgMaxX, GlgMinY, GlgMaxY, xy, lat_lon ); } ////////////////////////////////////////////////////////////////////////// // Generate a location info string by converting +- sign info into the // N/S, E/W suffixes, and decimal fraction to deg, min, sec. ////////////////////////////////////////////////////////////////////////// String CreateLocationString( GlgPoint world_point ) { int x_deg, y_deg, x_min, y_min, x_sec, y_sec; char char_x, char_y; if( world_point.x < 0. ) { world_point.x = -world_point.x; char_x = 'W'; } else if( world_point.x >= 360. ) { world_point.x -= 360.; char_x = 'E'; } else if( world_point.x >= 180. ) { world_point.x = 180. - ( world_point.x - 180. ); char_x = 'W'; } else char_x = 'E'; if( world_point.y < 0. ) { world_point.y = -world_point.y; char_y = 'S'; } else char_y = 'N'; x_deg = (int) world_point.x; x_min = (int) ( ( world_point.x - x_deg ) * 60. ); x_sec = (int) ( ( world_point.x - x_deg - x_min / 60. ) * 3600. ); y_deg = (int) world_point.y; y_min = (int) ( ( world_point.y - y_deg ) * 60. ); y_sec = (int) ( ( world_point.y - y_deg - y_min / 60. ) * 3600. ); return "" + x_deg + " deg " + x_min + " min " + x_sec + " sec " + char_x + " x " + y_deg + " deg " + y_min + " min " + y_sec + " sec " + char_y; } ////////////////////////////////////////////////////////////////////////// // Update data display. ////////////////////////////////////////////////////////////////////////// void UpdateMap() { int i, size; double value; String res_name; if( !IsReady || !DoUpdate ) return; if( ShowFlow ) { if( flow_display_obj == null ) // First time. flow_display_obj = Drawing.GetResourceObject( "MapArea/Link0/Line/LineType" ); // Links's flow is constrained: animating one animates all. // Flow direction is defined by the order of the links points when // constrained. if( flow_display_obj != null ) { // Query the current line type and offset double flow_data = flow_display_obj.GetDResource( null ).doubleValue(); int line_type = ( (int)flow_data ) % 32; int offset = ( (int)flow_data ) / 32; // Increase the offset and set it back. --offset; if( offset < 0 ) offset = 32 * 31; flow_data = offset * 32 + line_type; flow_display_obj.SetDResource( null, flow_data ); } } // Update facility values every time. size = FacilitiesGroup.GetSize(); for( i=0; i 2. ) { double icon_type = icon.GetDResource( "Group/Graphics/IconType" ).doubleValue(); if( icon_type != 0. ) icon_type = 0.; else icon_type = Rand( 0., 6. ); icon.SetDResource( "Group/Graphics/IconType", icon_type ); } } } if( ( counter % UpdateN ) == 0 ) // Update link values every n-th time. { size = LinksGroup.GetSize(); for( i=0; i 1000 ) counter = 0; Drawing.Update(); } ////////////////////////////////////////////////////////////////////////// // Toggle resource between 0 and 1. ////////////////////////////////////////////////////////////////////////// void ToggleResource( GlgObject object, String res_name ) { double value = object.GetDResource( res_name ).doubleValue(); object.SetDResource( res_name, value != 0. ? 0. : 1. ); } ////////////////////////////////////////////////////////////////////////// static void error( String string, boolean quit ) { System.out.println( string ); // Thread.currentThread().dumpStack(); if( quit ) System.exit( 0 ); } ////////////////////////////////////////////////////////////////////////// BufferedInputStream OpenStream( String filename ) { filename = GetFullPath( filename ); if( StandAlone ) { try { File file = new File( filename ); return new BufferedInputStream( new FileInputStream( file ) ); } catch( NullPointerException e ) { error( "null filename", true ); } catch( FileNotFoundException e ) { error( "Can't open file: " + filename, true ); } catch( SecurityException e ) { error( "Can't open file: " + filename, true ); } return null; } else { URL url; try { url = new URL( filename ); } catch( MalformedURLException e ) { error( "Invalid URL: " + filename, true ); return null; } try { URLConnection connection = url.openConnection(); connection.setUseCaches( false ); connection.setDefaultUseCaches( false ); return new BufferedInputStream( url.openStream() ); } catch( IOException e ) { error( "Can't open URL: " + filename, true ); return null; } } } //////////////////////////////////////////////////////////////////////// int GetButton( AWTEvent event ) { if( ! ( event instanceof InputEvent ) ) return 0; InputEvent input_event = (InputEvent) event; int modifiers = input_event.getModifiers(); if( ( modifiers & InputEvent.BUTTON3_MASK ) != 0 ) return 3; else if( ( modifiers & InputEvent.BUTTON2_MASK ) != 0 ) return 2; else return 1; } //////////////////////////////////////////////////////////////////////// String GetParameter( String name, String default_value ) { String param = getParameter( name ); if( param != null ) return param; else return default_value; } //////////////////////////////////////////////////////////////////////// boolean GetBoolParameter( String name, boolean default_value ) { String param = getParameter( name ); if( param == null ) return default_value; return param.equals( "True" ) || param.equals( "true" ) || param.equals( "TRUE" ); } //////////////////////////////////////////////////////////////////////// double GetDoubleParameter( String name, double default_value ) { String param = getParameter( name ); if( param == null ) return default_value; try { return new Double( param ).doubleValue(); } catch( NumberFormatException e ) { error( "Can't parse double parameter: " + name, false ); return default_value; } } ///////////////////////////////////////////////////////////////////// // Reads a string into a buffer, returns strlen // Automatically eats trailing white space ///////////////////////////////////////////////////////////////////// int ReadSimpleString( InputStream stream ) { int i, offset = 0; buffer[ 0 ] = 0; try { // Skip white places while( buffer[ 0 ] == ' ' || buffer[ 0 ] == '\n' || buffer[ 0 ] == '\r' || buffer[ 0 ] == 0 ) if( stream.read( buffer, 0, 1 ) == -1 ) return 0; // offset = 0 here while( buffer[ offset ] != ' ' && buffer[ offset ] != '\n' && buffer[ offset ] != '\r' && buffer[ offset ] != 0 ) { ++offset; if( offset == buffer_length ) // Increase buffer size { byte new_buffer[] = new byte[ buffer_length * 2 ]; for( i=0; i < buffer_length; ++i ) new_buffer[i] = buffer[i]; buffer = new_buffer; buffer_length *= 2; } if( stream.read( buffer, offset, 1 ) == -1 ) // The last char may have no space after it: acceppt return 0; } return offset; } catch( IOException e ) { stream_error = true; // EOF return 0; } } String ReadString( InputStream stream ) { int length = ReadSimpleString( stream ); if( length == 0 ) return null; return new String( buffer, 0, length ); } String ReadName( InputStream stream ) { String name = null, name_part; while( true ) { name_part = ReadString( stream ); if( name_part == null || name_part.equals( ":" ) ) return name; if( name == null ) name = name_part; else name = name + " " + name_part; } } char ReadChar( InputStream stream ) { int ch; while( true ) { try { ch = stream.read(); } catch( IOException e ) { ch = -1; } if( ch != ' ' && ch != '\n' && ch != '\r' && ch != 0 ) break; } if( ch == -1 ) { stream_error = true; // EOF } return (char) ch; } int ReadInt( InputStream stream ) { int length = ReadSimpleString( stream ); if( length == 0 ) { stream_error = true; // EOF return 0; } try { return Integer.parseInt( new String( buffer, 0, length ) ); } catch( NumberFormatException e ) { stream_error = true; error( "Error parsing integer value.", false ); return 0; } } double ReadDouble( InputStream stream ) { int length = ReadSimpleString( stream ); if( length == 0 ) { stream_error = true; // EOF return 0.; } try { return Double.valueOf( new String( buffer, 0, length ) ).doubleValue(); } catch( NumberFormatException e ) { error( "Error parsing double value.", false ); stream_error = true; return 0.; } } double Rand( double low, double high ) { return low + ( high - low ) * Math.random(); } ////////////////////////////////////////////////////////////////////////// // Stops updates. ////////////////////////////////////////////////////////////////////////// public void stop() { StopUpdates(); IsReady = false; super.stop(); } ////////////////////////////////////////////////////////////////////////// void StopUpdates() { if( timer != null ) { timer.stop(); timer = null; } } ////////////////////////////////////////////////////////////////////////// void StartUpdates() { if( timer == null ) { timer = new Timer( 30, this ); timer.setRepeats( true ); timer.start(); } } ////////////////////////////////////////////////////////////////////////// // ActionListener method to use the bean as update timer's ActionListener. ////////////////////////////////////////////////////////////////////////// public void actionPerformed( ActionEvent e ) { if( timer != null ) UpdateMap(); } }