/* * Copyright (c) 2016, Metron, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Metron, Inc. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.metsci.glimpse.examples.dnc; import static com.metsci.glimpse.dnc.DncDataPaths.glimpseDncFlatDir; import static com.metsci.glimpse.dnc.DncProjections.dncTangentPlane; import static com.metsci.glimpse.dnc.facc.FaccIo.readFaccAttrs; import static com.metsci.glimpse.dnc.facc.FaccIo.readFaccFeatures; import static com.metsci.glimpse.dnc.geosym.DncGeosymThemes.DNC_THEME_NIGHT; import static com.metsci.glimpse.dnc.geosym.DncGeosymThemes.DNC_THEME_STANDARD; import static com.metsci.glimpse.dnc.util.DncMiscUtils.sorted; import static com.metsci.glimpse.dnc.util.DncMiscUtils.startThread; import static com.metsci.glimpse.dnc.util.DncMiscUtils.takeNewValue; import static com.metsci.glimpse.docking.DockingFrameTitlers.createDefaultFrameTitler; import static com.metsci.glimpse.docking.DockingGroup.DockingFrameCloseOperation.DISPOSE_ALL_FRAMES; import static com.metsci.glimpse.docking.DockingThemes.tinyLafDockingTheme; import static com.metsci.glimpse.docking.DockingUtils.loadDockingArrangement; import static com.metsci.glimpse.docking.DockingUtils.requireIcon; import static com.metsci.glimpse.docking.DockingUtils.saveDockingArrangement; import static com.metsci.glimpse.examples.dnc.DncExampleUtils.initTinyLaf; import static com.metsci.glimpse.examples.dnc.DncExampleUtils.newLabel; import static com.metsci.glimpse.platformFixes.PlatformFixes.fixPlatformQuirks; import static com.metsci.glimpse.util.GeneralUtils.floats; import static com.metsci.glimpse.util.GlimpseDataPaths.requireExistingDir; import static com.metsci.glimpse.util.logging.LoggerUtils.initializeLogging; import static java.awt.Font.BOLD; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.media.opengl.GLAnimatorControl; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import org.jdesktop.swingx.JXTreeTable; import com.metsci.glimpse.axis.Axis1D; import com.metsci.glimpse.dnc.DncChunks.DncChunkKey; import com.metsci.glimpse.dnc.DncCoverage; import com.metsci.glimpse.dnc.DncFeature; import com.metsci.glimpse.dnc.DncLineFeature; import com.metsci.glimpse.dnc.DncPainter; import com.metsci.glimpse.dnc.DncPainterSettings; import com.metsci.glimpse.dnc.DncPainterSettingsImpl; import com.metsci.glimpse.dnc.DncPointFeature; import com.metsci.glimpse.dnc.DncQuery; import com.metsci.glimpse.dnc.convert.Flat2Query.QueryCache; import com.metsci.glimpse.dnc.convert.Flat2Query.QueryCacheConfig; import com.metsci.glimpse.dnc.convert.Flat2Render.RenderCache; import com.metsci.glimpse.dnc.convert.Flat2Render.RenderCacheConfig; import com.metsci.glimpse.dnc.facc.FaccAttr; import com.metsci.glimpse.dnc.facc.FaccFeature; import com.metsci.glimpse.dnc.util.DncMiscUtils.ThrowingRunnable; import com.metsci.glimpse.dnc.util.SingletonEvictingBlockingQueue; import com.metsci.glimpse.docking.DockingGroup; import com.metsci.glimpse.docking.DockingGroup.DockingGroupAdapter; import com.metsci.glimpse.docking.DockingThemes.DockingTheme; import com.metsci.glimpse.docking.TileFactories.TileFactory; import com.metsci.glimpse.docking.TileFactories.TileFactoryStandard; import com.metsci.glimpse.docking.View; import com.metsci.glimpse.docking.xml.GroupArrangement; import com.metsci.glimpse.painter.decoration.BackgroundPainter; import com.metsci.glimpse.painter.decoration.BorderPainter; import com.metsci.glimpse.painter.decoration.CrosshairPainter; import com.metsci.glimpse.painter.info.FpsPainter; import com.metsci.glimpse.plot.Plot2D; import com.metsci.glimpse.support.color.GlimpseColor; import com.metsci.glimpse.support.settings.SwingLookAndFeel; import com.metsci.glimpse.support.swing.NewtSwingEDTGlimpseCanvas; import com.metsci.glimpse.support.swing.SwingEDTAnimator; import it.unimi.dsi.fastutil.ints.IntCollection; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import net.miginfocom.swing.MigLayout; public class DncExplorer { public static void main( String[] args ) throws IOException { initializeLogging( "dnc-examples/logging.properties" ); fixPlatformQuirks( ); initTinyLaf( ); DockingTheme dockingTheme = tinyLafDockingTheme( ); ToolTipManager.sharedInstance( ).setLightWeightPopupEnabled( false ); JPopupMenu.setDefaultLightWeightPopupEnabled( false ); // Render config // RenderCacheConfig renderConfig = new RenderCacheConfig( ); renderConfig.flatParentDir = requireExistingDir( glimpseDncFlatDir ); renderConfig.proj = dncTangentPlane( 40.6892, -74.0444 ); // New York RenderCache renderCache = new RenderCache( renderConfig, 4 ); // Query config // QueryCacheConfig queryConfig = new QueryCacheConfig( ); queryConfig.flatParentDir = renderConfig.flatParentDir; queryConfig.proj = renderConfig.proj; QueryCache queryCache = new QueryCache( queryConfig, 4 ); // Create plot // Plot2D plot = new Plot2D( "" ); plot.lockAspectRatioXY( 1 ); plot.setShowMinorTicksX( true ); plot.setShowMinorTicksY( true ); plot.setAxisSizeZ( 0 ); plot.setTitleHeight( 0 ); plot.getAxis( ).set( -200, 200, -200, 200 ); plot.setSelectionSize( 30 ); BackgroundPainter backgroundPainter = new BackgroundPainter( ); DncPainterSettings dncPainterSettings = new DncPainterSettingsImpl( renderConfig.proj ); DncPainter dncPainter = new DncPainter( renderCache, dncPainterSettings ); dncPainter.addAxis( plot.getAxis( ) ); CrosshairPainter crosshairPainter = new CrosshairPainter( ); plot.getLayoutCenter( ).addPainter( backgroundPainter ); plot.getLayoutCenter( ).addPainter( dncPainter ); plot.getLayoutCenter( ).addPainter( crosshairPainter ); plot.getLayoutCenter( ).addPainter( new FpsPainter( ) ); plot.getLayoutCenter( ).addPainter( new BorderPainter( ) ); // Create attrs table // Map<String,FaccFeature> faccFeatures = readFaccFeatures( ); Map<String,FaccAttr> faccAttrs = readFaccAttrs( ); DncExplorerTreeTableModel attrsTableModel = new DncExplorerTreeTableModel( faccFeatures, faccAttrs ); JXTreeTable attrsTable = new JXTreeTable( attrsTableModel ); attrsTable.getTableHeader( ).setReorderingAllowed( false ); JScrollPane attrsScroller = new JScrollPane( attrsTable ); // Create prefs panel // JPanel prefsPanel = new JPanel( new MigLayout( "fillx, wrap 1", "[fill,grow]" ) ); prefsPanel.add( newLabel( "Color Theme", BOLD ), "gapy 12" ); JRadioButton standardThemeRadio = new JRadioButton( "Standard" ); standardThemeRadio.addItemListener( ( ev ) -> { if ( standardThemeRadio.isSelected( ) ) { dncPainter.setTheme( DNC_THEME_STANDARD ); backgroundPainter.setColor( floats( 0.5f, 0.5f, 0.5f, 1 ) ); crosshairPainter.setCursorColor( GlimpseColor.getBlack( ) ); } } ); prefsPanel.add( standardThemeRadio, "gapleft 8" ); JRadioButton nightThemeRadio = new JRadioButton( "Night" ); nightThemeRadio.addItemListener( ( ev ) -> { if ( nightThemeRadio.isSelected( ) ) { dncPainter.setTheme( DNC_THEME_NIGHT ); backgroundPainter.setColor( floats( 0.1f, 0.1f, 0.1f, 1 ) ); crosshairPainter.setCursorColor( GlimpseColor.getWhite( ) ); } } ); prefsPanel.add( nightThemeRadio, "gapleft 8" ); ButtonGroup themeRadioGroup = new ButtonGroup( ); themeRadioGroup.add( standardThemeRadio ); themeRadioGroup.add( nightThemeRadio ); standardThemeRadio.setSelected( true ); prefsPanel.add( new JSeparator( ), "gapy 12, growx" ); prefsPanel.add( newLabel( "Coverages", BOLD ) ); List<DncCoverage> coverages = sorted( renderCache.coverages, ( a, b ) -> ( a.coverageName ).compareToIgnoreCase( b.coverageName ) ); for ( DncCoverage coverage : coverages ) { JCheckBox coverageCheckbox = new JCheckBox( coverage.coverageName ); coverageCheckbox.addItemListener( ( ev ) -> { dncPainter.setCoverageActive( coverage, coverageCheckbox.isSelected( ) ); } ); coverageCheckbox.setSelected( true ); prefsPanel.add( coverageCheckbox, "gapleft 8" ); } // Query // Predicate<DncFeature> allowHighlight = ( feature ) -> { if ( feature instanceof DncPointFeature ) { return true; } else if ( feature instanceof DncLineFeature ) { String coverage = feature.chunkKey.coverage.coverageName; return ( coverage.equalsIgnoreCase( "hyd" ) || coverage.equalsIgnoreCase( "ecr" ) || coverage.equalsIgnoreCase( "iwy" ) ); } else { return false; } }; BlockingQueue<DncQuery> queries = new SingletonEvictingBlockingQueue<>( ); Runnable submitQuery = ( ) -> { Collection<DncChunkKey> chunkKeys = dncPainter.activeChunkKeys( ); Axis1D xAxis = plot.getAxisX( ); float xMin = ( float ) ( xAxis.getSelectionCenter( ) - 0.5*xAxis.getSelectionSize( ) ); float xMax = ( float ) ( xAxis.getSelectionCenter( ) + 0.5*xAxis.getSelectionSize( ) ); Axis1D yAxis = plot.getAxisY( ); float yMin = ( float ) ( yAxis.getSelectionCenter( ) - 0.5*yAxis.getSelectionSize( ) ); float yMax = ( float ) ( yAxis.getSelectionCenter( ) + 0.5*yAxis.getSelectionSize( ) ); queries.add( new DncQuery( chunkKeys, xMin, xMax, yMin, yMax ) ); }; dncPainter.addActiveChunksListener( submitQuery ); plot.addAxisListener( ( axis ) -> submitQuery.run( ) ); startThread( "DncQuery", true, new ThrowingRunnable( ) { DncQuery oldQuery = null; public void runThrows( ) throws Exception { while ( true ) { DncQuery query = takeNewValue( queries, oldQuery ); attrsTableModel.retainChunks( new HashSet<>( query.chunkKeys ) ); queryCache.runQuery( query, dncPainter.chunkPriorityFunc, ( chunkKey, features ) -> { List<DncFeature> highlighted = features.stream( ).filter( allowHighlight ).collect( Collectors.toList( ) ); attrsTableModel.setChunkFeatures( chunkKey, highlighted ); IntCollection featureNums = new IntOpenHashSet( ); highlighted.stream( ).mapToInt( f -> f.featureNum ).forEach( featureNums::add ); dncPainter.highlightFeatures( chunkKey, featureNums ); } ); oldQuery = query; } } } ); // Show // SwingUtilities.invokeLater( ( ) -> { NewtSwingEDTGlimpseCanvas geoCanvas = new NewtSwingEDTGlimpseCanvas( ); geoCanvas.addLayout( plot ); geoCanvas.setLookAndFeel( new SwingLookAndFeel( ) ); GLAnimatorControl animator = new SwingEDTAnimator( 30 ); animator.add( geoCanvas.getGLDrawable( ) ); animator.start( ); View[] views = { new View( "geoView", geoCanvas, "Geo", false, null, requireIcon( "icons/fugue/map.png" ) ), new View( "attrsView", attrsScroller, "Features", false, null, requireIcon( "icons/eclipse/class_hi.gif" ) ), new View( "prefsView", prefsPanel, "Prefs", false, null, requireIcon( "icons/fugue/equalizer.png" ) ), }; String appName = "dnc-explorer"; DockingGroup dockingGroup = new DockingGroup( dockingTheme, DISPOSE_ALL_FRAMES ); dockingGroup.addListener( createDefaultFrameTitler( "DNC Explorer" ) ); TileFactory tileFactory = new TileFactoryStandard( dockingGroup ); GroupArrangement groupArr = loadDockingArrangement( appName, DncExplorer.class.getClassLoader( ).getResource( "dnc-examples/docking-defaults.xml" ) ); dockingGroup.restoreArrangement( groupArr, tileFactory, views ); dockingGroup.addListener( new DockingGroupAdapter( ) { public void disposingAllFrames( DockingGroup group ) { saveDockingArrangement( appName, dockingGroup.captureArrangement( ) ); attrsTableModel.dispose( ); animator.stop( ); } } ); } ); } }