/************************************************************* * Spring 2003, Visualization Class (Professor Yap) * Hw4 Solution by * Zubin Girglani (zg220@nyu.edu), * Marianna Shvartsapel (m_shvartsapel@yahoo.com), * Evelina Khukhashvili (ek401@nyu.edu) * * This display shows the map of Manhattan (lines only) * It supports zooming (buttons) and panning. * It requires a Postgresql server to serve map information. * * Separately, there is a Reader program to enter the * Tiger data into a Postgresql Database. * * BUGS: * -- should not get a new image buffer each time it is repainted! * -- zooming should not shift the center of display * -- should allow window resize (and do not open to cover whole * screen when started out -- but provide this option) * * EXTENSIONS (not all implemented): * -- add quit button (done) * -- add a print button to support Xfig output (half-done) * -- add slider for zooming (not done) *************************************************************/ import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.*; import java.sql.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; import org.postgresql.geometric.*; public class MapDisplay extends JFrame implements ActionListener { String DEFAULT_HOSTNAME = "slinky.cs.nyu.edu"; String DEFAULT_PORT = "5432"; String DEFAULT_DATABASE = "kzm"; String DEFAULT_USERNAME = "visclass"; String DEFAULT_PASSWORD = "visclass"; String DEFAULT_TABLENAME = "rt12"; Connection con; Statement stmt; ResultSet rs; Dimension screenSize; Insets screenInsets; Dimension frameSize; Dimension mapSize; Point pressedPoint; Point translatedPoint; BufferedImage mapImage; Graphics2D mapGraphics; Container contentPane; JPanel mapPanel; JPanel controlPanel; JButton minusButton; // zoom out JButton plusButton; // zoom in JButton printButton; // print Xfig JButton quitButton; // quit Object[] tigerLines; int count = 0; // debug counter boolean printFlag = false; // whether to output in Xfig String printFile = "output.fig"; // name of Xfig output file double minLong; double minLat; double cosMinLat; // projection scale factor double maxLong; double maxLat; double scale; public MapDisplay() { // Moved from paintComponent: // mapImage = new BufferedImage( mapSize.width, mapSize.height, BufferedImage.TYPE_INT_ARGB ); openConnection(); retrieveData(); closeConnection(); showFrame(); } public void openConnection() { try { Class.forName( "org.postgresql.Driver" ); con = DriverManager.getConnection( "jdbc:postgresql://" + DEFAULT_HOSTNAME + ":" + DEFAULT_PORT + "/" + DEFAULT_DATABASE, DEFAULT_USERNAME, DEFAULT_PASSWORD ); stmt = con.createStatement(); } catch( Exception e ) { e.printStackTrace(); } } public void retrieveData() { screenSize = Toolkit.getDefaultToolkit().getScreenSize(); screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration() ); frameSize = new Dimension( ( screenSize.width - screenInsets.left - screenInsets.right ), ( screenSize.height - screenInsets.top - screenInsets.bottom ) ); pressedPoint = new Point( 0, 0 ); translatedPoint = new Point( 0, 0 ); ArrayList al = new ArrayList(); try { rs = stmt.executeQuery( "SELECT min(startpt[0]) FROM " + DEFAULT_TABLENAME ); while ( rs.next() ) { minLong = rs.getDouble( 1 ); } rs = stmt.executeQuery( "SELECT min(startpt[1]) FROM " + DEFAULT_TABLENAME ); while ( rs.next() ) { minLat = rs.getDouble( 1 ); cosMinLat = Math.cos(Math.toRadians(((double)minLat)/1000000.0)); } rs = stmt.executeQuery( "SELECT max(startpt[0]) FROM " + DEFAULT_TABLENAME ); while ( rs.next() ) { maxLong = rs.getDouble( 1 ); } rs = stmt.executeQuery( "SELECT max(startpt[1]) FROM " + DEFAULT_TABLENAME ); while ( rs.next() ) { maxLat = rs.getDouble( 1 ); } rs = stmt.executeQuery( "SELECT details FROM " + DEFAULT_TABLENAME ); scale = frameSize.width / ( maxLong - minLong ); while ( rs.next() ) { PGpoint[] lines = ( ( PGpolygon ) rs.getObject( 1 ) ).points; for ( int j = 0; j < lines.length; j++ ) { lines[ j ].x = ( lines[ j ].x - minLong ); lines[ j ].y = Math.abs( ( lines[ j ].y - maxLat ) ); } al.add( new PGpolygon( lines) ); } tigerLines = al.toArray(); // Is this a bug? Shouldn't we multiply the Longitude by Cosine(Lat)? mapSize = new Dimension( ( int ) ( ( maxLong - minLong ) * scale ), ( int ) ( ( maxLat - minLat ) * scale ) ); } catch( Exception e ) { e.printStackTrace(); } } public void closeConnection() { try { rs.close(); stmt.close(); con.close(); } catch( Exception e ) { e.printStackTrace(); } } public void showFrame() { contentPane = getContentPane(); addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { dispose(); System.exit( 0 ); } } ); setLocation( 0, 0 ); setSize( frameSize ); setResizable( false ); contentPane.setLayout( new BorderLayout() ); mapPanel = new JPanel() { public void paintComponent( Graphics g ) { Graphics2D g2 = ( Graphics2D ) g; mapSize.width = ( int ) ( ( maxLong - minLong ) * scale ); mapSize.height = ( int ) ( ( maxLat - minLat ) * scale ); // THE NEXT LINE SHOULD BE MOVED OUT OF LOOP! mapImage = new BufferedImage( mapSize.width, mapSize.height, BufferedImage.TYPE_INT_ARGB ); mapGraphics = mapImage.createGraphics(); mapGraphics.setPaint( Color.BLUE ); for ( int i = 0; i < tigerLines.length; i++ ) { PGpoint[] lines = ( ( PGpolygon ) tigerLines[ i ] ).points; GeneralPath gp = new GeneralPath(); gp.moveTo( (float)(lines[ 0 ].x * scale * cosMinLat) , (float)(lines[ 0 ].y * scale) ); for ( int j = 0; j < lines.length ; j++ ) { gp.lineTo( (float)(lines[ j ].x * scale * cosMinLat) , (float)(lines[ j ].y * scale) ); } mapGraphics.draw( gp ); } g2.drawImage( mapImage, translatedPoint.x, translatedPoint.y, mapSize.width, mapSize.height, this ); } }; mapPanel.setBorder( BorderFactory.createLineBorder( Color.GREEN ) ); mapPanel.addMouseListener( new MouseAdapter() { public void mousePressed( MouseEvent e ) { Point p = e.getPoint(); pressedPoint.x = p.x - translatedPoint.x; pressedPoint.y = p.y - translatedPoint.y; } } ); mapPanel.addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged( MouseEvent e ) { Point p = e.getPoint(); p.x = p.x - pressedPoint.x; p.y = p.y - pressedPoint.y; translatedPoint = p; repaint(); } } ); controlPanel = new JPanel(); controlPanel.setBorder( BorderFactory.createLineBorder( Color.GREEN ) ); minusButton = new JButton( "-" ); minusButton.addActionListener( this ); controlPanel.add( minusButton ); plusButton = new JButton( "+" ); plusButton.addActionListener( this ); controlPanel.add( plusButton ); // Chee's addition: printButton = new JButton( "Print" ); printButton.addActionListener( this ); controlPanel.add( printButton ); quitButton = new JButton( "Quit" ); quitButton.addActionListener( this ); controlPanel.add( quitButton ); contentPane.add( mapPanel, "Center" ); contentPane.add( controlPanel, "South" ); setVisible( true ); } public void actionPerformed( ActionEvent e ) { if ( e.getSource() == minusButton ) { scale *= 0.6; } else if ( e.getSource() == plusButton ) { scale *= 1.70; } else if ( e.getSource() == printButton ) { if (printFlag) printFlag = false; else printFlag = true; } else if ( e.getSource() == quitButton ) { System.exit(0); } repaint(); } public static void main( String[] args ) { new MapDisplay(); } }