/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ package demo.triplebuffering; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.URL; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.border.BevelBorder; import javax.swing.border.LineBorder; import ilog.views.IlvApplyObject; import ilog.views.IlvGraphic; import ilog.views.IlvManager; import ilog.views.IlvManagerView; import ilog.views.IlvPoint; import ilog.views.IlvRect; import ilog.views.IlvTransformer; import ilog.views.swing.IlvJManagerViewControlBar; /** * The main class <code>TripleBuffering</code>. */ SuppressWarnings("serial") public class TripleBuffering extends JRootPane { /** * Data structure for airline companies. */ private static final AirLine[] companies = { new AirLine("AA", "images/airline1.gif"), new AirLine("AL", "images/airline2.gif"), new AirLine("AM", "images/airline3.gif"), new AirLine("CP", "images/airline4.gif"), new AirLine("CS", "images/airline5.gif"), new AirLine("DE", "images/airline6.gif"), new AirLine("FI", "images/airline7.gif"), new AirLine("IB", "images/airline8.gif"), new AirLine("IT", "images/airline9.gif"), new AirLine("KL", "images/airline10.gif"), new AirLine("KO", "images/airline1.gif"), new AirLine("QA", "images/airline2.gif"), new AirLine("SA", "images/airline3.gif"), new AirLine("SB", "images/airline4.gif"), new AirLine("UN", "images/airline5.gif") }; /** * Data structure that records the <code>Image</code> objects for the logos of * the companies. */ private static final Image[] companiesLogos = new Image[companies.length]; /** * Number of animated tracks. */ private int maxTracks = 50; /** * Array of animated tracks. */ private Track[] tracks; /** * Bounding box of the background map. */ private static IlvRect mapBox; /** * Delta for track movements. */ private static double delta; /** * The manager. */ private IlvManager manager; /** * The view of the manager. */ private IlvManagerView mgrview; /** * Timer for animation. */ private Timer timer; /** * Font of the track symbols. */ private Font font = new Font("Helvetica", Font.PLAIN, 10); /** * The check boxes. */ private JCheckBox showLabelsButton, showLogosButton, lastPositionButton; private JCheckBox layerCache, tripleBuffer; /** * The combo box. */ private JComboBox<String> combo; /** * To indicate the performance: */ private JLabel fpsLabel; /** * The layer that contains the tracks. */ private int trackLayer; /** * The history of fps. We show an average fps to avoid that the ftp flickers * too much. */ private long[] fpsHistory = new long[50]; private int fpsHIndex = 0; private boolean fpsHistoryFull = false; /** * Initializes the sample. */ public void init() { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need to be in possession // of a Perforce JViews Diagrammer Deployment license. // IlvProductUtil.DeploymentLicenseRequired( // IlvProductUtil.JViews_Diagrammer_Deployment); // Creates the manager manager = new IlvManager(); // Creates the view for the manager mgrview = new IlvManagerView(manager) { Override public void paint(Graphics g) { long time = System.nanoTime(); super.paint(g); time = System.nanoTime() - time; if (time == 0) time = 1; long fps = 1000000000 / time; fpsHistory[fpsHIndex++] = fps; if (fpsHIndex >= fpsHistory.length) { fpsHistoryFull = true; fpsHIndex = 0; } int max = (fpsHistoryFull ? fpsHistory.length : fpsHIndex); long sum = 0; for (int i = 0; i < max; i++) { sum += fpsHistory[i]; } fpsLabel.setText("Refresh " + (sum / max) + " fps"); } }; // Sets the keep aspect ratio on mgrview.setKeepingAspectRatio(true); // Sets the background of the view. // Either a simple color... // mgrview.setBackground(new Color(88, 210, 221)); // ...or a nice gradient obtained via a background pattern: try { URL url = getClass().getResource("images/BackgroundPattern.gif"); mgrview.setBackgroundPatternLocation(url); } catch (Throwable th) { System.err.println("Couldn't get file: images/BackgroundPattern.gif"); } // Reads the background map. try { manager.setFileName(getClass().getResource("world.ivl")); } catch (Exception th) { System.err.println("Couldn't get file: world.ivl"); } // Sets the tripple buffering on for the layers of the map. mgrview.setTripleBufferedLayerCount(manager.getLayersCount()); mapBox = manager.computeBBox(null); delta = mapBox.width / 200; getContentPane().setLayout(new BorderLayout(0, 0)); // Tracks will be added in a new layer at the top. trackLayer = manager.getLayersCount(); // Creates the tracks. tracks = new Track[maxTracks]; for (int i = 0; i < maxTracks; i++) { Track track = newRandomTrack(Color.black, Color.blue, Color.yellow); manager.addObject(track, trackLayer, false); tracks[i] = track; } // Reads the foreground clouds. try { manager.read(getClass().getResource("clouds.ivl")); } catch (Exception th) { System.err.println("Couldn't get file: clouds.ivl"); } IlvGraphic template = manager.getObject("cloud"); manager.removeObject(template, false); for (int i = 0; i < 100; i++) { manager.addObject(newRandomCloud(template), trackLayer + 1, false); } manager.removeObject(manager.getObject("background"), false); manager.getManagerLayer(trackLayer + 1).setAlpha(0.75F); mgrview.setLayerCached(trackLayer + 1, true); getContentPane().add(mgrview, BorderLayout.CENTER); // Creates a toolbar for basic zoom/unzoom operations. IlvJManagerViewControlBar toolbar = new IlvJManagerViewControlBar(); toolbar.setFloatable(false); toolbar.setSelectButtonAvailable(false); toolbar.setOrientation(JToolBar.VERTICAL); toolbar.setView(mgrview); getContentPane().add(toolbar, BorderLayout.WEST); getContentPane().add(createControlPanel(), BorderLayout.SOUTH); // Create the timer. timer = new Timer(66, new Animation()); // true for debugging Timer.setLogTimers(false); } /** * Creates a random point located somewhere on the map. */ public IlvPoint randomPoint() { IlvPoint randomPt = new IlvPoint(mapBox.x + (Math.random() * mapBox.width), mapBox.y + (Math.random() * mapBox.height)); return randomPt; } /** * Creates a new track. */ public Track newRandomTrack(Color color, Color hilit, Color alt) { // Company int companyIndex = (int) (Math.random() * companies.length); AirLine company = companies[companyIndex]; // Flight name. String name = company.getName() + " 0" + (100 + (int) (Math.random() * 900)); // Logo image Image image = getLogoImage(companyIndex, company.getLogoFileName()); // Creates the track. Track track = new Track(name, image, randomPoint(), randomPoint(), font, color, hilit, alt); // Random speed [250 - 1500] mph track.setSpeed(250 + (int) (Math.random() * 1250)); // Random height [5000-55000] ft track.setAltitude(100 * (50 + (int) (Math.random() * 500))); track.setWarningDistance(delta * 2); return track; } /** * Returns the image for the logo of a given company. The image is read only * once for each company name. */ private Image getLogoImage(int companyIndex, String companyLogoFileName) { Image image = companiesLogos[companyIndex]; if (image != null) // the image was already read return image; // otherwise, read the image try { URL url = getClass().getResource(companyLogoFileName); image = Toolkit.getDefaultToolkit().getImage(url); } catch (Throwable th) { System.err.println("Couldn't get file: " + companyLogoFileName); } // store it, to avoid reading again next time companiesLogos[companyIndex] = image; return image; } /** * Creates a new cloud. */ public IlvGraphic newRandomCloud(IlvGraphic template) { IlvGraphic cloud = template.copy(); cloud.move(randomPoint()); return cloud; } /** * Starts the sample. */ public void start() { mgrview.setTransformer(new IlvTransformer(2.5, 0, 0, 2.5, 250, 150)); timer.start(); } /** * Stops the sample. */ public void stop() { timer.stop(); } /** * Changes the number of tracks. */ private void setNumberOfTracks(int number) { if (number == maxTracks) return; maxTracks = number; timer.stop(); manager.deleteAll(trackLayer, false); tracks = new Track[maxTracks]; Track.transparentLastPositions = (maxTracks <= 100); Track.antialiasedLastPositions = (maxTracks <= 100); for (int i = 0; i < maxTracks; i++) { Track track = newRandomTrack(Color.black, Color.blue, Color.yellow); manager.addObject(track, trackLayer, false); tracks[i] = track; } showLabelsButton.setSelected(true); showLogosButton.setSelected(true); lastPositionButton.setSelected(true); mgrview.repaint(); timer.start(); } /** * Shows or hides the last positions. */ private void setShowingLastPositions(final boolean value) { for (int i = 0; i < maxTracks; i++) manager.applyToObject(tracks[i], new IlvApplyObject() { Override public void apply(IlvGraphic obj, Object arg) { ((Track) obj).setShowingLastPositions(value); } }, null, false); mgrview.repaint(); } /** * Shows or hides the labels of tracks. */ private void setShowingLabels(final boolean value) { for (int i = 0; i < maxTracks; i++) manager.applyToObject(tracks[i], new IlvApplyObject() { Override public void apply(IlvGraphic obj, Object arg) { ((Track) obj).setShowingLabels(value); } }, null, false); mgrview.repaint(); } /** * Shows or hides the logos of tracks. */ private void setShowingLogos(final boolean value) { for (int i = 0; i < maxTracks; i++) manager.applyToObject(tracks[i], new IlvApplyObject() { Override public void apply(IlvGraphic obj, Object arg) { ((Track) obj).setShowingLogo(value); } }, null, false); mgrview.repaint(); } /** * Action listener used by the timer to animate the tracks. */ private class Animation implements IlvApplyObject, ActionListener { Override public void actionPerformed(ActionEvent evt) { // Update the position of the tracks for (int i = 0; i < maxTracks; i++) manager.applyToObject(tracks[i], this, null, false); // Repaint the entire sample, not only the manager view, // to avoid delayed repaints of the other components of the sample TripleBuffering.this.repaint(); } /** * The method that moves a track. */ Override public void apply(IlvGraphic obj, Object arg) { Track track = (Track) obj; if (track.hasLanded()) track.init(randomPoint(), randomPoint()); else { IlvPoint destination = track.getDestination(); IlvPoint position = track.getPosition(); double d = (delta * track.getSpeed()) / 800; double X = destination.x - position.x; double Y = destination.y - position.y; double R2 = X * X + Y * Y; if (R2 <= d * d) track.land(); else { double R = Math.sqrt(R2); double dx = (d * X) / R; double dy = (d * Y) / R; track.translatePosition(dx, dy); } } } } /** * Item listener for check boxes. */ private class CheckBoxListener implements ItemListener { Override public void itemStateChanged(ItemEvent e) { final boolean selected = e.getStateChange() == ItemEvent.SELECTED; Object source = e.getItemSelectable(); if (source == tripleBuffer) mgrview.setTripleBufferedLayerCount(selected ? 1 : 0); else if (source == layerCache) mgrview.setLayerCached(2, selected); else if (source == showLabelsButton) setShowingLabels(selected); else if (source == showLogosButton) setShowingLogos(selected); else if (source == lastPositionButton) setShowingLastPositions(selected); else if (source == combo) { int value = 50; try { value = Integer.parseInt(e.getItem().toString()); } catch (Exception ex) { } setNumberOfTracks(value); } fpsHIndex = 0; fpsHistoryFull = false; } } private JComponent createControlPanel() { JPanel p = new JPanel(); p.setBorder(LineBorder.createGrayLineBorder()); CheckBoxListener listener = new CheckBoxListener(); lastPositionButton = new JCheckBox("Last Positions"); lastPositionButton.setMnemonic(KeyEvent.VK_P); lastPositionButton.setSelected(true); lastPositionButton.addItemListener(listener); p.add(lastPositionButton); showLabelsButton = new JCheckBox("Labels"); showLabelsButton.setMnemonic(KeyEvent.VK_L); showLabelsButton.setSelected(true); showLabelsButton.addItemListener(listener); p.add(showLabelsButton); showLogosButton = new JCheckBox("Logos"); showLogosButton.setMnemonic(KeyEvent.VK_G); showLogosButton.setSelected(true); showLogosButton.addItemListener(listener); p.add(showLogosButton); JPanel trackNumber = new JPanel(); combo = new JComboBox<String>(); combo.addItem("50"); combo.addItem("100"); combo.addItem("300"); combo.addItem("500"); combo.addItemListener(listener); trackNumber.add(new JLabel("Tracks:")); trackNumber.add(combo); p.add(trackNumber); tripleBuffer = new JCheckBox("Triple Buffer"); tripleBuffer.setMnemonic(KeyEvent.VK_B); tripleBuffer.setSelected(true); tripleBuffer.addItemListener(listener); p.add(tripleBuffer); layerCache = new JCheckBox("Layer Cache"); layerCache.setMnemonic(KeyEvent.VK_C); layerCache.setSelected(true); layerCache.addItemListener(listener); p.add(layerCache); fpsLabel = new JLabel(); fpsLabel.setForeground(Color.MAGENTA); fpsLabel.setBorder(new BevelBorder(1)); fpsLabel.setPreferredSize(new Dimension(130, 20)); p.add(fpsLabel); return p; } /** * A main method to run the demo as an application. */ public static void main(String[] args) { // Sun recommends that to put the entire GUI initialization into the // AWT thread SwingUtilities.invokeLater(new Runnable() { Override public void run() { JFrame frame = new JFrame("Triple Buffering Demo"); frame.addWindowListener(new WindowAdapter() { Override public void windowClosing(WindowEvent e) { System.exit(0); } }); TripleBuffering app = new TripleBuffering(); frame.getContentPane().add(app); frame.setSize(790, 480); app.init(); app.start(); frame.setVisible(true); } }); } /** * A data structure for airlines. */ private static class AirLine { private String _name; private String _logoFileName; AirLine(String name, String logoFileName) { _name = name; _logoFileName = logoFileName; } String getName() { return _name; } String getLogoFileName() { return _logoFileName; } } }