From 6a6f363893b53a774349a0a55e533cb7aab31348 Mon Sep 17 00:00:00 2001 From: Edward Moyse <edward.moyse@cern.ch> Date: Thu, 20 Dec 2018 14:38:09 +0100 Subject: [PATCH] Removing Atlantis, as this is now hosted elsewhere. --- graphics/AtlantisJava/CMakeLists.txt | 31 - graphics/AtlantisJava/ant/build.xml | 469 --- .../AtlantisJava/configuration/PSProlog.txt | 156 - .../AtlantisJava/configuration/colormap.xml | 369 --- .../AtlantisJava/configuration/config.dtd | 169 -- .../AtlantisJava/configuration/epusti.csv | 5 - graphics/AtlantisJava/configuration/pdg.xml | 109 - .../configuration/rpsplt_fcal.csv | 498 --- .../AtlantisJava/configuration/rpsplt_hec.csv | 329 -- .../configuration/rpsplt_tile.csv | 169 -- graphics/AtlantisJava/events/event.dtd | 506 ---- graphics/AtlantisJava/geometry/AGeometry.xml | 233 -- .../AtlantisJava/geometry/AMuonGeometry.xml | 220 -- graphics/AtlantisJava/geometry/ATLAS_IDS.xml | 27 - graphics/AtlantisJava/geometry/IdDict.dtd | 118 - .../AtlantisJava/geometry/IdDictATLAS.xml | 56 - .../geometry/IdDictCalorimeter.xml | 731 ----- .../geometry/IdDictForwardDetectors.xml | 140 - .../geometry/IdDictInnerDetector.xml | 559 ---- .../geometry/IdDictLArCalorimeter.xml | 694 ----- .../geometry/IdDictLArElectrode.xml | 327 -- .../geometry/IdDictLArHighVoltage.xml | 222 -- .../geometry/IdDictTileCalorimeter.xml | 398 --- graphics/AtlantisJava/img/atlantis_icon.gif | Bin 2939 -> 0 bytes graphics/AtlantisJava/img/atlantis_log.gif | Bin 18919 -> 0 bytes graphics/AtlantisJava/img/atlas.jpg | Bin 32018 -> 0 bytes graphics/AtlantisJava/img/atlas_logo_big.png | Bin 7956 -> 0 bytes .../img/cursor_DnD_invalid_32x32.gif | Bin 153 -> 0 bytes .../img/cursor_DnD_invalid_64x64.gif | Bin 204 -> 0 bytes .../img/cursor_DnD_valid_32x32.gif | Bin 147 -> 0 bytes .../img/cursor_DnD_valid_64x64.gif | Bin 202 -> 0 bytes .../AtlantisJava/img/cursor_fisheye_32x32.gif | Bin 1191 -> 0 bytes .../AtlantisJava/img/cursor_fisheye_64x64.gif | Bin 1259 -> 0 bytes .../img/cursor_fisheye_bw_32x32.gif | Bin 167 -> 0 bytes .../img/cursor_fisheye_bw_64x64.gif | Bin 220 -> 0 bytes .../AtlantisJava/img/cursor_move_32x32.gif | Bin 235 -> 0 bytes .../AtlantisJava/img/cursor_move_64x64.gif | Bin 286 -> 0 bytes .../AtlantisJava/img/cursor_pick_32x32.gif | Bin 142 -> 0 bytes .../AtlantisJava/img/cursor_pick_64x64.gif | Bin 194 -> 0 bytes .../AtlantisJava/img/cursor_rectsel_32x32.gif | Bin 176 -> 0 bytes .../AtlantisJava/img/cursor_rectsel_64x64.gif | Bin 207 -> 0 bytes .../AtlantisJava/img/cursor_rotate_32x32.gif | Bin 1126 -> 0 bytes .../AtlantisJava/img/cursor_rotate_64x64.gif | Bin 1190 -> 0 bytes .../img/cursor_rotate_bw_32x32.gif | Bin 238 -> 0 bytes .../img/cursor_rotate_bw_64x64.gif | Bin 300 -> 0 bytes .../AtlantisJava/img/cursor_sync_32x32.gif | Bin 916 -> 0 bytes .../AtlantisJava/img/cursor_sync_64x64.gif | Bin 973 -> 0 bytes .../AtlantisJava/img/cursor_zoom_32x32.gif | Bin 335 -> 0 bytes .../AtlantisJava/img/cursor_zoom_64x64.gif | Bin 394 -> 0 bytes .../AtlantisJava/img/cursor_zoom_bw_32x32.gif | Bin 161 -> 0 bytes .../AtlantisJava/img/cursor_zoom_bw_64x64.gif | Bin 212 -> 0 bytes graphics/AtlantisJava/img/downarrow.png | Bin 183 -> 0 bytes .../AtlantisJava/img/interaction_clock.png | Bin 1033 -> 0 bytes .../AtlantisJava/img/interaction_fisheye.png | Bin 694 -> 0 bytes .../AtlantisJava/img/interaction_pick.png | Bin 260 -> 0 bytes .../AtlantisJava/img/interaction_rotate.png | Bin 608 -> 0 bytes .../img/interaction_rubberband.png | Bin 699 -> 0 bytes .../img/interaction_rubberbandyx.png | Bin 699 -> 0 bytes .../AtlantisJava/img/interaction_scale.png | Bin 422 -> 0 bytes .../AtlantisJava/img/interaction_skew.png | Bin 271 -> 0 bytes .../img/interaction_synccursors.png | Bin 455 -> 0 bytes graphics/AtlantisJava/img/interaction_zmr.png | Bin 1010 -> 0 bytes graphics/AtlantisJava/img/interaction_zr.png | Bin 234 -> 0 bytes graphics/AtlantisJava/img/left.gif | Bin 172 -> 0 bytes graphics/AtlantisJava/img/minerva_log.gif | Bin 19469 -> 0 bytes graphics/AtlantisJava/img/mode_loop.png | Bin 470 -> 0 bytes graphics/AtlantisJava/img/mode_loop_on.png | Bin 475 -> 0 bytes graphics/AtlantisJava/img/mode_random.png | Bin 1032 -> 0 bytes graphics/AtlantisJava/img/mode_random_on.png | Bin 1045 -> 0 bytes graphics/AtlantisJava/img/mode_sequential.png | Bin 387 -> 0 bytes .../AtlantisJava/img/mode_sequential_on.png | Bin 386 -> 0 bytes graphics/AtlantisJava/img/right.gif | Bin 172 -> 0 bytes graphics/AtlantisJava/img/toolbar_next.png | Bin 659 -> 0 bytes graphics/AtlantisJava/img/toolbar_open.png | Bin 550 -> 0 bytes .../AtlantisJava/img/toolbar_previous.png | Bin 634 -> 0 bytes graphics/AtlantisJava/img/uparrow.png | Bin 189 -> 0 bytes graphics/AtlantisJava/lib/Jama.jar | Bin 33329 -> 0 bytes graphics/AtlantisJava/lib/batik-anim.jar | Bin 95479 -> 0 bytes graphics/AtlantisJava/lib/batik-ext.jar | Bin 10261 -> 0 bytes graphics/AtlantisJava/lib/batik-extension.jar | Bin 68051 -> 0 bytes graphics/AtlantisJava/lib/batik-parser.jar | Bin 73710 -> 0 bytes graphics/AtlantisJava/lib/batik-script.jar | Bin 61893 -> 0 bytes graphics/AtlantisJava/lib/batik-xml.jar | Bin 30862 -> 0 bytes graphics/AtlantisJava/lib/commons-cli-1.0.jar | Bin 30117 -> 0 bytes .../AtlantisJava/lib/commons-codec-1.4.jar | Bin 58160 -> 0 bytes .../AtlantisJava/lib/commons-logging-1.1.jar | Bin 52915 -> 0 bytes graphics/AtlantisJava/lib/jas-aida-dev.jar | Bin 3738 -> 0 bytes graphics/AtlantisJava/lib/jas-aida.jar | Bin 40424 -> 0 bytes graphics/AtlantisJava/lib/jas-jel.jar | Bin 33570 -> 0 bytes graphics/AtlantisJava/lib/jlibeps.jar | Bin 17486 -> 0 bytes graphics/AtlantisJava/lib/oncrpc.jar | Bin 86081 -> 0 bytes .../lib/ostermillerutils_1_05_00.jar | Bin 34346 -> 0 bytes .../AtlantisJava/lib/test/fest-assert-1.2.jar | Bin 89901 -> 0 bytes .../lib/test/fest-reflect-1.2.jar | Bin 37208 -> 0 bytes .../AtlantisJava/lib/test/fest-util-1.1.2.jar | Bin 18962 -> 0 bytes .../lib/test/jcip-annotations-1.0.jar | Bin 2255 -> 0 bytes .../lib/ws-commons-util-1.0.2.jar | Bin 34407 -> 0 bytes graphics/AtlantisJava/lib/xml-apis-ext.jar | Bin 85686 -> 0 bytes .../AtlantisJava/lib/xmlrpc-client-3.1.jar | Bin 45124 -> 0 bytes .../AtlantisJava/lib/xmlrpc-server-3.1.jar | Bin 75310 -> 0 bytes .../AtlantisJava/share/InteractiveServer.py | 483 --- graphics/AtlantisJava/share/MINERVA.jnlp | 84 - graphics/AtlantisJava/share/atlantis | 13 - graphics/AtlantisJava/share/atlantis.jnlp | 81 - graphics/AtlantisJava/share/atlantis_online | 15 - graphics/AtlantisJava/share/ntupleXML.h | 1351 --------- .../AtlantisJava/share/specificconfig.jnlp | 83 - .../src/atlantis/ACommandLine.java | 399 --- .../src/atlantis/AOpenGLTools.java | 22 - .../AtlantisJava/src/atlantis/Atlantis.java | 770 ----- .../src/atlantis/canvas/ACanvas.java | 1113 ------- .../canvas/ADrawCalorimeterSummedEndcaps.java | 937 ------ .../src/atlantis/canvas/AGLGraphics.java | 486 --- .../src/atlantis/canvas/ALayout.java | 231 -- .../canvas/ALayoutChangeListener.java | 16 - .../src/atlantis/canvas/ALegendWindow.java | 197 -- .../src/atlantis/canvas/AOverlay.java | 193 -- .../src/atlantis/canvas/AScale.java | 356 --- .../src/atlantis/canvas/AScaleBorder.java | 1282 -------- .../src/atlantis/canvas/ATitleMenuBar.java | 92 - .../src/atlantis/canvas/AWindow.java | 1549 ---------- .../src/atlantis/canvas/AWindowGLView.java | 337 --- .../src/atlantis/canvas/AWindowSwingView.java | 57 - .../src/atlantis/canvas/package.html | 23 - .../src/atlantis/config/AConfig.java | 432 --- .../src/atlantis/config/AConfigNode.java | 263 -- .../src/atlantis/config/AConfigUpdater.java | 405 --- .../src/atlantis/config/ADefaultValues.java | 206 -- .../src/atlantis/config/package.html | 6 - .../src/atlantis/data/A3DPointData.java | 254 -- .../src/atlantis/data/AAODData.java | 359 --- .../src/atlantis/data/ABJetData.java | 134 - .../src/atlantis/data/ACSCDData.java | 304 -- .../src/atlantis/data/ACSCData.java | 197 -- .../src/atlantis/data/ACalorimeterData.java | 2662 ----------------- .../src/atlantis/data/ACalorimeterRPSPLT.java | 260 -- .../src/atlantis/data/AClusterData.java | 385 --- .../atlantis/data/ACompositeParticleData.java | 114 - .../src/atlantis/data/ADHelix.java | 539 ---- .../src/atlantis/data/AETMisData.java | 562 ---- .../src/atlantis/data/AElectronData.java | 180 -- .../src/atlantis/data/AEmTauROIData.java | 34 - .../src/atlantis/data/AEventFromXML.java | 786 ----- .../src/atlantis/data/AFCALData.java | 1228 -------- .../src/atlantis/data/AG4StepData.java | 559 ---- .../src/atlantis/data/AHECData.java | 574 ---- .../src/atlantis/data/AHelix.java | 854 ------ .../src/atlantis/data/AHelixAODData.java | 178 -- .../src/atlantis/data/AHistogram.java | 422 --- .../src/atlantis/data/AHistogramData.java | 15 - .../src/atlantis/data/AHitData.java | 487 --- .../src/atlantis/data/AInDetSegmentData.java | 30 - .../src/atlantis/data/AInDetTrackData.java | 164 - .../src/atlantis/data/AJetData.java | 782 ----- .../src/atlantis/data/AJetROIData.java | 38 - .../src/atlantis/data/ALArData.java | 1032 ------- .../atlantis/data/ALVL1JetElementData.java | 446 --- .../src/atlantis/data/ALVL1ResultData.java | 292 -- .../atlantis/data/ALVL1TriggerTowerData.java | 800 ----- .../src/atlantis/data/ALegoData.java | 1042 ------- .../src/atlantis/data/AMBTSData.java | 595 ---- .../src/atlantis/data/AMDTData.java | 338 --- .../src/atlantis/data/AMuonData.java | 95 - .../src/atlantis/data/AMuonHitData.java | 192 -- .../src/atlantis/data/AMuonROIData.java | 34 - .../src/atlantis/data/AMuonSegmentData.java | 56 - .../src/atlantis/data/AMuonTrackData.java | 200 -- .../src/atlantis/data/AOldHelix.java | 338 --- .../src/atlantis/data/APDGTable.java | 107 - .../src/atlantis/data/AParticle.java | 57 - .../src/atlantis/data/APhotonData.java | 166 - .../src/atlantis/data/APixelClusterData.java | 403 --- .../src/atlantis/data/APixelRDOData.java | 160 - .../src/atlantis/data/APulseShapePlot.java | 513 ---- .../src/atlantis/data/AROIData.java | 334 --- .../src/atlantis/data/ARPCData.java | 311 -- .../src/atlantis/data/ARVxData.java | 1043 ------- .../src/atlantis/data/AS3DData.java | 486 --- .../src/atlantis/data/ASMTrData.java | 626 ---- .../src/atlantis/data/ASNPData.java | 659 ---- .../src/atlantis/data/ASTrData.java | 254 -- .../src/atlantis/data/ASVxData.java | 167 -- .../src/atlantis/data/ASegmentData.java | 164 - .../src/atlantis/data/ASiClusterData.java | 385 --- .../src/atlantis/data/ASiClusterRDOData.java | 481 --- .../src/atlantis/data/ATGCData.java | 340 --- .../src/atlantis/data/ATILEData.java | 843 ------ .../src/atlantis/data/ATRTData.java | 752 ----- .../src/atlantis/data/ATauJetData.java | 198 -- .../src/atlantis/data/ATrackData.java | 1389 --------- .../src/atlantis/data/ATrackResidualData.java | 323 -- .../src/atlantis/data/ATrigS3DData.java | 252 -- .../src/atlantis/data/ATriggerInfoData.java | 213 -- .../src/atlantis/data/AVertex.java | 328 -- .../src/atlantis/data/AVertexFit.java | 289 -- .../src/atlantis/data/package.html | 8 - .../src/atlantis/event/AAssociation.java | 298 -- .../atlantis/event/AAssociationManager.java | 118 - .../atlantis/event/ABufferedEventSource.java | 263 -- .../src/atlantis/event/AData.java | 1661 ---------- .../src/atlantis/event/AEpsImageProducer.java | 117 - .../src/atlantis/event/AEvent.java | 1051 ------- .../src/atlantis/event/AEventInfo.java | 212 -- .../src/atlantis/event/AEventInfoPrinter.java | 60 - .../src/atlantis/event/AEventManager.java | 319 -- .../src/atlantis/event/AEventSource.java | 114 - .../atlantis/event/AEventSourceException.java | 65 - .../src/atlantis/event/AFileEventSource.java | 309 -- .../src/atlantis/event/AFilter.java | 275 -- .../src/atlantis/event/AImageProducer.java | 129 - .../src/atlantis/event/ANewEventListener.java | 18 - .../event/ANewEventSourceListener.java | 16 - .../atlantis/event/AObjectsAssociation.java | 26 - .../src/atlantis/event/APngImageProducer.java | 119 - .../atlantis/event/AStreamedEventSource.java | 52 - .../src/atlantis/event/ASvgImageProducer.java | 117 - .../src/atlantis/event/AURLEventSource.java | 385 --- .../src/atlantis/event/AZipEventSource.java | 478 --- .../event/oncrpc/AONCRPCEventSource.java | 304 -- .../src/atlantis/event/oncrpc/Event.java | 86 - .../atlantis/event/oncrpc/EventRequest.java | 79 - .../src/atlantis/event/oncrpc/Server.java | 47 - .../src/atlantis/event/oncrpc/Streams.java | 53 - .../src/atlantis/event/package.html | 9 - .../atlantis/event/xmlrpc/AClientXMLRPC.java | 244 -- .../event/xmlrpc/ARemoteCallerException.java | 22 - .../atlantis/event/xmlrpc/AServerXMLRPC.java | 43 - .../xmlrpc/AServerXMLRPCEventSource.java | 146 - .../event/xmlrpc/AXMLRPCEventSource.java | 238 -- .../src/atlantis/geometry/AAtlasDetector.java | 119 - .../geometry/ABarrelCalorimeterDetector.java | 284 -- .../geometry/ABarrelSiliconDetector.java | 276 -- .../atlantis/geometry/ABarrelTRTDetector.java | 184 -- .../src/atlantis/geometry/ABoxDetector.java | 172 -- .../src/atlantis/geometry/ABoxDetectors.java | 168 -- .../geometry/ACalorimeterDetector.java | 699 ----- .../src/atlantis/geometry/ADetector.java | 157 - .../atlantis/geometry/ADetectorSystem.java | 122 - .../src/atlantis/geometry/ADetectors.java | 114 - .../src/atlantis/geometry/ADiscDetector.java | 57 - .../geometry/AEndcapCalorimeterDetector.java | 328 -- .../geometry/AEndcapCryostatDetector.java | 158 - .../geometry/AEndcapSiliconDetector.java | 220 -- .../atlantis/geometry/AEndcapTRTDetector.java | 173 -- .../geometry/AGapCalorimeterDetector.java | 179 -- .../atlantis/geometry/AGeneralDetectors.java | 71 - .../geometry/AGeometryFromXMLReader.java | 286 -- .../atlantis/geometry/ARectangleDetector.java | 49 - .../src/atlantis/geometry/ATBxDetector.java | 81 - .../atlantis/geometry/ATrapezoidDetector.java | 211 -- .../geometry/ATrapezoidDetectors.java | 163 - .../src/atlantis/geometry/package.html | 8 - .../src/atlantis/globals/AGlobals.java | 202 -- .../src/atlantis/globals/package.html | 13 - .../graphics/AAbstractGraphics2D.java | 315 -- .../src/atlantis/graphics/AClipper.java | 226 -- .../src/atlantis/graphics/ACoord.java | 355 --- .../src/atlantis/graphics/ACursorFactory.java | 227 -- .../atlantis/graphics/ADrawParameters.java | 98 - .../src/atlantis/graphics/ADrawable.java | 24 - .../atlantis/graphics/ADrawnGraphics2D.java | 149 - .../atlantis/graphics/ADummyGraphics2D.java | 215 -- .../atlantis/graphics/AGLPixelGraphics.java | 47 - .../src/atlantis/graphics/AGraphics.java | 407 --- .../src/atlantis/graphics/AIcon.java | 28 - .../src/atlantis/graphics/ALegoDraw.java | 1150 ------- .../atlantis/graphics/APickingGraphics2D.java | 432 --- .../src/atlantis/graphics/APixelGraphics.java | 304 -- .../graphics/ATemplateGraphics2D.java | 47 - .../atlantis/graphics/AVectorGraphics.java | 309 -- .../atlantis/graphics/colormap/AColorMap.java | 365 --- .../graphics/colormap/MappedColor.java | 93 - .../src/atlantis/graphics/dnd/ACallBack.java | 9 - .../src/atlantis/graphics/dnd/ADnDButton.java | 88 - .../src/atlantis/graphics/dnd/ADnDLabel.java | 184 -- .../atlantis/graphics/dnd/ADragListener.java | 9 - .../graphics/dnd/AObjectTransferable.java | 62 - .../graphics/encoders/AImageEncoder.java | 167 -- .../graphics/encoders/PngEncoder.java | 582 ---- .../atlantis/graphics/layout/AFlowLayout.java | 115 - .../atlantis/graphics/layout/AGridLayout.java | 214 -- .../graphics/layout/ARunAnotherLayout.java | 26 - .../src/atlantis/graphics/package.html | 6 - .../src/atlantis/gui/AAboutDialog.java | 214 -- .../src/atlantis/gui/ACheckBox.java | 33 - .../src/atlantis/gui/ACheckNode.java | 86 - .../gui/AClosingConfirmationDialog.java | 63 - .../atlantis/gui/AColorComboBoxRenderer.java | 126 - .../src/atlantis/gui/AColorHelpDialog.java | 260 -- .../src/atlantis/gui/AColorMapDialog.java | 109 - .../src/atlantis/gui/AColorMapEditor.java | 281 -- .../src/atlantis/gui/AComboBox.java | 51 - .../src/atlantis/gui/AConfigWriter.java | 417 --- .../src/atlantis/gui/AControlButton.java | 84 - .../src/atlantis/gui/ACrashReporter.java | 232 -- .../atlantis/gui/ADefaultCellAttribute.java | 129 - .../src/atlantis/gui/ADemoDialog.java | 434 --- .../src/atlantis/gui/ADemoFileChooser.java | 41 - .../src/atlantis/gui/ADemoLoop.java | 200 -- .../src/atlantis/gui/AEventLoopDialog.java | 346 --- .../atlantis/gui/AEventPropertiesDialog.java | 721 ----- .../src/atlantis/gui/AEventQueue.java | 165 - .../src/atlantis/gui/AEventSourceToolBar.java | 523 ---- .../src/atlantis/gui/AFileControl.java | 210 -- .../AtlantisJava/src/atlantis/gui/AGUI.java | 572 ---- .../src/atlantis/gui/AGUILayoutManager.java | 131 - .../src/atlantis/gui/AGUIUtilities.java | 167 -- .../src/atlantis/gui/AHelpControl.java | 45 - .../src/atlantis/gui/AHelpSystem.java | 118 - .../src/atlantis/gui/AInteractionToolBar.java | 429 --- .../src/atlantis/gui/AItemTabbedPane.java | 144 - .../src/atlantis/gui/ALayoutDialog.java | 109 - .../src/atlantis/gui/ALazyPanel.java | 109 - .../src/atlantis/gui/AListsControl.java | 28 - .../src/atlantis/gui/ALogPane.java | 205 -- .../src/atlantis/gui/AMainLogPane.java | 13 - .../src/atlantis/gui/AMenuButton.java | 46 - .../src/atlantis/gui/AMouseHelpDialog.java | 312 -- .../atlantis/gui/AMultiSpanCellTableUI.java | 81 - .../src/atlantis/gui/AMutableCheckBox.java | 183 -- .../src/atlantis/gui/AOpenGLControl.java | 160 - .../src/atlantis/gui/AParamGUIDataModel.java | 173 -- .../src/atlantis/gui/AParametersPage.java | 44 - .../src/atlantis/gui/AParametersTable.java | 253 -- .../src/atlantis/gui/APasswordDialog.java | 203 -- .../atlantis/gui/APointerPositionWindow.java | 175 -- .../src/atlantis/gui/APopupHelper.java | 48 - .../src/atlantis/gui/APreferencesControl.java | 429 --- .../atlantis/gui/AReadColorMapChooser.java | 35 - .../src/atlantis/gui/AReadFileChooser.java | 103 - .../atlantis/gui/AReadGeometryChooser.java | 79 - .../src/atlantis/gui/ASaveCanvasDialog.java | 477 --- .../src/atlantis/gui/AStartupWindow.java | 86 - .../src/atlantis/gui/ATabbedPaneUI.java | 35 - .../src/atlantis/gui/ATextField.java | 31 - .../src/atlantis/gui/ATreeCellRenderer.java | 34 - .../atlantis/gui/ATreeExpansionListener.java | 43 - .../src/atlantis/gui/AWindowControl.java | 190 -- .../src/atlantis/gui/AXMLFileChooser.java | 108 - .../src/atlantis/gui/AXMLGeometryChooser.java | 73 - .../src/atlantis/gui/package.html | 8 - .../atlantis/interactions/A3DBoxGroup.java | 14 - .../interactions/A3DBoxInteraction.java | 202 -- .../atlantis/interactions/AClockGroup.java | 62 - .../interactions/AClockInteraction.java | 103 - .../interactions/AEnterExitListener.java | 13 - .../interactions/AFishEyeChangeListener.java | 17 - .../atlantis/interactions/AFishEyeGroup.java | 116 - .../interactions/AFishEyeInteraction.java | 389 --- .../atlantis/interactions/AInteraction.java | 323 -- .../interactions/AInteractionGroup.java | 143 - .../AInteractionsConfigReader.java | 69 - .../interactions/AInteractionsManager.java | 535 ---- .../atlantis/interactions/ALineSegment.java | 165 - .../src/atlantis/interactions/AModifier.java | 85 - .../interactions/AMouseDragListener.java | 20 - .../interactions/AMousePressListener.java | 16 - .../src/atlantis/interactions/ANZMRGroup.java | 16 - .../interactions/ANZMRInteraction.java | 80 - .../interactions/AParallelogramSelection.java | 119 - .../src/atlantis/interactions/APickGroup.java | 102 - .../interactions/APickInteraction.java | 419 --- .../atlantis/interactions/APopupListener.java | 16 - .../interactions/ARectangleSelection.java | 95 - .../interactions/ARectangleVPSelection.java | 524 ---- .../interactions/ARectangleYXSelection.java | 320 -- .../ARotatedRectangleSelection.java | 211 -- .../interactions/ARubberbandGroup.java | 109 - .../interactions/ARubberbandYXGroup.java | 109 - .../interactions/AScaleCopyGroup.java | 14 - .../interactions/AScaleCopyInteraction.java | 24 - .../src/atlantis/interactions/ASelection.java | 455 --- .../src/atlantis/interactions/ASkewGroup.java | 14 - .../interactions/ASkewInteraction.java | 123 - .../interactions/ASleepMouseDragListener.java | 13 - .../interactions/ASquareSelection.java | 87 - .../interactions/ASynchroCursorsGroup.java | 15 - .../ASynchroCursorsInteraction.java | 483 --- .../interactions/AVPSelectionGroup.java | 15 - .../interactions/AWindowInfoInteraction.java | 73 - .../interactions/AXSkewSelection.java | 124 - .../interactions/AXSliceSelection.java | 79 - .../interactions/AYSkewSelection.java | 124 - .../interactions/AYSliceSelection.java | 79 - .../src/atlantis/interactions/AZMRGroup.java | 14 - .../interactions/AZMRInteraction.java | 700 ----- .../src/atlantis/interactions/package.html | 11 - .../src/atlantis/list/AColorIcon.java | 69 - .../AtlantisJava/src/atlantis/list/AList.java | 128 - .../src/atlantis/list/AListManager.java | 1765 ----------- .../src/atlantis/list/AListProcessor.java | 10 - .../src/atlantis/list/package.html | 6 - .../src/atlantis/nge/ANAnimInterpolate.java | 47 - .../src/atlantis/nge/ANAnimSegment.java | 13 - .../src/atlantis/nge/ANAnimSetProjection.java | 38 - .../src/atlantis/nge/ANAnimThread.java | 67 - .../src/atlantis/nge/ANAnimVar.java | 27 - .../src/atlantis/nge/ANAnimationManager.java | 92 - .../src/atlantis/nge/ANCacheToken.java | 11 - .../src/atlantis/nge/ANColor.java | 87 - .../src/atlantis/nge/ANFrameManager.java | 190 -- .../src/atlantis/nge/ANGlobalFlags.java | 17 - .../src/atlantis/nge/ANLinearProjection.java | 229 -- .../src/atlantis/nge/ANLinearTransition.java | 140 - .../src/atlantis/nge/ANManager.java | 122 - .../src/atlantis/nge/ANObjectGenerator.java | 151 - .../src/atlantis/nge/ANPickDrawer.java | 59 - .../src/atlantis/nge/ANPickHandler.java | 11 - .../src/atlantis/nge/ANPickHandlerSimple.java | 19 - .../src/atlantis/nge/ANPickHelper.java | 51 - .../src/atlantis/nge/ANPickListener.java | 15 - .../src/atlantis/nge/ANPickResult.java | 21 - .../src/atlantis/nge/ANPickResultPrinter.java | 17 - .../src/atlantis/nge/ANProjection.java | 20 - .../src/atlantis/nge/ANProjection3D.java | 90 - .../src/atlantis/nge/ANProjectionPhysics.java | 181 -- .../src/atlantis/nge/ANProjectionYX.java | 46 - .../src/atlantis/nge/ANRenderHints.java | 33 - .../src/atlantis/nge/ANRenderer.java | 22 - .../src/atlantis/nge/ANRendererBasic.java | 88 - .../src/atlantis/nge/ANSelectionList.java | 81 - .../src/atlantis/nge/ANTerribleHacks.java | 119 - .../src/atlantis/nge/ANTestWindow.java | 119 - .../src/atlantis/nge/object/ANObject.java | 27 - .../src/atlantis/nge/object/ANObjectList.java | 30 - .../atlantis/nge/object/ANObjectTestAxes.java | 44 - .../src/atlantis/nge/object/ANObjectVL.java | 66 - .../nge/object/data/ANObjectDataCell.java | 170 -- .../nge/object/data/ANObjectDataJet.java | 146 - .../nge/object/data/ANObjectPointing.java | 147 - .../nge/object/data/ANObjectTracks.java | 82 - .../nge/object/geometry/ANObjectBeamLine.java | 21 - .../nge/object/geometry/ANObjectGeomCalo.java | 159 - .../nge/object/geometry/ANObjectGeomMuon.java | 229 -- .../atlantis/output/AExceptionHandler.java | 61 - .../src/atlantis/output/ALogInterface.java | 25 - .../src/atlantis/output/AOutput.java | 54 - .../AtlantisJava/src/atlantis/package.html | 8 - .../parameters/AAbstractParameter.java | 913 ------ .../atlantis/parameters/AColorParameter.java | 92 - .../src/atlantis/parameters/ACommand.java | 31 - .../parameters/ACommandProcessor.java | 451 --- .../atlantis/parameters/ACutParameter.java | 171 -- .../parameters/AEnumeratorParameter.java | 278 -- .../atlantis/parameters/ALinkParameter.java | 151 - .../parameters/AListIntegerParameter.java | 98 - .../atlantis/parameters/ANumberParameter.java | 104 - .../src/atlantis/parameters/APar.java | 657 ---- .../src/atlantis/parameters/AParameter.java | 107 - .../parameters/AParameterChangeListener.java | 11 - .../parameters/AParameterConfigReader.java | 114 - .../atlantis/parameters/AParameterData.java | 202 -- .../atlantis/parameters/AParameterState.java | 38 - .../parameters/AParameterSuperGroup.java | 241 -- .../parameters/AParameterUtilities.java | 102 - .../atlantis/parameters/AParametersGroup.java | 157 - .../parameters/AStatusGroupParameter.java | 213 -- .../atlantis/parameters/AStatusParameter.java | 58 - .../parameters/AStatusRootParameter.java | 435 --- .../src/atlantis/parameters/package.html | 7 - .../src/atlantis/projection/AProjection.java | 32 - .../atlantis/projection/AProjection2D.java | 348 --- .../atlantis/projection/AProjection3D.java | 167 -- .../atlantis/projection/AProjection3DBox.java | 569 ---- .../projection/AProjectionEventInfo.java | 197 -- .../atlantis/projection/AProjectionFR.java | 127 - .../atlantis/projection/AProjectionFZ.java | 76 - .../atlantis/projection/AProjectionInfo.java | 102 - .../projection/AProjectionLegoPlot.java | 402 --- .../atlantis/projection/AProjectionN3D.java | 66 - .../atlantis/projection/AProjectionNGE.java | 143 - .../projection/AProjectionNPhysics.java | 95 - .../atlantis/projection/AProjectionNYX.java | 71 - .../atlantis/projection/AProjectionPhi.java | 73 - .../atlantis/projection/AProjectionRZ.java | 68 - .../projection/AProjectionTrackResidual.java | 167 -- .../atlantis/projection/AProjectionVP.java | 169 -- .../atlantis/projection/AProjectionXZ.java | 81 - .../atlantis/projection/AProjectionYX.java | 307 -- .../atlantis/projection/AProjectionYZ.java | 72 - .../projection/AProjectionsManager.java | 110 - .../src/atlantis/projection/package.html | 9 - .../src/atlantis/utils/A3Vector.java | 98 - .../src/atlantis/utils/A4Vector.java | 127 - .../atlantis/utils/AAtlantisException.java | 41 - .../src/atlantis/utils/AClipPolygon.java | 98 - .../src/atlantis/utils/ACommandHistory.java | 213 -- .../src/atlantis/utils/AHashMap.java | 201 -- .../src/atlantis/utils/AIdDictionary.java | 152 - .../src/atlantis/utils/AIdField.java | 537 ---- .../src/atlantis/utils/AIdHelper.java | 599 ---- .../src/atlantis/utils/AIdRange.java | 392 --- .../src/atlantis/utils/AIntHashtable.java | 79 - .../src/atlantis/utils/ALogger.java | 213 -- .../src/atlantis/utils/ALoggerFactory.java | 25 - .../src/atlantis/utils/AMath.java | 328 -- .../src/atlantis/utils/ANewIdHelper.java | 157 - .../src/atlantis/utils/APoint.java | 72 - .../src/atlantis/utils/APolygon.java | 238 -- .../src/atlantis/utils/AUtilities.java | 243 -- .../src/atlantis/utils/AVector.java | 84 - .../src/atlantis/utils/package.html | 6 - .../src/atlantis/utils/xml/AArrayParser.java | 36 - .../atlantis/utils/xml/AFloatArrayParser.java | 255 -- .../atlantis/utils/xml/AIntArrayParser.java | 126 - .../utils/xml/AStringArrayParser.java | 103 - .../utils/xml/AXMLEntityResolver.java | 40 - .../atlantis/utils/xml/AXMLErrorHandler.java | 127 - .../src/atlantis/utils/xml/AXMLUtils.java | 38 - graphics/AtlantisJava/src/overview.html | 25 - .../AtlantisJava/test/events/emptyEvent.xml | 6 - .../test/events/muonCollections.xml | 240 -- .../test/events/muonCollections2.xml | 291 -- .../AtlantisJava/test/events/rvxEvent.xml | 44 - .../test/events/rvxInconsistentEvent.xml | 258 -- .../atlantis/AtlantisHeadlessTestCase.java | 38 - .../test/src/atlantis/HeadlessTest.java | 21 - .../src/atlantis/InconsistentEventTest.java | 36 - .../src/atlantis/NoTracksElementTest.java | 36 - .../src/atlantis/canvas/AScaleBorderTest.java | 19 - .../test/src/atlantis/canvas/AScaleTest.java | 104 - .../test/src/atlantis/canvas/AWindowTest.java | 14 - .../test/src/atlantis/data/AHelixTest.java | 100 - .../test/src/atlantis/data/AOldHelixTest.java | 92 - .../src/atlantis/event/AEventInfoTest.java | 68 - .../src/atlantis/graphics/ACoordTest.java | 73 - .../src/atlantis/list/AListManagerTest.java | 51 - .../parameters/AAbstractParameterTest.java | 120 - .../parameters/AParameterDataTest.java | 84 - .../test/src/atlantis/utils/A3VectorTest.java | 101 - .../test/src/atlantis/utils/A4VectorTest.java | 128 - .../test/src/atlantis/utils/AIdRangeTest.java | 90 - .../test/src/atlantis/utils/AMathTest.java | 69 - .../src/atlantis/utils/ANewIdHelperTest.java | 130 - .../test/src/guitest/AAssert.java | 28 - .../test/src/guitest/AtlantisGUIFixture.java | 141 - .../test/src/guitest/AtlantisGuiTestCase.java | 100 - .../src/guitest/EnumeratorParameterTest.java | 17 - .../src/guitest/EventSourceToolBarTest.java | 14 - .../src/guitest/InteractionToolBarTest.java | 48 - .../src/guitest/LoadEventFailureTest.java | 22 - .../test/src/guitest/LoadEventTest.java | 25 - ...LoadEventWithInvalidRecVertexDataTest.java | 29 - .../LoadEventWithValidRecVertexDataTest.java | 29 - .../src/guitest/LoadEventsManyTimesTest.java | 31 - .../MuonTrackCollectionsEmptyTest.java | 39 - .../src/guitest/MuonTrackCollectionsTest.java | 40 - .../test/src/guitest/OverlayTest.java | 27 - .../test/src/guitest/ProjectionsTest.java | 24 - .../guitest/ReadNextAndPreviousEventTest.java | 27 - .../test/src/guitest/StartAndExitTest.java | 19 - .../test/src/guitest/TabsTest.java | 23 - .../test/src/testutils/AtlantisInit.java | 20 - .../test/src/testutils/TeeOutputStream.java | 34 - .../test/src/testutils/TestUtils.java | 17 - 555 files changed, 103264 deletions(-) delete mode 100644 graphics/AtlantisJava/CMakeLists.txt delete mode 100755 graphics/AtlantisJava/ant/build.xml delete mode 100755 graphics/AtlantisJava/configuration/PSProlog.txt delete mode 100755 graphics/AtlantisJava/configuration/colormap.xml delete mode 100644 graphics/AtlantisJava/configuration/config.dtd delete mode 100644 graphics/AtlantisJava/configuration/epusti.csv delete mode 100755 graphics/AtlantisJava/configuration/pdg.xml delete mode 100644 graphics/AtlantisJava/configuration/rpsplt_fcal.csv delete mode 100644 graphics/AtlantisJava/configuration/rpsplt_hec.csv delete mode 100644 graphics/AtlantisJava/configuration/rpsplt_tile.csv delete mode 100755 graphics/AtlantisJava/events/event.dtd delete mode 100755 graphics/AtlantisJava/geometry/AGeometry.xml delete mode 100755 graphics/AtlantisJava/geometry/AMuonGeometry.xml delete mode 100755 graphics/AtlantisJava/geometry/ATLAS_IDS.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDict.dtd delete mode 100755 graphics/AtlantisJava/geometry/IdDictATLAS.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictCalorimeter.xml delete mode 100644 graphics/AtlantisJava/geometry/IdDictForwardDetectors.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictInnerDetector.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictLArCalorimeter.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictLArElectrode.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictLArHighVoltage.xml delete mode 100755 graphics/AtlantisJava/geometry/IdDictTileCalorimeter.xml delete mode 100755 graphics/AtlantisJava/img/atlantis_icon.gif delete mode 100755 graphics/AtlantisJava/img/atlantis_log.gif delete mode 100755 graphics/AtlantisJava/img/atlas.jpg delete mode 100644 graphics/AtlantisJava/img/atlas_logo_big.png delete mode 100755 graphics/AtlantisJava/img/cursor_DnD_invalid_32x32.gif delete mode 100755 graphics/AtlantisJava/img/cursor_DnD_invalid_64x64.gif delete mode 100755 graphics/AtlantisJava/img/cursor_DnD_valid_32x32.gif delete mode 100755 graphics/AtlantisJava/img/cursor_DnD_valid_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_fisheye_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_fisheye_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_fisheye_bw_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_fisheye_bw_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_move_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_move_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_pick_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_pick_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rectsel_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rectsel_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rotate_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rotate_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rotate_bw_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_rotate_bw_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_sync_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_sync_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_zoom_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_zoom_64x64.gif delete mode 100644 graphics/AtlantisJava/img/cursor_zoom_bw_32x32.gif delete mode 100644 graphics/AtlantisJava/img/cursor_zoom_bw_64x64.gif delete mode 100644 graphics/AtlantisJava/img/downarrow.png delete mode 100644 graphics/AtlantisJava/img/interaction_clock.png delete mode 100644 graphics/AtlantisJava/img/interaction_fisheye.png delete mode 100644 graphics/AtlantisJava/img/interaction_pick.png delete mode 100644 graphics/AtlantisJava/img/interaction_rotate.png delete mode 100644 graphics/AtlantisJava/img/interaction_rubberband.png delete mode 100644 graphics/AtlantisJava/img/interaction_rubberbandyx.png delete mode 100644 graphics/AtlantisJava/img/interaction_scale.png delete mode 100644 graphics/AtlantisJava/img/interaction_skew.png delete mode 100644 graphics/AtlantisJava/img/interaction_synccursors.png delete mode 100644 graphics/AtlantisJava/img/interaction_zmr.png delete mode 100644 graphics/AtlantisJava/img/interaction_zr.png delete mode 100755 graphics/AtlantisJava/img/left.gif delete mode 100644 graphics/AtlantisJava/img/minerva_log.gif delete mode 100644 graphics/AtlantisJava/img/mode_loop.png delete mode 100644 graphics/AtlantisJava/img/mode_loop_on.png delete mode 100644 graphics/AtlantisJava/img/mode_random.png delete mode 100644 graphics/AtlantisJava/img/mode_random_on.png delete mode 100644 graphics/AtlantisJava/img/mode_sequential.png delete mode 100644 graphics/AtlantisJava/img/mode_sequential_on.png delete mode 100755 graphics/AtlantisJava/img/right.gif delete mode 100755 graphics/AtlantisJava/img/toolbar_next.png delete mode 100755 graphics/AtlantisJava/img/toolbar_open.png delete mode 100755 graphics/AtlantisJava/img/toolbar_previous.png delete mode 100644 graphics/AtlantisJava/img/uparrow.png delete mode 100755 graphics/AtlantisJava/lib/Jama.jar delete mode 100644 graphics/AtlantisJava/lib/batik-anim.jar delete mode 100644 graphics/AtlantisJava/lib/batik-ext.jar delete mode 100644 graphics/AtlantisJava/lib/batik-extension.jar delete mode 100644 graphics/AtlantisJava/lib/batik-parser.jar delete mode 100644 graphics/AtlantisJava/lib/batik-script.jar delete mode 100644 graphics/AtlantisJava/lib/batik-xml.jar delete mode 100755 graphics/AtlantisJava/lib/commons-cli-1.0.jar delete mode 100644 graphics/AtlantisJava/lib/commons-codec-1.4.jar delete mode 100644 graphics/AtlantisJava/lib/commons-logging-1.1.jar delete mode 100755 graphics/AtlantisJava/lib/jas-aida-dev.jar delete mode 100755 graphics/AtlantisJava/lib/jas-aida.jar delete mode 100755 graphics/AtlantisJava/lib/jas-jel.jar delete mode 100644 graphics/AtlantisJava/lib/jlibeps.jar delete mode 100644 graphics/AtlantisJava/lib/oncrpc.jar delete mode 100644 graphics/AtlantisJava/lib/ostermillerutils_1_05_00.jar delete mode 100644 graphics/AtlantisJava/lib/test/fest-assert-1.2.jar delete mode 100644 graphics/AtlantisJava/lib/test/fest-reflect-1.2.jar delete mode 100644 graphics/AtlantisJava/lib/test/fest-util-1.1.2.jar delete mode 100644 graphics/AtlantisJava/lib/test/jcip-annotations-1.0.jar delete mode 100644 graphics/AtlantisJava/lib/ws-commons-util-1.0.2.jar delete mode 100644 graphics/AtlantisJava/lib/xml-apis-ext.jar delete mode 100644 graphics/AtlantisJava/lib/xmlrpc-client-3.1.jar delete mode 100644 graphics/AtlantisJava/lib/xmlrpc-server-3.1.jar delete mode 100755 graphics/AtlantisJava/share/InteractiveServer.py delete mode 100644 graphics/AtlantisJava/share/MINERVA.jnlp delete mode 100755 graphics/AtlantisJava/share/atlantis delete mode 100644 graphics/AtlantisJava/share/atlantis.jnlp delete mode 100755 graphics/AtlantisJava/share/atlantis_online delete mode 100644 graphics/AtlantisJava/share/ntupleXML.h delete mode 100644 graphics/AtlantisJava/share/specificconfig.jnlp delete mode 100644 graphics/AtlantisJava/src/atlantis/ACommandLine.java delete mode 100644 graphics/AtlantisJava/src/atlantis/AOpenGLTools.java delete mode 100644 graphics/AtlantisJava/src/atlantis/Atlantis.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/ACanvas.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/ADrawCalorimeterSummedEndcaps.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/AGLGraphics.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/ALayout.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/ALayoutChangeListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/ALegendWindow.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/AOverlay.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/AScale.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/AScaleBorder.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/ATitleMenuBar.java delete mode 100755 graphics/AtlantisJava/src/atlantis/canvas/AWindow.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/AWindowGLView.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/AWindowSwingView.java delete mode 100644 graphics/AtlantisJava/src/atlantis/canvas/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/config/AConfig.java delete mode 100755 graphics/AtlantisJava/src/atlantis/config/AConfigNode.java delete mode 100644 graphics/AtlantisJava/src/atlantis/config/AConfigUpdater.java delete mode 100755 graphics/AtlantisJava/src/atlantis/config/ADefaultValues.java delete mode 100644 graphics/AtlantisJava/src/atlantis/config/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/data/A3DPointData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AAODData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ABJetData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ACSCDData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ACSCData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ACalorimeterData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ACalorimeterRPSPLT.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AClusterData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ACompositeParticleData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ADHelix.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AETMisData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AElectronData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AEmTauROIData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AEventFromXML.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AFCALData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AG4StepData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AHECData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AHelix.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AHelixAODData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AHistogram.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AHistogramData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AHitData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AInDetSegmentData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AInDetTrackData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AJetData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AJetROIData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ALArData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ALVL1JetElementData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ALVL1ResultData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ALVL1TriggerTowerData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ALegoData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AMBTSData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AMDTData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AMuonData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AMuonHitData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AMuonROIData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AMuonSegmentData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AMuonTrackData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AOldHelix.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/APDGTable.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AParticle.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/APhotonData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/APixelClusterData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/APixelRDOData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/APulseShapePlot.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AROIData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ARPCData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ARVxData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/AS3DData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASMTrData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASNPData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASTrData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASVxData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ASegmentData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASiClusterData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ASiClusterRDOData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ATGCData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ATILEData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ATRTData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/ATauJetData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ATrackData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ATrackResidualData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ATrigS3DData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/ATriggerInfoData.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AVertex.java delete mode 100755 graphics/AtlantisJava/src/atlantis/data/AVertexFit.java delete mode 100644 graphics/AtlantisJava/src/atlantis/data/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AAssociation.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AAssociationManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/ABufferedEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AEpsImageProducer.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AEvent.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AEventInfo.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AEventInfoPrinter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AEventManager.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AEventSourceException.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AFileEventSource.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/AFilter.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AImageProducer.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/ANewEventListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/ANewEventSourceListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AObjectsAssociation.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/APngImageProducer.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AStreamedEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/ASvgImageProducer.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AURLEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/AZipEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/oncrpc/AONCRPCEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/oncrpc/Event.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/oncrpc/EventRequest.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/oncrpc/Server.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/oncrpc/Streams.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/event/xmlrpc/AClientXMLRPC.java delete mode 100755 graphics/AtlantisJava/src/atlantis/event/xmlrpc/ARemoteCallerException.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPC.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPCEventSource.java delete mode 100644 graphics/AtlantisJava/src/atlantis/event/xmlrpc/AXMLRPCEventSource.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AAtlasDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ABarrelCalorimeterDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ABarrelSiliconDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ABarrelTRTDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ABoxDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ABoxDetectors.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ACalorimeterDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ADetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ADetectorSystem.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ADetectors.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ADiscDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AEndcapCalorimeterDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AEndcapCryostatDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AEndcapSiliconDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AEndcapTRTDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AGapCalorimeterDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AGeneralDetectors.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/AGeometryFromXMLReader.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ARectangleDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ATBxDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetectors.java delete mode 100644 graphics/AtlantisJava/src/atlantis/geometry/package.html delete mode 100644 graphics/AtlantisJava/src/atlantis/globals/AGlobals.java delete mode 100644 graphics/AtlantisJava/src/atlantis/globals/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/AAbstractGraphics2D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/AClipper.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ACoord.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ACursorFactory.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ADrawParameters.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ADrawable.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ADrawnGraphics2D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ADummyGraphics2D.java delete mode 100644 graphics/AtlantisJava/src/atlantis/graphics/AGLPixelGraphics.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/AGraphics.java delete mode 100644 graphics/AtlantisJava/src/atlantis/graphics/AIcon.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ALegoDraw.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/APickingGraphics2D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/APixelGraphics.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/ATemplateGraphics2D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/AVectorGraphics.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/colormap/AColorMap.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/colormap/MappedColor.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/dnd/ACallBack.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDButton.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDLabel.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/dnd/ADragListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/dnd/AObjectTransferable.java delete mode 100644 graphics/AtlantisJava/src/atlantis/graphics/encoders/AImageEncoder.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/encoders/PngEncoder.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/layout/AFlowLayout.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/layout/AGridLayout.java delete mode 100755 graphics/AtlantisJava/src/atlantis/graphics/layout/ARunAnotherLayout.java delete mode 100644 graphics/AtlantisJava/src/atlantis/graphics/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AAboutDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ACheckBox.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ACheckNode.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AClosingConfirmationDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AColorComboBoxRenderer.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AColorHelpDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AColorMapDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AColorMapEditor.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AComboBox.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AConfigWriter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AControlButton.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/ACrashReporter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ADefaultCellAttribute.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ADemoDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ADemoFileChooser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ADemoLoop.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AEventLoopDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AEventPropertiesDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AEventQueue.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AEventSourceToolBar.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AFileControl.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AGUI.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AGUILayoutManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AGUIUtilities.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AHelpControl.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AHelpSystem.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AInteractionToolBar.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AItemTabbedPane.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ALayoutDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ALazyPanel.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AListsControl.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/ALogPane.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AMainLogPane.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AMenuButton.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AMouseHelpDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AMultiSpanCellTableUI.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AMutableCheckBox.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/AOpenGLControl.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AParamGUIDataModel.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AParametersPage.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AParametersTable.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/APasswordDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/APointerPositionWindow.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/APopupHelper.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/APreferencesControl.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AReadColorMapChooser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AReadFileChooser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AReadGeometryChooser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ASaveCanvasDialog.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AStartupWindow.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ATabbedPaneUI.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ATextField.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ATreeCellRenderer.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/ATreeExpansionListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AWindowControl.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AXMLFileChooser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/gui/AXMLGeometryChooser.java delete mode 100644 graphics/AtlantisJava/src/atlantis/gui/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/A3DBoxGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/A3DBoxInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AClockGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AClockInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AEnterExitListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/AFishEyeChangeListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AFishEyeGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AFishEyeInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AInteractionGroup.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/AInteractionsConfigReader.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AInteractionsManager.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ALineSegment.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/AModifier.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AMouseDragListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AMousePressListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/ANZMRGroup.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/ANZMRInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AParallelogramSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/APickGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/APickInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/APopupListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARectangleSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARectangleVPSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARectangleYXSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARotatedRectangleSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARubberbandGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ARubberbandYXGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASkewGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASkewInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASleepMouseDragListener.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASquareSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AVPSelectionGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AWindowInfoInteraction.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AXSkewSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AXSliceSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AYSkewSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AYSliceSelection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AZMRGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/interactions/AZMRInteraction.java delete mode 100644 graphics/AtlantisJava/src/atlantis/interactions/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/list/AColorIcon.java delete mode 100755 graphics/AtlantisJava/src/atlantis/list/AList.java delete mode 100755 graphics/AtlantisJava/src/atlantis/list/AListManager.java delete mode 100755 graphics/AtlantisJava/src/atlantis/list/AListProcessor.java delete mode 100644 graphics/AtlantisJava/src/atlantis/list/package.html delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimInterpolate.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimSegment.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimSetProjection.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimThread.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimVar.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANAnimationManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANCacheToken.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANColor.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANFrameManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANGlobalFlags.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANLinearProjection.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANLinearTransition.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANObjectGenerator.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickDrawer.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickHandler.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickHandlerSimple.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickHelper.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickResult.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANPickResultPrinter.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANProjection.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANProjection3D.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANProjectionPhysics.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANProjectionYX.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANRenderHints.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANRenderer.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANRendererBasic.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANSelectionList.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANTerribleHacks.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/ANTestWindow.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/ANObject.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/ANObjectList.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/ANObjectTestAxes.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/ANObjectVL.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataCell.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataJet.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectPointing.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectTracks.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectBeamLine.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomCalo.java delete mode 100644 graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomMuon.java delete mode 100755 graphics/AtlantisJava/src/atlantis/output/AExceptionHandler.java delete mode 100644 graphics/AtlantisJava/src/atlantis/output/ALogInterface.java delete mode 100755 graphics/AtlantisJava/src/atlantis/output/AOutput.java delete mode 100644 graphics/AtlantisJava/src/atlantis/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AAbstractParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AColorParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/ACommand.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/ACommandProcessor.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/ACutParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AEnumeratorParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/ALinkParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AListIntegerParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/ANumberParameter.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/APar.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AParameter.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterChangeListener.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterConfigReader.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterData.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterState.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterSuperGroup.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/AParameterUtilities.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AParametersGroup.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AStatusGroupParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AStatusParameter.java delete mode 100755 graphics/AtlantisJava/src/atlantis/parameters/AStatusRootParameter.java delete mode 100644 graphics/AtlantisJava/src/atlantis/parameters/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjection.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjection2D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjection3D.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjection3DBox.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionEventInfo.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionFR.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionFZ.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionInfo.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionLegoPlot.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionN3D.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionNGE.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionNPhysics.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionNYX.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionPhi.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionRZ.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/AProjectionTrackResidual.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionVP.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionXZ.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionYX.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionYZ.java delete mode 100755 graphics/AtlantisJava/src/atlantis/projection/AProjectionsManager.java delete mode 100644 graphics/AtlantisJava/src/atlantis/projection/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/A3Vector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/A4Vector.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AAtlantisException.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AClipPolygon.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/ACommandHistory.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AHashMap.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/AIdDictionary.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/AIdField.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AIdHelper.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/AIdRange.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AIntHashtable.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/ALogger.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/ALoggerFactory.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AMath.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/ANewIdHelper.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/APoint.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/APolygon.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AUtilities.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/AVector.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/package.html delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AArrayParser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AFloatArrayParser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AIntArrayParser.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AStringArrayParser.java delete mode 100644 graphics/AtlantisJava/src/atlantis/utils/xml/AXMLEntityResolver.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AXMLErrorHandler.java delete mode 100755 graphics/AtlantisJava/src/atlantis/utils/xml/AXMLUtils.java delete mode 100644 graphics/AtlantisJava/src/overview.html delete mode 100644 graphics/AtlantisJava/test/events/emptyEvent.xml delete mode 100644 graphics/AtlantisJava/test/events/muonCollections.xml delete mode 100644 graphics/AtlantisJava/test/events/muonCollections2.xml delete mode 100644 graphics/AtlantisJava/test/events/rvxEvent.xml delete mode 100644 graphics/AtlantisJava/test/events/rvxInconsistentEvent.xml delete mode 100644 graphics/AtlantisJava/test/src/atlantis/AtlantisHeadlessTestCase.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/HeadlessTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/InconsistentEventTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/NoTracksElementTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/canvas/AScaleBorderTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/canvas/AScaleTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/canvas/AWindowTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/data/AHelixTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/data/AOldHelixTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/event/AEventInfoTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/graphics/ACoordTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/list/AListManagerTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/parameters/AAbstractParameterTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/parameters/AParameterDataTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/utils/A3VectorTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/utils/A4VectorTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/utils/AIdRangeTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/utils/AMathTest.java delete mode 100644 graphics/AtlantisJava/test/src/atlantis/utils/ANewIdHelperTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/AAssert.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/AtlantisGUIFixture.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/AtlantisGuiTestCase.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/EnumeratorParameterTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/EventSourceToolBarTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/InteractionToolBarTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/LoadEventFailureTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/LoadEventTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/LoadEventWithInvalidRecVertexDataTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/LoadEventWithValidRecVertexDataTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/LoadEventsManyTimesTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsEmptyTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/OverlayTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/ProjectionsTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/ReadNextAndPreviousEventTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/StartAndExitTest.java delete mode 100644 graphics/AtlantisJava/test/src/guitest/TabsTest.java delete mode 100644 graphics/AtlantisJava/test/src/testutils/AtlantisInit.java delete mode 100644 graphics/AtlantisJava/test/src/testutils/TeeOutputStream.java delete mode 100644 graphics/AtlantisJava/test/src/testutils/TestUtils.java diff --git a/graphics/AtlantisJava/CMakeLists.txt b/graphics/AtlantisJava/CMakeLists.txt deleted file mode 100644 index 7d9ae4dd600..00000000000 --- a/graphics/AtlantisJava/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -################################################################################ -# Package: AtlantisJava -################################################################################ - -# Declare the package name: -atlas_subdir( AtlantisJava ) - -# External dependencies: -find_package( Java ) - -# Install files from the package: -atlas_install_joboptions( share/InteractiveServer.py ) -atlas_install_scripts( share/atlantis share/atlantis_online ) -atlas_install_generic( lib/*.jar - DESTINATION "share/AtlantisJava/lib" - EXECUTABLE ) -atlas_install_generic( img/*.gif img/*.png img/*.jpg - DESTINATION "share/AtlantisJava/img" - EXECUTABLE ) -atlas_install_generic( configuration/*.xml configuration/*.csv configuration/PSProlog.txt - DESTINATION "share/AtlantisJava/configuration" - EXECUTABLE ) -atlas_install_generic( events/event.dtd events/*.zip - DESTINATION "share/AtlantisJava/events" - EXECUTABLE ) -atlas_install_generic( geometry/*.xml - DESTINATION "share/AtlantisJava/geometry" - EXECUTABLE ) -atlas_install_generic( help/help.jar help/online.xml help/*.png - DESTINATION "share/AtlantisJava/help" - EXECUTABLE ) diff --git a/graphics/AtlantisJava/ant/build.xml b/graphics/AtlantisJava/ant/build.xml deleted file mode 100755 index 1172e921def..00000000000 --- a/graphics/AtlantisJava/ant/build.xml +++ /dev/null @@ -1,469 +0,0 @@ -<?xml version="1.0"?> - -<!-- Main Ant build file for Atlantis --> - -<!-- basedir attribute to be adjusted - target build directory - - - - - --> -<project name="Atlantis" default="usage" basedir=".."> - <!-- begin properties - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- read in overriden properties from ant.properties file - - - - - --> - <property file="ant.properties"/> - <property name="appName" value="Atlantis"/> - - <!-- Use Java 1.6. - Note that this controls the source code accepted and bytecode generated but - does NOT ensure that the correct libraries are available so in principle you - could still build code that requires different libraries to run. - This was added when we needed to enforve Java 1.5 but 1.6 was already - the most commonly installed version. --> - <property name="ant.build.javac.source" value="1.6"/> - - <!-- webstart codebase with appropriate default --> - <property name="codebase" value="http://www.cern.ch/atlantis/webstart"/> - - <!-- password for webstart certificate - certificate is created in - webstart target, used to sign *.jar files and erased afterwards --> - <property name="password" value="webstart_certificate_atlantis_password"/> - - <!-- list of "specific system configurations" in configurations/config-*.xml --> - <!-- NOT including MINERVA since this needs a slightly different JNLP file to load events from a URL --> - <property name="configs" - value="acr-general,acr-public,l1calo-acr,lar-acr,lar-publications,mbts-acr,mdt-acr,pixel-acr,pixel-publications,sct-acr,sct-publications,tgc-acr,tile-acr,tile-publications,trt-acr,trt-publications"/> - - <!-- timeout in milliseconds for JUnit tests, applies to each forked JVM instance --> - <property name="test.timeout" value="300000"/> - - <!-- directories - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <property name="src.src" value="src"/> - <property name="lib.src" value="lib"/> - <property name="test.src" value="test/src"/> - <property name="test.events" value="test/events"/> - <!-- runtime directories and files --> - <property name="conf" value="configuration"/> - <property name="events" value="events"/> - <property name="geom" value="geometry"/> - <property name="help" value="help"/> - <property name="img" value="img"/> - <property name="share" value="share"/> - - <property name="conf.src" value="${conf}"/> - <property name="events.src" value="${events}"/> - <property name="geom.src" value="${geom}"/> - <property name="help.src" value="${help}"/> - <property name="img.src" value="${img}"/> - <property name="share.src" value="${share}"/> - - <property name="conf.run" value="${targetDir}/${conf}"/> - <property name="events.run" value="${targetDir}/${events}"/> - <property name="geom.run" value="${targetDir}/${geom}"/> - <property name="help.run" value="${targetDir}/${help}"/> - <property name="img.run" value="${targetDir}/${img}"/> - <property name="share.run" value="${targetDir}/${share}"/> - - <property name="class.run" value="${targetDir}/classes"/> - <property name="lib.run" value="${targetDir}/lib"/> - <property name="test.run" value="${targetDir}/classes-test"/> - - <!-- directories for test libraries and output --> - <property name="lib.test" value="${targetDir}/lib/test"/> - <property name="report.test" value="${targetDir}/report"/> - - <!-- Atlantis - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <property name="atlantis.jar" value="${targetDir}/atlantis.jar"/> - <property name="atlantis.main.class" value="atlantis.Atlantis"/> - - <!-- Classpath for manifest in Jar file --> - <path id="classpath.mf"> - <fileset dir="${lib.run}"> - <include name="**/*.jar"/> - </fileset> - <fileset dir="${help.run}"> - <include name="**/*.jar"/> - </fileset> - </path> - - <!-- "foreach" task needed to generate specific system configs, provided by ant-contrib --> - <taskdef resource="net/sf/antcontrib/antcontrib.properties"> - <classpath> - <pathelement location="${lib.src}/build/ant-contrib-1.0b3.jar"/> - </classpath> - </taskdef> - - - <!-- =============================================================== --> - - <!-- targets begin - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <!-- preinit target - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="preinit" description="Test if targetDir argument is set"> - <fail unless="targetDir"> - targetDir variable must be set - try: ant usage - example: ant -DtargetDir="test" all - </fail> - <echo>Atlantis build will be made into ${targetDir} directory</echo> - </target> - - - <!-- init target - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="init" depends="preinit" - description="Makes required directories, copies libs"> - <mkdir dir="${lib.run}"/> - <!-- For runtime libraries use include element to take only Jar files from lib directory, - not build subdirectory --> - <copy todir="${lib.run}"> - <fileset dir="${lib.src}"> - <include name="*.jar"/> - </fileset> - </copy> - - <mkdir dir="${conf.run}"/> - <copy todir="${conf.run}"> - <fileset dir="${conf.src}"/> - </copy> - - <mkdir dir="${events.run}"/> - <copy todir="${events.run}"> - <fileset dir="${events.src}"/> - </copy> - - <mkdir dir="${geom.run}"/> - <copy todir="${geom.run}"> - <fileset dir="${geom.src}"/> - </copy> - - <mkdir dir="${help.run}"/> - <copy todir="${help.run}"> - <fileset dir="${help.src}"> - <include name="help.jar"/> - </fileset> - </copy> - - <mkdir dir="${img.run}"/> - <copy todir="${img.run}"> - <fileset dir="${img.src}"/> - </copy> - - <mkdir dir="${share.run}"/> - <copy todir="${share.run}"> - <fileset dir="${share.src}"/> - </copy> - - <mkdir dir="${class.run}"/> - - </target> - - - - <!-- compile target --> - <target name="compile" depends="init" - description="Compiles all source files"> - - <javac includeAntRuntime="false" srcdir="${src.src}" destdir="${class.run}" deprecation="on" verbose="no"> - <!-- <compilerarg value="-Xlint:unchecked"/> --> - <include name="**/*.java"/> - <classpath> - <fileset dir="${lib.run}"> - <include name="**/*.jar"/> - </fileset> - </classpath> - </javac> - </target> - - - <!-- all target - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="all" depends="jar, clean" - description="Copy runtime files, build and clean up"/> - - <!-- jar-atlantis target - - - - - - - - - - - - - - - - - - - - - - --> - <!-- Keep for compatibility with existing CMT requirements file --> - <target name="jar-atlantis" depends="all" - description="Create jar file of Atlantis"> - </target> - - <!-- jar target - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="jar" depends="compile" - description="Create all jar files for deployment"> - <manifestclasspath property="jar.classpath" jarfile="${atlantis.jar}"> - <classpath refid="classpath.mf"/> - </manifestclasspath> - - <!-- jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <jar destfile="${atlantis.jar}"> - <fileset dir="${class.run}" /> - <fileset dir="${targetDir}"> - <exclude name="classes/*"/> - <exclude name="lib/*"/> - <exclude name="help/*"/> - <include name="*/*"/> - </fileset> - <manifest> - <attribute name="Built-By" value="${user.name}"/> - <attribute name="Main-Class" value="${atlantis.main.class}"/> - <attribute name="Class-Path" value="${jar.classpath}"/> - <attribute name="Implementation-Title" value="Atlantis"/> - </manifest> - </jar> - </target> - - <!-- webstartcommon target - - - - - - - - - - - - - - - - - - - - --> - <target name="webstartcommon" depends="compile"> - <manifestclasspath property="jar.classpath" jarfile="${atlantis.jar}"> - <classpath refid="classpath.mf"/> - </manifestclasspath> - - <jar destfile="${atlantis.jar}"> - <fileset dir="${class.run}" /> - - <fileset dir="${targetDir}"> - <exclude name="classes/*"/> - <exclude name="lib/*"/> - <exclude name="help/*"/> - <include name="*/*"/> - </fileset> - - <manifest> - <attribute name="Built-By" value="${user.name}"/> - <attribute name="Main-Class" value="${atlantis.main.class}"/> - <attribute name="Class-Path" value="${jar.classpath}"/> - <attribute name="Implementation-Title" value="Atlantis"/> - </manifest> - </jar> - - <!-- clean up, leave only lib/*.jar, help/*.jar, atlantis.jar --> - <delete dir="${conf.run}"/> - <delete dir="${events.run}"/> - <delete dir="${geom.run}"/> - <delete dir="${img.run}"/> - <delete dir="${share.run}"/> - - <antcall target="clean"/> - <antcall target="webstartjarsigner"/> - </target> - - - <!-- webstart - distribution via webstart (lib/*.jar, help/*.jar and - atlantis.jar (includes all data files) --> - <target name="webstart" depends="webstartcommon" - description="atlantis distribution for Java WebStart"> - - <!-- copy webstart .jnlp files --> - <copy file="${share.src}/atlantis.jnlp" todir="${targetDir}"> - <filterset> - <filter token="CODEBASE" value="${codebase}"/> - </filterset> - </copy> - - </target> - - - <!-- webstart - MINERVA version --> - <target name="webstart-minerva" depends="compile" - description="Atlantis MINERVA distribution for Java WebStart"> - - <!-- copy webstart .jnlp files --> - <copy file="${share.src}/MINERVA.jnlp" todir="${targetDir}"> - <filterset> - <filter token="CODEBASE" value="${codebase}"/> - </filterset> - </copy> - - </target> - - - <target name="webstart-config"> - <!-- copy webstart .jnlp files --> - <copy file="${share.src}/specificconfig.jnlp" tofile="${targetDir}/${config}.jnlp"> - <filterset> - <filter token="CODEBASE" value="${codebase}"/> - <filter token="HREF" value="${config}.jnlp"/> - <filter token="CONFIG" value="config-${config}.xml"/> - </filterset> - </copy> - </target> - - - <!-- webstart including basic atlantis.jnlp and "specific system configurations" --> - <target name="webstart-all" depends="webstart,webstart-specificconfigs,webstart-minerva" - description="Atlantis for Java Webstart including basic atlantis.jnlp and specific system configurations"/> - - - <target name="webstart-specificconfigs"> - <foreach param="config" list="${configs}" target="webstart-config"/> - </target> - - - <!-- webstartjarsigner target - - - - - - - - - - - - - - - - - - - --> - <target name="webstartjarsigner" description="Sign all jar files"> - <delete file="${targetDir}/keystore"/> - <exec executable="${java.home}/bin/keytool"> - <arg line="-genkey -dname 'cn=Atlantis team' -alias Atlantis - -keypass ${password} -keystore ${targetDir}/keystore - -storepass ${password} -validity 180"/> - </exec> - <signjar alias="Atlantis" - keystore="${targetDir}/keystore" - keypass="${password}" - storepass="${password}"> - - <fileset file="${lib.run}/*.jar" /> - <fileset file="${help.run}/*.jar"/> - <fileset file="${atlantis.jar}"/> - </signjar> - <delete file="${targetDir}/keystore"/> - </target> - - - - <!-- updateconfigurations target - - - - - - - - - - - - - - - - - - --> - <!-- update special configurations - jython script performs update of - all special / customised configurations shipped with atlantis and then - runs Atlantis with each configuration file --> - <target name="updateconfigs" depends="jar" - description="Update / synchronise customised configuration files"> - <echo>Requires jython available in PATH, otherwise fails.</echo> - - <!-- arg to exec - arguments to specify atlantis distribution direct. - and where the configuration files for updating are located --> - <!-- exec for unix, mac --> - <exec executable="jython" osfamily="unix" failonerror="true"> - <arg line="share/configupdater.py --atlantis ${targetDir} - --update ${conf.src}"/> - </exec> - <!-- exec for windows --> - <exec executable="cmd" osfamily="windows" failonerror="true"> - <arg value="/c"/> - <arg value="jython.bat"/> - <arg value="share\configupdater.py"/> - <arg value="--atlantis"/> - <arg line="${targetDir}"/> - <arg line="--update"/> - <arg line="${conf.src}"/> - </exec> - - <echo>Deleting build directory ${targetDir}, calling delete ...</echo> - <delete dir="${targetDir}"/> - </target> - - <!-- javadoc target - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="javadoc" description="Make Javadoc documentation"> - <mkdir dir="${targetDir}" /> - - <javadoc packagenames="atlantis.*" - sourcepath="${src.src}" - destdir="${targetDir}" - overview="${src.src}/overview.html" - doctitle="Atlantis event display for ATLAS" - > - <classpath> - <fileset dir="${lib.src}"> - <include name="**/*.jar"/> - </fileset> - </classpath> - </javadoc> - </target> - - <!-- clean target - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="clean" description="Erase *.class generated files"> - <delete dir="${class.run}"/> - </target> - - <target name="test" depends="unit-tests,gui-tests" description="Run all tests"> - <!-- If testcase is set, specified test is run here. --> - <junit printsummary="yes" haltonerror="no" haltonfailure="no" failureProperty="test.failed" errorProperty="test.failed" - fork="yes" timeout="${test.timeout}"> - <sysproperty key="atlantis.test.events" file="${test.events}"/> - <formatter type="xml"/> - <test name="${testcase}" toDir="${report.test}" if="testcase"/> - <classpath refid="classpath.test"/> - </junit> - - <mkdir dir="${report.test}/html"/> - <junitreport todir="${report.test}"> - <fileset dir="${report.test}"> - <include name="TEST-*.xml"/> - </fileset> - <report todir="${report.test}/html"/> - </junitreport> - - <fail message="Failed JUnit test(s)" if="test.failed"/> - </target> - - <!-- Has to continue on failure or error so report target can run. --> - <!-- Not sure why need haltonerror="no" even if failures occur but no errors --> - <target name="unit-tests" depends="compile-tests,jar" description="Run unit tests"> - <mkdir dir="${report.test}"/> - <junit printsummary="yes" haltonerror="no" haltonfailure="no" failureProperty="test.failed" errorProperty="test.failed" - fork="yes" timeout="${test.timeout}"> - <sysproperty key="atlantis.test.events" file="${test.events}"/> - <formatter type="xml"/> - <!-- If testcase is set, specified test will be run in "test" target. Otherwise run all of them. --> - <batchtest toDir="${report.test}" unless="testcase"> - <fileset dir="${test.run}" includes="atlantis/**/*Test.class"/> - </batchtest> - <classpath refid="classpath.test"/> - </junit> - </target> - - <!-- Has to continue on failure or error so report target can run. --> - <!-- Not sure why need haltonerror="no" even if failures occur but no errors --> - <target name="gui-tests" depends="compile-tests,jar" description="Run GUI tests"> - <mkdir dir="${report.test}"/> - <junit printsummary="yes" haltonerror="no" haltonfailure="no" failureProperty="test.failed" errorProperty="test.failed" - fork="yes" timeout="${test.timeout}"> - <sysproperty key="atlantis.test.events" file="${test.events}"/> - <formatter type="xml"/> - <!-- If testcase is set, specified test will be run in "test" target. Otherwise run all of them. --> - <batchtest toDir="${report.test}" unless="testcase"> - <fileset dir="${test.run}" includes="guitest/**/*Test.class"> - </fileset> - </batchtest> - <classpath refid="classpath.test"/> - </junit> - </target> - - <!-- compile-tests target: compile JUnit tests --> - <target name="compile-tests" depends="compile" - description="Compiles source files for all tests"> - <mkdir dir="${lib.run}/test"/> - <copy todir="${lib.run}/test"> - <fileset dir="${lib.src}/test"> - <include name="*.jar"/> - </fileset> - </copy> - <mkdir dir="${test.run}"/> - <javac includeAntRuntime="false" srcdir="${test.src}" destdir="${test.run}" deprecation="on" verbose="no"> - <include name="**/*.java"/> - <classpath> - <fileset dir="${lib.run}"> - <include name="**/*.jar"/> - </fileset> - <fileset dir="${lib.test}"> - <include name="**/*.jar"/> - </fileset> - <pathelement path="${class.run}"/> - </classpath> - </javac> - <path id="classpath.test"> - <fileset dir="${lib.run}"> - <include name="**/*.jar"/> - </fileset> - <fileset dir="${lib.test}"> - <include name="**/*.jar"/> - </fileset> - <pathelement path="${targetDir}/atlantis.jar"/> - <pathelement path="${test.run}"/> - </path> - </target> - - <!-- usage target - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="usage" description="Prints usage hint"> - <echo level="info" message="Usage:"/> - <echo>targetDir - directory to build atlantis distribution in</echo> - <echo>ant -DtargetDir=[target directory] [all|jar|javadoc|test|report|updateconfigs]</echo> - <echo>and -DtargetDir=[target directory] -Dtestcase=[test-case class] test</echo> - <echo>ant -DtargetDir=[target directory] [-Dcodebase="Webstart codebase URL"] [webstart|webstart-specificconfigs|webstart-all]</echo> - </target> - - <!-- help target - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <target name="help" depends="usage" description="Prints usage hint"/> - -</project> diff --git a/graphics/AtlantisJava/configuration/PSProlog.txt b/graphics/AtlantisJava/configuration/PSProlog.txt deleted file mode 100755 index ca7483a2aeb..00000000000 --- a/graphics/AtlantisJava/configuration/PSProlog.txt +++ /dev/null @@ -1,156 +0,0 @@ -100 dict dup begin - -% Author: Charles Loomis - -% Redefinitions which save some space in the output file. These are also -% the same as the PDF operators. -/q {gsave} def -/Q {grestore} def - -/n {newpath} def -/m {moveto} def -/l {lineto} def -/c {curveto} def -/h {closepath} def - -/re {4 -2 roll moveto - dup 0 exch rlineto exch 0 rlineto - neg 0 exch rlineto closepath} def - -/f {fill} def -/f* {eofill} def -/F {gsave vg&FC fill grestore} def -/F* {gsave vg&FC eofill grestore} def - -/s {closepath stroke} def -/S {stroke} def - -/b {closepath gsave vg&FC fill grestore - gsave stroke grestore newpath} def -/B {gsave vg&FC fill grestore gsave stroke grestore newpath} def -/b* {closepath gsave vg&FC eofill grestore - gsave stroke grestore newpath} def -/B* {gsave vg&FC eofill grestore gsave stroke grestore newpath} def - -/g {1 array astore /vg&fcolor exch def} def -/G {setgray} def -/k {4 array astore /vg&fcolor exch def} def -/K {setcmykcolor} def -/rg {3 array astore /vg&fcolor exch def} def -/RG {setrgbcolor} def - -% Initialize the fill color. -0 0 0 rg - -/vg&FC {mark vg&fcolor aload pop - counttomark 1 eq {G} if - counttomark 3 eq {RG} if - counttomark 4 eq {K} if - cleartomark } def - -/vg&DFC {/vg&fcolor exch def} def - -/vg&C {mark exch aload pop - counttomark 1 eq {G} if - counttomark 3 eq {RG} if - counttomark 4 eq {K} if - cleartomark } def - -/w {setlinewidth} def -/j {setlinejoin} def -/J {setlinecap} def -/M {setmiterlimit} def -/d {setdash} def -/i {setflat} def - -/W {clip} def -/W* {eoclip} def - -% Setup the default graphics state. -% (black; 1 pt. linewidth; miter join; butt-ends; solid) -/defaultGraphicsState {0 g 1 w 0 j 0 J [] 0 d} def - -% Emulation of the rectangle operators for PostScript implementations -% which do not implement all Level 2 features. This is an INCOMPLETE -% emulation; only the "x y width height rect..." form is emulated. -/*rf {gsave newpath re fill grestore} def -/*rs {gsave newpath re stroke grestore} def -/*rc {newpath re clip} def -/rf /rectfill where {pop /rectfill}{/*rf} ifelse load def -/rs /rectstroke where {pop /rectstroke}{/*rs} ifelse load def -/rc /rectclip where {pop /rectclip}{/*rc} ifelse load def - -% Emulation of the selectfont operator. This includes a 20% increase in -% the fontsize which is necessary to get sizes similar to the Java fonts. -/*sf {exch findfont exch - dup type /arraytype eq {makefont}{scalefont} ifelse setfont} bind def -/sf /selectfont where {pop {1.2 mul selectfont}}{{1.2 mul *sf}} ifelse def - -% Initialize variables for safety. -/delta 0 def -/xv 0 def /yv 0 def /width 0 def /height 0 def - -% Initialize to portrait A4 page. -/pw 595 def /ph 842 def /po true def /ftp false def - -% Initialize margins to 20 points. -/ml 20 def /mr 20 def /mt 20 def /mb 20 def - -% set page size (usage: <page width><page height> setpagesize) -/setpagesize {/ph exch def /pw exch def} def - -% set page orientation (usage: portrait or landscape) -/portrait {/po true def} def -/landscape {/po false def} def - -% force natural size for image (usage: naturalsize) -/naturalsize {/ftp false def} def - -% resize image to fill page (usage: fittopage) -/fittopage {/ftp true def} def - -% set margins of the page (usage: <left><bottom><top><right> setmargins) -/setmargins {/mr exch def /mt exch def /mb exch def /ml exch def} def - -% set the graphic's size (usage: <width><height> setsize) -/setsize {/gh exch def /gw exch def} def - -% set the graphic's origin (usage: <x0><y0> setorigin) -/setorigin {/gy exch def /gx exch def} def - -% calculate image center -/imagecenter {pw ml sub mr sub 2 div ml add - ph mt sub mb sub 2 div mb add} def - -% calculate the necessary scaling -/imagescale {po {gw}{gh} ifelse pw ml sub mr sub div - po {gh}{gw} ifelse ph mt sub mb sub div - 2 copy lt {exch} if pop - ftp not {1 2 copy lt {exch} if pop} if - 1 exch div /sfactor exch def - /gw gw sfactor mul def /gh gh sfactor mul def} def - -% calculate image origin -/imageorigin {pw ml sub mr sub 2 div ml add - po {gw}{gh} ifelse 2 div sub - ph mt sub mb sub 2 div mb add - po {gh}{gw} ifelse 2 div po {add}{sub} ifelse} def - -% calculate the clipping origin -/cliporigin {pw ml sub mr sub 2 div ml add - po {gw}{gh} ifelse 2 div sub floor - ph mt sub mb sub 2 div mb add - po {gh}{gw} ifelse 2 div sub floor} def - -% Set the clipping region to the bounding box. -/cliptobounds {cliporigin po {gw}{gh} ifelse 1 add - po {gh}{gw} ifelse 1 add rc} def - -% set the base transformation matrix (usage: setbasematrix) -/setbasematrix {imageorigin translate - po {0}{90} ifelse rotate - sfactor sfactor neg scale - /defaultmatrix matrix currentmatrix def} def - - - diff --git a/graphics/AtlantisJava/configuration/colormap.xml b/graphics/AtlantisJava/configuration/colormap.xml deleted file mode 100755 index 1160b07c23b..00000000000 --- a/graphics/AtlantisJava/configuration/colormap.xml +++ /dev/null @@ -1,369 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE colormap [ - <!ELEMENT colormap (Mapping*)> - <!ATTLIST colormap - numMaps CDATA #REQUIRED - numColors CDATA #REQUIRED> - <!ELEMENT Mapping EMPTY> - <!ATTLIST Mapping - map CDATA #REQUIRED - index CDATA #REQUIRED - r CDATA #REQUIRED - g CDATA #REQUIRED - b CDATA #REQUIRED> -]> - -<colormap numMaps="9" numColors="29" > -<!-- map 0 - Default(1) --> - <!-- white --> - <Mapping map="0" index="0" r="176" g="176" b="176"/> - <!-- geometry --> - <Mapping map="0" index="1" r="58" g="58" b="58"/> - <Mapping map="0" index="2" r="32" g="32" b="32"/> - <Mapping map="0" index="3" r="205" g="92" b="92"/> - <Mapping map="0" index="4" r="55" g="101" b="140"/> - <Mapping map="0" index="5" r="130" g="200" b="130"/> - <Mapping map="0" index="6" r="70" g="130" b="180"/> - <Mapping map="0" index="7" r="200" g="200" b="200"/> - <!-- background --> - <Mapping map="0" index="8" r="255" g="255" b="255"/> - <!-- frames --> - <Mapping map="0" index="9" r="189" g="34" b="50"/> - <Mapping map="0" index="10" r="180" g="180" b="81"/> - <Mapping map="0" index="11" r="33" g="182" b="92"/> - <Mapping map="0" index="12" r="89" g="206" b="223"/> - <Mapping map="0" index="13" r="140" g="40" b="140"/> - <!-- grey --> - <Mapping map="0" index="14" r="153" g="153" b="153"/> - <!-- cells --> - <Mapping map="0" index="15" r="125" g="0" b="0"/> - <Mapping map="0" index="16" r="255" g="255" b="128"/> - <Mapping map="0" index="17" r="0" g="125" b="0"/> - <Mapping map="0" index="18" r="181" g="229" b="251"/> - <Mapping map="0" index="19" r="255" g="128" b="255"/> - <!-- red --> - <Mapping map="0" index="20" r="255" g="0" b="0"/> - <!-- green --> - <Mapping map="0" index="21" r="0" g="255" b="0"/> - <!-- blue --> - <Mapping map="0" index="22" r="0" g="0" b="255"/> - <!-- yellow --> - <Mapping map="0" index="23" r="255" g="255" b="0"/> - <!-- magenta --> - <Mapping map="0" index="24" r="255" g="0" b="255"/> - <!-- cyan --> - <Mapping map="0" index="25" r="0" g="255" b="255"/> - <!-- black --> - <Mapping map="0" index="26" r="0" g="0" b="0"/> - <!-- orange --> - <Mapping map="0" index="27" r="255" g="115" b="0"/> - <!-- cornflower blue --> - <Mapping map="0" index="28" r="135" g="206" b="250"/> -<!-- map 1 - Default(2) --> - <!-- white --> - <Mapping map="1" index="0" r="176" g="176" b="176"/> - <!-- geometry --> - <Mapping map="1" index="1" r="58" g="58" b="58"/> - <Mapping map="1" index="2" r="32" g="32" b="32"/> - <Mapping map="1" index="3" r="254" g="102" b="0"/> - <Mapping map="1" index="4" r="0" g="24" b="71"/> - <Mapping map="1" index="5" r="130" g="200" b="130"/> - <Mapping map="1" index="6" r="0" g="51" b="153"/> - <Mapping map="1" index="7" r="200" g="200" b="200"/> - <!-- background --> - <Mapping map="1" index="8" r="255" g="255" b="255"/> - <!-- frames --> - <Mapping map="1" index="9" r="189" g="34" b="50"/> - <Mapping map="1" index="10" r="180" g="180" b="81"/> - <Mapping map="1" index="11" r="33" g="182" b="92"/> - <Mapping map="1" index="12" r="89" g="206" b="223"/> - <Mapping map="1" index="13" r="140" g="40" b="140"/> - <!-- grey --> - <Mapping map="1" index="14" r="153" g="153" b="153"/> - <!-- cells --> - <Mapping map="1" index="15" r="185" g="0" b="0"/> - <Mapping map="1" index="16" r="255" g="255" b="128"/> - <Mapping map="1" index="17" r="0" g="125" b="0"/> - <Mapping map="1" index="18" r="181" g="229" b="251"/> - <Mapping map="1" index="19" r="255" g="128" b="255"/> - <!-- red --> - <Mapping map="1" index="20" r="255" g="0" b="0"/> - <!-- green --> - <Mapping map="1" index="21" r="0" g="255" b="0"/> - <!-- blue --> - <Mapping map="1" index="22" r="0" g="0" b="255"/> - <!-- yellow --> - <Mapping map="1" index="23" r="255" g="255" b="0"/> - <!-- magenta --> - <Mapping map="1" index="24" r="255" g="0" b="255"/> - <!-- cyan --> - <Mapping map="1" index="25" r="0" g="255" b="255"/> - <!-- black --> - <Mapping map="1" index="26" r="0" g="0" b="0"/> - <!-- orange --> - <Mapping map="1" index="27" r="255" g="170" b="0"/> - <!-- cornflower blue --> - <Mapping map="1" index="28" r="0" g="102" b="255"/> -<!-- map 2 - Default(M4+M5) --> - <!-- white --> - <Mapping map="2" index="0" r="255" g="255" b="255"/> - <!-- geometry --> - <Mapping map="2" index="1" r="40" g="0" b="0"/> - <Mapping map="2" index="2" r="0" g="35" b="0"/> - <Mapping map="2" index="3" r="132" g="39" b="32"/> - <Mapping map="2" index="4" r="138" g="138" b="68"/> - <Mapping map="2" index="5" r="98" g="134" b="122"/> - <Mapping map="2" index="6" r="78" g="139" b="170"/> - <Mapping map="2" index="7" r="97" g="65" b="97"/> - <!-- background --> - <Mapping map="2" index="8" r="44" g="47" b="50"/> - <!-- frames --> - <Mapping map="2" index="9" r="189" g="34" b="50"/> - <Mapping map="2" index="10" r="180" g="180" b="81"/> - <Mapping map="2" index="11" r="33" g="182" b="92"/> - <Mapping map="2" index="12" r="89" g="206" b="223"/> - <Mapping map="2" index="13" r="140" g="40" b="140"/> - <!-- grey --> - <Mapping map="2" index="14" r="153" g="153" b="153"/> - <!-- cells --> - <Mapping map="2" index="15" r="245" g="135" b="138"/> - <Mapping map="2" index="16" r="255" g="255" b="128"/> - <Mapping map="2" index="17" r="123" g="212" b="194"/> - <Mapping map="2" index="18" r="181" g="229" b="251"/> - <Mapping map="2" index="19" r="255" g="128" b="255"/> - <!-- red --> - <Mapping map="2" index="20" r="255" g="0" b="0"/> - <!-- green --> - <Mapping map="2" index="21" r="0" g="255" b="0"/> - <!-- blue --> - <Mapping map="2" index="22" r="0" g="0" b="255"/> - <!-- yellow --> - <Mapping map="2" index="23" r="255" g="255" b="0"/> - <!-- magenta --> - <Mapping map="2" index="24" r="255" g="0" b="255"/> - <!-- cyan --> - <Mapping map="2" index="25" r="0" g="255" b="255"/> - <!-- black --> - <Mapping map="2" index="26" r="0" g="0" b="0"/> - <!-- orange --> - <Mapping map="2" index="27" r="255" g="115" b="0"/> - <!-- cornflower blue --> - <Mapping map="2" index="28" r="102" g="128" b="255"/> -<!-- map 3 - Gray detector --> - <!-- white --> - <Mapping map="3" index="0" r="255" g="255" b="255"/> - <!-- geometry --> - <Mapping map="3" index="1" r="0" g="0" b="0"/> - <Mapping map="3" index="2" r="0" g="0" b="0"/> - <Mapping map="3" index="3" r="32" g="32" b="32"/> - <Mapping map="3" index="4" r="80" g="80" b="80"/> - <Mapping map="3" index="5" r="16" g="16" b="16"/> - <Mapping map="3" index="6" r="48" g="48" b="48"/> - <Mapping map="3" index="7" r="64" g="64" b="64"/> - <!-- background --> - <Mapping map="3" index="8" r="112" g="112" b="112"/> - <!-- frames --> - <Mapping map="3" index="9" r="189" g="34" b="50"/> - <Mapping map="3" index="10" r="180" g="180" b="81"/> - <Mapping map="3" index="11" r="33" g="182" b="92"/> - <Mapping map="3" index="12" r="89" g="206" b="223"/> - <Mapping map="3" index="13" r="140" g="40" b="140"/> - <!-- grey --> - <Mapping map="3" index="14" r="153" g="153" b="153"/> - <!-- cells --> - <Mapping map="3" index="15" r="245" g="135" b="138"/> - <Mapping map="3" index="16" r="255" g="255" b="128"/> - <Mapping map="3" index="17" r="123" g="212" b="194"/> - <Mapping map="3" index="18" r="181" g="229" b="251"/> - <Mapping map="3" index="19" r="255" g="128" b="255"/> - <!-- red --> - <Mapping map="3" index="20" r="255" g="0" b="0"/> - <!-- green --> - <Mapping map="3" index="21" r="0" g="255" b="0"/> - <!-- blue --> - <Mapping map="3" index="22" r="0" g="0" b="255"/> - <!-- yellow --> - <Mapping map="3" index="23" r="255" g="255" b="0"/> - <!-- magenta --> - <Mapping map="3" index="24" r="255" g="0" b="255"/> - <!-- cyan --> - <Mapping map="3" index="25" r="0" g="255" b="255"/> - <!-- black --> - <Mapping map="3" index="26" r="0" g="0" b="0"/> - <!-- orange --> - <Mapping map="3" index="27" r="255" g="115" b="0"/> - <!-- cornflower blue --> - <Mapping map="3" index="28" r="102" g="128" b="255"/> -<!-- map 4 - Original --> - <!-- white --> - <Mapping map="4" index="0" r="255" g="255" b="255"/> - <!-- geometry --> - <Mapping map="4" index="1" r="0" g="0" b="0"/> - <Mapping map="4" index="2" r="0" g="0" b="0"/> - <Mapping map="4" index="3" r="255" g="0" b="0"/> - <Mapping map="4" index="4" r="0" g="0" b="255"/> - <Mapping map="4" index="5" r="0" g="255" b="0"/> - <Mapping map="4" index="6" r="0" g="0" b="0"/> - <Mapping map="4" index="7" r="255" g="0" b="255"/> - <!-- background --> - <Mapping map="4" index="8" r="0" g="204" b="255"/> - <!-- frames --> - <Mapping map="4" index="9" r="189" g="34" b="50"/> - <Mapping map="4" index="10" r="180" g="180" b="81"/> - <Mapping map="4" index="11" r="33" g="182" b="92"/> - <Mapping map="4" index="12" r="89" g="206" b="223"/> - <Mapping map="4" index="13" r="140" g="40" b="140"/> - <!-- grey --> - <Mapping map="4" index="14" r="153" g="153" b="153"/> - <!-- cells --> - <Mapping map="4" index="15" r="245" g="135" b="138"/> - <Mapping map="4" index="16" r="255" g="255" b="128"/> - <Mapping map="4" index="17" r="123" g="212" b="194"/> - <Mapping map="4" index="18" r="181" g="229" b="251"/> - <Mapping map="4" index="19" r="255" g="128" b="255"/> - <!-- red --> - <Mapping map="4" index="20" r="255" g="0" b="0"/> - <!-- green --> - <Mapping map="4" index="21" r="0" g="255" b="0"/> - <!-- blue --> - <Mapping map="4" index="22" r="0" g="0" b="255"/> - <!-- yellow --> - <Mapping map="4" index="23" r="255" g="255" b="0"/> - <!-- magenta --> - <Mapping map="4" index="24" r="255" g="0" b="255"/> - <!-- cyan --> - <Mapping map="4" index="25" r="0" g="255" b="255"/> - <!-- black --> - <Mapping map="4" index="26" r="0" g="0" b="0"/> - <!-- orange --> - <Mapping map="4" index="27" r="255" g="115" b="0"/> - <!-- cornflower blue --> - <Mapping map="4" index="28" r="102" g="128" b="255"/> -<!-- map 5 - Grey --> - <!-- white --> - <Mapping map="5" index="0" r="255" g="255" b="255"/> - <Mapping map="5" index="1" r="255" g="255" b="255"/> - <Mapping map="5" index="2" r="255" g="255" b="255"/> - <Mapping map="5" index="3" r="255" g="255" b="255"/> - <Mapping map="5" index="4" r="255" g="255" b="255"/> - <Mapping map="5" index="5" r="255" g="255" b="255"/> - <Mapping map="5" index="6" r="255" g="255" b="255"/> - <Mapping map="5" index="7" r="255" g="255" b="255"/> - <!-- grey --> - <Mapping map="5" index="8" r="204" g="204" b="204"/> - <!-- black --> - <Mapping map="5" index="9" r="0" g="0" b="0"/> - <Mapping map="5" index="10" r="0" g="0" b="0"/> - <Mapping map="5" index="11" r="0" g="0" b="0"/> - <Mapping map="5" index="12" r="0" g="0" b="0"/> - <Mapping map="5" index="13" r="0" g="0" b="0"/> - <Mapping map="5" index="14" r="0" g="0" b="0"/> - <Mapping map="5" index="15" r="0" g="0" b="0"/> - <Mapping map="5" index="16" r="0" g="0" b="0"/> - <Mapping map="5" index="17" r="0" g="0" b="0"/> - <Mapping map="5" index="18" r="0" g="0" b="0"/> - <Mapping map="5" index="19" r="0" g="0" b="0"/> - <Mapping map="5" index="20" r="0" g="0" b="0"/> - <Mapping map="5" index="21" r="0" g="0" b="0"/> - <Mapping map="5" index="22" r="0" g="0" b="0"/> - <Mapping map="5" index="23" r="0" g="0" b="0"/> - <Mapping map="5" index="24" r="0" g="0" b="0"/> - <Mapping map="5" index="25" r="0" g="0" b="0"/> - <Mapping map="5" index="26" r="0" g="0" b="0"/> - <Mapping map="5" index="27" r="0" g="0" b="0"/> - <Mapping map="5" index="28" r="0" g="0" b="0"/> -<!-- map 6 - BW --> - <!-- white --> - <Mapping map="6" index="0" r="255" g="255" b="255"/> - <Mapping map="6" index="1" r="255" g="255" b="255"/> - <Mapping map="6" index="2" r="255" g="255" b="255"/> - <Mapping map="6" index="3" r="255" g="255" b="255"/> - <Mapping map="6" index="4" r="255" g="255" b="255"/> - <Mapping map="6" index="5" r="255" g="255" b="255"/> - <Mapping map="6" index="6" r="255" g="255" b="255"/> - <Mapping map="6" index="7" r="255" g="255" b="255"/> - <Mapping map="6" index="8" r="255" g="255" b="255"/> - <!-- black --> - <Mapping map="6" index="9" r="0" g="0" b="0"/> - <Mapping map="6" index="10" r="0" g="0" b="0"/> - <Mapping map="6" index="11" r="0" g="0" b="0"/> - <Mapping map="6" index="12" r="0" g="0" b="0"/> - <Mapping map="6" index="13" r="0" g="0" b="0"/> - <Mapping map="6" index="14" r="0" g="0" b="0"/> - <Mapping map="6" index="15" r="0" g="0" b="0"/> - <Mapping map="6" index="16" r="0" g="0" b="0"/> - <Mapping map="6" index="17" r="0" g="0" b="0"/> - <Mapping map="6" index="18" r="0" g="0" b="0"/> - <Mapping map="6" index="19" r="0" g="0" b="0"/> - <Mapping map="6" index="20" r="0" g="0" b="0"/> - <Mapping map="6" index="21" r="0" g="0" b="0"/> - <Mapping map="6" index="22" r="0" g="0" b="0"/> - <Mapping map="6" index="23" r="0" g="0" b="0"/> - <Mapping map="6" index="24" r="0" g="0" b="0"/> - <Mapping map="6" index="25" r="0" g="0" b="0"/> - <Mapping map="6" index="26" r="0" g="0" b="0"/> - <Mapping map="6" index="27" r="0" g="0" b="0"/> - <Mapping map="6" index="28" r="0" g="0" b="0"/> -<!-- map 7 - HITCOL --> - <Mapping map="7" index="0" r="0" g="0" b="85"/> - <Mapping map="7" index="1" r="0" g="0" b="255"/> - <Mapping map="7" index="2" r="85" g="85" b="170"/> - <Mapping map="7" index="3" r="0" g="170" b="255"/> - <Mapping map="7" index="4" r="0" g="255" b="255"/> - <Mapping map="7" index="5" r="0" g="85" b="85"/> - <Mapping map="7" index="6" r="0" g="85" b="0"/> - <Mapping map="7" index="7" r="0" g="170" b="0"/> - <Mapping map="7" index="8" r="0" g="255" b="0"/> - <Mapping map="7" index="9" r="170" g="255" b="0"/> - <Mapping map="7" index="10" r="255" g="255" b="0"/> - <Mapping map="7" index="11" r="255" g="170" b="0"/> - <Mapping map="7" index="12" r="170" g="85" b="0"/> - <Mapping map="7" index="13" r="255" g="85" b="85"/> - <Mapping map="7" index="14" r="255" g="0" b="0"/> - <Mapping map="7" index="15" r="170" g="0" b="0"/> - <Mapping map="7" index="16" r="85" g="0" b="0"/> - <!-- not used --> - <Mapping map="7" index="17" r="0" g="0" b="0"/> - <Mapping map="7" index="18" r="0" g="0" b="0"/> - <Mapping map="7" index="19" r="0" g="0" b="0"/> - <Mapping map="7" index="20" r="0" g="0" b="0"/> - <Mapping map="7" index="21" r="0" g="0" b="0"/> - <Mapping map="7" index="22" r="0" g="0" b="0"/> - <Mapping map="7" index="23" r="0" g="0" b="0"/> - <Mapping map="7" index="24" r="0" g="0" b="0"/> - <Mapping map="7" index="25" r="0" g="0" b="0"/> - <Mapping map="7" index="26" r="0" g="0" b="0"/> - <Mapping map="7" index="27" r="0" g="0" b="0"/> - <Mapping map="7" index="28" r="0" g="0" b="0"/> -<!-- map 8 - GREY HITCOL --> - <Mapping map="8" index="0" r="255" g="255" b="255"/> - <Mapping map="8" index="1" r="240" g="240" b="240"/> - <Mapping map="8" index="2" r="224" g="224" b="224"/> - <Mapping map="8" index="3" r="208" g="208" b="208"/> - <Mapping map="8" index="4" r="192" g="192" b="192"/> - <Mapping map="8" index="5" r="176" g="176" b="176"/> - <Mapping map="8" index="6" r="160" g="160" b="160"/> - <Mapping map="8" index="7" r="144" g="144" b="144"/> - <Mapping map="8" index="8" r="128" g="128" b="128"/> - <Mapping map="8" index="9" r="112" g="112" b="112"/> - <Mapping map="8" index="10" r="96" g="96" b="96"/> - <Mapping map="8" index="11" r="80" g="80" b="80"/> - <Mapping map="8" index="12" r="64" g="64" b="64"/> - <Mapping map="8" index="13" r="48" g="48" b="48"/> - <Mapping map="8" index="14" r="32" g="32" b="32"/> - <Mapping map="8" index="15" r="16" g="16" b="16"/> - <!-- not used --> - <Mapping map="8" index="16" r="0" g="0" b="0"/> - <Mapping map="8" index="17" r="0" g="0" b="0"/> - <Mapping map="8" index="18" r="0" g="0" b="0"/> - <Mapping map="8" index="19" r="0" g="0" b="0"/> - <Mapping map="8" index="20" r="0" g="0" b="0"/> - <Mapping map="8" index="21" r="0" g="0" b="0"/> - <Mapping map="8" index="22" r="0" g="0" b="0"/> - <Mapping map="8" index="23" r="0" g="0" b="0"/> - <Mapping map="8" index="24" r="0" g="0" b="0"/> - <Mapping map="8" index="25" r="0" g="0" b="0"/> - <Mapping map="8" index="26" r="0" g="0" b="0"/> - <Mapping map="8" index="27" r="0" g="0" b="0"/> - <Mapping map="8" index="28" r="0" g="0" b="0"/> -</colormap> diff --git a/graphics/AtlantisJava/configuration/config.dtd b/graphics/AtlantisJava/configuration/config.dtd deleted file mode 100644 index 189f117e091..00000000000 --- a/graphics/AtlantisJava/configuration/config.dtd +++ /dev/null @@ -1,169 +0,0 @@ -<!ELEMENT AtlantisConfiguration (Initialization, Parameters,ParameterDifferences*, WindowCorners*)> - -<!ELEMENT Initialization (Interactions, Canvas)> - -<!ELEMENT Interactions (Panel*, InteractionControl+)> - -<!ELEMENT InteractionControl (Panel*)> - <!ATTLIST InteractionControl - projectionName CDATA #REQUIRED - availableInDemoMode CDATA "YES" - defaultInDemoMode CDATA "NO" > - -<!ELEMENT Panel EMPTY> - <!ATTLIST Panel - screenName CDATA #REQUIRED - fileName CDATA #REQUIRED - toolTip CDATA ""> - -<!ELEMENT Canvas (UsedWindow+, Layout+)> - <!ATTLIST Canvas - startupLayout CDATA #REQUIRED - aspectRatio CDATA #REQUIRED> - -<!ELEMENT UsedWindow EMPTY> - <!ATTLIST UsedWindow - name CDATA #REQUIRED - projection CDATA "EP" - group CDATA "Data"> - -<!ELEMENT Layout (Window+, Page+)> - <!ATTLIST Layout - name CDATA #REQUIRED - startup CDATA #REQUIRED - startupWindow CDATA #REQUIRED> - -<!ELEMENT Window EMPTY> - <!ATTLIST Window - name CDATA #REQUIRED - hPos CDATA #REQUIRED - vPos CDATA #REQUIRED - width CDATA #REQUIRED - height CDATA #REQUIRED> - -<!ELEMENT Page EMPTY> - <!ATTLIST Page - name CDATA #REQUIRED - content CDATA #REQUIRED> - -<!ELEMENT Parameters (SuperGroup*)> - <!ATTLIST Parameters - userLevel CDATA #REQUIRED> - -<!ELEMENT SuperGroup (Group*)> - <!ATTLIST SuperGroup - name CDATA #REQUIRED - toolTip CDATA "" - userLevel CDATA "0"> - -<!ELEMENT Group (Command*,((ENUM)*, (SENUM)*, (ICUT)*, (SICUT)*, (FCUT)*, (SFCUT)*, (INT)*, (SINT)*,(LINT)*, (SLINT)*, (FLOAT)*, (SFLOAT)*, (COLOR)*, (SCOLOR)*, (StatusRoot)*, (STATUS)*, (LINK)*)* )> - <!ATTLIST Group - name CDATA #REQUIRED - sname CDATA "" - guiUsage (NO_USE|TABLE|PROJECTION|BRAIN_TEST) "NO_USE" - scope (LOCAL|GLOBAL) "GLOBAL" - userLevel CDATA "0" - toolTip CDATA ""> - -<!ELEMENT Command EMPTY> - <!ATTLIST Command - name CDATA #REQUIRED - command CDATA #REQUIRED - ul CDATA "0" - toolTip CDATA ""> - -<!ENTITY none "0"> - -<!ELEMENT ENUM EMPTY> <!ATTLIST ENUM fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT SENUM EMPTY> <!ATTLIST SENUM fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT ICUT EMPTY> <!ATTLIST ICUT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" isMod (YES|NO) "NO" op CDATA #REQUIRED dop CDATA "" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT SICUT EMPTY> <!ATTLIST SICUT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED isMod (YES|NO) "NO" op CDATA #REQUIRED dop CDATA "" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT FCUT EMPTY> <!ATTLIST FCUT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" isMod (YES|NO) "NO" op CDATA #REQUIRED dop CDATA "" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT SFCUT EMPTY> <!ATTLIST SFCUT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED isMod (YES|NO) "NO" op CDATA #REQUIRED dop CDATA "" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT INT EMPTY> <!ATTLIST INT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" isMod (YES|NO) "NO" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT SINT EMPTY> <!ATTLIST SINT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED isMod (YES|NO) "NO" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT FLOAT EMPTY> <!ATTLIST FLOAT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" isMod (YES|NO) "NO" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT SFLOAT EMPTY> <!ATTLIST SFLOAT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED isMod (YES|NO) "NO" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT LINT EMPTY> <!ATTLIST LINT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT SLINT EMPTY> <!ATTLIST SLINT fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED tip CDATA "" ul CDATA "0" scope CDATA "" u CDATA "&none;"> -<!ELEMENT COLOR EMPTY> <!ATTLIST COLOR fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT SCOLOR EMPTY> <!ATTLIST SCOLOR fn CDATA #REQUIRED sn CDATA "" va CDATA #REQUIRED pv CDATA "-inf : inf" st (ON|OFF) #REQUIRED tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT StatusRoot (StatusGroup*, STATUS*)> <!ATTLIST StatusRoot fn CDATA #REQUIRED sn CDATA "" st (ON|OFF) "OFF" tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT StatusGroup (StatusGroup*, STATUS*)> <!ATTLIST StatusGroup fn CDATA #REQUIRED sn CDATA "" st (ON|OFF) "OFF" tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT STATUS EMPTY> <!ATTLIST STATUS fn CDATA #REQUIRED sn CDATA "" st (ON|OFF) #REQUIRED tip CDATA "" ul CDATA "0" scope CDATA ""> -<!ELEMENT LINK EMPTY> <!ATTLIST LINK to CDATA #REQUIRED> - -<!ELEMENT ParameterDifferences (DIFFERENCE*)> - -<!ELEMENT DIFFERENCE EMPTY> - <!ATTLIST DIFFERENCE - group CDATA #REQUIRED - name CDATA #REQUIRED - windowName CDATA "*" - va CDATA "" - st CDATA "" - op CDATA ""> - -<!ELEMENT WindowCorners (CORNERS*)> - -<!ELEMENT CORNERS EMPTY> - <!ATTLIST CORNERS - windowName CDATA #REQUIRED - x0 CDATA #REQUIRED - y0 CDATA #REQUIRED - x1 CDATA #REQUIRED - y1 CDATA #REQUIRED - x2 CDATA #REQUIRED - y2 CDATA #REQUIRED> - -<!ENTITY length "1"> -<!ENTITY energy "2"> -<!ENTITY energyMEV "3"> - -<!ENTITY user "0"> -<!ENTITY superuser "1"> -<!ENTITY debug "3"> - -<!ENTITY assocCutOptions "All=0, Connected=1, Unconnected=2"> -<!ENTITY drawTo "Pixels = 0, Silicon Strips = 1, TRT_DriftCircle=2, LAr = 3, TILE = 4, Muon System = 5"> -<!ENTITY colorFn "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Track Segment = 4"> -<!ENTITY colorFnTRT "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Track Segment = 4, isOutlier = 5, driftSign = 6, threshold = 7"> -<!ENTITY colorFnMTr "Constant = 0, Index = 1, Pt = 2"> -<!ENTITY colorFnCal "Constant = 0, SubDetector = 1, Cluster = 2, Layer = 3, Energy = 4, Jet = 5, ECAL/HCAL = 6, Time = 7"> -<!ENTITY colorFnS3D "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Group = 4, Layer = 5"> -<!ENTITY colorFnTrigS3D "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Layer = 4"> -<!ENTITY colorFnSiCluster "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Layer = 4, Orientation=5"> -<!ENTITY colorFnPixCluster "Constant = 0, Simulated Track = 1, Reconstructed Track = 2, SubDetector = 3, Layer = 4, Orientation=5, dE/dx=6"> -<!ENTITY colorFnSTr "Constant = 0, Index = 1, Pt = 2, Particle Type = 3, Origin Vertex = 4"> -<!ENTITY colorFnRTr "Constant = 0, Index = 1, Pt = 2, Collection = 3, Simulated Track = 4, RecVertex = 5, Objects = 7"> -<!ENTITY colorFnBasic "Constant = 0, Index = 1"> -<!ENTITY colorFnBasicVtx "Constant = 0, Index = 1 , VertexType = 2"> -<!ENTITY colorFnBasicCollection "Constant = 0, Index = 1, Collection = 2"> -<!ENTITY colorFnBasicCollectionBJets "Constant = 0, Index = 1, Collection = 2, BJets = 3"> - -<!ENTITY energyMode "Sum (Linear) = 0, Max (Linear) = 1, Sum (Logarithmic) = 2, Max (Logarithmic) = 3, Sum (Square Root) = 4, Max (Square Root) = 5"> -<!ENTITY symbol "Filled Square=0,Filled Circle=4,Horizontal Line=1,Vertical Line=2,Plus=3"> -<!ENTITY pickingModes "Event Data=0, Detectors=1"> -<!ENTITY frameCol "0,8:14"> -<!ENTITY detectCol "0:8,14"> -<!ENTITY dataCol "0,8,14:28"> -<!ENTITY histoCol "0,8,14:28"> -<!ENTITY real "<,>"> -<!ENTITY eta "η"> -<!ENTITY rho "ρ"> -<!ENTITY phi "Φ"> -<!ENTITY delta "Δ"> -<!ENTITY lambda "λ"> -<!ENTITY sigma "σ"> -<!ENTITY prime "'"> -<!ENTITY ne "!="> -<!ENTITY le "<="> -<!ENTITY ge ">="> -<!ENTITY int "=,≠,<,≤,>,≥"> -<!ENTITY intEqual "="> -<!ENTITY modesFZ "Standard = 0, RPC Middle 1 = 1, RPC Middle 2 = 2, RPC Outer = 3, MDT Inner and Extension = 4, MDT Middle = 5, MDT Outer = 6"> -<!ENTITY modesYX "Standard = 0, TGC Inner 1 = 1,TGC Middle 1 = 2, TGC Middle 2 = 3, TGC Middle 3 = 4, MDT/CSC Inner 1 = 5, MDT Extension = 6, MDT Middle = 7, MDT Outer = 8, FCAL EM= 9, FCAL HAD 1= 10, FCAL HAD 2= 11, LAr Ecap Presamp= 12, LAr Ecap 1= 13, LAr Ecap 2= 14, LAr Ecap 3= 15, HEC 1= 16, HEC 2= 17, HEC 3= 18, HEC 4= 19, LAr Ecap Summed=20, HEC Summed=21, MBTS=22"> - -<!-- Entities for including blocks of common data --> -<!ENTITY CommonInteractions SYSTEM "common-interactions.xml"> -<!ENTITY CommonParameters SYSTEM "common-parameters.xml"> diff --git a/graphics/AtlantisJava/configuration/epusti.csv b/graphics/AtlantisJava/configuration/epusti.csv deleted file mode 100644 index 0c0b9051835..00000000000 --- a/graphics/AtlantisJava/configuration/epusti.csv +++ /dev/null @@ -1,5 +0,0 @@ -# Event Properties User Selected Trigger Items - -# example: "L1_EM7, L2_e10, EF_e10, L2_g10, EF_g10, L1_J70, EF_tau100" - -"" \ No newline at end of file diff --git a/graphics/AtlantisJava/configuration/pdg.xml b/graphics/AtlantisJava/configuration/pdg.xml deleted file mode 100755 index 20f87414de8..00000000000 --- a/graphics/AtlantisJava/configuration/pdg.xml +++ /dev/null @@ -1,109 +0,0 @@ -<?xml version="1.0"?> - -<!DOCTYPE PDG [ - - <!ELEMENT PDG (Particle*)> - - <!ELEMENT Particle EMPTY> - - <!ATTLIST Particle - charge (-1 | 0 | 1 | 10) #REQUIRED - type CDATA #REQUIRED - code CDATA #REQUIRED - name CDATA #REQUIRED - > - - <!-- - charge = 10 : unknown particle or bug - --> - - <!ENTITY eta "η"> - <!ENTITY rho "ρ"> - <!ENTITY phi "Φ"> - <!ENTITY delta "Δ"> - <!ENTITY pi "π"> - <!ENTITY sigma "Σ"> - <!ENTITY tau "τ"> - <!ENTITY xi "Ξ"> - <!ENTITY omega "Ω"> - <!ENTITY mu "μ"> - <!ENTITY gamma "γ"> - <!ENTITY nu "ν"> - <!ENTITY lambda "Λ"> - <!ENTITY psi "ψ"> - <!ENTITY upsilon "Υ"> - -]> - -<PDG> - - <!-- - 'type' used for InDet selection cuts - --> - - <Particle charge="10" type="0" code="1" name="unknown" /> - <Particle charge="10" type="0" code="0" name="Bug" /> - - <Particle charge="1" type="1" code="211" name="π" /> - <Particle charge="1" type="1" code="2212" name="Proton" /> - <Particle charge="1" type="1" code="321" name="K" /> - <Particle charge="1" type="1" code="3222" name="σ" /> - <Particle charge="-1" type="1" code="3112" name="Anti-σ" /> - <Particle charge="1" type="1" code="411" name="D" /> - <Particle charge="1" type="1" code="431" name="Ds" /> - <Particle charge="-1" type="1" code="3312" name="ξ" /> - <Particle charge="-1" type="1" code="3334" name="ω" /> - <Particle charge="-1" type="2" code="15" name="τ" /> - <Particle charge="-1" type="3" code="11" name="e" /> - <Particle charge="-1" type="4" code="13" name="μ" /> - <Particle charge="0" type="5" code="111" name="π0" /> - <Particle charge="0" type="5" code="2112" name="Neutron" /> - <Particle charge="0" type="5" code="130" name="K0_L" /> - <Particle charge="0" type="5" code="310" name="K0_S" /> - <Particle charge="0" type="5" code="3212" name="σ0" /> - <Particle charge="0" type="5" code="221" name="η" /> - <Particle charge="0" type="5" code="3122" name="λ" /> - <Particle charge="0" type="5" code="3322" name="ξ0" /> - <Particle charge="0" type="5" code="421" name="D0" /> - <Particle charge="0" type="6" code="22" name="γ" /> - <Particle charge="0" type="7" code="12" name="ν" /> - <Particle charge="0" type="7" code="14" name="ν" /> - <Particle charge="0" type="7" code="16" name="ν" /> - <Particle charge="0" type="7" code="1000022" name="neutralino" /> - <Particle charge="0" type="7" code="1000039" name="gravitino" /> - <Particle charge="0" type="8" code="1" name="u" /> - <Particle charge="0" type="8" code="2" name="d" /> - <Particle charge="0" type="8" code="3" name="s" /> - <Particle charge="0" type="8" code="4" name="c" /> - <Particle charge="0" type="8" code="5" name="b" /> - <Particle charge="0" type="8" code="6" name="t" /> - <Particle charge="-1" type="9" code="1000015" name="stau" /> - <Particle charge="-1" type="9" code="2000011" name="selectron" /> - <Particle charge="-1" type="9" code="2000013" name="smuon" /> - <Particle charge="1" type="10" code="24" name="W" /> - <Particle charge="-1" type="11" code="601" name="From Ntuple: d" /> - <Particle charge="1" type="11" code="602" name="From Ntuple: u" /> - <Particle charge="-1" type="11" code="603" name="From Ntuple: s" /> - <Particle charge="1" type="11" code="604" name="From Ntuple: c" /> - <Particle charge="-1" type="11" code="605" name="From Ntuple: b" /> - <Particle charge="1" type="11" code="606" name="From Ntuple: t" /> - <Particle charge="0" type="12" code="21" name="gluon" /> - <Particle charge="0" type="13" code="23" name="Z" /> - - <!-- - fragmentation types - --> - - <Particle charge="0" type="14" code="91" name="cluster fragmentation" /> - <Particle charge="0" type="14" code="92" name="string fragmentation" /> - <Particle charge="0" type="14" code="93" name="independent fragmentation" /> - - <!-- - extra particles (Higgs (h0), J/psi, upsilon) - --> - - <Particle charge="0" type="15" code="25" name="h0" /> - <Particle charge="0" type="15" code="443" name="J/ψ" /> - <Particle charge="0" type="15" code="553" name="υ" /> - -</PDG> diff --git a/graphics/AtlantisJava/configuration/rpsplt_fcal.csv b/graphics/AtlantisJava/configuration/rpsplt_fcal.csv deleted file mode 100644 index f5c29d69492..00000000000 --- a/graphics/AtlantisJava/configuration/rpsplt_fcal.csv +++ /dev/null @@ -1,498 +0,0 @@ -# Real Pulse Shape Plots Lookup Table values for FCAL calorimeter - - -# FCAL, lookup table layer 0, amplitude values -FCAL_LAYER0_AMPLITUDE - "0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.00145f, -0.0002f, -0.00052f, - -9e-05f, 0.00017f, 0.00022f, 3e-05f, -0.00031f, - -0.00061f, -0.00046f, -0.00033f, 0.00012f, -0.00013f, - -0.00025f, -0.0005f, -0.00038f, -0.00035f, -0.0002f, - -0.00042f, -0.00031f, -0.00022f, 0.0001f, -0.00017f, - -0.00033f, 0.00028f, 0.00017f, 2e-05f, 9e-05f, - -0.00018f, -0.00023f, 6e-05f, -3e-05f, -0.00037f, - -0.00029f, -0.00021f, -0.00042f, -0.00047f, -0.00032f, - -0.00041f, -0.0002f, 0.0001f, 0.00032f, 0.0006f, - 0.00147f, 0.00234f, 0.00409f, 0.00701f, 0.01124f, - 0.01704f, 0.02441f, 0.0349f, 0.04655f, 0.06027f, - 0.07674f, 0.09489f, 0.11624f, 0.13948f, 0.16603f, - 0.19516f, 0.22665f, 0.25946f, 0.29534f, 0.3334f, - 0.37421f, 0.41508f, 0.45488f, 0.49473f, 0.53529f, - 0.5759f, 0.61356f, 0.65022f, 0.68584f, 0.72121f, - 0.75454f, 0.78585f, 0.81642f, 0.84443f, 0.8694f, - 0.89244f, 0.9134f, 0.93157f, 0.94811f, 0.96263f, - 0.9756f, 0.98573f, 0.99294f, 0.99721f, 0.99958f, - 0.99937f, 0.99596f, 0.99067f, 0.98339f, 0.97312f, - 0.96037f, 0.94624f, 0.93069f, 0.9126f, 0.89226f, - 0.87097f, 0.84789f, 0.82241f, 0.79715f, 0.7696f, - 0.74111f, 0.713f, 0.68302f, 0.65322f, 0.62221f, - 0.58901f, 0.55499f, 0.52119f, 0.48651f, 0.45161f, - 0.41474f, 0.37863f, 0.34418f, 0.31038f, 0.2759f, - 0.24106f, 0.20725f, 0.17425f, 0.14223f, 0.10914f, - 0.07784f, 0.04664f, 0.01518f, -0.01539f, -0.04403f, - -0.07252f, -0.1007f, -0.12714f, -0.15365f, -0.17955f, - -0.20587f, -0.23009f, -0.25359f, -0.27704f, -0.29989f, - -0.32317f, -0.34403f, -0.3634f, -0.3812f, -0.39806f, - -0.41503f, -0.42994f, -0.4448f, -0.45808f, -0.46945f, - -0.47926f, -0.48934f, -0.50054f, -0.51152f, -0.52073f, - -0.52908f, -0.53691f, -0.5431f, -0.55034f, -0.55776f, - -0.56445f, -0.56952f, -0.57341f, -0.57756f, -0.58138f, - -0.58532f, -0.58718f, -0.58934f, -0.5898f, -0.59049f, - -0.59047f, -0.5886f, -0.58601f, -0.58368f, -0.58009f, - -0.57595f, -0.56963f, -0.55958f, -0.54925f, -0.5387f, - -0.52797f, -0.5171f, -0.50614f, -0.49513f, -0.4841f, - -0.47308f, -0.46212f, -0.45122f, -0.44041f, -0.42973f, - -0.41916f, -0.40875f, -0.39851f, -0.38846f, -0.37862f, - -0.36901f, -0.35965f, -0.35054f, -0.34168f, -0.33306f, - -0.32471f, -0.31661f, -0.30876f, -0.30117f, -0.29382f, - -0.28672f, -0.27987f, -0.27327f, -0.2669f, -0.26077f, - -0.25487f, -0.2492f, -0.24375f, -0.23855f, -0.23358f, - -0.22884f, -0.22433f, -0.22007f, -0.21602f, -0.21221f, - -0.20861f, -0.20521f, -0.20199f, -0.19895f, -0.19609f, - -0.19337f, -0.19079f, -0.18833f, -0.186f, -0.18376f, - -0.1816f, -0.17953f, -0.17753f, -0.17557f, -0.17367f, - -0.1718f, -0.16996f, -0.16814f, -0.16634f, -0.16454f, - -0.16276f, -0.16097f, -0.15917f, -0.15737f, -0.15555f, - -0.15372f, -0.15186f, -0.14997f, -0.14801f, -0.14599f, - -0.14389f, -0.1417f, -0.13943f, -0.13712f, -0.13482f, - -0.13255f, -0.13036f, -0.12824f, -0.12623f, -0.12429f, - -0.12243f, -0.12061f, -0.11882f, -0.11704f, -0.11527f, - -0.11349f, -0.11167f, -0.10983f, -0.10794f, -0.10603f, - -0.10406f, -0.10205f, -0.1f, -0.09791f, -0.09578f, - -0.09361f, -0.09141f, -0.08918f, -0.08694f, -0.08466f, - -0.08238f, -0.08009f, -0.0778f, -0.0755f, -0.07321f, - -0.07093f, -0.06867f, -0.06642f, -0.06421f, -0.06202f, - -0.05986f, -0.05774f, -0.05566f, -0.0536f, -0.05158f, - -0.04959f, -0.04764f, -0.04572f, -0.04385f, -0.04203f, - -0.04025f, -0.03853f, -0.03687f, -0.03526f, -0.0337f, - -0.03218f, -0.03072f, -0.0293f, -0.02794f, -0.02663f, - -0.02536f, -0.02413f, -0.02294f, -0.02181f, -0.0207f, - -0.01964f, -0.01861f, -0.01761f, -0.01665f, -0.01573f, - -0.01484f, -0.01399f, -0.01319f, -0.01242f, -0.01168f, - -0.011f, -0.01034f, -0.00973f, -0.00914f, -0.00861f, - -0.00808f, -0.00761f, -0.00716f, -0.00673f, -0.00632f, - -0.00595f, -0.00559f, -0.00526f, -0.00494f, -0.00464f, - -0.00436f, -0.00409f, -0.00383f, -0.00359f, -0.00335f, - -0.00312f, -0.00291f, -0.00271f, -0.00252f, -0.00234f, - -0.00219f, -0.00204f, -0.0019f, -0.00174f, -0.00158f, - -0.00139f, -0.00118f, -0.00094f, -0.00068f, -0.00042f, - -0.00016f, 8e-05f, 0.00032f, 0.00052f, 0.0007f, - 0.00088f, 0.00102f, 0.00114f, 0.0013f, 0.0014f, - 0.00148f, 0.00159f, 0.00171f, 0.0018f, 0.00191f, - 0.00197f, 0.00207f, 0.00218f, 0.00232f, 0.00243f, - 0.00254f, 0.00267f, 0.0028f, 0.00292f, 0.00305f, - 0.00318f, 0.00331f, 0.00347f, 0.00363f, 0.00376f, - 0.00388f, 0.00405f, 0.00421f, 0.00433f, 0.00446f, - 0.00458f, 0.00473f, 0.00488f, 0.00497f, 0.00514f, - 0.00522f, 0.00538f, 0.00553f, 0.00563f, 0.00573f, - 0.00588f, 0.00596f, 0.00608f, 0.0062f, 0.00629f, - 0.00636f, 0.00646f, 0.00654f, 0.00663f, 0.00669f, - 0.00674f, 0.00679f, 0.00688f, 0.00688f, 0.00696f, - 0.00702f, 0.00704f, 0.00711f, 0.00712f, 0.0072f, - 0.0072f, 0.00727f, 0.00729f, 0.00729f, 0.00737f, - 0.00737f, 0.00737f, 0.00737f, 0.00746f, 0.00746f, - 0.00746f, 0.00746f, 0.00746f, 0.00746f, 0.00746f, - 0.00746f, 0.00746f, 0.00737f, 0.00737f, 0.00737f, - 0.00737f, 0.00737f, 0.00737f, 0.00729f, 0.00729f, - 0.00729f, 0.00729f, 0.00729f, 0.0072f, 0.0072f, - 0.00717f, 0.00712f, 0.00708f, 0.00704f, 0.00704f, - 0.00696f, 0.00696f, 0.00696f, 0.00696f, 0.00696f, - 0.00696f, 0.00696f, 0.00696f, 0.00696f, 0.00696f, - 0.00688f, 0.00688f, 0.00688f, 0.00688f, 0.00688f, - 0.00684f, 0.00679f, 0.00679f, 0.00679f, 0.00671f, - 0.00671f, 0.00671f, 0.00671f, 0.00663f, 0.00663f, - 0.00663f, 0.00663f, 0.00659f, 0.00655f, 0.00655f, - 0.00655f, 0.00655f, 0.00655f, 0.00651f, 0.00646f, - 0.00646f, 0.00646f, 0.00646f, 0.00646f, 0.00646f, - 0.00646f, 0.00646f, 0.00639f, 0.00638f, 0.00638f, - 0.00638f, 0.00638f, 0.00638f, 0.00638f, 0.00638f, - 0.00638f, 0.00638f, 0.00638f, 0.00638f, 0.0063f, - 0.00629f, 0.00629f, 0.00629f, 0.00629f, 0.00629f, - 0.00629f, 0.00629f, 0.00629f, 0.00629f, 0.00622f, - 0.00622f, 0.00622f, 0.00622f, 0.00622f, 0.00622f, - 0.00622f, 0.00622f, 0.00612f, 0.00612f, 0.00612f, - 0.00612f, 0.00612f, 0.00612f, 0.00612f, 0.00612f, - 0.00606f, 0.00605f, 0.00605f, 0.00605f, 0.00605f, - 0.00605f, 0.00605f, 0.00601f, 0.00596f, 0.00596f, - 0.00596f, 0.00596f, 0.00596f, 0.00596f, 0.00596f, - 0.00588f, 0.00588f, 0.00588f, 0.00588f, 0.00588f, - 0.00588f, 0.00585f, 0.00579f, 0.00579f, 0.00579f, - 0.00579f, 0.00579f, 0.00572f, 0.00572f, 0.00572f, - 0.00572f, 0.00572f, 0.00572f, 0.00572f, 0.00572f, - 0.00572f, 0.00563f, 0.00563f, 0.00563f, 0.00563f, - 0.00563f, 0.00563f, 0.00563f, 0.00563f, 0.00563f, - 0.00563f, 0.00563f, 0.00563f, 0.00563f, 0.00563f" - - -# FCAL lookup table layer 1, amplitude values -FCAL_LAYER1_AMPLITUDE - "0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, -0.00014f, - -0.00015f, -0.00019f, -0.00024f, -2e-05f, 8e-05f, - 0.00012f, -3e-05f, -0.00012f, -0.00011f, -0.0002f, - -4e-05f, 7e-05f, 5e-05f, -1e-05f, -9e-05f, - -3e-05f, -0.00012f, -3e-05f, -3e-05f, -1e-05f, - -3e-05f, -1e-05f, -0.00011f, -0.00021f, -0.00017f, - -0.00016f, -6e-05f, 1e-05f, 1e-05f, -3e-05f, - -0.00018f, -0.0002f, -0.00018f, -8e-05f, -2e-05f, - -5e-05f, 0.00011f, 4e-05f, 0.00032f, 0.00076f, - 0.00136f, 0.00271f, 0.00417f, 0.00696f, 0.01099f, - 0.01602f, 0.02229f, 0.02963f, 0.03936f, 0.05282f, - 0.06928f, 0.08819f, 0.10857f, 0.12914f, 0.15221f, - 0.17682f, 0.20343f, 0.23335f, 0.26583f, 0.29864f, - 0.33272f, 0.36835f, 0.40457f, 0.44149f, 0.47595f, - 0.51049f, 0.54648f, 0.5816f, 0.61676f, 0.65114f, - 0.68367f, 0.7141f, 0.74147f, 0.76915f, 0.79855f, - 0.82565f, 0.85105f, 0.87379f, 0.89366f, 0.9111f, - 0.927f, 0.94162f, 0.95496f, 0.96664f, 0.97688f, - 0.98534f, 0.99109f, 0.99601f, 0.99887f, 0.99964f, - 0.99962f, 0.99681f, 0.99299f, 0.98726f, 0.98f, - 0.97158f, 0.96249f, 0.95187f, 0.9393f, 0.92385f, - 0.90628f, 0.88827f, 0.86996f, 0.85269f, 0.83453f, - 0.81503f, 0.79519f, 0.77368f, 0.74984f, 0.72628f, - 0.70228f, 0.67716f, 0.65181f, 0.62399f, 0.59774f, - 0.57129f, 0.54263f, 0.51398f, 0.48417f, 0.45309f, - 0.42268f, 0.39325f, 0.36432f, 0.33302f, 0.29777f, - 0.26282f, 0.22816f, 0.19507f, 0.16394f, 0.13389f, - 0.10437f, 0.07385f, 0.04319f, 0.01199f, -0.01883f, - -0.04912f, -0.07801f, -0.10802f, -0.13734f, -0.16453f, - -0.19169f, -0.2182f, -0.24487f, -0.27109f, -0.29671f, - -0.32083f, -0.34391f, -0.36456f, -0.38568f, -0.40796f, - -0.428f, -0.44835f, -0.46643f, -0.48286f, -0.49816f, - -0.51161f, -0.5248f, -0.5374f, -0.54928f, -0.5608f, - -0.57103f, -0.57868f, -0.58697f, -0.59288f, -0.59803f, - -0.60282f, -0.60532f, -0.60756f, -0.60862f, -0.60882f, - -0.60828f, -0.60572f, -0.60473f, -0.60353f, -0.60196f, - -0.6001f, -0.59736f, -0.59308f, -0.58847f, -0.5836f, - -0.57846f, -0.57308f, -0.56749f, -0.56171f, -0.55576f, - -0.54966f, -0.54343f, -0.5371f, -0.53066f, -0.52415f, - -0.51757f, -0.51094f, -0.50428f, -0.4976f, -0.4909f, - -0.4842f, -0.47749f, -0.47078f, -0.4641f, -0.45745f, - -0.45081f, -0.44422f, -0.43769f, -0.43118f, -0.42475f, - -0.41838f, -0.41207f, -0.40583f, -0.39965f, -0.39355f, - -0.38752f, -0.38156f, -0.37568f, -0.36988f, -0.36414f, - -0.35848f, -0.35292f, -0.34744f, -0.34205f, -0.33676f, - -0.33155f, -0.32642f, -0.32135f, -0.31634f, -0.31139f, - -0.30648f, -0.30164f, -0.29688f, -0.29227f, -0.28779f, - -0.28349f, -0.27937f, -0.27541f, -0.2716f, -0.26792f, - -0.26432f, -0.26084f, -0.25743f, -0.25406f, -0.25074f, - -0.24743f, -0.24413f, -0.24086f, -0.23757f, -0.23428f, - -0.23096f, -0.22764f, -0.22429f, -0.22092f, -0.21754f, - -0.21414f, -0.21072f, -0.20729f, -0.20385f, -0.20038f, - -0.19692f, -0.19344f, -0.18993f, -0.18644f, -0.18293f, - -0.17943f, -0.17592f, -0.17244f, -0.16898f, -0.16553f, - -0.16211f, -0.1587f, -0.15533f, -0.15198f, -0.14866f, - -0.14538f, -0.14213f, -0.13891f, -0.13573f, -0.13259f, - -0.12948f, -0.12641f, -0.1234f, -0.12042f, -0.11747f, - -0.11457f, -0.11173f, -0.10891f, -0.10617f, -0.10345f, - -0.10079f, -0.09819f, -0.09562f, -0.09311f, -0.09065f, - -0.08823f, -0.08586f, -0.08354f, -0.08125f, -0.07903f, - -0.07685f, -0.07471f, -0.07262f, -0.07057f, -0.06857f, - -0.06662f, -0.06471f, -0.06284f, -0.06102f, -0.05926f, - -0.05751f, -0.05582f, -0.05416f, -0.05254f, -0.05096f, - -0.04942f, -0.04792f, -0.04647f, -0.04507f, -0.04369f, - -0.04235f, -0.04104f, -0.03974f, -0.03845f, -0.03717f, - -0.03591f, -0.03467f, -0.03347f, -0.03231f, -0.03119f, - -0.03012f, -0.0291f, -0.02812f, -0.02718f, -0.02629f, - -0.02542f, -0.0246f, -0.02381f, -0.02304f, -0.0223f, - -0.02157f, -0.02088f, -0.0202f, -0.01953f, -0.01888f, - -0.01824f, -0.01761f, -0.017f, -0.0164f, -0.0158f, - -0.01523f, -0.01466f, -0.0141f, -0.01355f, -0.01301f, - -0.01247f, -0.01195f, -0.01141f, -0.0109f, -0.01039f, - -0.00989f, -0.0094f, -0.0089f, -0.00842f, -0.00796f, - -0.0075f, -0.00705f, -0.0066f, -0.00616f, -0.00575f, - -0.00533f, -0.00493f, -0.00452f, -0.00413f, -0.00375f, - -0.00338f, -0.003f, -0.00265f, -0.00228f, -0.00195f, - -0.00162f, -0.00128f, -0.00096f, -0.00064f, -0.00035f, - -5e-05f, 0.00023f, 0.0005f, 0.00079f, 0.00105f, - 0.00131f, 0.00156f, 0.00181f, 0.00201f, 0.0023f, - 0.0025f, 0.00267f, 0.00287f, 0.00315f, 0.00335f, - 0.00346f, 0.00367f, 0.0039f, 0.0041f, 0.00421f, - 0.00441f, 0.00458f, 0.00473f, 0.0049f, 0.00505f, - 0.00516f, 0.00522f, 0.00537f, 0.00551f, 0.00552f, - 0.00569f, 0.00579f, 0.0059f, 0.00601f, 0.00615f, - 0.00628f, 0.00632f, 0.00648f, 0.00653f, 0.00664f, - 0.00679f, 0.0068f, 0.00696f, 0.00696f, 0.007f, - 0.00711f, 0.00711f, 0.00724f, 0.00728f, 0.00728f, - 0.00728f, 0.00743f, 0.00743f, 0.00743f, 0.00743f, - 0.00744f, 0.00759f, 0.00759f, 0.00759f, 0.00759f, - 0.00759f, 0.00759f, 0.00774f, 0.00775f, 0.00775f, - 0.00775f, 0.00775f, 0.00775f, 0.00775f, 0.00775f, - 0.00789f, 0.00791f, 0.00791f, 0.00791f, 0.00791f, - 0.00791f, 0.00791f, 0.00791f, 0.00791f, 0.00791f, - 0.00791f, 0.00792f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00807f, 0.00807f, - 0.00807f, 0.00807f, 0.00807f, 0.00791f, 0.00791f, - 0.00791f, 0.00791f, 0.00791f, 0.00791f, 0.00791f, - 0.00791f, 0.00791f, 0.00791f, 0.00791f, 0.00791f, - 0.00791f, 0.00791f, 0.00791f, 0.00791f, 0.00791f, - 0.00791f, 0.00775f, 0.00775f, 0.00775f, 0.00775f, - 0.00775f, 0.00775f, 0.00775f, 0.00775f, 0.00775f, - 0.00775f, 0.00775f, 0.00775f, 0.00775f, 0.0076f, - 0.00759f, 0.00759f, 0.00759f, 0.00759f, 0.00759f, - 0.00759f, 0.00759f, 0.00759f, 0.00759f, 0.00759f, - 0.00759f, 0.00753f, 0.00743f, 0.00743f, 0.00743f, - 0.00743f, 0.00743f, 0.00743f, 0.00743f, 0.00743f, - 0.00743f, 0.00743f, 0.00743f, 0.00743f, 0.00743f, - 0.00728f, 0.00728f, 0.00728f, 0.00728f, 0.00728f, - 0.00728f, 0.00728f, 0.00728f, 0.00728f, 0.00728f, - 0.00728f, 0.00728f, 0.00728f, 0.00727f, 0.00711f, - 0.00711f, 0.00711f, 0.00711f, 0.00711f, 0.00711f, - 0.00711f, 0.00711f, 0.00711f, 0.00711f, 0.00711f, - 0.00711f, 0.00711f, 0.00711f, 0.00711f, 0.00711f" - - -# FCAL lookup table layer 2, amplitude values -FCAL_LAYER2_AMPLITUDE - "0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -0.00128f, -0.00011f, 0.00018f, 2e-05f, - 0.00012f, -6e-05f, -5e-05f, -4e-05f, -4e-05f, - -6e-05f, -0.00031f, 3e-05f, -0.00022f, 7e-05f, - -3e-05f, 2e-05f, 0.00011f, 9e-05f, -0.00025f, - -5e-05f, -0.00026f, -3e-05f, -3e-05f, -5e-05f, - -3e-05f, 8e-05f, 0.00016f, 0.00025f, 0.00015f, - 0.00018f, 9e-05f, -0.00016f, -0.00017f, 0.00012f, - 0.00031f, 0.00061f, 0.00137f, 0.00259f, 0.00487f, - 0.00807f, 0.01106f, 0.01611f, 0.02298f, 0.03195f, - 0.04154f, 0.05328f, 0.06624f, 0.08155f, 0.09926f, - 0.11723f, 0.13765f, 0.16233f, 0.18937f, 0.21701f, - 0.24599f, 0.27675f, 0.30806f, 0.34205f, 0.3763f, - 0.40922f, 0.44335f, 0.47795f, 0.51151f, 0.54584f, - 0.58035f, 0.61246f, 0.64345f, 0.67427f, 0.70516f, - 0.73373f, 0.75953f, 0.78417f, 0.80817f, 0.83037f, - 0.85125f, 0.87108f, 0.88998f, 0.9072f, 0.92291f, - 0.93755f, 0.95053f, 0.96236f, 0.97239f, 0.9802f, - 0.9869f, 0.99293f, 0.99661f, 0.99861f, 0.99968f, - 0.99958f, 0.99822f, 0.99567f, 0.9913f, 0.98539f, - 0.97946f, 0.97165f, 0.96321f, 0.95356f, 0.943f, - 0.93288f, 0.92124f, 0.90748f, 0.8924f, 0.87741f, - 0.86239f, 0.84699f, 0.83096f, 0.81354f, 0.79568f, - 0.77812f, 0.75942f, 0.73898f, 0.71895f, 0.6979f, - 0.67584f, 0.65541f, 0.63427f, 0.61183f, 0.58872f, - 0.56582f, 0.54277f, 0.51966f, 0.49662f, 0.47374f, - 0.45068f, 0.42633f, 0.40063f, 0.37501f, 0.35003f, - 0.32551f, 0.30122f, 0.27643f, 0.2508f, 0.22669f, - 0.2018f, 0.1756f, 0.15017f, 0.12637f, 0.102f, - 0.07617f, 0.05128f, 0.02768f, 0.00478f, -0.01868f, - -0.0427f, -0.06341f, -0.08504f, -0.10568f, -0.12438f, - -0.14567f, -0.16618f, -0.18641f, -0.20502f, -0.22295f, - -0.24012f, -0.2569f, -0.27256f, -0.28823f, -0.30194f, - -0.31542f, -0.33028f, -0.34304f, -0.35301f, -0.36387f, - -0.37478f, -0.38515f, -0.39437f, -0.4023f, -0.41029f, - -0.41949f, -0.42512f, -0.43117f, -0.43628f, -0.44007f, - -0.4454f, -0.45203f, -0.45813f, -0.46382f, -0.46907f, - -0.4739f, -0.47832f, -0.48235f, -0.48597f, -0.4892f, - -0.49207f, -0.49454f, -0.49666f, -0.49841f, -0.49984f, - -0.50092f, -0.50166f, -0.50208f, -0.50221f, -0.50202f, - -0.50155f, -0.50082f, -0.49982f, -0.49856f, -0.49706f, - -0.49533f, -0.49338f, -0.49122f, -0.48885f, -0.48628f, - -0.48354f, -0.48064f, -0.47755f, -0.47432f, -0.47094f, - -0.46742f, -0.46379f, -0.46001f, -0.45611f, -0.45208f, - -0.4479f, -0.44361f, -0.43919f, -0.43467f, -0.43006f, - -0.42543f, -0.42077f, -0.41613f, -0.4115f, -0.4069f, - -0.40233f, -0.39778f, -0.39325f, -0.38873f, -0.38422f, - -0.37971f, -0.37519f, -0.37068f, -0.36616f, -0.36163f, - -0.3571f, -0.35256f, -0.34802f, -0.34347f, -0.33892f, - -0.33436f, -0.32982f, -0.32529f, -0.32077f, -0.31626f, - -0.31179f, -0.30733f, -0.30289f, -0.2985f, -0.29413f, - -0.2898f, -0.28552f, -0.28129f, -0.27709f, -0.27294f, - -0.26885f, -0.26479f, -0.26078f, -0.25685f, -0.25293f, - -0.24906f, -0.24524f, -0.24147f, -0.23772f, -0.23403f, - -0.23038f, -0.22676f, -0.22318f, -0.21964f, -0.21614f, - -0.21268f, -0.20925f, -0.20586f, -0.20249f, -0.19916f, - -0.19588f, -0.19261f, -0.1894f, -0.18622f, -0.18305f, - -0.17994f, -0.17686f, -0.1738f, -0.17078f, -0.16779f, - -0.16484f, -0.1619f, -0.15902f, -0.15615f, -0.15333f, - -0.15054f, -0.14777f, -0.14504f, -0.14234f, -0.13967f, - -0.13704f, -0.13444f, -0.13187f, -0.12934f, -0.12684f, - -0.12439f, -0.12197f, -0.11959f, -0.11724f, -0.11494f, - -0.11265f, -0.1104f, -0.10815f, -0.10592f, -0.10371f, - -0.10151f, -0.09934f, -0.0972f, -0.09509f, -0.09302f, - -0.09099f, -0.08899f, -0.08705f, -0.08514f, -0.08327f, - -0.08145f, -0.07966f, -0.0779f, -0.07617f, -0.07448f, - -0.07282f, -0.07119f, -0.06958f, -0.06801f, -0.06646f, - -0.06493f, -0.06344f, -0.06196f, -0.06051f, -0.05908f, - -0.05768f, -0.05629f, -0.05495f, -0.0536f, -0.05229f, - -0.051f, -0.04974f, -0.04849f, -0.04726f, -0.04607f, - -0.0449f, -0.04375f, -0.04262f, -0.04151f, -0.04044f, - -0.03937f, -0.03834f, -0.03732f, -0.03634f, -0.03536f, - -0.0344f, -0.03347f, -0.03256f, -0.03166f, -0.03079f, - -0.02993f, -0.02908f, -0.02826f, -0.02745f, -0.02666f, - -0.02588f, -0.02512f, -0.02437f, -0.02364f, -0.02293f, - -0.02223f, -0.02154f, -0.02087f, -0.02021f, -0.01957f, - -0.01892f, -0.0183f, -0.01768f, -0.0171f, -0.01651f, - -0.01594f, -0.01536f, -0.01482f, -0.01428f, -0.01375f, - -0.01323f, -0.01271f, -0.01221f, -0.01171f, -0.01123f, - -0.01076f, -0.01029f, -0.00984f, -0.0094f, -0.00898f, - -0.00857f, -0.00817f, -0.00777f, -0.00739f, -0.007f, - -0.00663f, -0.00624f, -0.00587f, -0.00551f, -0.00514f, - -0.00479f, -0.00444f, -0.0041f, -0.00377f, -0.00344f, - -0.00313f, -0.00282f, -0.00252f, -0.00223f, -0.00195f, - -0.00168f, -0.0014f, -0.00114f, -0.00089f, -0.00063f, - -0.00039f, -0.00015f, 9e-05f, 0.00031f, 0.00053f, - 0.00076f, 0.00096f, 0.00117f, 0.00138f, 0.00158f, - 0.00178f, 0.00194f, 0.00216f, 0.00234f, 0.00251f, - 0.00269f, 0.0029f, 0.00298f, 0.00319f, 0.00338f, - 0.00353f, 0.00368f, 0.00383f, 0.00398f, 0.00408f, - 0.00427f, 0.00438f, 0.00447f, 0.00458f, 0.00472f, - 0.00488f, 0.00501f, 0.00512f, 0.00517f, 0.00532f, - 0.00546f, 0.00547f, 0.00561f, 0.00572f, 0.00576f, - 0.0059f, 0.00594f, 0.00606f, 0.0062f, 0.0062f, - 0.00635f, 0.00636f, 0.0065f, 0.0065f, 0.00664f, - 0.00665f, 0.0068f, 0.0068f, 0.00684f, 0.00695f, - 0.00695f, 0.0071f, 0.0071f, 0.00721f, 0.00725f, - 0.00725f, 0.00739f, 0.0074f, 0.0074f, 0.00751f, - 0.00755f, 0.00755f, 0.00759f, 0.00769f, 0.00769f, - 0.00769f, 0.00769f, 0.00783f, 0.00783f, 0.00783f, - 0.00783f, 0.00795f, 0.00799f, 0.00799f, 0.00799f, - 0.00799f, 0.00812f, 0.00813f, 0.00813f, 0.00813f, - 0.00813f, 0.00813f, 0.00828f, 0.00829f, 0.00829f, - 0.00829f, 0.00829f, 0.00829f, 0.00829f, 0.00829f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00844f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00858f, 0.00858f, 0.00858f, - 0.00858f, 0.00858f, 0.00854f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f, - 0.00843f, 0.00843f, 0.00843f, 0.00843f, 0.00843f" - - -# FCAL lookup table time values -FCAL_TIME - "0.5f, 1.5f, 2.5f, 3.5f, 4.5f, - 5.5f, 6.5f, 7.5f, 8.5f, 9.5f, - 10.5f, 11.5f, 12.5f, 13.5f, 14.5f, - 15.5f, 16.5f, 17.5f, 18.5f, 19.5f, - 20.5f, 21.5f, 22.5f, 23.5f, 24.5f, - 25.5f, 26.5f, 27.5f, 28.5f, 29.5f, - 30.5f, 31.5f, 32.5f, 33.5f, 34.5f, - 35.5f, 36.5f, 37.5f, 38.5f, 39.5f, - 40.5f, 41.5f, 42.5f, 43.5f, 44.5f, - 45.5f, 46.5f, 47.5f, 48.5f, 49.5f, - 50.5f, 51.5f, 52.5f, 53.5f, 54.5f, - 55.5f, 56.5f, 57.5f, 58.5f, 59.5f, - 60.5f, 61.5f, 62.5f, 63.5f, 64.5f, - 65.5f, 66.5f, 67.5f, 68.5f, 69.5f, - 70.5f, 71.5f, 72.5f, 73.5f, 74.5f, - 75.5f, 76.5f, 77.5f, 78.5f, 79.5f, - 80.5f, 81.5f, 82.5f, 83.5f, 84.5f, - 85.5f, 86.5f, 87.5f, 88.5f, 89.5f, - 90.5f, 91.5f, 92.5f, 93.5f, 94.5f, - 95.5f, 96.5f, 97.5f, 98.5f, 99.5f, - 100.5f, 101.5f, 102.5f, 103.5f, 104.5f, - 105.5f, 106.5f, 107.5f, 108.5f, 109.5f, - 110.5f, 111.5f, 112.5f, 113.5f, 114.5f, - 115.5f, 116.5f, 117.5f, 118.5f, 119.5f, - 120.5f, 121.5f, 122.5f, 123.5f, 124.5f, - 125.5f, 126.5f, 127.5f, 128.5f, 129.5f, - 130.5f, 131.5f, 132.5f, 133.5f, 134.5f, - 135.5f, 136.5f, 137.5f, 138.5f, 139.5f, - 140.5f, 141.5f, 142.5f, 143.5f, 144.5f, - 145.5f, 146.5f, 147.5f, 148.5f, 149.5f, - 150.5f, 151.5f, 152.5f, 153.5f, 154.5f, - 155.5f, 156.5f, 157.5f, 158.5f, 159.5f, - 160.5f, 161.5f, 162.5f, 163.5f, 164.5f, - 165.5f, 166.5f, 167.5f, 168.5f, 169.5f, - 170.5f, 171.5f, 172.5f, 173.5f, 174.5f, - 175.5f, 176.5f, 177.5f, 178.5f, 179.5f, - 180.5f, 181.5f, 182.5f, 183.5f, 184.5f, - 185.5f, 186.5f, 187.5f, 188.5f, 189.5f, - 190.5f, 191.5f, 192.5f, 193.5f, 194.5f, - 195.5f, 196.5f, 197.5f, 198.5f, 199.5f, - 200.5f, 201.5f, 202.5f, 203.5f, 204.5f, - 205.5f, 206.5f, 207.5f, 208.5f, 209.5f, - 210.5f, 211.5f, 212.5f, 213.5f, 214.5f, - 215.5f, 216.5f, 217.5f, 218.5f, 219.5f, - 220.5f, 221.5f, 222.5f, 223.5f, 224.5f, - 225.5f, 226.5f, 227.5f, 228.5f, 229.5f, - 230.5f, 231.5f, 232.5f, 233.5f, 234.5f, - 235.5f, 236.5f, 237.5f, 238.5f, 239.5f, - 240.5f, 241.5f, 242.5f, 243.5f, 244.5f, - 245.5f, 246.5f, 247.5f, 248.5f, 249.5f, - 250.5f, 251.5f, 252.5f, 253.5f, 254.5f, - 255.5f, 256.5f, 257.5f, 258.5f, 259.5f, - 260.5f, 261.5f, 262.5f, 263.5f, 264.5f, - 265.5f, 266.5f, 267.5f, 268.5f, 269.5f, - 270.5f, 271.5f, 272.5f, 273.5f, 274.5f, - 275.5f, 276.5f, 277.5f, 278.5f, 279.5f, - 280.5f, 281.5f, 282.5f, 283.5f, 284.5f, - 285.5f, 286.5f, 287.5f, 288.5f, 289.5f, - 290.5f, 291.5f, 292.5f, 293.5f, 294.5f, - 295.5f, 296.5f, 297.5f, 298.5f, 299.5f, - 300.5f, 301.5f, 302.5f, 303.5f, 304.5f, - 305.5f, 306.5f, 307.5f, 308.5f, 309.5f, - 310.5f, 311.5f, 312.5f, 313.5f, 314.5f, - 315.5f, 316.5f, 317.5f, 318.5f, 319.5f, - 320.5f, 321.5f, 322.5f, 323.5f, 324.5f, - 325.5f, 326.5f, 327.5f, 328.5f, 329.5f, - 330.5f, 331.5f, 332.5f, 333.5f, 334.5f, - 335.5f, 336.5f, 337.5f, 338.5f, 339.5f, - 340.5f, 341.5f, 342.5f, 343.5f, 344.5f, - 345.5f, 346.5f, 347.5f, 348.5f, 349.5f, - 350.5f, 351.5f, 352.5f, 353.5f, 354.5f, - 355.5f, 356.5f, 357.5f, 358.5f, 359.5f, - 360.5f, 361.5f, 362.5f, 363.5f, 364.5f, - 365.5f, 366.5f, 367.5f, 368.5f, 369.5f, - 370.5f, 371.5f, 372.5f, 373.5f, 374.5f, - 375.5f, 376.5f, 377.5f, 378.5f, 379.5f, - 380.5f, 381.5f, 382.5f, 383.5f, 384.5f, - 385.5f, 386.5f, 387.5f, 388.5f, 389.5f, - 390.5f, 391.5f, 392.5f, 393.5f, 394.5f, - 395.5f, 396.5f, 397.5f, 398.5f, 399.5f, - 400.5f, 401.5f, 402.5f, 403.5f, 404.5f, - 405.5f, 406.5f, 407.5f, 408.5f, 409.5f, - 410.5f, 411.5f, 412.5f, 413.5f, 414.5f, - 415.5f, 416.5f, 417.5f, 418.5f, 419.5f, - 420.5f, 421.5f, 422.5f, 423.5f, 424.5f, - 425.5f, 426.5f, 427.5f, 428.5f, 429.5f, - 430.5f, 431.5f, 432.5f, 433.5f, 434.5f, - 435.5f, 436.5f, 437.5f, 438.5f, 439.5f, - 440.5f, 441.5f, 442.5f, 443.5f, 444.5f, - 445.5f, 446.5f, 447.5f, 448.5f, 449.5f, - 450.5f, 451.5f, 452.5f, 453.5f, 454.5f, - 455.5f, 456.5f, 457.5f, 458.5f, 459.5f, - 460.5f, 461.5f, 462.5f, 463.5f, 464.5f, - 465.5f, 466.5f, 467.5f, 468.5f, 469.5f, - 470.5f, 471.5f, 472.5f, 473.5f, 474.5f, - 475.5f, 476.5f, 477.5f, 478.5f, 479.5f, - 480.5f, 481.5f, 482.5f, 483.5f, 484.5f, - 485.5f, 486.5f, 487.5f, 488.5f, 489.5f, - 490.5f, 491.5f, 492.5f, 493.5f, 494.5f, - 495.5f, 496.5f, 497.5f, 498.5f, 499.5f, - 500.5f, 501.5f, 502.5f, 503.5f, 504.5f, - 505.5f, 506.5f, 507.5f, 508.5f, 509.5f, - 510.5f, 511.5f, 512.5f, 513.5f, 514.5f, - 515.5f, 516.5f, 517.5f, 518.5f, 519.5f, - 520.5f, 521.5f, 522.5f, 523.5f, 524.5f, - 525.5f, 526.5f, 527.5f, 528.5f, 529.5f, - 530.5f, 531.5f, 532.5f, 533.5f, 534.5f, - 535.5f, 536.5f, 537.5f, 538.5f, 539.5f, - 540.5f, 541.5f, 542.5f, 543.5f, 544.5f, - 545.5f, 546.5f, 547.5f, 548.5f, 549.5f, - 550.5f, 551.5f, 552.5f, 553.5f, 554.5f, - 555.5f, 556.5f, 557.5f, 558.5f, 559.5f, - 560.5f, 561.5f, 562.5f, 563.5f, 564.5f, - 565.5f, 566.5f, 567.5f, 568.5f, 569.5f, - 570.5f, 571.5f, 572.5f, 573.5f, 574.5f, - 575.5f, 576.5f, 577.5f, 578.5f, 579.5f, - 580.5f, 581.5f, 582.5f, 583.5f, 584.5f, - 585.5f, 586.5f, 587.5f, 588.5f, 589.5f, - 590.5f, 591.5f, 592.5f, 593.5f, 594.5f, - 595.5f, 596.5f, 597.5f, 598.5f, 599.5f" - diff --git a/graphics/AtlantisJava/configuration/rpsplt_hec.csv b/graphics/AtlantisJava/configuration/rpsplt_hec.csv deleted file mode 100644 index 0b1285de75e..00000000000 --- a/graphics/AtlantisJava/configuration/rpsplt_hec.csv +++ /dev/null @@ -1,329 +0,0 @@ -# Real Pulse Shape Plots Lookup Table values for HEC calorimeter - - -# HEC lookup table, amplitude values -HEC_AMPLITUDE -"0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0.000101187f, 0.00664058f, 0.00527695f, 0.0002041f, -0.000215028f, 0.000293915f, 0.000490323f, 0.000903528f, 0.00170435f, -0.00314031f, 0.00552285f, 0.00920343f, 0.0145539f, 0.0219273f, -0.0316359f, 0.043942f, 0.059033f, 0.0770143f, 0.0978915f, -0.121549f, 0.147763f, 0.17623f, 0.206609f, 0.238601f, -0.272f, 0.306696f, 0.342649f, 0.379813f, 0.418056f, -0.457117f, 0.496607f, 0.536044f, 0.57493f, 0.612812f, -0.649334f, 0.684243f, 0.717392f, 0.748708f, 0.778165f, -0.805768f, 0.831539f, 0.85551f, 0.877704f, 0.898131f, -0.916774f, 0.933594f, 0.948547f, 0.961595f, 0.972719f, -0.98191f, 0.989184f, 0.994564f, 0.998103f, 0.99988f, -1f, 0.998581f, 0.995722f, 0.991483f, 0.985877f, -0.978879f, 0.970462f, 0.960624f, 0.949425f, 0.936981f, -0.92346f, 0.909059f, 0.893975f, 0.878385f, 0.862425f, -0.846174f, 0.829654f, 0.812831f, 0.795626f, 0.777953f, -0.759737f, 0.740952f, 0.721636f, 0.701896f, 0.681887f, -0.661787f, 0.64177f, 0.621975f, 0.602503f, 0.583422f, -0.564766f, 0.54655f, 0.528765f, 0.511376f, 0.494318f, -0.477505f, 0.460853f, 0.444298f, 0.427826f, 0.411478f, -0.395336f, 0.379494f, 0.364017f, 0.348923f, 0.334176f, -0.319715f, 0.305481f, 0.291443f, 0.277605f, 0.263994f, -0.250654f, 0.237625f, 0.224942f, 0.21263f, 0.200696f, -0.189132f, 0.177913f, 0.166995f, 0.156325f, 0.145848f, -0.135522f, 0.125326f, 0.115279f, 0.105427f, 0.0958465f, -0.0866154f, 0.0777954f, 0.0694189f, 0.0614767f, 0.0539207f, -0.0466707f, 0.0396293f, 0.0327093f, 0.0258526f, 0.0190475f, -0.0123301f, 0.00576636f, -0.000577978f, -0.00665906f, -0.0124708f, --0.0180326f, -0.023372f, -0.0285029f, -0.0334147f, -0.0380814f, --0.0424744f, -0.0465814f, -0.0504199f, -0.0540364f, -0.0574984f, --0.060883f, -0.0642531f, -0.06764f, -0.0710355f, -0.0743926f, --0.0776445f, -0.0807294f, -0.0836115f, -0.0862943f, -0.0888135f, --0.091227f, -0.0935885f, -0.0959315f, -0.0982592f, -0.100547f, --0.102752f, -0.104836f, -0.106781f, -0.108595f, -0.110316f, --0.112001f, -0.113707f, -0.115471f, -0.117302f, -0.119178f, --0.121058f, -0.122894f, -0.124646f, -0.126288f, -0.127819f, --0.129262f, -0.130658f, -0.132056f, -0.133495f, -0.134988f, --0.136514f, -0.138027f, -0.139477f, -0.140829f, -0.142082f, --0.143263f, -0.144417f, -0.145579f, -0.146758f, -0.147944f, --0.149106f, -0.150203f, -0.151199f, -0.152063f, -0.152785f, --0.153383f, -0.153917f, -0.154483f, -0.155185f, -0.156098f, --0.157233f, -0.158526f, -0.159851f, -0.161065f, -0.162059f, --0.162781f, -0.163253f, -0.163543f, -0.163732f, -0.163889f, --0.164059f, -0.164269f, -0.164541f, -0.1649f, -0.165369f, --0.165963f, -0.166671f, -0.167457f, -0.168261f, -0.169021f, --0.169687f, -0.170237f, -0.170686f, -0.171074f, -0.171449f, --0.171844f, -0.172271f, -0.172716f, -0.173152f, -0.173545f, --0.173864f, -0.174091f, -0.174214f, -0.174244f, -0.174208f, --0.174145f, -0.174091f, -0.174075f, -0.174109f, -0.174199f, --0.174347f, -0.174556f, -0.174822f, -0.175124f, -0.175427f, --0.175685f, -0.175868f, -0.175971f, -0.176023f, -0.17607f, --0.17616f, -0.176313f, -0.176514f, -0.176721f, -0.176879f, --0.176951f, -0.176934f, -0.176855f, -0.17676f, -0.176689f, --0.176655f, -0.176648f, -0.176647f, -0.176639f, -0.176628f, --0.176632f, -0.176673f, -0.176754f, -0.176855f, -0.176936f, --0.176952f, -0.176875f, -0.176706f, -0.17647f, -0.176211f, --0.175972f, -0.175794f, -0.175711f, -0.175755f, -0.175946f, --0.176285f, -0.176742f, -0.177258f, -0.177757f, -0.17817f, --0.17845f, -0.178579f, -0.178566f, -0.178437f, -0.178227f, --0.177974f, -0.177712f, -0.177464f, -0.177238f, -0.177031f, --0.176835f, -0.176652f, -0.176495f, -0.176386f, -0.176349f, --0.176395f, -0.176518f, -0.176694f, -0.176894f, -0.177086f, --0.177248f, -0.177368f, -0.177442f, -0.177475f, -0.177466f, --0.177409f, -0.177287f, -0.177085f, -0.176805f, -0.176481f, --0.176177f, -0.175968f, -0.175917f, -0.176041f, -0.176305f, --0.176639f, -0.176956f, -0.177192f, -0.177313f, -0.177318f, --0.17723f, -0.177084f, -0.176912f, -0.176746f, -0.176605f, --0.176497f, -0.176412f, -0.176339f, -0.176273f, -0.176226f, --0.176224f, -0.176294f, -0.176444f, -0.176653f, -0.176876f, --0.177061f, -0.17717f, -0.177187f, -0.177116f, -0.176969f, --0.17676f, -0.176495f, -0.176185f, -0.175846f, -0.175501f, --0.175181f, -0.174914f, -0.174722f, -0.174603f, -0.174535f, --0.174484f, -0.174419f, -0.174334f, -0.174257f, -0.174241f, --0.174339f, -0.174568f, -0.174897f, -0.175247f, -0.175527f, --0.175668f, -0.175649f, -0.175504f, -0.175302f, -0.175115f, --0.17499f, -0.174941f, -0.174946f, -0.174966f, -0.174962f, --0.174908f, -0.174796f, -0.174638f, -0.174464f, -0.174308f, --0.174196f, -0.174135f, -0.174112f, -0.174105f, -0.174099f, --0.1741f, -0.174129f, -0.174211f, -0.174347f, -0.174508f, --0.174639f, -0.174693f, -0.174653f, -0.174547f, -0.17444f, --0.174397f, -0.17446f, -0.174621f, -0.174834f, -0.175026f, --0.175129f, -0.175111f, -0.174973f, -0.174755f, -0.174506f, --0.174263f, -0.174042f, -0.173832f, -0.173617f, -0.173383f, --0.173135f, -0.172888f, -0.172667f, -0.172506f, -0.172432f, --0.172467f, -0.172611f, -0.172834f, -0.173088f, -0.173314f, --0.173464f, -0.173523f, -0.173511f, -0.173469f, -0.17344f, --0.173454f, -0.173512f, -0.173588f, -0.173645f, -0.173641f, --0.173557f, -0.173396f, -0.173188f, -0.172974f, -0.172789f, --0.172649f, -0.172556f, -0.172492f, -0.17244f, -0.172391f, --0.172346f, -0.17231f, -0.172284f, -0.172267f, -0.172255f, --0.172249f, -0.172253f, -0.172273f, -0.17231f, -0.172352f, --0.172388f, -0.172401f, -0.172379f, -0.172311f, -0.172176f, --0.171942f, -0.171573f, -0.17104f, -0.17034f, -0.169499f, --0.168562f, -0.16757f, -0.166543f, -0.165477f, -0.164352f, --0.163143f, -0.161835f, -0.160427f, -0.158922f, -0.157329f, --0.155643f, -0.153858f, -0.15196f, -0.149937f, -0.147782f, --0.145494f, -0.143082f, -0.14057f, -0.137992f, -0.135393f, --0.132824f, -0.130331f, -0.127944f, -0.12568f, -0.123532f, --0.121472f, -0.119454f, -0.117412f, -0.115278f, -0.112998f, --0.110548f, -0.107945f, -0.105239f, -0.102501f, -0.0997942f, --0.0971684f, -0.0946474f, -0.0922345f, -0.0899178f, -0.087684f, --0.0855244f, -0.0834364f, -0.0814211f, -0.0794707f, -0.0775634f, --0.0756617f, -0.0737202f, -0.0717019f, -0.0695945f, -0.0674152f, --0.0652053f, -0.0630127f, -0.0608754f, -0.0588116f, -0.056822f, --0.0549011f, -0.0530426f, -0.0512422f, -0.049497f, -0.0478024f, --0.0461557f, -0.0445622f, -0.0430403f, -0.0416186f, -0.0403259f, --0.0391799f, -0.0381777f, -0.0372926f, -0.0364776f, -0.0356725f, --0.0348179f, -0.0338654f, -0.0327897f, -0.0315966f, -0.0303215f, --0.0290217f, -0.0277614f, -0.0265938f, -0.0255459f, -0.0246139f, --0.0237676f, -0.0229666f, -0.0221815f, -0.0214062f, -0.0206548f, --0.0199489f, -0.0192999f, -0.0186995f, -0.0181225f, -0.0175376f, --0.0169217f, -0.0162671f, -0.015582f, -0.0148865f, -0.0142068f, --0.013571f, -0.0130013f, -0.0125088f, -0.0120878f, -0.0117106f, --0.0113307f, -0.010896f, -0.0103706f, -0.00975524f, -0.00909709f, --0.00847957f, -0.00799095f, -0.00768947f, -0.00757594f, -0.00759465f, --0.007658f, -0.00768306f, -0.00761927f, -0.00745677f, -0.00721301f, --0.0069087f, -0.00655204f, -0.00613803f, -0.00565728f, -0.0051098f, --0.00451485f, -0.00390879f, -0.00333665f, -0.00284016f, -0.00244591f, --0.00216087f, -0.00197292f, -0.00185468f, -0.00177376f, -0.0017025f, --0.00162463f, -0.00153632f, -0.00144381f, -0.00135502f, -0.00127151f, --0.00118363f, -0.00107486f, -0.000933489f, -0.000765153f, -0.000595878f, --0.000462136f, -0.000391149f, -0.000381636f, -0.00039948f, -0.000392457f, --0.00031506f, -0.000148614f, 9.0048e-05f, 0.00035786f, 0.000604245f, -0.000786303f, 0.000878787f, 0.000875978f, 0.000791694f, 0.000657695f, -0.00051893f, 0.000425818f, 0.000426074f, 0.000551054f, 0.000806885f, -0.00117476f, 0.00161695f, 0.00208652f, 0.00253376f, 0.00290882f, -0.00316028f, 0.00323814f, 0.00310475f, 0.00275044f, 0.00220837f, -0.00155712f, 0.000907431f, 0.000374364f, 4.94567e-05f, -2.10426e-05f, -0.000152468f, 0.000507839f, 0.000947469f, 0.00136192f, 0.00165448f, -0.00176273f, 0.00167267f, 0.00141913f, 0.00107273f, 0.000722145f, -0.000454802f, 0.000340469f, 0.000418315f, 0.000688105f, 0.00110894f, -0.00160413f, 0.00207832f, 0.00244585f, 0.00265788f, 0.0027142f, -0.00265461f, 0.00253537f, 0.00240031f, 0.00226566f, 0.00212575f, -0.00197065f, 0.00180602f, 0.00166146f, 0.00158237f, 0.00160939f, -0.00175419f, 0.00198981f, 0.00225835f, 0.00249251f, 0.00264239f, -0.00268974f, 0.00264634f, 0.00253697f, 0.00238428f, 0.00220657f, -0.00202457f, 0.00187327f, 0.00179975f, 0.00184459f, 0.00201759f, -0.00228424f, 0.00257413f, 0.00280859f, 0.00293672f, 0.00295574f, -0.00290479f, 0.0028433f, 0.00282479f, 0.00288132f, 0.00302619f, -0.00326351f, 0.00359044f, 0.00398678f, 0.00440043f, 0.00474437f, -0.00491837f, 0.00484987f, 0.00453341f, 0.00404398f, 0.00351183f, -0.00306889f, 0.00279655f, 0.00270115f, 0.0027279f, 0.00280162f, -0.00286887f, 0.00291904f, 0.00297615f, 0.00307301f, 0.00322684f, -0.00343021f, 0.00365863f, 0.003885f, 0.00409031f, 0.00426691f, -0.00441451f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f, -0f, 0f, 0f, 0f, 0f" - - -# HEC lookup table, time values -HEC_TIME -"0f, 1.03959f, 2.07917f, 3.11876f, 4.15835f, -5.19794f, 6.23752f, 7.27711f, 8.3167f, 9.35629f, -10.3959f, 11.4355f, 12.475f, 13.5146f, 14.5542f, -15.5938f, 16.6334f, 17.673f, 18.7126f, 19.7522f, -20.7917f, 21.8313f, 22.8709f, 23.9105f, 24.9501f, -25.9897f, 27.0293f, 28.0689f, 29.1084f, 30.148f, -31.1876f, 32.2272f, 33.2668f, 34.3064f, 35.346f, -36.3856f, 37.4251f, 38.4647f, 39.5043f, 40.5439f, -41.5835f, 42.6231f, 43.6627f, 44.7023f, 45.7418f, -46.7814f, 47.821f, 48.8606f, 49.9002f, 50.9398f, -51.9794f, 53.019f, 54.0585f, 55.0981f, 56.1377f, -57.1773f, 58.2169f, 59.2565f, 60.2961f, 61.3357f, -62.3752f, 63.4148f, 64.4544f, 65.494f, 66.5336f, -67.5732f, 68.6128f, 69.6524f, 70.6919f, 71.7315f, -72.7711f, 73.8107f, 74.8503f, 75.8899f, 76.9295f, -77.9691f, 79.0086f, 80.0482f, 81.0878f, 82.1274f, -83.167f, 84.2066f, 85.2462f, 86.2858f, 87.3253f, -88.3649f, 89.4045f, 90.4441f, 91.4837f, 92.5233f, -93.5629f, 94.6025f, 95.642f, 96.6816f, 97.7212f, -98.7608f, 99.8004f, 100.84f, 101.88f, 102.919f, -103.959f, 104.998f, 106.038f, 107.078f, 108.117f, -109.157f, 110.196f, 111.236f, 112.275f, 113.315f, -114.355f, 115.394f, 116.434f, 117.473f, 118.513f, -119.553f, 120.592f, 121.632f, 122.671f, 123.711f, -124.75f, 125.79f, 126.83f, 127.869f, 128.909f, -129.948f, 130.988f, 132.028f, 133.067f, 134.107f, -135.146f, 136.186f, 137.226f, 138.265f, 139.305f, -140.344f, 141.384f, 142.423f, 143.463f, 144.503f, -145.542f, 146.582f, 147.621f, 148.661f, 149.701f, -150.74f, 151.78f, 152.819f, 153.859f, 154.899f, -155.938f, 156.978f, 158.017f, 159.057f, 160.096f, -161.136f, 162.176f, 163.215f, 164.255f, 165.294f, -166.334f, 167.374f, 168.413f, 169.453f, 170.492f, -171.532f, 172.572f, 173.611f, 174.651f, 175.69f, -176.73f, 177.769f, 178.809f, 179.849f, 180.888f, -181.928f, 182.967f, 184.007f, 185.047f, 186.086f, -187.126f, 188.165f, 189.205f, 190.245f, 191.284f, -192.324f, 193.363f, 194.403f, 195.442f, 196.482f, -197.522f, 198.561f, 199.601f, 200.64f, 201.68f, -202.72f, 203.759f, 204.799f, 205.838f, 206.878f, -207.917f, 208.957f, 209.997f, 211.036f, 212.076f, -213.115f, 214.155f, 215.195f, 216.234f, 217.274f, -218.313f, 219.353f, 220.393f, 221.432f, 222.472f, -223.511f, 224.551f, 225.59f, 226.63f, 227.67f, -228.709f, 229.749f, 230.788f, 231.828f, 232.868f, -233.907f, 234.947f, 235.986f, 237.026f, 238.066f, -239.105f, 240.145f, 241.184f, 242.224f, 243.263f, -244.303f, 245.343f, 246.382f, 247.422f, 248.461f, -249.501f, 250.541f, 251.58f, 252.62f, 253.659f, -254.699f, 255.739f, 256.778f, 257.818f, 258.857f, -259.897f, 260.936f, 261.976f, 263.016f, 264.055f, -265.095f, 266.134f, 267.174f, 268.214f, 269.253f, -270.293f, 271.332f, 272.372f, 273.412f, 274.451f, -275.491f, 276.53f, 277.57f, 278.609f, 279.649f, -280.689f, 281.728f, 282.768f, 283.807f, 284.847f, -285.887f, 286.926f, 287.966f, 289.005f, 290.045f, -291.084f, 292.124f, 293.164f, 294.203f, 295.243f, -296.282f, 297.322f, 298.362f, 299.401f, 300.441f, -301.48f, 302.52f, 303.56f, 304.599f, 305.639f, -306.678f, 307.718f, 308.757f, 309.797f, 310.837f, -311.876f, 312.916f, 313.955f, 314.995f, 316.035f, -317.074f, 318.114f, 319.153f, 320.193f, 321.233f, -322.272f, 323.312f, 324.351f, 325.391f, 326.43f, -327.47f, 328.51f, 329.549f, 330.589f, 331.628f, -332.668f, 333.708f, 334.747f, 335.787f, 336.826f, -337.866f, 338.906f, 339.945f, 340.985f, 342.024f, -343.064f, 344.103f, 345.143f, 346.183f, 347.222f, -348.262f, 349.301f, 350.341f, 351.381f, 352.42f, -353.46f, 354.499f, 355.539f, 356.579f, 357.618f, -358.658f, 359.697f, 360.737f, 361.776f, 362.816f, -363.856f, 364.895f, 365.935f, 366.974f, 368.014f, -369.054f, 370.093f, 371.133f, 372.172f, 373.212f, -374.251f, 375.291f, 376.331f, 377.37f, 378.41f, -379.449f, 380.489f, 381.529f, 382.568f, 383.608f, -384.647f, 385.687f, 386.727f, 387.766f, 388.806f, -389.845f, 390.885f, 391.924f, 392.964f, 394.004f, -395.043f, 396.083f, 397.122f, 398.162f, 399.202f, -400.241f, 401.281f, 402.32f, 403.36f, 404.4f, -405.439f, 406.479f, 407.518f, 408.558f, 409.597f, -410.637f, 411.677f, 412.716f, 413.756f, 414.795f, -415.835f, 416.875f, 417.914f, 418.954f, 419.993f, -421.033f, 422.073f, 423.112f, 424.152f, 425.191f, -426.231f, 427.27f, 428.31f, 429.35f, 430.389f, -431.429f, 432.468f, 433.508f, 434.548f, 435.587f, -436.627f, 437.666f, 438.706f, 439.746f, 440.785f, -441.825f, 442.864f, 443.904f, 444.943f, 445.983f, -447.023f, 448.062f, 449.102f, 450.141f, 451.181f, -452.221f, 453.26f, 454.3f, 455.339f, 456.379f, -457.418f, 458.458f, 459.498f, 460.537f, 461.577f, -462.616f, 463.656f, 464.696f, 465.735f, 466.775f, -467.814f, 468.854f, 469.894f, 470.933f, 471.973f, -473.012f, 474.052f, 475.091f, 476.131f, 477.171f, -478.21f, 479.25f, 480.289f, 481.329f, 482.369f, -483.408f, 484.448f, 485.487f, 486.527f, 487.567f, -488.606f, 489.646f, 490.685f, 491.725f, 492.764f, -493.804f, 494.844f, 495.883f, 496.923f, 497.962f, -499.002f, 500.042f, 501.081f, 502.121f, 503.16f, -504.2f, 505.24f, 506.279f, 507.319f, 508.358f, -509.398f, 510.437f, 511.477f, 512.517f, 513.556f, -514.596f, 515.635f, 516.675f, 517.715f, 518.754f, -519.794f, 520.833f, 521.873f, 522.913f, 523.952f, -524.992f, 526.031f, 527.071f, 528.11f, 529.15f, -530.19f, 531.229f, 532.269f, 533.308f, 534.348f, -535.388f, 536.427f, 537.467f, 538.506f, 539.546f, -540.585f, 541.625f, 542.665f, 543.704f, 544.744f, -545.783f, 546.823f, 547.863f, 548.902f, 549.942f, -550.981f, 552.021f, 553.061f, 554.1f, 555.14f, -556.179f, 557.219f, 558.258f, 559.298f, 560.338f, -561.377f, 562.417f, 563.456f, 564.496f, 565.536f, -566.575f, 567.615f, 568.654f, 569.694f, 570.734f, -571.773f, 572.813f, 573.852f, 574.892f, 575.931f, -576.971f, 578.011f, 579.05f, 580.09f, 581.129f, -582.169f, 583.209f, 584.248f, 585.288f, 586.327f, -587.367f, 588.407f, 589.446f, 590.486f, 591.525f, -592.565f, 593.604f, 594.644f, 595.684f, 596.723f, -597.763f, 598.802f, 599.842f, 600.882f, 601.921f, -602.961f, 604f, 605.04f, 606.08f, 607.119f, -608.159f, 609.198f, 610.238f, 611.277f, 612.317f, -613.357f, 614.396f, 615.436f, 616.475f, 617.515f, -618.555f, 619.594f, 620.634f, 621.673f, 622.713f, -623.752f, 624.792f, 625.832f, 626.871f, 627.911f, -628.95f, 629.99f, 631.03f, 632.069f, 633.109f, -634.148f, 635.188f, 636.228f, 637.267f, 638.307f, -639.346f, 640.386f, 641.425f, 642.465f, 643.505f, -644.544f, 645.584f, 646.623f, 647.663f, 648.703f, -649.742f, 650.782f, 651.821f, 652.861f, 653.901f, -654.94f, 655.98f, 657.019f, 658.059f, 659.098f, -660.138f, 661.178f, 662.217f, 663.257f, 664.296f, -665.336f, 666.376f, 667.415f, 668.455f, 669.494f, -670.534f, 671.574f, 672.613f, 673.653f, 674.692f, -675.732f, 676.771f, 677.811f, 678.851f, 679.89f, -680.93f, 681.969f, 683.009f, 684.049f, 685.088f, -686.128f, 687.167f, 688.207f, 689.247f, 690.286f, -691.326f, 692.365f, 693.405f, 694.444f, 695.484f, -696.524f, 697.563f, 698.603f, 699.642f, 700.682f, -701.722f, 702.761f, 703.801f, 704.84f, 705.88f, -706.919f, 707.959f, 708.999f, 710.038f, 711.078f, -712.117f, 713.157f, 714.197f, 715.236f, 716.276f, -717.315f, 718.355f, 719.395f, 720.434f, 721.474f, -722.513f, 723.553f, 724.592f, 725.632f, 726.672f, -727.711f, 728.751f, 729.79f, 730.83f, 731.87f, -732.909f, 733.949f, 734.988f, 736.028f, 737.068f, -738.107f, 739.147f, 740.186f, 741.226f, 742.265f, -743.305f, 744.345f, 745.384f, 746.424f, 747.463f, -748.503f, 749.543f, 750.582f, 751.622f, 752.661f, -753.701f, 754.741f, 755.78f, 756.82f, 757.859f, -758.899f, 759.938f, 760.978f, 762.018f, 763.057f, -764.097f, 765.136f, 766.176f, 767.216f, 768.255f, -769.295f, 770.334f, 771.374f, 772.414f, 773.453f, -774.493f, 775.532f, 776.572f, 777.611f, 778.651f, -779.691f, 780.73f, 781.77f, 782.809f, 783.849f, -784.889f, 785.928f, 786.968f, 788.007f, 789.047f, -790.086f, 791.126f, 792.166f, 793.205f, 794.245f, -795.284f, 796.324f, 797.364f, 798.403f, 799.443f, -800.482f, 801.522f, 802.562f, 803.601f, 804.641f, -805.68f, 806.72f, 807.759f, 808.799f, 809.839f, -810.878f, 811.918f, 812.957f, 813.997f, 815.037f, -816.076f, 817.116f, 818.155f, 819.195f, 820.235f, -821.274f, 822.314f, 823.353f, 824.393f, 825.432f, -826.472f, 827.512f, 828.551f, 829.591f, 830.63f" diff --git a/graphics/AtlantisJava/configuration/rpsplt_tile.csv b/graphics/AtlantisJava/configuration/rpsplt_tile.csv deleted file mode 100644 index 213666c43c9..00000000000 --- a/graphics/AtlantisJava/configuration/rpsplt_tile.csv +++ /dev/null @@ -1,169 +0,0 @@ -# Real Pulse Shape Plots Lookup Table values for TILE calorimeter - -# TILE, time values -TILE_TIME -"-75.5f, -75f, -74.5f, -74f, -73.5f, --73f, -72.5f, -72f, -71.5f, -71f, --70.5f, -70f, -69.5f, -69f, -68.5f, --68f, -67.5f, -67f, -66.5f, -66f, --65.5f, -65f, -64.5f, -64f, -63.5f, --63f, -62.5f, -62f, -61.5f, -61f, --60.5f, -60f, -59.5f, -59f, -58.5f, --58f, -57.5f, -57f, -56.5f, -56f, --55.5f, -55f, -54.5f, -54f, -53.5f, --53f, -52.5f, -52f, -51.5f, -51f, --50.5f, -50f, -49.5f, -49f, -48.5f, --48f, -47.5f, -47f, -46.5f, -46f, --45.5f, -45f, -44.5f, -44f, -43.5f, --43f, -42.5f, -42f, -41.5f, -41f, --40.5f, -40f, -39.5f, -39f, -38.5f, --38f, -37.5f, -37f, -36.5f, -36f, --35.5f, -35f, -34.5f, -34f, -33.5f, --33f, -32.5f, -32f, -31.5f, -31f, --30.5f, -30f, -29.5f, -29f, -28.5f, --28f, -27.5f, -27f, -26.5f, -26f, --25.5f, -25f, -24.5f, -24f, -23.5f, --23f, -22.5f, -22f, -21.5f, -21f, --20.5f, -20f, -19.5f, -19f, -18.5f, --18f, -17.5f, -17f, -16.5f, -16f, --15.5f, -15f, -14.5f, -14f, -13.5f, --13f, -12.5f, -12f, -11.5f, -11f, --10.5f, -10f, -9.5f, -9f, -8.5f, --8f, -7.5f, -7f, -6.5f, -6f, --5.5f, -5f, -4.5f, -4f, -3.5f, --3f, -2.5f, -2f, -1.5f, -1f, --0.5f, 0f, 0.5f, 1f, 1.5f, -2f, 2.5f, 3f, 3.5f, 4f, -4.5f, 5f, 5.5f, 6f, 6.5f, -7f, 7.5f, 8f, 8.5f, 9f, -9.5f, 10f, 10.5f, 11f, 11.5f, -12f, 12.5f, 13f, 13.5f, 14f, -14.5f, 15f, 15.5f, 16f, 16.5f, -17f, 17.5f, 18f, 18.5f, 19f, -19.5f, 20f, 20.5f, 21f, 21.5f, -22f, 22.5f, 23f, 23.5f, 24f, -24.5f, 25f, 25.5f, 26f, 26.5f, -27f, 27.5f, 28f, 28.5f, 29f, -29.5f, 30f, 30.5f, 31f, 31.5f, -32f, 32.5f, 33f, 33.5f, 34f, -34.5f, 35f, 35.5f, 36f, 36.5f, -37f, 37.5f, 38f, 38.5f, 39f, -39.5f, 40f, 40.5f, 41f, 41.5f, -42f, 42.5f, 43f, 43.5f, 44f, -44.5f, 45f, 45.5f, 46f, 46.5f, -47f, 47.5f, 48f, 48.5f, 49f, -49.5f, 50f, 50.5f, 51f, 51.5f, -52f, 52.5f, 53f, 53.5f, 54f, -54.5f, 55f, 55.5f, 56f, 56.5f, -57f, 57.5f, 58f, 58.5f, 59f, -59.5f, 60f, 60.5f, 61f, 61.5f, -62f, 62.5f, 63f, 63.5f, 64f, -64.5f, 65f, 65.5f, 66f, 66.5f, -67f, 67.5f, 68f, 68.5f, 69f, -69.5f, 70f, 70.5f, 71f, 71.5f, -72f, 72.5f, 73f, 73.5f, 74f, -74.5f, 75f, 75.5f, 76f, 76.5f, -77f, 77.5f, 78f, 78.5f, 79f, -79.5f, 80f, 80.5f, 81f, 81.5f, -82f, 82.5f, 83f, 83.5f, 84f, -84.5f, 85f, 85.5f, 86f, 86.5f, -87f, 87.5f, 88f, 88.5f, 89f, -89.5f, 90f, 90.5f, 91f, 91.5f, -92f, 92.5f, 93f, 93.5f, 94f, -94.5f, 95f, 95.5f, 96f, 96.5f, -97f, 97.5f, 98f, 98.5f, 99f, -99.5f, 100f, 100.5f, 101f, 101.5f, -102f, 102.5f, 103f, 103.5f, 104f, -104.5f, 105f, 105.5f, 106f, 106.5f, -107f, 107.5f, 108f, 108.5f, 109f, -109.5f, 110f, 110.5f, 111f, 111.5f, -112f, 112.5f, 113f, 113.5f, 114f, -114.5f, 115f, 115.5f, 116f, 116.5f, -117f, 117.5f, 118f, 118.5f, 119f, -119.5f, 120f, 120.5f, 121f, 121.5f, -122f, 122.5f, 123f, 123.5f, 124f, -124.5f" - -# TILE, amplitude values -TILE_AMPLITUDE -"0f, 2.304e-05f, 5.178e-05f, 8.592e-05f, 0.00012515f, -0.00016918f, 0.0002177f, 0.00027043f, 0.00032705f, 0.00038728f, -0.00045081f, 0.00051733f, 0.00058656f, 0.00065819f, 0.00073193f, -0.00080746f, 0.0008845f, 0.00096275f, 0.0010419f, 0.00112166f, -0.00120172f, 0.00128179f, 0.00136157f, 0.00144076f, 0.00151905f, -0.00159642f, 0.0016754f, 0.00176001f, 0.00185428f, 0.00196225f, -0.00208795f, 0.00223542f, 0.00240868f, 0.00261177f, 0.00284873f, -0.00312358f, 0.00344037f, 0.00380312f, 0.00421586f, 0.00468264f, -0.00520748f, 0.00579479f, 0.00645263f, 0.00719117f, 0.00802059f, -0.00895106f, 0.00999278f, 0.0111559f, 0.0124507f, 0.0138872f, -0.0154757f, 0.0172264f, 0.0191494f, 0.0212549f, 0.0235531f, -0.0260541f, 0.0287667f, 0.0316991f, 0.0348593f, 0.0382556f, -0.041896f, 0.0457887f, 0.0499419f, 0.0543637f, 0.0590621f, -0.0640455f, 0.0693218f, 0.0748993f, 0.0807861f, 0.0869903f, -0.09352f, 0.100383f, 0.107581f, 0.115115f, 0.122983f, -0.131184f, 0.139719f, 0.148586f, 0.157786f, 0.167316f, -0.177177f, 0.187369f, 0.19789f, 0.208739f, 0.219917f, -0.231423f, 0.243248f, 0.255385f, 0.267822f, 0.28055f, -0.29356f, 0.306842f, 0.320385f, 0.334181f, 0.348219f, -0.362489f, 0.376982f, 0.391688f, 0.406597f, 0.421699f, -0.436986f, 0.452445f, 0.46806f, 0.483808f, 0.499668f, -0.515617f, 0.531635f, 0.547698f, 0.563786f, 0.579876f, -0.595946f, 0.611975f, 0.62794f, 0.64382f, 0.659592f, -0.675236f, 0.69073f, 0.706053f, 0.721186f, 0.736109f, -0.7508f, 0.76524f, 0.779408f, 0.793285f, 0.806849f, -0.82008f, 0.832959f, 0.845464f, 0.857576f, 0.869274f, -0.880538f, 0.891349f, 0.901693f, 0.911564f, 0.920954f, -0.929854f, 0.938257f, 0.946156f, 0.953541f, 0.960406f, -0.966742f, 0.972542f, 0.977798f, 0.982501f, 0.986645f, -0.990222f, 0.993234f, 0.995685f, 0.997581f, 0.998929f, -0.999733f, 1f, 0.999735f, 0.998944f, 0.997632f, -0.995806f, 0.99347f, 0.99063f, 0.987293f, 0.983464f, -0.979148f, 0.974352f, 0.969089f, 0.963376f, 0.957231f, -0.95067f, 0.943711f, 0.936371f, 0.928666f, 0.920615f, -0.912235f, 0.903542f, 0.894553f, 0.885287f, 0.875759f, -0.865988f, 0.855985f, 0.845763f, 0.835332f, 0.824704f, -0.81389f, 0.8029f, 0.791746f, 0.780439f, 0.768991f, -0.757412f, 0.745713f, 0.733906f, 0.722002f, 0.710012f, -0.697947f, 0.685818f, 0.673635f, 0.66141f, 0.649153f, -0.636873f, 0.624581f, 0.612288f, 0.600004f, 0.587739f, -0.575503f, 0.563307f, 0.551161f, 0.539076f, 0.527062f, -0.515129f, 0.503286f, 0.491542f, 0.479906f, 0.468386f, -0.456991f, 0.445729f, 0.434609f, 0.42364f, 0.412831f, -0.402189f, 0.391724f, 0.381444f, 0.371358f, 0.361474f, -0.351802f, 0.342348f, 0.333115f, 0.3241f, 0.315301f, -0.306715f, 0.298339f, 0.290172f, 0.282211f, 0.274453f, -0.266897f, 0.259539f, 0.252377f, 0.245409f, 0.238632f, -0.232044f, 0.225642f, 0.219421f, 0.213379f, 0.207511f, -0.201813f, 0.196283f, 0.190915f, 0.185707f, 0.180655f, -0.175755f, 0.171003f, 0.166395f, 0.161928f, 0.157598f, -0.153402f, 0.149335f, 0.145394f, 0.141575f, 0.137874f, -0.134288f, 0.130813f, 0.127445f, 0.12418f, 0.121015f, -0.117947f, 0.11497f, 0.112082f, 0.109278f, 0.106556f, -0.103911f, 0.10134f, 0.0988427f, 0.0964156f, 0.0940569f, -0.0917646f, 0.0895367f, 0.0873709f, 0.0852652f, 0.0832176f, -0.0812259f, 0.0792881f, 0.0774021f, 0.0755657f, 0.0737769f, -0.0720337f, 0.0703338f, 0.0686753f, 0.0670561f, 0.065474f, -0.0639269f, 0.0624129f, 0.0609298f, 0.0594755f, 0.0580479f, -0.0566449f, 0.0552645f, 0.0539046f, 0.052563f, 0.0512377f, -0.0499268f, 0.0486296f, 0.0473466f, 0.0460778f, 0.0448235f, -0.0435841f, 0.0423598f, 0.0411508f, 0.0399573f, 0.0387798f, -0.0376183f, 0.0364732f, 0.0353447f, 0.0342331f, 0.0331386f, -0.0320615f, 0.0310021f, 0.0299605f, 0.0289372f, 0.0279322f, -0.0269459f, 0.0259786f, 0.0250305f, 0.0241018f, 0.0231928f, -0.0223038f, 0.021435f, 0.0205867f, 0.0197591f, 0.0189525f, -0.0181671f, 0.017403f, 0.01666f, 0.0159379f, 0.0152367f, -0.0145562f, 0.0138962f, 0.0132567f, 0.0126374f, 0.0120383f, -0.0114592f, 0.0109f, 0.0103606f, 0.00984081f, 0.00934049f, -0.00885952f, 0.00839776f, 0.00795509f, 0.00753137f, 0.00712647f, -0.00674024f, 0.00637256f, 0.0060233f, 0.00569231f, 0.00537947f, -0.00508463f, 0.00480767f, 0.00454845f, 0.00430684f, 0.0040827f, -0.00387587f, 0.00368583f, 0.00351191f, 0.00335339f, 0.0032096f, -0.00307982f, 0.00296336f, 0.00285953f, 0.00276764f, 0.00268698f, -0.00261686f, 0.00255658f, 0.00250545f, 0.00246277f, 0.00242785f, -0.00239998f, 0.00237849f, 0.00236265f, 0.00235179f, 0.00234521f, -0.0023422f, 0.00234208f, 0.00234415f, 0.0023477f, 0.00235206f, -0.00235651f, 0.00236036f, 0.00236293f, 0.0023635f, 0.00236139f, -0.00235594f, 0.00234693f, 0.00233436f, 0.00231825f, 0.00229862f, -0.00227549f, 0.00224886f, 0.00221876f, 0.0021852f, 0.00214819f, -0.00210775f, 0.0020639f, 0.00201666f, 0.00196603f, 0.00191204f, -0.0018547f" diff --git a/graphics/AtlantisJava/events/event.dtd b/graphics/AtlantisJava/events/event.dtd deleted file mode 100755 index e9937b30976..00000000000 --- a/graphics/AtlantisJava/events/event.dtd +++ /dev/null @@ -1,506 +0,0 @@ -<!-- -kine element is alias to barcode resp. to new-style truth association - using barcodes + numBarcodes (1 hits - to more tracks) at hits - (2006/08), kine should be removed completely on turn 2006/2007 ---> - -<!ENTITY % string.Type "CDATA"> - -<!ENTITY % eventAttributes - "version %string.Type; #IMPLIED - runNumber %string.Type; #IMPLIED - eventNumber %string.Type; #IMPLIED - dateTime %string.Type; #IMPLIED - lumiBlock %string.Type; #IMPLIED - eventProperties %string.Type; #IMPLIED"> - - -<!ELEMENT Event - (BJet|CaloETMis|Cluster|CompositeParticle|CSC|CSCD|Electron|EmTauROI| - ETMis|FCAL|HEC|IDScan|iPat|Jet|JetROI|LAr|LVL1JetElement|LVL1Result| - LVL1TriggerTower|MBTS|MDT|MSeg|Muon|MuonETMis|MuonROI|ParticleJet| - Photon|PixelRDO|RMTr|RPC|RTr|RVx|S3D|SCTRDO|Segment|SiHit|SMTr|STC|STr| - TauJet|TGC|TILE|Track|TrigS3D|TriggerInfo|TRT|xKal)+> -<!ATTLIST Event %eventAttributes;> - -<!ENTITY % attributes 'count CDATA "" storeGateKey CDATA ""'> - -<!ENTITY % type 'type (FLOAT|INT|STRING) #FIXED'> -<!ENTITY % unit 'unit (NONE | CM | RAD | GEV)'> -<!ENTITY % integer - ' %type; "INT" - multiple CDATA "1" - %unit; "NONE" '> -<!ENTITY % float - ' %type; "FLOAT" - multiple CDATA "1" - %unit; "NONE" '> -<!ENTITY % string - ' %type; "STRING" - multiple CDATA "1" - %unit; "NONE" '> - -<!ELEMENT BJet (charge|clusterIndex|clusterKey|clusterLinkCount|energy| - eta|label|lhSig|mass|phi|pt|secVtxCount|secVtxFitProb|secVtxMass| - secVtxMult|secVtxRPhiDist|secVtxTagLh|secVtxTagLhErr| - trackIndex|trackKey|trackLinkCount|weight)+> -<!ATTLIST BJet %attributes;> - -<!ELEMENT CaloETMis (et|etx|ety)+> -<!ATTLIST CaloETMis %attributes;> - -<!ELEMENT Cluster (cells|energy|emfrac|et|eta|id|numCells|phi)+> -<!ATTLIST Cluster %attributes;> - -<!ELEMENT CompositeParticle (author|charge|dataType|daughterIndex|daughterKey| - daughterPdgId|eta|label|pdgId|phi|pt|typeEV)+> -<!ATTLIST CompositeParticle %attributes;> - -<!ELEMENT CSC (barcode|hitsFull|id|identifier|kine|length|numHits|sigma| - x|y|z)+> -<!ATTLIST CSC %attributes;> - -<!ELEMENT CSCD (barcode|charge|id|identifier|kine|length|x|y|z)+> -<!ATTLIST CSCD %attributes;> - -<!ELEMENT Electron (author|clusterIndex|clusterKey|clusterLinkCount|dataType| - emWeight|eOverp|et37|eta|etCone|etCone20|etHad1|f1|fracs1| - hasTrack|hitsBLayer|hitsHighThresTRT|hitsPixel|hitsSCT| - hitsTRT|isEM|isEMString|pdgId|phi|pionWeight|pt|trackIndex|trackKey| - trackLinkCount)+> -<!ATTLIST Electron %attributes;> - -<!ELEMENT EmTauROI (energy|energyEM|energyTAU|eta|phi|roiWord|thrPattern)+> -<!ATTLIST EmTauROI %attributes;> - -<!ELEMENT ETMis (et|etx|ety)+> -<!ATTLIST ETMis %attributes;> - -<!ELEMENT FCAL (adc2Mev|adcCounts|cluster|dx|dy|energy|id|layer|sub| - x|y|channel|feedThrough|slot)+> -<!ATTLIST FCAL %attributes;> - -<!ELEMENT HEC (adc2Mev|adcCounts|energy|eta|id|layer|phi|sub| - cluster|channel|feedThrough|slot)+> -<!ATTLIST HEC %attributes;> - -<!ELEMENT IDScan (barcode|chi2|cotTheta|covMatrix|d0|hits|id|numHits| - phi0|pt|z0)+> -<!ATTLIST IDScan %attributes;> - -<!ELEMENT InDetSegment (hits|numHits|phi|theta|x|y|z)+> -<!ATTLIST InDetSegment %attributes;> - -<!ELEMENT iPat (barcode|chi2|cotTheta|covMatrix|d0|hits| - id|kine|numHits|numPolyline|phi0|polylineX|polylineY| - polylineZ|pt|z0)+> -<!ATTLIST iPat %attributes;> - -<!-- cluster should be an array of calo Cluster IDs, but it's not provided in - the event files nor any processing exists in the Jet handling code --> -<!ELEMENT Jet (OutOfTimeEfrac|bTagName|bTagValue|cells|cluster|clusterIndex|clusterKey|clusterLinkCount| - emfrac|et|eta|fcorCell|fcorDotx|fcorJet|fcorJetForCell|fracSamplingMax|hecf| - isBad|isGood|isUgly|n90cells|n90const|nbadcells|id|jvf|numCells|phi|pt| - quality|qualityLAr|qualityTile|sMax|tileGap3f|time|timeClusters|trackIndex|trackKey| - trackLinkCount|mass|px|py|pz)+> -<!ATTLIST Jet %attributes;> - -<!ELEMENT JetROI (energy|eta|phi)+> -<!ATTLIST JetROI %attributes;> - -<!ELEMENT LAr (adc2Mev|adcCounts|BadCell|cellGain|cellPedestal|cellTime|cluster| - energy|eta|id|layer|phi|sub|channel|feedThrough|slot)+> -<!ATTLIST LAr %attributes;> - -<!ELEMENT LVL1JetElement (energy|eta|phi)+> -<!ATTLIST LVL1JetElement %attributes;> - -<!ELEMENT LVL1Result (ctpItemList|ctpWord0|ctpWord1|ctpWord2| - energyEtMiss|energyEx|energyEy|energySumEt| - itemListEF|itemListL2|passedEF|passedL1|passedL2| - passedTrigger|prescaleListEF|prescaleListL1|prescaleListL2)+> -<!ATTLIST LVL1Result %attributes;> - -<!ELEMENT LVL1TriggerTower (emADC|emBCID|emEnergy|eta|hadADC|hadBCID|hadEnergy| - isEMSaturated|isHadSaturated|numADC|phi|sumEnergy)+> -<!ATTLIST LVL1TriggerTower %attributes;> - -<!ELEMENT MBTS (channel|energy|eta|label|module|phi|quality|sampling|time|type| - adcCounts|cellPedestal|cellRawAmplitude|cellRawTime)+> -<!ATTLIST MBTS %attributes;> - -<!ELEMENT MDT (barcode|driftR|id|identifier|kine|length|x|y|z)+> -<!ATTLIST MDT %attributes;> - -<!ELEMENT MSeg (cotTheta|hits|numHits|phi0|x|y|z)+> -<!ATTLIST MSeg %attributes;> - -<!ELEMENT Muon (author|chi2|dataType|eta|etConeIsol|pdgId|phi|pt| - trackIndex|trackKey|trackLinkCount)+> -<!ATTLIST Muon %attributes;> - -<!ELEMENT MuonETMis (et|etx|ety)+> -<!ATTLIST MuonETMis %attributes;> - -<!ELEMENT MuonROI (energy|eta|phi|roiWord|thrName|thrNumber|thrValue)+> -<!ATTLIST MuonROI %attributes;> - -<!ELEMENT MuonSegment (hits|numHits|phi|theta|x|y|z)+> -<!ATTLIST MuonSegment %attributes;> - -<!ELEMENT ParticleJet (cells|cluster|et|eta|id|numCells|phi|pt)+> -<!ATTLIST ParticleJet %attributes;> - -<!ELEMENT PixCluster (barcode|barcodes|eloss|etaModule|id|numBarcodes| - phiModule|widthx|widthy|x0|y0|z0)+> -<!ATTLIST PixCluster %attributes;> - -<!ELEMENT Photon (clusterIndex|clusterKey|clusterLinkCount|emWeight|et37| - eta|etCone|etHad1|f1|fracs1|isEM|isEMString|phi|pionWeight|pt)+> -<!ATTLIST Photon %attributes;> - -<!-- PixelRDO - object derived from S3D --> -<!ELEMENT PixelRDO (etaModule|id|phiModule|x|y|z)+> -<!ATTLIST PixelRDO %attributes;> - -<!ELEMENT RMTr (barcode|cotTheta|hits|hitsFull|id|kine|numHits| - numPolyline|phi0|polylineX|polylineY|polylineZ|pt| - x|y|z)+> -<!ATTLIST RMTr %attributes;> - -<!ELEMENT RPC (barcode|id|identifier|kine|length|width|x|y|z)+> -<!ATTLIST RPC %attributes;> - -<!ELEMENT RTr (barcode|chi2|cotTheta|covMatrix|d0|kine|phi0|pt|z0)+> -<!ATTLIST RTr %attributes;> - -<!ELEMENT RVx (chi2|covMatrix|numTracks|vertexType|primVxCand| - sgkey|tracks|x|y|z)+> -<!ATTLIST RVx %attributes;> - -<!ELEMENT S3D (barcode|barcodes|clusters|etaModule|kine|numBarcodes|phi| - phiModule|rho|x|y|z)+> -<!ATTLIST S3D %attributes;> - -<!-- SCTRDO - object derived from STC (SiCluster) --> -<!ELEMENT SCTRDO (BCIDError|etaModule|firstHitError|formatterError|id| - lvl1Error|phiModule|preambleError|secondHitError| - syncError|timeBin|x0|x1|y0|y1|z0|z1)+> -<!ATTLIST SCTRDO %attributes;> - -<!ELEMENT Segment (hits|numHits|phi|theta|x|y|z)+> -<!ATTLIST Segment %attributes;> - -<!ELEMENT SiHit (energyloss|trackid|x|y|z)+> -<!ATTLIST SiHit %attributes;> - -<!ELEMENT SMTr (barcode|cotTheta|id|kine|phi0|pt|x|y|z)+> -<!ATTLIST SMTr %attributes;> - -<!ELEMENT STC (barcode|barcodes|etaModule|id|kine|numBarcodes| - phiModule|widthside|x0|x1|y0|y1|z0|z1)+> -<!ATTLIST STC %attributes;> - -<!ELEMENT STr (barcode|code|eta|id|phi|phiEndVertex|phiVertex|pt| - rhoEndVertex|rhoVertex|zVertex|zEndVertex)+> -<!ATTLIST STr %attributes;> - -<!ELEMENT TauJet (author|charge|clusterIndex|clusterKey|clusterLinkCount| - emRadius|eta|etEMCalib|etHadCalib|isolFrac|isTau|isTauString| - logLhRatio|numTracks|phi|pt|stripWidth|trackIndex| - trackKey|trackLinkCount)+> -<!ATTLIST TauJet %attributes;> - -<!ELEMENT TGC (barcode|id|identifier|kine|length|lwidth|swidth| - x|y|z)+> -<!ATTLIST TGC %attributes;> - -<!ELEMENT TILE (adcCounts1|adcCounts2|BadCell|cluster|energy|eta|id|layer|phi| - pmt1Chi2|pmt1Energy|pmt1Gain|pmt1Number|pmt1Pedestal| - pmt1Time|pmt2Chi2|pmt2Energy|pmt2Gain|pmt2Number| - pmt2Pedestal|pmt2Time|sub|pmt1ADCStatus|pmt2ADCStatus| - pmt1RawTime|pmt2RawTime|pmt1RawAmplitude|pmt2RawAmplitude)+> -<!ATTLIST TILE %attributes;> - -<!ELEMENT Track (author|barcode|chi2|cotTheta|covMatrix|d0|driftSign|hits|id| - isOutlier|kine|numHits|numPolyline|numTsos|phi0|polylineX| - polylineY|polylineZ|pt|tsosDetType|tsosPosR|tsosPullLoc1| - tsosPullLoc2|tsosResLoc1|tsosResLoc2|trackAuthor|z0|numDoF| - nBLayerHits|nPixHits|nSCTHits|nTRTHits)+> -<!ATTLIST Track %attributes;> - -<!ELEMENT TrigS3D (barcodes|cluster|dphi|dr|dz|eta|id|layer|numBarcodes|phi| - r|x|y|z)+> -<!ATTLIST TrigS3D %attributes;> - -<!ELEMENT TriggerInfo (energyEtMiss|energyEx|energyEy|energySumEt| - trigInfoEF|trigInfoExtL1ID|trigInfoL1|trigInfoL2| - trigInfoLvl1Type|trigInfoStatus|trigInfoStreamTag)+> -<!ATTLIST TriggerInfo %attributes;> - -<!ELEMENT TRT (barcode|barcodes|driftR|id|kine|numBarcodes|phi|rhoz|sub| - threshold|noise|bitPattern|timeOverThreshold)+> -<!ATTLIST TRT %attributes;> - -<!ELEMENT xKal (barcode|chi2|cotTheta|covMatrix|d0|hits| - id|numHits|numPolyline|phi0|polylineX|polylineY| - polylineZ|pt|z0)+> -<!ATTLIST xKal %attributes;> - -<!ELEMENT OutOfTimeEfrac (#PCDATA)> <!ATTLIST OutOfTimeEfrac %float;> -<!ELEMENT adc2Mev (#PCDATA)> <!ATTLIST adc2Mev %float;> -<!ELEMENT adcCounts (#PCDATA)> <!ATTLIST adcCounts %integer;> -<!ELEMENT adcCounts1 (#PCDATA)> <!ATTLIST adcCounts1 %integer;> -<!ELEMENT adcCounts2 (#PCDATA)> <!ATTLIST adcCounts2 %integer;> -<!ELEMENT author (#PCDATA)> <!ATTLIST author %string;> -<!ELEMENT BadCell (#PCDATA)> <!ATTLIST BadCell %integer;> -<!ELEMENT barcode (#PCDATA)> <!ATTLIST barcode %integer;> -<!ELEMENT barcodes (#PCDATA)> <!ATTLIST barcodes %integer;> -<!ELEMENT bitPattern (#PCDATA)> <!ATTLIST bitPattern %integer;> -<!ELEMENT BCIDError (#PCDATA)> <!ATTLIST BCIDError %integer;> -<!ELEMENT bTagName (#PCDATA)> <!ATTLIST bTagName %string;> -<!ELEMENT bTagValue (#PCDATA)> <!ATTLIST bTagValue %float;> -<!ELEMENT cellTime (#PCDATA)> <!ATTLIST cellTime %float;> -<!ELEMENT cellGain (#PCDATA)> <!ATTLIST cellGain %integer;> -<!ELEMENT cellPedestal (#PCDATA)> <!ATTLIST cellPedestal %float;> -<!ELEMENT cells (#PCDATA)> <!ATTLIST cells %integer;> -<!ELEMENT channel (#PCDATA)> <!ATTLIST channel %integer;> -<!ELEMENT feedThrough (#PCDATA)> <!ATTLIST feedThrough %integer;> -<!ELEMENT slot (#PCDATA)> <!ATTLIST slot %integer;> -<!ELEMENT charge (#PCDATA)> <!ATTLIST charge %float;> -<!ELEMENT chi2 (#PCDATA)> <!ATTLIST chi2 %float;> -<!ELEMENT cluster (#PCDATA)> <!ATTLIST cluster %integer;> -<!ELEMENT clusters (#PCDATA)> <!ATTLIST clusters %integer;> -<!ELEMENT clusterIndex (#PCDATA)> <!ATTLIST clusterIndex %integer;> -<!ELEMENT clusterKey (#PCDATA)> <!ATTLIST clusterKey %string;> -<!ELEMENT clusterLinkCount (#PCDATA)> <!ATTLIST clusterKey %integer;> -<!ELEMENT code (#PCDATA)> <!ATTLIST code %integer;> -<!ELEMENT cotTheta (#PCDATA)> <!ATTLIST cotTheta %float;> -<!ELEMENT covMatrix (#PCDATA)> <!ATTLIST covMatrix %float;> -<!ELEMENT ctpItemList (#PCDATA)> <!ATTLIST ctpItemList %string;> -<!ELEMENT ctpWord0 (#PCDATA)> <!ATTLIST ctpWord0 %integer;> -<!ELEMENT ctpWord1 (#PCDATA)> <!ATTLIST ctpWord1 %integer;> -<!ELEMENT ctpWord2 (#PCDATA)> <!ATTLIST ctpWord2 %integer;> -<!ELEMENT d0 (#PCDATA)> <!ATTLIST d0 %float;> -<!ELEMENT dataType (#PCDATA)> <!ATTLIST dataType %integer;> -<!ELEMENT daughterIndex (#PCDATA)> <!ATTLIST daughterIndex %integer;> -<!ELEMENT daughterKey (#PCDATA)> <!ATTLIST daughterKey %string;> -<!ELEMENT daughterPdgId (#PCDATA)> <!ATTLIST daughterPdgId %integer;> -<!ELEMENT deta (#PCDATA)> <!ATTLIST deta %float;> -<!ELEMENT dphi (#PCDATA)> <!ATTLIST dphi %float;> -<!ELEMENT dr (#PCDATA)> <!ATTLIST dr %float;> -<!ELEMENT driftR (#PCDATA)> <!ATTLIST driftR %float;> -<!ELEMENT driftSign (#PCDATA)> <!ATTLIST driftSign %integer;> -<!ELEMENT dx (#PCDATA)> <!ATTLIST dx %float;> -<!ELEMENT dy (#PCDATA)> <!ATTLIST dy %float;> -<!ELEMENT dz (#PCDATA)> <!ATTLIST dz %float;> -<!ELEMENT eloss (#PCDATA)> <!ATTLIST eloss %float;> -<!ELEMENT emfrac (#PCDATA)> <!ATTLIST emfrac %float;> -<!ELEMENT emADC (#PCDATA)> <!ATTLIST emADC %integer;> -<!ELEMENT emBCID (#PCDATA)> <!ATTLIST emBCID %integer;> -<!ELEMENT emEnergy (#PCDATA)> <!ATTLIST emEnergy %float;> -<!ELEMENT emRadius (#PCDATA)> <!ATTLIST emRadius %float;> -<!ELEMENT emWeight (#PCDATA)> <!ATTLIST emWeight %float;> -<!ELEMENT energy (#PCDATA)> <!ATTLIST energy %float;> -<!ELEMENT energyEM (#PCDATA)> <!ATTLIST energyEM %float;> -<!ELEMENT energyTAU (#PCDATA)> <!ATTLIST energyTAU %float;> -<!ELEMENT energyEtMiss (#PCDATA)> <!ATTLIST energyEtMiss %float;> -<!ELEMENT energyEx (#PCDATA)> <!ATTLIST energyEx %float;> -<!ELEMENT energyEy (#PCDATA)> <!ATTLIST energyEy %float;> -<!ELEMENT energyloss (#PCDATA)> <!ATTLIST energyloss %float;> -<!ELEMENT energySumEt (#PCDATA)> <!ATTLIST energySumEt %float;> -<!ELEMENT eOverp (#PCDATA)> <!ATTLIST eOverp %float;> -<!ELEMENT et (#PCDATA)> <!ATTLIST et %float;> -<!ELEMENT et37 (#PCDATA)> <!ATTLIST et37 %float;> -<!ELEMENT eta (#PCDATA)> <!ATTLIST eta %float;> -<!ELEMENT etaModule (#PCDATA)> <!ATTLIST etaModule %integer;> -<!ELEMENT etCone (#PCDATA)> <!ATTLIST etCone %float;> -<!ELEMENT etCone20 (#PCDATA)> <!ATTLIST etCone20 %float;> -<!ELEMENT etEMCalib (#PCDATA)> <!ATTLIST etEMCalib %float;> -<!ELEMENT etHad1 (#PCDATA)> <!ATTLIST etHad1 %float;> -<!ELEMENT etHadCalib (#PCDATA)> <!ATTLIST etHadCalib %float;> -<!ELEMENT etx (#PCDATA)> <!ATTLIST etx %float;> -<!ELEMENT ety (#PCDATA)> <!ATTLIST ety %float;> -<!ELEMENT etConeIsol (#PCDATA)> <!ATTLIST etConeIsol %float;> -<!ELEMENT f1 (#PCDATA)> <!ATTLIST f1 %float;> -<!ELEMENT firstHitError (#PCDATA)> <!ATTLIST firstHitError %integer;> -<!ELEMENT fcorCell (#PCDATA)> <!ATTLIST fcorCell %float;> -<!ELEMENT fcorDotx (#PCDATA)> <!ATTLIST fcorDotx %float;> -<!ELEMENT fcorJet (#PCDATA)> <!ATTLIST fcorJet %float;> -<!ELEMENT fcorJetForCell (#PCDATA)> <!ATTLIST fcorJetForCell %float;> -<!ELEMENT formatterError (#PCDATA)> <!ATTLIST formatterError %integer;> -<!ELEMENT fracs1 (#PCDATA)> <!ATTLIST fracs1 %float;> -<!ELEMENT fracSamplingMax (#PCDATA)> <!ATTLIST fracSamplingMax %float;> -<!ELEMENT hadADC (#PCDATA)> <!ATTLIST hadADC %integer;> -<!ELEMENT hadBCID (#PCDATA)> <!ATTLIST hadBCID %integer;> -<!ELEMENT hadEnergy (#PCDATA)> <!ATTLIST hadEnergy %float;> -<!ELEMENT hasTrack (#PCDATA)> <!ATTLIST hasTrack %integer;> -<!ELEMENT hecf (#PCDATA)> <!ATTLIST hecf %float;> -<!ELEMENT hits (#PCDATA)> <!ATTLIST hits %integer;> -<!ELEMENT hitsBLayer (#PCDATA)> <!ATTLIST hitsBLayer %integer;> -<!ELEMENT hitsFull (#PCDATA)> <!ATTLIST hitsFull %string;> -<!ELEMENT hitsHighThresTRT (#PCDATA)> <!ATTLIST hitsHighThresTRT %integer;> -<!ELEMENT hitsPixel (#PCDATA)> <!ATTLIST hitsPixel %integer;> -<!ELEMENT hitsSCT (#PCDATA)> <!ATTLIST hitsSCT %integer;> -<!ELEMENT hitsTRT (#PCDATA)> <!ATTLIST hitsTRT %integer;> -<!ELEMENT id (#PCDATA)> <!ATTLIST id %integer;> -<!ELEMENT identifier (#PCDATA)> <!ATTLIST identifier %string;> -<!ELEMENT isBad (#PCDATA)> <!ATTLIST isBad %float;> -<!ELEMENT isEM (#PCDATA)> <!ATTLIST isEM %integer;> -<!ELEMENT isEMString (#PCDATA)> <!ATTLIST isEMString %string;> -<!ELEMENT isEMSaturated (#PCDATA)> <!ATTLIST isEMSaturated %integer;> -<!ELEMENT isGood (#PCDATA)> <!ATTLIST isGood %float;> -<!ELEMENT isHadSaturated (#PCDATA)> <!ATTLIST isHadSaturated %integer;> -<!ELEMENT isTau (#PCDATA)> <!ATTLIST isTau %integer;> -<!ELEMENT isTauString (#PCDATA)> <!ATTLIST isTauString %string;> -<!ELEMENT isUgly (#PCDATA)> <!ATTLIST isUgly %float;> -<!ELEMENT isolated (#PCDATA)> <!ATTLIST isolated %integer;> -<!ELEMENT isolFrac (#PCDATA)> <!ATTLIST isolFrac %float;> -<!ELEMENT isOutlier (#PCDATA)> <!ATTLIST isOutlier %integer;> -<!ELEMENT itemListEF (#PCDATA)> <!ATTLIST itemListEF %string;> -<!ELEMENT itemListL2 (#PCDATA)> <!ATTLIST itemListL2 %string;> -<!ELEMENT jvf (#PCDATA)> <!ATTLIST jvf %float;> -<!ELEMENT kine (#PCDATA)> <!ATTLIST kine %integer;> -<!ELEMENT label (#PCDATA)> <!ATTLIST label %string;> -<!ELEMENT layer (#PCDATA)> <!ATTLIST layer %integer;> -<!ELEMENT length (#PCDATA)> <!ATTLIST length %float;> -<!ELEMENT lhSig (#PCDATA)> <!ATTLIST lhSig %float;> -<!ELEMENT logLhRatio (#PCDATA)> <!ATTLIST logLhRatio %float;> -<!ELEMENT lvl1Error (#PCDATA)> <!ATTLIST lvl1Error %integer;> -<!ELEMENT lwidth (#PCDATA)> <!ATTLIST lwidth %float; > -<!ELEMENT mass (#PCDATA)> <!ATTLIST mass %float;> -<!ELEMENT module (#PCDATA)> <!ATTLIST module %integer;> -<!ELEMENT nbadcells (#PCDATA)> <!ATTLIST nbadcells %integer;> -<!ELEMENT noise (#PCDATA)> <!ATTLIST noise %integer;> -<!ELEMENT nBLayerHits (#PCDATA)> <!ATTLIST nBLayerHits %integer;> -<!ELEMENT nPixHits (#PCDATA)> <!ATTLIST nPixHits %integer;> -<!ELEMENT nSCTHits (#PCDATA)> <!ATTLIST nSCTHits %integer;> -<!ELEMENT nTRTHits (#PCDATA)> <!ATTLIST nTRTHits %integer;> -<!ELEMENT n90cells (#PCDATA)> <!ATTLIST n90cells %integer;> -<!ELEMENT n90const (#PCDATA)> <!ATTLIST n90const %integer;> -<!ELEMENT numADC (#PCDATA)> <!ATTLIST numADC %integer;> -<!ELEMENT numBarcodes (#PCDATA)> <!ATTLIST numBarcodes %integer;> -<!ELEMENT numCells (#PCDATA)> <!ATTLIST numCells %integer;> -<!ELEMENT numDoF (#PCDATA)> <!ATTLIST numDoF %integer;> -<!ELEMENT numHits (#PCDATA)> <!ATTLIST numHits %integer;> -<!ELEMENT numPolyline (#PCDATA)> <!ATTLIST numPolyline %integer;> -<!ELEMENT numTracks (#PCDATA)> <!ATTLIST numTracks %integer;> -<!ELEMENT numTsos (#PCDATA)> <!ATTLIST numTsos %integer;> -<!ELEMENT passedEF (#PCDATA)> <!ATTLIST passedEF %integer;> -<!ELEMENT passedL1 (#PCDATA)> <!ATTLIST passedL1 %integer;> -<!ELEMENT passedL2 (#PCDATA)> <!ATTLIST passedL2 %integer;> -<!ELEMENT passedTrigger (#PCDATA)> <!ATTLIST passedTrigger %integer;> -<!ELEMENT pdgId (#PCDATA)> <!ATTLIST pdgId %integer;> -<!ELEMENT phi (#PCDATA)> <!ATTLIST phi %float;> -<!ELEMENT phi0 (#PCDATA)> <!ATTLIST phi0 %float;> -<!ELEMENT phiEndVertex (#PCDATA)> <!ATTLIST phiEndVertex %float;> -<!ELEMENT phiModule (#PCDATA)> <!ATTLIST phiModule %integer;> -<!ELEMENT phiVertex (#PCDATA)> <!ATTLIST phiVertex %float;> -<!ELEMENT pionWeight (#PCDATA)> <!ATTLIST pionWeight %float;> -<!ELEMENT pmt1Energy (#PCDATA)> <!ATTLIST pmt1Energy %float;> -<!ELEMENT pmt2Energy (#PCDATA)> <!ATTLIST pmt2Energy %float;> -<!ELEMENT pmt1Chi2 (#PCDATA)> <!ATTLIST pmt1Chi2 %float;> -<!ELEMENT pmt2Chi2 (#PCDATA)> <!ATTLIST pmt2Chi2 %float;> -<!ELEMENT pmt1Time (#PCDATA)> <!ATTLIST pmt1Time %float;> -<!ELEMENT pmt2Time (#PCDATA)> <!ATTLIST pmt2Time %float;> -<!ELEMENT cellRawAmplitude (#PCDATA)> <!ATTLIST cellRawAmplitude %float;> -<!ELEMENT cellRawTime (#PCDATA)> <!ATTLIST cellRawTime %float;> -<!ELEMENT pmt1RawTime (#PCDATA)> <!ATTLIST pmt1RawTime %float;> -<!ELEMENT pmt2RawTime (#PCDATA)> <!ATTLIST pmt2RawTime %float;> -<!ELEMENT pmt1RawAmplitude (#PCDATA)> <!ATTLIST pmt1RawAmplitude %float;> -<!ELEMENT pmt2RawAmplitude (#PCDATA)> <!ATTLIST pmt2RawAmplitude %float;> -<!ELEMENT pmt1Gain (#PCDATA)> <!ATTLIST pmt1Gain %integer;> -<!ELEMENT pmt2Gain (#PCDATA)> <!ATTLIST pmt2Gain %integer;> -<!ELEMENT pmt1Pedestal (#PCDATA)> <!ATTLIST pmt1Pedestal %float;> -<!ELEMENT pmt2Pedestal (#PCDATA)> <!ATTLIST pmt2Pedestal %float;> -<!ELEMENT pmt1Number (#PCDATA)> <!ATTLIST pmt1Number %integer;> -<!ELEMENT pmt2Number (#PCDATA)> <!ATTLIST pmt2Number %integer;> -<!ELEMENT pmt1ADCStatus (#PCDATA)> <!ATTLIST pmt1ADCStatus %integer;> -<!ELEMENT pmt2ADCStatus (#PCDATA)> <!ATTLIST pmt2ADCStatus %integer;> -<!ELEMENT polylineX (#PCDATA)> <!ATTLIST polylineX %float;> -<!ELEMENT polylineY (#PCDATA)> <!ATTLIST polylineY %float;> -<!ELEMENT polylineZ (#PCDATA)> <!ATTLIST polylineZ %float;> -<!ELEMENT preambleError (#PCDATA)> <!ATTLIST preambleError %integer;> -<!ELEMENT prescaleListEF (#PCDATA)> <!ATTLIST prescaleListEF %string;> -<!ELEMENT prescaleListL1 (#PCDATA)> <!ATTLIST prescaleListL1 %string;> -<!ELEMENT prescaleListL2 (#PCDATA)> <!ATTLIST prescaleListL2 %string;> -<!ELEMENT vertexType (#PCDATA)> <!ATTLIST vertexType %integer;> -<!ELEMENT primVxCand (#PCDATA)> <!ATTLIST primVxCand %integer;> -<!ELEMENT pt (#PCDATA)> <!ATTLIST pt %float;> -<!ELEMENT px (#PCDATA)> <!ATTLIST px %float;> -<!ELEMENT py (#PCDATA)> <!ATTLIST py %float;> -<!ELEMENT pz (#PCDATA)> <!ATTLIST pz %float;> -<!ELEMENT quality (#PCDATA)> <!ATTLIST quality %float;> -<!ELEMENT qualityLAr (#PCDATA)> <!ATTLIST qualityLAr %float;> -<!ELEMENT qualityTile (#PCDATA)> <!ATTLIST qualityTile %float;> -<!ELEMENT r (#PCDATA)> <!ATTLIST r %float;> -<!ELEMENT rho (#PCDATA)> <!ATTLIST rho %float;> -<!ELEMENT rhoEndVertex (#PCDATA)> <!ATTLIST rhoEndVertex %float;> -<!ELEMENT rhoVertex (#PCDATA)> <!ATTLIST rhoVertex %float;> -<!ELEMENT rhoz (#PCDATA)> <!ATTLIST rhoz %float;> -<!ELEMENT roiWord (#PCDATA)> <!ATTLIST roiWord %float;> -<!ELEMENT sampling (#PCDATA)> <!ATTLIST sampling %integer;> -<!ELEMENT secondHitError (#PCDATA)> <!ATTLIST secondHitError %integer;> -<!ELEMENT secVtxCount (#PCDATA)> <!ATTLIST secVtxCount %float;> -<!ELEMENT secVtxFitProb (#PCDATA)> <!ATTLIST secVtxFitProb %float;> -<!ELEMENT secVtxMass (#PCDATA)> <!ATTLIST secVtxMass %float;> -<!ELEMENT secVtxMult (#PCDATA)> <!ATTLIST secVtxMult %integer;> -<!ELEMENT secVtxRPhiDist (#PCDATA)> <!ATTLIST secVtxRPhiDist %float;> -<!ELEMENT secVtxTagLh (#PCDATA)> <!ATTLIST secVtxTagLh %float;> -<!ELEMENT secVtxTagLhErr (#PCDATA)> <!ATTLIST secVtxTagLhErr %float;> -<!ELEMENT sgkey (#PCDATA)> <!ATTLIST sgkey %string;> -<!ELEMENT side (#PCDATA)> <!ATTLIST side %integer;> -<!ELEMENT sigma (#PCDATA)> <!ATTLIST sigma %float;> -<!ELEMENT sMax (#PCDATA)> <!ATTLIST sMax %float;> -<!ELEMENT stripWidth (#PCDATA)> <!ATTLIST stripWidth %float;> -<!ELEMENT sub (#PCDATA)> <!ATTLIST sub %integer;> -<!ELEMENT sumEnergy (#PCDATA)> <!ATTLIST sumEnergy %float;> -<!ELEMENT swidth (#PCDATA)> <!ATTLIST swidth %float;> -<!ELEMENT syncError (#PCDATA)> <!ATTLIST syncError %integer;> -<!ELEMENT theta (#PCDATA)> <!ATTLIST theta %float;> -<!ELEMENT threshold (#PCDATA)> <!ATTLIST threshold %integer;> -<!ELEMENT timeOverThreshold (#PCDATA)> <!ATTLIST timeOverThreshold %float;> -<!ELEMENT thrName (#PCDATA)> <!ATTLIST thrName %string;> -<!ELEMENT thrNumber (#PCDATA)> <!ATTLIST thrNumber %float;> -<!ELEMENT thrValue (#PCDATA)> <!ATTLIST thrValue %float;> -<!ELEMENT thrPattern (#PCDATA)> <!ATTLIST thrPattern %float;> -<!ELEMENT tileGap3f (#PCDATA)> <!ATTLIST tileGap3f %float;> -<!ELEMENT time (#PCDATA)> <!ATTLIST time %float;> -<!ELEMENT timeClusters (#PCDATA)> <!ATTLIST timeClusters %float;> -<!ELEMENT timeBin (#PCDATA)> <!ATTLIST timeBin %integer;> -<!ELEMENT trackAuthor (#PCDATA)> <!ATTLIST trackAuthor %integer;> -<!ELEMENT trackid (#PCDATA)> <!ATTLIST trackid %integer;> -<!ELEMENT trackIndex (#PCDATA)> <!ATTLIST trackIndex %integer;> -<!ELEMENT trackKey (#PCDATA)> <!ATTLIST trackKey %string;> -<!ELEMENT trackLinkCount (#PCDATA)> <!ATTLIST trackLinkCount %integer;> -<!ELEMENT tracks (#PCDATA)> <!ATTLIST tracks %integer;> -<!ELEMENT trigInfoEF (#PCDATA)> <!ATTLIST trigInfoEF %string;> -<!ELEMENT trigInfoExtL1ID (#PCDATA)> <!ATTLIST trigInfoExtL1ID %string;> -<!ELEMENT trigInfoL1 (#PCDATA)> <!ATTLIST trigInfoL1 %string;> -<!ELEMENT trigInfoL2 (#PCDATA)> <!ATTLIST trigInfoL2 %string;> -<!ELEMENT trigInfoLvl1Type (#PCDATA)> <!ATTLIST trigInfoLvl1Type %string;> -<!ELEMENT trigInfoStatus (#PCDATA)> <!ATTLIST trigInfoStatus %string;> -<!ELEMENT trigInfoStreamTag (#PCDATA)> <!ATTLIST trigInfoStreamTag %string;> -<!ELEMENT tsosDetType (#PCDATA)> <!ATTLIST tsosDetType %string;> -<!ELEMENT tsosPosR (#PCDATA)> <!ATTLIST tsosPosR %float;> -<!ELEMENT tsosPullLoc1 (#PCDATA)> <!ATTLIST tsosPullLoc1 %float;> -<!ELEMENT tsosPullLoc2 (#PCDATA)> <!ATTLIST tsosPullLoc2 %float;> -<!ELEMENT tsosResLoc1 (#PCDATA)> <!ATTLIST tsosResLoc1 %float;> -<!ELEMENT tsosResLoc2 (#PCDATA)> <!ATTLIST tsosResLoc2 %float;> -<!ELEMENT type (#PCDATA)> <!ATTLIST type %integer;> -<!ELEMENT typeEV (#PCDATA)> <!ATTLIST typeEV %string;> -<!ELEMENT weight (#PCDATA)> <!ATTLIST weight %float;> -<!ELEMENT width (#PCDATA)> <!ATTLIST width %float;> -<!ELEMENT widthside (#PCDATA)> <!ATTLIST widthside %float;> -<!ELEMENT widthx (#PCDATA)> <!ATTLIST widthx %float;> -<!ELEMENT widthy (#PCDATA)> <!ATTLIST widthy %float;> -<!ELEMENT x (#PCDATA)> <!ATTLIST x %float;> -<!ELEMENT x0 (#PCDATA)> <!ATTLIST x0 %float;> -<!ELEMENT x1 (#PCDATA)> <!ATTLIST x1 %float;> -<!ELEMENT y (#PCDATA)> <!ATTLIST y %float;> -<!ELEMENT y0 (#PCDATA)> <!ATTLIST y0 %float;> -<!ELEMENT y1 (#PCDATA)> <!ATTLIST y1 %float;> -<!ELEMENT z (#PCDATA)> <!ATTLIST z %float;> -<!ELEMENT z0 (#PCDATA)> <!ATTLIST z0 %float;> -<!ELEMENT z1 (#PCDATA)> <!ATTLIST z1 %float;> -<!ELEMENT zEndVertex (#PCDATA)> <!ATTLIST zEndVertex %float;> -<!ELEMENT zVertex (#PCDATA)> <!ATTLIST zVertex %float;> diff --git a/graphics/AtlantisJava/geometry/AGeometry.xml b/graphics/AtlantisJava/geometry/AGeometry.xml deleted file mode 100755 index 0d903668879..00000000000 --- a/graphics/AtlantisJava/geometry/AGeometry.xml +++ /dev/null @@ -1,233 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE AGeometry [ -<!ELEMENT AGeometry (ADisc | ARectangle | ABarrelCalorimeter | - AEndcapCalorimeter | AGapCalorimeter | - ABarrelSiliconDetector | AEndcapSiliconDetector | - ABarrelTRTDetector | AEndcapTRTDetector)* > -<!ELEMENT ADisc EMPTY > -<!ATTLIST ADisc - p CDATA #REQUIRED - c CDATA #REQUIRED - n CDATA #REQUIRED - rIn CDATA #REQUIRED - rOut CDATA #REQUIRED - nIn CDATA "256" - nOut CDATA "256"> -<!ELEMENT ARectangle EMPTY > -<!ATTLIST ARectangle - p CDATA #REQUIRED - c CDATA #REQUIRED - n CDATA #REQUIRED - xMin CDATA #REQUIRED - xMax CDATA #REQUIRED - yMin CDATA #REQUIRED - yMax CDATA #REQUIRED - xR (YES|NO) "YES" - yR (YES|NO) "YES"> -<!ELEMENT ABarrelCalorimeter EMPTY > -<!ATTLIST ABarrelCalorimeter - c CDATA #REQUIRED - n CDATA #REQUIRED - sampling CDATA #REQUIRED - region CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED - eta0 CDATA #REQUIRED - deta CDATA #REQUIRED - neta CDATA #REQUIRED - meta CDATA #REQUIRED - phi0 CDATA #REQUIRED - nphi CDATA #REQUIRED> -<!ELEMENT AEndcapCalorimeter EMPTY > -<!ATTLIST AEndcapCalorimeter - c CDATA #REQUIRED - n CDATA #REQUIRED - sampling CDATA #REQUIRED - region CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED - eta0 CDATA #REQUIRED - deta CDATA #REQUIRED - neta CDATA #REQUIRED - meta CDATA #REQUIRED - phi0 CDATA #REQUIRED - nphi CDATA #REQUIRED> -<!ELEMENT AGapCalorimeter EMPTY > -<!ATTLIST AGapCalorimeter - c CDATA #REQUIRED - n CDATA #REQUIRED - sampling CDATA #REQUIRED - region CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED - eta CDATA #REQUIRED - phi0 CDATA #REQUIRED - nphi CDATA #REQUIRED> -<!ELEMENT AEndcapCryostat EMPTY > -<!ATTLIST AEndcapCryostat - c CDATA #REQUIRED - n CDATA #REQUIRED - sampling CDATA #REQUIRED - region CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED - neta CDATA #REQUIRED - nphi CDATA #REQUIRED> -<!ELEMENT ABarrelSiliconDetector EMPTY > -<!ATTLIST ABarrelSiliconDetector - c CDATA #REQUIRED - n CDATA #REQUIRED - layer CDATA #REQUIRED - length CDATA #REQUIRED - width CDATA #REQUIRED - thickness CDATA #REQUIRED - tilt CDATA #REQUIRED - nz CDATA #REQUIRED - nphi CDATA #REQUIRED - r0 CDATA #REQUIRED - phi0 CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED> -<!ELEMENT AEndcapSiliconDetector EMPTY > -<!ATTLIST AEndcapSiliconDetector - c CDATA #REQUIRED - n CDATA #REQUIRED - layer CDATA #REQUIRED - length CDATA #REQUIRED - width CDATA #REQUIRED - thickness CDATA #REQUIRED - nz CDATA #REQUIRED - nphi CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - phi0 CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED> -<!ELEMENT ABarrelTRTDetector EMPTY > -<!ATTLIST ABarrelTRTDetector - c CDATA #REQUIRED - n CDATA #REQUIRED - layer CDATA #REQUIRED - nphi CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - phiIn CDATA #REQUIRED - phiOut CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED> -<!ELEMENT AEndcapTRTDetector EMPTY > -<!ATTLIST AEndcapTRTDetector - c CDATA #REQUIRED - n CDATA #REQUIRED - layer CDATA #REQUIRED - nphi CDATA #REQUIRED - rMin CDATA #REQUIRED - rMax CDATA #REQUIRED - phi0 CDATA #REQUIRED - zMin CDATA #REQUIRED - zMax CDATA #REQUIRED> -]> - -<AGeometry> -<ABarrelSiliconDetector c="PIX" n="Pixel" layer="0" length="2" width="1.9" thickness="0.270702" tilt="-14.0063" nz="20" nphi="14" r0="3.32803" phi0="22.2819" zMin="-33.6323" zMax="33.6323" /> -<ABarrelSiliconDetector c="PIX" n="Pixel" layer="1" length="6.08" width="1.64" thickness="0.306424" tilt="-19.9962" nz="13" nphi="22" r0="5.10491" phi0="-0.391852" zMin="-40.5702" zMax="40.5702" /> -<ABarrelSiliconDetector c="PIX" n="Pixel" layer="2" length="6.08" width="1.64" thickness="0.307646" tilt="-19.9962" nz="13" nphi="38" r0="8.88103" phi0="-0.12952" zMin="-40.5702" zMax="40.5702" /> -<ABarrelSiliconDetector c="PIX" n="Pixel" layer="3" length="6.08" width="1.64" thickness="0.30793" tilt="-19.9962" nz="13" nphi="52" r0="12.2722" phi0="3.38916" zMin="-40.5702" zMax="40.5702" /> -<AEndcapSiliconDetector c="PIX" n="Pixel" layer="0" length="6.08" width="1.64" thickness="1.51617" nz="1" nphi="48" rMin="8.91479" rMax="14.9795" phi0="3.75" zMin="48.79" zMax="49.79" /> -<AEndcapSiliconDetector c="PIX" n="Pixel" layer="1" length="6.08" width="1.64" thickness="1.51617" nz="1" nphi="48" rMin="8.91479" rMax="14.9795" phi0="3.75" zMin="57.29" zMax="58.29" /> -<AEndcapSiliconDetector c="PIX" n="Pixel" layer="2" length="6.08" width="1.64" thickness="1.51617" nz="1" nphi="48" rMin="8.91479" rMax="14.9795" phi0="3.75" zMin="64.29" zMax="65.29" /> -<ABarrelSiliconDetector c="SIL" n="Silicon" layer="0" length="12.609" width="6.144" thickness="0.83814" tilt="11.0677" nz="6" nphi="32" r0="30.134" phi0="3.24616" zMin="-74.8273" zMax="74.8273" /> -<ABarrelSiliconDetector c="SIL" n="Silicon" layer="1" length="12.609" width="6.144" thickness="0.75531" tilt="11.0546" nz="6" nphi="40" r0="37.2063" phi0="2.63207" zMin="-74.8273" zMax="74.8273" /> -<ABarrelSiliconDetector c="SIL" n="Silicon" layer="2" length="12.609" width="6.144" thickness="0.836751" tilt="11.2967" nz="6" nphi="48" r0="44.4326" phi0="2.10644" zMin="-74.8273" zMax="74.8273" /> -<ABarrelSiliconDetector c="SIL" n="Silicon" layer="3" length="12.609" width="6.144" thickness="0.776445" tilt="11.2902" nz="6" nphi="56" r0="51.4693" phi0="1.80488" zMin="-74.8273" zMax="74.8273" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="0" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.03842" zMin="83.5567" zMax="84.6532" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="0" length="11.77" width="6.31592" thickness="24.099" nz="1" nphi="40" rMin="33.7464" rMax="45.7959" phi0="4.46486" zMin="86.5567" zMax="87.6532" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="1" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.01417" zMin="91.5768" zMax="92.6732" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="1" length="11.77" width="6.31592" thickness="36.6061" nz="2" nphi="40" rMin="27.4929" rMax="45.7959" phi0="4.5" zMin="91.5768" zMax="95.6732" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="2" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.03842" zMin="107.327" zMax="108.423" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="2" length="11.77" width="6.31592" thickness="36.6061" nz="2" nphi="40" rMin="27.4929" rMax="45.7959" phi0="4.46486" zMin="107.327" zMax="111.423" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="3" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.01417" zMin="128.167" zMax="129.263" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="3" length="11.77" width="6.31592" thickness="36.6061" nz="2" nphi="40" rMin="27.4929" rMax="45.7959" phi0="4.5" zMin="128.167" zMax="132.263" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="4" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.03842" zMin="138.147" zMax="139.243" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="4" length="11.77" width="6.31592" thickness="36.6061" nz="2" nphi="40" rMin="27.4929" rMax="45.7959" phi0="4.46486" zMin="138.147" zMax="142.243" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="5" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.01417" zMin="175.317" zMax="176.413" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="5" length="11.77" width="6.31592" thickness="36.6061" nz="2" nphi="40" rMin="27.4929" rMax="45.7959" phi0="4.5" zMin="175.317" zMax="179.413" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="6" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.03842" zMin="209.697" zMax="210.793" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="6" length="11.77" width="6.31592" thickness="24.099" nz="1" nphi="40" rMin="33.7464" rMax="45.7959" phi0="4.46486" zMin="212.697" zMax="213.793" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="7" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="-1.01417" zMin="248.677" zMax="249.773" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="7" length="5.2475" width="6.83547" thickness="11.0247" nz="1" nphi="40" rMin="40.2836" rMax="45.7959" phi0="4.5" zMin="251.677" zMax="252.773" /> -<AEndcapSiliconDetector c="SIL" n="Silicon" layer="8" length="12.1235" width="6.2019" thickness="24.7693" nz="1" nphi="52" rMin="43.8426" rMax="56.2272" phi0="1.01417" zMin="273.747" zMax="274.843" /> -<ABarrelTRTDetector c="TRT" n="TRT" layer="0" nphi="32" rMin="56.7302" rMax="69.8248" phiIn="-6.17382" phiOut="-10.7369" zMin="-70.975" zMax="70.975" /> -<ABarrelTRTDetector c="TRT" n="TRT" layer="1" nphi="32" rMin="70.1346" rMax="86.6458" phiIn="-10.7202" phiOut="-5.99874" zMin="-70.975" zMax="70.975" /> -<ABarrelTRTDetector c="TRT" n="TRT" layer="2" nphi="32" rMin="86.9559" rMax="107.232" phiIn="-6.00171" phiOut="-10.9221" zMin="-70.975" zMax="70.975" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="0" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="85.85" zMax="98.55" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="1" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="100.18" zMax="112.88" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="2" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="114.565" zMax="127.265" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="3" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="128.86" zMax="141.56" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="4" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="143.12" zMax="155.82" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="5" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="157.388" zMax="170.088" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="6" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="175.008" zMax="185.408" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="7" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="187.185" zMax="197.585" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="8" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="199.34" zMax="209.74" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="9" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="211.49" zMax="221.89" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="10" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="223.64" zMax="234.04" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="11" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="235.795" zMax="246.195" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="12" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="247.96" zMax="258.36" /> -<AEndcapTRTDetector c="TRT" n="TRT" layer="13" nphi="34" rMin="64.67" rMax="100.1" phi0="0" zMin="260.083" zMax="270.483" /> -<ADisc p="YX" c="Sol" n="Solenoid" rIn="122.9" rOut="127.4" /> -<ARectangle p="RZ" c="Sol" n="Solenoid" xMin="-265" xMax="265" yMin="122.9" yMax="127.4" xR="NO" /> -<ABarrelCalorimeter c="ECAL" n="LAr Presampler" sampling="0" region="0" rMin="142.173" rMax="143.858" zMin="0" zMax="325.0" eta0="3.1225e-17" deta="0.025" neta="61" meta="0" phi0="-0.175783" nphi="64" /> -<ABarrelCalorimeter c="ECAL" n="LAr" sampling="1" region="0" rMin="148.175" rMax="158" zMin="0" zMax="325.0" eta0="0.003125" deta="0.003125" neta="447" meta="1" phi0="-0.175783" nphi="64" /> -<ABarrelCalorimeter c="ECAL" n="LAr" sampling="1" region="1" rMin="148.175" rMax="158" zMin="0" zMax="325.0" eta0="1.4" deta="0.025" neta="3" meta="0" phi0="-0.175783" nphi="256" /> -<ABarrelCalorimeter c="ECAL" n="LAr" sampling="2" region="0" rMin="158" rMax="184" zMin="0" zMax="325.0" eta0="0.0" deta="0.025" neta="56" meta="0" phi0="-0.175783" nphi="256" /> -<ABarrelCalorimeter c="ECAL" n="LAr" sampling="2" region="1" rMin="158" rMax="184" zMin="0" zMax="325.0" eta0="1.4" deta="0.075" neta="1" meta="0" phi0="-0.175783" nphi="256" /> -<ABarrelCalorimeter c="ECAL" n="LAr" sampling="3" region="0" rMin="184" rMax="198.47" zMin="0" zMax="325.0" eta0="0.0" deta="0.05" neta="27" meta="0" phi0="-0.175783" nphi="256" /> -<AEndcapCalorimeter c="ECAL" n="LAr Endcap Presampler" sampling="0" region="0" rMin="29.0" rMax="203.4" zMin="368.075" zMax="371.425" eta0="1.50988" deta="0.025" neta="12" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="0" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="1.38444" deta="0.05" neta="1" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="1" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="1.43452" deta="0.025" neta="3" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="2" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="1.50965" deta="0.003125" neta="96" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="3" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="1.81009" deta="0.00416667" neta="48" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="4" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="2.01027" deta="0.00625" neta="64" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="1" region="5" rMin="29.0" rMax="203.4" zMin="375.424" zMax="380.073" eta0="2.41048" deta="0.025" neta="4" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Inner Endcap" sampling="1" region="0" rMin="29.0" rMax="203.4" zMin="375.424" zMax="420.125" eta0="2.51004" deta="0.1" neta="7" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="2" region="0" rMin="29.0" rMax="203.4" zMin="380.073" zMax="424.326" eta0="1.38381" deta="0.05" neta="7" meta="0" phi0="-0.234375" nphi="256" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="2" region="1" rMin="29.0" rMax="203.4" zMin="380.073" zMax="415.624" eta0="1.43388" deta="0.025" neta="43" meta="0" phi0="-0.234375" nphi="256" /> -<AEndcapCalorimeter c="ECAL" n="LAr Inner Endcap" sampling="2" region="0" rMin="29.0" rMax="203.4" zMin="420.125" zMax="424.326" eta0="2.5094" deta="0.1" neta="7" meta="0" phi0="-0.234375" nphi="64" /> -<AEndcapCalorimeter c="ECAL" n="LAr Outer Endcap" sampling="3" region="0" rMin="29.0" rMax="203.4" zMin="415.624" zMax="424.326" eta0="1.50867" deta="0.05" neta="20" meta="0" phi0="-0.234375" nphi="256" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="0" region="0" rMin="37.2" rMax="203.4" zMin="435" zMax="463" eta0="1.50824" deta="0.1" neta="10" meta="0" phi0="0" nphi="64" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="0" region="1" rMin="37.2" rMax="203.4" zMin="435" zMax="463" eta0="2.50892" deta="0.2" neta="4" meta="0" phi0="0" nphi="32" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="1" region="0" rMin="48.5" rMax="203.4" zMin="463" zMax="510" eta0="1.50755" deta="0.1" neta="10" meta="0" phi0="0" nphi="64" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="1" region="1" rMin="48.5" rMax="203.4" zMin="463" zMax="510" eta0="2.50817" deta="0.2" neta="3" meta="0" phi0="0" nphi="32" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="2" region="0" rMin="48.5" rMax="203.4" zMin="513" zMax="559" eta0="1.6" deta="0.1" neta="9" meta="1" phi0="0" nphi="64" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="2" region="1" rMin="48.5" rMax="203.4" zMin="513" zMax="559" eta0="2.5" deta="0.2" neta="3" meta="0" phi0="-7.95139e-16" nphi="32" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="3" region="0" rMin="48.5" rMax="203.4" zMin="559" zMax="605" eta0="1.7" deta="0.1" neta="8" meta="2" phi0="-3.97569e-16" nphi="64" /> -<AEndcapCalorimeter c="HCAL" n="HEC" sampling="3" region="1" rMin="48.5" rMax="203.4" zMin="559" zMax="605" eta0="2.5" deta="0.2" neta="4" meta="0" phi0="-7.95139e-16" nphi="32" /> -<ADisc p="YX" c="ECAL" n="FCAL EM" rIn="7.84392" rOut="47.5" /> -<ARectangle p="RZ" c="ECAL" n="FCAL EM" xMin="466.85" xMax="511.85" yMin="7.84392" yMax="47.5" /> -<ADisc p="YX" c="HCAL" n="FCAL HAD 1" rIn="7.90558" rOut="47.5" /> -<ARectangle p="RZ" c="HCAL" n="FCAL HAD 1" xMin="512.3" xMax="557.3" yMin="7.90558" yMax="47.5" /> -<ADisc p="YX" c="HCAL" n="FCAL HAD 2" rIn="7.96007" rOut="47.5" /> -<ARectangle p="RZ" c="HCAL" n="FCAL HAD 2" xMin="559.75" xMax="604.75" yMin="7.96007" yMax="47.5" /> -<ABarrelCalorimeter c="HCAL" n="TILE Barrel" sampling="0" region="0" rMin="229" rMax="260" zMin="0" zMax="282" eta0="0" deta="0.1" neta="10" meta="0" phi0="0" nphi="64" /> -<ABarrelCalorimeter c="HCAL" n="TILE Barrel" sampling="1" region="0" rMin="260" rMax="344" zMin="0" zMax="282" eta0="0" deta="0.1" neta="9" meta="0" phi0="0" nphi="64" /> -<ABarrelCalorimeter c="HCAL" n="TILE Barrel" sampling="2" region="0" rMin="344" rMax="386" zMin="-36.5199" zMax="282" eta0="-0.1" deta="0.2" neta="4" meta="0" phi0="0" nphi="64" /> -<ABarrelCalorimeter c="HCAL" n="Extended TILE" sampling="0" region="0" rMin="229" rMax="260" zMin="355.95" zMax="615" eta0="1.1" deta="0.1" neta="5" meta="11" phi0="0" nphi="64" /> -<ABarrelCalorimeter c="HCAL" n="Extended TILE" sampling="1" region="0" rMin="260" rMax="314" zMin="355.95" zMax="615" eta0="1" deta="0.1" neta="5" meta="10" phi0="0" nphi="64" /> -<ABarrelCalorimeter c="HCAL" n="Extended TILE" sampling="2" region="0" rMin="314" rMax="386" zMin="355.95" zMax="615" eta0="0.9" deta="0.2" neta="2" meta="10" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="1" region="0" rMin="299" rMax="344" zMin="346.435" zMax="355.92" eta="9" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="2" region="0" rMin="344" rMax="386" zMin="325.05" zMax="355.95" eta="8" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="3" region="0" rMin="264.6" rMax="295.9" zMin="354.45" zMax="355.95" eta="10" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="3" region="0" rMin="230.5" rMax="264.6" zMin="354.45" zMax="355.95" eta="11" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="3" region="0" rMin="182.7" rMax="230.5" zMin="353.2" zMax="354" eta="13" phi0="0" nphi="64" /> -<AGapCalorimeter c="HCAL" n="ITC Gap" sampling="3" region="0" rMin="146.5" rMax="182.7" zMin="353.2" zMax="354" eta="15" phi0="0" nphi="64" /> -<AEndcapCryostat c="HCAL" n="Minimum Bias Trigger Scintillators" sampling="0" region="0" rMin="15.3" rMax="42.6" zMin="319.187" zMax="321.187" neta="1" nphi="8" /> -<AEndcapCryostat c="HCAL" n="Minimum Bias Trigger Scintillators" sampling="1" region="0" rMin="42.6" rMax="89" zMin="319.187" zMax="321.187" neta="1" nphi="8" /> -</AGeometry> diff --git a/graphics/AtlantisJava/geometry/AMuonGeometry.xml b/graphics/AtlantisJava/geometry/AMuonGeometry.xml deleted file mode 100755 index bf6ea122c01..00000000000 --- a/graphics/AtlantisJava/geometry/AMuonGeometry.xml +++ /dev/null @@ -1,220 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE AMuonGeometry [ -<!ELEMENT AMuonGeometry (ABox | ATBx | ATrd)*> -<!ELEMENT ABox EMPTY > -<!ATTLIST ABox - n CDATA #REQUIRED - zi CDATA #REQUIRED - zo CDATA #REQUIRED - ri CDATA #REQUIRED - ro CDATA #REQUIRED - w CDATA #REQUIRED - eta CDATA #REQUIRED - phi CDATA #REQUIRED - dphi CDATA "0" - sh CDATA "0" - RPCi CDATA "0" - RPCo CDATA "0"> -<!ELEMENT ATBx EMPTY > -<!ATTLIST ATBx - n CDATA #REQUIRED - zi CDATA #REQUIRED - zo CDATA #REQUIRED - ri CDATA #REQUIRED - ro CDATA #REQUIRED - w CDATA #REQUIRED - eta CDATA #REQUIRED - phi CDATA #REQUIRED - sh CDATA "0" - dphi CDATA "0" - RPCi CDATA "0" - RPCo CDATA "0" - zis CDATA #REQUIRED - zos CDATA #REQUIRED - ws CDATA #REQUIRED - or CDATA "0"> -<!ELEMENT ATrd EMPTY > -<!ATTLIST ATrd - n CDATA #REQUIRED - zi CDATA #REQUIRED - zo CDATA #REQUIRED - ri CDATA #REQUIRED - ro CDATA #REQUIRED - wi CDATA #REQUIRED - wo CDATA #REQUIRED - eta CDATA #REQUIRED - phi CDATA #REQUIRED - dphi CDATA "0" - sh CDATA "0" - a CDATA "0"> -]> -<AMuonGeometry> -<ABox n="MDT_BIL" zi="33" zo="124.607" ri="474.091" ro="515.705" w="267.15" eta="1" phi="1 2 3 7" /> -<ABox n="MDT_BIL" zi="51" zo="124.586" ri="474.091" ro="515.705" w="267.15" eta="1" phi="4" /> -<ABox n="MDT_BIL" zi="56" zo="147.607" ri="525.691" ro="567.305" w="267.15" eta="1" phi="5" /> -<ABox n="MDT_BIL" zi="125" zo="234.628" ri="474.091" ro="515.705" w="267.15" eta="2" phi="1 2 3 4 5 7" /> -<ABox n="MDT_BIL" zi="235" zo="326.607" ri="474.091" ro="515.705" w="267.15" eta="3" phi="1 2 4 5 7" /> -<ABox n="MDT_BIL" zi="235" zo="344.628" ri="474.091" ro="515.705" w="267.15" eta="3" phi="3" /> -<ABox n="MDT_BIL" zi="345" zo="454.628" ri="474.091" ro="515.705" w="267.15" eta="4" phi="1 2 3 4 5" /> -<ABox n="MDT_BIL" zi="345" zo="436.607" ri="474.091" ro="515.705" w="267.15" eta="4" phi="7" /> -<ABox n="MDT_BIL" zi="455" zo="546.607" ri="474.091" ro="515.705" w="267.15" eta="5" phi="1 2 3 4 5" /> -<ABox n="MDT_BIL" zi="437" zo="528.607" ri="474.091" ro="515.705" w="267.15" eta="5" phi="7" /> -<ABox n="MDT_BIL" zi="547" zo="656.628" ri="474.091" ro="515.705" w="267.15" eta="6" phi="1 2 3 5" /> -<ABox n="MDT_BIL" zi="547" zo="638.607" ri="474.091" ro="515.705" w="267.15" eta="6" phi="4 7" /> -<ABox n="MDT_BIS" zi="1" zo="110.628" ri="440.793" ro="469.207" w="167.15" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="111" zo="202.607" ri="440.793" ro="469.207" w="167.15" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="203" zo="294.607" ri="440.793" ro="469.207" w="167.15" eta="3" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="295" zo="386.607" ri="440.793" ro="469.207" w="167.15" eta="4" phi="1 2 3" dphi="22.5" /> -<ABox n="MDT_BIS" zi="313" zo="404.607" ri="440.793" ro="469.207" w="167.15" eta="4" phi="4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="387" zo="478.607" ri="440.793" ro="469.207" w="167.15" eta="5" phi="1 2 3" dphi="22.5" /> -<ABox n="MDT_BIS" zi="405" zo="496.607" ri="440.793" ro="469.207" w="167.15" eta="5" phi="4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="479" zo="570.607" ri="440.793" ro="469.207" w="167.15" eta="6" phi="1 2 3" dphi="22.5" /> -<ABox n="MDT_BIS" zi="497" zo="588.607" ri="440.793" ro="469.207" w="167.15" eta="6" phi="4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="571" zo="680.628" ri="440.793" ro="469.207" w="167.15" eta="7" phi="1 2 3" dphi="22.5" /> -<ABox n="MDT_BIS" zi="589" zo="680.607" ri="440.793" ro="469.207" w="167.15" eta="7" phi="4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIS" zi="681" zo="730.558" ri="454.864" ro="466.145" w="85.15" eta="8" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BML" zi="15" zo="184.698" ri="675.194" ro="754.205" w="357.6" eta="1" phi="1 2" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="39" zo="184.67" ri="675.194" ro="754.205" w="357.6" eta="1" phi="3 7" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="87" zo="184.614" ri="675.194" ro="753.005" w="357.6" eta="1" phi="4 5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="63" zo="184.642" ri="675.194" ro="753.005" w="357.6" eta="1" phi="6 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="185" zo="354.698" ri="675.194" ro="754.205" w="357.6" eta="2" phi="1 2 3 4 5 6 7 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="355" zo="524.698" ri="675.194" ro="754.205" w="357.6" eta="3" phi="1 2 3 4 5 6 7 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="525" zo="646.642" ri="675.194" ro="753.005" w="357.6" eta="4" phi="1 2 3 4 5 6 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="647" zo="768.642" ri="675.194" ro="753.005" w="357.6" eta="4" phi="7" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="647" zo="768.642" ri="675.194" ro="753.005" w="357.6" eta="5" phi="1 2 3 4 5 6 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="769" zo="914.67" ri="675.194" ro="754.205" w="357.6" eta="5" phi="7" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="769" zo="914.67" ri="675.194" ro="754.205" w="357.6" eta="6" phi="1 2 3 4 5 6 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="918" zo="966" ri="743.8" ro="753.8" w="304" eta="6" phi="7" RPCi="15" RPCo="15" /> -<ABox n="MDT_BML" zi="918" zo="966" ri="743.8" ro="753.8" w="304" eta="7" phi="1 2 3 4 5 6 8" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="15" zo="184.698" ri="777.694" ro="842.905" w="309.6" eta="1" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="185" zo="364.5" ri="777.694" ro="845.705" w="309.6" eta="2" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="368" zo="513.67" ri="777.694" ro="841.705" w="309.6" eta="3" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="514" zo="691.35" ri="777.694" ro="851.305" w="309.6" eta="4" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="692.5" zo="790.114" ri="777.694" ro="841.705" w="309.6" eta="5" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMS" zi="790.5" zo="936.17" ri="777.694" ro="842.905" w="309.6" eta="6" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BOL" zi="15" zo="232.754" ri="924.444" ro="989.055" w="498.6" eta="1" phi="1 2" RPCo="15" /> -<ABox n="MDT_BOL" zi="39" zo="232.726" ri="924.444" ro="989.055" w="498.6" eta="1" phi="3" RPCo="15" /> -<ABox n="MDT_BOL" zi="87" zo="232.67" ri="924.444" ro="989.055" w="498.6" eta="1" phi="4 5" RPCo="15" /> -<ABox n="MDT_BOL" zi="63" zo="232.698" ri="924.444" ro="989.055" w="498.6" eta="1" phi="6 7 8" RPCo="15" /> -<ABox n="MDT_BOL" zi="233" zo="450.754" ri="924.444" ro="989.055" w="498.6" eta="2" phi="1 2 3 4 5 6 8" RPCo="15" /> -<ABox n="MDT_BOL" zi="233" zo="378.67" ri="924.444" ro="989.055" w="498.6" eta="2" phi="7" RPCo="15" /> -<ABox n="MDT_BOL" zi="451" zo="620.698" ri="924.444" ro="989.055" w="498.6" eta="3" phi="1 2 3 4 5 6 8" RPCo="15" /> -<ABox n="MDT_BOL" zi="379" zo="524.67" ri="924.444" ro="989.055" w="498.6" eta="3" phi="7" RPCo="15" /> -<ABox n="MDT_BOL" zi="621" zo="838.754" ri="924.444" ro="989.055" w="498.6" eta="4" phi="1 2 3 4 5 6 7 8" RPCo="15" /> -<ABox n="MDT_BOL" zi="839" zo="1056.75" ri="924.444" ro="989.055" w="498.6" eta="5" phi="1 2 3 4 5 6 7 8" RPCo="15" /> -<ABox n="MDT_BOL" zi="1057" zo="1226.7" ri="924.444" ro="989.055" w="498.6" eta="6" phi="1 2 3 4 5 6 7 8" RPCo="15" /> -<ABox n="MDT_BOS" zi="1" zo="218.754" ri="1019.19" ro="1082.46" w="379.6" eta="1" phi="1 2 3 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="73" zo="218.67" ri="1019.19" ro="1082.46" w="379.6" eta="1" phi="4" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="219" zo="436.754" ri="1019.19" ro="1082.46" w="379.6" eta="2" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="437" zo="654.754" ri="1019.19" ro="1082.46" w="379.6" eta="3" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="655" zo="872.754" ri="1019.19" ro="1082.46" w="379.6" eta="4" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="873" zo="1090.75" ri="1019.19" ro="1082.46" w="379.6" eta="5" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BOS" zi="1091" zo="1284.73" ri="1019.19" ro="1082.46" w="379.6" eta="6" phi="1 2 3 4 5 8" dphi="22.5" RPCi="15" /> -<ABox n="MDT_BEE" zi="877.9" zo="1023.57" ri="433.023" ro="452.33" w="91.15" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BEE" zi="1023.9" zo="1169.57" ri="433.023" ro="452.33" w="91.15" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ABox n="MDT_BIR" zi="52" zo="143.607" ri="592.407" ro="634.021" w="267.15" eta="1" phi="6" sh="11.65" /> -<ABox n="MDT_BIR" zi="52" zo="143.607" ri="592.407" ro="634.021" w="267.15" eta="1" phi="8" sh="-11.65" /> -<ABox n="MDT_BIR" zi="200" zo="291.607" ri="596.1" ro="637.714" w="153.65" eta="2" phi="6" sh="68.4" /> -<ABox n="MDT_BIR" zi="200" zo="291.607" ri="596.1" ro="637.714" w="153.65" eta="2" phi="8" sh="-68.4" /> -<ABox n="MDT_BIR" zi="292" zo="392.617" ri="594.083" ro="635.697" w="110.55" eta="3" phi="6" sh="46.85" /> -<ABox n="MDT_BIR" zi="292" zo="392.617" ri="594.083" ro="635.697" w="110.55" eta="3" phi="8" sh="-46.85" /> -<ABox n="MDT_BIR" zi="394" zo="485.607" ri="596.1" ro="637.714" w="153.65" eta="4" phi="6" sh="68.4" /> -<ABox n="MDT_BIR" zi="394" zo="485.607" ri="596.1" ro="637.714" w="153.65" eta="4" phi="8" sh="-68.4" /> -<ABox n="MDT_BIR" zi="541" zo="614.586" ri="596.1" ro="637.714" w="153.65" eta="5" phi="6" sh="68.4" /> -<ABox n="MDT_BIR" zi="541" zo="614.586" ri="596.1" ro="637.714" w="153.65" eta="5" phi="8" sh="-68.4" /> -<ABox n="MDT_BIR" zi="616" zo="725.628" ri="594.083" ro="635.697" w="110.55" eta="6" phi="6" sh="46.85" /> -<ABox n="MDT_BIR" zi="616" zo="725.628" ri="594.083" ro="635.697" w="110.55" eta="6" phi="8" sh="-46.85" /> -<ABox n="MDT_BMF" zi="62.5" zo="280.254" ri="777.694" ro="841.705" w="309.6" eta="1" phi="6 7" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMF" zi="406" zo="599.726" ri="777.694" ro="841.705" w="309.6" eta="2" phi="6 7" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BMF" zi="728" zo="873.67" ri="777.694" ro="841.705" w="309.6" eta="3" phi="6 7" dphi="22.5" RPCi="15" RPCo="15" /> -<ABox n="MDT_BOF" zi="62.57" zo="280.324" ri="1028.19" ro="1093.06" w="379.6" eta="1" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOF" zi="405.46" zo="599.186" ri="1028.19" ro="1106.21" w="379.6" eta="2" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOF" zi="727.92" zo="873.59" ri="1028.19" ro="1107.41" w="379.6" eta="3" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOF" zi="1002.6" zo="1124.24" ri="1028.19" ro="1106.21" w="379.6" eta="4" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOG" zi="-60.821" zo="60.8208" ri="1028.19" ro="1093.06" w="379.6" eta="0" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOG" zi="282.07" zo="403.712" ri="1028.19" ro="1093.06" w="379.6" eta="1" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOG" zi="602.75" zo="724.392" ri="1028.19" ro="1093.06" w="379.6" eta="2" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOG" zi="877.14" zo="998.782" ri="1028.19" ro="1106.21" w="379.6" eta="3" phi="6 7" dphi="22.5" RPCo="15" /> -<ABox n="MDT_BOG" zi="1147.2" zo="1268.84" ri="1028.19" ro="1106.21" w="379.6" eta="4" phi="6 7" dphi="22.5" RPCo="15" /> -<ATrd n="MDT_EIL1" zi="749.146" zo="785.86" ri="207.6" ro="317.228" wi="132.15" wo="186.9" eta="1" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EIL2" zi="749.146" zo="785.86" ri="319.1" ro="428.728" wi="186.15" wo="240.9" eta="2" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EIL3" zi="749.146" zo="785.86" ri="427.23" ro="464.774" wi="207.15" wo="207.15" eta="3" phi="1 2 3 4 5 7" /> -<ATrd n="MDT_EIL3" zi="749.146" zo="785.86" ri="427.535" ro="465.079" wi="174.15" wo="174.15" eta="3" phi="6" sh="-16.5" /> -<ATrd n="MDT_EIL3" zi="749.146" zo="785.86" ri="427.535" ro="465.079" wi="174.15" wo="174.15" eta="3" phi="8" sh="16.5" /> -<ATrd n="MDT_EIL4" zi="745.796" zo="782.51" ri="472" ro="509.544" wi="153.65" wo="153.65" eta="4" phi="1 5" /> -<ATrd n="MDT_EIL4" zi="745.796" zo="782.51" ri="472" ro="635.691" wi="235.15" wo="316.9" eta="4" phi="2 3 7" /> -<ATrd n="MDT_EIL4" zi="745.796" zo="782.51" ri="473.105" ro="636.796" wi="165.15" wo="246.9" eta="4" phi="4" sh="35" /> -<ATrd n="MDT_EIL4" zi="745.796" zo="782.51" ri="511.445" ro="639.094" wi="128.15" wo="191.9" eta="4" phi="6" sh="-62.5" /> -<ATrd n="MDT_EIL4" zi="745.796" zo="782.51" ri="511.445" ro="639.094" wi="128.15" wo="191.9" eta="4" phi="8" sh="62.5" /> -<ATrd n="MDT_EIL5" zi="745.796" zo="782.51" ri="508.04" ro="635.689" wi="253.15" wo="316.9" eta="5" phi="1 5" /> -<ATrd n="MDT_EEL1" zi="1116.5" zo="1148.11" ri="651.3" ro="772.942" wi="336.15" wo="396.9" eta="1" phi="1 2 4 5 6 7 8" /> -<ATrd n="MDT_EEL1" zi="1066.09" zo="1097.7" ri="671.8" ro="817.47" wi="244.65" wo="288.3" eta="1" phi="3" /> -<ATrd n="MDT_EEL2" zi="1116.5" zo="1148.11" ri="774.97" ro="896.612" wi="396.15" wo="456.9" eta="2" phi="1 2 4 5 6 7 8" /> -<ATrd n="MDT_EES1" zi="1011.9" zo="1043.51" ri="589.3" ro="734.97" wi="201.45" wo="245.1" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EES2" zi="1011.9" zo="1043.51" ri="737" ro="858.642" wi="244.65" wo="281.1" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EML1" zi="1411.25" zo="1447.66" ri="177" ro="346.698" wi="118.65" wo="203.4" eta="1" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EML2" zi="1411.25" zo="1447.66" ri="348.5" ro="542.226" wi="202.65" wo="299.4" eta="2" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EML3" zi="1411.25" zo="1447.66" ri="544" ro="737.726" wi="298.65" wo="395.4" eta="3" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EML4" zi="1411.25" zo="1447.66" ri="739.5" ro="933.226" wi="394.65" wo="491.4" eta="4" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EML5" zi="1411.25" zo="1447.66" ri="935" ro="1128.73" wi="490.65" wo="587.4" eta="5" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EMS1" zi="1369.65" zo="1406.06" ri="177" ro="370.726" wi="83.55" wo="141.6" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EMS2" zi="1369.65" zo="1406.06" ri="372.5" ro="566.226" wi="141.15" wo="199.2" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EMS3" zi="1369.65" zo="1406.06" ri="568" ro="761.726" wi="198.75" wo="256.8" eta="3" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EMS4" zi="1369.65" zo="1406.06" ri="763.5" ro="957.226" wi="256.35" wo="314.4" eta="4" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EMS5" zi="1369.65" zo="1406.06" ri="959" ro="1152.73" wi="313.95" wo="372" eta="5" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOL1" zi="2124.25" zo="2160.66" ri="277" ro="446.698" wi="168.15" wo="252.9" eta="1" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOL2" zi="2124.25" zo="2160.66" ri="448.5" ro="618.198" wi="264.15" wo="348.9" eta="2" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOL3" zi="2124.25" zo="2160.66" ri="620" ro="765.67" wi="348.15" wo="420.9" eta="3" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOL4" zi="2124.25" zo="2160.66" ri="767.5" ro="913.17" wi="420.15" wo="492.9" eta="4" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOL5" zi="2124.25" zo="2160.66" ri="915" ro="1060.67" wi="492.15" wo="564.9" eta="5" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOL6" zi="2124.25" zo="2160.66" ri="1062.5" ro="1208.17" wi="564.15" wo="636.9" eta="6" phi="1 2 3 4 5 6 7 8" /> -<ATrd n="MDT_EOS1" zi="2165.85" zo="2202.26" ri="277" ro="446.698" wi="124.95" wo="175.8" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOS2" zi="2165.85" zo="2202.26" ri="448.5" ro="618.198" wi="175.35" wo="226.2" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOS3" zi="2165.85" zo="2202.26" ri="620" ro="789.698" wi="225.75" wo="276.6" eta="3" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOS4" zi="2165.85" zo="2202.26" ri="791.5" ro="937.17" wi="276.15" wo="319.8" eta="4" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOS5" zi="2165.85" zo="2202.26" ri="939" ro="1084.67" wi="319.35" wo="363" eta="5" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EOS6" zi="2165.85" zo="2202.26" ri="1086.5" ro="1232.17" wi="362.55" wo="406.2" eta="6" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="TGC_T1F1" zi="1327.15" zo="1334.15" ri="190" ro="397.54" wi="57.69" wo="112.34" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23" dphi="7.5" /> -<ATrd n="TGC_T1F1" zi="1345.05" zo="1352.05" ri="190" ro="397.54" wi="57.69" wo="112.34" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24" dphi="7.5" /> -<ATrd n="TGC_T1E1" zi="1345.05" zo="1359.95" ri="388" ro="1068.2" wi="64.49" wo="154.85" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47" dphi="3.75" /> -<ATrd n="TGC_T1E1" zi="1327.15" zo="1342.05" ri="388" ro="1068.2" wi="64.49" wo="154.85" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48" dphi="3.75" /> -<ATrd n="TGC_T2F1" zi="1460.05" zo="1464.42" ri="252.59" ro="432.15" wi="75.51" wo="122.78" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23" dphi="7.5" /> -<ATrd n="TGC_T2F1" zi="1475.55" zo="1479.92" ri="252.59" ro="432.15" wi="75.51" wo="122.78" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24" dphi="7.5" /> -<ATrd n="TGC_T2E1" zi="1475.55" zo="1485.42" ri="418.4" ro="1191.7" wi="68.47" wo="170.84" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47" dphi="3.75" /> -<ATrd n="TGC_T2E1" zi="1460.05" zo="1469.92" ri="418.4" ro="1191.7" wi="68.47" wo="170.84" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48" dphi="3.75" /> -<ATrd n="TGC_T3F1" zi="1502.05" zo="1506.42" ri="261" ro="440.56" wi="75.51" wo="122.79" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23" dphi="7.5" /> -<ATrd n="TGC_T3F1" zi="1517.55" zo="1521.92" ri="261" ro="440.56" wi="75.51" wo="122.79" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24" dphi="7.5" /> -<ATrd n="TGC_T3E1" zi="1517.55" zo="1527.42" ri="436.56" ro="1191.7" wi="70.84" wo="170.84" eta="1" phi="1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47" dphi="3.75" /> -<ATrd n="TGC_T3E1" zi="1502.05" zo="1511.92" ri="436.56" ro="1191.7" wi="70.84" wo="170.84" eta="1" phi="2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48" dphi="3.75" /> -<ATrd n="TGC_T4F1" zi="698.06" zo="702.43" ri="217" ro="443.4" wi="62.38" wo="121.99" eta="1" phi="1 3 4 6 7 9 10 12 13 15 16 18 19 21 22 24" dphi="7.5" /> -<ATrd n="TGC_T4F1" zi="693.04" zo="697.41" ri="217" ro="433.4" wi="62.38" wo="119.36" eta="1" phi="2 5 8 11 14 17 20 23" dphi="7.5" /> -<ATrd n="TGC_T4E1" zi="730.87" zo="735.24" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="1 4 7" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="2" dphi="-5.5" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="3 6" dphi="5.5" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="5 8" dphi="-5.5" /> -<ATrd n="TGC_T4E1" zi="730.87" zo="735.24" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="9 12" dphi="15" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="10" dphi="9.5" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="11 14" dphi="20.5" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="13" dphi="9.5" /> -<ATrd n="TGC_T4E1" zi="730.87" zo="735.24" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="15" dphi="15" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="16" dphi="35.5" /> -<ATrd n="TGC_T4E1" zi="730.87" zo="735.24" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="17" dphi="30" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="470" ro="619" wi="83.33" wo="108.09" eta="1" phi="18" dphi="24.5" /> -<ATrd n="TGC_T4E1" zi="730.87" zo="735.24" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="19" dphi="45" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="20" dphi="39.5" /> -<ATrd n="TGC_T4E1" zi="737.53" zo="741.9" ri="520" ro="619" wi="91.64" wo="108.09" eta="1" phi="21" dphi="50.5" /> -<ATrd n="MDT_EIS1" zi="707.746" zo="744.46" ri="207.6" ro="335.249" wi="89.85" wo="128.1" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="MDT_EIS2" zi="707.746" zo="744.46" ri="337.1" ro="446.728" wi="127.65" wo="160.5" eta="2" phi="1 2 3 4 5 6 7 8" dphi="22.5" /> -<ATrd n="CSC_CSS1" zi="708.102" zo="738.022" ri="86.6016" ro="207.832" wi="40.29" wo="75.7865" eta="1" phi="1 2 3 4 5 6 7 8" dphi="22.5" a="-11.587" /> -<ATrd n="CSC_CSL1" zi="744.539" zo="774.459" ri="92.0422" ro="206.732" wi="61.01" wo="117.027" eta="1" phi="1 2 3 4 5 6 7 8" a="-11.587" /> -<ABox n="MDT_BIM" zi="107" zo="216.628" ri="519.465" ro="561.079" w="153.65" eta="1" phi="6" sh="-56.6" /> -<ABox n="MDT_BIM" zi="107" zo="216.628" ri="519.465" ro="561.079" w="153.65" eta="1" phi="8" sh="56.6" /> -<ABox n="MDT_BIM" zi="217" zo="326.628" ri="519.465" ro="561.079" w="153.65" eta="2" phi="6" sh="-56.6" /> -<ABox n="MDT_BIM" zi="217" zo="326.628" ri="519.465" ro="561.079" w="153.65" eta="2" phi="8" sh="56.6" /> -<ABox n="MDT_BIM" zi="327" zo="436.628" ri="519.465" ro="561.079" w="153.65" eta="3" phi="6" sh="-56.6" /> -<ABox n="MDT_BIM" zi="327" zo="436.628" ri="519.465" ro="561.079" w="153.65" eta="3" phi="8" sh="56.6" /> -<ABox n="MDT_BIM" zi="437" zo="546.628" ri="519.465" ro="561.079" w="153.65" eta="4" phi="6" sh="-56.6" /> -<ABox n="MDT_BIM" zi="437" zo="546.628" ri="519.465" ro="561.079" w="153.65" eta="4" phi="8" sh="56.6" /> -<ABox n="MDT_BIM" zi="547" zo="656.628" ri="519.465" ro="561.079" w="153.65" eta="5" phi="6" sh="-56.6" /> -<ABox n="MDT_BIM" zi="547" zo="656.628" ri="519.465" ro="561.079" w="153.65" eta="5" phi="8" sh="56.6" /> -</AMuonGeometry> diff --git a/graphics/AtlantisJava/geometry/ATLAS_IDS.xml b/graphics/AtlantisJava/geometry/ATLAS_IDS.xml deleted file mode 100755 index 81f4d7c3a44..00000000000 --- a/graphics/AtlantisJava/geometry/ATLAS_IDS.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE IdDict SYSTEM "IdDict.dtd" [ - <!ENTITY InnerDetector SYSTEM "IdDictInnerDetector.xml"> - <!ENTITY LArCalorimeter SYSTEM "IdDictLArCalorimeter.xml"> - <!ENTITY TileCalorimeter SYSTEM "IdDictTileCalorimeter.xml"> - <!ENTITY Calorimeter SYSTEM "IdDictCalorimeter.xml"> - <!ENTITY MuonSpectrometer SYSTEM "IdDictMuonSpectrometer.xml"> - <!ENTITY ATLAS SYSTEM "IdDictATLAS.xml"> - <!ENTITY LArHighVoltage SYSTEM "IdDictLArHighVoltage.xml"> - <!ENTITY LArElectrode SYSTEM "IdDictLArElectrode.xml"> - <!ENTITY ForwardDetectors SYSTEM "IdDictForwardDetectors.xml"> -]> - -<IdDict IdDictVersion="v1"> - -&InnerDetector; -&LArCalorimeter; -&TileCalorimeter; -&Calorimeter; -&MuonSpectrometer; -&ATLAS; -&LArHighVoltage; -&LArElectrode; -&ForwardDetectors; - -</IdDict> - diff --git a/graphics/AtlantisJava/geometry/IdDict.dtd b/graphics/AtlantisJava/geometry/IdDict.dtd deleted file mode 100755 index 5077ec98a63..00000000000 --- a/graphics/AtlantisJava/geometry/IdDict.dtd +++ /dev/null @@ -1,118 +0,0 @@ -<?xml encoding="US-ASCII"?> - -<!-- IdDict: Identifier Dictionary - ========================== - - o This describes the possible identifier ranges. - - o One may describe several identifier dictionaries, each by a IdDictionary element. - A dictionary is identified by its name. - - o Each dictionary may describe : - - + individual identifier fields ("field"). - - - This is useful when the field values are individually labelled. - - purely numeric fields do not need to be explicitly - described, in which case, their possible ranges will be deduced from the defined - regions. - - + identifier regions ("region"). - - - they are the alternate identifier ranges for this dictionary. - - a region specifies a contiguous range of identifiers, complete for the dictionary. - - it may be labelled with a "name". - - it may also have a "tag" (see alternate regions) - - it contains the ordered list of fields with their explicit value range. - - each entry in this list may be - - a range assigned to a given field ("range") - - a reference to a subregion ("reference") (see below) - - a reference to a complete identifier domain ("identifiers") - - a list of alternative ranges which are differentiated according - to their tag ("alternate_ranges") - - + alternate regions ("alternate_regions"). - - - this contains two or more alternate region specifications - which are differentiated by their "tag". An empty tag is - default. This allows at generation time to select a specific - tag. - - + subregions ("subregion") - - - A subregion speficies a contiguous range of identifiers, describing a - subset of the identifier fields in the dictionary. - - it must identified by a name. - - the role of subregions is to be referenced by regions, and they typically describe - the parts that are common to several regions. - ---> - - - -<!ENTITY % DTD_constraint 'IdDictVersion ( v1 ) #REQUIRED'> - -<!ELEMENT IdDict ( IdDictionary )* > -<!ATTLIST IdDict - %DTD_constraint;> - -<!ELEMENT IdDictionary ( field | subregion | region | alternate_regions )* > -<!ATTLIST IdDictionary - name ID #REQUIRED - version CDATA #IMPLIED - date CDATA #IMPLIED - author CDATA #IMPLIED> - - -<!ELEMENT field ( label )* > -<!ATTLIST field - name CDATA #REQUIRED > - -<!ELEMENT label EMPTY> -<!ATTLIST label - name CDATA #REQUIRED - value CDATA #IMPLIED> - -<!ELEMENT alternate_regions ( region )* > -<!ATTLIST alternate_regions - name CDATA #IMPLIED> - -<!ELEMENT region ( range | reference | dictionary )* > -<!ATTLIST region - name CDATA #IMPLIED - group CDATA #IMPLIED - tag CDATA #IMPLIED - next_abs_eta CDATA #IMPLIED - prev_samp CDATA #IMPLIED - next_samp CDATA #IMPLIED - prev_subdet CDATA #IMPLIED - next_subdet CDATA #IMPLIED - eta0 CDATA #IMPLIED - deta CDATA #IMPLIED - phi0 CDATA #IMPLIED - dphi CDATA #IMPLIED> - -<!ELEMENT range EMPTY> -<!ATTLIST range - field CDATA #REQUIRED - value CDATA #IMPLIED - minvalue CDATA #IMPLIED - maxvalue CDATA #IMPLIED - values CDATA #IMPLIED - prev_value CDATA #IMPLIED - next_value CDATA #IMPLIED - wraparound (TRUE | false) "false"> - -<!ELEMENT reference EMPTY> -<!ATTLIST reference - subregion IDREF #REQUIRED> - -<!ELEMENT dictionary EMPTY> -<!ATTLIST dictionary - name IDREF #REQUIRED> - -<!ELEMENT subregion ( range | reference | dictionary )* > -<!ATTLIST subregion - name ID #REQUIRED> - - diff --git a/graphics/AtlantisJava/geometry/IdDictATLAS.xml b/graphics/AtlantisJava/geometry/IdDictATLAS.xml deleted file mode 100755 index 95314ee2c0d..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictATLAS.xml +++ /dev/null @@ -1,56 +0,0 @@ - -<IdDictionary name="ATLAS"> - - <field name="subdet"> - <label name="InnerDetector" value="2" /> - <label name="LArCalorimeter" value="4" /> - <label name="TileCalorimeter" value="5" /> - <label name="MuonSpectrometer" value="7" /> - <label name="Calorimeter" value="10" /> - <label name="LArHighVoltage" value="11" /> - <label name="LArElectrode" value="12" /> - <label name="ForwardDetectors" value="13" /> - </field> - - <region> - <range field="subdet" value="InnerDetector" /> - <dictionary name="InnerDetector" /> - </region> - - <region> - <range field="subdet" value="LArCalorimeter" /> - <dictionary name="LArCalorimeter" /> - </region> - - <region> - <range field="subdet" value="TileCalorimeter" /> - <dictionary name="TileCalorimeter" /> - </region> - - <region> - <range field="subdet" value="MuonSpectrometer" /> - <dictionary name="MuonSpectrometer" /> - </region> - - <region> - <range field="subdet" value="Calorimeter" /> - <dictionary name="Calorimeter" /> - </region> - - <region> - <range field="subdet" value="LArHighVoltage" /> - <dictionary name="LArHighVoltage" /> - </region> - - <region> - <range field="subdet" value="LArElectrode" /> - <dictionary name="LArElectrode" /> - </region> - - <region> - <range field="subdet" value="ForwardDetectors" /> - <dictionary name="ForwardDetectors" /> - </region> - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictCalorimeter.xml b/graphics/AtlantisJava/geometry/IdDictCalorimeter.xml deleted file mode 100755 index f94f801d91e..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictCalorimeter.xml +++ /dev/null @@ -1,731 +0,0 @@ - -<IdDictionary name="Calorimeter" > - - -<field name="DetZside" > - <label name="negative_DMTile_side" value="-5" /> - <label name="negative_DMLar_side" value="-4" /> - <label name="negative_eta_side" value="-2" /> - <label name="negative_lvl1_side" value="-1" /> - <label name="positive_lvl1_side" value="+1" /> - <label name="positive_eta_side" value="+2" /> - <label name="positive_DMLar_side" value="+4" /> - <label name="positive_DMTile_side" value="+5" /> -</field> - - -<!-- Dead Material Types --> -<!-- xxxxxxxxxxxxxxxxxxxx --> - -<!-- 3 types of LAr Dead Material --> - - <subregion name="DMLArOutside" > - <range field="DetZside" values="negative_DMLar_side positive_DMLar_side" /> - <range field="DMvalue" value="1" /> - </subregion> - - <subregion name="DMLarInside" > - <range field="DetZside" values="negative_DMLar_side positive_DMLar_side" /> - <range field="DMvalue" value="2" /> - </subregion> - - <subregion name="DMLArBeamTest"> - <range field="DetZside" values="negative_DMLar_side positive_DMLar_side" /> - <range field="DMvalue" value="3" /> - </subregion> - -<!-- 2 types of Tile Dead Material --> - - <subregion name="DMTileOutside" > - <range field="DetZside" values="negative_DMTile_side positive_DMTile_side" /> - <range field="DMvalue" value="1" /> - </subregion> - - <subregion name="DMTileDefHits" > - <range field="DetZside" values="negative_DMTile_side positive_DMTile_side" /> - <range field="DMvalue" value="2" /> - </subregion> - - <subregion name="DMTileBeamTest" > - <range field="DetZside" values="negative_DMTile_side positive_DMTile_side" /> - <range field="DMvalue" value="3" /> - </subregion> - - - -<!-- Dead Material Phi regions --> -<!-- xxxxxxxxxxxxxxxxxxxxxxxxxx --> - -<!-- 3 types of Phi region --> - - <subregion name="DMPhi-1" > - <range field="phivalue" minvalue="0" maxvalue="63" wraparound="TRUE" /> - </subregion> - - <subregion name="DMPhi-2" > - <range field="phivalue" minvalue="0" maxvalue="31" wraparound="TRUE" /> - </subregion> - - <subregion name="DMPhi-3" > - <range field="phivalue" value="0" wraparound="TRUE" /> - </subregion> - - - -<!-- LAr DM Samplings --> -<!-- xxxxxxxxxxxxxxxxx --> - - -<!-- 4 sampling region: 0 to 3 --> - - <subregion name="DMLArSampling-0" > - <range field="samplingvalue" value="0" /> - </subregion> - - <subregion name="DMLArSampling-1" > - <range field="samplingvalue" value="1" /> - </subregion> - - <subregion name="DMLArSampling-2" > - <range field="samplingvalue" value="2" /> - </subregion> - - <subregion name="DMLArSampling-3" > - <range field="samplingvalue" value="3" /> - </subregion> - - -<!-- Tile DM Samplings --> -<!-- xxxxxxxxxxxxxxxxx --> - - -<!-- 4 sampling region: 0 to 3 --> - - - <subregion name="DMTileSampling-0" > - <range field="samplingvalue" value="0" /> - </subregion> - - <subregion name="DMTileSampling-1" > - <range field="samplingvalue" value="1" /> - </subregion> - - <subregion name="DMTileSampling-2" > - <range field="samplingvalue" value="2" /> - </subregion> - - <subregion name="DMTileSampling-3" > - <range field="samplingvalue" value="3" /> - </subregion> - - - -<!-- LAr DM regions --> -<!-- xxxxxxxxxxxxxx --> - -<!-- type 1, sampling 0, regions 0 to 5 --> - - <region group="DM_Reg" name="DM_4_1_0_0" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" minvalue="0" maxvalue="5" /> - <range field="DMEta" minvalue="0" maxvalue="49" /> - <reference subregion="DMPhi-1" /> - </region> - -<!-- type 1, sampling 1, region 0 to 7--> - - <region group="DM_Reg" name="DM_4_1_1_0" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="14" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_1" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="14" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_2" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="15" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_3" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="15" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_4" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="4" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_5" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="2" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_6" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="6" /> - <range field="DMEta" minvalue="0" maxvalue="18" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_1_7" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="7" /> - <range field="DMEta" minvalue="0" maxvalue="17" /> - <reference subregion="DMPhi-1" /> - </region> - -<!-- type 1, sampling 2, region 0 to 5--> - - <region group="DM_Reg" name="DM_4_1_2_0" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_2_1" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_2_2" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="4" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_2_3" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="17" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_2_4" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="4" /> - <range field="DMEta" minvalue="0" maxvalue="17" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_2_5" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="6" /> - <reference subregion="DMPhi-1" /> - </region> - - -<!-- type 1, sampling 3, region 0 to 2--> - - <region group="DM_Reg" name="DM_4_1_3_0" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="32" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_3_1" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="14" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_1_3_2" > - <reference subregion="DMLArOutside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="2" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-3" /> - </region> - - -<!-- type 2, sampling [0,3], region 0 to 5--> - - <region group="DM_Reg" name="DM_4_2_0_0" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="0" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_0_1" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="1" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - - <region group="DM_Reg" name="DM_4_2_0_2" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_0_3" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_0_4" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="4" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_0_5" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-0" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="19" /> - <reference subregion="DMPhi-1" /> - </region> - - - <region group="DM_Reg" name="DM_4_2_1_0" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="0" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_1_1" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="1" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_1_2" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_1_3" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_1_4" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="4" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_1_5" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-1" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="19" /> - <reference subregion="DMPhi-1" /> - </region> - - - <region group="DM_Reg" name="DM_4_2_2_0" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="0" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_2_1" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="1" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_2_2" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_2_3" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_2_4" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="4" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_2_5" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-2" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="19" /> - <reference subregion="DMPhi-1" /> - </region> - - - <region group="DM_Reg" name="DM_4_2_3_0" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="0" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_3_1" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="1" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_3_2" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_3_3" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="3" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-2" /> - </region> - - <region group="DM_Reg" name="DM_4_2_3_4" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="4" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_4_2_3_5" > - <reference subregion="DMLarInside" /> - <reference subregion="DMLArSampling-3" /> - <range field="DMregion" value="5" /> - <range field="DMEta" minvalue="0" maxvalue="19" /> - <reference subregion="DMPhi-1" /> - </region> - - -<!-- TILE DM regions --> -<!-- xxxxxxxxxxxxxxx --> - -<!-- type 1, sampling 0, region 0 to 1 --> - - <region group="DM_Reg" name="DM_5_1_0_0" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-0" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="9" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_5_1_0_1" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-0" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="4" /> - <reference subregion="DMPhi-1" /> - </region> - -<!-- type 1, sampling 1, region 0 to 2 --> - - <region group="DM_Reg" name="DM_5_1_1_0" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-1" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_5_1_1_1" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-1" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="2" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_5_1_1_2" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-1" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="3" /> - <reference subregion="DMPhi-1" /> - </region> - - -<!-- type 1, sampling 2, region 0 to 2 --> - - <region group="DM_Reg" name="DM_5_1_2_0" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-2" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="7" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_5_1_2_1" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-2" /> - <range field="DMregion" value="1" /> - <range field="DMEta" minvalue="0" maxvalue="4" /> - <reference subregion="DMPhi-1" /> - </region> - - <region group="DM_Reg" name="DM_5_1_2_2" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-2" /> - <range field="DMregion" value="2" /> - <range field="DMEta" minvalue="0" maxvalue="1" /> - <reference subregion="DMPhi-1" /> - </region> - -<!-- type 1, sampling 3, region 0 --> - - <region group="DM_Reg" name="DM_5_1_3_0" > - <reference subregion="DMTileOutside" /> - <reference subregion="DMTileSampling-3" /> - <range field="DMregion" value="0" /> - <range field="DMEta" minvalue="0" maxvalue="16" /> - <reference subregion="DMPhi-1" /> - </region> - -<!-- type 2, sampling 0, region 0 --> - - <region group="DM_Reg" name="DM_5_2_0_0" > - <reference subregion="DMTileDefHits" /> - <reference subregion="DMTileSampling-0" /> - <range field="DMregion" value="0" /> - <range field="DMEta" value="0" /> - <reference subregion="DMPhi-3" /> - </region> - - -<!-- LVL1 part --> -<!-- xxxxxxxxxxxxxxxxx --> - - <field name="LVL1sampling" > - <label name="EM" value="0" /> - <label name="Hadronic" value="1" /> - </field> - - <subregion name="LVL1" > - <range field="DetZside" values="negative_lvl1_side positive_lvl1_side" /> - <range field="LVL1sampling" values="EM Hadronic" /> - </subregion> - - - <region group="Reg_Lvl1" name="Lvl1_0" > - <reference subregion="LVL1" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="24" /> - <range field="phi" minvalue="0" maxvalue="63" wraparound="TRUE" /> - <range field="layer" minvalue="0" maxvalue="3" /> - </region> - - <region group="Reg_Lvl1" name="Lvl1_1" > - <reference subregion="LVL1" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="2" /> - <range field="phi" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer" minvalue="0" maxvalue="3" /> - </region> - - <region group="Reg_Lvl1" name="Lvl1_2" > - <reference subregion="LVL1" /> - <range field="region" value="2" /> - <range field="eta" value="0" /> - <range field="phi" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer" minvalue="0" maxvalue="3" /> - </region> - - - <region group="Reg_Lvl1" name="Lvl1_3" > - <reference subregion="LVL1" /> - <range field="region" value="3" /> - <range field="eta" minvalue="0" maxvalue="3"/> - <range field="phi" minvalue="0" maxvalue="15" wraparound="TRUE" /> - <range field="layer" minvalue="0" maxvalue="1" /> - </region> - - - -<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --> -<!-- Online L1 Trigger Tower regions --> -<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --> - - -<!-- Fields used to describe a TTower --> - - <field name="barrel_endcap_fcal" > - <label name="barrel" value="0" /> - <label name="endcap" value="1" /> - <label name="fcal" value="2" /> - </field> - - <field name="em_had" > - <label name="em" value="0" /> - <label name="had" value="1" /> - </field> - - -<!-- Subregion definition --> - - <subregion name="OnlineL1-barrel" > - <range field="DetZside" values="negative_eta_side positive_eta_side" /> - <range field="barrel_endcap_fcal" value="barrel" /> - </subregion> - - <subregion name="OnlineL1-endcap" > - <range field="DetZside" values="negative_eta_side positive_eta_side" /> - <range field="barrel_endcap_fcal" value="endcap" /> - </subregion> - - <subregion name="OnlineL1-fcal" > - <range field="DetZside" values="negative_eta_side positive_eta_side" /> - <range field="barrel_endcap_fcal" value="fcal" /> - </subregion> - - -<!-- Online L1 EM-Barrel --> -<!-- xxxxxxxxxxxxxxxxxxxx --> - -<region group="Online_L1" name="l1_barrel" > - <reference subregion="OnlineL1-barrel" /> - <range field="em_had" value="em" /> - <range field="tower_eta" minvalue="1" maxvalue="15" /> - <range field="tower_phi" minvalue="1" maxvalue="64" /> - <range field="tower_layer" minvalue="0" maxvalue="3" /> - </region> - - -<!-- Online L1 EM Endcap --> -<!-- xxxxxxxxxxxxxxxxxxxx --> - -<region group="Online_L1" name="l1_emec_region1" > - <reference subregion="OnlineL1-endcap" /> - <range field="em_had" value="em" /> - <range field="tower_eta" minvalue="1" maxvalue="11" /> - <range field="tower_phi" minvalue="1" maxvalue="64" /> - <range field="tower_layer" minvalue="0" maxvalue="3" /> -</region> - -<region group="Online_L1" name="l1_emec_region2" > - <reference subregion="OnlineL1-endcap" /> - <range field="em_had" value="em" /> - <range field="tower_eta" minvalue="12" maxvalue="15" /> - <range field="tower_phi" minvalue="1" maxvalue="32" /> - <range field="tower_layer" minvalue="0" maxvalue="3" /> -</region> - -<!-- Online L1 HEC Endcap --> -<!-- xxxxxxxxxxxxxxxxxxxxx --> - -<region group="Online_L1" name="l1_hec_region1" > - <reference subregion="OnlineL1-endcap" /> - <range field="em_had" value="had" /> - <range field="tower_eta" minvalue="2" maxvalue="11" /> - <range field="tower_phi" minvalue="1" maxvalue="64" /> - <range field="tower_layer" minvalue="0" maxvalue="3" /> -</region> - -<region group="Online_L1" name="l1_hec_region2" > - <reference subregion="OnlineL1-endcap" /> - <range field="em_had" value="had" /> - <range field="tower_eta" minvalue="12" maxvalue="15" /> - <range field="tower_phi" minvalue="1" maxvalue="32" /> - <range field="tower_layer" minvalue="0" maxvalue="3" /> -</region> - - -<!-- Online L1 FCAL --> -<!-- xxxxxxxxxxxxxxx --> - -<region group="Online_L1" name="l1_fcal_em" > - <reference subregion="OnlineL1-fcal" /> - <range field="em_had" value="em" /> - <range field="tower_eta" minvalue="1" maxvalue="4" /> - <range field="tower_phi" minvalue="1" maxvalue="16" /> - <range field="tower_layer" value="0" /> -</region> - -<region group="Online_L1" name="l1_fcal_had" > - <reference subregion="OnlineL1-fcal" /> - <range field="em_had" value="had" /> - <range field="tower_eta" minvalue="1" maxvalue="4" /> - <range field="tower_phi" minvalue="1" maxvalue="16" /> - <range field="tower_layer" minvalue="0" maxvalue="1" /> -</region> - - -</IdDictionary> diff --git a/graphics/AtlantisJava/geometry/IdDictForwardDetectors.xml b/graphics/AtlantisJava/geometry/IdDictForwardDetectors.xml deleted file mode 100644 index 588eb81db1c..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictForwardDetectors.xml +++ /dev/null @@ -1,140 +0,0 @@ - - -<!-- - - The ForwardDetectors identifier is arranged as follows - - ForwardDetectors - part=BCM - <to be defined> - - part=BCM_Online - <to be defined> - - part=LUCID - <to be defined> - - part=LUCID_Online - <to be defined> - - part=ZDC - side module type channel - - part=ZDC_Online - side module type channel gain delay - - --> - -<IdDictionary name="ForwardDetectors" > - - <!-- - Start by defining some symbolic labels used for some fields - (other fields will be specified by numeric ranges) - --> - - <field name="part" > - <label name="ALFA" value="1" /> - <label name="ALFA_Online" value="2" /> - <label name="BCM" value="3" /> - <label name="BCM_Online" value="4" /> - <label name="LUCID" value="5" /> - <label name="LUCID_Online" value="6" /> - <label name="ZDC" value="7" /> - <label name="ZDC_Online" value="8" /> - <label name="Extra" value="9" /> - <label name="Extra_Online" value="10" /> - </field> - - <field name="side"> - <label name="negative" value="-1" /> - <label name="positive" value="+1" /> - </field> - - - <!-- - - ALFA - to do - - --> - - <region group="ALFA" name = "alfa"> - <range field="part" value="ALFA" /> - </region> - - <region group="ALFA_Online" name = "alfa"> - <range field="part" value="ALFA_Online" /> - </region> - - <!-- - - BCM - to do - - --> - - <region group="BCM" name = "bcm"> - <range field="part" value="BCM" /> - </region> - - <region group="BCM_Online" name = "bcm"> - <range field="part" value="BCM_Online" /> - </region> - - <!-- - - LUCID - to do - - --> - - <region group="LUCID" name = "lucid"> - <range field="part" value="LUCID" /> - </region> - - <region group="LUCID_Online" name = "lucid"> - <range field="part" value="LUCID_Online" /> - </region> - - <!-- - - ZDC - - --> - - <!-- ZDC - offline --> - - <region group="ZDC" name = "zdc"> - <range field="part" value="ZDC" /> - <range field="side" values="negative positive"/> - <range field="module" minvalue="0" maxvalue="3"/> - <range field="type" minvalue="0" maxvalue="1" /> - <range field="channel" minvalue="0" maxvalue="63" /> - </region> - - <!-- ZDC - online --> - - <region group="ZDC_Online" name = "zdc_online"> - <range field="part" value="ZDC_Online" /> - <range field="side" values="negative positive"/> - <range field="module" minvalue="0" maxvalue="3"/> - <range field="type" minvalue="0" maxvalue="1" /> - <range field="channel" minvalue="0" maxvalue="63" /> - <range field="gain" minvalue="0" maxvalue="1" /> - <range field="delay" minvalue="0" maxvalue="1" /> - </region> - - <!-- - - EXTRA - to do - - --> - - <region group="EXTRA" name = "extra"> - <range field="part" value="Extra" /> - </region> - - <region group="EXTRA_Online" name = "extra"> - <range field="part" value="Extra_Online" /> - </region> - - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictInnerDetector.xml b/graphics/AtlantisJava/geometry/IdDictInnerDetector.xml deleted file mode 100755 index 98c405c193a..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictInnerDetector.xml +++ /dev/null @@ -1,559 +0,0 @@ - - -<!-- - - The InnerDetector identifier is arranged as follows - - InnerDetector - part=Pixel - side=barrel - layer phi_module eta_module phi_index eta_index - side=endcap - disk phi_module eta_module phi_index eta_index - - part=SCT - side=barrel - layer phi_module eta_module side strip - side=endcap - disk phi_module eta_module side strip - - part=TRT - side=barrel - layer phi_module straw_layer straw - side=endcap - wheel phi_module straw_layer straw - - - --> - -<IdDictionary name="InnerDetector" > - - <!-- - Start by defining some symbolic labels used for some fields - (other fields will be specified by numeric ranges) - --> - - <field name="part" > - <label name="Pixel" value="1" /> - <label name="SCT" value="2" /> - <label name="TRT" value="3" /> - </field> - - <field name="barrel_endcap"> - <label name="negative_endcap" value="-2" /> - <label name="negative_barrel" value="-1" /> - <label name="barrel" value="0" /> - <label name="positive_barrel" value="+1" /> - <label name="positive_endcap" value="+2" /> - </field> - - - - <!-- - - Pixel - - --> - - <!-- Dummy region: This forces the bit packing to be the same for all layouts --> - - <region group="pixel" name = "dummy"> - <range field="part" value="Pixel" /> - <range field="barrel_endcap" values="negative_endcap barrel positive_endcap"/> - <range field="layer" minvalue="0" maxvalue="2"/> - <range field="phi_module" minvalue="0" maxvalue="51" /> - <range field="eta_module" minvalue="-6" maxvalue="+6" /> - <range field="phi_index" minvalue="0" maxvalue="327" /> - <range field="eta_index" minvalue="0" maxvalue="191" /> - </region> - - - <!-- - Define few subregions which are re-used in several id-ranges. - --> - - <subregion name="pixel_barrel"> - <range field="part" value="Pixel" /> - <range field="barrel_endcap" value="barrel" /> - </subregion> - - <subregion name="pixel_endcap"> - <range field="part" value="Pixel" /> - <range field="barrel_endcap" values="negative_endcap positive_endcap" /> - </subregion> - - <subregion name="pixel_default_eta_module"> - <range field="phi_index" minvalue="0" maxvalue="327" /> - <range field="eta_index" minvalue="0" maxvalue="143" /> - </subregion> - - <subregion name="pixel_phi_barrel_module"> - <range field="eta_module" minvalue="-6" maxvalue="+6" /> - <reference subregion="pixel_default_eta_module" /> - </subregion> - - <subregion name="pixel_phi_endcap_module"> - <range field="eta_module" value="0" /> - <reference subregion="pixel_default_eta_module" /> - </subregion> - - <!-- - Then enumerate all the possible regions of the Pixel subdetector. - Each region corresponds to an identifier range. - --> - - <!-- - The follow region is the pixel b-layer. Normally, the correct - phi_index max should be 319, but we set it to 327 as for the other - layers to allow to calculate the pixel_id from SiDigit, i.e. using - the G3 numbering which is not completely correct. This should be a - temporary fix. Correct specif: - <range field="phi_index" minvalue="0" maxvalue="319" /> - --> - <alternate_regions> - <region group="pixel" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="21" wraparound="TRUE" /> - <range field="eta_module" minvalue="-6" maxvalue="+6" /> - <range field="phi_index" minvalue="0" maxvalue="327" /> - <range field="eta_index" minvalue="0" maxvalue="191" /> - </region> - <region group="pixel" tag="initial_layout" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="21" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - <region group="pixel" tag="final_layout" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="21" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - <region group="pixel" tag="destaged_layout" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="21" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - </alternate_regions> - - <alternate_regions> - <region group="pixel" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="1" /> - <range field="phi_module" minvalue="0" maxvalue="37" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - <region group="pixel" tag="initial_layout" /> - <region group="pixel" tag="final_layout" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="1" /> - <range field="phi_module" minvalue="0" maxvalue="37" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - <region group="pixel" tag="destaged_layout" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="1" /> - <range field="phi_module" minvalue="0" maxvalue="37" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - </alternate_regions> - - <region group="pixel" > - <reference subregion="pixel_barrel" /> - <range field="layer" value="2" /> - <range field="phi_module" minvalue="0" maxvalue="51" wraparound="TRUE" /> - <reference subregion="pixel_phi_barrel_module" /> - </region> - - <alternate_regions> - <region group="pixel" > - <reference subregion="pixel_endcap" /> - <range field="disk" minvalue="0" maxvalue="2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="pixel_phi_endcap_module" /> - </region> - <region group="pixel" tag="initial_layout" > - <reference subregion="pixel_endcap" /> - <range field="disk" values="0 2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="pixel_phi_endcap_module" /> - </region> - <region group="pixel" tag="final_layout" > - <reference subregion="pixel_endcap" /> - <range field="disk" minvalue="0" maxvalue="2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="pixel_phi_endcap_module" /> - </region> - <region group="pixel" tag="destaged_layout" > - <reference subregion="pixel_endcap" /> - <range field="disk" minvalue="0" maxvalue="2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="pixel_phi_endcap_module" /> - </region> - </alternate_regions> - - - - <!-- - - SCT - - --> - - - <subregion name="SCT_barrel"> - <range field="part" value="SCT" /> - <range field="barrel_endcap" value="barrel" /> - </subregion> - - <subregion name="SCT_endcap"> - <range field="part" value="SCT" /> - <range field="barrel_endcap" values="negative_endcap positive_endcap" /> - </subregion> - - <subregion name="SCT_eta_module"> - <range field="side" minvalue="0" maxvalue="1" /> - <range field="strip" minvalue="0" maxvalue="767" /> - </subregion> - - - - - <subregion name="SCT_phi_negative_barrel_module"> - <range field="eta_module" minvalue="-6" maxvalue="-1" next_value="1" /> - <reference subregion="SCT_eta_module" /> - </subregion> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <reference subregion="SCT_phi_negative_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="1" /> - <range field="phi_module" minvalue="0" maxvalue="39" wraparound="TRUE" /> - <reference subregion="SCT_phi_negative_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="SCT_phi_negative_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="3" /> - <range field="phi_module" minvalue="0" maxvalue="55" wraparound="TRUE"/> - <reference subregion="SCT_phi_negative_barrel_module" /> - </region> - - - - - - <subregion name="SCT_phi_positive_barrel_module"> - <range field="eta_module" minvalue="+1" maxvalue="+6" prev_value="-1" /> - <reference subregion="SCT_eta_module" /> - </subregion> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="0" /> - <range field="phi_module" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <reference subregion="SCT_phi_positive_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="1" /> - <range field="phi_module" minvalue="0" maxvalue="39" wraparound="TRUE" /> - <reference subregion="SCT_phi_positive_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="2" /> - <range field="phi_module" minvalue="0" maxvalue="47" wraparound="TRUE" /> - <reference subregion="SCT_phi_positive_barrel_module" /> - </region> - - <region group="sct" > - <reference subregion="SCT_barrel" /> - <range field="layer" value="3" /> - <range field="phi_module" minvalue="0" maxvalue="55" wraparound="TRUE" /> - <reference subregion="SCT_phi_positive_barrel_module" /> - </region> - - <subregion name="SCT_ring_0"> - <range field="phi_module" minvalue="0" maxvalue="51" wraparound="TRUE" /> - <range field="eta_module" value="0" /> - <reference subregion="SCT_eta_module" /> - </subregion> - - <subregion name="SCT_ring_1"> - <range field="phi_module" minvalue="0" maxvalue="39" wraparound="TRUE" /> - <range field="eta_module" value="1" /> - <reference subregion="SCT_eta_module" /> - </subregion> - - <subregion name="SCT_ring_1_2"> - <range field="phi_module" minvalue="0" maxvalue="39" wraparound="TRUE" /> - <range field="eta_module" minvalue="1" maxvalue="2" /> - <reference subregion="SCT_eta_module" /> - </subregion> - - <region group="sct" name="SCT_endcap_ring0_disks08"> - <reference subregion="SCT_endcap" /> - <range field="disk" minvalue="0" maxvalue="8" /> - <reference subregion="SCT_ring_0" /> - </region> - - - <region group="sct" name="SCT_endcap_ring1_disk0"> - <reference subregion="SCT_endcap" /> - <range field="disk" value="0" /> - <reference subregion="SCT_ring_1" /> - </region> - - <region group="sct" name="SCT_endcap_rings12_disks15"> - <reference subregion="SCT_endcap" /> - <range field="disk" minvalue="1" maxvalue="5" /> - <reference subregion="SCT_ring_1_2" /> - </region> - - <region group="sct" name="SCT_endcap_ring1_disks67"> - <reference subregion="SCT_endcap" /> - <range field="disk" minvalue="6" maxvalue="7" /> - <reference subregion="SCT_ring_1" /> - </region> - - <!-- - - TRT - - --> - - <subregion name="TRT_barrel"> - <range field="part" value="TRT" /> - <range field="barrel_endcap" values="negative_barrel positive_barrel" /> - </subregion> - - <subregion name="TRT_endcap"> - <range field="part" value="TRT" /> - <range field="barrel_endcap" values="negative_endcap positive_endcap" /> - </subregion> - - - - <subregion name="TRT_layer_0"> - <reference subregion="TRT_barrel" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" value="0" /> - </subregion> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" value="0" /> - <range field="straw" minvalue="0" maxvalue="14" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" minvalue="1" maxvalue="4" /> - <range field="straw" minvalue="0" maxvalue="15" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" minvalue="5" maxvalue="9" /> - <range field="straw" minvalue="0" maxvalue="16" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" minvalue="10" maxvalue="14" /> - <range field="straw" minvalue="0" maxvalue="17" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" minvalue="15" maxvalue="17" /> - <range field="straw" minvalue="0" maxvalue="18" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_0" /> - <range field="straw_layer" value="18" /> - <range field="straw" minvalue="0" maxvalue="17" /> - </region> - - - - - - <subregion name="TRT_layer_1"> - <reference subregion="TRT_barrel" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" value="1" /> - </subregion> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" value="0" /> - <range field="straw" minvalue="0" maxvalue="18" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" minvalue="1" maxvalue="5" /> - <range field="straw" minvalue="0" maxvalue="19" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" minvalue="6" maxvalue="10" /> - <range field="straw" minvalue="0" maxvalue="20" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" minvalue="11" maxvalue="15" /> - <range field="straw" minvalue="0" maxvalue="21" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" minvalue="16" maxvalue="20" /> - <range field="straw" minvalue="0" maxvalue="22" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" minvalue="21" maxvalue="22" /> - <range field="straw" minvalue="0" maxvalue="23" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_1" /> - <range field="straw_layer" value="23" /> - <range field="straw" minvalue="0" maxvalue="22" /> - </region> - - - - - - <subregion name="TRT_layer_2"> - <reference subregion="TRT_barrel" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" value="2" /> - </subregion> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" value="0" /> - <range field="straw" minvalue="0" maxvalue="22" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="1" maxvalue="4" /> - <range field="straw" minvalue="0" maxvalue="23" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="5" maxvalue="9" /> - <range field="straw" minvalue="0" maxvalue="24" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="10" maxvalue="14" /> - <range field="straw" minvalue="0" maxvalue="25" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="15" maxvalue="19" /> - <range field="straw" minvalue="0" maxvalue="26" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="20" maxvalue="24" /> - <range field="straw" minvalue="0" maxvalue="27" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" minvalue="25" maxvalue="28" /> - <range field="straw" minvalue="0" maxvalue="28" /> - </region> - - <region group="trt" > - <reference subregion="TRT_layer_2" /> - <range field="straw_layer" value="29" /> - <range field="straw" minvalue="0" maxvalue="27" /> - </region> - - - - - <region group="trt" > - <reference subregion="TRT_endcap" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" minvalue="0" maxvalue="5" /> - <range field="straw_layer" minvalue="0" maxvalue="15" /> - <range field="straw" minvalue="0" maxvalue="23" /> - </region> - - <region group="trt" > - <reference subregion="TRT_endcap" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" minvalue="6" maxvalue="13" /> - <range field="straw_layer" minvalue="0" maxvalue="7" /> - <range field="straw" minvalue="0" maxvalue="23" /> - </region> - - <alternate_regions> - <region group="trt" > - <reference subregion="TRT_endcap" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" minvalue="14" maxvalue="17" /> - <range field="straw_layer" minvalue="0" maxvalue="15" /> - <range field="straw" minvalue="0" maxvalue="17" /> - </region> - <region group="trt" tag="initial_layout" /> - <region group="trt" tag="final_layout" > - <reference subregion="TRT_endcap" /> - <range field="phi_sector" minvalue="0" maxvalue="31" wraparound="TRUE" /> - <range field="layer_or_wheel" minvalue="14" maxvalue="17" /> - <range field="straw_layer" minvalue="0" maxvalue="15" /> - <range field="straw" minvalue="0" maxvalue="17" /> - </region> - <region group="trt" tag="destaged_layout" /> - </alternate_regions> - - <!-- Dummy region: This forces the bit packing to be the same for all layouts --> - - <region group="trt" name = "dummy"> - <range field="part" value="TRT" /> - <range field="barrel_endcap" values="negative_endcap negative_barrel positive_barrel positive_endcap"/> - <range field="phi_sector" minvalue="0" maxvalue="31" /> - <range field="layer_or_wheel" minvalue="0" maxvalue="17" /> - <range field="straw_layer" minvalue="0" maxvalue="29" /> - <range field="straw" minvalue="0" maxvalue="28" /> - </region> - - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictLArCalorimeter.xml b/graphics/AtlantisJava/geometry/IdDictLArCalorimeter.xml deleted file mode 100755 index 9eac43e8636..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictLArCalorimeter.xml +++ /dev/null @@ -1,694 +0,0 @@ -<IdDictionary name="LArCalorimeter" version="fullAtlas" > - - <field name="part" > - <label name="LArEM" value="1" /> - <label name="LArHEC" value="2" /> - <label name="LArFCAL" value="3" /> - <label name="LArOnline" value="4" /> - <label name="LArOnlineCalib" value="5" /> - <label name="LArEMdisc" value="-1" /> - <label name="LArHECdisc" value="-2" /> - <label name="LArFCALdisc" value="-3" /> - </field> - - <field name="barrel-endcap"> - <label name="negative-endcap-inner-wheel" value="-3" /> - <label name="negative-endcap-outer-wheel" value="-2" /> - <label name="negative-barrel" value="-1" /> - <label name="barrel" value="0" /> - <label name="positive-barrel" value="+1" /> - <label name="positive-endcap-outer-wheel" value="+2" /> - <label name="positive-endcap-inner-wheel" value="+3" /> - </field> - - <field name="barrel-ec"> - <label name="barrel" value="0" /> - <label name="endcap" value="1" /> - </field> - - <field name="pos_neg"> - <label name="negative-side" value="0" /> - <label name="positive-side" value="1" /> - </field> - - <subregion name="LArFCAL-module" > - <range field="phi-fcal" minvalue="0" maxvalue="15" wraparound="TRUE" /> - </subregion> - - <subregion name="LArEM-extralarge-module" > - <range field="phi" minvalue="0" maxvalue="31" wraparound="TRUE" /> - </subregion> - - <subregion name="LArEM-large-module" > - <range field="phi" minvalue="0" maxvalue="63" wraparound="TRUE" /> - </subregion> - - <subregion name="LArEM-thin-module" > - <range field="phi" minvalue="0" maxvalue="255" wraparound="TRUE" /> - </subregion> - - - - <!-- EM Barrel --> - - <subregion name="LArEM-barrel" > - <range field="part" value="LArEM" /> - <range field="barrel-endcap" values="negative-barrel positive-barrel" /> - </subregion> - - <region group="lar_em" name="LArEM-barrel-00" - next_samp="LArEM-barrel-10 LArEM-barrel-11" - next_subdet="LArEM-outer-wheel-10 LArEM-outer-wheel-00" - eta0="0.0" deta="0.025" phi0="0.0" dphi="64" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="0" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="60" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-10" next_abs_eta="LArEM-barrel-11" - prev_samp="LArEM-barrel-00" - next_samp="LArEM-barrel-20" - eta0="0.003125" deta="0.003125" phi0="0.0" dphi="64" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" minvalue="1" maxvalue="447" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-11" - prev_samp="LArEM-barrel-00" - next_samp="LArEM-barrel-21" - eta0="1.4" deta="0.025" phi0="0.0" dphi="256" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="1" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="2" /> - <reference subregion="LArEM-thin-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-20" next_abs_eta="LArEM-barrel-21" - prev_samp="LArEM-barrel-10" - next_samp="LArEM-barrel-30" - eta0="0.0" deta="0.025" phi0="0.0" dphi="256" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="2" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="55" /> - <reference subregion="LArEM-thin-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-21" - prev_samp="LArEM-barrel-11" - next_subdet="LArEM-outer-wheel-10" - eta0="1.4" deta="0.075" phi0="0.0" dphi="256" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="2" /> - <range field="region" value="1" /> - <range field="eta" value="0" /> - <reference subregion="LArEM-thin-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-30" - prev_samp="LArEM-barrel-20" eta0="0.0" deta="0.05" phi0="0.0" dphi="256" > - <reference subregion="LArEM-barrel" /> - <range field="sampling" value="3" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="26" /> - <reference subregion="LArEM-thin-module" /> - </region> - - - - <!-- EM outer wheel --> - - <subregion name="LArEM-outer-wheel" > - <range field="part" value="LArEM" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_em" name="LArEM-outer-wheel-00" - next_samp="LArEM-outer-wheel-12" - prev_subdet="LArEM-barrel-00" - eta0="1.5" deta="0.025" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="0" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="11" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-10" next_abs_eta="LArEM-outer-wheel-11" - next_samp="LArEM-outer-wheel-20" - prev_subdet="LArEM-barrel-00 LArEM-barrel-21" - eta0="1.375" deta="0.05" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" value="0" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-11" next_abs_eta="LArEM-outer-wheel-12" - next_samp="LArEM-outer-wheel-21" eta0="1.425" deta="0.025" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="2" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-12" next_abs_eta="LArEM-outer-wheel-13" - prev_samp="LArEM-outer-wheel-00" - next_samp="LArEM-outer-wheel-21" eta0="1.5" deta="0.003125" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="2" /> - <range field="eta" minvalue="0" maxvalue="95" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-13" next_abs_eta="LArEM-outer-wheel-14" - next_samp="LArEM-outer-wheel-21" eta0="1.8" deta="0.0041666666667" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="3" /> - <range field="eta" minvalue="0" maxvalue="47" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-14" next_abs_eta="LArEM-outer-wheel-15" - next_samp="LArEM-outer-wheel-21" eta0="2.0" deta="0.00625" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="4" /> - <range field="eta" minvalue="0" maxvalue="63" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-15" - next_samp="LArEM-outer-wheel-21" eta0="2.4" deta="0.025" phi0="0.0" dphi="64" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="5" /> - <range field="eta" minvalue="0" maxvalue="3" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-20" next_abs_eta="LArEM-outer-wheel-21" - prev_samp="LArEM-outer-wheel-10" eta0="1.375" deta="0.05" phi0="0.0" dphi="256" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="2" /> - <range field="region" value="0" /> - <range field="eta" value="0" /> - <reference subregion="LArEM-thin-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-21" next_abs_eta="LArEM-inner-wheel-10" - prev_samp="LArEM-outer-wheel-11 LArEM-outer-wheel-12 LArEM-outer-wheel-13 LArEM-outer-wheel-14 LArEM-outer-wheel-15" - next_samp="LArEM-outer-wheel-30" eta0="1.425" deta="0.025" phi0="0.0" dphi="256" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="2" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="42" /> - <reference subregion="LArEM-thin-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-30" next_abs_eta="LArEM-inner-wheel-20" - prev_samp="LArEM-outer-wheel-21" eta0="1.5" deta="0.05" phi0="0.0" dphi="256" > - <reference subregion="LArEM-outer-wheel" /> - <range field="sampling" value="3" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="19" /> - <reference subregion="LArEM-thin-module" /> - </region> - - - - - - - <!-- EM inner wheel --> - - <subregion name="LArEM-inner-wheel" > - <range field="part" value="LArEM" /> - <range field="barrel-endcap" values="negative-endcap-inner-wheel positive-endcap-inner-wheel" /> - </subregion> - - <region group="lar_em" name="LArEM-inner-wheel-10" - next_samp="LArEM-inner-wheel-20" eta0="2.5" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArEM-inner-wheel" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="6" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-inner-wheel-20" - prev_samp="LArEM-inner-wheel-10" eta0="2.5" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArEM-inner-wheel" /> - <range field="sampling" value="2" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="6" /> - <reference subregion="LArEM-large-module" /> - </region> - - - - - - <!-- - - LArHEC - - --> - - <subregion name="LArHEC" > - <range field="part" value="LArHEC" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_hec" name="LArHEC-00" next_abs_eta="LArHEC-01" - next_samp="LArHEC-10" eta0="1.5" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArHEC" /> - <range field="sampling" value="0" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="9" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-10" next_abs_eta="LArHEC-11" - next_samp="LArHEC-20" prev_samp="LArHEC-00" eta0="1.5" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArHEC" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="9" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-20" next_abs_eta="LArHEC-21" - next_samp="LArHEC-30" prev_samp="LArHEC-10" eta0="1.6" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArHEC" /> - <range field="sampling" values="2" /> - <range field="region" value="0" /> - <range field="eta" minvalue="1" maxvalue="9" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-30" next_abs_eta="LArHEC-31" - prev_samp="LArHEC-20" eta0="1.7" deta="0.1" phi0="0.0" dphi="64" > - <reference subregion="LArHEC" /> - <range field="sampling" values="3" /> - <range field="region" value="0" /> - <range field="eta" minvalue="2" maxvalue="9" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-01" - next_samp="LArHEC-11" eta0="2.5" deta="0.2" phi0="0.0" dphi="32" > - <reference subregion="LArHEC" /> - <range field="sampling" value="0" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="3" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - <region group="lar_hec" name="LArHEC-11" next_abs_eta="LArFCAL-1" - next_samp="LArHEC-21" prev_samp="LArHEC-01" eta0="2.5" deta="0.2" phi0="0.0" dphi="32" > - <reference subregion="LArHEC" /> - <range field="sampling" value="1" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="2" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - <region group="lar_hec" name="LArHEC-21" - next_samp="LArHEC-31" prev_samp="LArHEC-11" eta0="2.5" deta="0.2" phi0="0.0" dphi="32" > - <reference subregion="LArHEC" /> - <range field="sampling" value="2" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="2" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - <region group="lar_hec" name="LArHEC-31" - prev_samp="LArHEC-21" eta0="2.5" deta="0.2" phi0="0.0" dphi="32" > - <reference subregion="LArHEC" /> - <range field="sampling" value="3" /> - <range field="region" value="1" /> - <range field="eta" minvalue="0" maxvalue="3" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - - - - <!-- - - LArFCAL - - --> - - <subregion name="LArFCAL" > - <range field="part" value="LArFCAL" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_fcal" name="LArFCAL-1" - eta0="3.2" deta="0.025" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="1" /> - <range field="eta-fcal" minvalue="0" maxvalue="62" /> - <reference subregion="LArFCAL-module" /> - </region> - - <region group="lar_fcal" name="LArFCAL-2a" - eta0="3.2" deta="0.05" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="2" /> - <range field="eta-fcal" minvalue="0" maxvalue="29" /> - <range field="phi-fcal" values="0 7 8 15" /> - </region> - - <region group="lar_fcal" name="LArFCAL-2b" - eta0="3.2" deta="0.05" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="2" /> - <range field="eta-fcal" minvalue="0" maxvalue="30" /> - <range field="phi-fcal" values="3 4 11 12" /> - </region> - - <region group="lar_fcal" name="LArFCAL-2c" - eta0="3.2" deta="0.05" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="2" /> - <range field="eta-fcal" minvalue="0" maxvalue="31" /> - <range field="phi-fcal" values="1 2 5 6 9 10 13 14" /> - </region> - - <region group="lar_fcal" name="LArFCAL-3a" - eta0="3.2" deta="0.1" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="3" /> - <range field="eta-fcal" minvalue="0" maxvalue="14" /> - <range field="phi-fcal" values="2 10" /> - </region> - - <region group="lar_fcal" name="LArFCAL-3b" - eta0="3.2" deta="0.1" phi0="0.0" dphi="16" > - <reference subregion="LArFCAL" /> - <range field="module" value="3" /> - <range field="eta-fcal" minvalue="0" maxvalue="15" /> - <range field="phi-fcal" values="0 1 3 4 5 6 7 8 9 11 12 13 14 15" /> - </region> - - - - <!-- - - Disconnected Channels - - --> - - <subregion name="LArEM-barreldisc" > - <range field="part" value="LArEMdisc" /> - <range field="barrel-endcap" values="negative-barrel positive-barrel" /> - </subregion> - - <region group="lar_em" name="LArEM-barrel-00disconnected" > - <reference subregion="LArEM-barreldisc" /> - <range field="sampling" value="0" /> - <range field="region" value="0" /> - <range field="eta" minvalue="61" maxvalue="63" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-10disconnected" > - <reference subregion="LArEM-barreldisc" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" value="0" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-barrel-30disconnected" > - <reference subregion="LArEM-barreldisc" /> - <range field="sampling" value="3" /> - <range field="region" value="0" /> - <range field="eta" value="27" /> - <reference subregion="LArEM-thin-module" /> - </region> - - - <subregion name="LArEM-outer-wheeldisc" > - <range field="part" value="LArEMdisc" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_em" name="LArEM-outer-wheel-00disconnected" > - <reference subregion="LArEM-outer-wheeldisc" /> - <range field="sampling" value="0" /> - <range field="region" value="0" /> - <range field="eta" minvalue="12" maxvalue="19" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-11disconnected" > - <reference subregion="LArEM-outer-wheeldisc" /> - <range field="sampling" value="1" /> - <range field="region" value="1" /> - <range field="eta" minvalue="3" maxvalue="6" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-13disconnected" > - <reference subregion="LArEM-outer-wheeldisc" /> - <range field="sampling" value="1" /> - <range field="region" value="3" /> - <range field="eta" minvalue="48" maxvalue="63" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-outer-wheel-15disconnected" > - <reference subregion="LArEM-outer-wheeldisc" /> - <range field="sampling" value="1" /> - <range field="region" value="5" /> - <range field="eta" minvalue="4" maxvalue="7" /> - <reference subregion="LArEM-large-module" /> - </region> - - - <subregion name="LArEM-inner-wheeldisc" > - <range field="part" value="LArEMdisc" /> - <range field="barrel-endcap" values="negative-endcap-inner-wheel positive-endcap-inner-wheel" /> - </subregion> - - <region group="lar_em" name="LArEM-inner-wheel-10disconnected" > - <reference subregion="LArEM-inner-wheeldisc" /> - <range field="sampling" value="1" /> - <range field="region" value="0" /> - <range field="eta" value="7" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_em" name="LArEM-inner-wheel-20disconnected" > - <reference subregion="LArEM-inner-wheeldisc" /> - <range field="sampling" value="2" /> - <range field="region" value="0" /> - <range field="eta" value="7" /> - <reference subregion="LArEM-large-module" /> - </region> - - - - <subregion name="LArHECdisc" > - <range field="part" value="LArHECdisc" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_hec" name="LArHEC-20disconnected" > - <reference subregion="LArHECdisc" /> - <range field="sampling" values="2" /> - <range field="region" value="0" /> - <range field="eta" value="0" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-30disconnected" > - <reference subregion="LArHECdisc" /> - <range field="sampling" values="3" /> - <range field="region" value="0" /> - <range field="eta" minvalue="0" maxvalue="1" /> - <reference subregion="LArEM-large-module" /> - </region> - - <region group="lar_hec" name="LArHEC-11disconnected" > - <reference subregion="LArHECdisc" /> - <range field="sampling" value="1" /> - <range field="region" value="1" /> - <range field="eta" value="3" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - <region group="lar_hec" name="LArHEC-21disconnected" > - <reference subregion="LArHECdisc" /> - <range field="sampling" value="2" /> - <range field="region" value="1" /> - <range field="eta" value="3" /> - <reference subregion="LArEM-extralarge-module" /> - </region> - - - <subregion name="LArFCALdisc" > - <range field="part" value="LArFCALdisc" /> - <range field="barrel-endcap" values="negative-endcap-outer-wheel positive-endcap-outer-wheel" /> - </subregion> - - <region group="lar_fcal" name="LArFCAL-1disconnected" > - <reference subregion="LArFCALdisc" /> - <range field="module" value="1" /> - <range field="eta-fcal" value="63" /> - <reference subregion="LArFCAL-module" /> - </region> - - <region group="lar_fcal" name="LArFCAL-2adisconnected" > - <reference subregion="LArFCALdisc" /> - <range field="module" value="2" /> - <range field="eta-fcal" minvalue="30" maxvalue="31" /> - <range field="phi-fcal" values="0 7 8 15" /> - </region> - - <region group="lar_fcal" name="LArFCAL-2bdisconnected" - eta0="3.2" deta="0.05" phi0="0.0" dphi="0.4" > - <reference subregion="LArFCALdisc" /> - <range field="module" value="2" /> - <range field="eta-fcal" value="31" /> - <range field="phi-fcal" values="3 4 11 12" /> - </region> - - <region group="lar_fcal" name="LArFCAL-3adisconnected" > - <reference subregion="LArFCALdisc" /> - <range field="module" value="3" /> - <range field="eta-fcal" value="15" /> - <range field="phi-fcal" values="2 10" /> - </region> - - - <!-- LAr Online --> - - - <!-- LArOnline -Barrel --> - - <subregion name="LArOnline-Barrel"> - <range field="part" value="LArOnline" /> - <range field="barrel-ec" values="barrel" /> - </subregion> - - <region group="LArOnline" name="laronline-barrel"> - <reference subregion="LArOnline-Barrel" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" minvalue="0" maxvalue="31" /> - <range field="slot" minvalue="1" maxvalue="14" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-EndCap Standard --> - - <subregion name="LArOnline-Endcap"> - <range field="part" value="LArOnline" /> - <range field="barrel-ec" values="endcap" /> - </subregion> - - <region group="LArOnline" name="laronline-endcap-standard"> - <reference subregion="LArOnline-Endcap" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="0 1 4 5 7 8 11 12 13 14 17 18 19 20 23 24" /> - <range field="slot" minvalue="1" maxvalue="13" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-Endcap-Special --> - - <region group="LArOnline" name="laronline-endcap-special" > - <reference subregion="LArOnline-Endcap" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="2 9 15 21" /> - <range field="slot" minvalue="1" maxvalue="15" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-HEC--> - - <region group="LArOnline" name="laronline-hec"> - <reference subregion="LArOnline-Endcap" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="3 10 16 22" /> - <range field="slot" values="1 2 5 6 7 8 9 10" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-FCAL--> - - <region group="LArOnline" name="laronlinefcal" > - <reference subregion="LArOnline-Endcap" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" value="6" /> - <range field="slot" minvalue="1" maxvalue="14" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline -Barrel Calib --> - - <subregion name="LArOnline-Barrel-Calib"> - <range field="part" value="LArOnlineCalib" /> - <range field="barrel-ec" values="barrel" /> - </subregion> - - <region group="LArOnline" name="laronline-barrel-calib"> - <reference subregion="LArOnline-Barrel-Calib" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" minvalue="0" maxvalue="31" /> - <range field="slot" value="15" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-EndCap Standard Calib --> - - <subregion name="LArOnline-Endcap-Calib"> - <range field="part" value="LArOnlineCalib" /> - <range field="barrel-ec" values="endcap" /> - </subregion> - - <region group="LArOnline" name="laronline-endcap-standard"> - <reference subregion="LArOnline-Endcap-Calib" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="0 1 4 5 7 8 11 12 13 14 17 18 19 20 23 24" /> - <range field="slot" value="15" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-HEC CALIB --> - - <region group="LArOnline" name="laronline-hec-calib"> - <reference subregion="LArOnline-Endcap-Calib" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="3 10 16 22" /> - <range field="slot" values="3 4 12" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - <!-- LArOnline-FCAL CALIB --> - - <region group="LArOnline" name="laronline-fcal-calib"> - <reference subregion="LArOnline-Endcap-Calib" /> - <range field="pos_neg" values="negative-side positive-side" /> - <range field="feedthrough" values="6" /> - <range field="slot" value="16" /> - <range field="channel_in_slot" minvalue="0" maxvalue="127" /> - </region> - - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictLArElectrode.xml b/graphics/AtlantisJava/geometry/IdDictLArElectrode.xml deleted file mode 100755 index 948ccf3d099..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictLArElectrode.xml +++ /dev/null @@ -1,327 +0,0 @@ -<IdDictionary name="LArElectrode" version="fullAtlas" > - - <field name="detector" > - <label name="EMB" value="0" /> - <label name="EMBPS" value="1" /> - <label name="EMEC" value="2" /> - <label name="EMECPS" value="3" /> - <label name="HEC" value="4" /> - <label name="FCAL" value="5" /> - <label name="EMBPUR" value="6" /> - <label name="ECPUR" value="7" /> - </field> - - <field name="configuration" > - <label name="Atlas" value="1" /> - <label name="TestBeam" value="2" /> - </field> - - <field name="zside"> - <label name="A" value="0" /> - <label name="C" value="1" /> - </field> - - <field name="module"> - </field> - - <field name="hvphi" > - </field> - - <field name="hveta" > - </field> - - <field name="hvgap" > - </field> - - <field name="electrode"> - </field> - - - <!-- LAr Electrodes--> - - <subregion name="AtlasLArElectrode"> - <range field="configuration" value="Atlas" /> - </subregion> - - <!--EMB-FT=-1 --> - <region group="LArElec" name="EM-BARREL-ALL"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMB" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="15" /> - <range field="hvphi" values="1" /> - <range field="hveta" minvalue="1" maxvalue="7" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="0" maxvalue="31" /> - </region> - - <!--EMB-FT=0 --> - <region group="LArElec" name="EM-BARREL-FT0"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMB" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="15" /> - <range field="hvphi" values="0" /> - <range field="hveta" minvalue="1" maxvalue="7" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="32" maxvalue="63" /> - </region> - - <!--EMBPS --> - <region group="LArElec" name="EM-BARREL-PS"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMBPS" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" values="0 1" /> - <range field="hveta" minvalue="1" maxvalue="4" /> - <range field="hvgap" values="0 1" /> - <!--note that this value 'electrode' is DUMMY until confirmation by Hostachy--> - <range field="electrode" value="0" /> - </region> - - <!--EMEC-INNER-WHEEL--> - <region group="LArElec" name="EM-ENDCAP-INNER-S1"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="1" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="0" maxvalue="3" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S2"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="2" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="4" maxvalue="7" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S3"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="3" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="8" maxvalue="11" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S4"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="4" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="12" maxvalue="15" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S5"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="5" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="16" maxvalue="19" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S6"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="6" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="20" maxvalue="23" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S7"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="7" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="24" maxvalue="27" /> - </region> - <region group="LArElec" name="EM-ENDCAP-INNER-S8"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="8" /> - <range field="hveta" minvalue="7" maxvalue="8" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="28" maxvalue="31" /> - </region> - - <!--EMEC-OUTER-WHEEL--> - <region group="LArElec" name="EM-ENDCAP-OUTER-S1"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="1" /> - <range field="hveta" minvalue="0" maxvalue="6" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="0" maxvalue="23" /> - </region> - <region group="LArElec" name="EM-ENDCAP-OUTER-S2"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="2" /> - <range field="hveta" minvalue="0" maxvalue="6" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="24" maxvalue="47" /> - </region> - <region group="LArElec" name="EM-ENDCAP-OUTER-S3"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="3" /> - <range field="hveta" minvalue="0" maxvalue="6" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="48" maxvalue="71" /> - </region> - <region group="LArElec" name="EM-ENDCAP-OUTER-S4"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="4" /> - <range field="hveta" minvalue="0" maxvalue="6" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" minvalue="72" maxvalue="95" /> - </region> - - <!--EMEC-PS--> - <region group="LArElec" name="EM-ENDCAP-PS"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMECPS" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="0" /> - <range field="hvgap" values="0 1" /> - <range field="electrode" value="0" /> - </region> - - <!--HEC--> - <region group="LArElec" name="HEC-ETA1"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="HEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="1" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" minvalue="1" maxvalue="8" /> - </region> - - <region group="LArElec" name="HEC-ETA2"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="HEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="2" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" minvalue="9" maxvalue="24" /> - </region> - - <region group="LArElec" name="HEC-ETA3"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="HEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="3" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" minvalue="25" maxvalue="32" /> - </region> - - <region group="LArElec" name="HEC-ETA4"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="HEC" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="31" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="4" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" minvalue="33" maxvalue="40" /> - </region> - - <!--FCAL--> - - <!--FCAL1--> - <region group="LArElec" name="FCAL-S1"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="FCAL" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="15" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="1" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" value="0" /> - </region> - - <region group="LArElec" name="FCAL-S2"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="FCAL" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="7" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="2" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" value="0" /> - </region> - - <region group="LArElec" name="FCAL-S3"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="FCAL" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="0" maxvalue="3" /> - <range field="hvphi" value="0" /> - <range field="hveta" value="3" /> - <range field="hvgap" minvalue="0" maxvalue="3" /> - <range field="electrode" value="0" /> - </region> - - - <!--EMBPUR--> - <region group="LArElec" name="EMB-PUR"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="EMBPUR" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="1" maxvalue="5" /> - <range field="hvphi" value="0" /> - <range field="hveta" minvalue="0" /> - <range field="hvgap" minvalue="0" maxvalue="1" /> - <range field="electrode" value="0" /> - </region> - - <!--ECPUR--> - <region group="LArElec" name="EC-PUR"> - <reference subregion="AtlasLArElectrode" /> - <range field="detector" value="ECPUR" /> - <range field="zside" values="0 1" /> - <range field="module" minvalue="1" maxvalue="10" /> - <range field="hvphi" value="0" /> - <range field="hveta" minvalue="0" /> - <range field="hvgap" minvalue="0" maxvalue="1" /> - <range field="electrode" value="0" /> - </region> - - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictLArHighVoltage.xml b/graphics/AtlantisJava/geometry/IdDictLArHighVoltage.xml deleted file mode 100755 index b0a26c9558e..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictLArHighVoltage.xml +++ /dev/null @@ -1,222 +0,0 @@ - -<IdDictionary name="LArHighVoltage" version="fullAtlas" > - - <field name="configuration" > - <label name="Atlas" value="1" /> - <label name="TestBeam" value="2" /> - </field> - - <field name="cannode"> - </field> - - <field name="hvline"> - </field> - - <field name="partition" > - </field> - - <field name="canline"> - </field> - - - <!-- HighVoltage Lines--> - - <subregion name="AtlasHighVoltage"> - <range field="configuration" value="Atlas" /> - </subregion> - - - <!-- LArHV HEC --> - - <region group="LArHV" name="LArHV-HEC-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="48" maxvalue="79" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - <region group="LArHV" name="LArHV-HEC-C"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="148" maxvalue="179" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - <!-- LArHV FCAL --> - - <region group="LArHV" name="LArHV-FCAL-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="80" maxvalue="93" /> - <range field="hvline" minvalue="0" maxvalue="7" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - <region group="LArHV" name="LArHV-FCAL-C"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="180" maxvalue="193" /> - <range field="hvline" minvalue="0" maxvalue="7" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - <!-- LArHV EMB --> - - <!-- EMB-A-SIDE--> - <region group="LArHV" name="LArHV-EMB-A-STD"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="200" maxvalue="231" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMB-C-STD"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="232" maxvalue="263" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMB-A-SPE"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="296 297 306 307" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMB-C-SPE"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="299 304 305 308 309" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - - <!-- LArHV EMBPS --> - - <region group="LArHV" name="LArHV-EMBPS-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="264" maxvalue="279" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - <region group="LArHV" name="LArHV-EMBPS-C"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="280" maxvalue="295" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - <!-- LArHV EMEC --> - - <region group="LArHV" name="LArHV-EMEC-A1"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="0" maxvalue="47" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMEC-A2"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="320" maxvalue="322" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMEC-C1"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="100" maxvalue="147" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="LArHV-EMEC-C2"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="324 325" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - <!-- LArHV EMECPS --> - - <region group="LArHV" name="LArHV-EMECPS-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="312" maxvalue="315" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - <region group="LArHV" name="LArHV-EMECPS-C"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="316" maxvalue="319" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - <!-- LArHV EMPUR --> - - <region group="LArHV" name="LArEMBPUR-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="300" maxvalue="303" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - <!-- All these lines are free to use --> - - <region group="LArHV" name="NOCONN-NEW"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="310 311" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="NOCONN-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="323" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="NOCONN-C"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" values="326 327" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="FREE-A"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="94" maxvalue="99" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - <region group="LArHV" name="FREE-B"> - <reference subregion="AtlasHighVoltage" /> - <range field="cannode" minvalue="194" maxvalue="199" /> - <range field="hvline" minvalue="0" maxvalue="15" /> - <range field="partition" value="1" /> - <range field="canline" value="1" /> - </region> - - - -</IdDictionary> - diff --git a/graphics/AtlantisJava/geometry/IdDictTileCalorimeter.xml b/graphics/AtlantisJava/geometry/IdDictTileCalorimeter.xml deleted file mode 100755 index 76ab90dd0d5..00000000000 --- a/graphics/AtlantisJava/geometry/IdDictTileCalorimeter.xml +++ /dev/null @@ -1,398 +0,0 @@ -<IdDictionary name="TileCalorimeter" version="fullAtlasAndTestBeam" > - - <field name="section" > - <label name="Online" value="0" /> - <label name="Barrel" value="1" /> - <label name="Extended-barrel" value="2" /> - <label name="ITC-gap-scintillator" value="3" /> - <label name="Testbeam" value="4" /> - </field> - - <field name="side" > - <label name="positive" value="+1" /> - <label name="negative" value="-1" /> - </field> - - <subregion name="cylinder-pos" > - <range field="side" value="positive" /> - <range field="module" minvalue="0" maxvalue="63" /> - </subregion> - - <subregion name="cylinder-neg" > - <range field="side" value="negative" /> - <range field="module" minvalue="0" maxvalue="63" /> - </subregion> - - <subregion name="cylinder" > - <range field="side" /> - <range field="module" minvalue="0" maxvalue="63" /> - </subregion> - - <subregion name="pmt1" > - <range field="pmt" value="0" /> - <range field="adc" minvalue="0" maxvalue="1" /> - </subregion> - - <subregion name="pmt2" > - <range field="pmt" minvalue="0" maxvalue="1" /> - <range field="adc" minvalue="0" maxvalue="1" /> - </subregion> - - <subregion name="tower0AB" > - <range field="tower" value="0" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower0" > - <range field="tower" value="0" /> - <range field="sampling" minvalue="0" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower1" > - <range field="tower" value="1" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower2" > - <range field="tower" value="2" /> - <range field="sampling" minvalue="0" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower3" > - <range field="tower" value="3" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower4" > - <range field="tower" value="4" /> - <range field="sampling" minvalue="0" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower5" > - <range field="tower" value="5" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower6" > - <range field="tower" value="6" /> - <range field="sampling" minvalue="0" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower7" > - <range field="tower" value="7" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower8" > - <range field="tower" value="8" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower9" > - <range field="tower" value="9" /> - <range field="sampling" value="0" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower10" > - <range field="tower" value="10" /> - <range field="sampling" minvalue="1" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower11" > - <range field="tower" value="11" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower12" > - <range field="tower" value="12" /> - <range field="sampling" minvalue="0" maxvalue="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower13" > - <range field="tower" value="13" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower14" > - <range field="tower" value="14" /> - <range field="sampling" minvalue="0" maxvalue="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="tower15" > - <range field="tower" value="15" /> - <range field="sampling" value="0" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="D4" > - <range field="tower" value="8" /> - <range field="sampling" value="2" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="C10" > - <range field="tower" value="9" /> - <range field="sampling" value="1" /> - <reference subregion="pmt2" /> - </subregion> - - <subregion name="E1" > - <range field="tower" value="10" /> - <range field="sampling" value="3" /> - <reference subregion="pmt1" /> - </subregion> - - <subregion name="E2" > - <range field="tower" value="11" /> - <range field="sampling" value="3" /> - <reference subregion="pmt1" /> - </subregion> - - <subregion name="E3" > - <range field="tower" value="13" /> - <range field="sampling" value="3" /> - <reference subregion="pmt1" /> - </subregion> - - <subregion name="E4" > - <range field="tower" value="15" /> - <range field="sampling" value="3" /> - <reference subregion="pmt1" /> - </subregion> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower0AB" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower0" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower1" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower1" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower2" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower2" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower3" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower3" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower4" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower4" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower5" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower5" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower6" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower6" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower7" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower7" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower8" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower8" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-neg" /> - <reference subregion="tower9" /> - </region> - - <region> - <range field="section" value="Barrel" /> - <reference subregion="cylinder-pos" /> - <reference subregion="tower9" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower10" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower11" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower12" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower13" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower14" /> - </region> - - <region> - <range field="section" value="Extended-barrel" /> - <reference subregion="cylinder" /> - <reference subregion="tower15" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="D4" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="C10" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="E1" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="E2" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="E3" /> - </region> - - <region> - <range field="section" value="ITC-gap-scintillator" /> - <reference subregion="cylinder" /> - <reference subregion="E4" /> - </region> - - - <region> - <range field="section" value="Online" /> - <range field="ros" minvalue="1" maxvalue="4" /> - <range field="drawer" minvalue="0" maxvalue="63" /> - <range field="channel" minvalue="0" maxvalue="47" /> - <range field="gain" minvalue="0" maxvalue="1" /> - </region> - - <region> - <range field="section" value="Online" /> - <range field="ros" value="0" /> - <range field="drawer" values="0 1 2 3 4 5 6 7 8 9 10 11 16 17 18 19 20 21 22 255" /> - <range field="channel" minvalue="0" maxvalue="15" /> - <range field="gain" minvalue="0" maxvalue="0" /> - </region> - - <region> - <range field="section" value="Testbeam" /> - <range field="type" minvalue="-1" maxvalue="10" /> - <range field="tbmodule" minvalue="0" maxvalue="255" /> - <range field="tbchannel" minvalue="0" maxvalue="63" /> - <range field="tbdummy1" minvalue="0" maxvalue="15" /> - <range field="tbdummy2" minvalue="0" maxvalue="3" /> - <range field="tbdummy3" minvalue="0" maxvalue="3" /> - </region> - -</IdDictionary> diff --git a/graphics/AtlantisJava/img/atlantis_icon.gif b/graphics/AtlantisJava/img/atlantis_icon.gif deleted file mode 100755 index ea1ad1a27796918182df08347719cf5efdfb8723..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2939 zcmV->3xxDXNk%w1VKM+R0O$Vz00ICB3<wVq4hRoR78n%|6iN^iRS^_W8x&0z6<-<~ zTOJ-(B_v}WBZwp?XeJ|rF)}bLEM+Gsj3q0IF)(v6FNZZXdNDJTIx~+mHJ?2^YC%Fk zIX!ViLPa?{lR7?uKRtOvL1suwM?XV~K|-BGMuPtU07OHVNJf1|MTkK`tw>0B{{RO| zN^k!H6iG#>OH7GUR8dh-Yf4I|N=}wmR9I0@fl*SAPg0v#S8Q2ZSXNndQc|W{TxC{Q zj{h4JUtnJU9UWO(o>y1DVPa}sU7KWLbY*8`U0$$YVwzlEy<}se|12zQYJF^Nc4%g< zWofQ(a&P}OHga=(b8~`iZ>V&3bZl+I|2#c#aJ_GHxOH>0dVGfeM@4sdvVD23e}RAh zOig=!#fF54hKG@Xg1i4!Rfma&e}K?~g2axDkpEv_i;2ICi@K4MkpE+5i<YC9mYe@; zYmkxD0RI!1nwJd!0Fsu<|8jDmo0^`Sp_-hro}itVnA@3|*8g~TrK70-e}1W?qnW9; zp`p<v|1qGT-lU<}r>Ul@s=KbNusi-X|BH#JuF0yY;HjzSuCcE_{YR{;-2Ri0rMAqm zuhFr#xVN;qv$M*az{sDy&{6$Vva;i`vgu>*djFf5xVpDm{9LoM@s!NLpv28^?0sSP zYqq!HufEcp%gA=?hNZ>Tl+(R=>5;j(>Sg_A|D>eAz0Ql@tcT>E{ivqC!^XnF$HBwE zy}t0jzv|4y!+HOC|FN>g%FV^c;mOO#fBt~W$<O(?uE@vh$Hw=@$ny5TyZyYp%gX%F z($ACrjL**V&(Q7B(CC@{m(I}o;Ly?W%(<ueo!i*l)z|f|`lZ?1+1J+l*xKg#(8>DG z(c0Sbz4o%V`m@aMyV>3P-r?Ws-QC*i#^C47!ur48<NxI2`{(89<>%z<=+fxr_x|7B z>Fek1>+k67{Qc(T^6TpC@9gdF`2Xwf?ehQf^zrla{{Hdt_VoDr^z-)k_5b<!`uzF* z`~Ug>|Nj5{A^sIZa%Ew3Wn>_CX>@2HRA^-&M@dak04x9i001%oG5`Pw{s8|897wR> zKy<hK?K3E_mo<hEBSx%usR@S+V!l*aB1A}$DqqTE_#i_OJBcV6qKnfa$tiVY$mD@^ zsU{>#fYfloR?N!^G7nRtj7Nq;nQi^{?Ni6hU%!D$|84uWk6%A`Y*tVKClq48W*9K} z^GDAWk_H)w;d0eU6fRuLlt>_P$lSkv*gRC~%FtdF8R6Xd!Eiy$FdGF96fj^QF@gxg z`jEho#vHsUFzoUj=uXI#c84mQaHOtZKUa@%AuEPVttdzM`r$J>Ax*tFAgFErrw+y# zeg6DpvG<hV)2I8Aj{WEFAHFtM`sqWYVHjU?HptZb$1DW{-30mm;nP=7AMm7inbY%r z%Cw~r)>FE(p=O`IVip+WDlV`d5fL2#7+?%R{gd1_DJalMQi^Z@UPShIhR;9CFhIdF z1?_W72ap7lOftdPQUfCT3^bNHG#ubab9#WFnL+Wyvc(i7F5^H2y7?226M7&51Q4Jo zb<aHa?DNYMHPiu04c6GF4i75!!;c;}_)?%i{lsyC4CnYmjRh1?;}kqP06_#8x@hys z8dxwPg%oBmVhl8K95ICm$q3{Q4hp!UPdrq3U_?RjgkYs3X{6x5GN!RpgB9_>qs<#Z zuwa6vmzrS04`v(#k3Mm9kY_*Yq!7UzX@t{E3Be51k0Sn6_#;mRVnmROLg&OVMn3yY z5`?C}1`DhUc-*58ARFZQ&zEIPu+2Y&aKVp2`pCdcKaO}{Pcuoy14I<{+=B<E!j^k! z80&z#K{yJ16Auzv$hyKgclF{!Y$x>blv7~T08c)Dkb5Z;X5bOX8dA6*Y#8_8V?_=8 zB==7-50ul77kUW91tI<rGl4n;DWXF=pODLf6tsvV4KTYn<Bc$3{1B`h`9$GHKh51W zgCE?<pbtD6H1kguSL7_vC04BSE3kNo^9mhMN4<$RlgO;;54^;222}qTqOCkB`~uDe zRM7JPCld~Ige`aki-$Lh*bzx7t+b*_Bv4mVGXAh#gwsLVV>KheGJs@o$v=HKVa^ON zJR%S}zr+yE(k3vG&LVWY!pa~q4U$SJP?KW@uq+%C1tJgi^UMk_48zA0CEhW{KGz(e z?><owAqX#+vM`A$cD$lV69fPNfB-d60(vCbkQ<0KHT=B~G6+1P&m~DD#YP<eTr<EU zPQ@U|K5c6nL^^aV!ip2dw+}!Eq-<gbIamOTg^>{G)6X>qIBu^%82iUF3LpvtiNF&4 z2m{}`K?hS%qIm8z-X2;(2W9*LSV6c)J0Q@Ge|*CLj`)WzQZSY+WULqnC}2NCV2gd! zPg84f1|3wfhxQ4;eN>Qz9YXO5O|ifQ{_ofzJN99Y1oYt_$r!;?v`~kCAY%Xp+(!p= z@sAgp;0?~OgDNWFz8e~E3bLRB4>9<TcyQ2zMigNR7Ggrx6`&IW5rHlexWEQBB7*Ik zARTrQ2n^0+gYDQyISgP35yD_BY-r*$swa>d0Ae3<z~DIO5Q$V60goM6#nZ^q1^ewI z84%bG|3YXl`><hlwd+H3j!*+o(4u#=2t@-aVFWL}uMw&!#3Hg`H51?=96;!RKK4<J z0l?7`NidKfrr-`FfS{26u*NNFunvW33Jc;W1RY9|ibhbO346#yD+*zUZpeXL#{dH$ zet|P&Xg~?R5X2Mw0S*#0K^+bL;DkKv^ACR1;1_Qo-5<!I%}A(X7PDxDEa~73TJ%y1 z;SfRE`eBb@JfIkS$bc=*0fJ`u;|W<P&Ql;U1zrN{2Z8X0EVZf4^l<|g*1Qxi05OL2 z7^o8$u*W%4a0`A=K@$DI#RTZF5QV_Q3GrY=?^w`<V|YUuuXqJ8xDgFG^wI=t*oPI8 zVYGeBU=ICYMho=84_)|xq9iD!f!Gm+WF%z`<odx6q=1J>eBuvbpxiar!4GSwfr<io zMg_j{kL}r~9xb4XAxMCa(%=IKR>+4x-mwN@SxsPk(?)XY&;fMtMju&tLO<xS0<I)Q z4_=T}1?B((>%apDU?~34Jpyr6b8Tu3>*yyUI$(`{m?H&kcmOm0Aqgt*2WZUz#~iW% zrf>A49YA7EK8|6A+L8`s@VLt~MDP%K;D7;W&_X+=VS`=}#2;i3R6Fpoj0jl395|Vf zKEO~1T^J(}U0^~Gg1`hU;DHy=5X2Pd^$$zvK^{*ifFqtuh7lNHA$L&<I~q|0F6a*z z3OE5KIsl5NoTCnp`b9qOv5s}jBOlfPg9yN&ENg545LXz0A4~&?5}e`}=QYq(V4wzp zV0Z)@=EH>cp$|)lpcc~r2RN*ej2h&jgUPW)2NLlF8IR=>9M}dwjCPmi*vA|t(8IJ& z;Q$L%0u1bEj{a;!uz?P=c>`@$)<5Qp2^t_kU;O|@b+`<XW~@LDrYQym!o(lv!~-4Y zKr}n*QD}RlU;&4)k1j$`3DcmYIoses9Gc^YCCEb|t}<GovGkni?BhMB;B!Qr0%q;p z;Q>g%g*}{73}P(f8`Sv5H<qE63GFWn6M%v}0KtJ`s5&L;D1s5%VU99jfCPS^h7Aso z00ktV+6Fj41e)Op9!%f~)WF9WN-*5r6sH+8u!U93vDgQwfD?{zL?8NKh(~l{2ot!# z9Ijy+aPXiK65EYHz_9}uaKau7>BlloVW6lO=pW4>20fT#k6Z{L1id(RSDq3KBcOl{ z;RXaCPZZIMlItQEy|@G*;=pV|+&~7PNSnY7q7T2e;07;%LK1x7gAt^l1U^VY6<#0& l4RE0s6Vf<eMCz1!+(HivQ3}qUViiR|q8<DhHA4ad06XbHXI}sS diff --git a/graphics/AtlantisJava/img/atlantis_log.gif b/graphics/AtlantisJava/img/atlantis_log.gif deleted file mode 100755 index 7afe0dde1b99cc58b127f5ffb0c12f622a5f6326..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18919 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 J?sGr@06SDv1aSZW diff --git a/graphics/AtlantisJava/img/atlas.jpg b/graphics/AtlantisJava/img/atlas.jpg deleted file mode 100755 index fc381ca49e94fa5a0cfa5a3c64aa925e9239c761..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32018 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é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 Br{4eo diff --git a/graphics/AtlantisJava/img/atlas_logo_big.png b/graphics/AtlantisJava/img/atlas_logo_big.png deleted file mode 100644 index b41fa2deb8cbd1f2cf2163c921f70966e684c3ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7956 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 diff --git a/graphics/AtlantisJava/img/cursor_DnD_invalid_32x32.gif b/graphics/AtlantisJava/img/cursor_DnD_invalid_32x32.gif deleted file mode 100755 index 64c265d3e9f3f1d8e9486b0c6562beb6249452e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmV;K0A~M3Nk%w1VITk?0FnOy|NsA)nVA3p0KmY&A^8LW00093EC2ui03ZM$0007N zoIjw8?QfKrRKbe?-4$P5EgRrDpkN)+M3xcPW}OS3vC7injOSkc^7U>IU=Srk{)7ph z5%WB@qD7w6rc)+SOsMtP^|Ed&t*aSQ1it4JCwxx0$MMf1RnP19{J#GW7$`VMSZH_{ HSO5S!I%Gk4 diff --git a/graphics/AtlantisJava/img/cursor_DnD_invalid_64x64.gif b/graphics/AtlantisJava/img/cursor_DnD_invalid_64x64.gif deleted file mode 100755 index f0da1d0b3a4529cc22d74c22e7e9c64b174ab157..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmV;-05ktbNk%w1VL$*t0HFW?|NsA)nVA3p0RR90A^8LW00093EC2ui06+jh0007= zoIjw8?GK}TO4zHW-u!?IV%<o3;PQ#(I;BG9xd2N$t~EDu%_q2uNacDf*)9kqj)aDz z>7^_&o5^XkWA)*l!|Nuig=)LrRx(`KmN{Uwdi_0z-*AmF=&Z*vi-25j7IFe8b%R4j zh=qcf*y#8O87VnQS!sERnW?$S+3EQS8Y((UT55WVnyR|W+UoiW8!J0YTWfoZo2v_1 G0028RE?e0E diff --git a/graphics/AtlantisJava/img/cursor_DnD_valid_32x32.gif b/graphics/AtlantisJava/img/cursor_DnD_valid_32x32.gif deleted file mode 100755 index a2d986bab98db68aec96f8a155c2bc7079ad7486..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmZ?wbhEHblxI+2nE0RJ|Ns9C3=9Vj8~~DvKUo+V7?>DzfNTbkJOfjTPs_^Fx{Q6Z zMcle(?%kPxFZ6(g*TT<J)xEYoo3-Q#_i1C9?Mo9MoL}?lsgjr!pOPk*plw=!N3fpw zrIm}gdNVqsl9zeAWcBabB)(a<KRZiYFPCk??eoGBI%<#KU)%SeUxFi;fx#L8@_08! diff --git a/graphics/AtlantisJava/img/cursor_DnD_valid_64x64.gif b/graphics/AtlantisJava/img/cursor_DnD_valid_64x64.gif deleted file mode 100755 index 167754d0f3c04bc1c9e24829957dd640c15b7a2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmZ?wbhEHbbYO5`SjfQe|NnmmFbQNR{$ycfU|?d<0g3=+9f0iFAxbMxzvW-d&2X~2 zcuDB*`a)TcX>1LB&$>ES96i?m`;?jU_3v|ESKs;k*Jo#Q;SQm~gcDD)Z?g0)2vq8c zQZ@8nwPy2cRj$KQi+}D>J+GD1CB0@Ii}p(kz1HK`-*!32?LU6}>vW+L&)q%LcYM3X zu|1=qjm<MMv$AvM%AF@~zWm84rDf$6l~vU>Yt^n(w_g3?lGe8Nj?S*`o*lrzU=09% C&t1m= diff --git a/graphics/AtlantisJava/img/cursor_fisheye_32x32.gif b/graphics/AtlantisJava/img/cursor_fisheye_32x32.gif deleted file mode 100644 index 274cae270ef0f05f0ffe6e2c4bb40f2ab81d9121..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1191 zcmV;Y1X%k=Nk%w1VITk?0OtSz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@<y}iD^zQ4b}z`(%4!NJ19!o$PE#KgqK#l^<P#>dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1<F+1c9K z+S}XP+}zyV-QC{a-rwKf;Nall;o;)q;^X7v<mBY#<>lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IP59EC2ui03ZM$000R70R0IZNU)&6gZ}>gLzqyZLxl_lD#X!Y zVL^pSaD-_S1%-|z5D)%)BEyJ9g8zQ}fRv2eG;Pk1xiT{3<iLMIWVw1_GvNtN<=ip* z)k_wvRLH3P(P8snm{0n4^!x{d*}HVprgh6Ss8T0T)xweDVeuamQ2%_vXv(5iK7GV~ zk#kpwN0CB=IN5^-Y=%N1;1v2<dlLqkdi(U<;$`a75f?13>`^q%-nmI+l63k9Z4cR- zAY|0z*Y6%BPDmOwSfJnpktoLS(d%a8#pceRZ_+4JuirjKn(9PQfIvZzBVWATtCmFu z&cOc$H|2oop1oa|Abn9$;>eUFtL}wGTa#j;S+r`WazIq?-K<1~=CJuPWeq!VL`>d% z8ntJ_5j_NR&M<z&0ml`Hd~?hXE=-lvPX7I40}dygBFr?y%yP;IGd$v7LL}*DkV8EP zv4agBbWj98A4>EOMJ+b;P>d+i7}1S5=BVS2Jof10k3a?~<d8%bY2=YeCaL6-Oad7Y F06RyhM6Lh; diff --git a/graphics/AtlantisJava/img/cursor_fisheye_64x64.gif b/graphics/AtlantisJava/img/cursor_fisheye_64x64.gif deleted file mode 100644 index bd9f9e8f6fe33b42f1bad61e8ae8f64970c5a51f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1259 zcmV<H1Qh#6Nk%w1VL$*t0OtSz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@<y}iD^zQ4b}z`(%4!NJ19!o$PE#KgqK#l^<P#>dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1<F+1c9K z+S}XP+}zyV-QC{a-rwKf;Nall;o;)q;^X7v<mBY#<>lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IP59EC2ui06+jh000R70R0IZNU)&6gZ}>gL&&h9!+{DTMs%nU zM~8(EGd@(91V@-QQBdeeq7dP~Co+s+)X4JSzaKv!CF3?tn=@ptj0{-`QHU&8FL<^b z`tJm%a_*S@>Lm+SDrD6D=-~M;%qM+2gbro-4+gV$>84HVmT6F>PN1rVBgF&bKPI65 z`GTQ!>qZu}^64Y?i=4YcJc<+|#K|5!U^5g70jJOpUAry2lBu^(-z{FIJ{@tv;>sRH z<LsTAL?%h6f6(@{h0GO%jC%a~-J`?_NrMIp6r3Ou#TY(%-E6!#oq9EEjsIwrsn>5G zBTaQ8C_tbf$dNDJ?p4bo<KN=OkB`Y`{Ko;)J$t(_LHeSi#E~gUR^5xXCdI<Hap%?* z?~((edhg7VNFj5u@x>Htup<r;DnVowR{Qa1&_5&e5X?El_z?#jS0M7uF+aE<ly^S` zCE<8B;Bdkz!b~&FET@bx!y|Q_lv0Ez5)@GnLhN9J2OSi_PlOd+lp}Hym9!C#M>gr? zlTbz}<&;!bY2}qzW~t?tTz2W@mtck|=9pxbY37+|rm5zdY_{p<n{dV{=bUubY3H4I V=BekNeD>+*pMVA`sGR`;06VT9WwQVP diff --git a/graphics/AtlantisJava/img/cursor_fisheye_bw_32x32.gif b/graphics/AtlantisJava/img/cursor_fisheye_bw_32x32.gif deleted file mode 100644 index 31b8d566e033c12980fea7c35d4814ffc71832f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmZ?wbhEHbRA5kGSjfl#1pi?`@h1x-7XuT64oDOv&%jhMrGKTi;GH=o7c3a!cI`;s z#WJ_8<NlF}?G-D}W**9!dDcYg@XXS8*}b0`vK?-7s|)(2>{ISq;qxkF&C-G?YqsTG z(*BZotH|==d4C`6q{GsSUT^i=`|zyLO=hl*k|$1Oy%X24@QBE$=$Nr$$B7#+esD-? NT6#uiMlvv10|3B^Nkaet diff --git a/graphics/AtlantisJava/img/cursor_fisheye_bw_64x64.gif b/graphics/AtlantisJava/img/cursor_fisheye_bw_64x64.gif deleted file mode 100644 index 817fee3d0bc475f0c82ed063cc40d8d994ff2b00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220 zcmZ?wbhEHbbYO5`Sjfl#1pi?`@h1x-7XuT64oDOv&%m^HO8-i2L7v4n>%v|#RBS%K zrghd~7RBdFyDg&>ymHmnT+307k~TX3HUGuSBFS@S*+V#El_Jk~`jk!cdBp8L*=fc3 zXBT!}_FK3nZ8ZmPw_#>+_LYkC>#MhY7t_9Uyljq@#^>$fNu{Ce<{gYh+gqpqcxbfT z;ZsCrW#`P5J5Szx`IA#h%gQS%tEy|(s$HjUz52x^t!?ccon75Md-d+qw_pF}meH~C QiOH$ynX_h37z2Yf05A??I{*Lx diff --git a/graphics/AtlantisJava/img/cursor_move_32x32.gif b/graphics/AtlantisJava/img/cursor_move_32x32.gif deleted file mode 100644 index fb4d30e49177e62158f4e654cc3d6ac44ca82995..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmZ?wbhEHbRA5kGXyIo7f(9^d08<S>UIPdmIB?)UQ2al`e=r54fh;nB;!hSv1_nL` z9iU-A8x<HBSThzV_dRi*m$AyOVdXvp?kxqir;Ky2SFC%#x_yIc31hxn*rke)zBx)7 z0n`2jF5mempgVb8&4Uf+XTQqoJgRf;)W5e&3chdIWwYp9RCT1!HS4OPI{&Pu_}W(g Wj;`*W-oE|`6DLicGPO&Q!5RP%)qnc{ diff --git a/graphics/AtlantisJava/img/cursor_move_64x64.gif b/graphics/AtlantisJava/img/cursor_move_64x64.gif deleted file mode 100644 index 1312c63e98e5b27e17c32c04111bbc8880568a17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmZ?wbhEHbbYO5`XyIo7f(9^d08<S>UIPdmIB?)UQ2al`e=r54fh;nB;!hSv1_nL` z9iU-A8yy%JSZ6O#?t9`qFJslZ9BsRXm*+}q4>{z#ujzWeYu<%#%xvu**OEDtPffaT zX|rXN+u|$N4XZ^TExUbZvp0*?Y(L|jIXSzpX5V@*<K6u@$KXfD^!Bf{Hepf0$&D^P zrOoZOt_3~4xos1yi>G+TOn06<Ywo=H3l=U~ykzOJ<ttXMTD@lNy7e12ZrZ$M>$dGX bcJA7}XYaoK2M!)OeB|h{<0n=tGFSruJQJW= diff --git a/graphics/AtlantisJava/img/cursor_pick_32x32.gif b/graphics/AtlantisJava/img/cursor_pick_32x32.gif deleted file mode 100644 index 381e8e27aeeebf84f1b6d6b308471777ca4917c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142 zcmZ?wbhEHbRA5kGSjfl#1pi?`@h1x-7XuT64oDOv&%hKvMZWO#+tm$KQ`jog?{awa zaYc$1Jq{0BKFuoo(6(coS7zv_&8u6O`hOBfvKBvE+n1Sr?kf7GO}yo6GtxYo%$DEO m`h4rF)%+bd&2(PhY)EA>y54vC`IlXP`_8}qUK7K}U=08S{XCBV diff --git a/graphics/AtlantisJava/img/cursor_pick_64x64.gif b/graphics/AtlantisJava/img/cursor_pick_64x64.gif deleted file mode 100644 index 933ee9025e4ffa057890de5c5681cb3faa9e6ef8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmZ?wbhEHbbYO5`SjYeZ|Ns97(+r9~Ss1w(m>6_GT#!5i)8r}gg{R;0D~C9o?EcI> zHJZ0AI=u6lW`*3TtgM^IF8)6G%}M>M?EVAyA8svK;_`I6@U982=M7g*`B4(0Y-06t z#i}r!jO^NVd%Rz5_Rtfa`?w^nI&Zh(gReF$b@%o=sO9{3n_9#gkx|hxW5tdWH(vbU skkqvFjLfX;oVjx6$(t{Ka!P4gc|~Pab<J9}>(s4Rzqob>FfdpH02n${2><{9 diff --git a/graphics/AtlantisJava/img/cursor_rectsel_32x32.gif b/graphics/AtlantisJava/img/cursor_rectsel_32x32.gif deleted file mode 100644 index 735e03ad7ed142cfc3c718381ecc73112c91a385..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmZ?wbhEHbRA5kGSjYeZ|Ns97(+rCLM4gLL6H8K46v{J8G895GQWe}ieFGR2f3h%g zF)%UcfYgCBGB9OK=@&cscIUh~2~pwe?FwJNi;UEmB%WcFajGZhah@XsLvd~R5AK^^ zX8rnGAu~V!nDDh}9+!M77vFRWdU4+DuSEa(^lv3k%G!-ST6mfE@4r<%J+^GI?;%rz XcdG2ucihd^x!_{r5m6Dqz+epkb<adM diff --git a/graphics/AtlantisJava/img/cursor_rectsel_64x64.gif b/graphics/AtlantisJava/img/cursor_rectsel_64x64.gif deleted file mode 100644 index 6af540579930f5b3fe343ccb10159401343bf607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 207 zcmZ?wbhEHbbYO5`SjYeZ|Ns97(+r9~Ss1w(m>6_GT#!5i(}F4eVkh77Cr59(^_t;c z%qzaOE{~#+&Z?JOwQsuT80ef|lYM`uB!k0+->j_rZt-1V{@1r8Ws+tQS7X5B3++q8 zR2^0tW!yQ|b^U$5W}3(HyLwi(W!s<U|2Sy5y#3*iKiAhCn-<Pqp?<?HVnxA^B^C$E zwk?;K68hwYf%<~dlQ&=f<do8~@`}o;>YBA`*Qr~tesM`_TYE=mS9i}|z5Dd-(*X<& F)&O_rTOR-b diff --git a/graphics/AtlantisJava/img/cursor_rotate_32x32.gif b/graphics/AtlantisJava/img/cursor_rotate_32x32.gif deleted file mode 100644 index 61b6efdc627f8271344f4822dfbc560f0bdea2b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1126 zcmV-s1eyCsNk%w1VITk?0OtSz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@<y}iD^zQ4b}z`(%4!NJ19!o$PE#KgqK#l^<P#>dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1<F+1c9K z+S}XP+}zyV-QC{a-rwKf;Nall;o;)q;^X7v<mBY#<>lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IO;3EC2ui03ZM$000R70PzVNND$vYaLSq$T*$B?!74Wf8FR?+ zU%!6;GX5jjC{U6rOOipONDv)>lP5P4+$O4(7c){OlEl{!8UvIn7v2I!hfA@U0<jcG zNf8{EYd|R(SP%g~PKMsZC^<$loCXG-bU7uNtw)Y^6frTVgU_G2rwz}+$mWpO2@Ab| z5>!G%Awym?1j!{hY)7(&%UsmjJFplLqzt2tSVmajFdp9;R`UU@F}_na)HQ@wB$j19 zF4{F@cf>_G!j3-d(C6@)ke?*~`Rj*IiiEfh$yL$um*PJF+%91t;f^FVEv;e`sPRF; zt(obPbQ$K%;lBhE21t=x?n)Ris2W86BQPKVfp2IV(nHpS39Cd4{{@(TGTz>2OQJM6 sWQf&3jq}Wt5n;CMp~N0!Sw@j3dXRF8f)GY1;e-@cXyJtzHWUy5JDGV9h5!Hn diff --git a/graphics/AtlantisJava/img/cursor_rotate_64x64.gif b/graphics/AtlantisJava/img/cursor_rotate_64x64.gif deleted file mode 100644 index a376b6b532e11f4472aab2b577d2da106b4c0601..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1190 zcmV;X1X=q>Nk%w1VL$*t0OtSz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@<y}iD^zQ4b}z`(%4!NJ19!o$PE#KgqK#l^<P#>dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1<F+1c9K z+S}XP+}zyV-QC{a-rwKf;Nall;o;)q;^X7v<mBY#<>lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IO;3EC2ui06+jh000R70PzVNND$vYaLSq$T*$DY!-o(TR=F|A zSj3AM9scXr@1Mti1RDiPQe{apXc<#xL<gW{OOOP&iE8D=j1-G1b2{t?je$#;3vU6V z!=;$cqYSYWc=-?<mupC)3Z!IUK?DFm8F~|=<e1c>;WRMtqzfy=Y&~+U`<fFIgF5*9 znakSn9E@yiQ}Q}tp_fV}G!*8&$cu)coWph`8+>t@i&{C05rN7WVzd#<5cBv}8Dcdb zz;d3lp|0~oXhmY><l~~9X@~5NxG0y>(T5%SUOT)d#3;mn{`%pQBEhfjhUBW~Sp4uG z0B)BskZ^b0AvG<neiNwiLBXx+4%37s=`zfj#sm`vNCE$_+?6n3P&NEVU_b%_-{`U* zNDo;PCaff~&_4kb*it<EIrPjDQ8aOgA*>Aa(LD2bl%PYl?4iUSa9wzmCwh=_iiaeY zXyS<|rl{hIEVk(4i!jD0<BT-cXyc7I=BVS2Jof10k3a?~<d8%bY2=YeCaL6-C<X)o EJ0^8NZ2$lO diff --git a/graphics/AtlantisJava/img/cursor_rotate_bw_32x32.gif b/graphics/AtlantisJava/img/cursor_rotate_bw_32x32.gif deleted file mode 100644 index 6833e4bb8a3619f0bb523896726efb0ed8713672..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmZ?wbhEHbRA5kGc+3C>j0_A+49pCy><kR-oU9z&?6UGQ|NsAoNTQL7KUo;L82A}< zK;j@X7+7Y1IH@^tZ^x^%>P+qeG7VQtBf2_M%Yx(;_}8UNI{&=2X+g1Ad~W-PzX44T zIUOg+HZn97eb$VacYrCZnIlDSw|n_3#)`wU4s6?`w#`1JT&C~YzT5g%CiC{sf1Q+7 zlbo2);>{3N#1T~^8kA==A<whfw$FgUNn@6gS}O-L+k68{zZo-?v{pAH$tx;XtX;Eq T>$dGXcJA7}XYW2)K?Z98b8t+t diff --git a/graphics/AtlantisJava/img/cursor_rotate_bw_64x64.gif b/graphics/AtlantisJava/img/cursor_rotate_bw_64x64.gif deleted file mode 100644 index 5ba49f2c75c5ea37270b345b1bdb4505dea40816..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 300 zcmZ?wbhEHbbYO5`c+3C>j0_A+49pCy><kR-oU9z&?6UGQ|NsAoNTQL7KUo;L82A}< zK;j@X7+7w8IH@^tZ^x^%yZ_5F$v74;h^<(s^(;ws*2WTDrXL3W(+wAFO?a)wP^5Eo zZoy7RkzU2dNuI6(1s9YX43@IFvU-1ukf_e=aCmkpXnw0wxo$#Tz02LOyK=Yg|E-a# zC}?Q3X^pCEYwGarZ7l3kESc18Q&g^*Idz&SL!v?jN9vrp{9$v<qn9pI3Yz4yX4!HE z&su-Y%?ml0*>;NTiRj;4n5D13OD9Q1?eIzW6X!2ozH;^2^&2;D-M(}8-u(v;A3c8Z j^x5+lFJHZW^Y-2Q4<A2${_^$P_a8rh{r;mZ$Y2cs!q9rk diff --git a/graphics/AtlantisJava/img/cursor_sync_32x32.gif b/graphics/AtlantisJava/img/cursor_sync_32x32.gif deleted file mode 100644 index c383ec1293a38aa62b98f1fb5095a73eceb8b700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 916 zcmb`GziX6n48~J%xQe3Sbx@?7KPpxfhb%3nLkBBPRd8_Vpbi0xgVoLHY`v|Miv&BJ zh=YTmxXOVbRwE(~PR_01;8+KVpM3uY1IK&0Bu}2_$$J+sEzZo|=t)nu4+zn3pMHDv z$@&$e(J1*nCEJ51-w1yDf1x5K;v!L-$W%p5)I~!yt7s}_VlEb9S-q~}Chp=Po;4aO zVG=G862(+fB~8*L1KI^#&|oo4ch;T?Q+3r)&00%lrsis)mc@dio4TuqdKM{q!!%qY zG!l-CYMQ2Nh9+BK4H%?h2`y?Y1{-Lw7|s$@IpJnumZguiWbWo+o+TF+6vHjTB2f=1 zdM({DERlyF&}14r&<_a|!WuA0!;)5buo!Hh!OC*3%H%}2XBmk;){;edB)%dS78E_h z6CZIJ1K>qFMxz!h@dKJnV+WiNj6zrg25Bat1rHX34RqFts+%%7kz5QT(Z^b{XfIj$ z+U{M&cEYl`U8Q=P(dBycu11?3b%ds{kQ(W_N#jw#4Vu@1D`6g*Sas~rp0RrQ&emI9 z{|V`=N{%0$`TbyFt#jzi)m<5_4-TH#dwcit@WR9H`IXI`J5S$lOrBfYcX;*W*5K6q zk>#ydy-$y)#y)IL-|KyTGI8bY^3S{53y-FkZvHymo%%W)UqAl$dH2@0;nHAnes*H# X%d=~*SAKka^Wyu<>+kOG@5tOgZNZLs diff --git a/graphics/AtlantisJava/img/cursor_sync_64x64.gif b/graphics/AtlantisJava/img/cursor_sync_64x64.gif deleted file mode 100644 index 1853af35b54f06708257342985a282853ba158e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 973 zcmb_by=#+k5I)hNQn5%7v4|*A4N+WfiLFSCT0atX5CuUBMZKxu7f2DLuLZ$Dqe2l6 zQBhnf*pCdR;Lu1=i@i}@Y!R)XbSgMGozMOL1`ooU%iTTqJkPy3c(}K?tG`4g`qe>* zEPb-{$dF|b&1Tc_yOXB}p7@5qZ~rftNQjikViPiEVj)&yBlai?lL(2D7>P%(GO3U% zsgZh&8j}f`k{MYrC1-LWS8@aG01jwiVHn*Wdm@BcnT^?FEiw@nWib{H7AUH)Dyy-2 zkV3Bso3a_3gCj=Sg<aW=9b3T~U?2^apoJP10~^r5!mx*+$Pp@HA|Cp%7MZH3iF(Kd z3lvSoOw6Gkq|hs_;wBDx@B=h44LhJ8B%lzi0S3}wiB|ByVqgOrSRT$r89BmKJ&c4t ztVL#~=I|AA!2(5fQ-_am8U}zD+F>-*!b<o7nwW+i-~_=?2-W}tX-t9^cwjNG0qt?3 z=tdbi!f`Pe34K_L%+gC1zNULeF`Y1MPFIQEWOTTmyo=FfM;sw345UOlZjyKeaDv9` zfGfc~Xu_(^e^)Gvmv2YB)$yO8wwL59Hx!p{>>X~)70%2|JZlYg(C)!Qlg|&_T(hlj zZsvaf``V^`<&k{-=exUGPjv4et)DMH*m<`0DW7}s_EE9@$K2^FUD?yp(CSr3M&$VI zo(qfBYfHa-A0Dfe?{r=+e6F1u-_tdE^4yoPwbR4b^H&F2by-(9I{W(7*T%(#kB=*j svH3THe-`Iw8{^-mv*qm@t5Xx-TeouC`)q1*;lsTxl_%BpmrB(055haHy8r+H diff --git a/graphics/AtlantisJava/img/cursor_zoom_32x32.gif b/graphics/AtlantisJava/img/cursor_zoom_32x32.gif deleted file mode 100644 index 6880193d449f3c7f2e895ed742024d78d2bc460c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335 zcmZ?wbhEHbRA5kGXc1sgS64SSHnz97_xJaYjg8I9%Brug@9OHBHf`FHB}+DM-hAlL zp^FzU-n)12&6_v>{{8z;B2fIv!pOxSz@Wnb1Ry&ZSkEY^^!aD@Wvp8DRA7%oz&aCe zo@1XZ&ImH}&-!4fVBpoA+{qxaPL8!{@s((ek_*d(T|;L1^iFaRxZ|{-ZGF{ui;V3q zN2}geSa;s|dEHLs$ye1H)4~R|($oUh%vOGmre@~2Dkh^eC4LsxR<?d;*TigAhRkU( z%og0iJRD369L7skTo{uLC-%<T7*ou^z-P6qnT>~sjiuwDCO_w5mlG#d^f-A^F6eCG s<k)#FhLM?b=J{*<j4W(Sx9?16WS#Qp@xAwVHoW@!?fZ|P(-ax30hG$1m;e9( diff --git a/graphics/AtlantisJava/img/cursor_zoom_64x64.gif b/graphics/AtlantisJava/img/cursor_zoom_64x64.gif deleted file mode 100644 index 72d75f2a100a07b6a5173a1461dde5d071718b17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 394 zcmZ?wbhEHbbYO5`Xc1sgS64SSHnz97_xJaYjg8I9%Brug@9OHBHf`FHB}+DM-hAlL zp^FzU-n)12&6_v>{{8z;B2fIv!pOxSz@Wnb1Ry&ZSpO-g^!aD@Wvp74^Lo)!fin&P z`zqE=K9Zor&;D3|!KUnlN~S}?6tQzc2Uo0lB*)sc*d#`yA!1eOnkt?}YQc+D1Y}MY ztWoskx8qCtabwMj>#~(qp=k+qnT<`J{4A|)svVuyHGOIg`4hWXi>L5&OqgMrmeIy! zw!o{Kbqd@3<>5ZrrK}9a>zbMExTASEm>4+Bx2;HH%r#A)yXsJL9RmZO!|5u1HXa@} zmg$$m_&K+v-MYQPh?6JpQT0(yj#Dq18JRg*-oEQ%WMO0a@^um;>(YlmTARcJ5>_;^ z32Vii*s$<$yMVIS9FL8Qj&@5JXWcomaq;nf1?Mgq&rM5CPS)TEUKMk4)6(Mt4AuZ9 ChPv4R diff --git a/graphics/AtlantisJava/img/cursor_zoom_bw_32x32.gif b/graphics/AtlantisJava/img/cursor_zoom_bw_32x32.gif deleted file mode 100644 index 9e2afd655574cbbe2991ba2b52ca0e71a7ddff91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161 zcmZ?wbhEHbRA5kGSjYeZ|Ns97(+r9~Ss1w(m>6_GT#!5iQ_&RpmB-)CYnbyg(j#=j z!(Y4^QqOH~&v1=BIVZ_$Q<JvVLap=VvF(;;rPoFrQ1A;g`87diajwT5&FLppxK2&k zCuYg);oVuPJejB6YTZk}7wa^8O3nAF|7^XtP5HsE@0RzzPrbg}*u#RkV#SUVH(vb6 J2xnlh1^`V8K-~ZU diff --git a/graphics/AtlantisJava/img/cursor_zoom_bw_64x64.gif b/graphics/AtlantisJava/img/cursor_zoom_bw_64x64.gif deleted file mode 100644 index 2efd87e0d4d1a5f4cb08e46a16fe2bd9199564a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212 zcmZ?wbhEHbbYO5`SjYeZ|Ns97(+r9~Ss1w(m>6_GT#!5i)6yyOE04eBU!1~uWA?Ip zGKr!Qj_%Xs7@8KH%v$&>G}+raUuyl=y5(G2w?8)6$$Le-77aC4@!rW}HUG$pk|?gw z#qMi3qpnnX8s(MG5!LN{k-tVsXuIWyZmWB9F4s1RzgpwI`0I3WkJj`VEsQf}wB4xi z;E+6N;i;bP88+kO&6htprL?TPqOz*GX06(F>ej1YT+-Us-qG3B-LqHkK7IT3Z*Cc# JKLHF3)&K`XRH^^~ diff --git a/graphics/AtlantisJava/img/downarrow.png b/graphics/AtlantisJava/img/downarrow.png deleted file mode 100644 index 17b7273d22a682f1fe269ed260d78559fe342144..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^oFFy_8<4DKZ~;+_#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*x382FBWFymBhK53vJdx@v7EBj4O9zks(HNN^6Kp}Ha7sn8Z%gKNK z|F>sWJaEK;<v_@h6F=sAsa^CG+|@ksM~}wCmNg&#*So#Bc2H%4h`?Jlw^gp(3>$U` V3)nnaa~5a>gQu&X%Q~loCIGGWIavSz diff --git a/graphics/AtlantisJava/img/interaction_clock.png b/graphics/AtlantisJava/img/interaction_clock.png deleted file mode 100644 index 0078909d9bd3ec15a13d2c8fe542faa1618e61d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1033 zcmV+k1or!hP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5(zIU_!C_K00W6hL_t(I%T1C|NE>$m#=rkRcNcSNa?2ST4NVtk77X3Aahi-6jq^b$ zgFySBTU~|}L6}TO9D5q9dly=Y4>N<#!XB2!M%V`Kp&L!Ngke)!R;xJDX~D@@NbWE( z%iSfn2fMQG^@AVZ4?cqbB@hVw(%;|Da~zif@cHQITWD!*37+Zf48DK)@|q+`Nt?~4 zO;1n90HmYQC<p*dO}&Smo$WXF_V#{FCX=+Osi~UF<(2?^8jr`lPN#EGRn-gg^Ya## zWgFFM^#=gwlh>bt0f3Qk7>^(SHnhCFOg$bC6h%?8*=#hQ&wpexnV3SM@aOpWc%`?u z*TS+aWm&cZ0Fu|g2J^w(9Cn`l1DDHngHk%5PN!`f8yl8jFxcwo=+p(l0>9tye7(2N zuzGW~HZd`A|LExG_J7)p#cal-zX-lhr7Cv2z1?~GwCT89)}>;Rp6lyHn<%2)X2XNr z{l;r&&$0&x2XD^I%!~touVWS@7K`DD)`yps%+KB3-ND`MZH$eLVI&knO;K=Mt>RRB zI|!xF0X=c+76Bo@19&yFrh#U&S%@tJk|g=%l2jiFg%BPd1~nL9G#Wt&0ihI>QfR75 z&N!XN-X3qax5o<rFqBFX*yDYN!{JzT*zI_GY>ZS74p80SM^RN#*L7H}RuD?T8I7=7 zt>l|T!mzoy`7I~@eaMu{N6>ZM7Y>JE00?Wb06Y(dQhXPSfvPGxmzKcWY@n2)-e?%s z*VnPQxHt^p0RsR-Lqk7SDit_7I#gZPxx@W^boKP${FN&(o6RVcO3?CoxIG@ovaB>W zHyaCu!c71tM`|^jF&YjlQ<pB0z~CUm^E_CN1AXo;$ucZF4~-C9y>?9#1fdR~X<=aj z)aUcz;iDW(Ces&!@Dj7TyQ>-)2GDirx{i9i4$*1_SQcAbTUsKKVBBu^4Y%8k7Yo{K zZ3qPXU>WW(5{cOV$mf;0xjByKc}S83zPTA+t*&aRREn9LoIC{3IWRDQm6eqfKxjCG zd+B=^2@j*)b}BbGFz8#my#`HHb&DWCmSrLcf`0MB#fJcVT3v(7<$@@RCjbEGdZi0b z^H15$Oy<jXqS337NaPc@+dbOQ8mifB&fNLw&SxLa&VGE(@1F%wi^t=TW%&hw0N_MX z43*1eZ>?5K0$>2p=Y0c!Mk#$)5QHbiV(~5j1%Uc5q{3DVVE(Lr00000NkvXXu0mjf DX)M-h diff --git a/graphics/AtlantisJava/img/interaction_fisheye.png b/graphics/AtlantisJava/img/interaction_fisheye.png deleted file mode 100644 index 6ddbd1b556a528d332b6e98e3272b4ed832b56d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 694 zcmV;n0!jUeP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5(*j3Z`B6?00K5iL_t(I%axM7OIu+S#(%dYgJ=|?LlEN-k}4=QH=z!x1ZpTm(Lsj_ zLU7Db^A`v%>Rh^CAsrM<X`n-(ba83PP=^M(IQW4>f*+M@9irEmr$aO}!P5GJcR1&H z-{-uCa|~|j>+9oxIXpb%O&UIYeT)krkw~z)nZ5UNS63(J=f9eAv$L-VJPY#V=XTw| zaU711PySl5RdXDN&tJatGX4VB>xBjO_x6!$0F=vR%H=Wuk^tD={?=q*+vj}zbV4q_ zhpVfz6Tjb2Fc<*f^z?-B@$sey6B85n#y2-NxUR0Qn#AShWqG|`Y}@AO=!j@EYP7Zx z2>2C=L;ws|p-><kjsUQ>wx;#<b&ACz7Z(>)DisC?2Q@#R1TZq0cLak0WilDs+S=-F z9UUGP7SiPNc{z@wt*tGcot<fPbX2RWtFkOhwrwjCiAa(T4h|$qp-@PnP^fMa4u@5( zR#mA~WLcIx9*^4F+tuISuj%P&U0z;lcXwCA!^4uK#l=P4!Xtoa^toYK7Luq|tIW*I z(9_ey(9jTbb93zM>@YbwiQ_oN)YKF!D=V0$iD{bkJunPNrBX&L7E?BxrBo`>-QA7X z>!r81mt-=D+wC@r#Ug+akH@vNwAA=M>2w-NNTN_EFg7-(k&zMkd_MVnzJ}I%YPA~1 z-DphH1YlrbfQ^lf#>foAXe?AKlIktwayd$+67Hu7e!PFnLwNLOkctI(D8_xsyLSG? c_4PHs0UEs*fFkCv7ytkO07*qoM6N<$f;Kfbng9R* diff --git a/graphics/AtlantisJava/img/interaction_pick.png b/graphics/AtlantisJava/img/interaction_pick.png deleted file mode 100644 index 5bb9411ccf89581a77f9a6a4ddec694bb70562c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k><XYDdx@v7EBj4OMj>w1-_kP<0)<*UT^vI!PA?61 z<U63i!Mu5Kas9{W&-3@46t>Q>a%R|m;m8TbRa+Pon&)k1@jB{KuB((~$;>#1BVE(3 zNm*6iG5f6RhO1HGmML9wkI$`L%qQplZBa^Wf9QMl>c3|DmfYBXC|+v2$An@wzfbHd xdOxl?zJ^;qzgS%7<C<83=!>@w^B+!r7WXK}u15OnQIH=QJYD@<);T3K0RSc+TpR!Z diff --git a/graphics/AtlantisJava/img/interaction_rotate.png b/graphics/AtlantisJava/img/interaction_rotate.png deleted file mode 100644 index 511c2837239dc8849ab31e74e1a9a3178ad12a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 608 zcmV-m0-ybfP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5(_$Z6O}Xo00H1hL_t(I%Z-yiXcR#d#((#x^6(B6QAiWGXiyMOM36wN0*i@_g@q7s zMFr1BltT&Hsw5$%kUi1_>_QL`H3~tj6hwt^o(e%YD+Li$WHY-nJM50lZrE(@Ag}u7 z&3qs4z4=~_9&z*h!!w?zb^y-o!g#M|<g$soSC{%cq2@fHPOiEBW2Mv`U<HUCEMM*| zaBpHcr*(MI7i!uQs_Y4cCww9k8Q?cC3CsW{EtF3{6h(td2G^ww%1UaK)My<h*E@kJ z;2BW1t>$Kd#^i}r<?Dk=>KQ46P)Usr!dE~iRq-e=oo*ptuh-WPx93m$vkT)5<?A6S zgU`ZMZ-9NktrX`1a6GA^&~CR0!*Ii3THls_4D1@2m%je#{*%8Ry}S0hHZax?)Z)2C zz|&UeIYq5?*YA0<(g=VrsnmVoY>W@Dw_uE6i}5vu_ih^E7Gf}kSGx+>mQ%1Tr<Xw5 zMIRDSv@K^FPzFjs6<D*a=G(+Dw$;o76TrEcV}QjCPP8p&7&r>KKHvaQ0ow7KVPJn| zm{$@v7Gs_Fz^T|MRiFSI>(a){xSH<EWLwQkvFEpEh%Rsgn9D9yb{k8T((cNk>S(P} u+H=I1DF4U(-ul>i@kz+PE+7CeP52LK!o?=qzBp|F0000<MNUMnLSTaCunB$u diff --git a/graphics/AtlantisJava/img/interaction_rubberband.png b/graphics/AtlantisJava/img/interaction_rubberband.png deleted file mode 100644 index c101f8ccd9fb2b067b6debd4d7bff251884d6dc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcmV;s0!00ZP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5)2c2;G3TS00KKnL_t(I%axK{Xp&JF$N%Tu>t|-07OTbRV<HtbnD$}9EW?YzmN5y5 zMifa?h(Ux!27?F}L9AU#tzG1mP?^D6BvQ%-(>K_xB%)RWTlHdFq8BfP=(LOA&5t?g zxjN7J{h$9i=Q$5SS&ToOz>Og{v|25MLLrRCBQTqfA{>ceOG^t*+ib{Yv#=T8ZGJqx zeh`3z1OkB)%d!AKyk0Mo$t3)KKg41&SeE5kC=^0IpGWVW=Z%|o4@^G^&g=p}cmqLu z7ph~!&jc#i@^5TS4`U)U5B-5o03h_saG11PFO>Q_+pg6(pp9P@^1m8By*OdMGrrJ# z-PJesaLHl?0D7HV&Wjj^ImvOHy4I)!NoEYbXNx#@s{2Rdj!W;cG!FovbGaNZ<2X)j zGMQ@1zc5!Y@*oBG)ian~P&Jn`Di(`jwRjtGV|a8DgBPu6Qafrm<#akr`9yHV;@6WN zc*Y*VHP8*^&hr&46ZIn#^@FN+@`o88?v38XWyfJ`>~H}fE9z*A#X?4>K9|Zj<Fl{e z^^CyY*MaQ^Z-S79n!+ai@xM=~2E}3#sjnZQ(d>iz&}~ox$*Mh~H5v_{$YioPN54(I zt#vK->U$Ao-u#<`LIH#j$mR063WIn&&L=vZ&X-DkZ|&(h_AQ-G3uu}yNhFe@R4QGr zcZ2^M<*Hu*K=>Zy6G37(sEFO5A{u&;+&bGu%GsJELzw$RWWOj)>;@I7+Z3fz36V%t hms1o4g+jsSe*n`u)A`6UA=>}|002ovPDHLkV1mM>Fp>ZO diff --git a/graphics/AtlantisJava/img/interaction_rubberbandyx.png b/graphics/AtlantisJava/img/interaction_rubberbandyx.png deleted file mode 100644 index eefdf1e4425d59f0b758beef4d94654db23d5f22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcmV;s0!00ZP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5)3XQh}Vt)00KKnL_t(I%axK{Xp&JF$N%Tu>t|-07OTbRV<HtbnD$}9EW?YzmN5y5 zMifa?h(Ux!27?F}L9AU#tzG1mP?^D6BvQ%-(>K_xB%)RWTlHdFq8BfP=(LOA&5t?g zxjN7J{h$9i=Q$5SS&ToOz>Og{v|25MLLrRCBQTqfA{>ceOG^t*+ib{Yv#=T8ZGJqx zeh`3z1OkB)%d!AKyk0Mo$t3)KKg41&SeE5kC=^0IpGWVW=Z%|o4@^G^&g=p}cmqLu z7ph~!&jc#i@^5TS4`U)U5B-5o03h_saG11PFO>Q_+pg6(pp9P@^1m8By*OdMGrrJ# z-PJesaLHl?0D7HV&Wjj^ImvOHy4I)!NoEYbXNx#@s{2Rdj!W;cG!FovbGaNZ<2X)j zGMQ@1zc5!Y@*oBG)ian~P&Jn`Di(`jwRjtGV|a8DgBPu6Qafrm<#akr`9yHV;@6WN zc*Y*VHP8*^&hr&46ZIn#^@FN+@`o88?v38XWyfJ`>~H}fE9z*A#X?4>K9|Zj<Fl{e z^^CyY*MaQ^Z-S79n!+ai@xM=~2E}3#sjnZQ(d>iz&}~ox$*Mh~H5v_{$YioPN54(I zt#vK->U$Ao-u#<`LIH#j$mR063WIn&&L=vZ&X-DkZ|&(h_AQ-G3uu}yNhFe@R4QGr zcZ2^M<*Hu*K=>Zy6G37(sEFO5A{u&;+&bGu%GsJELzw$RWWOj)>;@I7+Z3fz36V%t hms1o4g+jsSe*n`u)A`6UA=>}|002ovPDHLkV1mlNFem^3 diff --git a/graphics/AtlantisJava/img/interaction_scale.png b/graphics/AtlantisJava/img/interaction_scale.png deleted file mode 100644 index 6a4699d2530b7a1ecc737e10e23055bd2be2e433..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k><XYDdx@v7EBj4OMj>7)X?3A0pebseE{-7<r;kqF z=yf<iqILgj&LtNDkEe0;mKAEap3n-)c>QF-(S6N7n4U?>{1Oqp;wi8&`i@M@W($)G z4#Erh^vv(YuxmyH&c1YTv)sAkmVf>*t+=smFE59fcfZ?Wfet;thp!Tu7hlaXWotey z&9&;btsTpvSL;q+JFVO{WztC%%~|eVoCj(@xD?m(AKv7(?3yJ*p^WhHkLlrS>sfr3 zukSVSy>}?!>GkdBoevkz+4MS$(c^MU+3vsT&3?;^`4&v6djHk0uV?+Tpvs4qUYbj$ zoMGH@Zsys@3cj_isZ-BbHe}8^^Gt+cjdfpeT(aw0J^`k`>v?<X_S^F`Jzx;n8nyOi z<-MCh3<{rW?WOvUw<PY^=@Y^6<&^Ng{RK<o*1!Mr=&a^xBi1{$3|#UB(OH|t-U9=X N!PC{xWt~$(699D`tXcp7 diff --git a/graphics/AtlantisJava/img/interaction_skew.png b/graphics/AtlantisJava/img/interaction_skew.png deleted file mode 100644 index db0c357a0f7014f917abe4dd102b4fdedcc0b886..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k><XYDdx@v7EBj4OMj>8(-znE3fkOSBE{-7<r;`&T zG7fMY{qJ$5nc=3TWg8C<&v6L}38#(=Jq!Cf`=?*;Z){vRABa0Rm<_HN*8ceLP=uNJ za26XIo3|3rfso_JjvebbUFlNUJW)_iZDD|?6T|vl|6Pu;#K;=YYOw|?b!TI1%Vyy@ zu(Gct|HX?J0Z(|Jg|Ck@40yrI^MKcMuEd_o1IEhC4CV)PZU_X2sREtG;OXk;vd$@? F2>_m;Tc`j4 diff --git a/graphics/AtlantisJava/img/interaction_synccursors.png b/graphics/AtlantisJava/img/interaction_synccursors.png deleted file mode 100644 index d19b2253e87ad4b95163fd50e26c924cd322f7c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 455 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k><XYDdx@v7EBj4OMj?KlyGM_%1e)UR>Eak-aeC?G z^IlAWBFE~>XKdS*Y0G`FK(yzASqF!kyn_5f*Izmpy*b2qw{R>fHSA_#j@8~#;J};n z^2FZdt(kpiRc^Agzx#R4wtipn&Mtk6K4&4e=0=OY#by@kUKM=b)X)2%Qts?C-=xMI zGw0=(dke3=vi!N2iT%B9&VjB)CwknHFKv+QUevMtx%oLi{|)-trkCG;6*OdMN%W9t zW9Z;uSbHsd&4H3%2md~n_`k4y?%9+RPm4sjDjC!!8$K<voEES$M5uPH>9-uSZq}`4 z_HKTYmv24B)uiCoHDd;2*5u!2i9c;7ZL;5br#Z+gXnV}+tAc_qEeafA&vVmy4kmHe zz2)g<^4e&;CTQi6`VFt%?$Tp8nl#aEvEXC{rB36n6OZ(N>^omzk@Eh+;_B+Z=A5t3 v9WAUY=X@P;iZNsR?MJ)v9_{^Eb54Dw@WBk3uP>Q_q0Hdv>gTe~DWM4ftv<bj diff --git a/graphics/AtlantisJava/img/interaction_zmr.png b/graphics/AtlantisJava/img/interaction_zmr.png deleted file mode 100644 index 06e95704d7442d5bdc2f7606e93ca4badc0bd7c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1010 zcmV<O0}cF%P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXY$ z5)Ubs!4d8N00VMKL_t(I%YBevOj~6D#m{$dOADo?YZ<M<F<TG<b1pDt)P;72IZS~y z5n@S-@kK)TqnMa<n&9FlXtLn422&rpMcAV=8b{4!8APW|J8)S*$0jZEf2Ad(Ev&b_ zExn&FZXufN_jYn}PEHQNF0PKcOSBqo1H&@UWHOmxXnp<1lP8-3UwkxHvK5JYqLFyP zR`d}sP$2}Me&l-heF6Y&ZEuOKt*wL8{%F^oK$J-cgo<ef75ikgsw~fW?-yK)MUv-Z z54rM0GPx$sVhbsyln`>903fc5mz)#R$#)Wp!fn%QhnO9yBrQs%;QjfokXZKbF(1yp z)Y;k5_2yB><*jJq8|||S6@Xy?9NXQ~QyER|ary=Aa!u2bm3{lwTv#Gm)2L-}Nr8H8 zDVRv6BAdqzmBsF_zdhr8PI+wUyU7o3A1XG#KnST2<tY@F=@5A&KJvVGNhFDi!K&h7 zLRLYsBFfs>Db>sVy1APFiZ;&z;LZ(y9}fV8kN^Od;d%ZOK`M_j%G^jsED8dEgim=W zr6et+*R%4n<C$zl1b}w;;gnJ{r8F(_dcDxUS}6@NBn<#jPMFMQ3Ehq-y@X+M*as0= zVQNPeo|Eg|KH+QtC<r0%Q%YY1aFdyt`2z<F1SPi^(xk;KfA?H(!(O#?L#C9)GC4VX zOvFGL=T)hg`~)Fz6GGeo>IfloBiFl4Y$}z)!E#-`p}6RcQP)?>E9Xwto#}a3$<~-x z!m|%b%<QJ+Xmu_Vm<ybZZF2XM>G<u)_L}3?y({)DE|e4jfWvX&bNeajW?6dqG{+@S zB$Lz{f{XhVl91ZxasSC{3QX^P-2CCf-}AP{#>T6=zhD6%S1#{Vsg<psUp>|1Hzv|A zAAV`{hmkLfe7}v)`h3170_23lVN;F4(9&wPZVV3(|Nf+*s;cVz{DPmZhl3Qr0msk< z3ZVC=v1{~UG)(JXuOHLtbi`(}o$l-F%lK|h3O=9jQ;WsIJnmrf_vZIDHZ{!ttE~V~ zT2|^RKTvUY_uP(-j;?`$f%N#q1f80iy4c>{o&^A?HP$i!U^-@;SzcYDZEdy{0BCM$ zCio9_yS-&-Xoz#W-PG&#e*eVK7wZWC>%!tZ)#>%0;VJa@_t&{xuE^lvV9)=|>gwvJ gh96@z8Z`j$4+}VgyZ<SIYXATM07*qoM6N<$g8K#F#Q*>R diff --git a/graphics/AtlantisJava/img/interaction_zr.png b/graphics/AtlantisJava/img/interaction_zr.png deleted file mode 100644 index c6f46cc29f0c9381097e522bebaef22c65ce5b1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k><XYDdx@v7EBj4OMj-*lJiYB*K%p#87sn8b)5!@E zpBe;bDj(hOz~1P;q%)JUT_GC~sFj>OFCiqsndu^ye(KB_m6Io5v~4&u*IN8=<PwHy z_xINuKj30d;z|AW|G#~kaA7NB7_&yN+mr}}V{SamB_$;uml|a5hIo1$23nQQZ7@4F S=%YB0$>8bg=d#Wzp$PyGeMznW diff --git a/graphics/AtlantisJava/img/left.gif b/graphics/AtlantisJava/img/left.gif deleted file mode 100755 index 279e6710d4961d7644ea2e3e39e6afd300147aa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmZ?wbhEHb6k!l!SjfQe|Ns9p|Nk?9f#N^Ekc`Y?g~Xx~1t67~r%;lSs!&jxl#`jP zkdmL9n3<=i;GJ3ql<+7`&qyuSQOE}IG8|GfOZ1ZSb9EGgQwvH`bCXhw6bvmbO&Jt_ zvM@3*Ff!<X%m>-Xz@**Nzw-3iM{+%$5nXSNI_AHs_0#Z5ammWC>ec*qNb!1QNo>>3 NI{94w6cGjnYXFzvI#mDw diff --git a/graphics/AtlantisJava/img/minerva_log.gif b/graphics/AtlantisJava/img/minerva_log.gif deleted file mode 100644 index b7ba3677b6b3ad098bbbbf5c7b639d41de2aac10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19469 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 diff --git a/graphics/AtlantisJava/img/mode_loop.png b/graphics/AtlantisJava/img/mode_loop.png deleted file mode 100644 index c4573849c5c3555e80b5f91df2659d592a11d9ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470 zcmV;{0V)28P)<h;3K|Lk000e1NJLTq000;O000mO1^@s63?#pm00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXV& z5DqFI>3sPB00CA>L_t(I%jMKDYgADX1>i5cWHm)%WN{&oI)#!-5DET;blTX8R+d7l z{DE|-V`Jfu5Fw2iL<oU&!6Gr}rb)L&^g-0-EDVp0Bm`_681B7im~-Bpx%2oR?KzgS ze~kV39^T;2q@*eIa4SBC>EP8?(BKdQyuk04e?q4wbuf?PBp%=>=eZ&>z_&uQgL`-y zU&nc3530Zb!}tRFS%)}@NC%tv5`qyv<_6W?CB9n0(~$L3CRzKzj|+Z31n)2C&)dYG z)bjL_I7)qG9R>e|o0oh5(`}#=vZjzLA`N~{X!fOTe1l#ogHonR_>~13>|(angW2F+ zoLxs`;V-Xfm?u2dYVuBtV->IQHSrJF7zeu{JuGuD-p{v&=57ei@htEC5tee>@r*Qh zSihi)nF#f98#me$8T&k8de^Xs?>WD`PDvNBjUPqeRVm@tKm9ZQ0egvCbyUn(761SM M07*qoM6N<$f`~84z5oCK diff --git a/graphics/AtlantisJava/img/mode_loop_on.png b/graphics/AtlantisJava/img/mode_loop_on.png deleted file mode 100644 index 1a6b5bed230293c52fa71d78d228a3a7fc2ac3e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmV<10VMv3P)<h;3K|Lk000e1NJLTq000;O000mO1^@s63?#pm00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXV& z5Dq6{SO7!-00CP`L_t(I%jMKPOI%S92H?kC){jDCSh65&ZDFtyLJ0W_cBV-iVr3}^ zf{2Ypy410;@JEC|nh*&A38V`aCSukmorSufrg<+ME*lXR(l{`jGw<A)IrDY7kMtVz zxi8^+_#1ZdXpqqeM)4p#g;wyAo}rH;bg+z@8h=5fG-_ZP$1(hYpOL4EARU|(j`r~w zFT)$Sitb4npo3m`2JM_ZoF+&EZ*dq0XZV~9N_rptVhR3<vv$fPXFK?DfiJ|thkx{E zFZvf{c}8P+hV^`~9(e)R7{B8HwCX@3O{;h__-27!4runBsmh?@t>9ZV+%N(9IKU*f z^V;pm2WaAam>@H^Oi?c*JW^}&e$B@scJM3uPk2))n{j$n>_K&(t}V@699-d5=KVQl zlWnyleLO8+(8NRnweb*R^^FXD9k9J?=;C+em0?QS#YbEe0al9=zWc9##=kQhUUfCu RORoR`002ovPDHLkV1m->!f^lq diff --git a/graphics/AtlantisJava/img/mode_random.png b/graphics/AtlantisJava/img/mode_random.png deleted file mode 100644 index d7861bd112a56079c81778995267ee6d15259878..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1032 zcmV+j1o!)iP)<h;3K|Lk000e1NJLTq000;O000mO1^@s63?#pm00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXV& z5Ed~Pmn}>H00W3gL_t(I%bk>8Nb6-7$3MSKH?{5TgvDT}sf7kP?QkT>JFkw2ghL`T z4hJ;I2z3{`aSkuMP;Zopqa}D_ricc?h8!nYL{Nv8n^=xhEB43jVxyc##WT14e!njI z?J&fk(*qB@&-?OzKhN_%ypO<h*wob2*O^S_^;j&Xcez||h@u$tcsx=#9KL95Y`ix* zI{N7P9o2sox7lprL?Y2*Fc=>Bd_G-1pD*)xJUAQ<mDOs!6_3ZiU0GS_{NI3RG+MW@ zvGH<EP0fe>{rw4m`uciICKGD4nvszaO)M7s^xpsipaBeu-vY{&eH5|dwzf8LXlUp{ zk|Y&CYilbzJ3IdfsZ^v=shXPrDn;~n-~jj$I0XIx^hJmyNoV)(-+ymyZEa+IecdFA zq6mmZp=>sb-|v6nCcsNT2q*(O6n|TZe^nr=LZR@Y)oT6HU@&~s)z$U%^z^j<=;$cD zx3`De?WVoGooF;F%+1Yxb{!B>)@I<Z5;p@f@C#6;)9EgZMk6MZ>9);gD{O6T&4$C_ zN}WzeRaF&UuNS-B&i3~9N5jLzm$EDiC|PP0v2!4&z;a4_7x)3F5CkE=xw-l9<m6;8 zl}aH=QoOgf_v3+qf$f8X1M2GP2nK_MLLoXjIw~Cw$77&b0R9A;m8`E@HSj&~*7*4N zesy*At1T@pc)ecP<#K5RK`0y_A8%%}*>`t$cj@fxM3!ZimX^?JwPI~;?E?WgD*@z6 z#5E;=H-RV9)6-uZ9v;5m)YP<JQBkp>)oM@s`uZL^ozBGa^0LZevCz=az~bT}Jv}`b zjm9U%3Ub$;NuxCPXP^MQR)kxv)`-*TY%rV6Qh9l~90&x|$z<|QE|*)my1Ft02!eoG zt!8y~HC?6%?<-<=O91;yC9OcdSe9O||7~Vw=5xQ_e<lb5fk1#*EcVs;`S~ldEE5Wa zh(scEcXxAnd08z0YT!2TQ%Qq0%KDD-gi>i^#>U1H3kwT10Ks6;l}@KWk!2ZxiHQlK z(I{4{6-ko5EB;iqB3h-y5^$+xF5NKnJQ|HAVX;^yL!nSQ9*+yn&CSow1wp{)^JVAf z=PQe&LIj?c{DBN`b(1*2<mBW#@p!y1lgaGa?RLR#x06gJpPhTXUb(5M$wKL@d0un7 z-S;Aq$cA38&-?v;(eL-C08tc01_uWp&(6+%0Pr`641u;s+#A*a0000<MNUMnLSTY6 CspO9U diff --git a/graphics/AtlantisJava/img/mode_random_on.png b/graphics/AtlantisJava/img/mode_random_on.png deleted file mode 100644 index 19c332640d439e2f44b055430f1326603626be51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1045 zcmV+w1nT>VP)<h;3K|Lk000e1NJLTq000;O000mO1^@s63?#pm00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXV& z5EmcPS`oqk00WgtL_t(I%bk?nOCwhp#($G&{Me+~qD3~<Zgg!F>Id!GKftRMkz$Zi z%OV9WR48gLa$^)rz3>C7D27_W8*3HOLLouc2zDvGSr|5g)F4f1W@3UEs9M+BsF|5w z>`5z&g?0}d-Z}5#JkN99_n9N{KgRIz@b|~Z$JMH;+Wdb1Tbib+fj~fyMx$pH6%`M9 zdwZX}c*gW!!M$E@G?7Tu*zNWwp-{+rb#;{!2m}}$95i`6o>$`W_zw#U3ym*LpeV{4 zD=RCnm6n!%+}_@v0B|~;I2;blW-~oKJr-3}zx+1>6JQ0(#C#nnye`1$bne&J*K1u} zU1z$kn*i$S>e$%Wcn)APad>!GdJ{p806hVI1%3e(;1sx%CDC>Lw4<ZrgQcaVp5^6b zho)&7pk;y5=`^w|-@1vwC4eR1U7$up35W}loJ=P3s>kE`)^4{yZfa`!^W@~DeRp>^ zwY9ay?CdNJ4Gk!YB27$8eDxy1PvW~;sE>+RE%GXmZ?#&_N=iy_I2^aVUT<b?ZEY+X zjTTs~RtgIX2?m4sd_LCK*FWj*?mjmRL%QCB`@jL<1q=}nMBV`Gk|bTNuC6{hIy%}? zRn?~Jdc3u@_2KmNG~?srD2l@N_BN47gyQ1jg2BPTJwzFFph_q=uH8-o-V`^i?C<Y? zTvSwaucoGkU@&O-{eFuiNtylq{nd0j{r=|WCXJ1a7>2>z+#Gp%d0JUn*+*G|cSKpd zz-Pecz!yLzAOjV^{>aG4H#<8!AG%zwr}_E$D|vZ&Cv9zQkEW)k67%!(Cb!#7d3iZA zGc&Zbv`|t~@_UxR5H&vl&V*&}0DEHZw#ei0cw$piQ{}a_wR&!Dt`QE0&B<i)?aRx{ zg^P=eS^!CsFq_RRE-t2Wg!-of>^|@Za7*L>?g8i7y4h^DpGQYWzm{eBRFWjZ;V`PI ze)sIzv%7|25Q#*H#bPu!H*<b|UL*k);4Tmm82Yv5R{}{ObKQD<eSL}P>FH8{?d@%U zDwX=wFrK$>U|;}6QSf*?=(_%+B+ghwS&GCu1N<hGXKr}(0v3xU;dZ-+B9TZc9*;{^ zRaO7ELy`!ELg~rL$%3rXOW;U2DGJ2IpPaerT^br1dM_T2w;dlJZ~1&a$>;NtOeX){ z4+evV%jI%st@u)7c6RnbEEZd_*=$#`ENikX9|D@DX>@jW?v0I&Jp}j*RH}o%%uq|M P00000NkvXXu0mjf7Ov<J diff --git a/graphics/AtlantisJava/img/mode_sequential.png b/graphics/AtlantisJava/img/mode_sequential.png deleted file mode 100644 index e4c2d857205282a26b8e45ca5427cf8d14d47acb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^5<o1#!3HFGRQ68=QjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?i-Fp&gD|6$#_S59AbW|YuPgga4i*7nrFU^NfO3q?o-U3d7N_4{ z+3R&AK!EkZ`Chj_j;#%wdY76h{a|Q{=-#n(t$*T6=AQyd${ka0+=x2j<|<MjVY+c< ztH3o47HwODJ7?~kJ~Pw!ds}@?^TbnDZJi&y_dKxO7cKfCf$jMZ2l>Z>@duM{D}6q3 zc-M)fvxTxpt?f^2ZthJ?&sU0UGfB$)VYyE0quQHRuISQExeYzHC%CUY!5Q{ArmI$` zZ4UFEM9$Ycj_dWUl1+)<aH^p5=7;6Ysg_6L76)`D`y9;JAQiE<d5h9{rw!IeGM(AW zEe>4HKl6a;_SfFL!@8#o!z=ZDUnB~9)}HWGvFwi6f2cyYEqY7sNl%rzJo^t6XGH&b cJO8fwVkM^wOt<Bi14D?x)78&qol`;+02^MQjQ{`u diff --git a/graphics/AtlantisJava/img/mode_sequential_on.png b/graphics/AtlantisJava/img/mode_sequential_on.png deleted file mode 100644 index c083bef019f8924502fcfff9cce53910dbcfb8b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^5<o1#!3HFGRQ68=QjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?i-Fp&gD|6$#_S59AbW|YuPgga4i*7XLz`W7{XkQgJY5_^EKa|@ zZ0pVJD8Tl>oi}_&_K`zM89FxHs}uA)wsuV0_LEnvY}UQ`kNO3?-!?5>yHvh+Qo+fi zX?%UoJ_=DUxewR8d3R>d=G}jixx}3GlO(ktidP&}c(e0@gS7G!i8i@~qDP+};yb1& zo3ik9g!Zf%ZOL!yuLcNq8Z8m@J}l2ZxulIL_Df;J{${4#6-OlXE*uu!R?zQjqj=EL zY*9t0%<UV8rTq$nQzx|AuI%XG-x!y8ZT(yARDo8t9j?Kt+s<0tS#98<9Cxlnch~M? zcg=a?3Oc{v-_gu2b5-0bI4-dI*z&3-W}U0zlRRc!|K})oQriCG<jE3;vwkSsJXU^V b-{Zeq*n6+ci%TlN0AlcT^>bP0l+XkK$IX_4 diff --git a/graphics/AtlantisJava/img/right.gif b/graphics/AtlantisJava/img/right.gif deleted file mode 100755 index b256e5f75fb1f5467251abbf9442f338892e6ab5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmZ?wbhEHb6k!l!SjfQe|Ns9p|Nk?9f#N^Ekc`Y?g~Xx~1t67~r%;lSs!&jxl#`jP zkdmL9n3<=i;GJ3ql<+7`&qyuSQOE}IG8|GfOZ1ZSb9EGgQwvH`bCXhw6bvmbO&Jt_ zvM@3*Ff!<X%m>-Xz@**Nzw)%~qgf4szES6oR(^g_8+4;}QR+O8Rat3Y55;}UDY3n~ OBkprQ{}oXN25SJ<qdqzS diff --git a/graphics/AtlantisJava/img/toolbar_next.png b/graphics/AtlantisJava/img/toolbar_next.png deleted file mode 100755 index bd1b428684b001ef8ebe6fad7b5d10b3271953eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 659 zcmV;E0&M+>P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02{9W02{9XUK)`c00007bV*G`2iXV% z3jiBk5G7>*00I+9L_t(I%e9kBNL5i3hQG7-d0dT?rdE<f5N1wmpwqB%H7iXLsR(LT zgUBGLrVW||5lvFm8d^jUWb_zFL@5r8Gz+!NdwpH6=iGaqdpGDYD1;>Xr~l$xi?!Ad z|0rWEqyBLBB}2+dVaWdX{cURk#9Bt|Wv|BGLSGUTdUqY^-nec+n4jkSnf=sn&$Op; zX}F=SuX$a7Xl0h#EtQ<=XyHIh{Z2{pa#w3_S3_IB_+tk(O{eohS`|7CNs5c4K^_$q zx!KnPTBEflx8N}__<`(V_!J>JChoR>`30!j)2X{IoWyoASeA{H5<~oGq%}$@(ljB8 zV}^!j85z$nXvB$$d&eF~0DE)eWw)XR*L4xnL?cidQl*I#O%x}DVN4iCRJnp`m-4T< z)mC@+p(+zV#Q~F_auiA?b#+^*-sG~O+{Us5hM`FlMHD3jrGUapf#t;|lF|xF*_Z%n z93V{#CsRh63JP9|UkXu55yvs5AjJ1P^2<xiOi!`uhx5Y99RK{}%0mMnvtwUgNUH*s zpdt?)d+4~t*=qv?VTkV+$z|sleftXE_a6(>>C6t@m;=5~5KKL*{QZnhO`|T$IHW3N z=HnP|hMtEh;-Vp~>+`Q~>z{Sznm;OSqQGbHeh=egqwl0$ezY+DXymW6;MDHb2!Rmh tEkoMpic>F&>q?nZ*L=s>)^w2nt#1c?_#WV$fCK;l002ovPDHLkV1f)JA;|y$ diff --git a/graphics/AtlantisJava/img/toolbar_open.png b/graphics/AtlantisJava/img/toolbar_open.png deleted file mode 100755 index c2d8efa7b0707f148900b981c51a5fc9adc92067..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 550 zcmV+>0@?kEP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10i#JoK~y-6jg!4@6G0S(zxmmjStGAyq99zLM4_Ofh=fE(LGl0~ z<rz|;yh2*?BB>}SXem-sKm%n8Tl|P3u@#b#*s*;nW;V_)(ZZ3gMw*%P%{{X_N<;uq zO057ZETs5blE#6E4C0Ik3Gz(-Q)w?Eg5B6VoQROEZ|?)}?fVamF{w04sYL;uPN&k6 z1@!LAdwluWjT6>jtwn1cODUArF^`I=*0=W$p1(c>Km#2AnsRbJO@L^=?!sEEiBM|{ z09#Mm>}=jm9SG{;N*G7~!mKqqjb(&V<0)KR#rw2EWi0{{q>NDq)bF5@?>c+UT!Gwx zsfVu)1Ymx7g7)oOPpNA@K1GN4HLS}FFP^S4`q^h|<1wd~^G0(!Xx_a4O!xjOZ$I?0 z!8yh==pRiuKASN*pEUv|Q$zn~LTed<bJ*NxIHPF?L&!9_lSV+u;$CMoxzDh<cPtf- z-(649vJ@@*&pYUKJxhfn_YNC;#&XBeTI(?wHRmt&XsySc!V$_2-hCRTrD3D7sv)^| oDB=@-K>Dq@{TbIKz#RDc2lQW)UGczGVE_OC07*qoM6N<$f|ic$PXGV_ diff --git a/graphics/AtlantisJava/img/toolbar_previous.png b/graphics/AtlantisJava/img/toolbar_previous.png deleted file mode 100755 index 940797b8a588cd4a74ce79ffd8c3957041c319e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 634 zcmV-=0)_pFP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY8?OKW8?OOg8j&0T000McNliru*9;sHE){3)r;z{v0tZP% zK~#9!wbRXO6G0fq@!#xjvfJGdgDFi(6@{khsiCQ0jE5?%BKA-!2-+6$D2NI@sNk&# z)|28z4_b&y75oSE=vma>Btj8dji$CWjoEB=citM4UJ9wN_<`s6d|`$e{40W==$&{9 zA^C*lynEr<+3RRQ!!~+OJq$DV`&~|Jlal+WYZ*|`LUMdAQ(v4<>^3H^oF9g_zJ%>) zTNj@wQi`i8*!1zCL|`!63j)9|fBto#XMC<p3jQb-)rZE06X<9U!Ku0cA@D0jgcC=k zYDA!!Q4m#!;IzE@>RyC2mQOz(B@nay$w+%P9Y-(_fU0Ux6r~aPK?(uRIVknvdoE^f zKESv69MQT@&fd`#@8ZE!l*D5p)M`E$1GE4(Bh7#i5{z=#wu^lJ12}V=M-bEj<337j z1VI%D?*NQ81wo-g)i|Uipj4ph_*g4dP$(>8rT7(sHUsMV`{yr=UD-EFAD54QDy&$x z1C(vvn2OC{I~<NH;Ccd-a!|%mwQYP^%!8H|rU^F1vKKl9^KzDD9ZL;l&=Ko|WtlK^ z9k(x!fdty>6M_;90gBeRM0fFJWXnt3nLa}#r&B7#jeXfedf&hSgiI4NQzzi9<_UgR zI62a9?LGW1J#tB2yZ>71v6TGdzhLeeG$r?M3Bk@m2zbS}1b;)1?;q8>GCBM&8?MXX UHoH%CfB*mh07*qoM6N<$f(*zK!2kdN diff --git a/graphics/AtlantisJava/img/uparrow.png b/graphics/AtlantisJava/img/uparrow.png deleted file mode 100644 index 339e331a52746b8c5d30b968cacbe4e6745576be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^oFFy_8<4DKZ~;+_#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*x382FBWFymBhK53vJdx@v7EBj4O9zks;>z(;MKp|UC7sn8Z%Udsc zb1^9JI3HZ{egEg;&_7K|vtkoDTBI)MEo?q>;+bRcHlEyzj2l!q?;Pq9(s_5fG=Adz by-OJmToo4S`}f)kXb^*^tDnm{r-UW|tsOe{ diff --git a/graphics/AtlantisJava/lib/Jama.jar b/graphics/AtlantisJava/lib/Jama.jar deleted file mode 100755 index 4c76beca1d5499cd3f996b3e3f30d77b02c7d319..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33329 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 diff --git a/graphics/AtlantisJava/lib/batik-anim.jar b/graphics/AtlantisJava/lib/batik-anim.jar deleted file mode 100644 index 6913e421c916241b2c96081e5402191b6e18e1db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95479 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�BKLF<5Q}XZ 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 diff --git a/graphics/AtlantisJava/lib/batik-ext.jar b/graphics/AtlantisJava/lib/batik-ext.jar deleted file mode 100644 index 8c904e1f2ab5de46eec36952299a181769e867c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10261 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 diff --git a/graphics/AtlantisJava/lib/batik-extension.jar b/graphics/AtlantisJava/lib/batik-extension.jar deleted file mode 100644 index 106e4ac3cbd922d89f6b08087a30485ad0d2799b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68051 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⁡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 D5d`4g diff --git a/graphics/AtlantisJava/lib/batik-parser.jar b/graphics/AtlantisJava/lib/batik-parser.jar deleted file mode 100644 index 286b3799c3f922a0ddf66a99eec096f4ab01429b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73710 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 diff --git a/graphics/AtlantisJava/lib/batik-script.jar b/graphics/AtlantisJava/lib/batik-script.jar deleted file mode 100644 index 433f02e67c5561b54ae05161e9578cc6f474bbee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61893 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%0D^F!FMsLy;1}Q~>nkrO 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 E4>EvKeE<Le diff --git a/graphics/AtlantisJava/lib/batik-xml.jar b/graphics/AtlantisJava/lib/batik-xml.jar deleted file mode 100644 index d05eb25f7778d3463f07380cf5ec1df675d534bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30862 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 BOe_EZ diff --git a/graphics/AtlantisJava/lib/commons-cli-1.0.jar b/graphics/AtlantisJava/lib/commons-cli-1.0.jar deleted file mode 100755 index 22a004e14e16720cae9af97d4d1475b12d2388aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30117 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 F{{Zietb70f diff --git a/graphics/AtlantisJava/lib/commons-codec-1.4.jar b/graphics/AtlantisJava/lib/commons-codec-1.4.jar deleted file mode 100644 index 458d432da88b0efeab640c229903fb5aad274044..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58160 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 diff --git a/graphics/AtlantisJava/lib/commons-logging-1.1.jar b/graphics/AtlantisJava/lib/commons-logging-1.1.jar deleted file mode 100644 index 2ff9bbd90d63f92cdffea944869ed9bea7ead49c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52915 zcmb5U1CS`emMz-0ZQHhO+qP}nwr!ubZS!>ZY1?-9Klja@8*}GJ%$rvgRh1F7vyf|L z=H6?kf;2D)6u>_=$c{>u|5Nzq3G(k%R#ZihR#HxkUg4i+5C9N=%{G|lA!h&HZU6)T zK>4p`vVwAwVxr0_bh2Wx@r`mr0tg}>$=CR;Fro6pprV}!frk<E7^V8TYqO9$b*^oQ zhc}JLluZx>zc<*MnYj<=l~#@9DZ%$pX|{V<t@9`^0KWnamPZeQscSb#gi6aicw~Lf zq%@Yr!*p*Y?<uKAU{Jl?&1aU%k>oi?sKvAbOJ?^t=RG48IlA;Z=^V^uc@yAmZ!3_0 z&|2_ewSC4)AhMxh>G_wu_r(@}+0fSd84!7-5wn{gt}^QDj1-nj)ckmV!}j^mSDEqM zqMzTyv8P#2l(Me+0RHFy0|0>iw`KzQ`~UV%=KpG;|Gx$FKP?O$42>;J{|7_le>XI? zx3#smbN(+C{?Yb-ZT_`k|1JIF-T!>@e^#)uH#fJm`>&t$-zyUQ&lN3g9c=#f+W&yO zrDZ?N79IdVkLJHYE+Z){DyJ+;=i=eAt)=a}Ig0A{Qort0rfdmTmdj#^eG=Jt7*;E6 zDbis_mK;vnK+p!(FiuAh_4UM?-V<12;{L8CTgEDRxzT)bpL>%t0)5xfCrUq+i*(~! z$yKh$^Ki(Y;`-ZV|KjaJ=u_6MxCQ*~>0)h%r^A9B<||vh{`uoeXOYd>xUC-R&t#8R zAoNZBjh|NZ$hlN^kESl|O*(t^FAsNTa=w~+Xh(NnZ+GXXJz78Ad1dvfr?2h%aQIhP z$X6@6I+a>(-T)`N??G$k2l6b)wq#jiEmCgAeo1gsZE_R!$VC^_dZb^CMlMwdYEP>w z#*zBydMJF_mh2imn0MZUxfKr5s*y8-HL4Rry+CiPF`K!sav4~B79O)H#?_sB8uZ5U zDAcn44PIT?Asg<KPzsP}=X(T)9G5XGKV@ItInLB!xi}y;oxhOK+_b&MHwl#mY)y&l zBp)M@jKjf6u2K_7B_Xu}Fn2ZSNBe>G1Z#2ZVZm@~ETIT%q42SkI{TM)+l<u*nigAX z&$>x|3f3<S$DBNdIy}s2&KBZZ*%25gsuuPJ#F^<$#l#)=h4k;0n$=qYUNmo!s0z8i z-3h^nr6A?TPP$RPBWVmosku8;PkFZ1VvlC2)gr#+7VZW<TIxwQI!vFjiXlsMEapSD z4%|A$C4bcoWc4(WM)kfvKi$w<aswY54uK0E?1D9Ly#s8Sq(UPJ9*VgdgeV15lP@y! zCQtdZ9mwePYkj8Y>K^Nb|ICxYcVa1~p?dmw0G=bZtiYiH_Gn+>fbxuBk^^=eku0w^ zXhTv$oUP!AYuT&T)`T8CTFavSglM;vEjqABYNF!QbTwg4pd^G8F$Y_?R6Dxg7BfFJ zjNLl55OS0PU4(BD3+ln}D};R3Ke@F$a<`W%V)|^^e1jG`RCQj$ed4wo+feXZS!=yE zZcV_oz(E2jE^zuNg#{GZWBoLuDK&UX=rHmYq&vFENM!373t=kF;yXhp0+<KXlY`GL zK+C=NpI#}zo!C`V(T+HrJ{bG6JTE~~T<%FPW;j3))0PHY4>B47HJp7mYH0!{@JMWr z%Oc<N50wHfpa3_d@THgxhX&XgfO&8XVrxU;t(vHD!f0rZ3khn|?*qXV;F)d?%{Cwu z;11@X?<Yt1sy93klPDWMr%ynsPo9G}><1%RAh2`C0c;&~!+xIikhBUa_z>fA)fcPO zIKapFMc|E6ZAEQ`b~NmqIi&{za##mo0c2XP1e2*7p#)p{<UxR<v9b98A^w^1Wb-uC zI7$hYAiR)XpJquxX^^pZ1@Fpv|3rxgmRm`Fq#tg4>waR$>ba5VuE$dQr8M@b($j)M zX@SlqR$XHSmjJ#^&a?$q1bR@CT-ymFw+0~6nnsEmNmQM<P(dzL=$cZQytYG>@`2^Q zdN9U`pv<;Ok2O!OQ&Fl2kHU5bIpT1XDUo2Z&ej6u=P&g}Bpn5)xYNHX8(_<B2f)qa z0rE$1K{PAbix1U;c<>Hc3$a_~=z7B{5gAp)^f%stZ*hMHYsS9i{k`dm-t>N^nI78O z2gFo^1ZzUTDgXxhX=tnsMcgymnyU!k=&ZKB0otLM`h<c-`9P@&;YZj0h7w96^$zg2 zG#4PzIT$*-0HvUoS`!hf6F7Ut>Jb7QtGkMZkW^LTH>4ZC8lM?;qV<s&JrhQzh@hEm z3%0|SlZ(oc<yhM7;?j70h({$$<(NUpnWiw$prTIw)ItngQd{aXvQWP4C4~ar(PJy| zWw?R}exl)=7*WuQ4d`<k(cH@0B}-`ht1FM&c>kPI-c~?F{MAC45%{DH$}qBmn5YDt z)X7H)iOYE#;(qyntu*lSu~TdayEH#oQT@q&y+pOcX4~Cspl0OL_{hrG`Gy&pbTdvW zs)}SHrUXGq!0hmT1Udj`h%(U7#R@<g<R19^nu>R<PBHVg^nG_Q^1)bozt<%iHo0@c zjDv@!HfTNzLKnC)Q9{0o^Ulv+Sm9<6YJxHE=pE!DDaXwiYz-*2P{DI-h(P>Kz^slH zuJ1vl=%2PD7Jehf#G_=~xfJI?G`D$tX7Ft(knJDf8=Zcp75EH;c_)}aqQIay>>}xf z2TkT1KwWS{?ze)7Bhb)_csAEq9{8vLD*(SYe?Y|;+;v7oa300yngj!~92nVtKB%tA zUi*e^7F>?pnwa$?Rch?Yfj^%%ZX69nkQ24oj?KZBu5wzk8=Bez`SS}DxK{dkujtoE zzYUfs^$`KT0}@5l<fr1$Lx3H_FRE!P=1A<Ta(0a3>mYvF(WSAz^FIs0B|sT-ahc9* zs|nhXe#;P?V82AGG!V75j&`J*Fz|?3iXF;-V)D?762I6j1LOTt)TRS6Xe{vA2NAD$ z#pzd+H5kdY|COA>#Cd`chx)mIqzuX^Gg6j_L7{9R=35pbMtqb(?-{7-=-Q7WdK0RV zNQcl0)eAF#UJJe0AYX$4)ted3ohl!8+~P_N54jPi2;rarZpS=OY_5UV0b)sP!v-|2 zh(lN$_`}{vB)@4!w<k}anW#m`Bmq^cM)~Yyi**{=-V1)|g?xS)+I^TDhhV9_jJ|T< z2fS6a7XhKg`4qcN_??TRqU6hQP10M=g!Q~-;(fnMrf7Lt+~9vw7&n3t^epI(LB7S? zY2zKzj<HCAto=fZDcqQIHf!42tO`t`f#~79I;iXpfQ5@sx5;6b0aVlvBfZjiyP!)z zqXy-voR|m+wLn;!&5s>VFnj6@Q~8>nfn98#AULTS20^QW$wQWv%sdNM>2N10C;hZ+ zu|gW8_Sk3tIlt1pGV^tR^#qf2<4E9b{QHeJ!O8sNa3fW)KU0RYk>-sW8C6Rjk}n1I zDTDHKS+kjlLNe#U%!sD~k?B_O6k;TOofX;n&!G90)BqS07AbD4@>|LuddUr_VF)%~ z<mD8>F_R0ELP?blbJtfs@CV6+BTrsj0Z3i)oPnecS=3vV-o}y2RMTCrjg+YuF!LG} zd{Zbyh*N+KO@etf`n!bi(`>jC=XnO=Mg^p-`43!o!wCIyv)NDC!$9pbj>BL)BG&qG zg|hS4EuvvA8MB8*oAIhaf9*^6`-tfhkd>a$UJ_)e)?Q%oL-Qg(s4;BS(oQQIVB1^~ z8345FpCImd##k7fFbspR<_VD{s?*F2@bx>6?{x<GZS5RZ#dE5N*2RWA$o_?0YG+WW zyOVL%(Zn3FRW8F0a||D>tK1GIBgPHg#L77f<&u`lN=+V~g{Z@&jtnUh__o<HPszaK z%_>RMxEgHp36WC9I5OkR^-3I9Amnf#>6y4b$Xz|wMgewoe6EV3xSTRP!(t`l4{4-k z=p>FE4xHw3n~c=h#ylKd(z1ANJb0&!bKCo~2mhrk&n!_ZGr%FDj83(^=ft)8>450{ zE7+Cv*u65CB{%6S+%!a`nOFt5oGKK35JM~zx;t#fu3bP%4aQax?b9=gTX;U<3S#B> zs%e6}0Cue5s@fKxdY3Kl*RBA5Kol^beFQXSJY7to*+5EnH{y`67j!Eb{Xy0+8%H}d zOjx;|6yN^L-X93AH;m(O;d!uF;gS-zm8u=FEBp9{0`6PLG#4jI6u+hYCl)JUHLyR5 zgMdBMMoWRozmwl=#>;lu^<igI09u#xPxhs_t#WS{ThZ_X{eyJj7$J+QvVqwfmOYK5 zQw;*TC1#|vf>0+6`CfFDo`76O3I`mcv-o2VrXro`9qT|7__b?BoOqG>X;!CP8Lr2U zzT(;OuSdp4wzrL3`?~d_v%5aEzK?S?YW&dr_3P>at}S{2{f5sfq{$aTs8!j>WHCjY zl`tL70c7biqp*m)p&AXQKaRdWE`Vx!y*hMyy0q)Qy}p*7&U+E~b$5Ec5L<LU8+`h@ ze=>zmx9|O2dydz@(ey^I_Tg}z_rCV!w*1<=dNlQ&e;sWOg4v@9{NS;zxLgRZGjE~F z4T18Q%i6OpI&(R|E`-J_e3A~&9GCLgy1;QD;<5MtatpbfP2p;tfI0upOD$`B6TPrx zo@#ta=k$Ri8xg(vwRIXsH<zyA2|Ax|N5HEA=Cd;2fb0??$Bq3fB%21JfDj+k#cI>S zK)<w;X5ZGG5%XwtV$S^FD<~3Z_7S^>P)K~z))5c!hITLwxHoY3)a}#9kHJfB5**Gn zXbMXf`y&#dL#@?`J9qEk{8mc9i?ja;>Snch(_Dgrpw%Ze03^)3(}VCN6f9&k6Z<sw zz-r3<SYyPvc2xV|KrFq6Q!EDa4SU<u+^juI9)>Qj2N_;#uMv9)u#2_q_XSx#u3u1* z&AZ-y3IgXqMAVuRd-0JKNw(J|Qb!??$FVFzH)#Lv%+&xkHF#jKV+6>T2f~TzuwiEn z9*b_$>h}}uIDmb~ty3`i9Omt|4vka|q(x{zcl!eo>NyQ1-*rN#{L<5F)9uDZYroJ` zE+Y?UspQFFQ?6NE|E86w2atj|)?}TEPek5W0p1rJihI@7?Mf00f^jpOpt~VkY`zep zy=Q1c@N{~;)-F#5eQ)0)prCQ^UGau7`EacX3&sXBa?Y%{eT$2%8#WSWTOV2>Vcic_ zAj<&7nY0Y~b`gn)d~y*D%%=>7H<>OopYfn`Z?f&VMYhz+eBCXS!RSinLPrZNp(4TB zLKJ1Lxb>24W<CxunXr1?3>Ca$^is#&@$Q5e*E}F?f(_QhCtvhv44arPM?k&0x`z5( z514o#y`BAD;t~H&0kowSK!n$AJ^f+*^`3pnB;Oy>ft@dOI*LzglqE}{f)%i)Q6X%; zkV>&ct~agfGAAG?5EAa-Z!mjGRFUJ$bbWKgR|}@S>TN<0<ie_(_a-?nI=VWUm+;qK zfwW@5*Bd%e*Nf#ct^#xfNP)Xzyk73{NjEq4=#G83fRp$;qLeHzH2?=7G&VT;idRd1 za##wvIj1dw6hh;p)@Tbe{3yqEt?i1(NvQ1vFj*YBoIod*b}^Vd!`h5LKJV%J3bGJ9 zxHktqM}s}qICCY0;VnmS_BEUsi>CYZ;IAL5pF&>2dE#v~eTxTt5>++kSz+>teF#)^ zw}G#-M@KIdM32M}AUeIDuRQY}+iz?s1&m@UB^*SqUuMEfOq`e-p#o{b5HE8*PVac_ zA6C9!NGfHd`h)ZN`*`2E%qYpR%W^vogVMpDf#n#lKN5YwcVx}AsaX{WK{*z%!!S6t zn{fyZ0+0nXE@Sr3Z<dn#7uSzE59mMtQY8K(JTDf)#L)U1)SLZ1{vjj$OSqAfSNR*D z|06nQon(XyAb<hr&sBF>26bac=P$q)&<YJv021B5VI`Am+d38w)xpR{hL{)$Qz^VB z+(rW`i6$}^TDSk@8N{jm()4Y(mo_i83lfYzk<8fRZrfMZkz=+j#rvP)2*m#pM{Fdy zriK0rLry>d03`pj&LCrNPG@Xm=<MvPBr826fa0@Rrk3&>zBX$9yb;yPFF@Q@5W=fL z<@Pzru1!0s#zyI5hvyaeQ*nRumO?Pvdz_(}`QeXHZ!bSzArx_Y&5$Q99f%6}kUHSD zV8fvMqp?it4@#X$$_|`4P@VfJscC16S+F4ubhEqpv62Aue5H>Ld0~sPJ9)uFTZq{8 zrK1_LA&+o%Za?ftpd$M${Vo-Q+S_Z`g3^1UBvP`OpH0f5iU?a3hX<QA_C%!H!f%~0 zYf*|?)-;De&e4`yIdrl9#M$dy!<<gZ2O$h@bIpwQaW#w6%fKenp=BeIsW9}Gv$Qrp zetiMnM9r|M=Zl{o9KfJUz20TatGq5w5q6b6@&X{Btuv1nP!9mmRVW)KdnS9vzdN%% z^Ub{f-fhNRNaK{pq{ry`flvH{@3HTgWj&ZLwZkj$zhj`LQ={YdxBZDg0RXuEuNVm1 z+nHIKyE+-VSlZi(dKjBJ{G;$6$mA+-+ARqn@Mg0)o@eQ8QG-hTUQAlIlr2n=uI57k z1R|nZs6axZk85_+A$2=k2knhePaqH_xQiMVCp5!l?->`3NWa_IW<Hso_VWMweg+2C z7#X5DZfYkq)E%^ibSJTqSWh{VK{XT-(*l7^29k|r;1!v|3^X$}5y2QX1)XXq8w`So zhFW#d4aorl1_ga_6deGbW~S)ynSkN$POI*nW0X0DJ_3H2XUQtF#`X@pX@5o=n$EnE z8hZJYwL(^&9Oz@1Z%FEY?$PGeUu!_ESn(=9EN<8{`}OdsaY+AINy3#{PI^iHOg!HF z1|6>vNZ5SUF4r)`pmA@NW7u-p{%N{i<<v(M0b`|fpo~5(PwSnwvBmByZZiz^U^++V zX}8@dyaR(X=leOkZwt5@0ySi|@nAb-ldTqvowjD>X*Xu!)hcT?8aiP@e&bnae@7nI zFp+V^=57sRDg6lqqnQm}ikHJp`J#FXCKvr;iZMFNKF*NqLkWWn>B}rZ`{yi!tuXfI zETjydB?nFw$72jtBHWDmu*;QZJ{SW)faI<XSqixfT+lI8ZBqgf$m9w_GuC%toLsBa zA$eaSr9&nY6~+(}t2PA>`$Zu}<xF)%N}iHhbjMJZe^8-lnJZJBVk4rY%==M8s-SB; zIRimAMpT#yJ+t!}_iXK5JqBM;O%pvmN|(YaN&vlh%unksrc!F6ANp|I1=Ezt7Y*~o zE6LZGmkmu~ngTVo0VVx5XT3;4b;)1I2%q3gH%2jjh+NKTczu9l=Anf3*G+*~XVEY1 zcB~7mg{*7gkC?=G-%6R5x8vo8r7y#JF`6&<e`m7`zdp0+-w{RQFQaMyuWS}GG<LCf z@+4vW4+6&~DoP76VubCSEhL*+rfFj8qFO4H*F_V65Ob&~c<`Ta$i-=2%1rpHs*9q3 z1^B77Fo)DogKxI=?2I+LfBa)`NgQEx^R;=e_*lPh)CCFDZ+TaOB&A7L5Dqlx+JFjo z5em+jq_7xckrWdB(8))(`JC8(3d_NyHqWl56Z{sEFr<U*ZasGnT8vH6;RcY0m@G{A zbmKX9{F3l)q^$^xT4<O4B{9d`h*MP|oT=#Lm82&+50x4R^e(ay04@_NCPgM#QzW4Q z-?#E%zAAYq7|VKqn^*(||5sw&f)JZOg|?m1b6!$gyftTjVF;T15l6h_q};Qq3C#q1 z(UPHI+5e(83rPY2hwdQa(3$V~660;vnS&7tQub)&2Epu?-NeUMzoc{EO5pYqzFsMv za+@hPY7L8`b_2C2usQ%+6l@4?*`wSy3A_E1=>H~OF^AZVNf_+fR%f^}nzGMn_5}X# zcny^bwoL!UOC0$B1uv$5;`Pq~2RobtlFm-JP)EA3GAkqq5xyHFL7`Mi;+UxP{KKr7 zLz`2t<&VguexL~GejxlVH3EK6hAWL0Me6y=Y)t%IPG-;RM}7Uy?jB&P&(?F}^+8;G zEExut>|i#misM2iK|d57XnW`pKz2J)L2NZlb*`PyxH*rMXPSt8Sh&(UU+~%)9>b-J zoX@7LXWm#=e92jU0QhPJ%^CN5^Q`43OyCb%Ew5^3(;Q}1mlp|UP`W0WY$BO+7=v1- z4{t6^>Bh-W3WT+J1#^p>`@R6JhgW~B(^;t)#)U~dboI<<;gsR&=x-84|G5zjF(G*} zuBl=ba>z=NvCC)UBpbNLWr&XQ92H}Rxl0W#QjD~a#I4DssfN!RFU(bFigY8Zlw5K9 z*sMeuB60c<RW9RoE_HmE&6CUYxD^@6HmkA8tCN^=TgPtO<r3jPw5KC}`-s~(V#Pwm zM|H3x?0b1>UHtxks94ky&}ep1J>z}WKVqPJKE!Xmxy38|X(FmktWzLvz*i~$Xec<s zuR&Kf&>Rq{7b&F~v`3RR)%7C_;S!(v3gwplfc}E_uUzZN5A|x;O+825qPS$$A-nlb zIyYkM`!7DqKe8sDNsm)+e`yi&|3nMs|D=Vi{oi@W_hQ)5NJe)tMFFZ*Kq^^*0cnh& zq)Mq&YEQW2-1nd+r`E>a)Sl=_A2kwazdsR}AByoJL}`I&WpQ@8_sxU(_uZWSPH%CD z`6-vj>26~17@QVdtBywdUeEyZz8NfATFfmki^J3qaE-@0OHnL09+!r(MGN<rG2fBk z^b&;!I}cjnHDk)}T;j0YXV4wJ>4)z6R|%6I=vx7ErdThs?xkL!d|@R}@UsaKWGW9K zkW_W1)OS{4Px)AoUp@(CMARH2v%4>*RDa}>3diBz7|H^U{k04$^vzfcpgetsnJpL5 zSwDNDo;@p6*}UzXDvo+5ivsd*9cY3SNF${l2-FlsRD=2!YSUE~aVsRzqI@l-R=}E7 z;zQF2hondz!4uK{Z2RyL4Pg}qYu1T6ZM1nE(ZEdo@PQ7A0Ui<Mm?+H!y=3Mn0ViTy zg=tl#7+z>0GuY@mD|vm|2)Ryq(VUTPQO0ZE74=nhl<**W2zr|?q@_x%&QK-x06whD zxaIE9aKR4J)FeHHxkR??d<99poMBpR=Q6kBNB5IWK#>l%I;LOFcv7@F)>9nOLt#%L zXhB1Tk!z5>h4+ipxbqi22YW~?IPwp1vc6MSm7kbMizu|>zPh2xZqiEhc)kZM4}J;N z9k5wGsBb)A`u{h_29R1=5c@BG68}0j|NE(c<v%%Ot&A**!V3$7Jf>N^cSLt81`93O zFPP>VNgpDzK%gBqxM)99lG(zVS#}(lo!|5WRE?rpdtZ$IshHMgzHiK`mbtvO>3iLC z@`sQ4>v?->4P%&x&8gy$!G6Cp5}Qm-W{aiK%4kMpMr3=K7J4Y7!C=1y6q^5hMIOy5 zqlF=a(suT=UlaHB4I{3&Vull2HKm1e^Hn*!kHOd&6WvB<peDBZx6V*YEH_qHv@{!* zh6zS4Ej!+W@AWIsZO%;Y*kEjWUr4qi1#tZCz{b6s6+Ywij9*&g`2&R&#UG@-`?b){ zQ~xvk+xmj+iEBDV29>_tyx~Q6E5SuX!uV1s3hx?yHdfPg%&_`#fzdULFf~<a2Ab7x z$B{fb8a_*DeUyU+>9-LLRCm*Ps!po)RJ|leWD!i5XD@^Z2Hw&LjC)wj2yaPq@sPjS zRPxnE8-U83r<r(Ii>65Xh+&0Oa)-h~ooo9C1*_k9?!ATGT<*rGZuI9^VNSxKc|$Ml zn`m*>T)3zrarHd$8aeVCrKCkISyYg^is@PB8qL_lwusW{gk!quB8rxQEc@QxL>7q# zDaM{ee+mFzER2_qdn1&fxI6+|XY5d-XU%sjVpd6BfKU<bRiGc2hglcJ5s|9u@nDkk zZ@sHB+pk~|+f=L3!lH`E`#!}mM?d_z@!!h=YuzgHOo;Mi7bMyxDGur$+$mlp5#?Ld zwrm>CZjw?AkGV_By^+X<xl!6kBU7UPsxpw>b6-h2-0pJrKz|T53Zi*nyu>jC1b5`L zegMCyPoX~?*#+cL`x5etSHRu`@82e&*Hh1(V^ojxj6W^2P7_vA7-sj>wa}YYY7W{` zsCI}~ska>p)`IrfW|LQ7zl*W9oqFzJjO{DnIlV^V9nS?mh*99M#4+B`m+B4pXkfbg z;Wc^m4NR)SIV7(Uip4nw;P4uPQ|ywygDdNYPGdVEvc-A=2#Z6y8Dk-h!IH%=mBm0$ zVmWEB9yA!MG?;OgV?no=(iV+l&4HieSVN)clCxswca$;H91^=l$M0n3UjBUoe_)6G zSpVy6ef>>t|L=Pl>py#$inj8S0LnKS1SKI<N?J6O3hlfQDaAglNQWxa5fKDjZ)igb z1L3Bml9*rA&j5IiqJhb%_}?xTXTC&4z#+`-&Gt6CapQB6v+?=<^#xva2jGkdQ|(b` zBr;MFl}<IP(yer-HBu5q3Cn7+fRHFASRKaIGEwdpE4PzW-&Xn(7pCPRA#RS#;&LW& z(96=pl_&9l!poH>dC8f?HM&r13<QbGxwXU?4H&kn!qsPdof$?OlcP-oN*y>hvyB+G zUOC3N9n{#~I8?ifB(u<}P0-Gjst0`q9@e^?n!-eo+&S%;X<yXxYlPP*ww&%HiA5H5 z>nO0XGY7u$x8mlnV8*a4$;JuH$D9i%`$b0I{0|sd&&?y~(rwu59%gnNsED8P+idg> zOsz=)$_8BH31rc0P_~x|#2M%*msOd$v>4RiVciraveXEFz5{s15@w<64KhTRejkUC zy19p5V8>CQRNx%YaB<3{{EnjVM4S7aRApzn1Ka9ppbaxqU3VxCLL|t=j!Z&3fWSx_ z{o&`7aLyhrdTqx<kw)yph1>i^xk=MLNDk!B#Upop+^0$}=ilPN*bwTC$9n-Pe9$*k zWTwMQbN=#H$LJDP&(|iEhkL2KbIDs(+0Q;!>omHqDqDKSIY^R<MR;8qb8Y<;U-**c zTZV^9NordCEJaefT2E31*=j3997wS?T5z2y*L28<5z?IsG9NYBCH!GLu8&&FqSW%T zu!M1iwD2CMu(S39dq;056J|r38<<2&S5S%*ipc||*#eydqq#*&jmf`MTAw!UtB=Sp z;@tZ~9wvvN$sfd*f5tD8qGo)&`^A{WSNH`o>6L=JC&t;mhtO!eWdhE`-g&C8s>mGR zrNkVJMH(K#1g)DXEHhE8n<*aN6hLPR33){8m0}u0WnFkKqA4lr3R3GKoX?C!<|sP^ z(GfoAg<r&96D5YJhVu2_CL-RM>huv(0Du%F008R$ZA|hX9psk}xDU$O-R*SOcF&PZ zOL3H!K|@HDEF%Go7%YO7#tINJN3Psr=2EVYXaINnNY4n{uAbu-&^lsMW2`oToul+t zQhVuoWA1Qc?mDIaN495|dmDK!z{v;b*Yg$i!|}{?HaoLD+S!{uzAunX0=-|QaZem9 z7u)%IiE(or`Pq8WfferBsYg?swd-eK+=YuyeX;nM8g36)>)Gj2qwW|SF1IU>=ol;) zn9JoNV}-HAm>sVC3S*72$XG>Om+MyXfiM?e&4Ik@<%(l{oG;h)(j6mi{=%I(7vB6` zK^*@1Yhs-L;vF(B|H|DQ*SF|c-}!4toc`IXJMK^6!5Wue@d3Z<XL{Vv>K#AVcYfT? zIgl%%i{Vme5wt3L7Tsm%yep#!I-IV_>0o7aVJAje^j;@MVRT}r!<kVEo!Es@4BhCt zQ4Zbc1(7m3vJ0akda?_nCc3f<qbj<cuFTSii!M%SG-fA<9J*}h>7u9tI-%}XVRUY1 zyEr=k>PSy#yF9vYCr3f_iOXG;uFK{~r5j>vbcC+R6_FV_uUq2+9oxo;Sr^9)om^Wq z^X0xw7snLcY-_ahrBSr5&97+Zt9_m>jvYF>hG^)k{ctzOL|q*l^z`+SQa8s;T^&1g z_4ScdH^)9*9s_jv-y`yuM(Mhjt<k)2?GWE{fNPG8!O=^5+H}3n{g@DN>k+2`*a{rG zVsv)<`#3F}yFzqy2S(UbaO)vdYb@YfF>ZMC9T<b5!O<{uIdB}%;ampXa0f=O2vlMY zj7by%==E$-;9}gnP&h-t#vK?Z0r-0!U=uF=r5uJ3I&sLJ21v-98-V5qD0F2^5!r|` z#H|ioFSsK!m^#yk`xbOf?c>KrX~1>EIAK#qM00@J4Ef+tI4xp@z;!1^+;~GHjXYeN zfa-fWFzsk3OyfLw9C6WaaP3&=3~8ZTG)B9kI^22DBRVvD`ygPNlMqpvp-9)%rg4)v z4s>bE;#2J!v(fbiaa0;~)R=Wi*{V9##~rNGrnJzlX-7>_(a4&^u5w$U=8led=qJvO zfavH>j;QEuj*ZFD-tF!2(cn2m&}|NlsnO0I?QzlCIYwxCS127GzmyO6V&xL!`y8Tx z=#CeKjPTH*?_kO)2500Pd3vu<qVGt{IRNopqL6sDDW&eb$|(+dO<#MJRqkS}#8hMX z-J-NU6P1_uO63&e8OtsD@#y?cQDQwxm028{G3Q*Ol5dIV>|CQ(+9xPicYEX<nbuaB z#^G=M$~D5-xktRZw<vi$LX}(Y1JLE2qu9&_!q+%N!S(i0a%BSX+qg%-?7%!8smM;T zy4NZFM39iy4szujk^dZ_upfw(x93K4-^I&0vg=)-z%w$#AHbELn(p@K@J!b5#ck#o z@hd-()Zei@JTrH1QtI`q=j@B(c|=C9VNP9m00Ye{I-9SxEwiVn&p8nvc0Fu=S9Hy+ zT|u{sZWR`ABc0!O2rtO#uV2A>5Fxs^EFrsk^9~qLL@9{eF5H^=Hw3@?f{73uS`u4S zg?9VNFRvZ{IgNK)Z0FyvgL0*L@F*_4Jq7|<$<6NzL7PdqdB0!mya&71?Ox9fWr$;F zC*J0(@7tE=&|>e}`~t*}=h&*{bN8k|vmquCu8mgOJhFp+BeE-+z1l<}rSlkFHYx9` z=H9)y2Q98_k&zM#@$%Vg=$kRG5uY|=Tzz(^pbq5^xhG+wHosogSnf%TNDoMIlAphV z_Y&6K&a3ES-MtWR+9#VJFc~E;(X?_2s)|UhalEz|-#&u$;_~?-i*b2*<^6gm)2zhe z;MrO)zi!}1c@}3^j?Zv}0b1m`rg4YjccNF$%*bOk=p)J|R@6r)gmL{CMA{3XQFitK z?<pj>8-5p*X^5!}9@T<aYTB}8#1|Iv`IAvXeHkq><Y&K(4<#n?g^;5e#+D(p(2O)G zNCAGYnQ-)H{p`g}%F+dyO%2Rnfr`Oap`3f!j>4G&gA`S$!4!4AMRB9KO78B_0}43L zK-`eBSVttAt)WedPQ<uadDKc<{?4-)xbq@1-C!)>I&8LKZb@wW;N3l(%}XM*MtZF1 zTfoqhVf6^wTZ3v<)5#{3d=Zn?e5NQ-p}ly1>FUny9ZHh2OCl~bP(d7gK`}$cIOvz@ zoK@11RS4ro^J)pPw~^bKfSZ)j)s+$ma`O}%r<P;H!rjJb2EU31;$@tu<@(8))-cIY z2|kttKCn4iptbRWib!#iu`6GPt=eN+E}l>NNeM7tOURKOe9lTrZ+1wZi$Gh)XX4FK zh@c`1E|5P~WLYYY(8P;aqL^*;4>w6Q4D`XvUF7r!9!D13ufs&iG{>06eTKQW8mN%s zrKfUc$Z%kpoYrn)AQ_y(mXJg~T8Sn9kP<o>X4e_SSy@8zUT{+g&9iq}UD85@{u4vc zOizsQc1^x_28T1!d@zQdLvT<T2|qin+o7z`79=8A?VK`yh2(^=na&&L9|>70u0)){ z@z;2q&!6lT7pzn<$&bzVzy!(gsea=nfO<R|e>MC8u#qQM%d9tRuzpSRFyAY{{lbRd z=vOemG`CE#nhvD!9z~(CFRH-Wa*02H*+^MA@%$HH{NY0jaC=*gFhfe$IKDjW`|%&e z(+MobvQc%S7`ix4%Ou!P+`_v<7^c^P<>D+j`J#7-f6qv0f!T?o5T-A$F0S+s)K~r9 zZ@TAl+TN<Lub|dDqN}adQ&s(=AXjFh8adWgNK7*%7)6H64hnb6RlIOrG&rctgUz#7 zQQkja45U{1-HGz#$qmg_tP2SDd8zb@qZ!v?L#*rV!$(%jvV2@@EkQXG?-jH_CQl%C zC0Q!=n1ST2G>;Pl3WSmYM^D-|QD`qQ8LcKr#MfL?<l!l6>nkj3`PJEU{~qRAeQu?m zy2jdqaC4O1-D`*WxcF!~QVRRal@_F>roAyr<RI!LgPCgb0#WSof`nx#O;c3*LQY#z zr?056y`;)V7gV~jv%9RYy|Actl&R7#lzu*!YPNJoIHLu-Br<VUfkMhwxUNMR_3C=2 zFr#Z}>43T3dK<8B4IkE~Rfm|uBVM$~1;1&lUP3s?N1D_T>=WB3aAq_Y#ZXgpzB|i< zsFw$Bm)I}On<lBf0ITIFyXDCHH_x`BK8KP+6uFH~jgXJ1gBnP1Z^M=?estF){^QDU zr<U&?7@vyEI+9|7;hnFo*{ejLnvn(Oo^&L~L@zuNFX_jb3uy8e@zQz}<=2N4Z=!_| zH^(bJi(2j<{}M73-O&%rT)xr2T6&vY9Yg})El5<4o<4~YD3(1SQKfA`wk2o28<vxH zn3a&z8<T!lV>jf!l({6CCf9}0Kt<n_xvpc=ic=QbB-b^Tg{Jbv<w?iG62?Z9f&4gi z@G_Wu`%pU36=XQm<dD*pr4U3g_R{ckDP;T@j8i!_cLp!MmZ{FhLHM?+s0~OKk0JjY zi>qflDdM09LL7HYKI!J_^-Tn(i>7I!>oA;`pR1>^qo3#u6Ow5An7oyWgz|yeaE_LN z9Ib?0X>&(aT~TXYQK6}>Dd$Gnr78-R*y-Ozx82w=%yt+tB6ea*6Jb2nvttc5(ED&@ zxp7_O2n||i5ai5@!ez&ZI8R5evZ$pd>=Q25Pq2rn=P^>Y#F~d4j;4o|wco7~T{Gfk zWzjx`mNC<x5>|MoX8^cl8cxT8OR}TQwuDUT1Fb@{NDYO>UkT6AmF~;oMuzqAGw_26 z?=ym0e*=spc{>W)TBhOF-av?3m*$bwdqQTLnLiT2S+mb&QY*4zyl582Z3xj0i{xmo z<lUv=>9=lSL?*T1WApsl=89tOldDPf5ZO6dS>iRVtQe75Zu`PqAoXJeCe4Yni5s}} z@ycAfjRMQ^(%P1HSZH~{!2|csh?qbut17F@Y-<D+v9MG3=<}i_jN|3uF9X!No>0+D zD7WuWO1tBBB^C-o#TpuKk{oz)u>p%Djd4wb-k!el3~;jIJiE!BbC$7!_f;l|6`6lb zh^HF{Va!g(jo8xB)$63epi5Opo}O4oR*q0Q=VP7Lvy%3i+$~eP3hTOkXc0NgWG#(- zg>8RzRk?L+#t66nbhmt|sT;1mNGuoK-aQ-?6Xs7#WYg)|W%Ku&$2xmS;!31y>BvV# z#CR_zFUYfkk&s|kqLwB~u#C}+nk)FyJE)7)1YAL;CiWQmi<?KK<pek=YAL~6l6{*S zW#^}*#eO9X@wrovc&U*<bXZSXXRUTdpJ|9hu<<1ZLm?H;hqPi)K+--mZ(No_nREqk zn=zWo8H-h(o!!Tnabl-Nv@m}+#EZ(tEr<w!l?Qm4WBN$`9fdEyPtXfXcBUifCl%?k z^YDlpagHwJ!UsScZGXMX@M>RjT93OguWF(;jL-CHM@`J9%(f4a=Mql+5i9eRRkgJ> zJ)q)Kb4GG)>(*j`ysr*6jKr7&I1)RRnWmCEUh{>FJ$DzDu1c}If2U0ltBr-u@rLEh zIaC_>SwND+#A$>W7wgT*P&MrcY<>I9d&mH{*WLt&SkF*FYEfBGc1J4I=_{{ZMI>pS z-9SjGKOw`^{56V7i2!A503~a^hwCwxBl_DVDYST?0{%lTc0us4UY2l(pygx8hK-_= zjYm1_gL-fUZ5fP`DQMrGiRqZ(M&at3fVtzi59WRq%d9%r7A@J#kQm9Dm0viF<B)=a zz>mF@wCZQAob@NVlpe2v#a7mx2!wrjU^!tIGW4^*b)fAnVKP~V>EZ)XIhUY}j3oe~ z$>Upq$3&tt#D(JRgZLoZlfvhYw+wmNEL3_0WTFA^MgLsr-dHcyHS@>K9oCYma{|(( z`aN38PmITE-tl5=^j@%#qW~^!I+mTt+H!MIBF7#lc)t<CYoI{jZk#vCO_<a5*C-PK zKLas@8xHd-+^gNi8NF^1y|-;(*8sz89ss3$!n8zueZFd>1nV*{)9|7FSk{=eNIaG< zD@AAdlo_??V_FFa=d~Jfmp$36O>Lvw`QyDD*|ksBp)uIDODxpK4W`dQo}mwU>Fpo} z0d0n%#Q=;lv{{B0!;n|_^sN>phMna~LWQJO8XhsPz#p||%mb<wd2ZQW-@FE&C01}l zp}tQg!TaU;qfM4d$}M=-Pn{qpb*ZjAC^<SQe9V~9Ox54xF2pew58hlsg%I0UYN3+# z?1+04brFdoLKzkzd{e#)i!2}<n?e&fAS3rJIosx!l(was#OJI|7<mAyHYl?R*RK}8 z2*cphwl+4A(OsI!(g~?*WrckXrt3^g!b=yk$0`>zvt=>cz>N~+#BiA0M^^FnpU(7z zq7^i8N^1+L$?Y?KP0V*QJf${KwUCxnJEse-Hh8f1KAyr+792kPb)w_XB<R_}pU9sg zu~5x&1dEE$EVBWXWyJ&S*hpwLcDoVoL|lW(uXT?gr7hu)Iz<hcl5Dk%QGT7v9BAdN z>y($W8!;%-!`nkO(w*Zu6l2SwRb@R^^E8eTf7+@PVk9I>i|Ki*oI|pQvU9!R>(`7~ zah$wOC1FVv-7dvC0q-IDMe-}*M80w#uB5W(Gm6q6PaZ*JNBR-+F<QlLK&IL>K~hBI zM>U=)H@Udt(hy2tk}fv>LYs(@N-hx{ms!HrCt@5*>LuO8y0L{3Gur;UOmvR!NYFl_ zSZ2zJ7~JQK1=K)tnMj69Wi|bg#da2bz_&f7o>CgPM5gTg;IpJGK-mE{O%@}Y?<<<& zXnsOJq*5*5J)>=jgXZjvC27dS0bCw7d5>Gfhyzr6YdHRD$J9cJs)k3GQr8g_Cw0-( z$Derak#}*zQCBuuhD~08Clv?Xf+*4E5=6VoA>x?~XD#B}@{l95QqqJg;!J7WB%kAv zomC-v=ZJZtM>C~{XZ-*^JSc1mL+Y=nCL4t#fdPR$li|k;DKGLx{V8I$z9~6s0>XO1 zgI(L+LZ^(<S_fg9j>Li^I^XaTS72|vNTf_`nb`4b^3&he<eirGx49E^6Y(-`VnTM& zk>g+0?u2U*+E3F$wkC)$%f@H0nxM%H&k)Lc7I6TT#4Y?LzC<EC!_@HuRLnu)_N%TO z;w?OT{_?@5fns{==NLPXuz1LyP+**ks2y_*kMZ!5I4s9`IKep{!wHYlmO|_!Y2gY| z+{cl-+BG{c`}a&-FcI(@TtdO)b;zKZi}o*93mzKw1Ds!*3c9+z*h4Mpt#*1+A(G^- zt+JnANe<yh>abOu(^`zyZD`M~p<b`T35ty&sw^mxpd4FKB_Z0PX&*5%mh+s}4<WT1 z-UmsDKgUu-*8qqE6OVU@aaPoeBdEm0z{cqtcQWDO$KkOzD7_WjC@gmABq|3>{b2?c z#3OLHPOza56vK#pN)2ZV3R}OaAIXI6q8o=%s5Zjpb+h=BFw6q6E{gQ%VXJvZuZHP% zeqBwntiz!L_Ct&h$KTls_@rn75iNf&E?yTtFQvI9{Fc}HU9R*&Dcyxkwr8I9+{p4B z@>eN^`-Z<(alid>D|aX3v&MuU0QsC<ghSqfeuY{&`teV{`5Qz(uD<mxAa9`qG^N^G z&Vb<h2bn8=AX?cH^L*9=;s<>_@<`8>d+#O!GlWd$?z(_}7}!q<-%8+jzasc-gWte2 zy@&I8#2mj2+_VN?b9KUhw`W%lpHxf(f~S@T2PIoP@i<t;3#GNfJGG1zh<M|uS;z~- zw&I@~!hOr#gMoBW3z`xp@Rqe@HKW@}7Oj|^95_WS0U*p}17$?EA*!4oqGTPK*e1C$ zy=$JA<=}i~Lmt25HArSLIm7q2=LGMLlTspnc<*lHZ0WrgaYniU5rS>n7OdNWZ@YnW zobhhCp~tjsQ>0^A6Ci~;9kjRRP>_Wl?gTPW)-k3#BaVQ(sa^#`Yg?qQJrDMLzzUt2 zTSvhhYdCa4ENwc4_`~n743Bb;0CjI0NMJ%iEm2Z6a=ifbCTA}}_tndFHG1~k?zvGU zY<jKowbzWePV2SDd--ob!*_)#CT@b~FI1y{OWtoo(jv9!1s!V&h${&`p~G0HgP~fY zvkZ)pD|Aj;gvMK(=jVl7by+#R^sl)ar|Fn>>Xc@vP3&<he<&yS?Er+^le{(}@o>ZO zB}OkyaMEF;3)3`b$8N+QKMi<GA0CF@O(4Sw|F8hdCNg<)PajlfO5uNIn{}bxIiR6~ z>I}D291>yWHz6}An@z{TmpmSidB+luefe*JpCI(>y*eglRbHn9E0b(XTZ-k#k`54F zsJjX^9WUq#0egZIm@Bxh0}ee8w4$jie(SaSqpMfm@6uH&b)A`4`}D!1-(#2ea}tPz zjR!oyq>cbpkf7#(2xZF5q0FaLK28IaGa)yn78eRkgpp3tRH!u>pgyfoKNN~;Lim+J zuu(=EWIOR}RnY`+r;OYhmtwe4mo|t~28*YdHt1^t(o><{TAOlqSE~$uNWuCPEDw%N zM&6>A=H&<ibES&mRI(VBDTODeBs)Ykft6E{A1p{wA5)d@>X-u4sR6a?-5FOehF(b_ zuu~E82%nA8PF8vZB8^I?K<G){SX*3b1#OfK-wK)%^Htl7o}@0_njXpch;u^wS8ql2 zDcg<BrEuR$AIW{TIbr)%Z_(OJ$|V+V5$8<y43=(@k5a-%L{0`9^)^Y<C_P7vObQ!8 zu1KfkPZs+!!R#GSsf`!Uu(A=LfJZ<%(rUT`dKU<!EIGCffH!E+jOYi#Ivd8H5@Z_; zsd4CD7IZ-M0<#5qXUdc!%MrA%S&V{w^HMLZ_DHtdJl2g$saL@NshQ-3$fDLs&0bEu zpmHBnoT+2LEG>5zC|k~kS)=m&WPa{vu2b!~<;<Lj@paIh(rf?4WR9N5g+n%=(!SWD zO+6r5)exd3JrGBppiKcrp4RU`Q(TTCcEIG6ZpwhF9)PX>Hzge;R1?_om>2Kr0K_Ip z$tFzNDgoFLX@NUABIuSdEL7^D);YY8K=`{fAjb&u83PTiJh_P}S+Hgc*jH)hLt_Rw zEbFD?a~-;#c`jc0D45(3x=}}ocBMC@=J(f!CQ6?t6x{}3M^jtMCeJ)i#)}E%x&ajD zkPnA`FZ!UWh&t}q=X}bfRnwk9HuxZ0eqLyTC3O(wW1f+=%p6jN9XDWHkvrV42V3dF zel?h8TT+JjKhU<N3MSS8Oxn;j4YgrdUTYhxLOr&)AU4}dQk=tW0Rd;eW&Jvhxc<WT zR0Nc?BWsp55TnXhYa(-gZi6hXvVx6J_D1nEa>LFg)-^-YvaXh;oR_X-2B_SlytkGs zau}m=jp%-IW~Ef_>ijz%bdGL(7Ol|(f;WY&(i7}@hIjhN!#<L^1X3_N6#lkzIyXK` z?8nI8=x(Z-Tm6t>mVV=`k+NKGQz4mCvYj*1GD>C1O#!b-dG)6xpSUb{@LI>%PGdhI zHg~LtQU2NzljzP8q3fk)3mcx%4YIrXL@W|bkVwhNDd*uDyf&n0m7FDPHz<~wzXfrk zyO@57?;?kg?`08rm-WE^p;%;o0=~`f4sKvtl5^9lpLG`X+N&)h98xobBV3ulSp@gj zq~!D#c52Pzm}+6RK3MmQFEvu5zl`(V+RpUC84v<Dc94L9#y!AouIs~;OUZzF`DI5? zb_XYP<fKTejB5g!Jbf3J%3XLV(E!U!!iF?%kLc#}aVLlI$A&8xl!c($lmvaqG<TXV zx?H|d1fBUv!P>{d$)^x;$=fg;FlB6XG;VA+XV}hP$O_g9BLoXjG&V>#c3}y4Xjzs) zY8%FQnb|PQi_N6^M4-15G)}c`kmpH9qaY7ldgY-|qz53a8eQm@7vpkux=@!FX2^;( zfmlQKGPPl}7ivzq9xQt0T7T-ft3!_$?^cOjxb8Wehe{7%p0a(2e&yya?GxH-tQU26 z`5!QRq%Hhq?p@_4x>vOxY*$zEIOUsx;$`kTizgT!vDiJFCvpz;ZBedY*zyYgQAbwv zY8AfgC452r3NJ<BzirQrJ*wV0@~W?gpqI-_R^5cbE{u7`OSDQ2(e8j6;rR)2)oytf z!sC|=n-0+KFuv1fM;US`^+sPLrpgPc`~-d7#>4DKY*~cEOB)1ugfzku@cVSPgq(33 zK(CS7Ci&hzTFhR#HoKJ-QvR-A|FQMGCBd98!F0H7w}n}^Ek0QATU_r)_%77}PWIwl zFd`4g{@6uNHPH*p{GDVxOgE>h$WwQGoz$aTYR1xx*bo*_hg|ul7+2j4uU9o&S=c|C zdvd<FRAfR0Zh#Ul`*RkW|Jx3f8`S%bpdz$9>CSHnAe*+Ue1a59^MW(X$<zr^h9<T0 za7hb4`RhUQ*0l~_BG;BpxJ8Sz=TDB@@tHo)-)!gh8(E3rJl4BltG3#2dA&E)<ke&i ztUBY5UEAPw+7AQcDL#%|BEhx&9)~f#_G*c3NaO6}FYi6KjVbdJX(rXj-|3aO0nIuY zm6G*%spHP1gsw6Xqa>#~I8&k7(Ber%w6h;XoQ`?cwou~C@Kar}99E@QmFyi_Gvb-0 z*4HY%m-!@j9?04Zbg_@*lH-kZ@x$0_nXH!(aDyJr8^hQ>R9EdeB3>;KGj8;V4B0$y zI~)-CS(O=OAB#k+@urVziD}uDO%&e)#x^6pAGUPjy^QPN@(DeAFJlgjXa<m=jOP0+ zTheV$9)}-rj|!e_xxKU~w>k3U*FYGd>HQu~<;k~98A5!fVB1^|cUVwPbwNa*h%}|q zmrmW#RJV3f6K+Dpe}Jp+_$<n^-zh`7vgM30UIbzCOHL>`fb+v>Utx42_=BzQ0Jh@h z26bEBftUNB^#k<oO?+R8E{R{sDfE1ji28wF!McO(2g6Z-J_FzR$)xxTZ_k`Rd8uB( zUG~8_aQKDLzhiZNqjNz1#3|oO?_XPc^$wi9%I65)XujI-e{$0x2z>g79|1XLB6uVz zIOfhb$ex~}3o{Vmv}<zQ2{EG7BMsehG2+;xVR~d^MDmm2yhJm$i^q(Gk7y+Ati4ub zM8ro{zP4~c?I1AU>h6(6^^WdD`+RDk?3$aL^%CHJrE-Avp*`GkJLV`1`|Ke=k5DL* zY#9Y|Na4^sRrU$cpgM~}u0&b31bC$@Rtu#>9z8k}iLSb;utj>kTO!pO_1s3X?Um=l z7D<DMgiPWgqG*ds=+JbItSt8`4wsO6r|*M`UNQh@-0cG~2UH@&5@o;JH0ZEoqqQTB zMyPWTg)<k3j6OkGYO#Up+bdonYkDWMm|~rZ;m-zD4^y@{LxoPT-GT7IQ{{ocn%Uy2 zL_-Z0CCWiKj~a)R<~*wp)FW&37H<aX$l}lk^PMBhGHld{8l<%+`UDWQ4njBr4^-|O zWqo7~+rUD~4@OgbOI~%X{1#5@4mC*P3p8fvf!8Y|xJoTyPk@AR>?MUS#$Hh4muV{- zd$jVG*;HcKCSc~0l!5#9hBKqkv<*ulei@jd<@DYo$GJ(a?&OPf!q`DtHZ7<=Vi2)y z3<)7F4F+-gn`p(_IpS~a_a_(>=@A;;03d!Ih^6K1@HQ+T_R-=euc!)9Z8X3otYdo+ z3cJOu2CrvmbVE`Ly<z#-C5wE@JLehHPW~a$$sWEm!f?ehbPE>N1sGZhja<(^CR4+} z)el@XfCJf{SLtN!5#-^1ozujq-oIKt&V2bDH^&L!?zp8ZE2tG#E%bX0zhg2oB3?%j zy9aL7LFaq#4*6iVX$xY~RLZ1%<oAz3f5j40XNwkGJ;S1Sy{1?kn^+nw&i}{QJ2r<J zeA~XUZQHh;tk||~+qP}nwr$(Cvy!an=6}wvy8GN0=kBVfx~f0GGv@4`WBl5Itt%Bf z*7)#Cq(O9XQvfVu?`#P4(MO8N%9T+Ez&|@u{@k(ZGduT;K-dE>l$yTZ+%rx|H*jKd zib41tbXr+AK>I|6LRmKmIeE>1vqw#_OY<GIT4fgizlR%g4D7@Pg5pk4`W;}l^i}ne zTkjo#PW~H2jUsQ*)pJkWr;Q?Spk`9d9)0Cbp*O*+DcDZbzOH-HNx(U-yOlV^;cCRC zSr5o`kf|Y2)CM763JPCUP}|`qP1)&Q50CNHs>-8{cWg!G0Xj@(^Y(Oyv-W7b&h9Mx zB=7fp#9hEJ#!A2Y6n&l14bRqcEN^`;u)@bt6!Lr}yHUq>N5-!qGbe~~m??qh%3<?j z_T0+e6<e2xy@(b!?lYRo10r{ws%$(zM`}+)69lymlTwe@9Z}y6PL@>KD?TTcU(rWk z<AcextTs^bjTBmGH>mzXn=W!!ak+((*#`{z%%}PV%X>FS^unty`U3Uhqh8?)k#c$V z{0VEhLZ7ejg(O?}iuH0=pZl-pa&5lU7Z~@lZ{PamT}0>)v5y`JGL<l);VRkygMzRv z(g6um<JdT|qLf*Q{OurCra^SAT(sweI+hP^Grnlv=Mw#C#Y|Eug!=3UyyAQpGRn!f za#6_!vV|S^PX&e(d6YyT&Cm@>(=~ueTe36j**Dw#ESa;OtD560<?3w?L-B^nR0Cm7 zJr$IbZuKtYQ5LClOot9waX>p&Z-^0xl2uH>$^GQpJw#C+{Fg1!2HcZApp6A3X3ymC zD%${tVHFBX4b1hXqo-;=N)6Ddf=@sz5}IX7y+~Dn;*E&sr9Nm6b&F^DV&=Ya4dSZB zOueoau)&Qnhp-l`nU$46mZ~A6@zxBt2PI3yhT=K3xm2``COq`aCdhXY_o*mLR<03~ z%`o72u_HXs0<>QVRK&TH=gZ(+V#a5KGbxY_Qv(BNsFjjI^=YUCB|Z$<R5I4x#*2Gd zhuPX94cQ%{(;P)34MBsC(vZ+Jqhi~G2#rn-{;XV#;m7`3vlMa`?R@R~L=2I24UaKy zt_h4%3)$ZAc6OE<JIAAr(5lygT6U7fteXSOp0s5Ao#M&(z@6@d+YAGj&HE`9Ny*W9 zZ+H6NN1}F|T1nnoO>)R#xerW#m>OtNb3qPS?vz{xlm)K_v;v=)fe1|$tY$p(Wj4X6 zR?Nc93;R-6Fzc1s;HYM&^9`W1r4K3_YVDdF=&hEgebF1CcHs}g>t(t?@RlfpHdoAN z3tTkd_wcuhgrDNfgx_?HSd>x4oG8lH@Z3o*yHJ)!lu*X_K{UB^VLL%BIJFEf2JMUf zFu@l6PI;=-_UV8;ExxD)XKD?;jV<pFWf`}0cht1|U~W>BbHzD&Iz{Km+}2Tqb|q%? zcps!mD2HEZiNtHZ5&rgkqEy1f&f*k5=vM0xjpN^~>EF9s4~95N-O9u@;i=z3`sVXq zIvR87*Zjo!lt<7U4un_V121fSHz2=-Z_s>0oUZ?YvE3@CpL(N|ZuNmY-S&kUY3&zM z(%LsbwS`_k`<JtMvo~>ihIL$)Va<SPtmWNNEOgM4c{m-wHd5wC0I`B~wkr!Ro^WOb zWQe(GBcP+xRU+js<ZL26Ba%O-Jzx0Vmj0U1^dG3r=1jhMTYT=W=|+pS1A5IDPY zj^e%O-4v3C9r3gV^&fKn{`S+qb7a>6W>t=PWRat{0dnvHbSXXesFQU8N{JG4nV-N6 z*|SS(qHB9uPI(&=ozK(XJ0hdb=KiV53D8)mukney&`Tpe#fz`Px$Xd_QQ!w0mh>oH z5(%&UP!9;o5n+_aedw}es)rtSM4Qqt$qL)!YH--^>?~Ho!%7kG74-I(VY}p+ZTp;H zaw(j0N*mB}2{)J-X1bmc(1!$b-KV}}fOsj^@G^}#L(wM~(J>^@+B<O#z{40Lk%yd6 z>3L<?3(yP--4M(pQqFVk0T|wxXyIxG5$-V<-Z>cFaH<Ku!<g9cPa=>zq8y(JA`Ql7 zsElME=ID6^%rjl@%$?XzoqkCtcMoTaQswo+mIctZ414UEcUjY~Gov5>J%0BeYy0dv zeoG4&0KhXW007nhuNzFs&c)Hl<iFgKY8Fl?Dk!`;n2STjgvJDf`81Lc8`+2v;ek@o z1OWztV912+EJ>z|#-^Uv7l7n+6p@i1wdN^$)l9XdQK&`XCMi&<_@98^AX7cfpQawW zSGlAU>GBn~AG<zhy<WGErFy+TuTS&`LniLT{<i?x0J(7c834Jk`yBwe@cW>skf@xf z;3_zZ4t0^;kqW4<743Q>z*Kn34(cPqRCuZng^_8>-8dq&M1spvYe?F7A_!I^&rl8Z zveMi^=EEt5&3xeqwV6{FV1ON((Y1(mF^4S@`?au!h_%R7Yf%@lhRZ5JVB6&d_*x@Z zXs{B)EX4>b@uQ}&Xtpcy1G2Det>)u}YD0)H7VaSIRvc8KaR+d)a{IEdV<5Mb&lc{W z+$`Nxf4yMYEjVIzpz{0I7B`FZ4Wz7|{e9)*NM4+Y7IT)HHe#UAWETH&wr0r6>!`_} z;V@%fFlWa&X8D4?(AET{(5$vdZ}qTRZbXFVE*uSslGv6gs&ZjVXhwk05-Cs<?#Q(j zCY?IE-1P#BZf~q}>6GXTgYJW7*4k#^iI%{y&IMAN<~I@9uc9ogF<qfU;#S8mB#yHE zCC8K~&eGy?rMp#UbJJp;uq=Jkq9UR`M*(3QNiyAZu2qunnZSPQsv#5>yeA_z!gknU z4CUDHw%Z=(Aj70AkIA$kPL;Z0zSjBIOVZ$i+K645Jb~I2s-d@<qxEuKPs}rZQ{A3> zy=J3C!PEDYan46=HWpJ~uUPN+w~}QJ$l;Zk;XJlAeK4sp45c(JCalg-7hRP{!goiO z!4D9MJdcqh8ykJA_yt90`oP^;IiPc|(Ma(~3Ip!ITgon44MyrhQC|2D{Fx`0Z9B6l zK{TW)r_(Fqzns<-Mr-oAd<6#RD3Gw8`XLrcjO|)iNpI<M6q#wqR`rf&`38LVZOQn; z)-b<Pqe}^=<$Ct5*8NTS!G-|Q=imd{Y6{xn>RxSc_pk#PtrI#lX_<z=sL4mGVW-xM zV`}X7jlAkfGhE^ksubm}P@AjxE#)aw>xICTV=xs4yT!Oldv=z_)+X{T7kTz1x?<1a z@hMjPCs~la9B?v1%koPJlf>F005gX+7+*L_AxfX&aLh3EI>nVQ+mGeq7-7;AM>daj zo5%XK<C7KDc|PENl8}40fxdZ+rb5W;ZB>D~3|QPIPv*oCX%>@2v@}5D-pHO#?^C1d z{0pJk4ynIC`hnKP;;U&B4en8mkMR*qn3Tjf=eA?-P1Y_@X6q<sa}Ax=T60H8yD*l3 zZ-jjpI1_c<$znVc@O&ozer*QSeV4$W%|F3ZvHo(i`M$4Z?dL3--en8ZWfGh*tOflb zsX4;)ayuB7K8he<!7wTlCGz8X!7Lr|Wbli{*6<a`>McDtJf|VvhAdz|0$ZFkwpjvW z7@c53D~|OB`Y<_V^WHeD1)PdY-cT}zr)f>1@NN0}`HTH-NK|%$HRt_8)qhZWlE2pB zlbB|_<YFHQZij-B#qQa53vh<Q-qIVPyf9wk)aPDXy2Ez--_K7~tfAeaA1+25uZK&L zs~o6(hR;pV?;_e3mTdXF>{-DULVDJxA5=|wBz@>_OH*Wv2{WFF1&0}0$jkyaAmHv( zQ&auWI7=s(gi~MdClarCjj#3@P7sgZqZ>0{k1!|C9sul2!yd>^w3u>vh&_`LaZjE& zj<_brbNeADmyF%gsyl?>+zurg0gP_xmvIp#6<#@Q@(eE|Iw+77X;bP@Vj%mk*2Or} zSlT>B)!at|S{<~x0;FW68-5C=`TFC*c|US;eX`YVsU}g&<_Bq0{X#|-{yvo(sWpp+ z)cWAu0N<3@V2cC4VX?l2>U`7Q4V~4)>`Ac0-m2<Gvub-KqwbT(ab7>**v4bzCuGGL zwRr2fqPgS|YKPP@xJd#;61mkTHpih_;FH_nn{*+)<o&sch11j8qpZHb5X%bJhgkuR z3>W4OBJIjpiz<Q<JYa+UWY3>>G*ATbJ-tTf>uU`0D>`*E^d-E6ry0p>$M7>C{WjhD zB95qb-a(sMzYHmFGzi;JRVjX_YE^>D{L*#B7H7h+c@0T+s6I#L)R{omsdNeFN9)Hd z{R=%kr17oBsE|4j*1DWu?T5Ryn%}mQ4Qjz0my#0)x_CyLJ7=V8soD@cCE^-59edT@ zGvq?!i-IB{&^)5JS{I*aY76?8;ht`%M~wU~X&Zbv8u5it?of;;!Y-}E5LIqLSE5#7 z@t8ES3o=tBv2-*AXa?)@km<b3q02n*2jKrq3zT#NbY}i01>$~-AJhN6`28=ioS>_L zwVmy6_S?+F@qZV=5>+YZEoFqB$ue2(GTFt`Gl8mm3F|YXeEeTi0x7<EmYjr;5L8LZ ziJ4Xn&B?gqP-nG)-fF$k!XtG7j=BR!7^qgO^+sb^7^Z}S^#l=|JL6r?!gNl@>x9wI zzvB=5g-8i=+;*&i7l_@c{VxdHKlvi@F^f$}3eEe=3eCc%%!?5axd%H<*11McJXs2C zMhc#p$2yTRnKK+&kZeiTrR&BRCm|G@_eA)5hE80eQ5;jIT%pvp84(7EcBA#fW2Ahw z_qHK!YxkBgc1O}MRo7Z3dswq0^|PiyGh|t`Z0r~%{%J-Oj`oPmNMuPBf0n3>lWqRc zMn*fTEyxfjwIwI6GuCip?$DqFr)W5*T0quJEQcD^Nnyy)?Un{d*J6ZBOa5(@zqwG3 zv6^XRDH4$Ii2;Hn+v(Rk(xBHojZIt$LH1_E4Cd3m^NB(Dv~mBQXDdw%E1!VGWv;Bn z%=8f)Ou)2Ta+;WMDk^PH4sO+8CMOw2XBDPVlhiP%aZ-Tn5lpzu`QT!|&J2=KSzt$z z`i0JM`%>JLS{A7^DKo`1B8#LjYg%Z{Eh`oVpJ!?`C^zIg)cnmJSA}v8<4jPa>ZI+u zcT}L9YNa#_(cVR?OkER^U43lSS)Oc^M76Fe+$<$sYEVS$K!nu63)BjW4>8H;K1J19 zsHkq5?V2?LHJC$V<!wXXk%;Z_$ud2biCma;+TQLSXgtOVOVYhkw-<QD8GFTXG0@R` zXChoJt<j34vIJ&Bohr|jyVYBD{Igb<k!b*J^)0Moy_IPpe*SmQD`%?5#k0aWPQI9A z(xgPdu?^EX21!vykAd}xeocxIi44x^XW3k1-RVV*RN=?QyTw_HjaryiN%l|m@x=g~ zL=a+TcnyIpi)|6l%P(N9<IfcUmp!1_#RVx>iTR0K*E6aiyv0%=`}kuv*zA%tZy4wp zG*q$0Wl09eTyMiOv2$^WUHltTgWmiL2CY`lBC+##GTGQ0ou{S%{A&R6GO~S&f7yaW z&WHsPya8s>@sZFM9Sz8?<3Fq+nP~+Dy6;Ri?+`-{DqY%KygKSdsr&pKEn~DX^FDaI zy1+4935-uD-G_cP-g}XMTF<wIa)Un3PrjerFn2_oKz)+jBKx+mzJ-x_{ou+wBm8#< zdjuz%7Pz$ocN;@_>mv)R0)RRGw;Z6x>@Ax5>(u>SIH#1FM7+Y~&mZN^pcURi%6xqO zlZqHAzWgahf>ij3^F5^%G+_#u_X-i<72dMSeBAz%ju<I`{3*8tDRPkKzDvsIeIaU8 zN6Dpj+W)Lb@RSAPIA&qN8BW36{gE2r7Yydhh92_a_~YT?;O7lkrNadK;K&2Hcu4ZW zWv&GLD!UcUcyJ3>=m*jH7=3FIi8WD;cwq|o!|%0(gWU!Zzycxq*hSW1gfU=<J{J%U zc7)IG&4hz%7=jB32K8VOxC&IsFE1{+H}=)`(PkF1T<%Ifgoy}$_R30^C45|Q?sZRp z=9ayM1pL^)bkT;&VcyGmP>YF_<|}~9QU0^7;K9u&dLbmtG0&VdA^&*s`)^A3AB3iu zh~}gy1ONcRFZ7iAf1q@d##W5X(k?cJCXSW{Mppk_@^aLy+)>O>ea)ISCS=L9g^<*3 zOVABAwl{$Qm5NI&0;PllNst8pkY!0=G^W*aXMtGKKi`(H*EN@DE=#VcPT2$%gSM<w zy=;2ESMk3r_<cVs?EN15Xbe*Q{bs$LdhK?fe9yY~-d*Xx&bB?03lRNQ?YTvR+F^|h zN2%@QbHj$W$xoZGX1=iS`h%$O7V{74-SJWvhz;>jpVDdEwMUS#PK}hOlc@O03c!k} z`05Ja^bpR_N1l>H%O0X5&8Y9QLrLEf)9In(>dfD$dP@(kI1~fUPTm94(MNDlpAsYO zKpteeY3Rp-$J&lxwvfKKnLPhYyN%$WKh{;g<wo9By#++Bp@1A#6c94k=sTSG8ZDd8 zZmM=`c&j>=cPwRe2?y|7kVu2B+-9~9bl`E%kY;CPNti4#HqqJ|GwIAWdeoX_S=>p% zw%39(X6$C;*yrF@SUU;?G-?H~#mkVuxn>rbY734>1xqu^>KCOnU&}yQ4yi4w_au>Q zDFVZ=wk=6!>THPgW!$p<JA%7Wo({ibSxoId%klNfOHrurWlq7fWD|{E=WF6jl_XJ| zkS1(S!H8hD!^P;ektqvm+Y5(9cT^lzf!Z7-{dJc$jxTl5=U^d|!MzA<Mwcv3k2Bp- zUE7ypHuKz)RnjCF*ynN1I=dHArSlta+N7D}<b{xG&gW{D3e0gV|65F@r7CwCs8-Hx zydu{;fzZ3DFlh-f*(%#<oRr08T>4TzEDoJ1b`kGYS8Qf<>vgkKd`2~!Y43`*DYm&J zlB_JH7`DrbK#UCjsBg=%kYZElKKT2P&S|JsQG9ILe?12`GcV@$<I8NyEuo5RN@fHz zGw<LV5EwpYMhcC_QU=6an;~1)KJq9y#HOA_fV`K%uOc;6Rp(h-eXK7zfJ5yRXKyDb z3D73nh3nQOfWGbQEFK+LG&v~}A>W;^M)kYQiIYR$oyZ1YxJT=PqGB68d{!)aW(#i_ zL{Oo5MfOU#79PnuU#W+o;a)WaSj>=xB~>&O$HE&0#i}y8=@-QkUMoFx#^N7}RsX0s z)5hDKpCfG}w@ZylFqYYCih<A8d$=nLioqd6S#}?Dy^NeZCR3QXd}5qAOCQRh+FfwO zL0fZ?rbv)lK5oc4f1;o}f5O;RwU-~AwdWt=;@%yiSEm@%#UIeSXb*aE`JTl3`e5D# z%Bp;dj@dOxjNRRPZS0}p-c4O0@XbGfV}2=2=M8&<&`fv!R0%df&nY(ro~Q*}Cfl;* z$mX&V+u}NA4HqgRm0DLv!|b?7NwEtrI4!+AOLCg5U@qNecy!TFa759k6ZFJ#lwbZi zNIY{5ArBD>N+Ep$t8wSayl%*t(tT~F$>thSW7z;b5F(#u7Ys<hVwo}w{$nr~d(n*4 z8r9Vl6f{fftwF$!e2ZhW;xTuRvQ<%$s&xd|FQ?|Aov}*^Pd4MQ#R)K+(<x}2H_{%f zRQrud#|G@1_=CuRoSUTT*pG9EN8=FEbn!8y-~qzC@h$yb)M?Lh*-<9hfn2y0zFUQs zDvx92BGR=fVYwV`CKI53;bP}*0Oq;r)_P~2hxTl;)o$4r=j!5&EFkpy%;dgzimS6w zOWU5%H*FgRZ&i;5$U}95>aWK|lgDRKGuy=aV;pqiRN)N4hc0B0)*0o>ya(sBJ7#8N z3?wPS37nVSDBkh|Gl`2Go}3eaRe^3t5(Y)bdC<Qr(}g6sX#=x6xZpW$Fph<!KE2PL zkKLxvja3h9qpflVHppuZo}GYj3Xg1I?ZIV-Sdl$Pi&ViEw*R!w0%@b>GXz4V^_8$B zuSbvpc~0m-Iae@=3F4T(^adA5=w}4ybaE8WALg+nLj0Kkdo4ujnlw({0F!5k_d5TB zdFnu4fiW!?tt=gOt+`k}RP#nrSS%t0x~Wy4;-Q?q(6jA7hv~uuX@c{l>)2M<J#k0H z>E?j+<R)`(2GZ7)Z->O{U9rO!(W$e&G+672q`Mq1Oc6Fx^DRNMf%>RMpVQyC`iRih z);-ry6Cm&3)kzqJ%DH{+m9gczGxqb*c9?-4MfQycrMxGir*9X91vL$QX742RheEz; zRrT0j%8CIcdo6h=OtV>>LS40Lft(Z`)Qa_I7e}@6aqQqOS{~>U(yZ@HJy+%3`?es~ zAA~Ai1XZzo1S0haz*aO9bWR>fqtZJ09cM^3nt3R!{gMx7_)Ga3*c}S~5CU(Ik?P)s zNBVj!{2PLPW9)$~*WS_|g6ly}QD_UJ53O$BC^<3CA+`{_XW9+;2ht~-^`3dxVD!Rh zg-ibk`FUc(++f5_*rZu>)th}GcAreu7kI=IhR{2cFNSg8-;KjxcSb$4kk0iibQA7} zl1Y_>B#5=V5la)G1Pcp`+2baX5AB56DyYDU!sdUFr11?r#_WVsk%ZVh1aU}@q~MMr zU2jn0n6M1oe6ccey)Pwic;s(YP4}$4@2hEtUXk%-bs2a2FAuzO_s~uExZQlcX%O$b ztWPKO%RKJO9%kewM-M$woQQl=vxS10<h*t$gVPTBdu0Ip0<3<O5)?aM%>>L-%&;*f zi}&b2pDw8^>bVx?G%2Be2#<Md*`Z$;vq5#g<8Q@HT9awpFHJzMed(_%^Qn{&+A%4? zWiNrxEo34GT!hFyWFify!UbTV*I@CKK=Vic@`qpyO3;OCz=mbyL;teCOi2oH4Nx7( zxx#$lTqsMb0s<3Q!ZqEdz{OneEUAYbk$Y~lgRH;DTiTI#szSS7G2Ybf87Fnl--Qa< zDpV`JP;I&Pi~O`JY?@n;DPQ>i??LQ8?a7bVDQMI$7y<W})6MulY)@GJds9-ADx-|8 zf-?3)ua{H|oLslqOqss|1&H-gf)wvNFJK`opD(|;=_*cUFi9f(1ZdN8IT&*5av+JG zdo)N_U1JfKyX53-F!zA7)8TxvSR%!{%MA&*i3x;<-tlz0^XmJ0wDUp6|MRqC#IX?e z`n4Y8fWL`g#&|&f5Q=YSs5qF6j~CsP{`asOpZV8D8L;9+L-)@fGVRM9TFre=#kXe^ zDn#sw28kvyT9vezq?nXOd>-U;!jQ~~x|FV}Q-Hu#M?-aRB(OBhg*a!m@uI#03*r7g zI1_o@sAYV4fl5tvq8v!(gtb$svqC5~mBB!M$})s7V71n4Wrw-hV_kglG&DU`<!EHO zJ2Ol5)CJj$1jR>m!s1gm!x<H=xm!SQdc0(4GBHtIeh88{iLvp$Qcu%V0zOZM4v$Oo zWnO|S;DByRKJUe5XZl%aR^8yEbO`TJ@+|v$t6oBaM)oW@7;9xEI+Hej!IODvAq&!_ zA|F#jGJsU6zf7sPJDA9-PdVsPHo56$qC5nYSOVGe9VaJ)XXISoZc$k=hrTp#@_qQz zg;jw;IG)LpudX<ct7#G_Abx~x%lU1&1z^XL&P?8Po3bQ7UaGfQGhBs=Vtu8@0@h+9 zS&(z-v25ejJQY^ndA9a8>eM-TVZ|a7!vK3Ff{T`4H24L2GD53OUv<Ky>h2b(YT_Ph z2Fe{A*|S7(f@I_*k14Vvn5)oX<3?Le7Mv3bbMBxz+Q&R?AwU+h&PaUF1v4tYJ&QJx zlo+^?7_})%!-$l6Aig0Oo5_*pk)obLQa!aHFh4kp$@ZW%n$CI39b1s?AvT(u$1`oj zi{>v8#e7qYX})?cpB7c83;^S8HkwnMX>ggcrI=2a&h6;0A5!vS>5+$~4tkRvFV7Y? zWkRz8+S%1*?J}?@s~prA2<}Rf51(DD#H8h!O;^U+b=$h|kqO<Sm4x9P-wtvMv$pj4 z2e##Aj18L`Wp7-ar}N-*iiT>^<PUu%GGzd;DtqWj4<Bkyge=l+{z^};MOoa47#T$W zuCz?j!$wllL&F<|i!!zkJT8PjyboTG_7(u&K3P#&)JJq~7lHZ76Upn6R^lr6IVKEm zFhqpif&Kx^OFcx&eqn}JvD-dqqSv_-)HAXb3SV>)9<cc+fd<xK6xo*X0e~*hG~!mV zR7zL9wL&xUkX$Fq5^=46RT;=@S^5WFZbw)=(XD?Mh~4ngag_M;6BrMF0q?%Y^*4|W zVBClOF#3JUew_H{I^x4$UO{3(AjSSIt-w!GEY-b#lI2=Yyh6J`OU7S3SPW7bodUZ$ zBzbfRZD|g{-;mEoP_p|}f6Df8P8r4C6&mzMQ;F(6A`pe(M`VAv=cW7vw}&wX1cM{G z@XPL*MyL_(Ai~U#Szl{Ri9?2x5e;Hv<5zzdq!Ed(x{R}9qA$j7Ma~?Go~O#rdG_)< zk6^F|1nxDV$E->0eQtZ&FBg>{7kAV;#K?p%)MF6BoU4Q$v~liz?!<(glaV<B4-~>V zTo%0g=eC8}J$T4(1z10DnlGE?r&l8(-$oNZ@V2u%GmxL|(7vFpr&nsB-JQn1XN&6o zv1zw_+Gl`R@^bivrFRIK?N*j2mlf%rh#t9;Hvk!mjMC%B)kw;Kqf`s?R;eL)khca= ztXQqmf(<&@K7_|L+Oh)>S=Ie9DvR|2HHZ{O9Rjy1^SFwCHag?nm4tbX!YrBuzHK5f zcHj?Tq=(J8g&RN*Wu!!wVdf12pC%C)4Zltzg6~$5XiZi5C>c;ldgFsC1;L_J)MY~@ z!NQRE8m-!V=G5=j&G#+A`&q2-+=l12mDxQ!p})2Zdh{(H8&KUt%K%6!A3oQeW~F{N z?t>(A8Ks6lK>w$*>ua}BWd6>Vk`e!B%Kj_rERz3S*;CZC<Wa;>c!}dQRu$}h00P6o zU}-w3MPy(yK@8Lsv{B@T)5q#zruLbFnt&rcGKSM%g`e2yjrgi19}6(ls8#<wB`KFo zyFKQ4lmAGlP`%DZPXRPROL}yD{Jn9K+vAgg@B4iHf*&99^gbDihZpmC>kotXc@rP5 zBGN^E=nQ8U>83oSMYM}@7aPVz#E;@2KSV~%i+r1ghlKTgTR0!{W<fJxyftb{m?<Sn z)@OdbHGA^U3)NbGCCDOU)A~Yan28H<5BGw18YlJznZF(bvNqF;!jD=HH$Tx0mPww0 zW8=mwiJ75e>mtPwjh2ZE9xIS=51dJ|HYOo?c9_#o5^4iM{z4Mnh;HB<=q;<48(dna zKft^;a1t17GEck5$vSIL8-zZOzbAr|;F#%Y;-EOtfsu00bMl6i=}+A3{7dK|4M%Q5 zi+IZft0Kh$Sx(SqOEUNvj)Si}D8bv{K(Sp*jua`_<k8{+PU960sC}iC=t#9PeA{B{ zCbk!k#GZ9&+6hAQ0!8wiAGUXLfyeS}<fy0E5V*EHyDhQ<qYJb;hh#<pEFp;!TPfMd zZ{_`Wkme<l+?N;cJA=UsR)t;Jsr!P?RaYY`1@5=~mo{6x=X`G+O{y%-gomWqzI1-n zdiMPzAZTU$@r}DI%EisiRT0DH#@@E%?5rmho!P41EG*#ARY}>faKJZmZmJ4|=7Hk- z;;bjlUi7bg6`vDNO;lQCje=soB+fsLC(Uy;DCng<n}-0KiW`ToL^&>|s}fr%W+l^B zbxDZTVlG*o*|kF`TAcj0R!tipZ?y$wjaD#X=<;5i=~`15bIPf_fJp2H^sVbzfw)#g z#Z+;bwKgLtvSPGib|+_s7Lm$c&WU`bgJJfi5^-MN4WemuwA$fqh2zsQT`wjIf5K=K zD@shJi>Z_Zw0fG!CyXrNLhYX@@-kIu0kZypzx8CZBF=nFI*;`76H=r^3CUI^LUzHk zR$JI#ky>t^&*i<MVnxS5)o_;jwbQCif7z%NWhbf<G8Vqn@&b5h_3~0pPN(5V#LVK- zY~N&$dGBCMlhX-A6HCl7Al4Pp^ILyg;aKWhf4q%(rX$kSQf1!ll6c?5OGqt}k)>qn zd`~u7XmuXU!$(zF&#mTUN~=<;C+Xo@o0Vf{>9%;S6hQ0^IEoBk{!)@jZIDFoR6Pr4 zP3QjNiee|a!}}cJiM49v3Ub<DYuaEOkC5L_UAKVpQS&siH5u74ScT8XP*G8Z(^j3k zsj4rE+Po~&b3)TtN#Y!=glfi-vqx1138lRD{WM=vOh>=bSiDd5%9`#6V*;$|95;;t zeuSb}%#X8g3xK!dxnGexZcp9v>vLN1>WCc&NEE<|h0TQJ5-VllO<~yl6C=iUDGmOI zn>C;^PhR9NQL(_TOZ9nAU?t0KPv8l1d24B<M`eF*Wp2OZR7YaYd#jTPmdjcFKG<gu z-~m?Z?lTP3wA2wEVa!Tf{TmdUc5t5=P|0$aboO7PY(B0?b3X^emQ>GvQ{{Z%u7)^M z_{AUHNKSEuu=Ap01|L5bffgztO+SvNCI}A@%c!8WdJ+olKjAWOji{6RfX7KONjpLo zt&3x7+dzreCT~Cz;EiJe*JUZ$rH)j_^|>+(F<6h%hxBDZz@gf2V&_lv5?Ppyk2FmU z**x1v#HiKLJxwOkMXM7$#77EhqCt(t6h{j*m>Sa0;!kP>GY+E|kby-&16S%U6<=Vd zuZoQ=YxUQqDrrFf9ys5jXyt;Sxdp@_twQ^VQlig6aD>a6%5sAH8%VVqAXC*Wcqa_L zj`==UKiQqZ^t$S$n7XCz@xZDjafQ=@HYLhEmgLtw@=GCKDnm4F#^wZ0cF!=HkDYkH zubAXk{gA))n(Fy-gIqGmulyii@;ICD<_0>qqgv#{4GZ+qR*yK<(|%nsK*62nv(*=K zFyMVN9i1fucL@J5p@Wt~>x^Kh@_5piEYO&$>v0O@1N`d;U3{dN*Itcd4VB&T4&s!r zwVF_l{%cnk?CCW-lFwg*^C?P=|Al7u$r89{YF~3jUhQzRnYQs#G5t?Qmho)sb8@jf z53XSsl#w6!L6I%o5k6cd7on`_#&GBPWsAq{!I2FLn}_21zW82}EnE^lJe_>_9S3T2 zzaqcMdDYBRVgA2%Ppd^NYM?sf1D%UWFL%K|TQt@5$ND-K6aVCdzKmw8U94Ub{=Y^F zd(y+EOhN#FE^z>W|2%c{e|g>Lf6bD9YutbFJ|%wNEc)Nmq#A8VZ{?L0{<Gd!Ci)=+ zef2OGe{msI4HO6~RR|J5B!b{S>C(E10Ta^M8TAz-P+ur*oduvRtDVLFItV25M_O9i zm2FxqUz%=LODy|3m2V8+XFKj@j%AntKYhO*vbwUpZacO*&OYa6VB~&2(BXrC-VeQT z$uH7Nj9O!pT&5Qo)y8;mpMLSI4f114F4=`g%D81096Dpn&OAzEm|U~V4ymz!xMo)! znqmcUx16IdF_s#H$7s21R~)ip&(7U*WA~OE%3}A{9)NJ&uHJxgf279p&fS}0e}Oux zxPGNaxLmsxM}AlCaj~x#?($<FF5UuT!d$Kw?&@R2T;JMbdgt!SW8f~{;$vdY-pXTR z&YvZ*eTxqcxPCQ9zo?$o2X-#LqN64*zOo}bmro&dWS0hM^eGpGswgg<>iH2#o$AFu zJ#?y9g@Wi-&JC)+{G4Eyh1w`59HJ#cS*LIbxP%jg4LHUPLPs2;HNr<6qCG+=oWglR zS+{UXIK~yiQqE!LFpeR@RnB40FpeogHjV;RU3;PQBv;wOY?gt$j)27QjP7(eM)wE} z-P1*U4v&x|wTwGI4v&~5ex@52a%+F~Y-P`+Dm#ZqHu5|BM>_Jmhj>53)Yp!GfN6Zj z5BQt~px@IgaXIyfd<Vx$rr*#@-)TvGj*l70FmKsfefyk#6D%2@F&27^H&(Ti$JnJ` zJCIrX_}X9OY2PEwcAW2R$lmtbkbodmgpNen2qGcr3MV30;DpjfXy9rtvWuJ!i`NZ# z$eZ(jgbn>lCrE-$qk+vCIpQ_I91c&78QS0u7Ug9_9oi10u@8c0&JO}anQTy?F=l{9 z?Ja21Mi<};(o|!QESfki1|Vrnh<<<5tp^tL(1z%wCJqaSgPr!NkiH=<^j?4XuKU;Q z?(qq!_Vgr8+11W_lkSC(pP&;uZ)CNud)n^p5Id(wIPyEkM?Suj!8r9#^7Zq<zC&Gf z-_R?aH}-1h1GV<S5WOQHbl)MM-T^Z7Z``zwd;InNLB9hYbl)gn^l$95&U+5ExFe)A z0PQ2BaKJPK5oD+dWGdD6V9~<hSXR1(SyFN=x`j9?y3?z<9VYu6DVTj@0<^ASg6(}I z+iKT{fo3>Hl(f!adu!JSL>9Ay17nmL#pnSQI>uBDvivzxQ~e65=|N69#ynLLwEZ~k zLX1572&7FBh1d_B!oVu%4$YCLszDh#g_tKDLrOX~Nd8*q2r_Gz2vf~E^N~Mv4s26f zlS@0J6L6cq?4JxbL*79EJB|E_F5c|}8)k1pJG4O%JEiq-PvL{~wuyUiAH*SS+c?lc zLcMr*!<qv!dZElVP9)o+K?=Jn`b!&@=y-NZ5Lmxy^GCKY;@#MC1%HNJY^#!6!Xa#! zkIeQ6uY`GXWh5dJKnrQwsjNIX6Vj<JG(zU7tJe^BpcpX7D+pE(3B&$uWXQj)U>feK zs;|<(HaCJrGY})k{wfD(b_6KQL^FK+PH?l5toQ9SsTW&^&>$LxZ4Jb$M#0RaVp;@P zu)&(<?3*$2Nr;c&=JPc*&4yMAT0p&ch2*9qWm~kp>}%V<!8=mrx6cN9V=q$LnQQYq z-Q@E<#6(;p15HN)w0lrsZWucP(Xs{aL=CQ{a17XVE8O&x9Z7Nv+cx^qOomBWs9?`$ zG>v7c8LHo|?a`a7`+6d!d2J)9ifzFYDyUap%7D@>BWC|XrY144+(uk+YjISj_)pKc zO9Mm>U_uyq!mmAIP|M?MnTfB0)R3i#3oSKNctO25sBMuiE>@jDT^;YzoSBGE^>)MY zyUMsz6t0(TgejCP2{{QXRYx<^u~oQ<T8Yk9nQ7;k{=(cgl{+zM$LhMb%}$f*)V{c6 ze(m<D4J+i^UJLt1(12lkQ78x{(Nv*sTepWMpeJOZl!iyeHfsCTI?VKS7fv-xqT;;5 z_0~8#qGpbpbaXhkEPK6@@4T3hS!rI*0kTQaS;s5Vr>W7aZe>;-2@ZTB9{J3I{2==3 zxj5;*WcM8<y27njZghB7?mUavco<4;RTXjRIa!)q<*A^ebD;vQEI&_sq^kyYO56pd z!sVPK`@y5;!eQaxv9=QwHGZnlA{L&ZZDpuZ&lrijVB~j?jR}>KHthm%MEagqa0zT# zvs`l#apMOMn%v*a$=w_(YLA<xMmd|(30Y$54`n+u-+(rzQP~cKf6|W=y~Yeec%1uo zE!%tp<v<ro69J9<YiDmk*F$FtLpW6orR|lL7GI%}m52Wx8(~YNtW=ZhbQ=sbZWc{W zTBxxghDln|R8~{ybX0V==E=tjCm%NtHy8i7#wv_7q%VkK#0kU(BQB)Vi-;4MGC+;X z*_!;!Ay6jb+pvEIoB{|!FY-VaAoMjEUo4`kNJULeS|RqT32nP>&tnmUVL!Cl=ItOK zGA!2%rWn^FS-p%L>Qfqm_`on*FhwVS;wC@<^ZTW<d1y`V#>7jAT2vkEO*@$>OD;Jj zkCIoWhGxM8e?Qh+3{-g!z*WXk!McHDNh@1yLGp>}>SQe7F@Ev@BF(O6U}gb3Z!U8+ z&>*~owP92{J`}|fD?u`oXi`zdiI_7LLq%^9ZPnz!x(#na2C{*A(-zpXpxq;Lkn$3t z;Oq%=20YsM3LiQsVvB_=GZUR<l0xT;#i+mDn!2HrGe;BKlEiVBE7rz3FXA)0^RhGn zMrE<dWvH$!teT6kz5nKIGnh@db}B1NpwU%VX}0Axda5ml4jW08O6~NK@EskoRZ8h) zn`2~bwKQ}Tb-UWzoh1SdjFE(K%T6Lh(NV1<x#o3u>YFR0O|?-WFj*Z3sn<c~I~CWf z4}1<2AbGVc2N^q3B5X{7^^GLwsW0?!?8J^EkjmCZHIP$*rlL)i@<$G3O*lr^X;THM zaKmld=K6QG3KI}{05dOuiQ~8{8m8n16fifD{z`r697Hu^Fn&yn=8n&sJv$!_eTeJ{ z+t5aNFRZ4s8nwmrPS%rM)E2&jsJ#;bo;Jeu^6RndCDr9v(^7l%QFUo7mb3XVj*w57 zmid=7nP$u`VejCPT8-g$lfO2Y<pzhiwsOud8q_ZQ-fiWT6Kh2e9&0G3{b4<p{`3t} zJ%R=s(vkr-mucfgvSlY~xY?yi)Y6}%tv^OncZ3!v3E9~F2`<;yURFm!y@41Xk~FwQ zAR3+@(t0+{x+x)?;A@*;*kUT!s>o}OHa^;rXMHC!Ugz4}8cImNa5@ekm5P)EuA<j6 z+(d4S*RH0jBka<(LSRZIvRK)jDY##aPc{@8Pvp89#6|2=K-8C!tlPpXG?)NEj@C7} z@Ah8&838xZL$V_ELviB@j+G0k^Tz<MF=s6vYp%E)M1`amSerVPJ824`7ftJG2-<m& zh<)WJrlcTM$&+7nQ|bOG=5g``?mCf>9_;lonMuqnd2wDRR?7t_h^~G8BedKi?x|`k znUBPm|B5t&r28C-`nW-HY_f-0f_(|go|Vn}5E)|Xscm9Ma2nGp8NFbhzIkKC{1!5G zX2VqI8^ppZk~wI3Xk`ZvCOu`f17=14c!Xst!6dX08}3jDxkO5Wf=E_<90%IAM4GXV zaC_hSuN7mrwf<UC>M)I~(^CO2PIW{)K>jJX<%G3r)k`LLp$99At%eld)a=qDb2-<h zHHlN4a=_d8@WasTWeb+#2JV37%7?N4k#bqO{x43WmVRI`!-#R5m%1fWYy1U421r1r z_20c!^0n)v>YfSYCK+)(Ee)jxXI{G;?iJ|8eUt(bc+0^)c<roeF6eQo+8X-W8p8JG z-K^uC*{jk#0dS1U)(;{^J}vw-^P6|yzycYva#P?<Eb~`e*kR4SAjv1-eNW9UFP}L# zElUY4yPV3UwPj`7Ov}d^J|L=ZbzBXb#x~oFP^v&a$3G>f%fC?7a0m4s-i&SvUmFXI zPAX?7_w;tz1eLXmz_d(6Rncy9A%3CQnBMXP5eL@HIC512f8(zZKPYmg3G(^HOduJ@ zUJFM(CdzR(Xm8hy-|uvT&^Qy;c$i6sIMqUDTl(tIbP+AlHU}!JWeH+QZgOUpf%)Cu zyzWb4s&&P3{61bd5rw#u2xre!mv%|0QK#rJ7MF?L8!>ea7USZYMn`H>q775=UV6M; zi+sPHh&9zVRdPbGN@hlo2=*GzD-|&s#=5AUC>BIq+5}#Gfj<CA9eI40-DRBoJ{b&m zqXgUZ$1t`trit5IFmnMTc57W}c?1_Uhz%2TJcV1_X(mx9Ef*zt@vz-<VRWNvT8wB% zg!-aFeJI2HQWc4W1hgczJ#aMYL033K->mJKX{gu@KVW423gsUnFW&J&>O|%XoZu0x z?E%38{ZU$}B~VZ=+94J}#a|f=V})yCxP<1K<L^W;XCzKSN*z@Wg#4J|M#`9qDeqFO z`_EL3(ADY{ECtA+X@#p|+S}5H-M<h5<`2hhnSrA8+zBFWn2~@rz2>Z(JX0tOqWb>J z^z$O9j*vK>>UThp#+WH?F6IQo2redG9LnhC&>%h!S3~ryys<6-OOu_z9$e=FhXjj9 ze?oHrw<3x`DP}jNafE>sw9Xvg!SOan5(3QQ-nu!y-H3Gqtg~~a69wa9Sd<ehfnu6* zw{EJf2cg!3QHN#L^L67Un``mlVn9k^swq9WG}L9r|0M@nMl#CcC~76Oc_{;ZkVBLu zaSf|+)3{LNOjExk*vdw(XGTvz5?eLC>=D+MuJ_iJbM>C^3ZK6<Cjy_pecBu_V>Zoz z>42mtatV-*b7i2h2+=mE);891Q_`{xA#*+7M!K8_dC5;l&Bv9O7{6#0H#vePRf~(( zhe2ZIN|!@7%U_FNq|)KFI9K&eWH4w;NV3iE8g8Hyjj&JVP;3=D<!SDzegJ%JNoS$* zJC@K&dgW{G(i>y_^(8d2YGW+fY*h!E(NCvySFhA1jp6<~+<-7JkIalx94Ndb+Y>hf z<r}8UhV8K#;YA7%@e1M%h>Vfzz?6!IRwD^^?5rhQviGcXn(E3ht78wfEdgQqIKj0n zp+`9PS0oHSnmK!aCR~5_=S*ROry1E<3P*Fm&C4?p8BV^6em#v)u1I`vZB(|F_h2UF zFP!4$H)2tUdZiB|Rt%xONbf-XKm>+OagnjkbReuMqLSDASlcvegLj`tTZLS6&_Ll3 zO?<zDLeRY#GG|jS*;yo+L2JifOT-cC0fK|k`m~>7hAuJnGiXQUcHVCeQoZpHa^4zb z@tdcL92)WDZj6lHVP=tSGf|}>nc|X)Pi>K|L5;+kC8LA(Iz>uy_F`v|b7vfs^*Ra@ zk{Tro;psc_!p0G?iq;X3=+5a0R-`r!>(B>;APRu!&;)nHThL)#Wn_7|7igOo73Dpn zs=DHTBdwmmD|d}6YVu#U+kZ^pbq$N?Ll)dCYI;LAw`^Wal=-(*^<-bdYjmX?_r}WF zr}YdDv-|%3>6p~RILhu*B;7j8a{m5Ko{oBe%t$-(%}^Wf+^;K`_<U9UE}VAx9>t9D z0uWf;m8k5=Quf+X#g=<PNLBFRUJ1;Xv@G@dgO1aKKkLK;LJJ$&)mtm*Qdem;zfFCG zwYUxI@;X%VI<Y`s)C}-Xp%cfs9h+$%4@3N2za2ePkq-#2Uwm?`--jXgF+x6+eWC{t zi#Z$PomL#U*jsGYU_G@6FL3V^C&YfpVBHbIcV34lIVfzu0Oy5peLWv1I4V|<t0ZUN zaSbN`8v8aZ>Jn~XX!_Ya@WODynUQ%VLmC}<$%thhSZsfsPkhcn?lMrUb4^Kz8bDpj z%K>Ha00Sn#%;L6An5-MRY`{xi+5^)YCgmQJCUmYK;}M`bh)rE?(*w;qjMXuQ&goAf zF!xDsUqqD!h^`GRg(LVjr`Ucbu!>kg1z{VsEkDc_eu59nzcurj(QS06wa|<n@kQN@ zK|SPdB8Sw#J~i{$d><L4f5;ay9m5OFK{c?q31J4{F-==Jq7vvlQdOlgOjya?okXZn zEHsisMBp~lagokVW7Y0)zRB*-#P&1`N>IJA9gg5=Ff`YJWpVv?;XAy8#*~hp&qfUW zMPAuD_j`XXau_l*cxR1UiS5-CI?2Bv)2(AU==cg}iMcwONf=GZr7s6gOlzO%)=jjK z(MrxLc{X}@F3~a}B06$HX)n$G=HlJu7-*$z4WVkDIYA0`ICIe$Y9>q_T?!BT>-KOR zc*uFq0^i%CZ!0ICN<5Y8+;hksGIDs~!#ozFbMnlJ9b6ODAagmH`z^u`_2k%N+6A$O zH;oZ|dCe?k@EnFBJL9=G&LX!z5&ya1>^L>PJqWtGD*$dU62JTWiyh|*Q;XdMUpqU& z3j%-YzW4^^iF51HJU-T$pG2R9^Vq!mZv}GcYUYZ9lS=U-Nz1;GZ(+<hCwutvJn)Lv zmUZBK0nQ(|H}HreAMs2dGIgoNqF=TfIn($X@Qo8a10mtvc%9^OMAiY&nyC)`8)*|T zSx+$Ykt14395#iVP|gDiDrK)<`2;h)f(O1S89iU*omZKHeh}$|RQ*pg*on!%Pe3+` zx*^U<Z2R6vvg?9R#S@!$8INB?&o{`N;y3pR@SD&(Mz11Y!CaZW_B%+(Bf4_R9Ha0% z5IBY2A;gIthvqxf7`5J!@d-AK{C8|qxlQaNe0C8OO+mM|ihV)lfg>xdl?r&RipzF> zsZrA9Fv9|oCI7WN`2PE)z;+Sb5cSGIyBcl)dpTaWL{4zd<dl0^W{6wG`+5o5zCjBD zzKYz~*b3!aG8bx|TG_$WrL%X|=C0CQKm0QD1F;L8Z^7&k{mT1WO{YM<Ce7k9QbIv$ z<bY)cM%66x(TZb2g=)BjWl4H99a@KFOnNOHdegFsVZdWHg$lMvN~bD~+FFFC3$PDc zq)Vlob#b?b4a!ZWUbfV`tYw#g4N{k~uy!$96t87eyQ&RpTRGqZvr7_(K=a26+k-zA zQe1_>L-!_~ZplCV6^blTX<~Na(^;lg?aZlI_0&@Z346#qv2TT8;{{UhHxkS@9*4g4 zn6`ul8WiyRxns{I{mOQ&X+rc1|BOQ9pFn<+u~u-D2HZMwH+wj1WWdC;;H~`8LLX50 zeXC_+Ton#2Ym%hvVHk77l;JgabfEwUq?r&e{qFLCs)`q~bF-FR(545e?#O?x11J(s zhhmAYqzk>_OT#4c;jY}pQQH58@3|!121T3b)2e&VnAP)L#Kimfhh9p#324<UVgTsJ zcy~d1&B6|Rt4p6RGe3>$mu@LV7fz<mrr4T4R8P+;!ww!VyUFuaAE(K3iB^i3^m@cx z%A8~a8y&+>Yx!ZoO$=1J>zQ;3)O_zLM6lKw_`EP?JxJ~Zyfw>~1ST^q$zf(WA=2Pf z$}){^RUOJDgTwrwV!MsT_R2V)%^+`un!E;G^rYahhTG!FzG3M?4o&|6wk3iMq2h{C zUNGo72-Pmao674J8~5Xw08FcZ4f0T>Q3Rcbb{TXqVW?6I>lZNrWum}0QxY3QF+sUf z6&(<n&|IsG4!KMMwJT7D;!~5}BTw2XOdi0M0CiIEmnsh~O&Yq(Y6!LYF?N?Pi=Xkv zIY-G7)D|dblCv(u#zn~#2LXi+5fe$Wg!C(Cs0XhtR_wr)MG=C?tQ04GVWFq@L)sB$ z3emofw%x<<QNJ$Iwcje3S4{c<@jRq5n@nZirfNK-VlE%*dV<_mUj|QGO5hq%3Gv}N z;&Gy7394Q5nmNv~R(PTnUwXheH(t!CoZ#i3(D_3R%FomT&xYwFXNkQjjgtj!3xat- z;~ubKlwSKMOmgn4%$6K+!;>lUNo+utQKR=eo1o(!*{0Wg`o}u3)5y~m&;4<ZMi(k+ z1V^JrA7VN|;#!otpr8*xE3{Lr4UTt29Zs$)5bgkLRqPe+Nab5gK<q<vrQ{FXndEC% z-+)h}SX)B83;RXPRXIX`N_U{%s&bt;oQhX_*STa5>F33d=OGlN(Veh1_wGa>J;rg+ z6mzFtMjv7jefqN<ZQ9<X$ip*R%hU4~&|Vlepv1k&HByw88?Dypx}t1eDB9E*Cg|Kp zUCLslXT3VTu>$2dqkG3qf+PIJ|4APGfEE0Q^%Q#oui_N8NZOs)etC>L<@a`aly~el zM-g_7vo8)*SENr68#=%dipGjXcEph$sGA;e1exhs07gEkA;*4(9M)YgPBVbNR1H1| z#0YGc&ngq(V8|RI0`(Bf#+o(y4}G?YMg_0se$<v5B29eX7ZUh&h0MP17-D-o>a*q% zdERlta$7qmDa{MRwrau;h)jM+7D(M;rJ5vXiko0&7=sP@-J@+lBx#J+BlM*GOtR<N z&gfFtD|k>^o*pdDlQLS3J}BZ6HNHd_bmMX*Uf3g`6TP(Z!ywg@cUsNPAM{d2UdW@v zlbWXZMyGHWawVBw?Jhv&61YCM5R3oDHOUhtlM)_*www><=F$kEz&q-nRhFSm)8Bbu z>|wM=K?sd{9RAY8e19v(UP)5Y2{P{}UnzRch%ghFiGrSY#=97{f3=^)_ulBAYdR4x z9T{TXvaOG>kMwqdQr#xle&Rw;q2bIja!|teeiMFBi%T#Lza-yBG4a*%km?+qZh3hp zVYw3Dc{D_eH$qOSSP#H8b<=AstmLpS`P^yyrQl>Ogn35+<?dRpJB(vVyt)bIJr?G! zZI$8m8R=p(xOEd$@`+zmdE?SlYm_E}o99H~qYS56x^#(zBbR}7k56)Av8tDpgd+4G zYjLzYyvWES*SZ8l6NJ}A2l-)|Tktw}0HzVbaYE;Ad7J<$2NcVZpm`d+g1Mr44IVIq z2dV$3vTuN{WXr!!Cmkmp+qP|69d&HmwmY`jv2ELC$Le%!`@8)gym|f2nt4-MsnlI7 zXYX^XPMtdS(>{Rj0+i0E+Qz&jK0%Y~;hFc&et^YBp6W)pq~<2d3PJ0KzUXuvac;*W zjk*__A&*{ymJ2&aU`MFNpzL@1d3hB*TAsq9n1xfaitr#YHP=CeJGY7)_nG#Knpc|@ zu2s)e>sApDsI-*Tb$+fc+&9!hg0)KVsiFHfcr1mm67)=%p90>>G$r|9a`USfJ@k!o z`8Bj@EBxibda6QqmZ{k57LrmCygjwewCJRwwLXm#LMUcG{3hI}jX~rdAuum{$aMK- zWzkNGi~z+Yj#B4&+`*!K-@(9fLwf2P)>ZTaIViI%tZQs_A=l5cX7P?_Uccea27zPi z6HDO53%cvSEwcOj;F+#(h|#1o#J9I4x%l42!dP0%kiiU3wPlVuGM(Wo+P{QzON@79 zE+Yz`WQl>o<mzbyD|=zg&Z~5nbVAVr)NVg-1_~T$&`Wz^i58!CqnAdjY?8G-eUMh* z3)H+N8diCiX1xVrSA3l>EN4P8VMKZ-w<1W^PHv<JvA<Ak4608PXzo#;;7Q^riBYjF zbp!3V{2J#!vi|s!b<jY+bYsQJ4A=MiJ|MgUcstv{N=_&q;xwR;KdrErUj`&P32ZqH zq)_1%W&+Zo-rMj!diAGvY>I~nH=!Str`%+wR5nuFeoLDKRsk=9rTmBkuy@%w7lcPX z+*%*6ZOI|X{d9S_lER5b81vqEy)62kJkQE>eThAb$|;Ce<`N`E+nlXwni!GK+gXYi zyUdvoaRK*LiAdC$Ng}s}3RoRNz2Mn)hAHExCcY0&{!JSv><rdHr?Fjv&kwJ!)8p77 z-|~jH?V5{5b$hle8?W4qH<koxDg`peNSf^*D17(EAbRyg;A>Agp7|X*pMfA}GONdw z{05vu=cqTZnWm1<PPq#XQC5OzBx#6eUU?M~)SEG^Bl(oN_vu5F=<ou+0Od6ZrsQPG zma>5wn=5`3PX}`-=@d`@psbECZ(euE1n$40X*&0_$8E*4nO_6Qqh7yRlgh8GLE(X+ zVO`p@$=t{`{mZ8&3+Qd~JvgLO1}jMJ66Kz2b(Z$hh3?fAg$Hqs;7?W@pQg?2iob*y zG$f{!RSZ(7gP@vOR10f_hc`HVFRd7IKBZo(oalCF5M3*Hyi}-wteSyo7qA#yZ9r`o zvlsxc2ja~Ky)>hV=$c!(R6e!z)Ck`iQb+EZ)_<U*5!24YG3-BJ?5{%T$xx9-;xFKf z@xY(*e@E^!)aAq6L^X08QA+Wx3Y`%bg^}%3As&|wz{iMFI6C&-*MkijTZ$u~^+zmo zq!_Q0tm+jmGYn99kun`?zL*2jIrVS%blaYPzEUF5;egmb#A@4;uzzf^{xLV6_|2}; z1Kng@)R6iX+=%92R4t~G*-wmtyw$9*xDfOz5iI?ZTpT?b7~@keH4SSvQx4E(jJEm( zTzy4LMbfoVQOd5iXw7w}P<4FR*u>7GQaMZb=6O~$<VU_>?;Rw2r|e$WOOy2LuUx`C zT|iBuZXDLy%NWYBiOsP%Hmx4aZNc1(2nk$A>mn?LPO9RIe*D{BTDE=~43VeS_xf`R z*#39`Qv~Eel&tQzlB;nYg8T<c_Dhzh7l4|*6T0vtyeAU3a9&+7!^5YR^ZOj^?7E=u zcJY9O1W0`GC+x8wp9q_t$XYD2gh!y`%i~_u+8RW$HaON`(`1_M=`Yz}lmYREr0^+n zh@W$@T~NE6U)sqQCrMuzF_2?H(uNzY?A+nb&t*s$({&WwLo*}@O=5=$5jn0u5)Kt1 zrjAuHcL>jdeT717i4jh^r%<?vey6#}vMK4)eny)8-rR&Ud#Z9xeUS^$4&k64sdqu& zYzweY&LpT~3vgHI$Rwhh+^!AH8Ho-ce+^e1EBEVReusuM(-H1D7`SN(oMr`e+hH6= zP3|)+-4CbI4Qoa;{#r(!(GeVT-%zct32qYZ1&^{MB)ta2)gNiw&^+R-b5DA9tPRbr z0Ld3~&ysyp`&E}XsOg1|NL9UY@kwf$y(L1v9m<}EkNI6R4(lChgszRQER^6K%IpCn zqQJEri!E9ThF7)|ln_=a(e*=l;|5f(suiIG8hD6`k_#egybs7|McFo3YkD+OOyO1D z5JcHXBlhwg`Dz=j{~XI>^!(>bYwuSsW6>$xL_Y;!h6Q3td#{2UI>KwH+TIK-$gVHY zLZ((_;@^%A>(b`SKY)EcLp|0_P=!;|CtBvl%M>O;h6a%ofldg;KQ;cklUw&q9bg5? zt(JB4C1_NztQWE#<qS4QCKzBNvCRDH%ZfDFN8Wn=0#n`%1LZrRfH9#*x*=N-RNtYq z!%L~$2jLm1n<jZT;_0p&Cx}R-hlZxA%R@B8GteI!(z;cf71HGQ$%g1==(cezQEviC zL`slNvb=c2tOJ?H=$b$l!wQr_c*RihgNc5_<by-3X<m)A8=LxvIZxhw152Pq`}}bM z5l>&)1G+Ir>rtm{lGoK7?5M(t{Q#khRa{eay4cA&zSJcFSI~%jPZ(`bHRhMYAGJTX zaWx!S_!xQ~L!lY7{U^%yh?YAPu4vwWlL@UIrvc{y<P8r%|FyhfK&*$9nd6_L8kMCS zR+W(7tasEK<Z;?0R(=YYxgrnA8bH`6tf?Sk9+3v61UA;=uhvo<XyB;Hf+tP$T!27% z8~_`KL26a!W$Hnn_~8LrF4JcaQHAAxAC@M~uAJoAbiuuUI2!Uf^NJS8==MO|NV1jb zb%F$i6oDjxG)D$uM;+jmX5hvQ3LHYmHF5RdX77uK86odYG44XHnzc;VWAC9Ki_vop z+cpbsf#BflyRb}%bB(f^Vrs|VrPfZe1C%H?#E@mmh^^@@L($gSSs>Bwh(a@J_e(Y` z-%g0&w)x?<D>FW(YT_Ec&Df_L>|!er>`#KhDLY!sm>0$b96xfHp=XY<7pzcToSOE{ zX!5wUBxPXq`5M^3qsbw-u!Qs!mb7Tes-4i5JGG25U9zx{xqjUITPbSAqgk}s1mkV6 zX#R|K6mk5K{=MoI%3N~^vU%xghU{75S?0ben~jh7&<2y?L;l8eMLGXLhP(o3usuMO z#cTn(G}VO6FTex(yVcsEz!Le1C350QtNxLtts#=q5a{}m64RKlpPEgDNS-zurc9+8 z(QAZum;9KkM80RUi9@c1=oodW6z9;2iUKrEWLBveCMnNYSi$`8h&QcsL|>XYO|emd za^0E)!q=DvB1-(WV-nK98_{L>uZI($NjjFcdL*m5Qtq%)&N)_n7ma$!s~<XAq{Fn; zH<ZFkm-K`fu+E;pu3N7UmzT`1q`e6g)!DtfoiaMfhJWh(sYJ4{V5~Uv72TZN$sPMO zS}5lV)c9?R0uuZ1mMcH>(A^W*-~N*tN{57rksTcQgiOJrg34IEU3{7^MXNQ~0o_Ld z*KiwP-;D#toP7wjsU7BR4tJ{MtZu_2jT5<08~PslR7s}%6?XBYDl;D-=)hga;}2@H zqxk+D{kBkj`78pB*Yys?d7!XWAMU~o6lOiAI1n6U`(2-S^|1*$f<jhZP01u90Inzz zc~*vxV|myviMy_7;ZgRB@*DWLOi20M^%dN6!6(UYU-NBZ`$HOUYCer5%CgV4Q|>D3 zL$yYN%<^qT+hyx>=iK-}i2IPxzozIsnZ&&X5qlqTy)NY3guF0#=b?8gK6QcRcVVV@ zuhG4dNxX|7`rKsldfl(xfS-0;&TC0?^Ak3Ryt^<g57I}|Vsu@JjLi()5sFgCN0GXG zmt_{np7tG#c&K|1tbI?wytd;vxblm{xRvq|oz0H#KkdX4!t)^;&cH#w!72o@!fxF) z53zdQ%(}X7+pD_Y!MnQ*IvCwN7~tF47i+zuyWfd^d<?C8p?Y1U8*II*y4#6<epJ+Y zL~-$~oqPyXJY*&0BExE^SUME#{E3lL?NO@dqDy(!P0a;DR4~g-D&M7=DBfx!Ospbp zFD7g+mXFE2E%s{gKoYr)lXgJ|Oxljgz8(Eg&_#6UL0q$NAGmKBwCD4iI4#^s(3Ai` z@^A?Jze*ndU*MUnjhroDD*Ag7pEwPhIeO%w=sBqz$K<H9K_g50#zstNLEmQS-4C2* z3JpB<n6n#e^HMw{c8U4YJ4~0oNQiKrK)lF1-y=)Qp})gj*2qnspLd;JKTl2ReD*b& zuGO0hron2oa#jBTJ*r&nFOxHEnpJX{(QTjSAkp=CsOZ~%#vNU1dV8{u2FIgxAzMU0 z%IUK-iVo5tDFPf%A|2jE3|Yv>FuVa@1l5C!n9PU(-f(wB(rQPC<l_+~*!$siEmY{_ zCllr!#@JC-F2XBp&fK#Yj!Fn%guy5}Zny?)+z8Ko;fyFwK`52E!_IlK&xc`lKWd3+ zog_gP@jTGgkV7GML1l`g_qVr$@ad;^<!W<qMy<dp0gAE9{jtJ@p&Yn)MCmjKBJ)Pe z{!`3QMaQk2tZ1^y+X!B7PWHV6%N|6!;M7qiA$;Kku=JKM`-m6aADv-sLV*Nc^%;LK zYzPp(?p#4x^`auz)KOcq0|Pl>*9_QZ^d$z!8%tH-eSV5Ug8peoUG{^OdRsLUxtn%v zfP9;a;srJDmd;hIhbrD5IjN4Uy7*4hZ?$BcN+kEDykA??Uz!AhJ2*%wH%`*CyDEmP zriz%AjL$}Vc=^+O41RU#{k7<>iSqe=W=%FrM>a_0uf31~-?2O26pQ!bt+zJ%Q%Mg` zb7I(O0gok0=R|P>6Rc%{IZLw*zq9=aIG7<@vZpD3)_xoo81V!N9!5+bb{xOZ`y%Xw z2HTCzI^$VK;l`9yWHw-LVZb*QR{jq9N3{R1YEtnJuh7hZJg!oxzm{gMXk_nfY2+wm zW9?|<>L_Gsq-Xt)${LwptXz<k;k_Fr+74UmnH%`|P1V&crPA@~2=^))^6S&Uh=Ww+ zx1Am0EtgMV+tOzVbG<KZ9%8HfG2L&9H*c_g5;$Ghg7PJL3>@5beok^TU5{rv+*ft^ zyulJkZ>K{rB4~zhxqsyL2S?ymkpC>NB(I=Xs;X!w7gUg2-us0>Nl9r<WxLo`*|PZi z{B!^VEazZb4IC0C?9iUMLZ7y@Qyv;5ECTVKt>Ea!%ydY+y@#X_o2<pb5Jro;N<dg0 zCfG$*6o+O^UqlpEbHT2G=3<S187J?68&0;K_Rzk9Gx)yaS|UhaeU$R}5&aL=Xemza zlB*zLx4>{HeS_UYmd43A)VlByj_?+1^=fXHNh;U6L+WFWLM=-Kx@7FhE8<U)k(&y( zww7q@ZmyM=7b{1YZ0*-g8X~(DgrIo_6*cvNvhE<KH^cYRSdXWu&!WO1Xw+AknmgJO z!!XgH@K_SbT*s*Qam%_{NR2~m?em;XJew*@pmVGpQc%4Pgi|Otg)-?TrF+U})OE_? z#2|inio{il#JB@}YN?tx4I`%Sm7tg#ZgB`3?ZqpP^T9n-SrnEEVU1<mJt}){H+=aN zc0oPm8siK`lDF-~v$^b3Fmmkac5}`=##r3iF$4p63DSAUQ_yFFR@(#X<^_b<bZ55V zOvyuIo%aNwWIEt_U_j&a&Bu~WhRidQ#TcC0x`hJ;A$4Zk$noX95r}e_xtger>Gi@j z;%mec_5&-im)JeudAGgT6b|PtS)It*Tv?dfJg-H=iY?1BVvs4PYjcm#JvS15IGV6o zRrT}C;oqsBXZgRePVhI4#0(KZeFB9pVI))*#k3Ca?+}IWMmckj`u@YsUIC3})`~gR zh&Q2^M|8oiI8b0$VbeaOe8JzAv0PgI4w)iZbjwd)$R5@{@`qIIN0HR@u2?{@^s)3) z&X$aa)>=H9c5r5l9$DJwr&VTPr}0nrM|U(bIrwj_sHO^P_0-yii{(Bpm`YLYN+S?> z`%rWr*`tVtCv@`!8_g5^4YBa=&ZxEG$=ePA5`M%hwERBt;@l9NhprX@w1|md@f%60 zLfCBVeAOCUROoKXOhqzKV@cf38p5WT$Fya#)>XH;6-Q!u^PHhMPKdXQ67w2lm$l#^ z9qa1l^5^64<|0rvz1Uw0edoj4*--6r7N0XKUA-D)1cq6}G4Ejd;uHbiIpK3VxB~_u z@Ye$Y(1XW<{RBX!>w9l~E?M#*RsGnv@Gsp5{SGJD5bt5bk_Q-{Uj3{wv-zWgn`~|O zz_CZ)0>3LNobZPY;yx7u$s&Bmh?s5{=HdbBU3wUHk%Z$glOn^IJ<H+XtO+98Eb{T| zv~Lgow$FaiW-}+jR}qCBh=hLzT@G;w@-FNRLER}X+(YKdCoWVH2cBrCW3^p@xg(Vz zE@w>1oSK>OiLb|;8vC?d&#{$h5#u!N0igynxTsBEYg7rAs0BR}cF|U;G;4ywo-@`X zxKF+y*x=21c+=U^Chv{4z5{lk*XQke{RirXw`AZ+AIZ4j^*-py<v#Yt#Xc|zQhrNR zAG3CT4xOSp(@l+IGH(>RncWkeF1(0zZr~jKNEFfzCW!{AhHNqG%x8kMbA!}74tC*K zF$m=+{2jv%*+ne)@A*iw3c(>tNkd9b632r4${nBWZ_&*N<2tWQJNOZfY)1&i^6&Zx zpFu}0;QInS5+zwAHm!7agu0ZPnxy#AK6tkzBsUQk?=`_TC~31RAIYLf3LKgIJ{g0- zVE}^w76uUj)$zZQRIB)Fd0+%s8W1!5ZE=vOXa!gtz<XyT6~gLat+&c+4{G>z(lheH z$)r&d$b<pOGlxc7n-^pu7D;AEzN!cTvuf8zdv1vlOscV1S&Hk9xZLfw?N4@IPwD7H z%lCq1t+<-z8STbK4zXsjSKBTKU{rzxTZmH6+k%GEVivbGhmfG%*PQJ5A@Hmjnl^I1 z@n+l8?NHu4AxtsyZ4<>>Gn8j=dGM^E`H?oypPeu`u9!@MaVAo(rKOMcuPVoD0)*?O zaU;hpL-Vc#DNC9#Mqdqy(bu#Jgw=@&7=uN0C@(3aLkPWwLJ%;@Us;x(1|YzsfpJeS zl`!u)hJv&6zYURbqeIh)@370KqLJu{^JYbm#j?>WJV<<ZmnDWSS~Vg47{DZc#SBkZ zpjQTKED2Dr{~(kI?l)Y!NZMylexnhK63n$cA~bD)#F=8G-j6ngnY<C9cQ^$_Uyk;f z)So-i{bz^7UV=U3fGOEDqr6hOPbY!UIiGfbdG^nKokatQ+ma)OJ>H||`i!gM0$1v4 z30M>P{Y2A6ndsO~XeR13*zy?df(2Hy0QPkurPdBPTV7;VHt{dR;EM#-Gw!$jP&jL} zsu>O$FjksmX6Tz!80liwuN!d99cN<f+44N}PY?|Ob3jf{#MPZSmR>>&Pf@{6o}{V{ zxaHD^&SpapT6CW0x)tJnGb9tm?_hs^ygTjRys^Ur0fi6)0nz=19EX37sK1XVb!b3( zL+X2Hy2ROptwb-sFFfuCkYI^n->Yd~@nH}`faEJ8A*C!S+eo(|>9{n+2ge4}2CY-| zQ|Iu3m4(ImC8%%2W`~Pn8pU4C$`(4SA&qV8r`Bz!mCw_seXl<E8{=z%(1uK19+Quq z4xK}f+WX^~p1X27FN^?D_)emL3o=-#Jn?vfNU=0&v)X)lmZx@66K2eX18~gO&v|$j zH=Tp!HMw@dgSe4QER(aUbL=|1f{|$E?Mk}}kxS-l-!5e^&u1QtBW-3LzC_-ed!`Qx zL_V|N&OgKqiZOR;?Kx3askjA<E){!LjG|E5D7nRtE|s*a?Hwy`<k}aEYA9DKw5ac4 zCR!+O6ka(e9xHVU?BP%@m96F2=Z(rxx|Cuov`88CNi9vUYp;;YG%&NwmKS=oE6L*B z%(}O#7|$q4D3VREw#wP!UClZ_*|MhbCI9rMO9bTY-}(CDUCuh)pfS3CPK$OgiNn28 z0OiS$Nk1^qRu}R)EU37#+rCl(_7)T!>Znh}MYxF9F6SbE%8UsWD|k#`j&?hAe*y^e zOzS{DG}C(tE_#V}PleT!1&viFf0^0;c%QJ9mGl$CEGzLRhuNE`X?F6@e9NZ<%j1OU zEX1|1(^-p$=Z8|W?f4T*`Hx&?+Djbi+6!t$Hiz8t-enF^%x<dVbq6$=UN<6{CUb3^ zQ{P-1v&1&%T6{b6u7RH#Cc^_Q8N77%Np6BCMVKqE70fDg=ngccHy7MEyfpSvZe%j6 z5@r%_(k4k9zw84F^6azR<W6!OVsUPY>&&#IYA?1Ze{`BtaXRyhYlq{!_U;i$aXgDB zrId--n0o~BQcFvA<RvGBo8!ogo=un5>`#!dhpJGhhwO_>bdm-op*p??g#!bL)vYJ{ zi~>oDcw3{JjIcS(Y%;4U#fTeqr|D~b8j00Io3k$?G6WWoiC~aNQ8Hm^qd!Vl;$U?2 zp>yJ>+T2<q^SO35juX7K#336&(%KP)YVBvTs^Ye44($qG%ttJu?`%%yWUgeZyW7O9 zG>Ua|il0ux;-Ep>N>k1o;bC5AAHvPOE5>$slD~9|%E)(rk<#p#g*`XNFWf`ZN&l1( zsaU>KOKX%^YeuuiIlXQboOO)5LhCQqt-0%;U1<C!6)$@?rkOmz77DDPNqVQLOJ4+R zm&XMh0*V=7Xd{hSd?AS1$Rm8E?!l@T2nL@hgxCn)hmbdPPzpoRS5xdkkGyIKGGa^o z8AlrPOmxeh`vWPUfG1*9aC~}dE$cGK;BHBn6NWTXnf{D0Bf3l@C=rP7zRJ@4m$Oov zbq%d$^}42p%5TOtR*DWnMpVV{cJ5lt=KT{DSdgEW*sNAHbmqP&b~V*@W>K)gsw`Qq zH&`JS7PhpMxFHrc);1t2ahOSK8CcB`H_9|L#EYw^Q<a&M#@4H_vW>>s&YNN%95e4! z>}Y&k6hS12WE<-rxN!c)@0)*-WTl8yr&(*VAtH5NTf!7sV`ycGzoP6wZg`V^W_;Dc zv9|wn<1u--J{<W}nf9AH8V@=&sEE4-{e}T?<|uWulIiLf3Cxf<WBA3v9j_ik_uh!f z%uCfS1i9eIz!q5XuzJv4y_q3r1v4+|4J3#=aG?%SeB|R}A!abbnk-yPa`?03=#T38 zEJp^lhZ)G9X$4c-X=?mjhl^pMt4@->nbt0e2MdYEY02+?=3{1U4Wn%p3uM01Tr~(j zq7h+aHkiju>!A>GiWV*iV(yy~lw3<4)+IM2MjR-!!v`Z`@2c~EeHE>T*4^i4>z18k zKo9Ic9iWe8iJ?IbcM7jSN~X}2=_VdXk_fYkM_whRNP0ypD(_|{O8CTBIR2S9$(O`l z{_~C~b12E}AV9-sqMiXM&e*xYGYNSV+fSp<i}h1^YsBOSi0Rgdw~a0SkK`RxNtK_g zaX#*0fP?wR3Tw$Rqq3Fy6LR%^4JS1<m~{b<7Z_G)Gq@bo#rs*;Y6Z#LtZzY$%HS{0 zB^#Ur9-}--vj<Ixn#i6Wxa8Y(|8t=F11`j!IDCrlM~a95yR=(N{t3}un3U1L#5-|) z-HI29D&z@Tm_&MOH9Z*aZBrMRX9%M5J0X2pc6pk{(ojipm(;JA%N<DaRL0^2#=%HV zx;vV>X9J<8k>EnX@wq(c(S=*wkXiPSSyzzBld_3zq#-MHT46aL$K-yBHD5CO_UM)0 zVDhbrJ-?5xaab!Od}AvZ?Fpzvi7h#>zqOr>YlY~gMK57?n5Z#a4wBm80r7%x8p<6w z6p3U|RBf2Cf~@Ox40R9~<1b!<A^;C>FA2gZYRdy&6>H}5Ga~rW;W3ic?o1xb{6zYV zl*`p#O$_wa2iXZ53yta!NmNoxlv+yaXuyEpk`lg9$rBsNtX?@KBc3C^iV{h>FyoWB zGCPSH+9~5FmT!jcgbd5JqQa6Hs1nKyC_-gnhQgnq*4Se2)V%I!x#cZ*7h!p+<R!)` zB-O1|X6@VJlEO>(q9j{i5G{~?GV(VoYVlM!DUO-xx+{q`C8#^BCeQN7=pEKut6Ly- z)bu26sA@)mj!9Y+%8)%v1P2-4)|(L`>7(lGM6g+P-OWP72d-~t`88wAM(JvEoVJ0? z8m?G`FXe>YYB({Vuh=Z=1*V0Dioc$Vt?f`B;0arjDip<JRm)g_7W)P)I3weCf=bIw zO1Jd-J0K$Ul90uGa+pmzaWRx|*3V(mLqj5AAXgZ-uR&_T<_%<miv1~Z7hIzxHAp%t zYdpK+Plka<-}cRWd0L?5B7K?lYdq)}SV3T3IqWvw^fdgz5#>r}M{ZRWVQjIfnHdGA z=L0=W!KouGg_6{V(W0P?9G9<$MORmmNkCCE9_V!W*&G+%$B|%f<H?xDcs0))s${R0 z?r2^gUYR-)a}|N!dq0=}y%m7m0lg)HOn!WU1BldL@Nw#*TukB6gS?S}m&b~2j13<P zxzQ1`yO9NG$1jPh-jm5=evSg61YVCmkn;5re9#A_F|xqpl48Lzn72)fGR`RM%bIii z_!=|ilV-g)=NN7?z<#>9%_sIq<T%eKX~&Jzm){7d7;N(hfrDE_JN;OR{*CD8#n&p= zz~J$1c(5U}iYn7UYn&opTW%?39H7BsjPj6@ob?1I&~!T}4^0URGmu0DJe<N+GaUMN zU@N#;!uqyhDK^DVpd(@gX;NS)3UKXD5Hv+{{#PHf#LQT{ptxmy#|*v(BGt$82ADoj zuZzq1KRL`x$jPJez>XH-?_qFH2`)0l++nW^OwBQHO27eor#Mf)hn?$H?I9cRy_U5P zB_=yJ()a*rxcfc__(WJ=Tw_Q|It=Sj=9SB1a!X-xd5#Sph`#Sra7ea^9!}bYF(*XL zfqOoY<9z3qCMm!O7d?!6nx9o@ax&VN(8%Y$d`m|+d`=q8x3OL(Uw6(heqh2kL$7SJ z2i|5t=;(Aq`YMeyb4HcHZ<zX3eRC8t(427b@uwU<Gm`uXRW*Do-&F49BdS`8rB4=o zCL@ue=M6*!zXvYrBe2ojX0Ke;w55CE&pC_Xfu%!r_W;%zmy)oJeCH?J_6M-jJUj*D znbbfY8?gi*pjV#ZiD>**JkfVMcP#A}4(<n5SfV9aLZ8VTJh6@TKuxZYH<Ta4$HQai zdG82Ur)bkZRUTe2-=65|yFz4l#JcvVaDjryXRPbMJ|3*LLlc2wdIzZp+JiBQ2f>K6 zOAi=#;_nZZJR6!fsrf5MrDdRSBc&G2HCeWbUc_Q#`($v+_4XWdZLMZ8tUUUUFd$`@ zWv-pLrd!DS&2jyVXy1ChS7M#o@jMxd;42-9GPKHKZ+>TYdrd9imJF?zv;WZqKF=Q+ zpD+fF{c^3~JiN>L1ZRspsnf*K<mWJmJZVIm5$$)qzU7%b(lVUe;#(IHcM$}P5k$LU z(Fil4{JbeRc#glzmORrrE%MB4!gjhz20L#57(KV>tta^`s^O8HivAkM=%!}<M8%O% z@ne=+B>TrYBt>V!8?@rndE;&N_^J{3sQ!gE@CGyvS945LL^+P@9+`haBC^9Pc2@!t zGHQb@`aps3?DKL0c2&u_7(y8whv7JbL&*4yW>RSiB-dS<+K)s$yc4LF{*93j8{2$x zGDP#<QMEIl;?FeLWvy_E<P%Z5%{y+%o!JcFJz^_Y{CWdOL|{LYJRxd5L+oW2SmAVP z`VAG|f^r0Q+iXLevI6W~-r+RfZDJ$exA`Dz#)>l*x5#6>akQe9%==9OI%+h`aPM5f zDMm9B3f6-5(P<RU3I`67DeiY#qQ8*i<x<TggJ|b@rc?@c$+l!KQbo_A?%9=o$;!c+ zW}}o-KyqcKno>x=!X8Laq%fdh=d?d`@lBG)XqtQPW<ECKoho`yBFajhNjZ%Ha<8M` zs{bB;=c|Ur&g6uu=Xa`C^^$LZq+^nO++tEv39>Ig#(wG*J1Q&doX-dlrE;nsZNNE9 z#0$3k@;p%nD^IXQ#N2z^_rr{iM~<l?yqnjzfUHL8j7oc6I{X#*K%#gPYEmxfY;cWX zd_#!ofLCk{ZDq&SfiW*grl)Gz-$s~jCN4c}SOFrv6}%O%=gyZ1-9fP@Wz0dQFjdzA zbeEdeiGp3tS<O~Pl{d(r30Qkdr*JEw6*+_1q{;spk-ZCMl1{p9tGrjhd_>hs8v@~z zu|yUk?kHu5T%Bc9UGrLyy2H0h+k#K|#Y^AkOO;~^<7^ya$|$ZDXnWU-HM9afey~ZT zyO-faaRkMoMaQT4<y=TlM91{0aZtqnv<-Lj$r?~;G2OMBAw4h;E7K}gMms7#)=oP# z3dan-!)N-cvDeBb%0<cjQ`yb#!;{9O0*mc!9&#^Abw~H^SW@SO*~I}tt?Q1OwYfm^ z65?4y9E&iU!7a8Lk2DJUPqjXv;JOMuhTzA=YM?%~MS5_dY?kqEK-~YSZzx=5k*^MI z`Blo2+>}+GW1FU>(HGoJY4FBwB63aTp5gt5W|ST1Ub|7YqPWQtV7XM##wt!RHvShF z=r;3&vs#x-qE|Kbb%wEk+3%{cZb_qDP>e&xC4?5r9|%qP)6${1LB#|4;s@S<U9VI* zmwCV1`1N0tr=#I7Lz!Vre&Iu#k<F0y_-xzu2$dl|;Fyp+*8!;Tv2FbhnSX5{-ozxH zCLj2=G~<IL|9~{!5p?iKqQ9lJ(G8_yi)!-&d!zsQk&|}kxFw=Vw-9mqi)U%GUy~iQ zwIU+)DvghvFtMnRvGAz)tQLb<+!@BS3%JK29|D6>eZuaIP4NwuDQ(Ch8=}q?Q9Djh z`f0}S6<XFep2JKH(5riL-*b*D0;)tfwV(H*BOwCGwFfof$wLj)yn#En^e2y7Mx#49 zQfkr;&Q#&i0oO=dFNbEy14OhdWsNWk%FpNggBCHDM@IF0JGowIb?J9De%Gs8FLP$* z=dnJK)kaFo-Wd#n0-hYr4hf%R?MR0^){Z{Ai-z68WclgF20TQQPT*aTNED|Wjk|6B zYoP^jfRAAh6lCH30}v20zyZ(l7mN@pMtT<FdJd+Jdis_||1fQ3#>?2u@xupi%FH&~ z;iyZ`2|fk`$>#2S+3|%qDxd^LRu9c3v|DW!svXc)X;kd-*#ScQ3il0){VET>PF4v) z>C>S)*KVRoR;o+K^YQ(X5OPgKQji5|rAD*ab`t1RaCbx`1v?XYj`?^Alw^w2=RPxV z75einN=<O5aSqd+jPCZOgOd@E!w`l0mx?o7P&JL50~TldXF=T&EKwLnlqW2AczHr5 zl;cLo<r_}B+3USdn5Q4$cE|&qw|&h^isOni-UobSk4N96pHokQm3$=WC<t(-t)IV- z?mbJES<2+p<DSR)UW;2uE()a<CP0llClpQy%oqGf-G-!oE8_algappG78}YKn|HAQ z`K)C$-4SnrT-~%QfH)0eRI1Xrc~CBw3f0_ElfNn&)Ljn)EIIcCC3QM>BatyJDvod% zF);PorUTqyFmTN=eZz@m1f?`_R7~Z!7kUHnfOMAHy&ivt{{B#2rCRQV-^aO^R^3~q zdZD;=m=-YhhB!`sRlW`5qqfz=atC_ne2p|Zu_*Ta+)cS#t<h-mL#JNoX)iq#Y{nGD z9lBzQRPQ4E`41=9OOO+~6jWC(QR;1aGS0qY1o;#!RzmK{XRtMbZ-f^(ikXWhs^?MS ztj~zvIbqp8xBF41%AK=pwgmf{;|{b23{#A^6Sn_a2L9KGT4Nx6hXahLM!@g?KB5@^ zZrqaRk?W&}_gbo#!2+fMbp`|DRVsG|tx*!h7okT^TxR&P6Zc&?j_|TBB?kTB!wY$! zm6Kk1L7U6@+2bVV`-`_1Q8&66!JSZqAhs~RqyEh_$;ToSXkZ!0b&CRJ2O-m`@o?h) zd-XB%FBh#zEP65IG<b_flx1XDs9)$MBen+oRYosm?Bh}>4LkvL2~z2e%p516;*BIt zq!Y{hd8FRlhmPCr&}0i$0!^(K6Jwf2Sq`Q)o#MwtA-T4*@9al5+4T;5QP%D}q>~kx z124ZYL0XQntz<H{l-gOMN!Sj#wei(YH_Zg?(av$a3qSXP(VV!#^>270gnVyczkmfk zaT~DhBeJ>UqYgfJ{TCnguQRL?@M2{HFhjopDuHqQ&-bi|wWGb;-_CNT(yBF}&ZE|9 zmMh{?v)Kyi4KTVn_K+;2j36|#Omn_~737FecZYZZ4i~sb+(<+!hDt?0$PV2o+(j>l zI5Pr%!-WDdufLqYiI?#aG85hQUWV7A+H>RN-c*;5n?JR2HD?3`QnEC4TC?R257PO5 zY>z4~2lf=xULds`uAiS>&)`5ByoDgEHm=@r0!$HfaSm}G2gWEs@D~fTJ#q=kRV>)$ z()@!|3hfqDA!O>68^%w=6f(my#U%)`Qbmi^JFiuHt12ri<|bt-_4#yI!GfpF4yC6N z<{hhEL#V7?OBmtr5x_$h7B9w56L2d@>kS$>Mh!3PTAR=`OEyiZdK_(9ORe8dGRvI5 zhn^Icjb2kg&MN+-<;p^$L5e`}kwOUm(n0PjPJZadswCg%>{0q7kYp-aQm<<DHbC5J z0ugG7TMm?}5+|6F7+cGMyJ2J1s&q?{!k<2=Q~~CWaHxT|rp+kRM1I(N%o)ph>#GBz z-r2Ml5-s-ZzT1aKnJ%>Yd9f&B+-1)L5gZf_n#vQM7d47(e$Q$l%0<ee&XZ+YsThm0 z1A~EKTdtYNiBBGbD^Z_Ddt7#bp2m;E+h&yga5y@fo^lFW_2Hw6h6hy~#b#sWQaF^B z0)yVaA-bR!SMS?z_vv*B5goCwy-a(l?Qrvr!k{PaQ^Ub+J%(k;3_g6jIwP*KzN8$x zo>}1?SAS&?wU~>xI}r<JEVf_+$>E|uaEO@JLSD`?YDaF<3yK%ehzqVK31zfYz95~7 zGY(h|Ca#j1Ix%>__mtI)i)l!ig)`fMp~ji*Unb5ERrx-uugxURo0cEn<*M_NzFhFc zv{v%|X%_+Wc2l=}>F)CbNFEd4F2ptlY3-(6dc;6C?o~AX$g%#on*_TFqAUYg$~BGj zAdJD`$^GjQ-M3+p`j~Gt#uO1VXzU_ZO2q-7jdZiDNv7aSBLlFFHt_*%5t~HkK~d?i zQR%9SgvPdTcw01H?#IpDK2AyUZ*uY4A}BLP#dk=eKIrh*7C5c&NO9A|@3vvrH3Iup z3Ym}ZvKcl<9s^=n7L;*62G(}5@=-jakTD*A@|WalqCu&BgD}d1t5teZ<Ly6|NHQ`W zGu!tOxm!d(HTZGJp9$v}c$u=WL|0Xnb--5i2vGFRc`<HIr<8pM`NRDG>n^?!#B%8d z+{GUufq;1b=et<J$k@o<$lAcj@Nc(r!<Ta#MP+pFjk`BfDU3Xrd@a3Vkk-{iXc1&K z)|no|GZkbermpq%%!Z)Kpw-2|E<q%|63DcaW;j{DkBwhLXHs-`T;6eZpEo>~A~{7R z>m@d?v+&NZx%UqbTkfa2@ZSB&p;Fi`lS0QxH(2ck`jwI5A>lufxHi&#;DHE1qPG<$ z)t1Ef&tptVvKFnC&JgMfv_wSJj=d-ij7PMWh|s4Gm2%|>Wq{meC(vULHOn9p2Ah(+ zs3Rmu!%8E(*$XzdX3u7KUMNXCc`U#hwTgO*hYsv(@tNXrcroaG)Eab&a5W!z<F6o> zThP4qmTE|dW=%~m@gP}k*=sg3YP(%naIer)IWABL3a2b<D!mgMZE>40OGuwoP=-Yn zb4hM^(E;MoIbVOzE|l_jzOALRt<>=2I(FfL9W0Qnn8hYDMY=T-!RKWkDN&bkLsBl9 z`3&3ZmntbU(eNcX;r^R0qCy)1&Zfs^paBlFu&KvPan7PvQR|i~iXLRiq|<8vyr}jX zk)VFtQ0DP%(thbkn0Tm8m!d_Ia@|htViEl0@Zfi@x9ooGCFRKA7d%*}wmqfgZc_;s zx8PlWMJon{^6^B!&5lgjtJez{JjhoM^kHVU1sqg)GUV13zU`gxCz0l9t&*EU5##d7 zFYey0K2)&lGd5#>+ay^R>@1DMX8`}=g;JjKo<N0KWp$f`S!1bPQq^bRhhUkJg<&<x zGYM-0?!jcrsh=%P5RuRPD=UF!uMr3O-bgiK;%bku*sg&AaGo(tyuM)5MbigNH?#Zf zqi(T7(I0_Q1}uEDJHXSogMJ!{*8#_81M{=yGoVuNjX!qsq;wh<R@r_%%guJs<3!M{ zPpx$wGKsScYog|)&e-|FUS&&l3~S+vbZO-%L@9XsA$LZU*%oHsOBiGbgUg={-jh1x zlihwx@a-jUFm$@OBQUr^g{}nFcT13Tf@(t$YEDdretQ3JF@mfl7EX=D``+L^F1!Ma zs@>Is@cc2{xI#nkJD35h%Ll4&YzI19=5Hzo4#4cWD8xr*r*Ijv$8x%&OF3o+YNuE* zs#pg!7x%{%Gb|@k7G_=`BQ+=P8j`V~zMW!$iwH${(?Wc?(Psog_YC}Sx-)XshYYk1 zKK|ZA%siJy(crl&o#Xn1+|+X^J?U$A7xAxJS$oM~8;jUefWiWhor9^9*Dq^uO{y?j zVQO%(E8TChd5g~ID9{)Z+8Di0R>^ofTkc|)O>!;R$YK|*cyw2*pYZ8uIK$g~$NBy| zH`tn)IWq&C%{PGPpT8n7@#j_fuTN4&e}Bez0G{!HwK>l*yIp20O`wGac@t1*`j$4o zc>YcSA~1qqPBC})*x)*;HBQ_2PYOQ4Hb9Wbq2Ro}D#S5cI`B-g^UNZGl9ZQQ%gf6g z`{R?N*SGikbi+AeVSdM8)|ljb1oW{*IU}StajEsTU}Ve4)W~+d{*mFp>UN<MjOi$> zWxy5%_B;`3QETzmQXJObtwRJ(9`x!CL1l(4&L1bGNL=tnn-hnFtHP!h8pD*fN-NU3 z%}Y9oHYJCW6JF|T^49X5$q`Ge_VM4<#GI5W+9{@SF<87K%kL|h3B3#Me4r!5XkuKV z7rakZqmwnRf$3W4a;ic!B)i>_KT@jS8)28J>K2}X9!V6ff1ZH`gGPQk3+wLf!s;uY zPJAnj;5I%~q=|kZ1ip`QSZ*_LR>ki^a3%zZsWe+V81RX!Q(kJeeuv*dZ4&4{068p5 zs4Uw_@o6n7lmuIV7>8?$AOIf%PSpxl5i3>MnpC|<8t&Y70mQe4K+VS|p&5i4hXNf? zU3?^v3mH@lA~Z3(Pn&d7r}3zn4YF3@>v`b!fZZRFoulY?`Oyz29cGhKl(IfHM2PA; z-{!Zh)F+7H5NH_P03jt=MBXb|1(95^P*1g>))9WfPdaqL`+BN9`=LX^5KX}yNs&0e zV1pUbNWmsJ&{0#?fy@@R=-K|09(rO!+i(XT;Vn~Qtvh6Wtx~k$uHNeTgzpYfL>_Wi zFuD7Jd2_-F6}uRf+%3#$rT!V*p9dqQx`S&jK<$JUpmxIazdoq`_H?RHwfL;GkKxVx zeZ7vltTwz!gbE<g2&zdZk1!90Fb@UoAC^+zOe?0UHMyf5QFzasxe<R8SKlC`PfKH! zR+v^SZpyNN!8CW+!Sp(FSRel;!DVH#@^-}Iwc+q-jFz@>8m8~LWAoH2`+n5rVWUf@ zB}{*QTa*DPI>wug_h2vpv$J@+Jebbxp*EO|nY(100(PG{!t^06xXQv+yN`{zeajCz zoo70*Ifz~UyhqdWvO5F}ZgiS_?F+#w_l1E6MZ2p9<j*bKmKkEhkeHteuG7?OlL`sB zBH|VllGRd+&SMQcy&Xcs+RLU$d#AWzP|$}lk+R#IA}_qD&X9+wwK~He2*5kg1+!zk z30h-55CjP7YkR^B1!Y|9?6MyXklD_L%R$}KpIz_Bw~vKS;qMHX*bRqILAt?+wYzE# zqg}|-WhD~n#P;bVuG{QXqtS(p+CXwd7o*V;><*x$MuisJ-MHGJbZBc1bwCX)l--k$ zS81<1bK6rQhKWV^eIA<Gb!T2@cWU9vjKBcV)Q)S)n2!!>y)kfCV9VunL6bW%o~>~$ z=0J#6RHfFlrHW}<&^HXeG3?*aNNH*!qu~lAX7h9dgslJ(9R-l`lvme2eK`QFQ2Ts< z4?2&gnjI;=%I9C6>yF7~G?(4BjEljFrct(vIO6x&kR1_cUTCI&`g5;%&`zk|hf$b; z;NabFxIFgyF2pP;QP`2kREuc6;sPNXPy#_B_gw?I*Ni4QqEiQjX&2H9hDJANQ3~dT zz($QKd_rb*V7WPqRLzZp5vuNO{&^fTRaE0<g@KO!;&>7LOc`7n5sp_dQ?+0n9xy_3 ztV2X430Vp$OQ=jYw#Em=S!;B?scb=(8qOX*l+<aBJ3rAXn?N6zTY3Y(llxxPvHA>@ zO8ICIVus>H5E}q54|doEYiE4^e(~<=b4@K&37@tsbLe_16Y`V>h=z1&aJ)Y?H9I{p zKRo81ZYT@Fq00yzDw91hQBaP}*ES-aRgQH9WN~jyv6`P{#z~V`YiumfH~7dYrjwLZ zwe0e{cKMskip#blr5Y;PM203ywN9ZQ3h>~BGs3t*EQu!|Gp`DRx)5V7D3+jDEDI97 zA}e9y7``1$ghs?Bsr8DB>5GnXpBxu;LS{O*w%#`L=3|)^mMCVc#>J|2=Pyk#=Useo zkTfqLG1%{5MVAP=om*SbFG>2g&D<2OpV4aIOvqSAhNOYLkopy4&4L4GA%w&aC2529 z8q$-IV*rJ;{_3TnUQ4xU@q-i#-RgCvaT(!xLP^d;pz0AJ33fQc(z>DLDoz|MHq6{x zD+UQxorAGihxH)a_XgJST<u2_$Hs-xPYh-11#lsct-7B+nZ$wIM6P0U!PE})VMy@I zl3w>qP?5DSE3uw?#BtzzKAPdilX9EbPqfps*-U~|=1(f&GN*p)r&u>sNM%ptQm6rE zSLrPTH{d>zB`aqGuA?wO{;ZPJW=>(7Ra-k~bPHL&>oGU6Uk8Hn03<6&(4&UnLwWHn zgX362+naRCghUK)=>e03g?)8wzj>z_pM7-GuGw8o-W&4Re;~Q~#NUlZ<fw>nt1th2 zfV&;<dZa6zO8c0xvyUZaKW_nbZJ_R|lMXASN@XFUmJ7^6O#V^uOJNAn1w|BGdTnX> zbtCn5mT21Sj|s0>_W|_I5Ua;@j<7RC;Hq7lg+~g1JR;vA2mT~Ofh!&>Ncp`NSMqK3 zaa4P;Rd!}~U2l&G^wP(V7y=dmHArM_5wifIE%ZL9Z7<kK-)pEO=4Qh~+PBDA;L7x3 zbTPFmsAk|5a$wlA6<-e+8!ACKk#Z&W=bxsh#KST$_!l1qcqJg@7^wHF15vB`nE(Qh zFR0uhIG(fTJK=9Yq7aYRU>EIX(_W~it2v0+JtW-x@t*8~7C*wO(Vs8e*5slqg?Vs$ z%#PHe)in$8G84R#4>izOs0Um|%;x2LRog=(3Vvwp-pRK+l-B9&JY4xi?u<DjKdv*% zAgjnoz$rt9lv1J(n2_auP3Jz``ECxa=4F9=p7AwTE|)yk0LZ3S1IzYj$N?G$0Td$0 zg;(nq`24d_>%ADvO!VPw_65>ik>kPC^l(GwLrbV_TM!{uk`;PGUu|q!MRoZ|u#w;4 zCvcJpqvAQ3@Hjg5)k6BIuLiG;G6E~iP01frnL}+V506yH4Kh|bt@Kq**GKiqdy4Ev zPk`x+E#43&^D`{`(P}Cyem+68_q0-}a)!b3)H-4`RP}CRd7n;fF0G;amHixSfNn3< z<M?8fsPeU@6f(^`SnO1oV`wh}e1V5FCa0hmY=<DG=#m$>(lA&}Glr3-Qk+-O$`)>A ztJKOi-nZ9@&B6C4QCWW&#W3gBawP8tIA~=wN)DZZ6$i%p715vj(LwsksL^qB##mFw zFcI+vIujNtOrK1ux?GW=s}^L(u^FN7wEJuOqKHmXjb5kpvM`trbBHcxe2t8<w(F*w zTSbE^BoXUG<!81az_6){r{@PRs5rNmA})>t@3Bx1v8XpT^=Z6^G~EM8Ucr;j@KP;& zdaYkDcpk#dR@PDHEiZ4E2gouK+z{mG^au0J4B<d7BU1gK&}_$9T>`lX4KyZXm}@<g zsOpzwm1b}_I_OQ=gxWr653X3kzS>`%4>AsdJzyoi;1oQ7$G>IYymwXmy?l9L0l#Ua zKCqJBV+vFp<+G1YGukz&R5elzvTsZ0_~C=WdN4?#W%x=AR41y$(>9FSyin+$X-K_# zhD(TClKu3~lhb2qV)!L%icK@|oAe{S&LaYTml91*0BWr;>i)dB*W!gcm%8K|2a`-d zyN7vzrpR0=bea=N#~j2mdx2LOd{8+J`47&sOwr-O5<yMmToibP{wDwFXneCfP_h8v zx~tKYqrP$#yrB^GCl2p~UGB5N?Ki-Z=L0Y@2q4fNut5Ue&j0V=?>oQ?`rkKrpi_Zg zhcY5c0yGk`qI7>Wg8=#^y|T<S4KWG$hw5J@^}jdz^(Wtt46y%aGZ_I{2~iP6C0ZHL zKM;U`eg*yiOCunFP5$rOFJdwP=C3-)|EUEah3;QkNc_Epo~@pNsnLIIi1d$kK)<N$ z|J=~P#>&dZ+Tl+CzrO81+W-!*{`uh-K;FLxump&Gnpyw(EBp?G|0kfe{|xkhIXHiu zkiT7o`ud$<D}eTmHudip0Tb{}_0NkSEg>W#t0+S2=<4`8LY^Q7x;mgA#(>{H&djgN z*aA>q_$Pv_oDu-zcYt44(NcnQToBN8djKIIyz`%1zMnASf2?Nx&s?H^?b0vAFPi0= z&Hyw*z$+o=Kk<HbX&BJM|4<(rfC$J4F*Y-Cve$Dov#}O&H88UMb?~>P`R_cAd^$`< zfS#)YxM=>wlZ5);c>Z33`yXzh-=X^o1nS2D&|(0q*Po$9(f=y+-~9u>L%+n`j6DLN z1OGp0EzG|P&Ghe2$OkG#0W1J)Ea1fdx!2#Y|0*=|zlXkNgMI!EIM1(u8~xAF;P`(P zn&sa^^GuW_50C(qLKJ|2sQz>rDT)3f^uGuGUE=;9*!h0!68{bOUj^@fzk<K32mgV~ z^7%jF{@)bv|7!{VEB>!3=6B7`Kk)IC|2zJFQ1JYn=y&z4KZrWD{u<Grw77nU|6Ky+ z5BL;={|*nB4E`(#^RMu~rkURh@BabsXa1Mq|GzT)zcc)v?)?XYRm5Ln_$~SScl_To zIRC(Ziuv#Of6C|l9s2i#yg#6W<NrJKe@M^!o#^*ulRt=%QvU+c@2Mxh!~dRn@CUq6 z`u_m`|4$JAE~4NM@T0Q-4*q9L=HF9i{<Z)A&c*x(1$X8DO7U+VDF4pK`Ugc;)&ENI zFCN$5zsc`Tpg(8~>;6}o-(5n#bNy~q{)5Z6>3`+=lZp9vqTdaMe-Od8{*Ofe7-FCR TS2tko1Nh1OwZ!fF_38fs60)DA diff --git a/graphics/AtlantisJava/lib/jas-aida-dev.jar b/graphics/AtlantisJava/lib/jas-aida-dev.jar deleted file mode 100755 index a698fcb714e42754a7e62a44c5934d5767d1aac4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3738 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 diff --git a/graphics/AtlantisJava/lib/jas-aida.jar b/graphics/AtlantisJava/lib/jas-aida.jar deleted file mode 100755 index b539738f665293379179708c453af1b88deb7d95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40424 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 H{`CI=ECbWP diff --git a/graphics/AtlantisJava/lib/jas-jel.jar b/graphics/AtlantisJava/lib/jas-jel.jar deleted file mode 100755 index 384f9eeb7a4e3652719925331a5f94fc0d1e0def..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33570 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 PKmRa1$BpKl{(Sm>VgE-2 diff --git a/graphics/AtlantisJava/lib/jlibeps.jar b/graphics/AtlantisJava/lib/jlibeps.jar deleted file mode 100644 index 6d049b27ce2c17e20455e390b0c554680c49808a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17486 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 O0^vp`28MQU!UO>Q&vP08 diff --git a/graphics/AtlantisJava/lib/oncrpc.jar b/graphics/AtlantisJava/lib/oncrpc.jar deleted file mode 100644 index 3910ab9f555e0a3cf6f8bcc3d2ef7fbacc09e6e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86081 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ļ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 A=Kufz diff --git a/graphics/AtlantisJava/lib/ostermillerutils_1_05_00.jar b/graphics/AtlantisJava/lib/ostermillerutils_1_05_00.jar deleted file mode 100644 index 79be1c0549dbce8d17fe99aa94815a442b81dc33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34346 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 diff --git a/graphics/AtlantisJava/lib/test/fest-assert-1.2.jar b/graphics/AtlantisJava/lib/test/fest-assert-1.2.jar deleted file mode 100644 index dcd667e53566009670eb087365eb064727f1525a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 89901 zcmaf(19WWdlJ}Dn+tx|av7Hm!wr$(ViEZ1qZQHhSVms$M@4Yj3?%etAOt0R%yVtJg zS+!TMUG=Mfm7F99C^XPtudq&i&cA*6j}z3NPibK#ej0HZ5jwg5FoOgN{bLp<M%{1t z=d$OY1NEQHr1@pUMT8ZVXr)E&r6(t(Bxz{p;3R1%rzd9`6zCV3c8?sWC8kHIC20g8 zAr1>w649x80d8%X5eg`h3W`oylvSv>Fvtl^3TR#^6AJf#u1GLBN_^kvlScFjuU3^{ z9kpZP4sa7h(V^9$1^Q2?fPnP=#dpv@PT4w`{=@D6Y4O+H{bgZd?CA7QX8QlK(O-A> z4>Ns7M`H&kb6Xq7f2@E6`fG*TO}LaUBoL6mA9Ip_vx48jLEoMKZ#&Q$TK(CoN>$wz z<pj%TIJt-)zm}n2@B8;&@G%&P1UWXnQal5zqG1_I2!q^-?=e$|?uXNnYMV4$4Nh=p z$my|8&gsS0W{{Ge>zj}HClAek-fV4Swq|c$Oa-#U=Hyza(I*?*?m5ryEw&HOzdz1u zfO!0I#2*I4h$4bmyr@a-(TmlxEk_o}!`9+c)eTh8OD3SaXv17q4K~a}BEsD=F(zR4 z?d3ytkYmv5KD@r^%H0areZ_~<k=?>}#}BIBveex>qwUDuN;7;Whnp&MkrmHWxbY9Q zD0_(xxhA~ech~GgQ0hqSI((y}2#rZiKEqe3Wngla;jKB5Xm3i*_~AHB-VV_)f;JeP zcmfB8r&w$(rJ6jA`BdpsJeXBo<{(dpw_>eW88DUVx$J~`kx97`(FQhP@7R8T*=(6i zL&j#Z@m9oO>m57lF;{g;l2;0)#_!toBsrlR$nC1g&B*C_L(kIapj2C|N2}4US@&we zH9*r>HV~3sJCStc-_~ESEX7)*msN8sw&vixKokS#r$||?J}#XWeI5Ve-lfFgwz=k3 z&et@4HRmvtt~$G6$1y*txZ2i&M64jQ>!RX(QdQUM+K~=t)m%2!pvoVyR`DH;W2Pgx zs>3*gvChE#HQs;Z>W}+|%gWc&SQSEn&Me5HT%!=_<eMNQ=h+t@ybfz^xfvuT@;>?> z`;2T+ueb4aMrzeeG$7kqKhU%VafqJK3X8_cXbSkva~Uwo7#dkrX#DIqp7v8K#k3i7 zM(EHblicHK(?jnj1z0@S(Y;b-dhqX-iJNu2*6k?L#sl@CtF1L6ly(j*Gr21|y5l={ zd9^8$I<bjX0?#7pXgXjoG!~E`m|SYNkzZ}>TFY+j6kI>%BaQC_YBUOpYLybY$GS&H zM=$(BYlU5)YfjHOh3n<2SA`EsDc&SaOOq~8I9Ooy<OUFKiQy1-`#^mv_sHDT2Z-6@ zd(q&?ZWZBb^kfDqTFdt^i&><0S%SNg)w31ibOdlnbVp{8U)q9oLtTG{>6*W=sIYVr z;>YZvVB?RVVEY6pV=szHHOk~&`34`b=k0bsc&*vZS5`R9(KR*hmB<f|;fw7`!}Sbl zLVd^#T;D>#*&bj!HYJnkn{yCPJy*Q_CKnQXgX2y3wS#$s#=t+%QB+A7A^)rlTRfw* z*?3k=cdFED4Tlg=b5Yu55c(2QL?IDom8FnZYqcZpQaa~L+SdDRV5Z4AzHQ(kFJybp z4)6M|9+JXZmJV^w6%?*}qR0^<Os-zOL%kx2Ct39nCfIn@L|!Mp<2p2>1vkcN&433I zp9#jbb#Q1%W#^z%gS$+x;gs(+h!|~zh7OMjS5%kzPNpxHub;+~Uci*K-uqERUsx;D z#BMC~D>bUyt3BP-yia{Ajg@vjIrRwckw$zy5B<m)PdtZ9^U=LIs@0l0X{KSYMfAs` z*_zJ0cAQWpFw-K`^Jbc<x9ukRl84lXH)ZHTZ~j$y#ux3DR(W_>FZpVUInPJV7B7+( z1@!Vt;a##NHFkf&wyW=Gg3Z%n8EIHRUDk)eMaavFU+Sr+Ss$V**^g$s$Y+GjK!>OX zm5T$Wv&$=C9L7=m<x9yuA0POEj5<SsK0#;G_oFpYch*UF7@punGdL}nPD5O@Xv=ro z+#{ji&W+mw7ggY^xcb-6dMvu^zTTxaqP|6Th{V826S$f`t`L>hqv5tiwE8AOwTYGT zb0n4fq$|tpFGyj{G&7f-739Oqn-5|kGM|*iyE$8brq0?w>>gw`xeYHCK1r6zQ?N)- z>_8ZP926mAzVVE(k3i-4+^y!!@wlR_KlEBxD%*WuM(K!h?tkJoSnjK8?#pi8IJMf- z@p>Hii4eB*hMuYRd6Oe(D=DDK)l?t{wJP2VEWi^f$`D<EUpBx+&`Wy7CH5=BJd!;O zN)a#@=36T94F!KrCLS?SlY9JA!KWvYAnC3^!6)&K=T)48m9F3c|2ZglkMi}4Ke)ou zV-#iujdWO!MIjGTrJ!Z6EBKUKW|u5=A!m>lHFc>0Uw&s)U)(}1ejKcjBXuRJFqouF zUz`#n_U_2CP)Nu<3!;z*l88e+>QK)R;K&#c!Vjp)B}N_o>Apc>`xPT6)<WEOqS$Bz z-=SXhZWoT8X)^4Sp7&k}dv0@_Pp~Yrtiw{7Fb|S|Z#$HMcgK|*FI@mZS_DDLy{-Hz zPoaC?i~9RT7<KUxj3{D$%3~<`1%`FH$;BDt*g(sca<a+Uns#ys!X~f84o1^P?>tNc ztNK3NEE^ot=}w?@%c$s8U0??Ea`+l(t#=XqmLCmMA40^aU&N{a37<ZyHAch@++D<~ zrfuz-lhm3Wqkl&10~VzcpO=_ZE-!s!++{z4S*^`d|2mr7iY60Y@NtW(KaX>Ch%QO2 z<}K`i-ilT+zu(3#o3Mk=R(p`-tL8Bv@dDzL(Ov~`kEYJS8ZmJVadKlMxL-Lss2*2D zd?;Gv)#{|Mf6p4aR?rue`^Ix#HUzl3<V9(RSS<GBOOkgB2iv#gl7_WUM#lcF@~EfU zzRjzhy)~mS;JEn6#kw1Ws89|?f%d)16iFp6`IN<eSu`+9wOq{Fr_x2)a0wNg;7wRS zxA-n)b|U9H%V{_1DG!vlgg^)IL#`|%mT})zhuRHv$9e_8CrSK9W7NNo6b8H~Lsqmk zZC14?!?Pe(W$Y0yG>04K=9s(fN04mYz^horA*IG(ARkAg_4&DS?R2YbV~kMCc7Jy6 z_;WpDvvNvUwUoY0luN+Rpw594=f(r=_5<+y-zujd-@WL3f-jSMD%Hg~Olb%U$c*Uj zm_A^`x7mN|{wEy$olrtvl$#JifPi|zfPg6eH$oA&akMiw{0nmaPAO4J6N(FbxL?f( z3I@4qI+VHcd=mWoIEf0vpjGI0;DdgeW+}B&QmFvr!3NiB{4TfKTnxUnxB{jxnlHFt zwhI#OKMYOhr+nTopFJ;9K5x&@*??B)3-+18(X`}|`eLC$RArI8wENi(ABz1op*B_G zdTYZ`MU*!Cw809XjFg#`dKtiefIVXx2)lYG<dJEsF|kPvu;NXmYU>;f={5FzO9Iiy z0o#Kp7|gbl%p_DtgwLVq(K_DlY_md%r)(8o(4prhJW-B?^0<SwU$~!?7Uw_@$eTWn zMyq6G#zR<fQFC_utZ|q@vUzHCh<;j`ftp|ls29}~`6}rDIlB0|&yu69Z^kVi04-&c z+Dx7XJoA2#q#$cV8>^(kPBh9OwBUdZqY^YTt7*qQp|<Cvm)bqk#n&2b8>rwuqFXWr zDo6AyQ}Zd@OJWqi5m%ic9+*W-fKAY`sydb=V!;mU87<P%%@+y`fknzdLJ+}&g)2T| zdWA8YV&jQPl^yt*R2S{FebMwZQ}@WjExEntSMp{2RjXh3q;trr!dG1|S2np@d7iI% zuq4Y+r?ulm;|O=fM?7aAu(Ec!hCu*lI}WP^h7Y+FN0OdGTTI?NuZIvV$GVG!0|%Yw zmX7A_OSrV8$YX6jI+?}}lxXrb?^u0Qh_>K2ld^{xCS4+oc&|K*JHgDhUX*CGHzNK_ zs0`?W21x=~Y=2ZHcTfYlLEVP9l;l%rcIlm_k0H4jlg8P{S&4?0P~>k9rY^np9ih}N zR>T~5Q_jwvqUU<WmJoGxp`thY(uv+LpN=;uaRp`tzm<%M_eXP)Ku!m~uS1O?ZVTC( z+9jvP+r#5A506P@1<Hq*ZAa2d>~Za_^Emh+X2n9%D#RNpYs87eFN~U1mH^IA<#~bu zX@Q-`0K(un`c@S}6~XfP9_6@`#7M34X)n<MTI7hbH|tW*G@8tH|0fv(xQMc0Yrr$l z^#ofmnvpqfftLe>fRn1AP~m4eVWdU&?Idfu1(7qM+wb0E_W4EhSx-_UxDVj}daVAc zIgEAAcfkJ?8y$bjiSPgJvHB<Gk5bZh+z>+LK4<@uTO@^(fh1{!rl>mr?U1IBn+LyB zSI7h(#V`&IiRy|@s-qzuqwzjTQgu6wBE#1MM@Go<bM;Xwaa9ekD!nT#NK0~g-flR_ z^i=)b^KzmK)N&IQ40}~_3!cpE6+RQMwv0FuE<#n|U@U!AHE|Xk4Dq4`pW*N(2d_JN zCio*UepO;GE*Pm2P?t5B0xO8NmuTH^l&+GXUv9J}I#h1AN#u&FKcQUGx(uUkG#g~C z`IKyj>jS_PksSGeqFZ*qFKs<oH@OcrKz^PqKBHxTJv4d7+OJRv5(tqrQRK2<gAeMO zKscvdqr89PX_5Z%jB#Ky<%CH}+(um?%R!Wo5yjz7{rs!Eu$K~+%>iRPAuq-H%ZcW6 zoEgu#j?Ped!p3d|E$Pt_d`gHRJU`nivq-B&xMF(3Kw8PY;|lyX6J(((&i<(RKqKm& zOj@Z;eW$XzoaU$V!Wt5-HJJFtvekLngT|QjhX0DH`vzfP-6%O_n2-s%)_3FANt_|c zCt!Wf`TjysvkfO9o^J(oEq(PPRD|8O_w6W@*H3$O<Q)+WI|@1KAtNWAb2~<2ORb9c z*s<;Q3H%#%>n`e6sr75YT+?7_r3W-xOANucfbRKQ7MD`feCVEjyawFTZmG=pumuj6 zx{?EFsngK`F$3KZzfI0wYdo0NGDC26JmF1~(WlibmMoVF<F!TZ4H|t%<9!6<J=a}{ zWv1_zsnK(dS_L@T<fzymYkBn9>ed5R?fL3RXah~K?W)eimK^7d_ABFzT9-d_Fh%;O z8MGq8cW%-%%SD8}`_HZGw2fQuvDv8Zc=xujf*~+KI*)16LyfA|UDa6gI(fggLS^T! z83cc?Vsa}vKMEHWJkzIIfn)C!tH*6eZU?+7*77Q^0-~Ur*uz}S7Q2A72An-~3E2l^ zb#4+AUwaVG^>$<AzNEhM9-Wwy{~VvuE&1skxt(%1gY=WjHM|c6-~nK6QU~~EK$~sC zJoz22bQFeCjG7ZTh*OY$du{7Mf-&@#V!Q&cMb@qa)sLd8#BsYuvlY`(+i(bE!*U1t zIDF@cYm~}9|BeN|3VkEy>RuRk&obp=%~3*uw%jN>a{WB#6r6OOOkGNWR{Wq{SlnjQ z;I&%y3^k8urcWs<mXEG}|6}qUb3$7eGQbN9I$$;N_~G{08#OVT$T<+=S$rk~<@9$D z=;!K4ie@(*jCQ6@8{~-sM9RSS$70Al7V77dS1Ixktk@4|i|&BE+QA%(Ym6XMw>WLC zsgVR-g4k8etrpI4*BT^nrS2zO;uz7IOao@>mldFi@4rMB-y&<T;`Q;DJ9Q`2KAsVW zZT+B!y<mfdSvsDP|0{<4B_2Q;Jds=ei5&rdj(?k){}w}p-JFbV9RHD;IUj9Tc)-EI z1;Jfhz*StpSw+CBcR%Ly50zRbGnGWZkw*6S7xR%<!s8b^_a{HNx+(|jg+#!QKJuMD z8yEMHKZR<!<cie@q$!94fW+#2WDIoLyMHRESU5n<I*EXjf<x*V>4C>f!BYQ2Y56-$ z6dtnM>-~v%RDVJq;D3#Je`zIu=ZK_KS3cYoq~V^BSacdPL}4*86=7rkqeT)Je;Ph^ zM5XuvcE}QHJAcJ!&ZDc^LiV9Em-Z}^k+ZM^B~2NI_#}3jn5?S@c5WHR{Rj4~@yYE2 z7h9L--jBYH4YnQI<0;Dq*PQ~_EjYc5b?aSL6zCS!eb}qrp9Ix|qBrs&1WXJFuGp!J z@_r4Z(|fcaC(=s$2jD#V2EbRWH{vKuts{daH|8KY4Dt~(*e{u39$wpn7&pQo&*^HB z@33BDLd4xxyHupfdllf_CI&ycZT4|mcY4{REBjkuy*381y+(Rnr7MS?rMw7u>2G|) z;9m0l2-3`kW28Sod0B3lP%>^DQ6O$$zMgaabkkSEb<<v0d<=J6NL_XbL3)_#V0zeY zYQwl+0{nQ>TQPq!-k73Py+nld?AwBW+2rHJV7`QeN#4qW{AQf<`<Zb%d<p(#xZ4Ab z#JQ0sLwZ2mCd5%xJNApyM%P%B%rVTUkql#IwauxxY3+Wt$wry{S}JB3t^6Ii>?Ln3 zY|pKD2VZ7BVZHkyGz+(u3F@nwKn1`om&Y>-cN-sOC8M8L(h`#`Co9Ns^AKikW(ZVP z)zj0IB@_W_`u6&vW<YIxLdsNlZF#<v!X~+1R(HC$cfj1f{FKXec+@wRDw5&CiZgTg zHe!uE!ff0>9VN<%Y^Z%3HyD@&5aM7$=SH77&UbhGX2cEto)sdLVH$HtdI><_MJ%k{ z=D-$^EJ?8EROTxyfcB)B5o_XCqZiP@$UQt_WDa<j8s^dVO@xz2e0N5C8q-PyXF!i} zk;3OhpBWVOe9;u+lF<cj%x4zJ8~X(rcJ4GiR0<z-Df}aEyEf1*2&PCRZw;IBNZ~Lq zK=1;#`5L!{$tE-l+Ow0;fvzgtjTA6V^q9|=hhjx>LbNL5N-{zG9aMpyTn@WGI(B&X za<M<d{AaD|Rc6z{WipqPf6*q1YKNyC``$%-=?!1F*?DEPUPbi-AWQ#B%a!8dY1+A) zcQ6QX<;@uyrz&s0dPqtUNYfc8%&CzR=~re4bbGl$P`^e6r%<xghK-I=OTWyuTh<kQ zjPN{mjzr!NHszU0WKw2Lori!-Mk3ibJ`#!Z@QA>3j;aPmu0m~P9<q&a;$bJvp-lD> zxEiig!jJRU_+H7YI;(2Z3O1w95=BEBaL*xzi7tJd5h^WmmgzC&@uE?knvU!&e*8w+ zz?Y(I|7s2L@EH(~`Q`mX+Y+=JHxsWp^p!`ETFM=))}f|o)sb1lLA0Y%TD~b9cJ#>5 zs1l~^DkK!mfiw799qOvvvP?Lw`Kr{-R54@f6!F073NKSV%BE-uek!?i3_SLvh?4p} z*X+i8%7$4<)m~~A$I{5cDFK$VZgq-v8f0e9d{$f9w-KhZ1ecd1`BMaHG%c2-T<b6; zq7|7u^(hdgypv%R^&n-E{DT-RsFC@Ev^aKMsK%nrYMP4>^z07j%&;RICjaMsZ}2aS zzJgZ7yvHI~WpsH*r5`k7Yl)Mfa*k*!Gir17dt8E8NXmXNO2RYMfyPT-K}k%grB)^i zaT@KBMiml*!bBE+<@p6p=tabm<$}F7TO%qkaLOq1P35$p)Z<*qiy?<<`0rL7<N(N) z3;hak4KgNWTC0{-IZ2{&d72_`#tMxf;Ryi&J1Ugsc5<U;t|ib68n(soP>nK`phG@% z#7gz5+D;?jUJ*;!B~*FKB@RkflkQvfIv)Rtn-@sh5h1mB7*)WAEqx-I{8TxKQSngI zXnYi590n}~>pCi<`!;9TC2NRO`gOhj0S)28UK`FTwMA(aQj@ebLK?g~Uag6!Sm$;? z&ZSH6p?GGfRXdf@x6Ot~2~>B_`K^7ra@0tBPET?l%9G532Xw7$hweqqDgI|$<y%ki zu!}i)j)DM62!EE~&*@%>X6M8V?49!t0VDR`=Djj9^H|&|y2oQqk5Y7}@J#_3<@+mo z?f1cDb6nVFA%d5qR2*$(Fm8k-YmnY9##zymb+)jcw?@gom!|C(hoVdk?oL7kj!N(Q z9v6;Y>?bV`En@_K9T#hKTFfrFL~5oiT-vqYr{l-jXusUg=u*TKkIX$BvUCxpb(&L9 ziCbt1*A&=ES$Yd!@{Rt=J%RH>%RgWv9X_$5#@0>NTydPd#l8QLR^58~8Xx=15U9c) zXlu9Uk^a?65X<9qV`(v2e!~gh!VcQlo92XGbdPk=x=_~XAZK8cQOo{3D1<eeu;IsP z(QoC&ZyEA_G@#M@P!CmvG5iGZ3Yvb#?12Mv><Wv|g91AVrF0@Y<FhfZPSfzSuJC3M zb!biZGltuG6R43)(MTOxCr%g6o5FV@t>0u_)+ZQFA(UWgv--WDR_TC5S@gs}TrBwl zfoWX(Vf7w7Fp&(j%CKZ_A>_vjLdE!`KyQ`c+|mhZeSwvc?TUc7v_Y(RbJG`U<-YBI zqpt)e{$f^g#J2c`Nf8$;KNb2OP<kZ4DBdfMG{^vlc@Of-9W?^5iw%sq;v4uA^^q$) z7--np0Cj}r0PE{J`aOBFST7t=Xd$@NskBQk7&D_@Sx3^HZwA<R;mf#uGIP_Z+6@%= zw=|yzMiE`WTnprbJ^_a!pDCVGHT{Ky=?=2T>+TyxW$Zw=bS~LrZ4KpNw-?9r#E)kx z5KKj)XEK(9MBe8LH?InkU3{cLb2ztTg4$qUX=J+^AgwCknJ18C`0BKN4yaaLpzH$R znMb<5rp(|+;7AA|?CcV(m6w3k-hx`dE<e)XJ<Beb4<D0lAv%<s8jwyYFx_2Dewt_< zgYRu9=1>I70m;{Q)?0E`$zCv|K}nWfjjr{M(vWvbjcJ1kb)g}Hk`*ykUH-QK;fSmp zEmgG(I>%AEXS%1V0IK3z>A+$OA+ws<ysr74)fNYzW(fM^@Q+RjCY{Tf8TjcL87MPk z{!S5)>gOEr4$N9jQnLi0&0S779Zj*>bKHmX&$>(f2OX>pT0ftF=*uXd-XYjkGT_T^ zb_L*@hY*c-$TkVS6QH}&*mey+p<3=xxoLgvg{0;(SPp2uzOTEZrik_CLhe^#->~xT zDu7?4`04|@b%1vY&e(TsgBa5|IMh6nPu$3KR+u@wj&;B!ct#9(#qgHG!<Q?9J9k0; zQn8qLbtQre{grzh-+B&D*gZ#_9r1hsvPkJQTlY5m`(Nr(Dx@?8Uf@49={F!C%6~&> z0{V{ThC;@Uh7RU-|D^ZGNz3;0A$n`_Ko>z1<z|0`5`v-N%wQu}up@EnwbB_6krc6X z1nm@s4G#wJ_7WIp(g@`{&}VFAvE6THjCpx=cY(0?MF&u`MvUf~6xbB#8%E?YqjJdI z5ysgM%3VgkM!plqi1^USGh$~k9?lp65*&lupIbJ6F&WVv<mr*S8Uw0J68z*^ybz%c zF(9}u97*7G01abZi?CBRl_FnRvtct$=;N@tpD@+Nc1^fp>nA2$neo-fO)AnS5Bp`% zLZaB$Z?>Ox@~z~08^ZXk1A9N)8I_W=Y`_hX0I(euiM&EsHA^MJre-tDtXt)0;u9_8 zw7Ft6f~A71`8(!4{!KADdfY{s$X(}!;7_CaIWG`)P%Ot*mGWrjMp{@|jFd34yhD7| zpRnh*8?-s38D&wNWYkuetO_cRF#jFxZ(vSkq`-lI?lJ$Dzroy8$k@=_THorQn}b=& z>aGhSs3SE3xFh_0&;UeeP;yBza&U>YcuWE0cwccKGI&sO^5*@}_2jt2#MvNPr=3$B z@~u42iM!bBg^*;^H>h>l+3uDa?k?4MV^M6vA7m#VOxbDg9Y4)Yu1>Fh_IyACW$d}Y zSp_=5aY16mQ-?{#6aSFRk1YjgKqm8LYoGvP;xdWT06%2!*vC)+vhiHP4t|H`@up(g zB<|6N28h`uzv*H-#qN;DCIB_Dof3E0W9I<d*iLbWutS>o7V&LD_mo5K_-An*$o>%i zR@^`;T%{&)b@2$h*;!O>VkyYI$lR!qXNfXe214UNr}H;<h@>nBg+o0ZrSb63*U8dS zSm*-ti!_2H6afxea^z1|PO2t*@gqHJB^8A|2Kl9a|MKu~(lPa>z|B0@=6o>1yrUpy zh({|3TqVfS4P$I6m^CH#VhRP;rS@&x=rwV9X>x^V(pYPVv2;dCQcikJT@;ip<-r%( z?s=3Uelav=al8bf$*qCuEeg{F1@|<;FacPID114O-wP^^jH+sLm(TFlhBcaju!Dt4 zDzkUc3Nr3o$yCG72h-By`RjC+44>LE`@?xrn6afX0odZ)fQnR$Z&S=Huf+yhJ*mi% zt(4+;NN89&QYB9(3$6AQBrK#xLhEcuEry3|noVxBWTeatVVnw#_`}~JjI6bk9tO8e zZ#!Z0p>%TeKef!@FS9NZnSS`OvO3dIPS;2676=O~<Kbf11x&^*;tQiPb8Wp{gAMfo z4~@(7TC1G-auHI7Cki>W<d2T?N1`dbjQghvP$_r>!Vx$2Y3az=`#(BRPFvTH2jcl} zEV>4rA~oa_kx*YXj{40pwF2=FpKyZwP&=q^yXbp2(J;Emtxi*h<uqxEuq`;&T#$L! zpj|n*AQP6Bnx=xX&k;H*nf8%lMNSKmzCl8$vP%lds*TVfP^9V~AiJSJ$cgikxdR(Z zsSOB0VxJsfh}Vy|w95*q*|o&)CVWjk<cz-#`v4h>0r19ces2?ZfT`YBH{`}cAPe=( zJR~0zXGAYpCX5FTy+bTnMil2vvo4`{&kG3QiPwqe20)nK0mu7<?(e@)e5YNwupH=v zt`R2pL1LGo@<Cdxi`K|=iG7Y9HouRoQ@fqkJZcMIu*zeYH?Fu_5^*IkFu_Ro7^=ZN z<6-m-nmTP9f2<_+zXd}Oaj!B=^37k07qHr|>{qp%s%=k3wW<xjsz;8gyj|~it7E1k zcao->g?kDkS#qNw&Nph6M{+bLBy<Tg6yT{!Lbq~On;+IE@gcJTh3|i%!3~z+vdp+$ zLH|JWgZ=<1wXk``YSmmV_YIM=eAsS6^mVR9(|jDJcEfB2KCQZ}1;N72Qb}mqFapca zEY8h;Erwh6uZ1J2%>{$mH@98TzeKlEom)knq^vKu%j7v-D~86U#-&zFf>+#_U35`Z z?2uMON-p!=Qp%{H2ncWn8VPl5T~tc4u}}#s(_vmZF|eR>A}WX3=*&*^Xs>IMWm^cS z(s4=8C7wbo4x3?@Cg7BABAy~I7N2CF@^MLzC60<TcVLnUNLtf6pjj1kEYGkNoI;&! zuDNsP4(Tgnb+l93Uc2q&{vu-P-l6e{=Kexv^63rVDZge}FHodksoSADIO|amD6NNd zE2@j0<bv48?mj)IrF#oiM>Vigs{(NW(Pz`v3m~-$h3l9BeuvX{<;omdt9^xE)eii; z+OtZ9)7<s_^sD9N&crhwK<Ci=NqAw4u*$$%ISu>{q5s>1>lhM8#WrLw7}_oq;({Hg zc@+2niFE|T#UD=d!k0!wEdb&I@J?!J*PBdSIS2Lxxy9FncY2WsWyz+Wcbv>wYXp7O zl5?t{G%66Z%M8i!tCh;aysZ>THL+mYJukW~AD3hX#(5E~sZwjPmTFvHtV@pU_D`?u zed2nEqU%XEgOf10g<wOW;HRWGp7SVLQ@++BP$(&-l@2CwC%sBN!>~3IJv}C_>tkKH z7J*=ODa5#N(*UMrpUS&#?G}eAS;oQ3_Wgci1KVu61KX?&>&UJA#n2i81-fa~PnnYG zGegJaq=_?Q$Mo@|3w_7sl!+gZ2a&{c7uRCAdf+WDFjuDFwl_$T2g9P3pr#MMW4;jn zdrp#%=kMl#00I)k00N@^cW7X1Yh|o&^FKybvQ*zyQJqnH1}ycnP=Rli>r21W4qK$j z_Qs}UK&}!|im_b4(>G35GBp4!5GEu%dm0;Co@Asa&==;X%VbU-6dxfLXC56t6;7Pm zT}__)rd`*xcQX-oUZ<bmUpKG2o;|N`7JjPMfb?Rw?tvm~UI%hOB1a;Pf<p6$>h+)~ z&6*XW1VRnt-S83O=I#ZexUq{B2!e({;RD=4clG^6!x5v|^#V}vgGS7bOHuGc$jlx9 zQPFd!?0t%$vM5}FH`INOpff0)d^bdWlAv@bodS0LyMVq5&>EynhhB4t&S`%BE`X#5 zF~lp&r#F@7k5NmNZ$uD|902tT*ciBQix_&$!L)ezAv#b`Fy(wxOGa6OIA(YY4piq= zCV)k|=q$7R5{d9KmnIqsIkZDUIW&s&@Pi2|>W7CKq(kh&PRRG&tGD!Md3~)LP%!t^ zg9T-A{OwLg$6<9~`TGim(B#-O*6P)GeumjVkBznC=0WrNxEd+RVg5YbIA{KNc`vlr zA26;_FnzV5?=R%SDY%(@BDcQ0nDDb1ZLLDkknN{S9B5rkxI!oB=Ki$ig2-LZ^)VZj zqrem!1L&^>9qgrIf)o6&i-~EF!V4yA51Qxi@7Us#WN;Jy_$u}z(aa(A%|`aIYrw() z*H>8HJV8hDn0u0RL1T(530G<KMj1oHb2YIXdNqw_!|G>pkxqepT?`ORaYyL~>25w) zTy_!ADKfmlhUI0qhS<Z-QCf2zeW}93Y?8DQ#+>madwJy|Ae{geW#vV@{9>qq(ml+G z=;RUwOVuPha?%7xJ(gjbAi82&?VMY08w_Llq>qa%?SO*QI#}1_RW=8?r18zdDQhMg z$T1-rrVfiSX5~p`DE$`N(1nsf<(^g2xvX^CnP`qXD1?eVxIg5V!DSUF&Fm2&62)~9 z*x_y#!~*Y@5#qY5jX&M1j=xRpMlkJA3%F8hhusPXoae85^wMc8HOmknX%Eb|l6OQh zyHE&L^Dn?p6-ANn>GhIOwOh(LjfwRRK->^w1vYzu65QWF^_760Ku!;U;qwryApk>Y z9qu7}O%Gt$^#P~2zaSHFN%f=QcjwP3w+;`iIJMeBR->HbuTBKSOtbKrZb3+MJ)k@w zKOi#C&f%O|vo+q&3eSqqf?wh)nY!H8eiVfvLENjYZDueNbP;qpp)8aT(rP9vtWsGj z8AXmBz9!8E_Kmg54=bsq_-Dh5GmYnoFX37$7O{*)h_xI2Vr)QD_tZ3mGvAKQkA~tv z?<iv_Nms|fy!413JB@g*Ei$J=*HAU-HWx3y2s&;|2{&{yQ+f?LR-6gVWy2yMfr4Xh z3C6@=P*pqXV!!%6@II>hT|s%o52S<Z$^D~WogN^@e=X;zwvfayfu=J>mhVGyE*3^B zm>*w@dx<+&+}8&#BBvPaUT%qJ6g?+@J}*>2VUeJZBuruxZanf~^lTN;T+3xedCJR! zE!KdeZZCZ*i&l;a4ee7WjEmgQ?>)ZfD)|Pfv_Db~aasZ$ZLp^Xg1Z?k8x<SS0|a)p zF1|~<M-E{l>V(~}6pKKmM-x3hrECXL$)pBdTW`e&A8nC0)HJm3&}vB>d(fRKq!M9N zfjo-KzzDHC?-5W*DAG(}qXz15pau4l{Z*!igLc$cKgmcrW3tG>Y~d|Y(5xoHQXe@k z%UaG;BtPf~dKE|-Q8Kbm;V7D`$JT~F)$uI|iCm(#7W59WB`-*)@rl-JJ3ChnU6DMX zN`yL^&k-D2CZiu;X*B}c`(-mnB##6nNS!rEUkQ^R3@S&oM0qri$AZFXPe(&p<DGc2 z3;aXJbxay5l^e>@W)Q`h^^j=1Rf+#j?wh-LWalE$Nh!-7C(%w?D#lRoP#cuHJtPfJ zCJ|k;J{Nl=#4c}9CQAdJC|<BUr`_UMa++nrk6^|TQ|g7GWQw}6Oun=PrsOk|iNtlI z>D<XRtchLKM6{PCk;>C_VfwE4nu{NikM4p)M&UXv(cP+;u=iH538QvFW3wod*T7s@ zRaH*9!FRU$JjGA`im}(-p^-3K%wbFsM71v>3Y0z&LpR*V_XtqYrIA1KkzLfwRynH{ z&y314uoQR;7U{?zEuqV{l2Lso*UI<yAvX;iCv7o%cN9VGFqR>R&STcNiyCR`;y(S1 zeij3mXf{SjD{A9DgN%Nb5aQ^$5~W045CGoUz}C1I`NK12O`q4pdEP1++fG#r$={yi zI$}p4{D%(e92f}(+7qP>iw(QQ12Q1=Vwc>Ljco$mQ@wXv+_0&$iCk$+G(eMOMU_zt zC<V%W`ImCy%PBR>v%WKGDaNK*dMK{TXI0^GQ<SL~NiG2iR{Aa(;n&iD&xo+bTqY3X z$%1hDshDK&;jD2rU)MWvZM{(R?%JD9AF#N!uW~i5-8t2}s~Ar#3?H|#P~m5?bnHR; zkk9SR{d0N#SIg(+3u|TW&ooBrpUGRY|04(gQ};M4Sz8fD8FS<}jzDuERihX~co3-^ zY#GU8kwC^eE11C?svIJ7(=={83VRkw#JhjjtmdPJ?L##|-?ZBLt-$rCT=dKubw(g} zTw}smg5xyLyXW@IVb0IrA27X~FC1Y=oxHxP_AKK2AQZ=isVV#Es4GR}0DBMuQhSt^ z!>49cVTvn2ov(14MtnYCNK|2Ssjl+C5DrSkncKu-ma?&p5WBytj4-=u(rSLjU-<w# zcs##PwX@6G#<tcvK_+-YB`Gaq65W9ScX&&C&n%T%^GT+A8jo!TH)Nx_7F*^k+Bhwf zCHzaAUobN6msayfEM9Hr7&hmt^9p)YR=<>NO-{9aiA99>t5Q2kUm)d1rwTx^s4~7| zwg18Fhc{8k9eF0)MnU3(u`#yuUSjImtPdZ%<c?fB8#UZQ;z2fb_I}Kh`_d5$T(F%A zHJi|b<`r!VOQZ(GX0veAH{E*ciS7}+kjq$Z?`t#XsuQJ}H3Qk!ecu*~$J6lO4!Vq9 za=JDfcbBA;z#R#^y=e(DxXxg6kP~`~-ETY$^wCglloLyZe$*zgn*)u}Xdo483%6x{ zGqpB)AUQazgUNn$H$~Cme(x{iy&zC+)Pz{CKHw-yBPfcpRhxob*wbYSlEyi|2n`F9 z%bE0PS1`Cnnx6c}X*ka_M@=<1dzmQDfSI_vHA>1Sz{AZ@+XI)kF_{qtbPh_ZqB$f6 zygUIF8wh9igdU6q>8#o!duvLw>c%Ba(cz*zulREn1IoM))6;lklvA+l7aK!Qb2*dc z9o3HC6)BUD-KAE9m_GTzDWOkf51$j6%O3)#o~2ceB08tJ7A{LilkHsNiZk2;ZG6VV zE_^iL2xSIh^AlFgRRtn>_!ysIHEb>@3}nqP25<lnbE0=dXR?Msw)&AS1=7}?VfVg0 z@k;IIM?zqen!t)P+8jc<SI>y44>2cy<W$yF{C=nO(ME)cz}j<QYC`>6bSnNCzav%| zqC<cHJY36o*;l9{n!_(2)so_GC8WwSB+;D4F3#m+ZDOxh4%P9|$DC-qf!&XXsfx5+ zhp+SnW$3-klp?5eB?4Zeq1Q=}?RVb>LCPBzrBA;2tS;&%Wv&oQ930+pK@1<fqYnvX zetTE4_<SekoqsE7_Fd5LH9z!UZbePkC@_iFpkUOSeNKYM35cuzkP6gYKP`*R?%x3Z ztZ%;!CaTpf8}4x~yREcJWfJy3QfA?C>>NJnSbUM_9h?1019oC{ok@|yRDCSuaRrbO z!CSeB7-sqN3;h1)j|caam7mwV|DDXWN12CN|ByM+A2R=UjbH(HC*%JQmY=zzD5Lf) zuu9{IkXx@U6;~1pe+$2$ak0&9)RRz`STbj{246^{XDUOr<CpLA1_5)m!$3q;1O=Os zk2!e}{{(qx@L8twh#v7YC6#2d6_fCsuCd+je16|@z4m^V`T2HzrwpV9zruy+`_5g9 zY5+O_%IGJ6NVa+ojK++81`6em#Kt8D{%*$p3mE@t;S{Kk-yZ@BpU5qBH_jnY&_?aj zPjrtV{l|sh$Q~3nw|D_DGl#?tYTp9r3?i504Q}5(C>>&_*bQ>u1ZWK+E-|~z4P~Dt zDA}gnJY0>VT)R#@NtYi;N==QqJskwel!VZso<s>CLOW~^SpE_T+<;witt>D|ttMCE z!Ad&$R9^f*kG~`z9t>Pq8UZq$w7k7=R3q112?Ix28Pl5icsVZ}aT!G*G9bU36co6n z`qudhNhFX@DmLUBp?1<?o^u3DVFoHvQ!VAt88?<0u>>6!B5@S?@}41Mi;)@ha`n{2 zAiuiW-;ms$p{+%ZE()?PFf`+3@yq51Yq-;Xw;eT79-E?l7%GwzL#Z=`hbmDp56udw z_B=R=$IdX1Sp$)1ArxK%SLS*@zcjuKd~wW7+?*Sw?6LOG^SAC|aAX*9!TMY>rOi5q z8K_8_plkyNA*3;R!U4h4aiVdJ6d^})D&x%7QC0Gik<}#*+!ax{@a3-5HSTbv;#SP% zAxQ99tptw)<WN5lSEX5jc^|H#84PNr7#O0a!k|F?I0g53Bm7aX^y<jaa!O(PGfib> zdA5jjQrJ9SPj;5{Yrs-9Wtf{rvDpqIY)SyeFrBvY&64$BNZx;uwFTlis||Kl*=Rd> zcVJ{QZ4#mx_xtSxxoLCtalA-BWva4P^SK{I0og*$D&dq;`J`}I!2uFsViyj7xi5pO z(y!?+CWqs)3i^x5k8J*f$z}S?|HkApj&_#A1x^sn<nfge7U$iyW@yVC+>{<6g-G&G z*iaYB;9VeQfyYbv5=7{?<Kb6$h+T|V$9o_zv6cLSJpM86FM+#?{!E~zd$<TWNR|Gf zIMerbz&s~=FzhG65nNtS;`qb6$OyV~r;J*AdzKt)Y@n)P&JY)eghC;|N&>EeMeyGs zJ)k@wf1PbUKDfaAVRGp|R1SWbx(T+)M(yG*Fwn=Wg8Y0uSyC-br``LpwsNkQO^BPw zLP;$mCDAY8wYY1f1u&${ldR(_Da3l5DYTGjDWKH7B8soZ?U}sbSl(WCx=v#)EgkTW z2D9-hQy-;<h|K01GJ-W;U)t<^hN`My-Dx~bykm6a5MyCrVIF^@zAq!AJdGMQ6;-LB zenL91I)<(&R5ijiawB+^6fQqxw=-lL@#&5TNDJ^sg@I=!W7fuM)<RkoAo{gZADwu~ z2q>2tEwhQUK*g;z0bOF4JkUNTb&ULKW0qycR%FFOmseseR&$vgb(R$^w@%Wd<NtkI z#+NQV8g8kgSuQ{1CIuNmv!5FqdUgQcqdi|B7qOEMoSOq?hgmV~u)FKxW#LQo0Y?6~ z5(VrEEGldVkw22E4N0p8N@d5qr3L2NFA-3LIx%i>xLXRXp@l<D+tNb|CH!^&!^l~z z84xj<Me1mXrfnO$R5G?~0xKzCA6$XDv+x_%sz8BDEmmD5X*E(KOr*+z*&@JL31os? zwOalhFN!Ez&<=xHgNqwowuu+2Xk+ZrY@38!QoubqC`rzL)ejwfZawOylR`3&qe>1= zT7(*&-w_xZKcgRBX*CSG<ED)+MnDo6I>8EBuoO}F50XD?spf@ploriKd73LLZ^h6* zLf>$HCb5y|-(gC%C5tbP$wiVMD1eO}s2?hu-%&<n7IX(*hk9AM=qO>LW0)Qd0XM$n z3hFrNaou!ajdUWprmqDS$PAQDvHvodkZKyk<xeYMqh6RwE^8da6-+x|qizVIQ8Z5Y z5yV(xs|MbaQ`uWXZy>xv9d?%FX*{D>IfG3}s`#ti{-Lg4FV(~lQ!rRkDmdH8<N09B z%)06~k<@Q=6FrL=E@0Z<?naqMCE}TBS%E)R929OjOMR~ya(<3F2wAWHiDgp~L)+&P zS(8caX@rkV5}*DGJse`zErmCd(<*Q$fIajKL!SYluPek}Yc+z<N;>Q3)_ISLs0#$Z z`$F7gqZM05<*>*TM*L@1NM+7eSSM@!&)5rHh<eY`043)9nX4u=?+0~jo4FeMzau#r zsQ(a3t;2kfe%3@W!@`{L{O++2rk-=Qdk~I3z6o0(O}0lw$);{dT5{m)N&%&;ViK|P zVD2x+LJfNP@~Xd(TqD)e1MgCeU7phew+vl6u^b;<9rzv%zZMRB2K#SFP9V$8>4z@M z?6+L&Znb0l>ejql0u(T!%Pu>+duDRKD4kdmG1Xv{&t+|uy+Jw{&|tzAxgUc3xpn_9 z$#+}l2U^;nNlqyEe?Qaox8(cJJg&UsiXx2q#cGX$os1rVTG&(s#sHU&Dtu~tAxj?I zJg?E{+b&IZwhYj8VJqUQm>F;I=p{HQwe<)by#*%V9wF0xn7MVkHp!4qP-lCKrE`6n z{_N&tdY=CHdZv>F&K$5o-Ac6-#-J62s-~Z0(lT}nAVeEtp%$tOCBg3=TXt?vUenNb zi_lNn1Lxc}aSPFp+9MsH3EqIcX6zif;R!(R^8h`AWJP7JnbOf!%9WyEXSPPA)}&gk z(5NO)Cs!wjv^4K1JsQPafNAIEN2)9HQ+~@}WexOyO4LDw8Tx3aS8aU6^*$5BGN)-N zPveN$ikW&UwxM88W1O^NB&OypQ%|P1&H^MTK3g%I!HS{<GN-%pB(KlAG#bfJ86`|K zmtoWwfb`WtumvWuK3coj6FK81QJfnX#yb@oD$HZW6eF#5^C5#(wX=AJusRIM*@e5% zr#||wZlRlN&JvcjH|eb=y`T?lqmtsK+Gw)|nJg^ZS~TvK+7tyECqZPrXGWNiyoIt= z{IXPQSq>Bz`B~|=DP}%a>!i7ZG_A*P)O44-u!>Y%W;<&$lU}T^Lrg&<87<~BgKhI- zmm<Y|9qP7J$62~N{+qkWqkDm;f=0EmW!t#GtavDMx@q&uTG$^We;+k4+~=X(4GIg* zKGT?LLPcSSR0y;^oW={0Uq%=o3=O<lc~gJFXu@E^gq-n$K68MIl9pb}sC8lyMJh{g z8C3HCQ<-6y{+mR@$qqs^WsRS99xdED5|}hYH%Rojj6;$u%Zsns`fX(K$uZM{@C56f zP2QyDg#XJ1m(Fy~xM>Jo(Gctso$HJb+jFi|ZTq*f4bJeOuIzP7GBCj<OEs+>qGz+u z6yP=O`N>x*F|qTtcjmT~*aY~YCQtWPaiP>Qvw4mVuAD+iPp+EIHqKuIXQ_qq&>qrt zSqt+9B1Vk{)7veYY)+mi-VbU{3&b~E0_=YH5Aojd*+Gcz9Id-!Ji#XAzZVYO{X`rO zVdj1^e=#Mxtr!OSI34E@T7mRXn3{b>m<dNBo>I>g&jIzY89j1RLbJt9xQ`u04$dUc zqW;bkz;xz8$O9WtHj0B*4@|!?4xyGO#IYaims-BC4;n+zs@jKAb^9Zh{W4Wopm7%8 zDlD{lC1p7!O-dv|tCps`&QMAVxq?bLVZEfE`4zz{P<l>yf<`AF&gJC~qW$3Mzl@yU zvy3~gE#aAR;i;_PjaJ6f`3ryCouCZDp)7!;v`K*=eo@ru=LPX&I+b&u=r5eMMZ&N} zGQcCn+A~NY?VFf4Ns2{+n74>RPQs_K?_zAsVv0kVOW0xy;1O?a2SN<)UCf&%g@Zco zEvyhf?vtG_9G^hdBKDYEhJ-EYM#`Fm*V%3H4mL$}?^zOkOCIMlgV{q1-@B0Y4Z-{& z@FUs1xjOH6Ver>PNgmzprJY;+s7?yY!`!-3yEnGS{E@hx#PGrz`%LZtO3MABHa$NV z)N6b6=Zf>t5tnm|9pVgov37Q$qEBu(?OtnUvDZG0F*Y=Q0yyuA+D$0)ix5bk(F}Wo z$-k-%^L^w?%>PGSA!w%W@IUJc6-zZ#V^kgxYM66S$k3K}Vd0b_EgDI=KC`ygAYU4T zaHWAOAj64C4kpRmEov&dEn6MRri<#d<f@kWFQu7<nK#Xz^Pi6`C5|R0bQhDg9liIR z?^A3$&)p}SCtfF$bicJbfPpM`i($NOQejm11NAcb0I`typq^Ua0|bbZzKhWB1&&DS z#Rn_W>gm%(Jt1-N-vItD<|~HR?m$V?x}j$mq=C@7;p^niMKE*xy&n*b*eP_w*hd9g zgWM@{!_kKWYKz<{e8bwu2`UN|jfCsk4@K5F!FMadkGiM=j+@Q@a{vfL*oR`0Np71a z)JxXND>dc4Z4Yu<$wiWoma%v28#hjZ@UPTddbu5%v4U<S9eMA}{F{18vHbn}7<-2d zYDY!u^-XZ40|AT32zojCQ_)>J%Z3t9HnzT3qD=N*Fy-~%qixJa<7{M7RR!u1i=K^g z!^qo=QW0A6R!w3^96iHHO)uLkrC<{S0rE$nNJ%)OU2Pub{t<(2n}eiJ&*5<tg$HDU zacZgClS3o|sfw?@^TcJ`b&zk3N_$HDSV*VdC6D}{@tEj$946-EbwPgX)S0l0QZsR7 zW<;{dQ=QHSxjjjP{{5w+WeixZn>k0I>&aTO^61HK4oY(Oi0$>h^~;2_xZ}_iWYrIc z<7e|O&XJ-^6jAwx2qrE)g+UbKAxb=vz>6z@ZFY78z1|<g6#V*h+4Bcbhvg%nu^Mvz zo9wb>T%xlGg}h5*D4o<W`ciN3>dA*Ro%wbJ<h!`Ck;xn4&SMJH>4_AnT2XuTxBU-A z=MLTN+MS~l0;3+L*Ecp!s?nTOQ#f@Wt7#c^YsV@^Jzr@;mkk{{Y0S&UOf(n6U3Oqa zskr-`VC@o1SY>tLxc&VWZZSb{H#{&?wb>$M=8NO~DsHhs@M;Hviqx6G2x>2g)3rB9 zeIs_kek2qz^LVETpz=pY(PN0VsLLYGk*+b&D4nOv$g4C_t%7EO`zphQYJdxLk|plR z4&lwI{y&{-^?+b6@SKJlus(HvM^N2<cl2%|H3)q&ExkP=uc>}EyKSfxwHNe#YOP=@ zYOSI<me%QhSEu@GC>z9c!P<bJ?|2rW@a-_`YM21b@26yDd5$f!8$725c`3OexhU=Q zZH}$BY8Ul^!G7*4;#{!|Ij!g*PQVSOJHAow>2`cdrL|@Z6wu;x6j2NNMCOVN%Aqgq zV8RtYIg)tSqRY9`{s{dJZ;V~%n4X;RU8dWifEY(g^wzT?lOW?CwWni89ES8u)yXDZ zvS!*%U&Y)7i7BTGz~y0Kc`C~ozhplRGuMl~T?!w^1rQi$>$UU~AHov@n6HU{GRP+3 zLdaYkug<tK*6IbK5cwhfl#(y9A3y^p87=V1T8f+34i-vcV3?ypj`H^-jmTXOc5k=L zGKya2RW%M1(d;LkA_|unM;(ZMO}kplG}9Dbm7M))MHK6S!nmKloNQstgS{u<#mU=0 zMD(k1z!qbXp>)7jo?up&8@IQ-4ji);B}XF<=r?e9S5%5$TWG<zR+zb>scImI%D^V} z@;TMMExVXug-GKfs2`Z+{@^R50TXA|k%E5D0^n;L080sCN7AuOHDNXjBO3AgM~Z=c zxzv5i;b$OVoC4%OMMYI4B_mc7N)&b@%b%WvQbm${v{V66vk20RPb<bcY_?B8$vRHR z{^g+u^EGthU>@^SzXZ8JrVvcY?0VNrC!KU2N0}Vlvw7Vr!WS;87HLpGsU0L5{K0)3 zHT2~V@<|2?T;U+YQajun*~wBlKD<S_)1j`$^732LR8PEByzOz#eK{Abaob|#CRk`B z+5LG%F&~boPD*hd<5;G}lpDM_Tj`ky=&Akw#!mJK^qhvVh^bVcm#s)cl?cu$F5d#1 zsZtvDUv+<!{`fY3MpaXq1xp%5^Y~XJW1sXUshlRMB=KX_#8>NO#+OecP@gJvs&*55 zshUZuch2EA1ZiPY2`!dj9u;cL<21}Kq2L~Btha<S?m)7FCg*KQxqFbwkwqOlT-<G# z(bieX1oj4U_y}8*!u=gN;NN;YzcY?Q+Y5<*>1D))gD^>CjV87)Q3n;P(yvyheZwic z3`X@COZ%hsvu`G!VHU&UO0`J?wdhv?>iY_}79`G*QPu<innsevn#~jGmCHiSxMRN> zV&T+XiCV%YBaEV0jSv(e%FG0FxD6=ZP8-@M^K~s19|%ZX31t!414c{_3qc0j7t=*# zMMGo)GD7rL%kQZtwje+0JH8v;G-7fUZHr7cvQy`Tl{1Sghb!qvS<EJv^XQgW^=h^j zv$L(huCCV+>2khVm#G{}E`1|b0lq)Pua(A@ZD5HxOCZLPjd1?Pa+tw4wais~U2nzZ zO>Z%DFqK7?d;6eq&wM<wU^wOI+0B);{Qnp`2k*+eB}{j0+a23x$F^<TMu#0I9ox38 zj_niMwmJFc-kFP;Z`Q1J_8+j<+4bA?R=xFX9=E-Lz<N)1To8fR_4of$6*Lvelbv6x z;u!AlRmK0jdjCUJXsO|-pnil%f%i6ihgAK;b_^z1QUC}qoL9xp$)QvhDwQvnjzeK$ z7%6aqdMe>7p8`N!zF2mCA2T`4Plk9GqkEJf!x+Xw*3qzjST@VPTs701e0!dniusl? zwCW4HT__7{xFWZMjiEqi+LE$wI2m)A@@ND^f4fhu9pT^*7$HKJ)Y3BYuA6wBM&Ll> zwv|Lc-7*nX?WUhdptHLJk6~x;pf;G!v=O(Z6yKD8f?PmBOJ~J7(M6O?i;Aa{>!(0G zK;k^qfUD(P2W3iE4wXsM$w*v!LS0sR-DqW9&zwd|h{!x1C7!0?D%?n8x{~(0o@gf0 zQWhgw30YJ5rX4ZdrVNZVue>!%e2uMfZE)Uvw_b<RlvIXxs@eU!3np4JsFVzf9196( zW@#^r5RNq@QLa+G>7@cwG8|MfMPQTy_mXTDsZCN`j`>2Kf!bs<j%!FNa<ut^OMEF? zAz%J%@Ov7XQId)#?AfX|6Ls-xnJ()B-9%gB6f<*~rgBw$u4$bN|Dfyh@J|K(qS8W& ziTWao6!uV|^&B`(tp&35suLNdG0P@ZeL&L^C%M7LXHq%-6ahOf^T+|qM&>%eE9w>! zEu*I`px8lM0I~sh5ONV&8%HU&zb!HWIHVyG4h+j2nyt2w|4=h20v7`u!-I~@UQST% z{zWQGhN=oy$sa7;lS1DFR!j~InI`7|7`|F04jD&W(VXSic)~UXg}&Awk!Z9MUc_k+ z!iQJtrR`j~o9RBD69!Qd+#ekk^BFRGa)MT&-9Ybo0deonC@w_JMiwe_7_$mPbx{?o z^f0O!NWOY#?3!JOjfw&QyrzVreD5GoK5uN1`9@j^r_Iy7(K!`-8Ym1aJEgKI<xUgj zyRzXovS^7)7P_<RGK)4`B}O8y6&<*ND5DxnB-oSdlPdQvuhST%!k}WwnCCPxwQ(#{ z)kd2(AU{pVMT$PH@uD+07-UjuDL=4<TGsVOl%Mn#dvR2W9wg4i5+x{PW2csJ6EzJd zM-N?|8w+Q!0eAb@d3NNaKN09Ge9ZGX;bTd~%Q+jS5w3pu1)$=;A<-h30|MenV)7FA zEN*@T%3@zDHDFVC#NWfp&vQ`uz&smm8S1()?q4m@Y4&ZZetQ?W1^w!S!KG*e#UC?b z(FO!l>nCe75I|U!8$O#8q*VX8R<ZX+!}UxS7HC`qYm^kI^Z<8RfU}fFO}NyT*UAz| zw9op}65*80G~OAoO)$;$L>WWfAw_tzkIw~uY=@B9e)Z{@LjfPG^WCRCgi1XZnrH`o zKLY|lZdgVK1mG6Fr#rs%kk520&AQKdQIsx(EZHD0LlFP00RlMTD`!WPMnjfdpa8@Q z{MLS+1V8}H49oI?%c?_9tY*6{`0qO)02qd4wm<-oyqD;^OB{Kb>2FCT3#FGHQ_;ya zUKeV^D+D{W0M%qigwAU~(?-`5K0e0P2QV1IOrV&EZeh^T%`8TLMCGS_6A(hvX6Uw? z;j7Rv8>R2BtP-5(Zi<v{UeOO^zaO4OP}Y(xH$(8zZ?Qwedae$=?g~M-#<v`15gdJn z8ExbxNV4kQ)x{sDogo7pE|+(?9Cz)Ccik`l#l?}3x7v+_{q_xx?C<@rLUz{H{}?#` z5C5w=lsgUpDT`c6Q)7c8x_XO*!%<eN$tXS!G$Xd3#1+vs15-d-$iJ#Eu~Q&vT#^YY zxT%08!zKqe*gp7Mp&JUcZ13-B7|onQw_J8HyPQG{HJI@Zol4c&DjM!*CePQ0PQQ;- zc4j*^xz5)sg>M}G&z;jS5S`N?2(e$CP>8V}5QG`?Jk$X~Ab78BNFJIVV%@9W{JVo% zCXTX7PEn_rxm|W~@A&@aqk(3yr)Y?*ob7o0rz(st2)UWQIehm)kWKPo0{1NqAm1Z@ zf|&>cuUvfJo#5==DV{4Q`ZwUL{NqE3x48al@wc>oJMp)q{!8(<EVj-qe~ja8QiP5( z{~zvKF?V<52ye?Ue*WE_TXy*F!O~ud2YSTUZpfeCuerkf;+`<V{NkSw!an2N1N+lS zHi)j-!ra8)V){QNI;3`Z{r!6|K_0P5i%1rkO03S->7t};N(+!}RuN-F_vIDChE&;Y zjJDPg5yoImAE+2x=~=l*%FQH&6f#QBqJ9+|u}P>LX=FQ-i6wvrl6E?{w9pcf$Jr<n z5taufF%Y`li~z(1ph=Y!69g(*K|FsKnjWfas$}j*vwk$Tl(Lk-4iy+n4!GP_MCAt? zXOpAGkdl&yRH(6M<<mw<)^0b^3avWqpA;F&AnkaA>?mvW<m9RIEaS-y^uoR^MBcdl zrbRpU@mDXts4%t4W5d^0d$YuWHe3<YGMveDAI^Qk{7_E$?wJU>+(KbC3SP})Gz$*j zn8%1=g*@8EhhEIlVBe&q2oQNfNi=%u1BS(ghM$}O7)jJXuCs-(3X_nAD`12=pJVn( zaIT>xitVd2&6weSIJO%z3%C{$S4yeuQUSZIg4Uu%1@Q9)Zfh`d{>qoFA-!aPCh}AQ zM-03d;cWSyCANVSUewD(7Dt`On8r#cl30_F0J1mKrJMjAVxnv$xEQp{M9VFMoy=Y| zm?sIzPNZ&RG*fy8m;TU7?BJp-X}EyyVE?C}tUrX3NeEUGMj5}H7aj`W!gA0}mFAAs zMq5B-#FCnc6@u(D5{r8wY~wE~brgk_vXjUz4ILcJNl2O~EKE3LTer|jhz~=pG^dR% zd1=7lhb(_*zl~;PjS$7;ZH_z}?22I{*NWdOa8Z$|+(ChZnr6fR;>QTqRHBn_B;l<w zD{i1yX6z^=kNm<-pA8@gLZU=crW@q0EoGEv!IC3u?_9B|G#H=9XDhv)Phkrb2F?&) z41U^?u9&d0Q7RJO&kR;95r<W{6-bMx&cgkz(jX-PTBwj(mm@vXQOOG!95PW+=}n>U zAhStAfwI6nM-iRN7jgaA-C$thc5Pr*H&=42ORl2gI%gkY)KC#z;D%wNZRN&TWgOF3 z<XtEF4b$M@iIojgZ_4C{E^A=NkfkW(*es}HEMwb4lV3?>Z3>TM8zd#X1cecCWzf@_ zt{w(yWS<LZ*6RumP?ZEdK;7m!=%r)0ZBtSy%yh;fqPq)YfF%ZYiirKj=M)HO#w=ir zk6cL7VGr`4);bjKkIjVY5_+ZZgc-Q&qfFzyr0{%4H$iUo=wXysDx_~hgt83#JFz|$ zb0xKXr2{&C`PXY*k6SDpnf<%!<c4Z?u6UxEm3A1ZNu!mR_(FA#>Nx9W4HMmvH!|lR zjF_i8zU5@hu;M%ecs`O>!xlYbG;8$dE=7G6qH<GKSkvMO$)`vyjrs~z<N9R>BJD{k zktML~90k0nD#T@6HZ|j0aa_4Pd@%e?Z}2geSH@0n<i+ENa=z4){E;{GO?j&0c5zAP z&~Y(etEm;Vn8usTRvgr>U-^b%!`8LGhHM!ymOX3XC-lPYan_=fgB;?ZD!Pthz<<-~ z!_<CD-=g+j>NLiq(E@Fbux1Ql*Ag_O3=>6`*&CYbr6pREcJQP3xWjKz3VJ7b_}voN zZ|lqe?d`>@P21~2@(|ksT_xHcQ99}_BNx}3lB()rgVSv?*|eOk5MR^DMRs~o&zCt` zpRR$UC|)cKz59Noy06f|gNZAq<NCdhFj0I^?EaNF7IHL5AMvn8v$U8ErH@D0=3o{$ z+iJNoBj@o36Ohy_=1<lxYGqmaJk_?7Bn@nQR8^}PTC9|8qq`86V778%%gUFQYcr>C zm@U=`D0Q<c`VMm9W>{RNcm$l<)t9Wk5s5xXL$wpIDvF2ThcVtz14Gt1ZLih%U}_{Q zcQ{i7GVfRLtE0RAeG@a1nH-PP7ttgVQhxxi$XB!{rXZn%R4`i<s6O=t`h`mNiq9sb zX!0nOs=>@Do}@?ypqZCC7=AbIt%4sRN$8P}`&)6QfHNE!MA8uyI|stk|APjET*qtc zC+$-MnjhZN=>t0fuq&b%DF?*Xe!Z`~0Q22$iK-Tu8Gmek%k?ZT45oEoZD{w(__t`j zP$LM~UK4w^jKHaaeWnb`Kbzp6pd8@hDo{{|2T8;~A6F{3ZV0ZLae*Hh1Nmvoz}3SX z(c(CvsJ4t#VDK^`<v^H+S$ckLX)CJ$)o<|>>@%2KFdy!Y(^+CW=P#a$MtndBxa0Cn z{K~!iR@|A0BY053no5hECae>0x`&93&J^j5s=*1xYqUqag*Wel8&Eg#fu4c-su|M* z3+|OWzbQ%9d?nTgv5!SCANaEl!e=^yZwc1L-I{M65Mnoi^8OauA{)5vnQ4GW6U;C? zJp0RUs!svx5n7|5GXnFH=*bqNQJ~FFcSsN613dJTFlBjhcDup}U+0)g<G9LUvE@O? zE3<yEvqQ+d3MHC97$honS+Y+99<zl&m`^8ccWnLa<1x#IS3jlUCrEa%BM$!Rw}u>Q zHT{N+AltM4RvGcEaV`)wmhYTkP5CIJ`f%Dm?K0eR%D+SBAH`8|AQ^HvqA2veePd6% zM&b;BJsxM&(?a{Bvck=z$34yQ(HE`g);AC;Q@(o5U;fr>B+sj^sDXm({1U}n2?yUs zWd;G^@iGsN(C2_6pIoatMg--7klI_iuD?3j2gndP=h2=6D%$yRCJA$$D&(E!Lgo|} z7M8)94S9prv>m^*!F(&>AZOt{$hbw%1pGm`Clt11H)=_odtkEfY5;*R*Pz7|#Eix8 zi@**zhC6IeN!%T`Z-+=7mRmY8XOkgEFXls2J&Jlfkw2X?+l<dw=!nc(KrI%gEG;`o zBZmJyr`z!Z^a);|uQpIrfZ|Y+?oVN|AZgPx)|3iXc)9ZcEMEXM>s9;x?a9nreyTSn z`W+j_d1^3cZlV@JHNOWb*?@{VPIbt$eN>osjBFJ!Z8r<`cmo#I0{n~ROker0A0RDP zcjzXDqSU{<q<iT4EHS)!$bBuyoM5y=h~H4B-)m**+XK2ifYD!>(bQnZa2#%B$XEk% zMSqTM$FH@v!_`EO53mABIhH@_rb|&r1?rKi79<_~ZiA6HuP1dWls$o_R*Y&bxTq&B z+}7`_A`t0LRgV9`?vFrJ3Slj-1F~p}2RY$A$`LEKYaY{x?U$97UvjY20MIt8EaH@# zm@7F*wJ2}h(3FwNN;{OFxSdnI#cC1wv5WN1l8ghj?n%voa3kz$5!OLN{@dfC3C@^G zlC--)uV?gzC|WN7Wy@qzdag^`Z1BjB$GLL7C4NH%<qSo1zr=bmBA`{V6S(k-YW(M- zbP53cKqiC~<0PqKv`Wt7AcG;5Q<K&cWItUUax-B0ip|ybGG)G+X@1i>g(W9_USD;J zdUqqzXRQ8g*Vjl^dpAJyAcRwzfzpB@Vau$(Y7hNA`b4M&A%n^8f)AvvxALn@qRIZq zP|=eohUP}9y5?~#mg}fuKOOIvf522GEUNOo&ay<GwJ4%=Dzui5<}rVGB)D@(7njq1 z)5gAi(vf${Pk79AKmxWaLnlU^*D}qnu66cn%A#eC3Q2ZS26Q0^(KlVVg|#?iPP!;# zGdSO8!IJA{J|ompb*ZG4TW(^V)AB*9TqCpC6t7I<hmF-mt!h1)+{AH7k=e?^nw1Yk zR-D&*O=U^Zrs#x^vzv;up}im7Wm_sYkd;$)dNAAK#5-zes1vid?vTY?-&F8+^CUKz zPrDQ5nm4`opOZ-~JszkpcH&k9*CZvEY-u-EpdT<7j6fo`d?93GrqFqFFqcc2JbQ04 zjrK0ZB<riShjj{747YVIn=G0odlGU4$SKuFPt_hrdxgVITIPtos}_X(qcVtjGOMhv z7zftm{S_K@hRndO_LxIe{UE1J8HZPe1F+IS>nQf&9p&~`h3a@0wBBwv#0JE_Tv~r2 ze<0+sKxDthD#5=<T7Sp-{FkQrC;g&Qamo%^0Mn<wrk(ctKvPahgK7^jSQBY2V*-ms z8cUi!@BF-8F;El7M4Oc>M*K$S6Zz3hgc>ia<!n6pC-^7&eYyy7gO*if`k6QL=Hr3S z<-~Zh9YM^u3VjhVLhukn+{Ic<F{ph^XH*wuXBtN7rReT`*fab-(bCSTY$u~Fn6V{i znz6H&-r7ZcggNx)*TMBkK9j}KZSjz!qB&-)qLp5@W(Ya%BCi-Xno;TIOuA;*R_eVM zvpCK=`+!XImQ!?0Q$bCo873R5x>eZloUj9@X1f>I)H&s2*_uTo@hJY4-gxI!2NQ@X z-_o&=*+#0<hEn^;Vi(1dAeoEMu8DVlDQAS<7`2=Cd#LPL(RG}SoCV~jt3@oL!W%lg zgiqnv!{DafhbZ2;Teu64BI>XXB*hp^L+;6*^E53%Y`LiUlRConemhp2sxgFuL(l_; z>ijf*I2Sxo;IR_s@$8wXr<ip86gVfT>iW|qJ`6{tHdIIP7|gg`41o=gYB2=8d^Ngm zNL@qVczMKpfLS=x<{Rk472;@S;rYspB}-jd5y1Hl?xwL}#oRKn;sFQ=tonD!sD<*M zcMK}8*LSOXogS=WMhT>06fYol1>peI=1?E_dJZv_D6R#@VASonk}aMhq(TQIW)`JF zXu%?oL>Xg9v5=XZPvFuH@nzTnLMkZ-^>*Rbu?9u^;Eeqbz;bzgCaqF4n&ZNg-K3+R zeG-mS(Qva!djWGGQGSUkd~O%QH^l;U5<AcxWT9_WhW<o-jo%XgyS+D^ZDAkxWhQp` zG86yZtgn!rjlF@RfuXg@zl-e31SuyJF~p%y;%Zu&g(XbuTX16h2vGDXewuv!NJi*h z@PYs;*^2$zj)V>?S2aplZHcY4ZxHy~_fREy?t8I283>7zQ<~K0RYL-(N7Hk>yu9zH zS-S7HmwJ9696^S_>l_I^*ti!Y4kXd}<+)oaOV5P<yBvfK1i@@H!m6Q2gtE}TBX)~9 zWEq_!F^jejFxf1FabD;>i^|dy$5U9lb5>uR6U`oV4CDtZuqLN<7^L|$(z6d-C7v)n zVN^A$b!TjZmhNQ+GMRBhc)`Z1j7?j2O`V6fo2=A}P+C0ZSI3b9bX~1H6La-szvJez zM8No#IZJVhN)}p2S6SpI=GL1lORrZhqi*KTB$e2AZbxpCgw91s{Rz>a)PQYGOq;c| zf#?L)6XDe7h)<%<m%x<u=a#jQWyflRHS0ZSld{`hK24jXT#Y~{e9u(^8Y&`<>u5Mr zd0POcZ}$!{DEG4kE5hI0B(Z8<<FrNjeF^Pg8wn1Y(<Dv=eBne~xNUG8NOMm|etrwe z-fEN3CnJkmnWl4K2FEDkGgFL-%&B~*uRLH8S&G?%m4>8Yinhy9ZU}t1GhF_Jb*S>? z<s2xOE(&U)=qDwl+vVx2QVsDpxQb{*bhqazF0z|W_n2Edj+!>Elq3My%JBK-me=hl z>AIrnC_l8c9Cfj1WEu2T*ec)F8?g>G9?(zcpP*&Ag=ajium})W8m~3cw)>`i(0E!E z{c!roVa$j%PGA6S3a?6$0#*Y>?Tc+%!{YgI0^-4ey12eqB4llKF<k8Ebo<k|;I&{o zH{hMZB=)1WozPe3PHiKwF*G;1!m44={9L^7$InjEO1M*TvW|5;^P%qx@eAF~&^`r! z=D=%!?nZ*W)3LiI_ErTwVYSe}R%<#9F28#*7+yv$jf8em8(zY%^fwnPO!@458NW_= z4b_w`rysB+Ur<(z+=2IL&s_`pZC{9YE^ALL>vw$1&{|{_$$io+DUIk&fdN)gC#*L? z<%`$=7`+_N@I`EAw-aXxES(sH1uSqaA!-IWeKOWj=x?Mr{39m(BjECmSkqmqEB7?B zRY4Ux&Ej-%zUhwZxjb%a=4vN?D~aLLg<83<%!19DqHZyJ)dioTtrsZkftUQv-Dqux zNL(tSkK7|a#Qnru@sZYdFZtba(AtWT+UT&>VdCf|{6t!HQP$J#iXs4wgvK5BTYmp} z)uh5NoQZyQ4`89bePjBYF@b+XwuO_Ot*C*8wTq*PsDY8QoukJ;sY}X!N;o2zzDav= zW2BTUEH?fNdFC+waW8@4{0eCy0dW3op+)Ma4!l<kBis9mt1({<&&?9%q?s9uPsc&} zZFUFm2ge}(=vrB_cCYp+zSpj)*RzlNscOG(?igB(+CAjh>0rxi(L}{N(c#{x5ejQj zh7z*$V+Trb7HbiCIR;=NaOLXp`L9&?B@`puZ6TO^5r#rU%YJmR<JA?F$pqDVQiWeG zP=93uHNP@5YEK(-El0faCT1!5$tr+O=Yj1}Vu(a6VRvT8_R6H=dFgxQF=QmVwHbN4 z&BA(xZgqOJ6;i^43*iX+$I4PIoWK2~Z?BLSjOqjpTbWi-eU+VxF(%mRG&N3}(TJTN zlMZwDB^fe@)e?YL@YK~tp_vNq*Ahhj`m*bIh3$D-2o3}D0%M~+rr(Bxb!tYefb+MT zDOe{t;1=}CwEMO$p&(1XRpP|wy_UTXAYi0*dmK*@enzSyU6dAV#8Y+o+DQ*!=Y4Eu zs)V)@HBP=h5qNE?XYZ*B=Aa4qq72ZulIEzJQCam*Q~8o!bPm4`RAXKmF^pSn)2#G{ zCYn8!dr#^&6bta-by?;*8*Y{Lef`NYjf)O`^LeL;*C>(E5hYw#!DJDgv^~z}dCvSD z6bsV!ZOnr_Qj`|&l`IJ?WniI}1b*;cC~5s5WH40SZ@@y4W{%B&P{=^a=DY++{JY{g z3DPYo<9ix-p2+y5w_p;$=&}yRDDcT@!mcU0q_=+e`vnittdo7lAU|P`?-7s7e=fGC z0Hb`0>G^Z$w4U)2fzNef=pWd^fPW!~hkqWsQot>iJ$Wa{KUW#F^PDTnmz+N2R-~OG zs5N^CReE-{9Ww1WPX~L6cVAyK7hG3GeTe=1AnV$}c)9@Q#q1Y>orVqENCuW!`DK*Y zO{je^iu2}~&C3fyddu7&gMSCD6~%jn-i!H%K`aa%(#{i=u`2QjluS?<Xk;A7bC4V! z(Gp!`E^tU3<pF965nS4lEP}(<y#T9fu=Rs&<61SoWi)g<s>)z~SKKf%AO9l%@}0Q& zEoC?LM{ZF90pcXf>Tj`*!qVuHUA{^(J2-{79XotH6Fo_h@ZXzAw7*_*lSU1yRgAe& z4!kRH4K=Yb1`!YsM}y8x6SBWoAp}7r=*6al!3ygVw#F>+?~%sI5DGzg<iavxPM;8t z%U^4Jk-YcpVICPTgPZ4}b2D8^GhIfexPn-<4=qDqi%WHr3^t9=ZEGf>TVJm59gtLO z6RlzHffST7pq$9Y8$8T>_My8R15?%HA1Sw_N+3Aq3Sz^}nE)Hagj#6rQMy_2gPHIG z5S>beIdkV}sGV~^4dU+3iQ^R0Xx|mhN_9hK3l$4N?g*}%X`1?dTLZn8)bhpnkoer1 z&Sx+<-1cTv3t@)dIHkf02kaWzW88<P!MX``eEn~`CPW|x(3)=X&xbyN|MRP4U%JiF z@|6H@eI>xefBRLkHMaN{R3uU9+;LVOkrx9vmoPZV_esOb$_7NarpXc})V1ux@|45i zB&S;u*@7#UL1OwC<_W$_BvavxBOhT)i1Q*iL9wUohof7)+v6E$`^c2urtdfPKPXU0 zB&5UQQPaN<HtK@7hp!?kg4)%Q9Owf8kPGf_U7--L3hVaN(aTrTtA^s%1eTW#)-v^F z8UQEh@-#C@4C%4Ea99D-)}im#%WZ!UH`!>7nl(1rGvb=`nB8l2W-PtZjBeb1P`E=B zjWM*_a0AY?`tIw}PO;(b4o#b_rPy1gbc&|b2v}v2(CO%C6C|IB0CJRpYn<ypMbFiK z>3k$Ajx%liILDj%(oD1yR$RhX@1KNnrO_5`8-ZGNSm?j<;55LAS&cmHu8XRerKyDK z2igu);9;BXc<3JxqQaBqx{CIxgu}Tda}#i+Dd9sfNdUH7XuGW=izug~V^_*p4v`}* z0p(1hNV`KFp}&|GY6*#db%X{)ilvZay-zn(X#10(o1k8&7##Fk#1&om%rRSaS<X_W zUDSK_aliD52^bQq^sSa5QT6q=jx+|6Fm7NNViqC;D%dRtt5nI?x5I5zSav!JI<S~l z{&e-?zW+vgQIjAefb%f8vCwvoo?9i;5M@hvfqn?f_>Sz0Y!8FtJemnAZ5V!b*E(Ft z=8T){)56pU6&vN)qTCkTQ_eh%sqq~Oh*Dg<`A;$TF(1bxht$Fx*-10j;cKDw#zEnx zsB~fX_Y|&+rr4Ejm7S&q5PH{b5$)4J44<ddJ5UCpz*c_^y$OiCQA#sKT1f6Oa!4N% z6WSmxM7RFS(1bvXMj8^)c}H^%+FvMfo&iS=*;_7#^#VGMHlpm@p*o^i;r610*yFe! z{`j`3Rn9Lt5a<tBf9h2;gKa*>dO<}abaKSSZfrccHi(i|RG;Dg^Wb9|39*%a9r*jN zMfdjy-^tn0<*zGP!q(N!%EXa`@t+{&NCD_x21Johb5>0l*TaS2P->wmdDJ#UjI5kN zbuA%aiIu+At8e&{(hkRi&*QKJAAZ%3yHMYSdV4Sp1-+Rn(H!-tCDivsx$U&JqiCJY zE@o}h>!_h_Gtoy|G}R!E?GAbwh^-?lpH#S}qz()2UCeLw`l*P2#-eIUrI+)aLRugk zl+C04$ikuIF?c7S*8yMowuuE!*aDe<MI70e84@KF;+ZVV_n(_q7pQU6`-*m%uV@$f z|KGHdiL-!_k%^O&#h2z#HL!Lu5%@Q#bfJ=s9Et#<ZxcN(FM<{|G`6rv|3ewBNKZeq zbRZ$2MZfx-a2MW?BF0p^@nzMFA1M@l7{MFR2gUB$gCf<_Y(G77d;KjB^VHeJBY|Ew zP>In*kpC~T!CLto0I>-bSy>H0V4?>FBmx{4eD0nHU&L_g5calGsQHkq3&$C61i|}a z;A_gHtKLoAA6%&G@CB-{UMHm11u4`$Fjo-^tV8RZVUMlPCjdi>XsbFd#!I`)#pT_R z`cAuhS2Fj(f&rr&1F6qBedy2`4<IlXA%e-EzADhOUvw#oR6K4<ouG60Q>-?hNRd=z zk}Or7Oc!_bJO{&f%ke`ll7x{Og@{hAOel{lcd0mkL@%I}4nzu8-<^2{RrI`OL;iNu zTT`*9YMd#Mmn$uI8hyPd3PmE`+oSc;mt;qmNaStVgH}ZDsblQ%HD0}&!Y`0w!Zk%a z#tzDbTPgXJjw&*^oPtWJS$`)S3<d=}iI!&|JeX1%N8QBzI-7k!zKtTx;Nddus5F}E zhbIJ@3y{-imr_WWd5eT+GurzShA4H2*B#@~F&J8`fJRg#pQDCMly|fti!2xI%mv<g z-Co247L)5asD{@8Xe%+aiM>ppqp{j>74kZ^K(+#`vS6P*9y?H{qDhKwsUVi-+(dy1 zwkLx0(vb2tW~<WPa<TwYJkM1IBzD@`3HjrQlnhZ@A~NS5Kx2b%V2Sfj3OpU0|1Blv z{IxXnMs8Ljc3;&*hCkjry6vM9crWalL@-tgpm+YH3ZEbSk#z_c-~2}mj;Ar!sC%Tu ztV=qN<nE9EVqxX!U)kk+>0_g>2U`9Pcp>z~DgDo|{b$gsXnpaTF?p@VRB6f`(%5XY zXJH0ptPc$Zr6^p*airmL$!vCIF`?<h>lmq`6MpaU`yo|d#X0MPZ#*l&nwiAx4%+_a zjdShh-F&WUf1T>~djr!)n}SPGXTE~EC|@iFFDt<sHq?pYo2$*;_4kM3VW|n5a+!DW z&fWd}4RoA#G10fv2+SWA)KrUUt-%HhbW&IBLNl{!twCtW32gQ>`ZNd!c*M{`jlbOM zRq^|xvv%t`?^^taQv?<8oXk`cS9{WBiHBZE@DHv6dN$r}9nM$*bp>#r0bJ!1?_l3W zcwWCT-Ur_}UzzWxquI?A&D!ZNF%c8V3$-f8>bC8(&^|*pi(LfBB0wF49(9k3D+ZM; zRLF?N8916t$8EVz6a?>vW5oN&gjiaPwpzawgo&HL$YN-+%L#XVT?!Q0c~21LnE6Fo zNzP_5$-yG0Z&sO<m4Pva5KYeONubtn1)pwmgyObos06L#MFw95w?@-Va&vtxOhw;x z>Fr{-Z``lX-O?}oBL%2H@Ze1A_ZxJm&t4ju@ro0|$!uBaLHl^e$f%<ou3@Jay>io9 z5FsdIxl{*?)M=|vSL?PZnAOBqT}5hBTS6`H^wOT7waB^#jqqepHuYEgf2p%FMvwz9 zZfy7fBkY{V^{%p&J8qXon~}LrBd5fOku$jPwM&~ytEnz8o2>}d?oFzw^8dJc+Zb$P zE<%$uO7n};%I91Abc@JOue|H_+Iisy;(^K3Z;5fAbl9Xp-F?`W?dXc|07X}|Dig93 zPVjGN??UN1nM1;R(JjumG`;YW^EphRT~2xheteOIWtl|x>SUaBTidZQ5PXmGUh3|^ zqH}Og*3(51Pn09{J^b!J=8f|P>@>YJ&5WDMi&(W~Da;hX6DIzB^v#sgf~HF}uWY}u z5QU_?)cXW<MYAnK&Z2nB`Wf`NZ1Pw-?N;x1ne5*EW?8C1*zc(~nFuhNT;NPsm=>`E zR_iO(IZoY(gOTArCLd5+qKRp;YrYwR=}q8In0b0+PPsQ=mk0&WAK&}ZQCmVD-4zyI zi3esdg#q9D?kQ%$ZDYBSqP|YL1UG_1Iva~-yBxJ!N)#5;<eX?48^3m4wML#Pf*$@B zMws4Co9Ks0g>Y)s)wcf({Qxr&s?dd;w0AQHx$JKbxZTxT5e>3!NmRutecLVH=t*zX z)@&mkj8Iu&D5)(Y$(}TFdjT{n%K*w@L+HVO)60L2)w`OUVuOF(RV!c7PVhH(m9UAm zv%x=t+b7P(ZjRxr{AHV7bU$kY%f<$7^kobD1}A5S2nkg}MMy>V2i1apeE~1E4wQ7V z3rsH<0*Vb3ncycvFh{!rl!^53NxseX%a7~l!)m)9-_`_H2hrd|;G(&z9JTxIxmwd- ztfkrqS!^0GD}<0t;|y|}>EVMh!p)~n`!#+fAW(87<RZgbO~{sGkb7;27mcD=P@$mp zE1bAEXCPBg?GOqacnXl{nL_xao<RzlTk|01(#P??J`<jr8$UXeoH8jBfGOnQqhy0V zHI%RmjMjKs8niAG@m&r#hv7n!{(_~ht`i4?m_?ZViOLg}rw*kwP^0{IEdl3X8ghXB zcKv>(fC-bxJs&WCz37kxYs^0V*)Q|jWUA2pdE#UbAF<NHX3NnMrUlPoimTmU7bvA} zl=7Kx*4|AIF?x6V2^~q^ub+Nw6N8C<ANqks$O|rN_stl?nP5d_#BDk!UgPE>HvqZv z{!+g^eTc$`q&SE(et5XbD67Kg!9_5Gv0SKyaf=VgInt_UupI@m64-yvZK3}d+p*Uv z;TQz_f^qa>K~1@<=Y_?8JnakX><-#$qc0`u6u5BvbJ@b+&eU9|$UEwuLae!Ajad1I zw1ubqwDEolT3}o3VMUr$e(4_7<v~l@E7k(inZ?c=aBUJwD*jPH7TT%RW$}q#hPvOf zapfoYf2KPrB3>WAzK%}b*ZRBa{{O*D{1=E@*7YwIH@qnLLS28x>|YFSIGOCfu-oq$ z{T<HlTXA{g9nMz&#_7h*!3Ij6-`UF>4~Y9hbo0g<ih@7?Z$Nkd7r>h+R=Soijwy#M zsPscZqjZGSIubS#RvPwu&v5T>&v*~8A!7}&1Q|Hne?huSh1bQ5zY0ffIA5UdzY7LC zm%mEF|NSyqrka;GDgf<+Y<YrYY?zo3QgIkuI1Y|PzJ%yIn<)qsIAU^0$WM;tOcIdv zuc30Ou%^bQyF#CCVNEM5m6x3GN*yBA8iZUxS7KhHWx3Cf`L567(~S1|^oa{=SCD51 z$HU3a&Bt}8$xNr4CqKCi&>GxNXnocV{GNSxi1a|~jgbQ#>y3#6UZ4()=Bp!Bwo9X1 zUo3)>eh81J+;6DfDPjZ$w+d_oMz;=Z+4@deXsJR>E5I#yzdR1&fxMyJu8!ucFN|-o zu(B)rb%4C#-5~4{F5tEx`3QQxpx(akq*>h9J;@FPc3s(r(X}2wC)Ad_6DI<#y9UWd z4mi>k*br(t{~Q>w>6zU^rpH^$)_N!pvKxCV2@YtkPiMLyzrl5G586U?u`w4(q%0KT ztQ_>qXPeq6z3#9mt(%Af+?y?r-_B%TG6dF>YFfq`z%^f3S1lB5wCZu!S<aGbQgcKq zlM167!k1b5i$ybou#@E%aLDp!4_M)Jyyo96rL<YWHHo4NaX_rFrNA?g=gvwB5pJQ; zQy~&HW{U?j!)%QL*&i^+NtR9{3?)h;(?ar3z#Z6Y<E0(}zN}f(=IL>wONRYokn-G! zQRIeirr@+QMrHXfE9o+3PDHX<m31m&&95%Lo7+B1Y;&Q<@jR9)ES(a9I!MY;^@C<( z!}eT8=&~IyHg@iK@gjFXLN3VY=SNhI;I)N!PSR1S*xb}a9l{qhyRZ+ZJYxMXDa1H9 zl45Y7KIcMxlcC=%HpMi$CQ$!iFXTm|$Jb=#>3!GRiRKC;7Uz1uB$;8{pfI=qElCh{ zn836LC)J*=K5<YTSvea2L*#j6C7)}u5JIlq9*C+?LDDvlOsS}NA<q4$y3QBsCdX3j z4#(V}B)9(VR`tYH7;pCJL3T!|R*H9m>Cq~waOfzjSu4rHX4YB@@4LGP1#epm;tcqh zG^`oLC_GL68V%yrwG=(|vsa@4GmBJ==jGaL^RJt{{!G9#4k-;43A@?t%kBHlK5+2V zrBxhE{jigY>hO9D|93;OijpSX!^^>nj(&5~WD4~_J4*E!J8H=MOtF~j5~V+~XNvZ4 z3!@yBTd-aETkY=Je^9Kuehrb16WmhjJy}Vw+q0Cv^D8@*k0_eS!@wWCvJz7ubC^Fs z7zu{pH9$-V^PsaxlP?v6!L3wpy*>e*5>o!?k3oG)nUGuJ89AWLP`OfKQ`;8BIz&Bk z*ZjlGLA`4Roi#9p#`EhC4OTyP^ZYjhFZ+peSRhn76CFj>hb0z0#S@q><*o=A{k9sD zZ{-&IQ)T2P<rD8m&Q?t16ZxCQ;25;-pK|DrUSYq1P1Ltcoks+=Pve=srQ$8FhqS(| zhMB@1L!+AIiK0Nf)jxJ#4wV6T)}Bk&1C6Llada$+F+|tN@~19JZB7SsZq?~_9@nVF zCNMC_ZrE&oMIuW+3Qq3A`krg5jEVMl?o!FN5uR}YmSd>TX(4MO(mK4p8f9_qUaQRa z9Zj1JA<Dl-2c9mMNwYR_V|2|lp&6MLfN3Z^EhN^*=hN+FEh?mC+-`oc^P-wK%AQ!P z=A1NyhtQROQrPMDNARe%fH}UT1O`1q=@l6YPapw)FKZWZy{;lR8Ns*WA2kqT&n$Rl zlB_C$DrYjxlCtXrkW}1+n*2G6ek>Vx6egb4CV{N9kP$?($yBP*cT}Rf5Mgh2?={<Y zSmbrF3e~y$srABn-?waB3MS078DZ>06(vsCOg5;JguPzQ=_*Sk<9xOPTLGzLne~mT z1TL}+HDUm+lT`3|DbP8ggp;MBj`)3Ennm%G$;JAbERj3Gu`!0i+gb5uu%VW}O`(H< zy_jqEJSe7&hcq*8@<Z8cOE;t<BzJN)WY<y|#_HXY=ps@o^Sq5Y)bnN6ob^c$1b(*J zo0dddK<-pt^asC4$uUO(gt@Y)6F>hrTThIrwnV;0sfs(VCYU6c&)F)Z(9X%8q0X`4 zNNy3ysNj%ePZF}a6M9MpP<&~d4Wd3CRt><YH;#g!uPo=WCmc9$mP47MQ~3EtxROXA z83VO(1`TjbI+{&wsUx5e>BL+mnjBF-F_4NSnP<q|p0yX1#}rmZ6AZZey)F)2P1dM$ z*FhO!U>agTHqi_fGC|4!dV}eTC`8YAR&b~zg4vYN!$2A%Kpw)|Uz41*i^7!PV7AL- zo!i+_R&)$&$^%<SuIwX#tQ2GP^|*j=X1HTrUxPD&zm~=pE7lb@hW3u5>?P)36Zg^> z;bZkTJG2E)m0&kSf@aBA;Mmke7d&$^`R9W3I2QA}GR(v=2k3dN_Z=3l?sLkAGi#zO zzb4a*7SoH!Vh(KcS`RxcN~&Ezx)uAwt2N?gsUJr-#A>_rY6@a!)ns<?r$BPq5Vi>g zIkv-UxZ^k4kBmE-`0l=&@`l4uHkxh1`yF8tPC{LiOlT+cuPJesK4BK^vh3fc(umEQ z;VQ(Ot}Cy>0SY|>K%Y_-b2g~O&7HBCNPSgGEJhqUijMcV)P_eq+=|G@=<fk92kXHi zxkZ|rj*q-iN9!GZ$086uv%f!i)As|xN=RNwo_8q62Q<cu4}7pDXUwiF!lyW)ADIPT zB#|2fB>4&Qc91VeaSfBbAn^xskS@GeX5>zn%;pc;A)Jo%&*DtC>%+wux{G<vTg79l z+vsL@_2Pu>QSbBB5wQk(N$57RyqdF#9}Y`BJH9J}DTQLuPJI2Ul9)bl`c!I?A5^C= z+XkZY)txbYH)jT-K=NCRqqE%+)`6DYK)Y`8IiYTd-hCyegZpPrnVelfu`rxnF!K~z zF&S&KO{1XZ4()AUXdc9~lPP_4bMHJF`Cn3OU#1CIJ<x1zk>NZ>KI{}9vVoItJfX1y zHL%uqM@@|AQb_vfRnS4DDC;}_2zuxPKvk7M$FDEw(r$W8QI;}*^`S1Hi<;x69uCnQ zZ<gcM1a<XtV!OlEMK~6>e@4vh_?o?;E);Gsl*&c^024~bi*$EEnJA19#~U1kqnkvd zgV%8%Z6MJk3n&}qS3#PO0v@G;Y_zVE=e{;YSX53pz|PN!-j4^=wtt_uB8T~^DE$=c zQBA<Fi2^1+i;7<qMejSllFdnsm&vJNm({J-fh|tPCPm0tOpLCV**d!#Y;~^V;N9Rz zmO(cwXP+#S*q*j7>uZIwL+Q5r_^&x3eCU?_{I4W!_iIu7zmv89IVtqNii*LJGJh2n zMZ0G#8_+A*DRx$-i9>&E32M6sGz_jFBa15{9QJ~^Q!oOexXn_q_}p)^s$W6)ql5ez z`-7g0HMK@{DoG5Q7;SR*Mma6s>yX$5QfysHBg<V}Vm~Y=VNrV5z8)(nxYhPvS}`B; z%f{dY3No&4Y_I|-M8~>HRs~f()tVb0LoNSMN&}Na*gW|qDvkucEs7b!3y%U3(v}dt z@vr>)FNqfJ>dBt<1ttgjl4yTdj1m4vR{D>P{+nKlQdpH;<wxX==WsOyhHBXNg+i1} z`_<+FFDR%kE{-Jr^QH?5hK9+?xLU!l905&{;05Ttq^!QYWSiD}zcnM($(85z@UnXI zn<oe4wgIy+m=<ev6G#K_88Q_;5haPgVSryj1Je*_HHsfr9k+~K>pUg}Eq!?L?{V9H z3Ik({*k}<Z)YQ6X(7W-#Q4NNqFr=WD)&(YR8R0Cc5bi*h_LvJ}TcQYK(L%16od*4j zFp!n#C4?HWZzx>X){@nBhcrH)rZO?pz6imHy2T=FNoJ#yoli|~_X-_XR|YiM%$(?= z8^{Y)&^Gh&xMkYQqLoU-8B7Kq`cMi)cRnopcc&$JrW3w+d;#BVdJi9Ie@<se>PF-5 zFCjjdexm2D)sC4@SPsy2`+>O*$#CO}k@E2{5EGi2QQQLcUQkP}_hnOj+VeVDV^{|t zY|j8&&huy1np8QkA7~)Z)s^*2pb?OzG2Ze#_tu>fuj2)LcOXx+*`^@fJT%6IeR zydzZ99mZ8ETBGm7dcj}8{iL*SYx<NHYKHMAPX6mapUqANo_>+fCB9xn{u=)HzrLaT z@Bi~Z6nUnqh8wC1;s@7=v{{HLOvD+9bt>#HP>#?u5@TQz(|CP`?}lcx64<6iLT+-P zYiRar{KBqoV8USjBt!Qj7zA%%AKwVH@x8A{j8x>9nN!ysG(k$&x*iuE0hMK1E`D#X z<(J<odc+Y`j$pnAeSC+?9PmYlQ14go*B}XCU_k5_NO`lk9ya}L%s9Nmi2lp{o*{ym z2LJKLJ4QzKw}V}%EKjD;;wxvwsVxnxsl=V<@6kKzh(p)FP8}4xh2PJ8QXji|cT~`; zYuz&kaA;&}I4E}$BH2wclCG0L#pSV4pe8C}N|OpTkiC&;P0NubUD?mf<G+iLL{_sS zCsmT2$+9NRzuEhdJON5Fm5o@Ia>&1!3>LveDw%i18%HxF($)(onpR93m8sl-3(ScG zRvZP^h0-)GzxH@i*KXNym^8Th>LRuJGwh~;2A90bFieRR<wNO;Wch;GNkHzw`$>)_ ziV}(sD_&D6`OAWu#|-{rzJ`Jl!IlV{DXgTYRP%z8m^2(Aqc!*-j)RB*CKS-RC5QOM znuWN!wC`PjRv8}lbY9bfki&eXYM(6e6KuO4Go^c5<HWpjy5My6Y;Is1ph83S#OS4D zfQ`A5m$aVRYN1-Ioi!djLNKd>xXQI}*2YKPiBGeUkM({#AE8m@tCXsUX#P9?_r}}V zsf3ALR!x)$X*<!%&r%VUp)h7Q5|k$VMJ^Yq!^*HAgYsx5PHJi$Caxg)^h?Bz^Q?FJ zZ^%hOL>se&N4T4<MG0~W#C$nv*kaL_Ciy{yy0cX0SYfzK>zMP>N|(7~Gx}*E%YquY z4@hme-Q1d|&umTUo@*l^<1Ty++Px2-UL%7$`%>e|NTW}sed1{fHszE1W{wZr<<At* z7Xw&e<u%%W$T}+ZLD+7NXkt!K&;Im5Pi{v>-a^xD<wZ(C)9vDcUGDILUEUsnpcB+R zg$@kSoFFOGWQq_+$YFNl>o8SOw1itR@u}G3WlN+aIGAfa`nGL3$Bf0Jdo-<uU2$P$ zQ$GQ-8?Px}k=jzWL~$ojY#5Fm;wUnVi>-cz;l2{!rUZ@_T2q51UqsM@kRJ+$SC|Yz z-c`Be1B1mkIA{m)G1($7;dJi`W0GWrEnf{_6xDezF~+uIE6T2km&QAKOKCZJC(tEl z(<v>rNbUxr=7wbP;F5cykR-iU32+;02x4766c_P)UrMD?$c}r4m54tpN8jikS6<gi z$BhtoF&so)j9yN~5?Ibo)<AQMsH;8Mqsc{2Jo=;Tk(S!L<ACC-eTvQ$&e<tQW-L3O zxAM+X>8e#aDq4OkY_0{zT(!c+8MG>A7*Q&UVBRzU2FOn?E;NX5!go4^>LFl7R{kJW z4ta2gOVNrR0nwf;#s1a7(v2oNILY4VpMnh_(yUI4T+Vm2O16E>57=;3xg&wehpd+m z+-K1hh-o0I5XMqt!k!X=(s=_kI1>2Sh%ml`1Z*3KZ;x_Qv>l)62{{JTGo?RF<%%6? zR}@wsH;A^^!k=ay>P-t2()|I<46I3exhLc5as};NMX~5lr|N<el-2j_v7|@?T<Sqo z)4{b41D>%eNCNkZU5ZAxp5{0{Sm4nte=Bq`iZ;e8AndVPMp!9l4paD5DXe=$Np8!7 z*gHJL*)0#DZI2oZA1+s2AxidbuTo$O<iz=kA>#J7Tsj3H6W8yu$QmoC6qHg;Z-JXw z;g>lXQi<@pgqFb1J&EI&+0X$Vc$AX|ly||D#llW7qhc^}EXRdh6r@=N_+0`@WM`k0 zfy#<_lrj31QNWZj!cLH*=rMBIejory8380f0JOX|$z3b3l9KXv<uM64N2b&c7Ebnf zJ5CNs%U==1*M0m2I!Wd4QS$9F6}+TsuMoMeUYcHo<vQ3|;ibT<extMWGN+4kwDhib z&2v%o+ph#w+O9ZrzZ~S~dZ*w8J<9k@RXXPPcV^(7r%z<fJ_OXN=k}NPS5haKgRp?J z^mwj#gv&+Vq@5Mylyq)pHjAY9OZM)LaQ=*!)u$$0`$cHz4CJ3mh^a{|pGDK@CEjut z8-Y5B?JK4lT~_zM;<)_YWJK^Y)>ukts-d(oKyl@sq1h3uwb~YC4+D{w9lxzQ#C@Hr zAb~3o0I`h&KbrPhm#@sr=dwAp8o$&eg3IR_3cmY+a`qkH0Xvg|=Cxm@jHsDFTxmPL zX#W@@#?dKNSxmpIgn(u^>T-|gJ!f^GR75$bewup{9l|US(@ffrDoBZ%Z!z!FvkJ~I zgHfgfQ5MHjI|IAe)4$FOGGc(C6!)r7U%XYNq@zFGv0lD)Hjt^(D*CMO5niv9h^BA| zi!9NQ@4ZrVi{M{r(O;%w$#Ya+udkGd?W<t-cR*MXM@KtHnXi_rftktwvK1%TIL(QE zRj?1m2&E;o1#=s6SQ0oK19B4tcTpw3AB>RLoEwnMshNqm2%}Q+W?DR}o|l_)3H{*z zp<L`mPU^c=a+~K%nC<%L`?|Tx`~E(a?FZBnCX1z~-eR&Vwbpc%7{%RUwQYq%U<eSL z>rD%`qgkWg?FzQD;pu4$_bCC!*I26gGflP2DCC0p+>QT~b?3%r)OvmU^B1g})w$Xm zt6dP!344=g_3*m)VjYX&i8zw*JDJe7LB}q0h7H8;ZqB94=e#j5LXEQXrQK~QI^g>( zEUC44E~9%Lo<Ns^NOz&sR8e$hZEVd|-#BMCj|S3)ZmEqOD}4C3TI85KOge<9nBXbW zW86(%Gg!<YH3FEfo4E4ftBtNSFHzZV!fftwPlDhM2`u=}VdMcI_lA6xbKHH9A<w0V zT%ksC5fHgtX=b166*P-bt7>_QD20WVHy1MWx1aNM=)(RTL$TGgodqLt?E<|u`Uy3J z!Zf<_ZXTO*=GE(A5WTlr{`j4YmoACn2BwOjeWm$>RY}(c0mbg3Y{l%clk_}<tGCcA z?tkq6NVx6_wCoDkI(v5QmZv%xcWC}0vLyDsxu08hAc32r>H|EsWT?Y3vUn345FYcb z@Y&VLon@x-NP@G|MlQgU&&)^)$DfL0ubb%T=1@B)G)7K9H(lv~ZSF#-$YpLzdrIN? zWS0z^RKzBf+T=)?hFc66W=oX@FAFr#wKN|}g?E`^8t>|l;~7CPK{9g#N$TQyWMH?d zzg`EGIPI1|2wt%ZQ#m&3mtYBi<MdS&uco4HB46|M#UDTJ8w)xF@~y$1nDzB?j?b)m zc%J6{#C_-9Z`NOZwydhxDIp-*T&7cn$vlrMU-(7wA<D?<Ej$%>p#2BTGfVDqhlp>% z8Y0<Tgh1EZF~b1P1J9%tfc$$bz91MW&PBTJ%0jfwnn;6ecE?LxjVaEED3j^;iIVs& zS)2_KYf&s8^KaR7@#dmfbbD4}R)u+P)Ae30<&sjfl0X97oimb~Xi?Q!eeY;1Po5)` z1b<ByT#v+{*86>-ap?=YlXqEcW+Dryss}AkT*owxsT41gs+^UJBqfLXzA&vKe=P}! zNs`Ad*~6k$=2lA=h3uc2rTv_pieUhc*<v!OwH!Y*73WX>`$wp|mthH1hs*$hQyi|7 zgYN%~->6Rr_&;9`iI^{X9RA;=yMOsJ|B>caCXG3*Dx(hmAoZn^jOV(b&J}?wbirFL zO5ih>lKAQ}6UyY!K^?=OYDFh5DVB-7gkUB0F!aR@CDqxe%Ok)#_a$JVpFO!@PIe}t z4JfQIDA5;CuRBd$a>sa8c7MF@yM2SWE)Dg~KykpwSUSQ(x-=B*7m=<TqGa=w>wj(O zCkuDbmfZqDnoBX5Bd9xG2CX8oXZ5#&(l(>FttpLJ+BZVt&KYDJx*$aYp%}^?P(VT~ zE%B7$H#_KI;f+i+k>Q^TvNeyl^^vWoD|ce`oExa1Q=Z&#R$=OjOI4Ro1_;Wq9>9nU z%|<<=pcJv{m6$gv$^Wzb-HSCrr}2X9#et;G#M+#bm=Vh^Eo9kCQ`%?&n8jMzEtaf0 zPr0v8GSS3fT~$3?9=oRky-QR}RZ5(R>qA4}Q_K39a)MR70E2?anptKFwKO~4UvTU` zB5vNCJS<ENb7bPgtTLgV$(!wA5OxeLOr~!&QbDf}XFZ2WUS_2r_yPhWrp1uO49$NR z)ZSQBfuSHkCdB~e{3>D5_NXq>SOrF&J|&i&9ap|x;@+w9(uD|fqLt;hUiv~?M@u4m zK#7C?d6GV+GS)G`6@x=gD^nR&S~Y<iqN(6zPV+w~d&eNlwk&M7Ds9`gZQHhOTa~tL z+qP|6mA1{wFV8t0_v`Ms9dU2O-Ya7NT(M%WIma0Dd7mkOJN;hMBw`(NWm*>nR;Od6 zOM#N|jmmU=bAut1C93pl<@sUfX3qEv<7|GS&cHafBVwgINw#Q2dnz$CA?oOMAi!cE zV0LiHR`d|!ydRqWfaU789X3BD8k)?hD(dwy*aONbGq|?GxsEyNuSQ#xG)=De?TD%N zQ4;Kw`mHzf{6}4uoGgvqW%gMBTqe&a(sy5LjhE()GTQgptml?__Gpc^YO$Bd%)jFs zv<swI<kgEh0y|ns^^pi8ofZ1Mx!`IY3y37yqGVT%S<$T%=b3L=F~h?zH9Mkp?sXK6 z5r{T6e!nwjtaq!Db<;WB@DYx1SI>?6AAhYLeS~BMdI}gaSGAw9b#~T4{DQN)`h~54 zuYJk5KVdPoRDAO5@aEn-*h8*gC8{aMdEZGT1I2l@$kg^g+SqC<TdFEq|B*<x#yVJj zLg89&ES~}sY}BY9rfSwuVliqVSwmw{jrJ0f+|JCPIr#+5fvHA)n7X06>{kk%vi?=V z#my}YJ29dUijCcqH6)~ddbj!8sbIjTM{HqKJLY1-1Cx;JQv^6P7$YSU!VQDAu+ywF zZvHAPI0Fc`Ct_CUtT*2n^Xx4(0p%J9N64CDp`Y1=IH+s<Ua>9Q4PCo^AQ2WZUaWO{ zFXigQE}&bI902a6XmA0jov%n1(9GLSIjF4T3oE}{Wfq6bqN5OZ438F=+yW2trQ-J` zN?!(ft?xpfI;K5D&)&GzZ_wz9Jim=}O~1(R07PEa*Zc9&AYOqRdFPrxyL5+81o_1* z^<H=n^#&v64NvF!#h5~Xbn88-q$-rKhd=XD${86m7URUmRJRCuh3wDyY7k~7H7oZ^ z-LoSy050~PRoK}g0gcBX|KSV@{dgGCb@HAS(Ne=tH$M~_gjSJWj~`qo0ifPDxv)GJ zsBUS?jJ$#pS0POYO0@RuJegjo^qU1h+oZa%0H-*2V}d?yAs-H~uhK4qD>rE+_%#PO z%}j$C7|qR0lOl>`dsb8}b=foGGpL2fk`@Iu03LVU*_}0{*XLuN9zstom#6L#CaYQu zl2t1!d~abf;kSpnj?WtzB0jFf_E5I-Twhl=TG$1gn)oI;1aaCMO;gZc*j4Y@?+NM2 z*;+@3g~x}Dq@|}pLe`egcd?xxXmZ4F{1Hgg<aYznxyd~QYqcb&B*Lc=<2N&_JOz~? zZ9%d;`Q??lki5X{<r)6g?UzrRB5}PNjeZ<#dV_#SowWsPu@|54p)3;U>l2QwXS6&* zWGpEk$ebn(F?ILy838?jF!9*|VDG)^qQ4@wDXk;E)CF+|&}#u-s9G?-{>!KX`|E+c z74pXqTKxYV@*`sYpXg1Ns=FSRG4e0kHO>T*H74`<WS52FOP2&DX-y3=SgC|Yp!G&4 zLjyj)u`4SE;|4?%lLaKWLg7J8iV!9KDo~12U*a+)8F?h+PTHI9-uEB2ea|MQrmP(e z7bIVuuhYLdd!DzsUgrT}fAWFaI1P+=``&=#2JX_}LiKLxV0g!u<QUwUlRVS4rHpxZ zzN52dKKT83z8`PIG~u!v2h9lr<+57`%?SW?|HLPOy{{AHx+w+4x$isPwTJccOX)uG zBX#?d<a(_K%{~}YP4!9|TS?^_Ixr{EHNAr-`Rz2&!gXVf<1+%v|3WkIha1-m*QeK# z*J*(9!+RN;_l_Uba_J}UQ?D%7jUw#_l+Tr)uG_B1OA)LOaL-e(t=k<|!tv{Y?d#Qb z>c=+VubW<6_m}S=jI^SU2+%)gem%GIkWxBEcdjH~dUvuUUj}!!BwzY>x+GtQcL)h7 zTVOUqK)OQcIdIDIs!D;$+~FMSI0;N$+KWu$OUA@`P1o`J3N7)oMS<Ja*xTVd>m;N` z-k<`~b~F6;3RWq|`xnbi0btQK#1!~SmvM*+zZ|@T6hH^#*s5Nh$>8aE$jTXJri4Ry zNG!qp{69J($r+IeJrp7dsZys9^);iB9A|@oX%NMIrAb7zq#~O`oRwuFZL~GDO2bPF zg_Yd>Ths=)pw34_kuC{%w)iz?v!SHOtun&>@xbJT=iiXKTqTyB0+IU=?6eVZN$9r> z^HGv(@Ib4evQ_(qW0;ung`LR5eUIZ*nfGmiDj!EFswmI&fodurb!2d`<lvT%L1e(| z$1rBZ>DS~ap%0ZF=*5|L%-eX;V=yDlu~0^co7+T}=LKs>&gxMTh%sE(I{f{KC{oVA zY>B)v^xfgv0^inXcW#8<kQ;mMmaH41ngY;64(9?(NtN5Z`Qe4{s#9`T0T?~{gS$pO zjX$Kag0<nx*||mwj{*!PI0_u7ireZUFQ#OBLW&P6x`hN3I`$`nVY1xiPi-66qXg#h z%+*cJ=UQr9DF}-8H{lVD9bT(5L(@@734aMgkFie4Duk4lPd$W5g1_nEVn%}!f<?Kn z>6<D<ixN+lN)i|l<fW$0`_5bPlqe0>OiSCL=SC8%J#lPcdra@g7l##mxG9W3q+f5s zGorm1UHT%Cs>&9VXcML*$euBksge*YClwG`*OXJ7Z8Oa#$0HuugbDCPtK})PH1Qn2 zb;ku1T8FKCzM{gbAdlL#rMOP9ejWilPSUy`^jlH+j33>;_e&^5iIwe?j(2W2dm-ps zkHt~;!X+d6NxC1v?JUue@d0H4gwpjBqQ)2iNcmIs4%zt=kZEH5gvr<BgH2Xc7=45! z28OATVf6rh&<B2m{An#EK3woK{Lxq5a+3^9EesN<vftuobO41O^cy@yTOd%PTCXo& z7T_s@pj#6F%^=6Pzh7J-4jYk07Jw9<Gs~kn2%!QWl+ePEXs^ez%swG=Lo{8xZ-f~t z<|xwYXu*(F@{YpK8NK?*F$b;iTB-s9)b!7ADG=qV6cPJT5%3cUyd^F40ji`hWB)5~ zv|f_tR>fZA*7>L@fa?AwfKKS`XgSM-W1v=G8(}piya2FPkN_(}dU$C}D{;JXG^vq6 zaq?XGW|BOpFH57oCV*hy@+L-^whF~w6t<&b6&6d(q?zT&I$*RAvJM`K9S$o}^fB23 zJCA{>F`$$hE9V8Q`RD~PxDtG1-3z>y;wgPMUEhs0;t10=A!bH-J%Pm$wV28&AwDL> zggVL{kmw~&HWgU;lU^jmtg%BWA{gy3*O-1}04#k6>VyG1VE6l^3cMzDVO-Mw;I<U- zz`NYIs!IpGD-VvQc@IbMG0WK>J#cw`69&4KoMorut!Yi~jkSfS^P2J_!rG)dT0apu zmFXSQ28j)ttc#n?ozAIN3u#8CoB{0Q<%ERxI!N5)!{lsGwoj~=*OJpF6;w3<3pngE z#FAVS_k$<-vQGRb=eQxxkFt^W#m#Zq^O89?);64a=BZ*&pXxc7XRg>NtBRCb)QzVW ztc%r+7Z%DN7SFg<k*IMGMuW<-vNL5S6Ev;}Q^Ox-PsYy-$Z;j+)`~ow;W0H#Y8Z0r z(Ax*`tTx=$wBNZl+JYJgizJnY20j+}dBOG(Im*;*G09QyWOoJw6LUM4RN`gQKqy(+ zU@hC3s&8kEbbnnF?{0r;gSLY_Vdt*KXns{GQ8M^?7tWB?EP=k)qo<vJz!p-HR~PEd zE_Xw(3BX2{jpI+}1lI_%ydiOQY9*2E83>)l85l5Bn|f+u#y`@V<>P+-{E=%DCdm=C z>>n`xVQFTZYSP6-Szv2iddReM1C=<%_uADc2ZD<5h@Me}$A_sURPeT_??&AT(~G7J zl>&!kcdRF%!)H2vstIqA_EWU<(Z|l@2P&E-_D&!)Q1{#q=)!2tTx1lpAbdyks4{T+ z-I+Xg$X%EwsQ^kR+2~45u(wJo^(~Z2OaeG!xC0J7f9G^P8W2a*S}l<GOLaCH$PwdR zIbI{uL{iz(EFvXW{yY)sJOdX2cgG-(mRvdVO!`>qOd$J1Ow*v^K2{_SaO4<YI_RX4 zKJ@mGWt2cISb-(GwjK_yi=9hFIYb<nx6fTgIZkLu+-A0Sa)}=>a5`ux3S7*wx@r*k zLADZpcC&k1mTu6wEJGVcJb=!E>cir|1H?d{<cqP)jIm892gY!$_`FgQ9H*RYnptmI z(i67hrApRkjb_a<(7XC8cZ#!SQd@t9cJ*Zw*r$}6w|5XoIbfEI20`TX$fb;e&T@^P z_&E~rUd#1Svm|C|=En$N)EqS7L8+*Bd?~@NDI9vw#fvMfvH7~9wS}_dP~&V#N?VXZ zNA33?@y&*i)K#S74uO%{!ftFxgl+JJZJLyYT2zT*OGZJ#&xC#o#}^YMBokyrvh!A% zn~e{&M+A0oN@ArDPvd*qs~qr4C9p9H52n?FYNmlck@<0}42m!I%<FJmYv@gZsJWx8 zDgr$@{j8<@wnq0;RI$})Nf%f``EBzRSYEDGjvL-X)w#QDTSc!nsAr8Fu^Zffbgp4F znKqEbOhFDF4Y@b8O*=g7BdKSyKecfEWG=yH!@8@<3Z8{(<jTyz(~Kl?kJnML2s^OY z+VFr_j}Bm6oaX>MzXJNLW7wE|P-KGPp~u>o5r;@H_H&}o59X!-5hV|DITy4!7u7?~ zck3j;u@2y^Zhn?hDBe1c<By00xUrI!RwBx_#Yy|`dFLK<YvT{i^m(w9xk*9Kk(bw; zU>FN*mWP(tiW2>Tv>#>%zl92iuyVwWN}CquPTb5I8oU}Rrj?Jmejc-OoM~ZlY*|0| znea3Pi50vPWjaGlv(UPvOKMKN8aQ@SGvl^T2f228F)Xq`Z<Oed$Q7@t^&uEQul2(M zEcbI%5`LcVf_dBainPL`VzRLD9lH#uxPf*ibguGuO?Hf8z^qDfvi8%5`!(p}c4mms zEU(s2&@a$%Nvz5Go|Ct2Np;ige>p9@i-Jci=y;YoV@%tZC>&Opl#J6*$WfcHpTRcG z^<|+8M^=WJ`X)@`4E`XWH)4;`qxM_>{)|Ok=WXySoUmA^s^#vhunmh5yU>Gr7g;0N z(hr?YPwa@y4V&ETQIrlYsmBl+jlugrr=OmB4_S!G*4Y%UbO-BkeoI@a24T#4p_`cx zp7J{*mTI(t-E4`sH$tCX_PPd=pRu1l&#pGHVzz*m6!8XX_iNiDdbe#?FtRf?Fsi9$ zF?@Ol*@c!Ef*Q64^CAt@@~@L}J5dr-a%Iru6oK=mGbk5{yhZ~pSSuP5wv1pC>Khn= z1ydgV9Wr@U*=cCOnoO(Z5SS}iU^X<{2SlK;=5R=_b8^w5jd1xs9ij35`Z-dDHZA`W ziap&uZ(q$|7rnZFkwZD%^u&fbiF{nkJ?+Q7E9WEK1cw{M8Ff9f1G3}fr=$h94V3)_ z_<!3ze@(L;b)JIyzT38C-|5<H|Euluz4QOZ3!IE?oc=}Of3rbEQsy?sLgpqW|C)Oy zUH^sYj`T><wC%H*VE`b76E`<?edNxSS0M{DnVT1wOBN}Ry97(Bjqci`(x5tL-s0XS z*;d-R<uL+8XW4rlNB&COZ}3dvlT7V{8MwOV>UihM@y<4N{Q7tw$@#I}S0DcDOsBOF zH~i=m&jU9AP487|2-0AXM^wm;%<6p7TD?n1|EqEzWgNrCvX$_`9olusOIA3D-_<IG z*UWaQb*6VTw)TvF!vRfUN&4Kf;zaFA#Gd}f+SM?afB!d&JNJ$yQFubj<)bq~h4x%& zE6wvn^peFb%0Rd}``J+`vF77P)E<W|u(16stksM)^09SD3ODPHjoednda^BW_OCj` z2(!fcmSJ=m<qlUjt0gR&)voqKD)nyahtbs3CT-4CLpoWoCLwtLVCfaN>&KVI;3bQ| zNP0%eu_#t=Ps!Yu&LtNBgcla#41&nikRLe9EaYR1Yb8$871rHa5oU3j?)-vE(vY38 zsrc3=p2|^6Xu~m7n-&|>7|-U~x)19<SrPAaQV*TW$o3jTq)@6~zbK%-?NtUZi@jhX z(2={5e)gI2^2~O)uuxos{(hn_k@^>CGQkVjztWOw#U(*dZq<g4L6UC*^>brSA56pa zYh&5XY}y_nC59LQRppGty3^%@FT!j|&c!e3=eg%#tVkV%matBcd~_}@)iuvRtOG#r zis+zvl-SIXJ`G<#rklN@QaoQyw&=kt)(&X6XU!W{1Ub7Qb=ss_rL1l*n^ENqwK(E< z9hl5jqGJM}K8=b_MX7@e%|PPg^KlQjXpY&Kq;{a!U85TzPU+J@b$qF14<O%9-h&o- zq~=m{rE~X8%_ajk2ucJHY|;_~_j%q5cp^7B3dxyD9N$9^r>_LYkX_(sq^}8XEmywC zfI*YZj};#bfdyX>2HZ&Y5Bu+1eIpojG(=1kFcNM9i3mnU-%x0T<9bSv`O{@(rYMRI z7L5p>G52}|wJ*uS2Eyw#(l<{5q-T@-lpXZoHK55C$GU^5Uh;?z2usnVw36lQA#A@R z`W=#I1rv|q#|3D<u<VUVzgYL`vNmxVxjw&$5<hhHo`LoF1)jd}T;UA)9bBA)oDM}x z$7kdWKs%3f=gk&c!}z^~KVa5c<N_lyZeZwXoe<mjK7a`_^I?B8tpPE1t%bgFs*CAe z0Y4miLn+;p8^Q+Y!-R-QWI-$m6_N-luMM0kg&&YQwd@9<V8qX9E;|0S*})WN!Vn1! zWzrhh80;VQP|o&5O<;<EW$?zdLs|dzpRWbzpTodU-`qafUrmAkKd*&<wTD$K9TAn$ zd}Qj!f-mO<@VnH1A`^>i3gqR293(f(VQ3V|K_NS5WCji~k!L_FjL>rIvkma}^7gL0 z4asqq=6qgU!{;<?SY5-oNRb@hZT~*zKIVS?JCuVik{Iw4ZGqkfFVGTXyVsdns&N;D z#Q9*+OK~JI+8hvf9}&C7Y4W7iIv3j&>SCnwCt?G~6~@V6>bh5Xa3{tUdg_2Fh|{KO zFi*^GX*8{q7dhO-nligZiUh!sP!mO#)lm70u{ItT3pdSdnx`3e^E`5ehRjTBv^I4P z>S|7v@_DtgvuTxtAcPR@s`5scSeB533g5(Xc%ci~f?`yV`{`!$5v2lp1#;zh<>9JD zkI3RCD9aY~frSjacDyrd6@Z;q2G9Jyi|~9JWra<1bFCSBvZf;%zi8h^liOmB_)FY6 zv+U`|k+#Ft;}otfzW{F>fvE=XPKITx3vpJ%IgPq}#STklIN!U8>Yx&jdLpnY3V3Ld zLj))S;?hvCBvw%qUtg`#X7yAl6?Jng`tQAmejSHaG2Y?T1b?lEL1#69_mdv7tlM-# zy3AGjRwF*`nmuaSh^O@nXK|IsI;V^I`BlRFIutNN*$W#zR~ZM+NfBZ=1UN*ZmsU#c z>@}3dKh4*_^S4<IQ!0`-?8sg&zYw;!AsG}c*?`N4&>x~9NRucLZTGSLuA)G#1e1_F zw+G)}dWAraosp!F_!COLJhez9$RIPf_J!G3A?P*BmWnufIB-&HZ{>1LS^3<bG%G8j z6vR2|R}CJn?8v;cCEmV6z0R;TYDSPp>XMb@rKoZ(@<GfE;A5QR3Si<f-K_R3x!}dR zUBWwG&p&NF{@~AOOjLwhbF``n=}7`AWYv1#yX!YpZ2T6hk-Z~2x0#C2z>7<ruzoD? zSZ2ZKgEDxY1hH#~6N0c9*q^U&uEWyd;_lFLsfVd*&?w1T3_U}V)aiX*eV&+~vTlv0 zA9}Ri-W75vNg?QF*WiT=#xT5o!U*mS8+>AN{Sk0wn6y)sE-7W@+L9H&xuFlEDg1Qx z0^>(~y^Hqy(1&Nevz2W;t5<U~sC9wuzB}F_vw|@b_*kqQ{I-Ggjz;vcH-G{o=k~dk z!5cr558y08C>((aubmu`un50cNJLYZjCWSZO@bPvZPcu6Q4Ud~Ty=j{hzRlY&=pwT zFJ)F04ssXvVnV1Xh3;-w$NC6({o^rK<4Gii@y&+o(-j21kN5zcFZ&B;5$g#-j2>9e z_k&*|^WZCn$-^$(4_5IH6bZe+DI=Mq3b>9?VyEJw+?^DuSd$<A8KiB}5yhZwR{X#N z((V@bRFa4!k63pUyu);Sew;(}-G#TMo9x|nlz+1)vWXA!`>UmDs56s&ZdkwsKX88b z1Z>w%yH^rkq0M~A7;Kr(IGqyq^jw<E_JXq0Q3e|m^9v-*7m#Cb27%zj=E#isri(E_ zfJJ0I+#KqOPw>gT>M!Ua=3l=X{I}t*-aJ0X#~BC5E-yBEu{CgR&_26UT1&RpTKv8~ zmR$Mi83J)%LXQs+BJ9vb?SklajpOPAO^{aTf;rJb4$33J0lWcu;mUFC7bd<q7&-fC zy!}|1EKt;{4FlPN-W%N_)#$H(WR*~@8pC$|b<IZ_c-GM$;7{`!2O~c>Zr{`YmDE$& zf>9*vjJOKmp0+J?@oxk1zjjs_UYd!2IZLR&U5NiH)JVk2R^RFW1z!1=43XLzEw8c2 z%0e-hSUS#^z*4hvD>Sh=RUuiyIbCYK>{Kc>Z4u>f9U^d_wjC<aP%ZgO-yv2{*)Lz8 z<(W6(n15u5w9@NOnYzC_-LIcJuD9Q>vi>~$PO|(_i&4$l2l>pYPaFs?0&WBlgeOot z15RPaG!LE+WC-Jyi#BY|whQ#%GDL(xK^V2`z<*?jf&X7*h@BF4kvnXE$q=#Z=6`<6 z5Et>r;<pF+^E!IEs$&BDQHaSL=t>mhhpJCba!a2e0`xP<&y@fKT4m*kJ(@`%AN0ld zbDI_ALpt&07rOk5!^&yM>yNBqDgC!A%lm~I=-a>#1ATFj`>_rlTL{5gT?;xKh0qW? z_4#q`-kg==Ls*s$$5|=KEPg77&jK*a4JWEGkbz{#PaT^mw2+uPpw>)F4Ds9Z{VhXW z7sQ!flQ$G#qu8V2k(s3qA&r&Af(<O-_h3X#5##4a_0~wqcNHG^Hf~7I5>pe+y~8}o zYa+3eNnhs@`@P`6l-I{P$g#7_lMvh*sdGFo2mg5@LAaOvb|H!?Z`LtSz(-QE;~Kii z!H+5X42Ygga*b~ZgdNGLO0>^iPNyxJTUla8ogjjUZtzTA>kNe|2|=A0z!{oVhxL#n zeY+4xYI9$UKHa7{T4+uAr$aX5k5EN~B~H}i-HGnY6wncsl_3nyTFT1vZ4jBI(FA}; z%)A<@5>!IUg$TjZI&YQH>Y#j5JDs$rSz84Yg_R*{U0q<Kzf%=A)lGhn@=KFAF0i!B zG=dc(HcelI7cDH(sTKupwPVQiASeSGbO^PW>v-5y62;uqLTvBoBX*7rfUJrYw3sap z4!E>tgs`Yx`nI^cfo>n}a<dH$nEOBPB7w4!YD=u-ipCjfD{Tw|<}2%}o($w$ieVrc zr^NNs5FbFqA*V}Xs^stHN~$=m<etRabHd{Gh8V$U+`)TI4v+%nAb5$`flS}su=jC* zaqM8hev1%sx&s?vT6+gn;r4e4wDxuxqN;n9ak`5Oyanx|)Li>)a6X*Me{!7am>uQi z<i_Nt<i^2li`jbS287u7)A+lb^j5@9Bn`x;5ObhGs^B~qO^w)!;BNI@fQL>bn;<=n zVIZRtQUL!XX3)1|xQeGoUMi|>QJjw?FjHtET32Y}^oAEtk=8L`!L_v2%m<!=BtI+7 zHH^#9vbIP=_M6K*PL2Fyw4xFJD3Rxke3Y@==%HgJ^Il3d93o<^YsT{kV`vlw8=IJ% zc1<!YJc+ELPAknZdc$*v8m2U5ztdYC?d=T<3Mt@^^c19#|1G)HsJ=1xfq$$}7nN{E zM@SMrbQ=j}g@jpV^iQXsOwc~ZbBv^EXOLt{-~Zc$82^_EQPy=P+3lR7*Tw(O{=Og6 zdo1!w;<Qpxcw8+UoaRt09Q1htOpoGxNFD~SWEUSVvmM&Ru*J@fikF2y*S87rZc!KL ziYxkVhefD_UK28?7HfH@bY2U%Wk4gK2<&{^<J*J?qoI{SO%qbW1LB_TXm0c<)=UsI z8HeYnhiy$aih*c^nGigL$2+DRczyaCv{~LBhiZ(f0K!V7O1NOzn8~8SSP5~WwBM-! zg8@UBD`W@8tl7<jIvYY3D%>Uhe6CYc4l5uY334L$hdrdmiJ;|m|8W&L1TuIKMC(H6 z5Wd+Mf1kPHY7j(+ygn??v#Gq<6u*A5v_2SeusnbNaU41FU1^90#8zvHO47;~m}3n< z&xWFlAe4#jw_h+Jj05uy-dL*~&z&f!lZ#)+CeCp&^)F|M>{Nupz}`n<Cz~${?qn>g zCLIpeFyPH^+3EDP@Pcm@qV-=Y#L0hDi2oSL*Nmd`CU4Ov9%_xptr<$>jvgY7Zy?7Z zJ}?MXoTdy?bxu{EpoZTn^9&e<YA{4~DWQVhS%M`;?b60(GsOO}lRs(sj{jpPN0d8Z z4~c~2{>x5oQ2XMc@ogtB`rA%U9$hNKmXG10R<_Dov^eHehWY>4$wA7pzU}1Wf7!{= zHjVzVlQRO@f&OJDmtEy9YuvUXd<Pu+Gbv`G(VQZ!VodlBIre8-fTj0Jhz4_wSM13a z<S!LsB1^%)REW+Vb2Z~~57&gQ_%XOZ5hIp|M)<+b;2FbGBLWE^tgyX!757wATVVHe zp7?sV-x5pWY>&xCG^&j7aw2|Ze<l8aa$Z8^DW|gLfKfYXd7J9f2{X}4r^}Nmu_mu} zr6@Q9;K?k{UKUI)%vG*t*=Q@Ss0*O-3>yGzz5CVfiTc}zzg36{oG~+hs}N;V{!$?t zv~yirWos6HJ4;Mhv4&xZ-#G7h|Fe7vM2g+c`z~8{zQ6zLFxo$B?|-of|2N<S*b@+0 z3)2G#9+GA-h%}UWIXRXOfjbitb|-JJ%x05)VDe^n%Cq|l_6PegfB+tGA*kzP5sgIw zxVnC3cm-Tz%!J4ml74+%k$qnClFUd1CwL^7<1wZCGQPy4zNKlv$E)@M5Zth)Ws`0O z3WSwy)I6Ey*k|3GF_F|)Xg#_m$BRk|W+uYJ3(3hn&RyZ8Tt<B#=6~KL4Z>l1<~ND( z_6>~xFFy9)@A5xD1ZmlC5W)K|5MdsndqNc-XfYO$<TzI%bQD2Bs0iioZxG>pd^`6~ z6%HH%sLu~x2>K48K+V{u2F8YK?w&PoA9pW+*<l?pSWJA0)k?c3?p_yPjyxyQ_&6dt zshgNYl_SzV%i(wLZJBvUp7cv{>KTz1z_hFg{{F029S$UMU8C{k{bJK<<!OKIG&KIw zYzyj!1fhergQpmsbZy}j2G+RCe@Fx(<fGN4j_4KeTEQRt8MjIz9fsN{f3VkQNtk&0 z@B)9$%d;fb)fZdh%D~zTVq?N~d{0wD`bQ!A&#vQG&QzY1tKG&8|3VRH^xI7TLJ^di zcAd(}3Je4bAaMD8wfnbAf=xLQhjarl*_i_07Sq6nin~Iq$i)_4cO`3EG#jSbC~rn= z+7KO(J21dBVaXaXp2_~WrlLpd${X!raA}AJvB({6-(h0ts=?AUln)A{LmE!e7^Z^v zEV=!Ve(+i~)v@Q;unl#^#*I)JF_yfd#Zke!$5g>Ku&%6~ey6H&4_PxvL7u#g)_6t! z&xdRVUm$S$jUiBfV+j8X=l-{c{I71Ds=C@=0v=Mn;6lYxv$^kjTTWn6VKYcVQe7h! z042~rA4cD|3_pMo(Q50g+F5tqg7w+kHlnvAr+MbA;ccg)ru*&am_0!sp+5@!v-{~_ z^YG)V?U~B;<@Vb4*N<7>S2}`OfzlzN)Ip*Maukk;E~+bicvwS>??n2^o11Mo3cY%h zAbmpgVXCWyx*D|ifmU4Dz*{_=y)D=Vw%$E>l$d(A$T}QaE;|^#KvFfXu|0Bh*%0s- zbQ~<BTdIg-HLjUGU=-SVH}T;K2A#Ou^2ik;KL7bNF*6fOttP6ec)7*mA!}uUU9tBo z9dLz^z@;jY{`#dr?$Y4|4g9Q}Nq>t;nR0uD<`eKO8<Gey(Jj2sMvVRRz<C?)yhoyv z5hh1I?1%*^^%i)={ebea`_(L}#u6uksxy|!u{ZFk`tvo|h2^mNZbF+<mk36icsM!p zedoBVuCq!FTvfz`$Ioy4fF$G03#|rYr82c_<_4pq9$;{Tp*X4qPF_<ebUiuvc8HQk zjU+rU)~4yVq$|6gSZSW*!%xl1%ZxdLW)_;=WHC{m01VRN?hk4V*`S_f(&9k73>HHR z`Xzgltt+Gc<&q};t$Ffp>c6Rhs=&KQN!bm!{$(uEo9oB7Uv(*V>V*R<MZsAOoZ>RZ zd79k8mqSIPwIxgm7W^$PsTk}wFj8fS;`&=>%T$!iWV+3(mLAK;C9cMk!3M(*kroz} zj<-$-&~@e92<3!6STJYHp(Ys7sNTUv8*i0IP#%rq%*>&0qolNn2*S0SsY_CdxFzXk ztkMIU!afxVfkd*j=B%&PeLRXeE}asnx7||+E`NTnYlNvL?B^?Fkz%j=5SkA+!en_) zr$;u}?j?}5f`lMxMR@>g+NtpqrmJ!Gud4t9wo3P%vk~n>1B=>A4ch~g+9~v9xJmYH zSgrWmpkI@@p<a)<>GpxX#HP+aFLE}gKqMoSGMLW=DRZ<flkF1%e>Z&4b0}V*zNrI$ z{T`!R<cJ#eOapri(^TUQe;$+;15V@Sn$f%4BP6c@Qq02y=KH*Kb<Dn4e|;2BIwE~R z94-kdT>Ut?G+LrXwEMPgyga;q*l`W{c4&u_dsBGp4l{wJ{Vc?)Zvdfq%j&A}jrlH* zDe9a~F@DD3@mWT!)fbY~vWq-qBP~cEs+uZI&0<E9TBtuNtwfAiaA7=+V{U-x9z34J z_=-gTu&6{M*~@`z&xI%B%;enRNwho)oF`-B>16zLh*n(iO5u_`U1g+FDItFeLjMHH zQKQNFE|gQwprdT~YR-zGUCYjHmwv^gR$Mct;~oeu5<LtJw1mZ>L$-9@325_NHzyn3 zX)pYtywxwIiitENNCk<urDoyreqv!P`}kJ@W~SAao&}>lb8(Y7q6LEu?L;O1R<;1L z_n`2}dj-r-tw`xoQg24@IN+0l#z;-H)0F&Ji9Z?|ZP6mwjVQUl?VNrpG`?X1$*{lI zkgEFw#KW)ahQQ^w`iUHtZMDL)-j?8)t8!8yv<Ra*Rz#4C)})H^KUl)jT}ZL!hc*}Y z8No^wH+wVyE?@XDx9jnPP)ZpBn`56$_kw${@xz92G>(?#Bg;g^E4m&zS!A3qs>CVw zS(QX)$`sj^%6707I1O}GP-t}hctv|h&Jwj};t1&_5LkNn1;6WF$&rDa__@;qCUL_D zqMRhE9HhcZMr~H`Db<wV1DVOEs>=>){IjBAi|0g7x!A=Rh%IPHqa%TaGxIg8TD#=F z@3%kAvsfC}JsJEB)>EHjgk#@>ReNd3X!5gb5p8)o?RU4Sh*?y|0~PfH$1)f)Sy%VV zPJhk)b3mARy0-Ec{4s6E9K($+wP@Hg8uFC=o8qZZaENyH-=9@s4c~`stUN9Xm_uNH zIUlh>+_*pX(Q;4ic^4D>kHx7LRla9T@>%%aG_Xrm?4>fHW#hm~yl_kE^D~Ee>sbM3 zt*K`MKbK;J9uZG@kMquE_?;D`oa21YQ1joC9)ABxqUik{NV7C$QvycM^0Vfhs{+Gk z#uvg}4u9sHAF53bT4vZDl(NGO=e%L!3>H*O+}hrc=#PWr6l=#(-wB1^V-ET<|BQ#4 zmA82FqprX?eBEP_`tpNqk#lHz@1@OodoskLIn?hw1Gj=kU+6Wk3P!m8)&cipA!`ez z4-sV(UQh+(@WLqe>;TSJYxM;IJ=d`8fbxrpve8?t&C5L|LF8SlhnR+`K69k~O1JF0 zU8aZ`<xkz2C9+}l+u-8?^uE-HgmN&suIU01sDyF9d?YAzSjZ^ad(%!)Gp{ySLyZ`A z2P{?poYWuQyh{jX^q18`%3z=WHq82qK?r6)biDfB40(L7mqh=oYi;Xbt?%SyZe#k- zQW=$KExRCxH1g#tOI^T*Mkg;1LJ;XEC8vaiC%Ykso*JnKLSJmPMP);6&WXSqp3~d% zGH#x4EBzri?AXCEY=uVafjje>^PBs4`_G^IPf}m@P6z{(Fg%Z2UsgweBloXb%$VBV zXPgK(g1xfPA-wGGpw|>3st7gk{*Yq;6?6}UwH41-*EJ=YmSl1Iz?PUpMRxhPCI<pj z^l}xM__^S37j32byF*bi-2*a|aC2g%LArywIHpIEK4o(i=An={eN~`UdbobsLE@^? zq<>!ajrd)yu;=rM8oAmSd5c{)beEXCz(#rT#bUW=cpWLOG7?M)>cM!oRjJn%l?&>O zAYG(Op&nd0v|X?dDp4?>IBR+RQ0%E!@z<+%%%Bv6=XgVlrh(c?<#{;+e1}16Zg~}^ z!)|~<nzc^KVb&??`EMz)(o#+b%V3>_@Wgy#WyLCF5L+vY914>zRdR*JM>TWKjAX&& z1xpcr@rq8Ty!$G39F^YmKxZqlZ#)bkAI<p0`gk|P5P*faFg7{14+RkHPi)^k3&l=Q zU<z6aU6{RwcD}8!0F)w>D@}<Znia+(Rns0(@H8^niH4tU=-8_A^^I5v0ON}+W{f%B z5d~hUNx6rCHxWfkIW8SkN6_j5CQ73D1o~C-iRqjqZFb2i$s1g8ca8~8DBKBVFJ6_9 znQ_`O*P`oC$+@1h+q6}~`69?DkWxIp1tB!yCLa50fhJn<CyfrP=$S8oM;UJT%I?(L zuiljB>BZfdL+=H41YT8`b&G}@Lj4L+Odsh-e1+ptAAg*@xRAZsCA&SUyLCm}@Gt*f z9>h0RAhh*9RBQ7x{WCGgO?pw25W7o2gz6h`zgjnx+Oz>}A*`9h&)r;1m-IKO2$#j+ z!*y5sE3+BSPy%z;75t`#LyZsN&4Iuwp0x*E=T!n2`5E4POVlt73tNpvg6Q-R-XEgW zyR$F*y6|uFM_#jg7ou1TPeo~URaalY|GBrMZmPRa`TnmgBLD9)Nz~ZJ*umWJKSI}4 z)twNHk^U4*XE0@vSo<N=@@X{33sC0z%T*K^mnHfa`%+WLB$#u?nv72tDyVKgdjq>} z>UhOEHrhRu!rF*tYk%YaDUJ_ohggqpUug$3MjXTiNBCcppDFKK?^~W<ob2z<p11&N z5v&1b{btDdXpr-{wYzd~A#nz_`&MEN{Kf-;xS{~F{<Hc(vET*>E1>pBidMJ5KWvO< zG5}iBxNY?Zs;pj9aa(}xJmK!`MSr+5T)Nin+OTX61beR8<={TQ-}?GWkn0;2Ci=d0 z3(glVX2;JLTy})Oj)5CC_?EXaq$fv4l0cH-qUENI!w^@YWdR&DO>)&*<owWWNiW>m z<sqhiHXRNzw&uf-8H3`J7Ay0PFQ#MXJY^h4((aw-QO2~!jdL#0o_AJfL}IRLu}xX1 zFD7cAMDMpDTcl%-TbNh)a06BUJ$7N6hiYP4l>cn1aNy<+iCEz@Cieg@Ok(M=`RH76 zTG+3{T61S)^9!CiSscgd&<d7VS^Ziys@41~(U)OZJE;FiELLn)FGgZ>Hu0fU)RObh z##pBHlDN98*?4W{1p#AoTgSHHRoV+G))iG)erB9<c=sci@w@Mt9z{w|wv~oqajdJ- z926XAHG?qab8?GYK&1Ox$^ayphZaVPI#xL{r7jh@RaWFNV^^D5al^dWfzVIM@C(%1 zNy&LgwbLp#FrTtY^YUiNWoL7xE9_lPH+(V&h2FP4W=_H`;Fl5Vrl1vE-R+Y)f9+_H z%FiyLyG#L4k1B^OOY0N+L?<T{TkC3-W2Fp_kNx;Kw0o3E{F%;$>2`7QA|hhJtEpql zss-eq%*iO(+dp4VfR+##8<#ceNq+@dM2=zb4k1UhEmDmtX<o6ECInUyg>6-_U;<U1 zqpdPE#B*wQ9XujMR-jYk+bT{DE6E94OQnP&t5N2oOA2#^h6r&*ihj5$4H~*>4f<#i z?}0b#qrM4qg_Vq|mVi%+HZ+NZjYM{i#gqth1(*U;g`OE&kR(NFP@7VWpHIZ>6Ugka z^Jb&o0_Y&Yi}I>xaMDpltWKDq9Gc9R(<?@W0!~)rU+6V=6Y1G+vxz+8D2rp(H$R#Q zWY><jhmG)Bl*&t#4DNE7FiD%D5z;C`)&nv+>hy`j*VOMai%gwgTta6OB?(_s{)9Az zMF=8}n}c@lq+55?)T*E^6kpl!0MN#0&`Nz8#>d-hHqI!N6IhO%EpQDaJ%LGiQbX$d zgd{g8yJFdzSc=C<88iJI3ch``9&xXz&CZs9<zQ4-L0B&08o(by9+dciA}xWH3|(G? zTwOI2wCt{BJuIiN=B^+oUX~mS<&uGQQ))5CZj0@rN|eBIwyIs14+iPZxb=bVFnNq5 z_d|fI`KXIXuav3J8P>HaC^-niq;9HkoD{v|=!F2$OZq|hx6m(4vg0*wp&4VMBz^Ye zUeTe}_-#!ylhkbE2dH5g!O*7eh<Zh$BtzsVd=Gz_+D~OC0uhCPCd?`|=v3R}CuU$v zYcFedQ5#Y0>5?9L|FDh_C&-7&DCvSspYByoGR}Z-E|1y8<zTujqtW~(-iXd(z2F-! zp2`7_XqTU3s2m3oSa%>Ho$#oR?ucU<*mojMcCQGIU2<20MOxjF2Q(p_z*|~Z`0f>k z-Wl4(t=1#aR*6u1fpzd<P1z!c_AfH<#(&Tf02WHub4;tU^MSpjZr^~IUlRX}c$-9M z298ks>uBk~wSdK7YHo~CpBCUUmsb*xi1AK@AC1GpVNuo8M8ld0k`9AXo>}gh!mTg0 zdtmIgV8?v`M6p?}BQ!DDX{I+cGvy<6kTZ^3sW3ZMq(fG=`@gi!L-ID+e0Yg}e4h#M zlK${g1n}9@c`eJx%CQ~$x|SH9>81L}ti4yf9-es~oPiyji5Z-cCEhWuQS~{RoSvCE z_@X5~G|fTvIcmSXr@Xz#yuIhVy%z<4$&(cr@y0S(z1KizUNCc;=o`u@?bT)3gd2gL z>V>x7l>2#w_ZiFv7)AxSyF4R*&vOL3EGlEzCmMaOmU~5-xaK>6#l{85Ht9FOh{dzR zjE^#%4krMN5i}l8GPu-9J#K`&p>1j_TV-mOoe)cB5u|~M@4Okxp|yV!>5P?LwZ^%x zrKO3~J_nACe*)aVhsy=}zz_Q1Jd}P%K<a>`pEo9{NOGwlKZ3%!R6{UgK)mDBO7?(2 z`oQ6@^YtsQEQ$0Y2j-z+JKhM)Gy3D-_JV(n--Jzr?&7|iW47OioBmhdMAX67+3w$0 zwkU-Oi2*(&?uB6y%cjRqA0=T0-~dfc2m%U$IpGLM*9Ep_LVEIqu-spV5_Y?wFY<fR z^C%Gl8NyfG$D8cW)BES|`-r{tE)8Oa8$xq~FoMMd++`I|kSdpPyp9`(IuqUIJP@KO zk}XifX}@UE?wC)*&Tq=dl>%6`4NNS%2eve;jRHFg^EMdt$d<j9>T!i~t#N<^%uhZ2 zyvsgn9WnM9oR6Ym+Az^S%_nQwPX5fFI<MlIXqz*QD?5lO8l{#_B#$_knwbw1P^>Q` zLRAZ{bjcsfVt)!0sSKtwoa|AZc3=5xS1|S4RPHKw^-Z$Cp4}yZtT$AP+|oqJEi=xL zmS9kdBd%{E3pUNOy?RbBeOU*QCOUycH8}GsMYqPz5hM9H^Mq?T($NjqG8;*FpbKJR z2p66NiRcDvjiuNH&teZL4dP&R2Xx6N2aA7MP1-1G!|x|jlPIU+5!<H;!8n}*t~=>Y zB&g(a1)&f0QXTyWzu#)*v-EgF*fp+vxTV--t{idix6)&b*8H!wE|UK2UEH^fwT|F_ zKT~n*Z@Bp1pJ|brxt`K@6rc@*CP@sONbnB<v?sc-z^PhMaDDN$z`Py3Djo*fv4JtE zRA2zLCTeT#a+kUGrX~YTbK&q@aUx|tO?b_YGUqaD>x$B?iY?8i<4yN_69)GL@Q0C1 z*K5ybAJeYmOitMz*9ZC^j6(*bFs(Pfm;j(zFUgoJSVj(`VW3%T7ya<8IQ;`OPPYvk z(4;WQc)mES%lq)GEPJIH#a&Y0wh(!e7<%^M1GWT2DV$?#*_#tiuD5DT**zlJ9EUw5 z-W-!VZj#@ocafO9y|C^Ngs46j!?HJ(kTY%aVaI77i(#lQulblhor4oPF8ii#K_$Gd zyQnlD^HHj|l&C(J{kCZ5%sLMo2@5oxyMq}vlOvj3U(^Y|>0h}Mcw28oeg1@v<)nQK zMYY_*#QYgQu$B5VeSj<VXY4>%>d({xuhgH318tIPdiNY7L^}w66GUMd`3oc#zk2Ek zmdXyR{c-3C0Lqmr8zi(A4h+jG>$$x!4Q8Ab18{DPuoWAt2=m)!Gqy&#TqRpo%_it{ zjCliqed-lf<K$Tw%}5b|hH@2KMc2|Medc)$OtHZSvGacOGS#zbp{l?tYq91=GkR(w zc(?0$GciQ8c8wS_%Y;kKrd1JV%hYW*714~P8xrQ?`%O1?A%CisfpuYv{3z7NeKI)% z8iG$n$Okj(nbQJKb<>7r{3bhy4qwAKoH@kDLbIjbe3=cQev<Wv7he{2g5$xFJQmV; z3$@((Sm1Caf3Dy2E<tOF!HsT?QYjE=4OJRu;QA~o>Hth8E>Ph?P0ed$Mt800v-{NT zB377{Ycx?J0&lr#$xJ0F$B=7K*}b9Nb@dg5*tDonoz8Q;-DRfy03Mb?(nN-V%}u^0 zz`Gy??&@UaLn|VPKh5W~k#MmbT(W-KTaBbxm$a^<A*(5n8G!ap6*;?@O@T*6UmpVR zKoCXqyEDh>$bi-fFAYdjTPEmp5E%~>rN^#=E17~Xl(tyLv3ahaVdqHZK|r;<iRFyi z9zO`{VnB<MH)y~7I-Bqs<IWHB$$Hoj?_n_)sffZ<VG`?Jt_A!xMQ3ec(3}Kl2u8-B zG09ga`A9}O^tiR&j^f7-OgJ*1EV#bt)(i|;JW0)<C!Uy?LaG8yQFK~%W4po@*7o4$ zaYFR;bDmGH+SmyS#LJ9=IwOP3Rmjz>E)^#~vV#gGVtCo?wzV<2ftx$s=yLvoVAO^@ z!i=+F+jx*Fb5Yd{p1PPd!vMv3dUUPZ=A4D2Bw+LEv`1dg0q6YKM#rbwm=Kjr_LE!* z%t2o(B7Hz4il*9tla{*E8ZK-LJCww5N+d%r8<}{)of5k~5}e(GHvB9u5QVV=)DInV zgGm>(3BTJcf|lQKY%C@8trh!j&QCg6uv?62ccc8304NWS2+N7BffGTPEl5&NAXr_I zt+J_nm$+`3XvmBpLf^ew@zg1eflWA!U^8DyuQ7%)w2uuds<B?IyhhkTaS#qT!@kZx zm(0*Fm;wwk#NWErU-XbGoXjBghHMXuWFXBgY$sr~P!G0RVK&$^%OH?|Vo(ft#TSar z1kaQ5g^H(Sr{E>kUv^J194+WmhF$~yIGjEljgkVmlYHOazx=kyavq=rtpqFwO*Z_k znFO&r%fic#fFv|5Je7z9Va4w*mw+UKymC*;#JfOIiQE9gdI)EilrI6?7%M0J#`z>m zW7RcGQHe5NBvW*(GuS7E!hi!(ost6C3#TO(wXo1W2V=oYqg>7Xjg;_+QxKl9P8Ysm zbku-F^G(HzUk~Fw64|(iNpyn~Ei4%2C*e`3f^a7784|tfq+|GNVHh4Hl~Ig$9JdQ* zwUQlYLPpw!{=5tfk$|qNVTZrA6i1p9U7H3~esVb<58-XyuUzA@0s-RO9r?n$449W< zXZ5*@CW&aLc5DwWXOh!e#m}2`sCaO0E2@KFGf#%}TxG>OU5>YH2&_eUmI|Wj#d68Y zyYivrQ)O>kSYTR4or=gVa@(J$2@0(C_VK>~(sVoo`j8|xf=jxYjvk__7tcxj$)#b9 zVbcuf6En3e$l;=%EX#ukP|D+ei4=QO6pgtNtlKP37rXIIpkl5uC%bvX$35^*GX1&- z8QB^)W<ep{Z}XC`BchH)3VBl27;ERkuvA3^Uza)*h+!IBJfdW3UPPK0x5AIEP?oe> z7W7gsvMZLU3)HDxd{}0wj|mt~tRzdWD6J`oX{K1)j>4`5Ej;90v{RVC#4^EM9sEN+ zlN64D*_QLpM@!#`;Au8Y87!G;rRokI-yfeSs6aJ!WK+s6`)nz}k*TO?D><GSxK=WA z$275e`tIPCRHSE2?`&%L6ve75x%TYAF+bnIpwO%)B*8z(A4IxlrX_U_Rxzbfu$)ga z5XMv2qkdeP+KYqMdOYF=R141sFX9MY9G4-<#$6%jkJmh#B5CHrjl~3z{4Q%CMk_R{ zxEQr(*i{Ssxm8<JedWI|BXtqPc;bdstyfn<1lRcLS&9s?&Ryh(L$-zHa6vb2b~q~- zzaJ7B?VDwWJx+&;oEjoADawtqqwp&2Fc@Nw&P^#7F_GtAJ<ilH*N|ogh7qOK@1Zeu zj{WD%CXv_7!ET}jdeGDyr5upj4EUfFnnNGVMiHtK5{jxMrx5#yHxaPezgNY?k6oIM zw4aD7peaKSlEL4(FQLz2)>Tg$CvTo@kzO6#S%x={C05R_Q$QFxk3dBLdItGyuT$W= znY@Z=U&o_KR)bW|CRqvxUUUdg5zNL<Y*r~&{6QjKfUS_4#dOwa!kCYnaXCohvTWs| z-cWWjaztU^_^95nW<6zM#LL18mm!<OjA^j|g-c7Kw5_{W!xJg5jh1zOv{9d$m?|Z4 z1HaEF$7{oPNm6RyvHXJD-?qe!<_LQ6N6>42`0aJcUg=2>%NuP4I;W?-7<2#g8&S?c z^MBv%`zh5Ac(b2-a3#5$zG(?{#nqmUfS`GXaUW~TqEue$gU}56shx_q7J(ym(O)=~ z_8knh`2&k&SX3-8L@Y3*A+d^XO&RSX`~^gxt}WiBPOhQcvalG0(3GM^y0}y1y2MT= z0|Shs++FH)D*PAhtxw=0Pk7qNl!9yW*e?{G=q`mV^%tNhHSP9cwD?StFOF9<be1at z<u3M26;sOU2G2{wXMK13tby~J^{2e)-;lp%)%Ke_v9<9?mu@D`CL4o8w%BZI1UH}m zly$k}i!#>B`bL}>k`2+<&)CPm0=1pnGyDOc-(@@8A}yq$6mJeo6t5m~Mv^O-6H?ye zI6aFk(;am(9knwhS5Cq-)27$2$z$t@rW#uAnVWqD!e=`{udHUTfn4a2v-HUABs%m* zKkz@JLM`0feVBv-($>+0H39ZNgqg9*m#N`qc6L8HaGXy#$W1^CE+M<jiVt5Z0isI+ zi%+nLmjD_QXB~rskZ=w^Jn<+4im6Tlf%DR5SZtdJT~$s?VBCz<Owaip)NZ&$dT4*< z7<(`e?=^U|?Z?nI#2ABWid~sll1-e!6O!kKV|WA5<r#<M7Dll>aS*3kpYM}YHcR0p z;xROpV%k8kS{Q!Vm5NLBo%fWn90lAazONjXI?i*55Yn^oxYWxo%x2a7n3k%Y8MgMe z$C0tZVuEW@V(6;Cp=Pb~UC%V#c49v50WvV?u2~YkMPBknuh+z_*Cbe!(8Jiub=;94 zzp#oOE~tgHNb$<_Dh*H;lun6xT6CF*KZ^J!D-`tUs|$rf8mpl!Xtpb1T1>^E$3dE) zqC8P{+ajKEst1dsO82FhRlIeT;tqBY?RmP_`*7g@wt;SDLzQaPLnQ|8z3R;ZS*0f8 z7IgqTRq09dw?}hz^O*tGZlzl~oPss!OtU8u9>G|z5A=a%Mrx33I6#}?$Lk~-0ZR;p zPzsGpr54#0py!~3XGwKnj@8NpGgZX<O^leg^9#Rn(fXp~ip^kuqTnjUi10A~;?Wq; zs(DwU;|pxu0YjJ`oQ0l!BEe;I>him4k3XVRnOdmd1Y}^Ay?26z6ku!7&r#2fm<QIt zaC+sFTLXT>*`&;~nSpHDlghIhQiU$nSl~i}UZyi&5JOw{a@1j0$u7h4yc1x~B3I(< zHaV<?h1%Aa4{MmhDA8Tf0xQ|#@Kwn&|6$!QeCpan7TAEP+tRPj?Uva(xMm#Ha3p2V zQDwiJO)e9{Jl)RNpBHJ5`-I81aEM`n7Vc>`2OoJh^rpwkf_5rsWPEF$XkTugcsA0* zFHOsP{q<kRL{UNtgk-<#RLt+W#s8{P|E_5ijP;F-9sU_w1j$Lu_J1GWpbUag;e-1K zhquiI$BY5l=Pv*kCk(^5`agWVQ<N>;x~09+wr$(CZQHhO+qP}nHdflUxiVMfx6i4+ z>g-ngznIZtUc|+0BW8>iZ}0u-QX2LW7BX7Nc_m~qV1E95lk8po3UsXNIT>uXGg;ST zr<+{<L{~@p20USqm8`7R){Mro%K3>(p~^iACiSyJy~gD2l<{gw4sxPxg{Mf0jzV&8 zItUaxa{^QyN(@82SfWC_@eYF`*i+;R2JnwB>d?n6$UYb?;g|}e^VMBM_xSCQ?<Ef= zRSZ-kMuRCQk4+Q$_(bb$mWw7Z)g939yPBa}Bg;vzqqC!^D{TA34<}a#aUhwRXZSJE zF*abZsu(Zd8kwZ%TzbGlJLfUQY4pixSj}9!JJ2XGvSxJiJUE*;%khPOYx+nyjbTBv z7-bVIj`l#V)|=DLXVLA^G&*xI0641C0h$>an%~knO}F-`Qggq<twgnRK52$6jui5J z6C9%sFmn<WQv3c5JMRpdOe*`cA}BvA@}D{wBy5dM-2ZDWd=hpg0R@mp`_}nvZL=~{ zN(AAJ%Y~(!e`e(1fy*KU&KwuUM4Pl%wTnNTGkI_j9)38K9E`N^eA`)$-E1e{M~27y z_Yc@Tco#4%T69WUYwMGW4M%yCdNb~HNYGUid-n|(v4dQLu63K|LielPaN=i=#BlZ$ zh4i;hziIs+F5d>_i!u3ZnHvy--n{@n*|9G3kwD&<;`!BlDwOq&a3~{BiOaz&MM)c@ zLHS>=ly&O_wpYf?QK5x|$kU6Rf#5lIq31ahI1pr&a*y!=1M&(OzP<gmK6L3}`jsbM z9ypI;Gr~{HcuFJ>Y5|@ksf%#tqHI5)uG$#`?nL@}X@)W^t~+wiD1vJ9;Gh58FC0Zs zlQy2P_1eCE&ks^$aM-Is!64UH=8DF2QHU!4+GLs!lF8%fb1Rs&YcqAYKIrSe^u}iB zp)5Qt-~T31Alahevix|c(SAJC{|PE9Vf+8%pk|f95+%2x$l5?QhoC@|H@1mtz)Dy| zRhm?+lueRgV#$GEO4<OVC8un+%in{&0Sq*Z%-`d<xX0%E-yZ6@d-vOE;~a^kR-V(} zY<4@JUpHN^y<TN}Uv9^kzp4W+Vek6CVAVko0u=xg_zA-iuiX5hA!C#S(Ff9TaLI!l zFlE{OLx7k$#qGoQ1OmgraY@~avG?n7SlRa!+@non+4mgW14ZQ)&&Xq95x7O}m<O1E z=McHY?zjh_fawssh3^;#sDQ^HWZ}Cd?=S}>xUw6EE}@fIAqw+b>Ghpp-c+BM<QFMH zJU~yJAqaPIuy78Jd2Pu9nNoBV{iB|o8u{l&jUzBokwH^kew0D7VXDe7C1hPy5D8^& zUWMmLMz;NxQr05$f1+5y0fhi~fMHy0?VY0S46{i4!v=ABDIgB+kCB6GrXU_9_)rR- zGA9}CiBh3&`DiViI;q1p6q$l0mk)>x@~H8`DM-S|t_gNf&I{;h5%=w3GS;^UL`dVK zabScE_&pg>Qo;CT54<H>id{ws&gLD16@iF|XFgre3|b@%<kF|{#{t8zpq7vFjPgkt zxJV1ak<>Y!R!jbMA;W(L>&Gh?Fx=iAu=zI?_XteENOHH1e*X!Ir7rYtfnW}+6r2o! zsRg9K*(iNkDCaC-XuciGzDa6E7kT%e1Y_|0$Q;JP5`%_b8_GUFgWbbO>w=sC2d$IL z$bail$W3%l&Bqh-t4tVm*FX(SzqxLtp4jvd*$++F<;_H=nJQVPkZLejEH(FL8Kn$^ zV@#{1dz*EAAf$r=xXj@ZB08%9bW_b_W0cRE+Nz$xVd{BX7q(&Q(p+bLPOVxTwAF?T z(~Fz{=oQNMQclUhs2azkt`22WUxT)5tVdv7IHSRAsjmmRF)hGZUE8-o-3f5hV23eN zcaPiiVIS(Bp$J<9IZFXnI6i*4|7EAF+=h9QGc<@!$Jz4aB1u42tB@_J9w`zitDu-8 z)U7l;L+$+wFOk7~Oze&UDi7XU(mr($JKJoZDexJ-c?blRcJP$i8{qWXJ|cvUV0MsL z+jO4_QzxK`+FJ(fGjtEL;U<)a`t4jg$a&Uh&&0q#{~rf+M(nn<omW9p2yUQlAncj3 zzQp%bs0po{HhQ{Q%D|V#V+7ZNTpOL=#eQQ6M~F|MpomD6xCDQsta&zSn|M}ah2ZcK z3AyI^QiW!cP5ER>Pk1pEQ`-6U=-OtkHRq#XBKKs4`WEA*bdU*6z4?ffv#4LC9L<DR z#(bycmyDJw3f)qfk1{-xP)#A-a^A;a_QeV>>td#HLlioiMlJoMhsdNr=4(P<av5bT z5SOdN)u9)LI{ZO!INdU)lCs6JeTdxsW4WH0OR;krfr5#&v~#3z()b5FV_+uJbVhAU z5{Krgb_yBhPOwa-2y#j?MJUc=({>ZfLZhVi1{h%$c=1j^bbIM@v1Ue`X#20-(XgL% z(G2?^S^*d#9AAG=f8UFJaMT!<{{EV`Wk8WPDESN9Y~T~Z*vKCPbr|dBFIII}D+lGG zy1-3?oKeL{6%!ywdSxJ(S{l%_?QQfh!q*V$Mp0s|3{g|L#Px<yRtw`9iAEWUp#%Bs z1Im%tr?|it1qfW~F;&r&^k~g6(V97nWz?Z^RH`EDby1dM=16zgA)GxH_Yde?OE+vu zw}c-9^^`nn*aI^ZRRORA)qfkPZ7d*HBtk6Pm7+!r%xU-s3>4R5Aid-b=y>6d6wImk z4N@fx&`}1<@%J9blOaWx`CvkDx1_2nG5vx&)B?5-Yr6?xo5&1ipOp(|Lk)!y(j>)k zWr*q|6V)(|pj$}1#g4cZ9}5MW+SzI7U<*gW9FIm+qrrmifBg|lVlZvpFPCDn<cjUA zF*(UJjxC&S_%ThZPbvSL7fna}oNG=gXBf*CO=n<C?fp(dcx%zDKFb_o=xMCG(ujWM zkP$JH)Mg3oRiQ>d$v`Jf*l#2e(qrrayEkrbo%MmR><xKO-++=0obds`K<l(XG(#OR zxPPuz{sT+7=QVwbw}`Ef<}8eJ#jM!iCt0DiuE?e-{uQm*m%m)cQS6GL_(ot>85(tH zpESYHXYk8!4xv9s9WUG(-@;AQqGw(B1uXF^BT2f=I*&!8CgO^Y_>&86J>P}QF?0M| zpwZ7Mep?8qcrc2$>$mdLf|<*@NFS@%LSNig2)FMZG;Ul%5-ap2q7^0&jtwV_Ep9MD z)ofF<J<-$9RgnL{lJ#A37Z$_PLA^C)<pZ$_haw0|Wk9y_^HRwMKzE3hB$ShkpDY(< zsg;<XY~}G%iDhWKO22jpn03@>(?aIh(?mjC**a%{sx(^wtL9^R@6^Nn(?OX(NL-ga zZr<pU(aaLNPOhz0ZpzZ}dHqR;i6%FDmD>=#FZsf5!vEdL{*RZYX0RDK_9p@Q3iF>k zQvca{|7D>5Z`Y~Hwi}WN@?V(^Qww!Xa>aOY0&jCfYbD`)J^vCsco>_K7IOrbEa}A> zi`FY!OCQy|6|?6zkJyh=v2tv@y9Foj2a&(naj&+m65^z`PXv8i86B^$T})25SGRtD zAHe%Ll8M3%OR>Zlun5{`?Slwr?g)pZ5RC1a0y(B1?E`AkFl-s98L1h%2dk!_+c0!Z z++z$v_F;dvOE-)ieRriHElg;bD!?2nrnVChVNLzrWEDs4q9a<Yk;bchZUT7LM%#7r zL<WOY=~qaR;iU+ZkE}*V#e6oS)FW*VBb5!QQOg9=4@T8ha$2m`2_wJ8B^@T5fJ2Na z+Tw>r2c^(M@l6&9#uVC)q#bi@eB=1dcX!k6HAY2|B4u%!&Q=Y|Xfi;d*OTI;mKhn{ zedbK^O4=$$HVMYx2a>brm@-(E4g9bHwo4fuVrA{d5ZT3tP{i9rZEPm1DI5UX&L=<M zt{syOtHshO#+=JmW^K+FmY`NFhMZ{U?8*GU4I>_1m_GF<Dr{J+IVcuM2vJ~VqJmJV zMx7_APoPeX`pTeRtEtU4Ok!d@Mw_WVNy*WGH0D@ctLB?%UHVyAx#Bg9tzjUxe|D*? zPPn!Wn^FvGuiX|XH#In{95G&%<qX4L3l51JIStY09Z)%NAc)r!tzpi`iK+_njbKVc zU2yD*%8h_Xa8R|fpkL9gLBkBtPo1^(+sF49FHKBwj0Xi;N$E?CvJH@p0LQ+cM}cKq z9Iye&0%Ha9iDrHL#9czByt4<`glxqgLN%mM%O+#3Y~D~3T~SHy@yhQNKN|Z@YHjYd znDfdm4tgyf_CS><R?+ZXJoP%7Hx;^Oi0KvklHONbG;!^6CCYaYV%!v3D+oiAQFO90 zw`L}$!UesoD&9PVt(YQDu*+*Iy*leSvTY?WMBwUa*rG&LWv99oXglL@mTZ=EiZpp8 z^+*HC;0Z6$LC1Mz^#b8#^W&&;u7=Kv2l+&($}E_rtO!2hi2XvvMe*>TicbAP>%snD za0q?N6=BW61Ad{{VUD~b38_viA#CyRo~q<2N#$+}h&_Z+8VqOk2Gd3_Cs?R3#&q6l z#97x%vYsS`WK=heqLjMe>x?1Q{uI1(FOOFicV;GP78Kt!OH&?`u@p;EZlx<Xm?)y) zdXjkOb~z7Tp-AnBk$-@krfd};d%VGW6+U@|-{1)Q+O#LTkzd<1?$#tls+1VI&-Nuh z(iHQmNnNXm_lPOpCVdG&Rh;@%K+zQUDoC9}R=`PI5H<3_#&@m>UQo3x^M)*w5kFI` z=YfdpSQ0#!XjY05Jkv<{h`qc5C=&f#q$>4HS?o(#@oCHl9$zRIN5>+~J6LrTi*sdH zeI$k(r+a_r0qobKya0w-<fkMmS6=jqS@c(4R8O^!5iASyL(cN7Pm}ox#TVyA4sl&Y zMTl=9U9wq3sBiBP+E8)CsoW<wc`Ql(k(q~HfIH~I=lSn%AChHmnL2y;IpErN?i4V1 z<pnPG>e7lWceRkvz_FA8u?;9(6;Qr)QTlbI+}}_CCLQ7=f)2nU{Q7nJlV<-<)<9_s zr~mmp(|~YS{_Vo+#$1E}12-QS3<55iE|QrLziv!4Oc)GI2xtHm1x|N2&n*E|guxI6 zJ!=_89lONou(YaWnAPrJ88*z``pYN?$*v)&A*t2jlHDS!S*DZCX0^59G0$tadws_| z;C9K!jpvl_lE=;cdfRLkX+e_Vge1rJtQ61V%&y1T|9e&n_QUJuD?KaE{T%NMuj5s2 z>rXTA%-q(~9FusF-~D3WV&DB!pVK3r?S~xPS6Z5{?BDBxzxRuDXKA<}DQUhkef!V5 zo#%c$Pky)`esn5SsC`C^w~n_warklYXOLlH$oId`5oo_r=kh)GPjbg-B)bQxOxr_F zO8nC&lA8F1Xy#5j6me4>lxAf@#HROKB;(2-!aKY_Amhqk!aZ~u^r-K`F?DsuX9#V* zx0W57(zB>KGzMoB<J3<Org#ctCsrRV`ow^_3kQfWc??11nD0lc+BGI-C~Z}pnnJT$ zwwRrqSlE8sH^pY5+O9e+P0oPYvN|?JWX;$voS<p}qqKz*77U9Dptx*@Ju&o9WPpcc zbqd`Ne|+!?%)Xe<!!vhrAv3s=h{0ku@O%u=n@)BW0eQB|#f7+A%W@(O6}02)xiPaY zGn)@1$#`<x4kH$r6VqC>PV9TuuYe&+@KBdCr&Z-wS}%@?DjiWdzO;U@8G1?BnUfci zB{E!<Pof02)nn%dm=hO-5%T{wx`DV%C@9Sh3X2XH_SEXvNyv9__W3#*3@5)NiYv!g z3zq=T<OA>#(Cw&_gCipdI0IaxFMkcS9kDN6R1#Z5XCQ<q*O!MY5$!6Bm^EiaL{>H< zQ{0h8qY|Wt)0xL6B}RB6M&b$5N{3HAtWN5ZRJyoei6xF1{{>r9(?yVXgq+MIBr#vY zOdtqPXNyo%UqB%)Wh2iyU+n7%$|cmmt}IWI09P7c(jspX6(57w@Zx?5!IK((3qukL zvO+GIKR?w}Fb+RgCh~$lAF;v71Tv9a6f9%>a;jy_NjShwcvB9HXx1nDY3jv{JxaX{ z;_=lARr5Yr-<4Jxd>+}H!GK)PCIj$OIoaFw3z+5@hbQ5V;cc4V899%nqrlA1T@}-> zi@S}L?p``@P8vy;2UROjZY_N85WJv+g6_{Xy>x&#z*UR21#xEWKx|P_I&+{Y`RI~v zd*!U|{WAvfreeb)LX?OR{+5N`IO=F{us7=9C6OqsD3ZRAZ(&||A)5sPVzY-NWNv)! z7&|AtEGP_cu$4RkCDzhVL4GcMr+QphqQRT93BBc=c^9v#wM=ZN5Rm#<#)ym3ILD6u zXoRKL%4FA2fzeRr^woM+I6-h(@*4gSKQ;5D)cX5wv4IVTIq+tGS<h_h*(!5JMSV?9 zGI*nswp{Q*5CLl6Os<s|a))Ilw-l&i7YI#eF!mG2eXMF0Ri@1X8-)C)lM+AQlyix0 zMY2&g)!Mrtci129>ai6bCz6}qi3*R!g*_FuEKVLRnAVZP2?Z7<Wwp4eEu2WVAG=}f zgah90%k=N;%m{$39x~HdDZz8_^qk2?95DgTYE`aS|FK+i*-VBacf~7@3e{Axq`W2M z6J$FzW(Mow{7Ct3H9Us3HnZU5(3NsZPSasSf?jBowOi%`2cK}dp#)_+2?7%-5Y22H zu{y&cX_LzpCD=n7(c$nA&?`Av_4T7%ZB1~E+1}YHm@jQXEjqePrwL}c(m6qai|ZIt zBOp;T@@icW3Nnp>O%_h_4G<b>sw5r{H)doB^oH0XpwJ8|v|9{TZ=nJPqJyN896DZX znb06!WzgQBP`W^&%r#2Rblo!1x_Kka9^tr-5mp)NGCPYW8Czaqyj61HyCIErb(ZCM zuB`)~%rjIj7EaMNOGC7t@I{K>lks9AOx`1>s63f#G_@nea&qb8TL+vnPmw%#_PYbd zgJgEp)4Fv(+Ljv9E!x-J9P{>8B&U!iom5Tv;ISg3&`v>mKo;eR6!ay69`gwk`>c0F z`K>Au>ht*?n&@)5NldR`-r_K?Ly%}*u^a(v2fU4d=8HpW5+(B^C@gxf^7=;MLQc1j zgJ)KCuuogQ`pmWm+U-+`TOoAo_N&;FM~p5!o8=QePcT`?HqRw0n}u^&J4TDIX9o@H zQk;a+z~CoKXWGru8L$t8kf%aXIeY$oOyEgAyFVk39<xviv&;Plstj~JOy#19<OyXW zsq;;e<l>paXoA2jwMZizGb#1$GDaC4=NXfgJC>MBRDLMiN`8I^g|kDRim$l;lgrCN z(i6)KjKi&j40KdHDXfE2dKNujw5bN-utR|O)s<7***&W3q`+G!qHwhRuWtN36{sax z>pL7mH)i8(D{;Gd0Pe-~E*fID$|ZM6Q=2gVMIsxDPbZ40YmZ<RcCnFi(Yi&eOm@Nz z7KB66S((5rVyiO_&bo!H>Qc7)I9dm%ge)a_bWCb)DLE_W*etVlkI39mP}1IBc+8|D zPUI|Cv|l$DlI7mQa`rGeE-^GsJ(kvx{gPcV_}V&mufK$!(mzP@&Bx>CJ1-sw40a0f zi7LsS$Dhs^gmjk!Q{~Rp0zP~KYvt+IUW~aBa2QIi1~>T>_`7l>Y2rn{JsU_$;jmfL zKN&Z(mPHv%GANh~pdC2&Qv+Y2AEbDt%$>w~mm{&?P>G)4?Wmphf9tRUl1)*Yj}Vtm zd-b)?=n+A>%cNC5zM$N7I_oN@bX-e0aK^n~2-eN?0>1fIi^CPV)5KyBkuTxLzZ*|K zO=3Gb&=%H^shCl7CaP)&xY_b9lPHx3e6+`=TJ@ZxO&>^D;bLbMskWXZf8ergkC0ea zQcd}qX|JAvJh#R9X@K9~%1DuY_6+~wF)S^#Q<*5S%+_GHqF7hX;NILw$kae)5*_;R zZ&*QJPTChXT}|K<R-nPb&w1NjIU2U%;D?1YY{t?9>mB*-w?HhLry>NZQJbyBM`KyQ z_f)Y&gITCAR*Z(cfQR6W?hUQWgeYPQ><uD36R|+1aq0lh9eI0U=@v9O9bdSmqr)US zwQ$tAi&MI1?|5a6PBJ3`C7GGc{H!Q0U3{na_`^~*ap@On$}Oikqmg-@kE+%}Wglv~ zEynaGz!GiM>@zPO8{^sVA>XFNafAQSoQS4Sra75)3DdI3bwki=zL6OV1yd@Mms5~| zLIiJw0>CmVzl=CW087e(WIHey$&BiZ{H3El_Fz8w8a6uTtrqA_(a+-ENqJRIS$Aji z7I-#t$5-t=d*}NglS!E(?B=0z$5#&Mb#8vkq0{h|0_vN(o@fKqaq}GWB2oS;vK_<) z$EQEIGnO|zSLo#cu`<X?3n^8=wxjg{Tjlk08*+s^KQmA8fHDtGzuIw{oW6cM5DGQh zaH5oJ=$ncLor*+Cplw0ytSGW19RS?6nq<AyYrVh{@RW_ZJx=?ZOqvKZQZ=U}1a?FH z&>j3_BvoYcL}aE`@^>K8vZB&C=e)MIhW5ELC>}!_Fr`kFG+@feB1|z@`N$#d{h1e? z8M^?}jIbBbv?I~h8)>v{=>E%63V47h@PK8z9~GcJ6#wmL1VZ#7eDuf`EI_OLFT)st zKc?*q*JmB-<Wf(>KGCs4M;YjT*j2Fdy|KImH1(KeDNXF{)2ucO)H<Q%0-fO&P<Yk@ zf*GylAvAzU?jr{C&_L_rp&Xdh(lGWvd>iaM*^D4xf2U~eIYzK5FCuG2MWXA#Tvew! z#p44^bpGea%$yY2=u{BOoYadPj!Hf6Er^xAoPrM&W}s`Zffph9udsr`IDAw-NvL1d zxRu&4D=mQLe7&Cq+^8lnu542)4Cfb}B+0fEo^cgtju#0RCTe|7nioBeh|fC!J9(j= zx7oryc@5p$HlCje6_sugB|9V(&#ZLzpj0^nrfM-CsB%Z=QpKHmQ;*K{g`WjCVDuk= z%1<KYp917h1m&Lw<)6SdC3FPQcmjdG=o0T!sbzK|j-Np1yW7e_e&!#4IH!=ss6ntB zq!F5>8+I8-be0%L7A2(b(cSrAmAqXLm4s>J`e3}?jBPfMx2QMQ?Nd{sx)C`5Sh7ny zp;o_CNrZsV;E}INnv^5M2E4oB(@W$Kn$%Yp%}AycDS;m60yHjGm6+U&PF#JLGu<vs zA7xjPNiGSjLl=})d*TVQO&u1cWiMdAjKE*WQsd_UQLs#$G{>Eg&)7V&OG9(ML8V!5 zEV-qqfV&HacgG3Y#tTY<N}FL(CI9w-<8;H~Xct;`=Xtw}vn;q(g!HC4d|9``+p;34 zE;)WEDgT1az7qfo<A1EDNYLyW)9eDXYJ1e$UY?t~KlbX3y3Z@Ea%E{|ugW>i(h*_2 z?~<KYS(%+YP@%cuZ~3IIao#(+61}N)oZk_1h_d%%`522rK(J%xHHavN^uI0gfinHH za-Z6r*Yw0{JLe(?*csgZAfi}xSyO<r_rC5*Xx2m!7$dNxsQm&n7FNb*@DUIN_SZac zlPCzeY9LgPZ^gb}sr9Ots%dze%-0*<4GNbk2`$E;3V<*)kx{L#mVv6gXu<<}kYnVg z&<B7Kmz$}c16)*6>V2mFmc^%${#C+J6x@+X1%i~ylbi=QIS0w_L0qPMl;K59?gz^D zxAFKy?$^&W-A$BQ%fMMiRTxcmle1qYP2FmVmQQZu5pC~YYVRAR{u|Tx4(n)O*EHC- zEu?4D`IYi$M65|rZ)S@|=!;7A`!a!zPeG)g(phU-kd1BT3s!4a1k;C3$N~lR5HhJD zpHECsc^HqrX1PMSsM#@e)eWq)IC<4tZ*n4JP>5DRuw+o`QDK4xQ4_RQ7D<gF*q3{% zZh2abWbtPoMmi^D0_yw<aM*}X_)}aL&R9=5hkx5T?7H-OA3*vlS)`ieOBkaph9g3G zn&ysMVu3?KZX;kL8O#!Ze+3!%83t)N$u*z#G*D9;KDqD_na4(SrzInQ;}3@d$=xp` z84&)M!;i^m%3Ka3krj=n+y=8IlDHYqdW#-w*3%yq^t53emQ^Qh=0wAbRqJt08;;fI z=L-j?-NxIaDdon1$aW~mBVHpQ_4DNAxUZZG;UH=;p6BM>{FH3wd7BEyZj~U|Vo-4e zz_1QI5x{jl{4IY;|1C9|%lu>Go#Vq_!*p;qDLcTH=;-{Ml50SOjO%TpJ>&%J<gH^; zFaf&xC{mWI1gom1N2%XEN8BVMt`rq+#z!gLn6e~ETKzZVD&a=VYFm<3!(fc+b*<`s z#wD#i>@!v^>w)8(q$N)euj}S_?C3t(mBVD_xo^gxNt#g;Q>oqpO1&r{BA2=1%p>=- znIybY#|KW!<TtZ>?SltzktC{R6sy>!?~a;@IU0%MpZxjyNUuxM_xzwU9HcXwXPc`a z>n5Cj8J$=Kbi~g(hs#M>^SD8lxO3n^j8hep)l<hRo-?$iuBRi*OZcq1_@%T*+PB<E z-y~;TXFAPhPByq%rvoQhAZy*ZV<*qptZ7&4+G%4aT>4J;jU^sKxiWURS+_wmT4^*h zSuelObGx%Haq8a<09bdAt?HX$G_Jio*na<U=;VFXY3%Nwc}B|);Xft$kV=wG%J9;* z7ii<bAjyzQ7}#e!ue++9>#YcqAM6f*)LU5BU!=GPi>Dv8xD_szq*f%sM@cHCMInCv zK2P)nxsCE(L6(zYL4!It%cG4|gG#)}psi4H7hFfT-d%=yfsr^Z=E>RWv{2+MyTUmO z{n?--yf`~Xj*FdhM;;eLXJeGgoHQ3X%;Zi>&lf#Lb7yCkN*<GWa=w-dgEUg6cS`Zb zZ@K!w{%3T|THR%U{YRN4{845p{zKGK+RoPO{{gr9R6}+_?hERl<fH)Xl|s#%GOSIl zAlDxjLPMw*@y1`N=jxwlY?_@$Ea#!7y8c>R+}Yq_q0y3-;wt0JS(019ljr+A_bipO zbiR|Z4#u@>fVP(nxBEW(`uV<f+w<ymd$;7LRtMCt*}f0Tw{;u30#ATW7!QFQNIn3- zR-V5gP8N;;-L)5RPA@p5z;<UJFB%38i^MH{2R|?b9EVJR?Jyw9#tj*_Fs;DG4J$W) zCV`1lwBQg}2A)gm9=fLycnY3N<{q#o5|{?AOX?o72RtAVs0N`+#C{yOMC+atG>9pY z`oswf*}YAZqJw?JMsAQ0q*0Sd-8vHLDbk{J7PBWUQH6*|s1r!J(8Q8a2PcjRHl>Bq zvb#%W*{L_rtgu2Nviheca!aqSa?reop$%gtI35>?5c|lb4IjL{Wn+_*92)979RKw* zsFQNyD~rmhI12%_C7x2`oCm|4NRsv(W$2l_b!N)gR(j#6S|=eTBIukzWEDh0^jOl- zu2vTlm5|{ltsU`o?P!dAKAa#=j9SXp<Pd?3>dcVeLgA@J9mq?w2&}XCLF~CZ&1)V+ z7*-;I(?p)UHYnhMDhqoOJD0FvPAHcu+uc&yRT4WKsMtq+#(?71Y|IhRK=NB@8k&lb zgVNj`Tqi?JLkoWads32utoG?-@|@L`1xDmqA*k^Dm#J%+VK4<{s53(}0P}C+9c1v~ z{s1ff`M^a1?vmeF<0^4b_$|dCAp{AE9-+p#<KCH7&{36?Aq?kP$|?$O;hCgQMgCUg z44NmzEh;L83&qkq<CxHCL1?3N+wqSp+mw@qlp$+en_gfGIvh9D4R*s1hsL&}reRtM zUms?OEV9?0CX4k`rkZOtUi+|=3@pT~QqC!pjEY7q9Km5Mcc5@t`!cwd21qeGg$g)u zT>G}Tnff(QJ16@%?rC96_Nig7;5%VW*wnHf$v6CAgcF_RtTDmDRrRXpK!s&`n5ZUk z3H`Vwb4UV2%yF#w!-NKL)n~c73q*&uxV-*w6PV0LL~rR~a^Soq>|*w~w0CzH1EAnt zdxUUldrr8${!p~-(?e<Srv}iqcXuc;wSz1_e5<4%zEzI;YrigTpmRAc=b3N$X+c(g zRDM!^>a32G9hW{8+%>Qb@Ju~Q5?9z~=m@QpIeYq$<Uwup`*6!yAyhigXD9YFQ!r4Y zXvj#ogs*r+EM|6el(F=PGsS^j3UkqShBC~AtMbK+w(ug!VOoaH*v4k^6_3*gvWxh9 zLw^h%3sw5D|3Z>kM)ZJk*AL)|x4^~ZBx^KUk#{>AR$fLLI;OF=-}?d^{>k&OiKs?R z_7U+=@C34|7_AK3*d6a3N~H3L-QIw0%(pi#=-np}8RCg$m{|v-Q5#`CknlpSJ~sJ= zk(e@KBEmMo92wi%7<h$Y`cUVR&?)-6gHww60_k6bE5&~ZS5wY&t-_m=W4b?tE2IGC ztRKQvbE|S~<U%++BGw2m0qVjSj&EBr96yL})JK4C>X1S;rd2@D=3NEs!yQ`wyc!GW z776z8z;(E-kt+ytzodFtQO5~oJJ2c?b%?quD<PPe%KX8Gp+kqaio^J$&NP0NV55qK zaV>EMRF!#*fNB=;W-=o+?2@8($Xo8WnLbv^-az0qBjv8?vL~};P?3Tbb<u^oD2g$r z%Aq;(J$3+B!Op>Xv-_mC1NoLrt=MC2{}VfMiH17hd-&%3;4jV1z`4yO<jF)x6Z<rT zD5ClJpuo-2dN7oi!a-i|o7uwo^q@iLEI~d>=={LoxgaFUBL%P)<P8V98p@gv1XDdA z-@3Y^Qub-=APqLf2u`F@g2{Gefd_L;4~xX^Wx~^Px_vIf-Hcqck<gK)#fJlUP46`V zx>f`3yDp5eZUnc?_1GfSp>iB{OQWgj)(LE(j6<bV3$v-@HDlTQ=?RJ{=Xw)K8%8tv zldEKtyUz*8Kb-#%t`5?5Gt^$NM?boM2v;Pvm|}Q8gewl#PzK}nLE|&&Qa8BV=vCD> z+Mz8w1KiS=KT7g@UE$GC-amvZsKfd*QPCg5)yTgHR~E75;+%zmt{N3<ECtKw(iK_% zn{ZVXv}`K{*>_~UVy}R0+rV+c2EBI+3$PXP95CLQ<Qhj+6J=xUhrgZ|Yg}sbxo&*S z+SnI=bxUo`b0vG!knj~`{Fn1z`fNL{k854cS<xINW0Y@)(0}Q(0`SzheJM#G=&K~w zm`pfO(wJLYKt0v7P0VgY(?eHb@gquB_sH*+^#ACygq4NFDhP@pFqO7qmB&dX8xVv; zEFm2orBe&BC`m0vO9__8#ub(YaVYe5HvpT4cgjs3)_K_L?w0Ei${g#!m8Sm%xN`m% z;3|zvu7A(M>`_@JwJc_)$+D4q<_B;^_FsUj{(k^hZ~rD|Pzq2QCH|<hfIn?*|548P zXZ!sh@~oEHKTx1hDaAo#%9du-kW@vO3Q}b%n+}yD#eU>^{Fd?+0uG3<Q0SbD;oi!* z3n{&gO1q1y=Rh6WG~V}vAi57P?He8p#`tW9!uq$h)5bo#Jf9cd$Io59FTg$SNror= zRv0n|7E$^!`nmf4J4_+YP%HIl1BfYZ@0^-TXe#I`Xgm7q`wN&*HVj+FYNqayJJumC z=r;5n6L&gDqR1F>Moi6BvsyZfc~oZXT*jzYBjg;GB6-A`J6~qu=x8NINaN^<LTA!( zs$Tkb(Z8kB)${WisUi*P8$0l;l?@8{8MQz2X-KP35|1mHR`#sLReMSs&39$lHQC8} z8v~9+V<n5G^gQRVBFs$a4L5?^9mYw~N`2(V3Y4+Lkw0hp?RH+OYZy{DcZgt$V+z}i z1dU0>OekuJvY*T`<GHXT3-hGc8C=QZDoR5bllttJ1P*Ru#@Gof`BGjB&XwOarA-vn zoy-<`Ey4Tp7i=(`_R<>`2Ae4YuK^<@RTn<XyDfICgx4+x2@803_^gVWtTyN4jrL$s zgm%iH+ol@osnd$BX4F&7wF$`yWg%xTxh@_1Q#!3jtyBkUW7`BUPJdrlFWx}`Wwk2I z|8`TEPE3YtXxK~jW=0a@36EhIyF3-CjXlD1BC?OE#?~aqayKeiU&OCP9<;^+wz?o2 zT&x*f!Um1#GqFRT-WSFighoM=nC9rO5+jkWV~&-_GK3<?2lxE-HB)wmAr8i5rpCa` zJly&oQ%-9ig@Eb9+HfT_8z1zxtu*F3X;mY7e2K*WhRsVmESscw%xX?9T09=*XrI0= zL)_ByUOv+)Ind?0c1aAC`kbq8ZV;I&dS(i$G$Wq8Pou63EpE*Gs+j0W-wGdZS%Mph zDjLgEa5k;$tF%3<^>pjRD@hCGmAXQXj!sAAC{nhEEj|x*W_8HqMdW$9<BK6}%oU(p z_j#f)AN-kuCM5Y_(<nazH9Mw?Hkp^|;itYKXcpdrG4nXS@=2}j*Fw*KH<=e@oSHAo zST$ogKzHJ0q)$oi64+wLJwjgZ>nsd+=rEJ@Rv?aUof|YOn!On>P--M&-h!l2Ymi{w zj}uC-9yp1Z<D_qnAyqsGS8^{8Rpx7626jsPlv#nY9D$@Lf}m8uT)67X|LC*$+__rG zTC)y*2VTt2+g|+vB(4;qxO}4pydPfCtvbWLH61C48w#RiJG*5odMg)WQad%;;ESDg ztCni!KKz<^iK}7&nsi>8Ljsz5<t@%3t7FB_5Eed|g)R)@mrO0I1|h3Hi=O<Na6-+r zAQn8zRxaety~H(j;+L23HB$nbc~vc(D4KENms*P-w8BxnJh`jz?-sT^N;NnYHK%zx zxIK+ShYN3yB@e!ZtDkHouk9OMRjZ$HC9lCBH5{71SN#;V{-VsUs=dXqGfEiOm2Z4Z zY{<)kHa{1SB@I_m<{HI3LU(XOu*hvQA&n*}=T&|7<x&-#RCq-VxsNg&-xqH^0I59D z##UKSvh8RV5S%iUJVuOWizUy>vFu5|G<R8@{JRqxRD5v!$9GHlli2-FuM{!{|DD$* z7O{19^!RUti{g~+(obsFh|ARw8lvD>$NZd%p&Zo;7qOCG5Lmsq61gEW-GXxj2hB@6 zA`YN)4~W08P%sc~uL$0aR3X@0rJ<v)<20Ac?Bw_DEg!&^2=?Gm3g|_<<#fxh-$K*- zqBv|Zd2seo13pAM49#9#-g#sgYDGuK_F}~!xI#90W-0o2w^Ag}LZK_O_pOI1H>5#r zxqYO@O=KzV3fHhA4Fh2r^uivKO)|RTNpg|7JE<i1JgS}fCWU2^5r#a6CKTn}TT@XA zjU<ve>5>H|wUb92yI#gkBvFMfmz=kkf|UqE(q*5&bq^_Bg1@>c74L;H7oC<MtV&q~ zgGaz&f)Qr%jm^Kj8h%M3q&5up;|i;bknyJ(-1DUprErO+tXtTXn6R!-Y5%cFvC_0S z2KMP9>xs@gp*-H`9<N#=Sn8U~=_Erv3vz$5!fuWRMQ(|PZUsy{p%!O|1WoQb%DQK( ze|sUwew!uOqHArCXtf#ZCi@Hk^&y@Ihygqqqt70L)+Z7gvNjIKjx=*{5PXcjJFy=4 z3t+c5s<)3_u!`qy)5lk?aFO{0K5$CWU<Z&#t-%Z`H;%2{_`*mV&sOZhX;pOpZ*Q1$ zeW#8XKVjc!qW^3_`u}c+|GE)s)c;jU_t!^))yp`sbdz-6OKH)$D~oyFkivqz*h15A z6L>ul9@eEXgII{I%OI{5U_lig4jDwGK%Sgj8Ip1(lUdoeInvR?fdbdvzYTi_@OEZ; zR<~(e<|(fG>m=*-Yv;D-*5}qMX>6za)%O=!1Swi4!@eLIY*V_i16>pmb?-iZvfpjf zp)XptyFVUob-$2%`UugVH}WXE#<x@)F`PG6xW2<dY3`Ha1-I+BTqLMFcM!{a;JDnQ z1*Pt93ozQI!%y1GKLB+f1vq?;dt=<*qXA|(?z17M_kmD+19Bb@B4EBJ{c|{PAbeko z0cqNAD8ASIcGzz;ay?grRBt&zeP&2;>~~<fe~N(o4tDvt?$Ex!sG`&~x<?OOQ0?m9 zu<ATB#r(|f;ZXk?-_xP~HND3}{cCbh8r3EaUJp+#sh-?O-UOAUlMJ=SIe34T?!Sxy zOSSM4j~zw9kbAS?>6+*7^(gY-+QC5_7M2NgUyg~ZNhH6H3o&-!$i71qh8XFelfuOX z2zXp$sUA~T;-c$gKv)}^**0EemHG^x+#&`l?lWr2QteD4`jK*`+QC;`pCT>~`#i3Y zk{2`4_*O3|jcOAs9F_@|qTZd+A#zBGVK&Zs9dVXCHQ+7?%V1wB6R;t@*RVkRRxQ1v znrBB-!3A_7uO3TQSgdf_^5bNbG&XEm%)&}H0m)E>CU4MJ#yMs?QR-uy7Y)DcPM!K) zriyHkUyC2=F9ZW76albv9JBKn2cuDEB8CtOB4RC}px)fz$gD{>FQ09*2uESCh?axw zl>+J-qFX+_ix4}^CXBcb5OC4Fy-_`yzC@v+R3ox}$Zb!~l|;}8bMclkAkI!(wV&>w z+r7G(g4FQ{T$z5W?$%5s(Y2E$<C?L;u$f$=S`CzH&MHFIOTpvR^+~4~c+b+o1me22 zm9=OyscxD=|7(2DwTDv~X410UseWpUvTtNv;<1?r5fULV^^V6om_`p`y1{#)66ff6 zB-5M)wk2r1639_|!IjnQ`W+RaP~|0@wUj2uq(Fd7+im-9lb3o7@PfqHu%WH#E}`(J z2^2j<wetzGjILJMNGC!*{K3MQS$2T#*;08q{hr&19uX(uu(^JwJgTWD6=T1c1TATB zHM~E9<GB;RFNp@qc)*0V5HA8t`?5O(P5dK}SV@bRw_2Fxg?T0+pWW)vpS#eW#HGC9 zXdWZ!(9&9-%f(DRPrY*rbeV9fiYZ-r){U-Yo}7Pd)w~59@AQTP#9gzFO1jq)zwpf9 zAU@iG;rOF8B(_mht|4YY+)#OrX_Bh4y(QsVlDQIAe$rXEDB%p11T`t_Z4pl*_Ttf` z3Dk6hZr!7>AHsu`Tj@Eu(C&8(qzjGZyyr24mBz~?$$PrVxlQ^FPYz78ujhL@OjD&i z_v3K}6}*IS&?IQeX8|RXQfgCcFs?ybK6qF#KB)WA(L#K1mVHn#+#!+jqhh<wLOJ*7 zPs`ab3!<yxG_7`GIecQUl}Jgjlzl}o+<_y6+P-5zNQKS;k+-Ta%vg%~*lfNbvzYE- z>(ek%?p{6O)=3167-9hcoX$J$A?-`BMFnx?F!YI(GTkt3WgNzh<l8S-iNef?tCIz3 zObE7{Vr}Y!NTWTC#Pk@e@{#dbYDyO6C~l$$^Qd6CLndcUZtrnM_C`<^IvQ66q6kfg zY#nU62oA$q;**GX<l&kpU-9kQU>-)W1tbjOXN~in7plynW(kS;^iazEs4G#Ghupj2 zv#rD&kVJKIRE3s@C$fWF9LMUAF=whX=^w98TNLL`+6bW3^NRBzccba3kSC;?*{ZE{ zkb3-LvpZb`Qm~G`h9m_x1e*y(WoB)!HsZ4el(9|3D1lc<?}8LLnFvr+$skpP3AH!% zA8JevAl_Ix@%CJ$r(b2)y56dTGt@8j?Xe^HX7~7g+i^aKH~J1-QCjtJ-Q1>%^6PZ= z8^D&;lJat^-i_tY=G*!Mfr6GQ89n$bW*++ZaV?L{7cz~bS0Id0Zb2piEoTUni5P7W zpWIClth|3F4L4*On%h$ov)Og+!Z(l_+>M9zmoT8nk7fm{@U7?1k<e_h2QLd9?Xw2I zRD(=%+U)a3gI5I0=8*U~IuMf&rFSYjngS_}9#(ryI(@Ygdr=)V*_fVdlPb61-RN9v zIBsx{Zl`CTRzg8(nwmJSm6mhPflQ31FQBqsx)kGb)~Qu4=gz;Dpq(h!i6uUy9~?v< z7Ot{U(Yh<lt;{a%R?S#2V0}81^eGdCYWCHURYZjx<u&S{CnMy!dH9TaEWOcP&IH-~ z5vNDi!TI&8UYPTK3TnMtiy%y#ub&p*v@<!Pe5KCXwodc>*~N<#pAwucnx+hdm}ZL< zYHC9s9RTuUXotHXo_Uy4&(!if=wgg#WcgywXo)9OW!b9Ne7+r$-)<I^6-`wWGm@63 z*JPMn$uT_!SjK-@NhsioSwL247dcqsc1mD(rq+n39LH-)70b>^S+3!;7>i7%%2@j7 zDn>V9QPMKn>lVIkp11vGi+#||+mzirU<WkY1=iO3qa*WLM@gk)Qq{1MydBzEin$q? z>bRTz0HJ&pu*_cOji?CWSyvzNW!JOD9w8}E(!F?UmCcXxH8Y>R%;rv;0jAJ^fN=w2 zy5w40bj=;cnlO<o!R&2sge6$45hWUpFKu-?7zHj$5rL`?L0g&-bDk;tOepD@yl*ZB z?cm6fLHHpZXzFV8`P0q|Bf_qob9m=k*afuZG&73M;SIszeg1c5ABO|>b{?B{A9v2) zos7T%xB3NdWSS^_{nV*zjKK=93GWU^a3-ky8E?=biM=;iyCG#KCo`KVqJyM;bDD;Y zAb_)#@v89NmbxUBA;qjpCbWtr?<_0uQ}S>t&+4dZlP|(Ux#o3XKerE$wT%abfyb>* zddN8|-FD{p)8p-`w@mKe*MW$sJKv$xme9FcBK7&P6jOs2hz`=3$fz#)e;r~tScX6! ztH{4gw3*2bP~R)3ZiC9|mUYn1s2*kX9rEW+cnRj!Zs4BQx1R%e#SRUqA+SY<*i&Ch zC$&;Q9mp0q{ZZPbm~IvfWYE+wS%SnEv=dqzKBmLWMcrN`KZ;0q?OBB*hQ(oG#1!gm z>IW92u)n13Gi1d#AA?Nson`e%W%UY#xza}~29B2X9WDFC?ip;5>M{k*y+=Y%;1}LF zLrlB%&0UXzO~pjbf!i`f&0jEqyPk)5VgFh@o?ZvdxXFPYiW+j?(r2dQ{opH#Ps#AE zZ%hkk!v>B04uDLdty+fO@h8H_J#a^*xdSn|Gf#xu&V|`(ONXZa-re?-Sttu`<P{1p zS4;*E+`Pp+x}lS8`!@z*%4Nwqi7?h%Fi7)d#3@nd<=-bMtK}||pCLS8Ap_U4%!EKY zQ9X^Hv63|?;%{C|c+_0X@(Dd?IDT+U4?MC%&=qUw8mQCm!_f~tKwgsqB{IzLX3&+^ zxTQ~@ANGrPx|Qe^-HKDSf3SQoE_jg4v3R<uLJcrgpdL6e7seq4k+M-&E2Saj^O%0O ztC<i7^+MGl2K*j>yHuXo6@M(5eKLt_p({IjdqA~rUff8-a`NtAm`cl%)?3BwRc^u( z+kfa#dz3Y8!yk;G+?OoUwo%-%l6haYo_wPDDR5XS^=@j(NX2G~8jm*H=#t(|R5e{a zO1B_plJS_{irj4cIm~65_VO2P*32}Yq;sT9H%o6$<E)y>PBAnEOj~ESW_+!huAZbr z#AnnjF)NM!WnpN1fi9A7XOi1HC#)e^pwZ<=rIVi0YRhN?tLB549hdm>4Fo?S@Il+< zS+Q}h+saw;nZpv(as{cHTk`RXnBv>lmP@ORU9xUBCqnzJF?5Ez?u@SK?Qd%pCFlQg zAaOQ(HNpcrYXKU&bXxW+&giQlKbtf;Dc{vXp6xW`BAs$sW;yIAw6wc@{%T^%Xh_*Z zI}Oe9P`Lo~UZo0#tLY5}Yt=q*m7QbPH^d&a2C3Ys5(2q-bmE<#Hn<5-uW8W3?4G^N zg56F1&^nWH_Ii~)t1Qwfie)yHVqe~1Me2~?BKF-ayOQoVwSZoj4m;Fr8^Hh3uKtNO zPynp_%Kp);c7Hyk|3SNwb+Iutas0o>XCcuHuz~#WB7eaH4U5?7>*q&fT2f+C1dzD8 zLZXd-`igG`_o=!4!x(9U2WKfxj%B|8yq>-T)(=sSGK&g^C-*cg1h05HEtbN&waSWH zt+SU{Q7xV%G;lnH@enAy6xKLa9_uR79^tEPr)S4iJ~Y1hY^FA*1RwW#4t7gLO0I^m zn~|K-62gm~k%B`22=+U1(_fq+HS7{e_x_*X_YeBY|46`m0rJ<cfuHp1f8xT+8Csec z{l9{f5ZcJUG5&(S7-o<U1{%Vm9Rfr}VhTayqXL8^6P+VcYubcv1B^m58JnVxtf|KI z)M58Diy>}~KCKStOH`IhY&M@KJc-jKmAYYhmB@IuZQOb>dG&>eynXfhJf8IY{oA$k z+Us%gho}rdKL!88fT#O6+>AX}1ef@h!~rehEz$iqAu`^bU>F`RI9_2!kS_aC5Zuxo z5${_$9xtfd=RR(Gnknq(-XZTBFbv;$$miK>INnW|+<O5auS{It{gBzd6Y~dm1YJD) zMUc_c=dT{Gdi2;KA>Q=j3?yRNMECSzB4S*UdlA0uz$IXx&|xFyR}#dyB=^AKGzssJ zVKoVEi32O*UfBZ*#9jP*8N^+}dmBW#B=^u^x9&R~I&ZmOa!G|0s!hL8R<ycY#Say8 zC@qFudV;u)!dKLn==`fx;wAy7Zxoq3$XGeav3wTuBbiEcJcSiMNrVc_%oa^z$V-1o zbvYZg+lsT+a859r3@JL#ILm863uT%cG{uzrBR3c(Qu1Sj>G=afEMQhC>4wk<EreoO zJ(!ZmPMQwOkD7y6<bb67l-P)A#ou&V(z<FPnu1=bEEz(;qbE$Gs@SL<D`+%L?-cY# zFg%$ERj$`i+U5b&<(F+{-jz!+MvJ@^O=5n7=bRaZ<kF0CkVPRX5%J8o&qBE3J2@zo zWBf)7NimRVGz6v9NHYPdnb?hfKf<h%N|mlsOTvL0!8yWRG}1(lSqqGeld42aq3&3^ zTBylQkEB4^V~1z*q}3zyK8!lcB%#106+n9BKB{R`GfM&|9%b-iaRH<_(m`MeeJADj zP)?IrhqchQjf$y|1YQ|?&%F5KA^iE)oURjTp-`Sa%OIt2sp+CJ^6VP<UPJ+$vZW$> zCq1D!O%Sr`at9|^RV$K$fg4mP?w#}ts#E|)e`c8~lf8goyG^Eu&QI@KblMRR)s!|f zKPgDpk%~EtlyYMFvB}}{ES+UQw|O^E;9^PRZ46#*v>N4_<(|zpqMhD}{%~m0R{B=n z#q7KD9hr$bW>UE?5=BemvqBIr4Mr%!u*8ZDdiyL@MhR2Y{r0C?ha7EzR46WngdEbf z26=B1dm^LvDYKjEg;XO6hGcM;<G5jJtAjnw6yuUr*V<za*s`nrFabhoPA3I%Tl@S5 z?vjD%XY^Z+s%A_w0=YpvShe>_*o~QsQh-!jv;b$mOcV$lM0gd5LuegXkLF807`Hb@ z_y>3vQa({4JVkw}Ccn5+V7;R>FcQ_6V-tVS>5e;fb1%R8V#9uZF=#a$yBMov0E!P~ zALK0q&6jqNZZD1S52UZmZ{E#_4zyw+6yiIC>L3A$EOEv&A=Ys4z5*FF;+8@q*PdGQ zRO{y3$Z=|G!au0Kry*z}>|lLlLwO`bTHSYG2;bm-i2HMQiQs+&_iFAE{>Q~f^^CM! zuJAcZtwAT@xJpIRH3A&v1X<v8LsW!+V7_lc{KD_#-q3c42izUtNH45fG=e_9vA&50 z{UrXx4SOJ>?NyWi%6^6nBu54hDcnQcD%>O3NAWI{4=zCbLmVmb$~KrKoSy&dx@`O! zNF%t1_$7W#rZ5X|UB=FBFdh7m*pS#6eF!N*?Y=*dTL$nzWrQo`3*+(LX-5vl<bx@6 z%G7LYsM_AuvXsOEfdh<c=lL;|SmYYpGA1LH_hPw8mWjHkFk~fI%WyX`X9H9ya*KM2 z1-t*E|NKwwUPXrjn<&ZDAWE@3<T#?O!$E&4nf^M7)f|yO*ds_1FqW~e*Fb<{LIYs+ zp6c?EvXr)u>QMzyfloD9mWepmrlQxLHVbzTRm}m7M33Nn?qWJ>-~5^IhRyoQJF<Fg zNy@pblq)G|OI3BB26xEj8mVQ_S!t_>7Sgr0hRX@zWYXf3iEG%&m5tnsg^(-n_`(yE z^8_=21Uf6#y0;DU(}FQQ(`R$0_O+HjTO7ma?BERp{q4Q}bgK#+nO1wq(vHGesQ*_f zO;OkV`clra;&52?Qblv#hbVE?2(S6XtQqfXPLYYkBDAXRS-+TxM>LB-_2Y4H8rnV0 zdBth70$}wq_B{98`W1055G&hKa;&@A$zW(jUZ&mHwrkn3J73AGrvA85C33>%5dlT1 zrbU=plVJ=$if>dM*hf_Wkh@Wf|1Ye&3Jl0Qyndug9)LjxY!rSfNxrNa0Jh+K7%`L= zO7pN7=#d~d4=_V;=XEaiOB`yua#uu1K{2L&ReW_F$aFS<lM&PZRoPj9Rk5@WTqFdf zyOHkhl<w~C101?Lq#Nl5kuK?ylm=-*LPEMz5KvJ6%e~jnD_8IL{Rj8i^Z1<oop)zv z-kF_w<9SqoE7dE!gh+W2W3=I*V~CjzCEC~^-v^2`nkg!?c`ArJ$$PFzd#f~?V`^5u z3WYXV`>QZMlHA*IZ-Y9y;%5b(OP|;w5k7ctsx;kx;NooDUcTu1$=Fg~<49*|rSgS~ zV&Jz&9<f3Uj0{MgiUHh8T3*r~uR_M_x*?C=%&$Ty9!gWgJqzYZRBHM3M3&oW6{D^( z4&035Lwy~0DN)}>jMZhX1y?05iIjT~c37PZejn|{&^<pZgfp9x$9K&<2CWp!*p51j z+09>X%@(Uy;NSf^69sh7b}`U2-ZRL&ac#$SM0UZUUcj!?0nWtR(T^SMzsfrRDKM-! z+X}zGw0Yz-YYfZC<X&ZWGOgh?@gQvQf#7TlnUc$^7?=)+d0~gJ*dpFS`aYTf_Tr>x z(%h!d82JPu6rq#2WF^)2-&RA8cHr&__Z28Hr{Uoh=g*stun?9waEutoo(kQwN;e%O zlub9)bD(jydYqSM3^x$X8~YsT^y5xaAO?1fd2`7V9T1gxBN-=!O74X;wJ!!O%tYBs zD&u9i5`JfT<B05DtR!Q$6uAzeK!G^S6d^ndsLXciK?Sc%o?XIfHZ)VV$H7Q#E@+Ih zJluu!=iZZJzJr~_&+Lc01bSt91<ya6BcxieEXE?ZKkCW8@|k5vAoFC_i|=#bVqFYE zxLiA1rNO0UJx!R8@&>EpN|+->$?XP8!}dd(qK|angIElcefsF?3(X1$?u7M$-Yb`d z)hDLf#(aD#QTNN<hj6O7GI`@*!83#27)D5UMyH;iY4`DjULgy?@rP4==7w4&k$Wdy zq(8CcT2B|y;DMtyT}DvZEvBB`OM!pjuCtaM>U`f9mb=tj)M`jSNhSEe#+N|dgH&>; z9Xh(+rVy7c{smU7iBCqKHoGF(C>yps+gP!7g7_K18-D*ucD_&SvUQdQVj0fZ@^y6a zhSpjg5OghXwVPIl)2gbNvG8g9qTtS52Zc+9M7W>AVmHIKqD#7Ds=h1BI`5xGqHxZj zbS#>YUQSvMHmsny>cT_m#gJ5^AW(*G;vE2wC#i+8mZmtCY>~d@FDM%k{s<EW|2Vr2 z53zz{n2nH(9;T_9T=JfMpKj2r3(9kaeH{(6fEQxb>O5UGqZg-Ld$q6dP%FTA)n9HX z?Lk;t4+CunA>8meEGQUu>L9hhV0^X#V*NKTOFsT+?u5N2_ez%_i<gRO31{Z54-OyU z5+{P)GP3<9hpXmhRj}=dphsp<-B=e5{9BVE`R<I;+(<Mfaac@qC2waDeF4=H{S&uX z>$XoX%@q{{_AJT<j<S?yM=;9pm%AR$y}N;&8Ft|P#I3z_<HEgk1J&YI1UEf2F!XsN z9m#^KEir5=?s06FL;ol47`DEMQ^ySR$ow<MnNipW7KaNb`X_c5*Z;_Nol(t<RSJ9W zUIyOpXa0Z9jQ_rIt{LG^;EMT8Awi&)Fo9CuD`K}XiF2tQ@jSAC1;<H<T)tEnUu1%H zKAU{X&b)iXX2HWDA~5h${8WO5NL{Cwz46Uj7m2}22z=zqx91&PY<#WrpKRR|FU~yA z7T%xwzIVS_zTPbSmeUElqH{wPy41`Us^1*e*WN&W6h#vGwAbOW;A>~%sFeU}qUhE2 zD=`e@z7uA_p|fX^D^toop<&Nro+CY5pWM#By6@kK)0cX64Z;GhLVMbOg6YE%TD7{* ze~F0o-t3eC>uJpuXVh`EM^+yVmSXi4W7KiYm0%QcHTURR7`<QbnlzS$Ru<?KBZ|1r zBco4IYovx7yUPdaaWcx$8<)|el!--N7criqdJ7ESTHkM1s2rf<B_}Bn`KovgifLqU z3vX67k>+U7YmZQKys+q`1fGI4yl)qj)(14B3Dw4f%v1|hYQuJ#^s*ebqZ16s4Fl<O zvSrCh+3Kv(7!&luGZn&1wU`2hN6+G_TjLDuLzOP=O2wpO1o%YT@a`8=h^c5#sk!QQ zzYZyyfE&*$S_4+D?Rd2_rzu_g#xm+R2_a0{ib?H0hEQJY)S+F}$1;qLpkzwN+9Tu? zPry*>vsFH{Do^uX4~~C3C4QbMer})th`Q)yydbW6@l$r{=Q8<SduX3`#lEmm<QHP< z5^^4_+Jq()NXOkv$|>(XDo)mM8>(g<wVNkDxAvn1XJ!aWo7>WCqIE6P_N|3Or_wsD z)Ye-S%GriuV;evi1~h^6<S*ljzG{%z7!nn+_U#XM#~lM<%qrkwd}rxq7OZ!`FPvU9 zlrH+g?Z3V!Gw1n<P`@j%>l439Xz7WT_`&|0P%C9xO2VcQr>_YXB6#ERwqvvMQ!y_v zAtX5Hq)X>jvxHxE>!OBwnS}b4gI{Beg0@LR5xiwM2o1ittAq$xa&IQNT|L&s8&I2? zev@SRr3jpMtv0MeS(+tY<eVQH$#yNFt|`y3iC)g@C_i~RoT2V>vxmk=zsyxV{ZJWU zx~U$4DRh^*vs`SgKS5$ft`rjQGAp#3*?#*A>qV|;zp|NG8+Mpk8~PIK*t!VR<HS=0 z#@Efk78LYMFvXEs!|}~q$$QN#lek^upqu-h1s|_GW@3poEAl=X4tXGr4|_l`$yg4p zJ0-j~v21yf@r6pIOtbwRl0xaJ^kG`rK<OL0x?ogyJe9=^*4lIzJ+6bRX1v+m`e?&- zipCu-*3cTmZXMLV=Dcw?x1nat{G^H{krY<HC~VLTQs>hZWLATII@BBG{%0rKuwO~n zt46;0R+u9+o$aU-Es?C-U$sX2S9`?t?bCmaumIgewco%*`PX?Q_UR%RvAsfY!JVR~ z$D)ktiFQxZeENt&)Rd*qgn$O_)G0MB(s4fNxwl~HI|ZtQ>O8<Bt8*4xUYXJoD|<^4 zUceMa&Qxddap`1bj#B-|ikSUOZ49^y9zjPs`COyP3Evi#g@Abk+}Bu2uJpm`Gh$H! zZ`nJAe9R>;VSDQf<GRL_(=E71a=xU6aTlWxc~3WUfj59NtOZ7T?N6mSS<nijrda5e zBvxL=n2TyK)b^p4WStr5=pPYPd6qTjwyS8B7qA))jWsY>H&P8W#`Ot0k{)DR939EX zn0&HqUZ$i#&3><V^L3ftOE@N?dXaWx<=lbgQCf*@^Y9|^FdO-|x2@JgH*992^Q7_v z8H>psd3J=Z#Sh@jwe5CXj_4K*{Vr3St(GKoj+wU2+aUdj^^cBEif7XI<Rqj^efNSB zM&}-ObLP#fYAO2rAHsZFc!I}xnA=IZqsdja^B6^;K0C-IMMAwf)@&qwDH=s*QaV5R zi19!?H3)6XPY4ICa-h{RrY0wE>FxQU?8tK~@=4CHz22#kbWuygg&Ce;Mbad0QR{fI z4O}tFa(wH=d=A^Q=?DqYnBj!{)ffCZVf<lqjHn6?J!TBM_ubGg7*7mGVtT*ItPxXX zkI*0Oou_|%{(uXmO5#9>DW=Sla^TtQ=PwO@8TbzL9jKRUln7pKS)?&--h(yyhtTYL zLQ9r;HGW9L<Ih*oTFXwAZN}4U0!LO}Qa0wNADmQNywK)J;8rzLd_2$gMCVOgBzqOv z(s9u@PetTU7YLI#qrK@b;&%7P5GDsVJCH9O70;SGW!}U3^7)J-+qX6s7kMd`@J#ES z;jArWi1P9FL~s~Kj%8G1r({fBh80kKy_ER4OPbLWj^^^vu1kVIh%d&SY<Hq9V!A%J z%h4_E{*;8bT~VDYkZ<^eNTwEsH?crDeD`Y0#bZkhj)9m6DKBc~c<1m$&c%Hb(lw5} zU4q|qU>Ae0Ji=spr`Hmxe5)oS$YrLfU`#p=)x?EP!>In%ki1|yB@_6Ag53v|zPEfL z3PlzH#qMcapL~)M+(-Fmwu128#+D6o$@cccVeaGVqYN%sidDfJn;0DHkHEgqZ{qo+ z>cNKTwC@p+5ne?pQWbm2$8}bXJd@tJ>D<ivbn{I%y<?9v_xTglcrWiKYN1l{spN$o z1xG0HRy35L6!Oir3Dbe7{s0k`eR#VJ**!*5S9drSaLL2_-E8Q7LX=>33JrAR63_5y z{x&m?46V`6PckH>Mu#ZMc}O+tNOHFvRh+GctahHlF!i@)X*ou3JE%W0%qigW?4MjC z-CUzTP1H<s!iPlJj@Su76GN;L9S!fQM0z41X*8aCuXPHNt<Na)z7Z4p933c4+oXCF zqIwqg;3MmZjpLyu;*)l1Bm3lg!ymE@mqm>R#AaP&PdQ>zn~MenvT(CdR>^4xcHJC` z`nYYQ`gkI>k&BmPM^W58S)wzONw7nabWPB7v1Pk4)@^j@$Bcc1g6rCy2>QBk(bu7@ zoOrT&)(XIeHgBRM9Ph`J6O5tyC<QyqZ*rFf<wrPH>eG)U;aCiqIQI8(^I?YsEoSbC zUR9s9?|=KT40yZD`BcLLiTtm~g1@t;QE~#?f?dFFKSfNBQI=P{&w`QFeIK4WvLu4b zRPGfd5M9tz<R(1qZJJRtc4OuEtC=>&8zx0cq8o^>)a!HyLk_uNT-m#AV8hR6*B=pA z2(HyJCM%4p0#igjC8)fv#E3i`QzB_@tWmZUOUf9ScQL!teoC3gPR2Kr_}u&hKX%YT za#lCkj0eszdRXKzYc<+tubZlf2E@+wC1ggG+LFbvKA%fqc2%rcntL$qO~I@-TP_wp zmpNW~Gn4e?VX`gP!|_%s>j%VhFO7?|h@6LQK6P;yqo-H%R<jXh@_kru{L10><&i5C zHBDB9V|@1{?d%6;ZV6$*{wmfa<YXNzEO^?kH}h1}VK(q38<Z<3_$vFdketfUf%iC+ z`Rz8fdfdiR=T2JA59r^xeY+Df&`3a)1_v-(q6L!a0I})s**jS<nS-2Nn2i6JMuP3_ zoS9T4MMUjw?Ei}3=&PcyIAw(4x9qCh%Im1ciGqTv)-M*8_aO%U{+OIx7E5}6l-;zl z>g=3bzlZS+Q-;TS2qjv0#MgWNNnT^EtPbF|9Z$t)&N<sY8#kZ70C}hAnv2)T8Eex` zoFhg-guIb7AByJnjGfg75GqTXD_289wF#ZmW~+0Jm3tCGL4<V8rE4iqPIl-fXLGA4 z<Me7X-Kt4Z##1SYr|P!sbnjEWcAI)<)n1{!OjfsrVv@AfvdhmYkoirNndo4y<CWC> zN4&o66k-hd_f2iD+%o-6SGV>u_M4aUo~&^+YjmhtVL#WI4oa}dto`y)lVQqp13r55 zTa{Xd4{2OUono)iK-~@D>^#=Q{U$UIx5T2oVZ{`~w5riOQ%?LoP8o(B%%;t^FAy`Y z1^se8(%GhVdgj@kY(CE;7$uF`BAM~TZ3=1hS>ai8)5Y=7pX6S2mpx$5I@l`}8qw8o zq>6F1nTRZgwWLohjYl0<vng`KX1_T329w<ST>K-!%u9P1KB!ENZ_hqFP%W>LF9r#C zFvb;bN-#WHpqYcWq3ZRW_o%ab1BL#nc=PBb7FhwaJa+MvFD<i&@CI%h*{6%))O<*8 z=m6mlGT~$r_V&h>#DN_+zORYa4B?`UrO>#I5pbhT)7tbhpG@IE6u5^5ha?dqf(Tzn zOf6{6iRLlaN0}LWU|X%8GuDf45}=ult8PITFb5EAlzx%cE}YnMFFPM{3_kbBO*{7> z58*8!gQFW)3a(QLN*`G;xbeJvsme$LsR|g}D<r%)3x7!s!JuNqtCHJE=D>k50h28C zwSmlsVdIS6l%!LNX#g$6Udk=e;%OXu_T~oZkQJ9FW5Ob_^i0dpS^S1$*2AG=8r|pa z0Sg^c?=J*ZdWhqd1f7|JOTInABgqgG6pHZ|(c`I@BTG)%F;A8D7uO)NEqAA7nplk< zw8Pr*sdd^#cM&?YTb}sjU_+Px?TLYUv}v-{qLgNtQ~5QwK`CWSj*L2of?63K7j;cE z6kAz5$#C^dsH%iLh`2wsGP{Cken?|3Jr{DTqTBF?3cKCO7~{^yWCy&A7yvIL+TZjm zRZDxPUu|UUx}&RObWSnY;ykY}w6W67rI3$*LhAkZ0FdDSJpd$lt5A9&=WIWd>-dY` z<&yXN_NixITb&T^Y4o^Kd93(RRRlA4!3N0XqKLs>@Cif5Nbm|L8BIeVWAxx44rIUT zfxsgq=N3D8)FldqjLxqT=r9Ka4m_demtd33I^pIQ&Zh#qBuNaw=8$@1tl$P(z~zv6 z<g7pkV#67bdZe#l2ChR<!5UC_#H<uRD)6khB1Lk_))sI%D(&o@&0abwO;kXMBW<}z z)z0A(;-b7IGJX`z1|pOZg1v+<6C0l~3m{5hN801Xa2;f$wrY|5%gc!WYh2!*fjVY? zd;bPy68e2FHCX4k*=<P_hhquNfof)2kM2PJjnn-ya%9`G@nm}qrRn=+7|)^2@?vOe z%!ClUlt;HsRGP@aPS{mLGJV31Lh-J`3Ci!}iN@xY^F_F6*BAvACMd!N;uQ%V2ImWV zv0<l52@7NU>J;a>OZ4o_pvg~A*ec~+9v<X#(m5$*EDOutKNTQQ1CeazIyvP<ORf#o zy6nBkyuOhq-%1TN6MkCOY^s|=hNJ5w*nf~qnoxcd`g9`QGpRKMZS;9%l1u(@GF$1? z+zc<;<N#vq%$KzH0+Fbt;W!h0kNPL{(EU}ZQ6L}0#^ru0g!CBmN@cPT9t&Gc*us_& zliATu@FYJgRl&tnSBE#*Ybq<tv%}_)#}R=Zkn*XgPt<5F6C;C5Z>v$qsX_2dYje>b z<7(DV5?6<>c6UQW$nSJo)HZ)VC~QmVJjK~GS`S-*-Y{|ySvWP#s#zGk)PkqbiKY%| zk}1{%Ht@2mAb)yN4Zpl%jNUfX12ZR;-()%6+k@1c8K$9i_@v3x<H7RgDtp%IszBi7 zD#8OUDt(#RT-|sxeKp;I`+4eynmZ&lUQ&3Nn^t5Y<;h)EF%=U#itGdxDVXhELKP{F ze8|MF!px9#KA`%H^iV-PL(8Jzez5I%6>UTaMd%O^7IngdZ1~Faf!^AxZ1^cNM5^ai zq=e=QEwbU%WCuyJL`ADHGO{19`r~XDVh_(9vK@*Y63c=ht~U#ImfO#79gYy+oziYN zZB}o9B9Qt6lLy+tXQ!EyvhK{@_t$C*aYKA-CHnfpWrT$yqVcn$Tg~LeU1<(><Jj|I zGt@>S8r6<u48`7n5>wMh0T-hTOW`vZOjogqnnC$WPS=shSC(VWauWWv)(k^lg%d6C zXY#T-0!*Ah2uQ4T(fmdx_GexqfkzyILMl4u9Y6?37ELWsJNxdVp6fwFautq&0LWI} zi;wLD^f(v=)%MjqWxKD#H{qXcVJmlrx)!JbAt1HYV%?)X>Q;;d$VzZ~_~#ptSO<3U z=<39J@SBFJ!}Ai@`)W=7TD%+kbu}Rx(a(vAkqhR-Dw>O2ifGlNgF~JG$@kzVs|9yY zTFC`~R8ZP`5T8p!$h0^$ARjcXsiJSJG6}`E8sBe@;(i^pfRf#BLx|Dsq!pAe<BYk8 zWQ~|YT0yrTAC%8)>1bQiOmGy6v+<ItAfDsVd?W^|WZ+1Et4p2mOxmM`G<JHJPtuj7 zK8oK2t79V1jHJzR)s5J!fS{p_e|Q*W03Jp~_zgVy%Dv7wNB64wrc6)OnoX7Jqx7C` z>4&c2Bo%0B!9a)WPKprgcw-CN%PN;hQLDYmmY_!xbw+|$$n3ULn+t;XK7Gj)B_fLi zUuOd^S_0&9f_oNLtTvcWWJTk$YM`UOd_p$T4u3=BK99(fCII1FNrmppxk2`ahmjP# zr)OZ>BH&@fa_eCfpMhN%+V_dZ(-DP1FbVK5GU4Zrez4N{EQ_NKQIarJdBJgdC?(xG zktdRMz?^=nFNLOVh(IzOoh@b8d^l<0dk9GEB+M%giQ5p6%<XUf3;`+HXBKJ55!<1G zgK%bpfIjGuJ~WXib?nEF`{IS8Vc=_fW5J?}z(l2;jwjI%mjDl=D3j_dFCD<csPGRD zBbwL}Y3@82H=WWszQXBJms0%i9!AzMrTQrtey``tR@ZPA&74Q<abCS=gL0snc|f`^ zJ10<DzidNx4LS66M9N&J@u|E9i0t~|(AP1MneijBx16>9aR=`a%r2E4(0t4rKWf1A zJ=d1^nyh-Qbbd_cPV$r(Dr&%V(~Kn46)v-1Za^dvhU>EDUilgQ=o0K1^YtU6Q+6GG ziX)hjdK~)9$TD(a^*}Y@pfV;h^+T6Zw<m)R^2&CVyQ7wpOD=~yLsAVsEow2$gYao| zmrrb2JUFZWbTPsMT#OzsLA`smRpXlqTHozggn)U<=T7vjYpQPxoW`g~m1)uE;`wfl zzez6YfyJmDPWP>g(ajwfqXYaAy*R+d2m)|1`dwi1KgZs`FO{nQ>0_kuq@Z9bu)Yv8 zi8IA20sc8{z1};#ml*8OHgP)jdvRIhqN1T=a@AEpu5mqIC0(YfnTKvK^*(PzA$RN? zJHEU$lX|l;BI8nXRXYyye=lfp?7Q{U-|s6X5CXCXr`LxIrW%E^8Hfm6-Fw2?LuXvz zz!43qIB`gRp^00`Qh+;yW3c|#HFO`Lifz$o&d4KZRX#Km!Jeg!u$zx$hr|Zn#csq< z7Zn8@AX;ZW<aVA=SBX7b8?+WIq%_VAYM1JdR%XqT-9VKenAx?M8IcLdNm5Q2-aM2C zzu3(b&)Ahs$8B$})P;H4KBQ1=G<QEf3A~BU1LlKUYAoEuAy1dWmK&CCSqBF^QNSO_ zFJ<u6RK)nGA{g&RpP%$BwqezWneH$ebZ~+f_C`!)sg|Zr8Z9G=R(sou-FCMOS!0}Z z!glVgX_s+UF2J~@m(vn?kdKdbeX!z*`P^`kD#Z?Kc3?d<IMlZ<p+$7oaAJ4RxJN;H zp%URUv9?}K*|MZn>z;W~Xgdi5tAgYLTx@}c{DMQY{w`7q$e;@0^Qb;pTOx(gXSr5x zpBB99sRL_!tea>{<?)uaQ9oWMWDyr#>!vfpdJF%8$F8u#dRsmdL`Q~=z__#A(u%X0 zXz2lui-?K<=8mce#aXkFZj|8Ih=U`kdVY^Am;td#X}UTl0VeSUVdw$^R?sMOs54$a zE+r0udHY}mnH+cb3_=mR9Gjep%!*l5g|gK`Gg^S^i%QX4ve#9wSk&=mKgsA?gf(Ul z?n*e)aOpM@IxmzbQ1CHCbQZ^^A`A7^4IjUeQCOjNSM1^CdM;Djaj*3K_3OefIq&SL z0v>)W)|y|;+uYqsPut^wJB53VrQTaon`f;$^yLpfqhhQ`>;WTNiOC$%26b1>OO966 z&?Eyj+LT3_JzO3tXRnt#{7&+-h{Zz5{6g=k1E^3Q?MoxX`zCb2L1c*#&+^O<OiF|N zGc-cM^+MJVpAiTA1H+NOhQESz|AyP$vx5AZ`S5X&9lyN4kUxkkM>y#*r<u4OW>@>V zqrnBY=xLqzPPo4=1w!i-`cC&J-dd$(da?G)3RzASip&p#fpRn2>+o-QtF;EuD?UI0 zK_L6fa$7P2TZDyeuV9i-0`b(LF>Mg`QtWS?jL7(NGJ%ZPbZFlo0=mX|DzAt_27AJ| znWerVPqv4h*dt2QsLr*Tb?Q=Kmdc2qWThr;`xXeQ$`Y#m6$CQi>GZ>#>E@@?sa7=d zBp*qneZ?*Y7z!wT3XVz(k!T8z5~iul{NIV}wLP82wkqv`FRhZ=v##v~lel(C?sfbT z74k_z2if&Cmdg3+X+gi`QwO@2rpWCv$v08M`RZ;S{DGbNw8sN@?f#lx<0b9ac<tZR zybRSkStT>@J~IJ9Abs&Zqje&+OOv)%SncG;JV&@<KaT=JG9&;VMu%tQdO2ws#k&FE zKDInT&2Rn!nsTF4=kQHy>0Po!iklEn>gPna9!9vwWfO5{^>03jd5<N^Y!56rP<qcS zaa=O}{5mmNa_-&^Z2uJD|9<;N)x`<O4gGh+uWU_kEsR;rZ-~{cJ-oD}E0E>;Y}H~X zs4;;VXefF?Z(LA&wbp^41v|B(=H{4hB;RdKx}#4ObAk`pz?qF1MN(5~1&UMW@r}|` z?$`dr-!4ymzj%#}98@2SRX_afYjM2jeRO;?_HsMR+jG-@y#1aL-&cZu!8X2V&bF{V zZ|%kLH3%%^T95F)Ypu3teGh1*eVBuhLr#r-f-MB`x_d~8;MVUGZ4Ny>-53z}5$UD! zyrRK+X6_i@M}hUs_!K7!_+QRwDhKV}Z84vm;trJ1V5Zuugm9*_<3!S&wf9xwS7qT< zrzc=kL+n$;nQxR)bo7<A9-)0rTKvOn3-m==dZsL+Ykc%Mrl<N?<6#a0!Prnxm!;sh z{Eu=QpKnL|DA-94?Z&4xmzM9wH}?BMU=r%6pjOvQ%F{`*nTkd(Qy~{x7PUyq4wm|9 zYkpctuV9u`7kw2<Bu@;+)j+5d=R^?aQfIK`E;*bL!%t5^H<wUgQ3(J+fLK=#E=bkk zFY*ci;||v>?4>Faig|_H2l)J`ycTXr=BB>NI1tI9Hf8<QWpPVL_N|0Eyrn624Xp8R zv8yX#bDy-#hq3eI2$W<y+b?P2TteFLSH>2A*z(c4g;3r3No1THrBzg;^D}UpOt_?9 zzT&}D@>CF#;y{Xx$z<1Geg)T(w#8PeR&_KI${?_9swxT=rWo<2#=d5U$YW)xB$uP0 z5vqM&O9wGZpzb1@Su{^wm}137sLI_S_I40SG`|*A^SDsR)-F6*Oe7rDvz787M)vTj zo&Iq20^0@)O+?cDqKcyV+yn(Y$TA)oT}0Ix`R$-AsRCAM1-^ix=pl2Hq|W;-ta);A z)(X*2PXeFdMJ7t3&VaWu^feRDU6p1zzJ#0Ld<gG;GCxWA_?Z4(r85Y90m|l_CuY8^ zDMjymNk(V#ZSdvT@^dzqXo{l>#>K%0n(wwMLpYOsa>qhk!+p~9`vMPCmsXooCedY5 zUn81m+qrSpbp(I$Q0^unh?@wpBWmx>??LMbJC?nIh$61NLXDbgmKC8Yfi3^=BILvr z4zihK6-YAHU^kG%o2egMfUn$~Kz7kTsMH^wl^QdH;zzoQd85`ne&P(*`KtVW9-H@u zR7M$F-fo@S`vW`d34U2^S$hUGH3ofr;clkWvS35Udw!#990aK+yifglOrX@nWNWj@ zOq3eX2Dr#?usZWY<4v_95zrYH6zCr85W#g0lmtIsd3t}3tiL2hnu1IrLb7Cig!)+* zB5zs+e6rsLzd9d7)@I1&JajqgoGixBfsGDZyYf_<r?bZB9!AQ2*GM^;A{2$_eYL|R zF{s(Jhg`*#!H*q_$m5b60-c4ov*NW8YPkE>$fIzIm7*oTaFed$L<wREaFae#sc=nr zD*i#>*fsGG;mcxsWUAd`cN1#{LFaUPYMrwB7ySmiBdud%-n<gbQMID`R^_fFY(*JP zS?oT`=2TD>1SxOTY?{eT)83^`WtvLpk(4wT9JH`!$3`dSR1KXUwq$Xar<oZ=S*)Ko zqXZ@i!=<0tTQ!&WGGNLjz>n3HkIOY!fOW7D4<DWi?ibd~xplRNl^+~0mV4IlfeeRb zmyQp7=|N8?zUpzB@}zL?DinANxF{%ql9r8IF0WMRCXBwR%6J7c&BbLX(4trDdvd$T zR!t?JCS@t{0(p89S)Gp+_Y?ZPyuywlzgdewf1H6talrQ_6vF-TAaJtC8m01034%Q( zZlgID*%JoKV&&`?Aq$hn&!I}w3CIxwTI+&bGlMWAIpv?zdr=_M%NWV?7?EJpi!Cj| zM7=b6!PZ-(Bp8HQ;A)hKTq?>~+G9{a3oms@s?zE!y|fy~dmv65r&u<cniL~S7&?Qq zJ*KB39Hr)oRBA`+Iv6&se2zA)Ye}yy;kl)N*Z!6iy;%8KQ@T<>x*)5wO_zDBXC~^y zkwG(a%P#ZJ?W1Z~Y0`<fwq52h4vReNEZxT0*^@NE5Aw!MCS~J_YOY9WE8k2fSg!D< zAf;$(_C28UaLq7ankvcZ{t%G<p_B~8C~$*3W!<3S)j|#AarMqTh8ypBitz+Twu>Cs zweE}bVJnVgPKU=SD-d{(!(Vt%517=MDzD(bsqttstzj9TmxUFp(sHA-X>Dk1Xu&>< z7LdF5G#3WD8tv&8j<rin_W2Pq9lXpbOQ6@{_PzI8(;sQ<tCOLP6w&5X1&!SKjEa|- z7fpPf^%afPA!gJ+oTn4K53IDW<;s2wjWUj&y)V9l;2HE5`^nOy>eMKxNCOe1Ip{Zx z#qaGt*p7bX_?Wts{{sG<#Wm&Y($C<E%`7|wwW=s&m|3&OqHp7`a&g*2KMKMDDMmVx z{L(d65u?<4Ikyw`C{^I&;U-3yV_sVl3m7jw97OU}w}VkI?wRsb_!e^Ujbj_7Y*AEc zsaZY&Y5!=nFAv3z-n-lN-Nn3<Wp$nxI?v+9j7osBKiR8J)ue9$Z?7yAdM{hX4qeIo z`U_cBC*~3*P0z%Mv2?f0Pno)}xvWl!E4uxiwGJG$fqz*Huh%FaV<9@%q6EUil1#&s zYQQCnYZb_FCkzX+<82oyi?UlOQ%xH;RCjMn^%LOj=5>XChRz4uVeLos!NB)R!1q%= zGqOaAI$fh@{8ZiSX@@o1n-`*GLx#1mZKmAsf6YVh#*InEdnvWdCNY<+3d++3wYa;# z%Xpt1tU>yAYbqOoQuVFE(h$9e@>|8{Jm16{X12wXS3^a(sT{_-z>Zn)N*KCr#x_sy zb0XNzI4<vNH@$E{Yh+{1E{~~u-&GpTsV#4Ft*4aCs74_yucIW|p~ScK5NKM2A<yAb zu`*OU_<^m30cpb$-K~e1`I1Qk0f)3-UL93Cw6r<GFQ4@}m@LE9dw0N1Z^o#eNGh^q z`FR<6tt{&BDpZ9ykKkL3`#64XbG#VCE*`)yb~WH;x9+@nAK|XudHLmzi#1zW$^9B& zOQ;q|Z3MX0{&Jr}&C&_vY-w*}_NPy6NW!SXf)GZ?_{MlIVn7i?{d0_-BI!7*nj#Sq zOsRO%mPe7jPG~R|aW!<_1Rsq*!|E%Qsuz$Z3m~h1jCK^&1hH)|?|XOhu&uYgf9wx2 z*V7pEk)q9o<m9#Rf;cojW6DX(nB`O#e!!kwXgV5-Z$L{rC2e;9>dRLO#qSAwrB@6~ zrmtA#)lFOo3csG%k9P=diu#PrCkMn%OS^Gs3@OEmYUl)ckoLsO)sIG*9Ja^S^Q_>^ zlSQWQsTu80+P=<aTzXmTm?Ae_(^#>!cHJt=lX!03hYZ5F`ogRhfPkF%s8uDN=QF?Z zGkP^6dv0|DKO?4&6NJRR2!TpmipUr)4Fj>jNw&AIXd9t8zgbUm3N%E`3K3Sm+6zj5 zx-QGXa-WGeC~U1%+6CiaL3U+c!lxA85Zb3G1)7;w^;vG$Yt}llt-zM$uYsHR;dL6| z*bj$@v=)avWwSSGB8la)(2cmqMj^`UeictrfJk_rBO@0r?L1cPF~klX4Ak;=584V# zk*HdEz=s`~FwY=7&C+k|OU54-J=+#)xFj5#g|1A&cK^nr#=zW`(q?^#{PUDID_9#2 z9+>j>;{M*L9(dyR?#3oIKWzeLr|ug9o&W>>ko3ch`H%9ROGlSW^o4}Kw8RL95yps0 zbBTefVCgxy7c`8Np1%3UJM(;*vb{;#%RX^g)fU~vlw+4d-rB2^(qHJh=&*A_@tK9W zo0i*{*#m=<1Lv{yGv6HNv9qi*heLlRJ!l6y14R>J^Yt{@Joq}egFb%ihthAB`_~Q^ zeI8gJo1HS+b!0YNR$mz8oOW;%DVPWl8K3$QT?-KqSM-D>Trmr(ggvD^W%0?nCI$gB zUPbcBCyJD(G(H&(<I}5ki(h!Ko>`niV?C|&2<%Iw?-*Q@rSBM7qdVx*)V{`xs;aw! z0sON)BKxN3JNkerZ%5BsD}4v{z~%Z?0MtBA<{P!vfm-&dlxo)rW-8u(j^QJvEXJil zT|z3^j@<;Mg%{hd*SWzdGhH+wjom?-PZ6=IiA5~M(VO*^`o$E}=Xl!kB0ae|v!U=) zrWu}*1LW+8cx4HEFVc9M+Q;y`fdzCMY@N$4StRN*eI+L}PS``)5|wbb-09Y6+r3W_ zmHMa*(-s`E93OFsES^C=`j*JTuprtW+W<f0E1Ndh*rY~2S+hGMv|O9qR+deWTHWbV z+Rl@KHLnxX&MZn*&3G@a+VPX}r2DetA?>&3R(TJU2XG04JLsN$jA`u0IZra5qvyAD z8Z^a@sB&*$$y}0EV#%ovs|s;Fpf8#)ugs;|-H}L4jC2*LqXz|IVLoHDS`;ulr-hEf z<I^P@$iN?6Zi8ajA+gF~C3gwi&=hmX=6o#bSq{qfz-6@|CSW^|9(9RUzEmQSe5rQ4 zgA3AG_o$qDk(W`8q1)8&8guUFn0ATxsiGtAkzz?74H~DWk<8p>zoAQ*#QS;puc4#S zEzu3yqRve*O_l+6L>&VrV;U;=aqBX`d)h6`v1vudpIMwOHp+KPQfB4!KO$<39@AtV z8H}M8b3s$RX~0JVLiC6tb$%e!MB3BU$4EBirSr!m!X1iMW>$Y;xc%_O%L6m_GkV+y zC(*%bh1kmd*>g<mKw6Z1WNfW{kYjx2W0S*@XowrFex609b!~pCbvq@jO6)62Q`GU{ z=HO?89uTP%>?y=Jo3bobsu|uN3#l_zu?nptna;+z{b<+WD^*eo`{CWJ6lzM2#c`Qd zEm-|x4F|6%3{p<%+DO-DJ$Pc@4>pHtf`Hj=Vs$Z8mDSkGqAeHiH;<BDr>eDzx~hdS ztY3Oa^b>2{pr(RuA{rjoT|N9tyKYbab!?58-e6sTcf8d#higwbEB<*k_pnKl_+xwR z$4?c6lb-{j30Pp%yBlF&N{?Iit>k_dPLfh<KZweD1}dC{nH0NEq;0#GbZQ^_ip1GF ze+CkC6{<~9Y=NnJW*A})5rHr*Z`nANM{S3g1gVz?zM0V?(dCzESZ~hThUxcym|`pE zjlKRPd2&asOn1Ilp49&u(OIX)_MOISBLV+8wdu1Ad2=_|Dly^t#;yS@8-eYQ=(#CG z<mxq_Rt3>fF}EqWLq_e4+vr_CVrZ`LL;4_>kF}(B!jHZXVY8M8RaVs#EMYkrGBKeh zx`+w3h&QKi2(B&#QKvjWlYovYwPb1rtpSc6120@EbsHDoeDIC2?q$-%TXF+K*YzJe zt=D(iV-I7^AJTB*N6L4m%<G(DlKN*Z#dp+Nbc`JmRX6*bscjFvx3Oa55r6x+-mx&Q zP8N9%uSga{cc-(;_q>y;?_MW<fvqrNJA3x@l=ur0EA>fx)s{m~somicJd(oCfZ<NT zGObIZUX)b=A4-oxg(%%o-i(Ah7SbBZiluvgSQ^@6Nh0sKj@2r>sqwrbThy9W_Mvy@ zA*@b(Xw4z#OB5Rt&laV|-=T&r9w+h%I59x3%eLv@J+Nb1o&KDq^GuY<EIiCLHZ0;v z*!55kB(R_C<uP)0QZm?M_A)F?M8Jgyl3T%a<mLGKv^UWVGT)dwUv&Z7xw(^FHI&vd z<UZIY&VfoQm9S@#P3)cYz;kb@)>$ss2&6P@Z~k^z&$+s$P`}xZ;81b)97}7%-j)GW zS;JhWj5nurT8~whrn7KM!L7lF>G4`q{UcJgeEX>mOQbpm=K}3HSP!D(LX<1IaO+oI z%*imFAn~tw<Tx>0=MZ1=+jrS|L^;b*-F!UN>L(snde)kuI_>_9n3T-G$lgh_E}U!f z{l~9Xc8^l+5whwOkQ7#7$}mzIofD6zDYGs}EpaZr&9N+D{2Q8@!Hj-WMhkRbCHfX) zS|Ye2FC0I8ZQkNSgQ1SgDs;%mzu-Td7m2|47U06G$)4FN!oy_B!4GR=j&N?a1zec$ zNs-a7;?cAg4OO#{x<j%tdsHCi@}a!xp)Q_0;M=yJAXLaiH%8UHUqQ8#l;fgh=Yy3f z3<Q_o7@N7bM&q=-3x7myGS_(T;C>gQ#vC;*e0%iECJZ;{M=Vt+2Uf834{fzgoW`4< zrJ)zdM~>Pcr@fRgH_&gu)weO1d^KWiw)IgxGaW5+9+&w{k@c)fJ(GvY!)H*g+&%LU z52@g$b7<LL>YM%G+oJ*>Q{;H(ymA43zlQfXP7R9QSr6hbx!pap#9BsQvb|e|O+HbE z6TwB2ffH}2!f-`mBP#0|p2ab=G>LBg#DXoFI3D`haaiUH4x;#>0Zkb(as*NZ+2;U4 zXYR1RtXG)^5mQV^xdL>ExjiNdx$tGZ>47wBi+I`jJOuh9FKr96q*=BvlAZc{v-mW6 zPov-;HlFGJJ@VMCRS{~o^ASF<E#L+Bds7!R`#)FF{tC~dZmSB!9rI)Kd^uE`lpunk zOJ~bK{?N8Wg#oPwwozQQBvfVUb0b`4b@O~-CSth#NBfh9pZk!x*Qa-)WBn#^{gc*T zw#p{RV@amX_wa1L9QQopxit9tbvyO_J-r@xG=pwFG`m&K0m9V^r#89+ZvtrJW2XwZ z)-gxLxl10wIHlguVD_V^@uFZ@qVVxBG#L--RaC)*xZVMRXXGbfw4f`wz(}Y2n5#Av zxp0wXTKemA=5Yk&J991Cx>c-l=J0%bIY8v`x)fceV@pg6k_F5UaSstDLDsUSIE;Xs z&P+urhqovLK87@AMWmHYStFy*<3alP9aD3hDg6DS#=KdMy63t@R`m0YUP7nLgvhvz z?gOca4U@2`1GETazDl7kN=scwHQkd24hGufK(K>ZxwqhVP($Z$vC<|!L?YYrw#4f; zA_SdJU37QtI?(rcSazekQM7eOL^8UrAD6XK)xThrz=LAVf|K|VS#Cs&j)nwk-yw6Q zbC>0+N0*t}<-_cC)u}w<dwD^^WBf(KJ6xDul)oyorEU;q$c$@uhj+m%Xw|2y*7{}H zjDr)q%qZ5O^#*4JXTDl}hMPFL3QlM&x~4cBuIiw}4y&6(fX<9FqnX?zS*LDFa;Lgp z?44}bF_yul1?(En7S1oaXzBbtyUUCYK8!s=`k`>L{ftDz)xuT;S_JYWZYidUb3C}$ z)%OXO8S*8}&3pnNW0^ocAyv3A=9FeWkS)pdbnCkO@uygJtXbDpUnh?i!0xF>eMOA} z<th4_rDIym#|&gb2aZ!t^*P0Z#4<Y@=nBQ=lmyCC1n$f(DUjjo76JQ+-&UWKiHsu@ zLt9&At3^LhciWQED>aJUlIk+nX;HJ&l9-x2Dn$~guJQGi)oPTnS1G<I+qL8vEi&;g zo1E_5&m608D?dYBgR-~wvdzrEs?stScd@5E+wpIoPAl{$0Ea(=`l7IMe@7(Yl1*Ep z@p=6#r1(c{4h1&>gCsD??@_@dK)$B!ex2}#sosqCBqWOk+myO-!F)R}gBS+82|p}8 z$5J4q@eimgUU|)iK&(6up_g|oo&cp68ZDhw$XEC%$kWU*?5o!kuo_EHDjbQo3LKBL z23phj`~JMn80AgHXp~R87C1amPX)!<KlrvPEcT7KImR@;+$lqoabWnQ$Fe337aw2Q z=d2%PN^YNVAos{A<Uqa2Y^*T*FyD4nj_ELl=$*B1eN{c!&=tHbVkzkjK7)9-@9`q+ zg4e))YS{t2{Uvm(C4+e;JxS7=P3Rg1>jr7-OW!4`tMgQZVLYR_$~dO1@}?yJ`)-dK z4B2)i`o1B7{T6=L%DL{Sb_$Ia8M$?Nyz0TJpsC_xs;qC%Elv-gbWpU(rx?$Rzqon$ z{axkWy$C?H057EfDagPld2uyi25AKeCR<}SkllaQ^8fke+bq3zz6@C4F@lVpJzW4R zJYYTlUoO7&kp3?h-<t9<{AtSf9}w(4!ZI?x>s+<_4ZzFv7vL3(_5TNQu(xIOu(fH| z7`9trM&aiZ`Wi6NM-}CU_bB8!HEd+FRD7=ZI@TdgZehcy8Yy(bhxOyu0{ZmYEOx}m z<=)Maqk}kEzLs|zxY_}4^dg6iFpwbclg86vM-8tmxUhN<>-7~=DL>ypCl7t3w=--6 zmSZVmx1d8Iq0_1jRw{%3^5IiXPMBzBKgj_8DE_%uJJRei!I2F&!6fmeJF?Ws{F8^a zX;P241xTQ1Ob^%GS&jSQu1y6#5OhPsl%EZ(t}`$0Btgx^GN5m=h8%dm^*TrptH*RM z2}uAsX7;DiK@~N@)C)V4>ezE*sD_Sfn>YwazIp;id@VK|#kV-N>w%FY?y@<HN+0Io zbjD1PSOH}`*dQBl&6{U8)ul2Ku@(|D@I@L1UvM~Av4Hf;%k__N*5PKcrxMkQt}nTH zk5V27l;S+yAk8~W3rePqazA>v?1P=v<64Ea4GXPG-Rs*q^Qtn0@L1;v5qUA+V3gW| zzX#r34_{xkeU4Gh+b<|%upUiZP)9!JJ(7kL`5}Qro@;ZQQ@n86U|ZybhDGeegey;7 z|M*Ik(}A{po=O`-^7z8MF!C2maoSl@=s8#}6-P@S8<T~0MuTTKiUKv)y7`*-3k$2w z3f;K+^T2)*wzXf{Ye<pacn9c+79_TX7FP$#VdV-+k({{J&O$T|XgSze?^{GIfOnkS z!HMhh22v?5PFJEmAJG~oD94iYtV=$P?o70_hFj}*3!vLTyyTMiDo5NnEncXag{{O| zN>J3R$^Uo&xt_|W0d315RB*+%lI@LtHufbs(Rag>9&tPt!Na;&@({JEMe(H9q-_g& z{8a`h_2bg6)XhNN=&9yzq2?00e$BV4H9gAC^95hO{0)Qrt5S?bg1v)JtnT5l-3DYQ z{B7JAbKdQOOiKFZK3V1dtXE&~zxP|%Kl-gm9^AYg(D<EzgXjO>2^^g49Y9VlV30H7 zP#1hRGs3+IZ<22)bMupKx!iNw{M6ky0XwyCWa*?e=H9pNdoRU2e2B|*HGe7`^RU@& z8D7v@l$aT5-GQhF+VBiN|5DQ-M%<Y}b%(5(-1T}XwNz#=-GxhIm?D6zrtQsatS&NN zJZ)6KHKdX(#C;4%AWi~M?y4VPa`RU~xpydh`|&?2;>TsM_rd|K6)#2KZ3=wB8#pj- zzxh`w2%rK!{pT`yVFhUkaaA=&d5Ir{d-raqRNt?-Jp(hVzsl_ow*jATZHfQwil0SY z{_BcAtdIYG*{wO{cl7P~hp4wd1Pv?-{>o_i2LblpEy3d?QqB<2bt1s!w?-k~OF;nF zZwUVg0Dl)5cBS5c0@zN!g8p-b>IZTjxV2vi^#@Yg&e;KoU;&s`|2fP2JNC9xK?eKp zVSw6f1t5>UGl6qK05g!$^q1Jb*|Gecc6;BjCKuG!z|}#(LGu&M1xPCRdz!e13&_s- zmqOlR3pThNjQ|1Z9{m}{_dB^DfD-NBu(t-~zrJlc)O3}{z@vBs3`(~av)@ZWz##sw zi6X|%U{f)Wv#Ar<;n&r9E9uF@9R)eSy8R62E?1H8H(aoV7|0ZCYi#rP&Gfq!tDGR* z!3$XUiUJnC^xuUA&IJMMzykHJDptha-UeiB_g~x9)mPlvNuXV&0X_V-Cw?yl0T#fJ z|8L}fX$Sg)?ERd8xZl$r{DArbi6wst1*RbXRn}z#9?W#0vBLco&iM!SGv~ix|3%O@ zUDR)HEvNq}=vzPy{7O(!OJk@1DkyzL>R3A<=q}KQ$iGVooC^Y!ME?c*FM>)dS+7R} zVLlOoNIX9`SVgJd5bbSj{_Od`Ygo7a|A7)Nqyo?hU;wr9v!)_b|8Lx1^sU=IF!2oR zkN~tON1#RhENZ>x?~t|*#!h#a*8koIZbeN;nmLdFDis0H1h<pO@1-ChR`=hyU}t+f z31hI0s}o4V*wn@Tdpz8`e23Ci?q;AWR)DGiI@NzlK>)eY@A!6RfLqY-bSsXjC}$~v z`3M}0|H0k10z%W@0-ar)TyKSxwsW($204+l{91u&30FHA0>a7z!ixXIMl<`L*{UEH zVN+9(vojdj)zC1uaRmwg%TSSLbYh<iJXcd-VEb7IO`HF(Kl#s_xot6SpnW_T;AY+d z^xKz|@1-E1!|K;$F_4Xm@jqd=%_L3S`)e3L$ODd_TQr32?_mE$tCxx`Ntywzt_2ty zZr_8xmx6%d-y!W?Z#RmZoQyqx*ZXd7oCv;oGasO>0|)hYDsV0c@NoZ)tbc<4&=kLF z8@JR*H!rRnU~q!~s`KXuW$f`kP=8amx8#F2V?q1C@Foq+YXC*`pHdJY?e*WuzkXga zhZug|fTWy21ylWp_(vTC{F*85<Yez84>Vh23(zlg&}}1#`St**3+Nh8fsumfCn$Hw zuc5aZ;-3QE-ZZlRIZgA!d-s?~?kaPRsNb-_KW`HLUDMnWoeeHRx`10Q1x6n3pQK|- z{XJ3C-VT^0xro~Tp)3IvK`sZj1Brpn&3`R7B1Av*1)wisZ)N}KS0pn3AHVWzIG&F# z;70qy<>))VARr?5H*gz!<9|9J-L0BnjJW0J0Bi*~er^rWCI80#*ABsmwwaLybcoM@ zj`_L&?*9+af9VgFsQDthK!0HP$2@<c?7vF;&x*ZmxuHCp&PRZpUI6yzsl!dpZ;<v* zw#F{E%Qycd-nKS|hMKcffHsYJw@T?7eod4F*@2wErvIk7#4SQT!~<1o4>aSSwJa>~ zHukHDlcbZq>t9jne=R45@x+ICV2V>idKbCa{%fSPEuaDZO-ih=d@)5pN_?O~f0nZP z^}irhK*naEzdTUyHc%IsBuWJUi3uQo9;-w~euK0#19|-VmeK7ni8z2>gbhsVf7bt_ zqrZdwdmp-OLNB`OF=By^e+kS!$$)<Jy%YpUz5PA)UnZY-v%>!XV!!(}@NSOyyR~>X zFWL{H#r|)Izsiz!7kf9~%Ma|<hkwET%dKPG$+qx=*mC)6;(vne|2_A@T|w_g?f-!t z`t)D0|7=OO&-`w%&L2QB7>Hl?$A5<Iyes700GU6SkPm*%{7tybyWqR=g?@ku(f$?u zn+J7U0e9W_e=y<kf6e@*Q~zC2@4Br2z`7Fr8vC;Y`(55$SKS}HQQ}|oe(kt>mwVR@ z=?7Pu>fgA(snOeU<E|UP4<rHoZ;=0R3b-rgUCX*3OhS%dGw;~h-38t?-1-4T2A0}> zH4gpKjO*{%+tze<`}POc2v|1yCHAMy+#kGuE}Gu%+5A~<mlRt?A%3iWe&50Q{fg_4 zA?Nnuoqt{o$aZH(=l8H5bD>)ph1fqNxeNPwhvz%^*LytQZ?Yi3?*9k=YscqD75;kp m{0HAz^8Y3HE&s=2x{@q3FgLn)PXhRRj|I%frGUZx-v0spdicZu diff --git a/graphics/AtlantisJava/lib/test/fest-reflect-1.2.jar b/graphics/AtlantisJava/lib/test/fest-reflect-1.2.jar deleted file mode 100644 index d33ddb65349ebd5b6ee159a2cf7d569bf7f5d4ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37208 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%0DX)y0o)U;4(#N*Jt_MWgdCi`%FGOoUVC* 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 DWLVZo diff --git a/graphics/AtlantisJava/lib/test/fest-util-1.1.2.jar b/graphics/AtlantisJava/lib/test/fest-util-1.1.2.jar deleted file mode 100644 index c5f608bfabb4b04653c0c6384e9a4ad28aba2d08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18962 zcmb8X1yo$g_B~8+2<}dBcXxMpcXxLQ5L|=1ySoN=cXyZI5F|k0BX4G2X2`tXxBi#a zeS0mcc2{*(ox9Jjb4peM2pAIJ=S9<z&-tGZf4)Jy-lc>T`KZLCg=u8}ECvoh{aWlL zjkQ|;_1_+^FQmU0lj4&W6BbfXq?QuCmKq(Al%S%Xf|j5nA0M5lm8YF$*xa+H6dxa? zl%V1V2iwh4jzgj7By?>~3zJ8bkXLX_Cof0BdXEsxAdl>cI3j=j`X6xy2k{Tvyi#!9 zp%p6P%!9TJT%TMCvY=Zv0sd+e008-$rUSpW$;RH~zpehg#Lv$CEMaWq;P|&<6mNiF z{$9+<(aiF{Wx@aRrO7d4(f44lza2aP0RC@f`RwiW+=OlHt@IonjqIrnEcF~5@|8n$ zuw0N|U{20XsC(*p<>g~^5oSP8OlOcR`AvcR6GUOO00E^Oee}@TM=5J-2?^WErp(J5 z%lWP5T(hJU<>RF=Qu|#6HIBV>E+05%?~F-2jFf+P?lQD)wBLE3KYDbyjI};YBvJ!4 z0lk3dAVz^s1q~#%#t!XBuJ?t`@U>!|>s<lI-i5k;2)^4A<5{QKF8(ll`3@czDu*8W z5--7XF)HffVT#@p3im)q=J8SzF0+#)Sxx`426y7>p%@^e=h}0+Q0NfqG8uq7>_DhD znGLb?Ac-#dyC;B-ZomG1*t;^?+Ro8Lz<YWIk|Z}gpW4wh!+lKv9ld=#<970G3w-4t ztmgw^Cld>w4m(-=?uqA<@{%-l?W2bzB&q4Xqr@f(X`*bhxf<Ha@|xNzYkyv0Qj4k= zp;DML_yQ7lhvD8G<7A;a9}^0olUP!!+~_lHJ42g%i=jYRj-}|dr)zJ`PZzWcA*Dxa zAU_{yq+qlT?_P$^gr_@`rPse)81FxqQKwk$RcSUH_9KvuL?c0eI=kI06~2lqZD%Gs zM9pY=d2M&UKzH}?`~>+!2?VA#Z#w2Y+M29X9-B$#fO>dr<s91=4<@$g4^>Xz6LY-A z`^?|7xG=fQJb(Shb+y@M?_Q4X;?Ouc4@2%gnv$&nElWupGcyxPmi1iVaYv|RH4Kx) zm`{3%M?i%#iS7K3#ymrLF*%qV2~oVX$aFX@M*$RAi8sD1Ig~SAYzm2lb0hd^7OSvv zue3!|b88Ve$6PY8JWp&Z>>2mDW#^j6d}fNrvc#bzpPEz}a5(J?^pcr2Dh{qgc~Q(I zoyLlW;EIKXN2sZXrBz)pv$+LWs41A`=`;TFkA{Yh;D(L)TjZ%*2yo$uJhtL*rJ4;) z-_sZRg%QpMeEdlR39<C(1A7o~46h(7g72A+E5z?%Dn#$8D?;xx{LgnVc5soa+C}Hl zZoy{ZmsZzkNQ_B8A{a`F-s5TK&(FlB5N|O(iS`~Nc#jTr1ZKiH=E?QS5IsThm<-Vn zJ|PIqO6*u!S&0xmK?>k|Q*E)JMPFz%u=}&YckIl;U3zFA2tD~O_y_Y`r666BXh((J zGgOA*S6sV`cP5-*gEC5m3@vLjB<!Xvx#-J>Xq03tC?F|g--svrjIBkO=g6^?39H%E zr8Z9`S%+^Fb@}^uY*u20cZA$?=y*hibQxxd`H960*%60H4(12GFw%kC8-yB7U=N!$ z4H?-hp#-0Nmjco53+&fion*k4D<Gz)icOSJNS;5;IF-f)8T{6tWuIQIIFNAx;F7a3 z9A2<oWnuNO>#8|rR#g{hqr71mo$k5k*5gw_Bm*xlu$XUEE9~@rO0txUc>Q~x9@)!} z`dIXZ@|T%MGLNc{)00$cb4Qe!#iQt0TVGFZae5|^l0!!r7~NfQPv!PwYx>2;#5Te$ zhhv@RDeNgxm(J5DMNFV(hJkP=sfd(ynN4k_?MEM&K5cwq>svD+JXJ}H(#$kmv$F14 zW-4~FZpLc&&7j%^wl1VemVR(Vta|r2DRb=A8=n=(-Q5WkLil*3!ch)bzP^v-e|?+4 zf_Ssk9f3wjp3kxg0OR)pvsGolDf~skbZvGuhJT2@wVV8fT#MgFC2Gt~g`o(Ul&A%S z&$5qd(KxqKg1~T+WsAy{Vk_~Y({cQ$(XGa&8Pw*eIf3bZ{zJydCa9HFQmgfFSJ|Mh zvLS7hA?;3G4GVO*^9O!ciK2qOj=)ZO!3jvtd{2I}afouH0Om*k{yM9Df6xP9nt1~> zg1Sd5>D}oVISzS)<UuYGdz$ieDiyfA1KtskI42v;KpMhwZT|13N~gjTvyza=UpU92 z-6x0?BMW5X`JLKKptCJSStj#+u`hO{AI#T7)K`VNPP1fgrB|lXj|}J|o!KKF$gX!> zePoBH!gE=LQJ2N%Z3Z|t@yOcvgJVj&$+m@RI3>Dh!u-wWWjXBI>-X@#iqj$#W9am> zL??`3XH3J`q&JQ`fDW;rBlty6y00(EAFNf6ENGtBzBd%eTX%temK}q9x@mvkWCVRf zK(T0WERjg|?v{o|qe9oiqU{`?IZhX1FM6`vOpobQbbxYNe2euIS^4?KFz+krmo9Cl z&ngEDZXCi>V9qnhEwX`JanT-!F?ZX_Cw<1>WZS;UcRrX7aOeDptA8Y=1WL*&#q`&e z-^3}HOfM+;=*NG@xWp+D?-uy=5TvAl?@O{^4Q>x1$h^p0o9O(&Nmb^U|Bo_k%dY1> zJnHI?WJ$z4EIVYqgWa*k$#vF&jwR`bY7ZYTgipZ<93fRUZY&q_Il4c7xWZ?y(3?RZ zPc5!uo{8n(As5^D9B-XX5>QULmJr__oq^O)`>mmjQBnp{iqdLa{JR)l_w;;OT|@@b zvYNYxvO5?T*@^B^y4sPnyL?j^d7HuP9X-2<gn&(Gq`P`f?)v1~)ceKw?lTp7G0WUp zUq8e=W=OfL9;8ug$OE{!Q%aCCI>;jiq*({WdX-}9T4;B!Sf69*wV(_3x>isriD_tY zTsG-X>!;yZG)%@S4Qta5cI+m@h6g!`tJ78t55o4oOA6o&8c4)vougkm9Z|avh4duB zh_?V8Wbne(koxU)W2kBGP`W9R0@Q4EBfoT>Q2Dc|A?^DE)gA)QD1cv!$|c3ZjFO=y zt@9@hgmrTocJSaf-0@u5{6$v&;0?q@7E9mW0RXH30RUk9J8y9KgD-f=OWDlu!g-}G zR>z{LFUyM`sgNQqh^pH1`UytE<)GrT5|#jSS@~f$*q;n*s|?F*(p-Qw*_!g@Ac%6= zZ;Id<V<+YnD`{k0wkNyUI6J>Q{cr=_q&uM(Z_@A$9D{^fWw6zu8ni)o?UY@I&3%_R z9fmfqt~cv)*QVMMg4F(qA9`<lz^QFQEBIt?OBw_fcB_5tgKM{Nz_;PG!gb+Z)BYoa z&ja220?k+*|6-l+Qw6G%>jH^k1@diE#|T08JbIA>Q5S7yk1#%}L}1W?(Xw`-z@@#$ zHz4ZR;H){}gYQO>1?BWgI?mQT%{BQ1XC&IARd&b+MFG>Mo=_UjFh7826QaQ%oS1?* zhXTR<E$NX?PqmgapGdbIUlJz>3LI;vu510oIV5v38VP1KOLD_S#Jl`LY66H>8*ITS zpeR(ZseAY{P<l=r8;hm_=nt*wC@CNwW`>kyh2Ei*Yb*FiXWDu9IF57oOt$k<coP)` zTNp~1H3c3Umdla1)$ZD8^6n2#%&2q%a!)-N6Hkr;Lylh}9rQqq1ELhNBGd1;3Q5h_ zlIE~x!sXbH+USnMB1O)m(Ou6#7{|J+N$)T&l&z1sPp2y&$rOZUN+BJq_Nj~4Ja@Rp z*32pV06ASF`*yBNa^y3BBw@%Rzr4)zYp(p{qm7>$;f7!53ef9Z!TD{j2w2)U80qO- z8vQw6oa9EVXJp~Hc0`~e&8G9rmZy2&=L4&B16FTONr525fV`It=pCjjSRGy*bcVz2 z4BXJ2aZ=_)S;N1i^8~c5z)S%tCi2)HPi8ZTJfGOuh<dl$-S8eWF{LRS8Z4C>qiK7y z<P()IcA;A`_(M<PmfkmRNJX5JBY8&gSPzz4ka_LrQ0Q`5qoLT#6*+m%g`_OReY?0b zk$~v~GdX=e7Z^mhoSdx9X-@1Mvl#gJ0YCvdyPc1^WU585g{OXdTj(Q@UF#4D!b^M? z7XoRmrHUDHId(cmCCkW3J<BRL!qFa7qhX&mo#d6fn&gkdD|dq*DREKlu0+kI=Al}O zkvS=|4>nW4z)BstMCN)z1C_^P;Oa~iWJH3*G$Bx4YWpeb+{_;6E<@}OKCn(GKzstH zz355b0oy;*{lU<}@oB}ST<Mr%H<wK0qqo$eZs*>D5ioOAq!eTF+SUcW4lJrJyhab8 zdS1hnNNO-&F%J8vB$Xev+!+7H42U+Z`FO(%(0uO;sDLdnMcOQ-)K#*=DGag?m2#t6 zhjf8nTMzxEGWKH{o<dv1dQyjV2?DM8=xvAW-mG*k^#fCc%j;;Nq6eTjEo}bH)A%_H ziUCZwn_fqs>2)R${yqzAEG>-;9L;R3h0QGg>uXp=O+fnb!u5C1&D6nYwKzAxs4XDT z_>yD`wEGN^Q-t|daA^kNWCevPLx-B{CVhNrPj2R^U;*G5m0Tn)04CVsuSwZtm5bIy zXpGlv3K9oT5Z8`h|C)<^DeMk>+<Q$QZ8ZkI@{-g6<1NY)*~YsSiF+OtEjql)mGQpM zwaX?<H?yQcT5T{uz20>s=*LuQ<Oj-9b{B^E!E=J{1&eDNqffk(ljukO@QzARO8H%~ z+=j%&UUeD&od1?betZZZ002|(0RV9SkDmXz0OFNblo3_Xo{0&Q;Xr+T)H&l(>hT~1 zkzkeblpy;svXOz|qhW>sKJ`FJ6DzxOYkz}30g6l2p2VDOQKng`Z)s7+&4Qg&IaFG) znb-|RtW%??y?cH+=ka`bzRUQ2nwjYhIvHhSs2Qe@g(xTLs?zTv2W-a`3Y28ojbzQJ zhrzIIR|`?wM1<qOZ^se(scGHcZPm^Wo^sHYCzM%l6_m-ZkF;hmB!C!40-iF=PAHJt zK#6~H@;cJr;IetN#9c=Uv!ppKLsfIGW;_5#M$y)hARX@naH~gII(9N<O3JFWs-b8} z;cE_`7^Q)cl7V`?Q#CatK}vSHSwU>#<k^l+ce{FN#7&Hmt+jdRL%*2Ul481_l-$ea z>~|9{s6G&TlY&oi&{N(r6;;-UYI9RpxefKi*)-Y#SPf90xE)8z>|}`&J~Xd-%EKOt z5IHI)YuPbsI8kb#8G+QZ<K)Jt3F1){iAmkZQ_U<U(V{nWQFZa@@DTZ7*WVIdx~8k2 zZjW>T5(U*{;Hqi3FcUh?mu^yheexpo4-#<lQy`P<`P5R(Az+Aop1l9eLE*0bx$$K0 zTTFtB^YY#ieQO>jWs83`JKJ16juZ3`49=6H+nRpFsT)oMoRkAz@xCvQ9nPOX-0(VX z+__r~mn_K937yZKSQ5ns=EsbtYS>@G_NdC_wW$w<$M?Q$6t1+5ovs-<{Kyd^DfdgC z6AkiOSFbPi0vuh***=Z2D#i564F3WNg{5qZ!#QMyJeZWCqj&wj4+O--RynY^v%4kS z1JZIAnU!>~sd5vDQ??2Z$K-S3WwsxlXKxQDi;TNd62(1QCatdKH$xSoB^>lj@_VSv z_noMa?Y%1B;=Uq`RH_ZNluHbAe90y(ktHTC+h;gC)w~<M%yYaqbG`Z62fZzYbbi@U zpg$q*Hmx%I)O6cvCxZ`bJn4vveTmbdQPsTvpto3N#9l(pdKU56DtB1LH?~KJwba%} z)T^^uK%K7U<fX;nupNo+-LOXf<4YrRL7{O$wg<?F9s$nX$YPY!xq}Y}kO<ZY;%S+| zcivf7O7UZlUDTd;?e~2&;Wl>QLGYdM6&1O@xNy9bmlXWd^9rK1Ap_u?{5>f7(5}f7 zq}82v>g|El<46;Lm77YDYfLe@SW%a_AKIhuUFpU*umrFQGx1p;!Ly-q{c-W*R>>hN zh%$KhJ&Nui@DXrwqGE+14n7r+Zz2i;A=MN1)sgumk9~ZRRNDVYNYNZx)F~!t8;VN> zbl7WV&+~~dtq*)$FI>bsl%mVP2mQuj{u3}yMoW`4z7WqSLfhdE+7_xZ2FYLrB5DX1 zABtaPr$+(_+x11^@Vzg+w~uQjMqx7Qd9pqeaWEXRh0GIRKreEaDvUM$;)Ou6_+mh~ zVti{`lCn$0u4eOY<@E$+1O_~z78HUwC;xR6b=J0X*|1gcP19g?w8{!*AC!$f(ia>t z`Zlh2mZze}B^DhMJ)2T2RCJi#L|?yHI35hQjLf<f!!Rss5FQ9UhP4Y}qqb5T4x&IL z=dD0);9*%9CDv6-=r72ZJFJ*yinWZ<Wqg(Lj1ny~K(s$MI9cm&PmYmuC~?Xdv^v=k z@6%ouCc)ghqYnX2#c1NApE2!+YCI-RbxAm7A81)K&bgjl-?Ho?B4_3tQx8*yhpv%b z4Kc>al4Fh#JjQDss{t(;q(O2S5YQrv{TNhRdPaGT`%iP)*%i7I`6_=&z6y8fznRn5 z$H!kxB3&iqBhntaH}TTik|i-50-!$uWiT8wUbFydi2jT%61WHiKTuoX7$N%NN$--{ z2QEPnt5dCda#bsda#I=J03pcgy1CFcjq>^B$M$FchKa{9W0q9Pfv6|%<nQ|)8|QAB zcWLQiFJ5PyJ^}ZQkt+m~w!G9XhfN9tTJTuC*|cW~k6iG;f{T8z$M>SZdrc~gJQ!UA z7nk;)fSGXvGDBZy?7xQ>trzY*)8Yi{;={zrJ*n}z(}oA(yP^dVu=<G@-ZX>b^cm=R zYL9#JQR^U8<?4Bg;ou|&(F9%kM;cr`<#F=l?@(M_%+a<J7wN$6VCo;FvPX*80+Kj! zVs|mPGKVYVd}I#~U!54-V`Fn;_WN))cS!}k$K~9;Y<jCvTrUQ_u;6mSe3vo?!LYQl zderP()95td`H|*yDP$jpW3S#EypCfnA@CC0d3rhNY{RHoV@wO;Owozej-h(Y(aLSy z`s-Q)1+gF}XomhmXyF=C-!cqzzT!OXxJq66{@kueevR}O7BhFVMDvl#z&$AgCuKMj zWiLE?y7O*?*gSko)yL+6o*c;zsfBcb4wuLR)XjI0b@dqHmej)vb_+Ncin>gSk@a$P z2ub9zkU%V~v{<cdDhCS@Dp$t{2mKz(FFrddXPf3EQ&x1};%}}8TuH<+N<@yVncKLb z5rb~t*QzJi-CB(ul^&wodpk9(t3rWbs2#Jjc%3f2dcc9n!hI>L`^!?Lw*%$xCY)os z-FYwHe<N+8e>aX%jPA>MCFry&NsL{&RxdfR%qnSU1drcW#Aa>d5EXy*lvLUp2@DI* zv{yAWuZctRaX<8PS5tCA`%w#d;DWJ$2}t3nwtDfQSe}BH)zI0kKY?=THBsYQJ=cg; zdPjuynZmK=)ImOm`85f1ew%Ndh;hPF<#;^1napxl5nzOaV3YDRrnFwsinuC{nk1Ui zy<h%~>=rSHnFj^9CXL3s$_Z(){jes9d(pyJ=bePii{ND|1XYw%QAeOhyYWspsA}%( zEzML>)i&dtu~VtLSOaQLD1L3TnTj>#)tSpyUz;636RTNiAvG&GhT&+D=p7hgY?kFy z)#vsUIMDV_=NP7aE9e)VB8|-zY>U~uk94M+9<F=?VW90%iH@3#7xdn`n?Z|un<Dqs zzL|sh@3AUpXcDcV8EmA67em~o>jtEqMI5kSr5|6G3xzuLdvxusa1?f_hMC<P*hwJl zN{o9V>O<GD&f_NCO%+#xflBDskPX^*QtRF|Ua;#HSsK(Gedmmn^hf6Q@5)_25p-8g zNKWad0N*ZY>&zb4=8%nt7dh7X;(WunZ`<8uXCPnmQv0#hggg$$R}KBdCtDK67&v%m zS~N01P*LF5y-#|1D&F}r7`=fI&-oNGmsE;!gv?g5GXeVS*Ae--`1#W4Bg2Ku(<kH= z!_CY^?aw~iBVop++_)G(FWsMg>pm_?TnQlzv(qqhE`jbjoA1%anL{TCO5yocN`-G) znTfDlp5=qtZ4JWqr5mmqqE3`<EYY=GgyE7&R0Y<ik<3ouUTdeT4obyyDLHY}i;D*W z<rWoVFMS>Dcpe--IkT1^yiyPyTE@P$Ud0XIWXj;PS&6qtFq^p2vC(7SOLn$*lod%L zC!*I9Qv)inps&%l(CrkrcSt)wQZA(WqE{wGOx4JxS0KObAThOwA~l%CUo`KxHO-c! zUrOJx+p**XN~z+<aA5AE+MdyKXd+=%x@Kclg$R+HP!{DBU_2|<|FJSzR3p`$koY*1 znEA6TU**tVovbE2jpqR9<6Y5)m(XznUZmDDbYuO5)2-M>5q>6p2~nVioVj{i52IuS zuAF(#m41*z8+p*qbC}KUR+=Vuh2i~*lr&>1&%Wmbzq2?>Qs2fJ-=GfBFzbX3KZN!E z3>X}Lv1d?Pz&tWXL=1F9p{zTwlL`DGWQIUhDPsa(Q7wgRzKby&cSKEgzZtq<<h3k> z@`ZZeIbv2w)fjNcJLspP<^T>kTr?Y@RQgsp8v%}vcf+z#@v40@rO5plg1aC)h|^zP zOTr(AYDv%8p$!C1kjR;-2X$BVfH9+JOd)1L$7!GwsG;Zl&HY5G3z%gQ)n{`SzV3RV z#TH@<D;ShhBTeXfLNwqCqz{s7bVt;0F(k=$N8t)km6CEHO-KHqnIT<|Be&5v1iFG? z5JWa)4EZwl%>@02s?4*-U|Wy}L=7s<hERjX{rB1g?ZDz@sN=)bNOec~j!)IaJ;Iio zA3uw!MoDP~^ztAB6~*Hw(%P}?V22BUNa{O(mLu5{mTq7|t<^Ad!fa5$7h9E-inwDJ z(+8cC+<8b6H|SH7JSiz*ix3m2_U!L39<|&q+%=Xg?9-@G9+r!6Ay+oKY8lU&*dhCl z`SEpUDoI``wQE)(iP$#9?>*TLhpVYcq&(_c{2FLSAbnCs7gTW$dvVT9&zHH?&>?A1 zhU+K%;het3yWJ)!erSWWf~GbO6JzWh3gd!D(9kVmk)8GalO{GzFJS7A*oJnvM*f7t z<vmtYQ(40n_%^kwVIpuLN@L@jEqK<Waxx1eGjxK?y%-EhEVH(0vbCykVYDn3-pn)L ztI`5sw8$>9?x=e%3OgTAcHk0rGBkH6jTJWr=t<@JnkXb};kPBD>SXWg<;pt%=e~m| zp66yiiru^u$IW}9Wx~O)4-&f>BrTaIDiYqklTR?Gs27rmVlqYV4YUurq&TDlVH;8z z0vsxdqQD)*0m@@SddKb#k+o)c1avwC$kqK2eN^91lU4#+jG630nI7S9&FM#mN2LCt zZ$zSsZwN!@!oz}Z$BYrWIG%B-DEl55tcNbLm!$bF4j=h?Y)`a&$epBgjXW3;eG>T2 z5bD-}^<J<M3f28Y2v{0;JUjVQvZVE<eRhYYqkh~?>`7N4TTEsbBWEgwtA1yfkGMQf z>elilI;wY=qJHrG1nTA&Q8G`Og`#w|C-vg#l0M2A1yy^`HVhe-e!@U;OWWHqsw8<D zy94|MnggitowS&FIG`u!6s8MSnW6U;0iSG+^x`fXEFU30LW1sUPfgiA?@uE$6yORu z^@Iyu;S6n31&Oo0yzEdMtd<&-19WWOAgg=ELuv2CxnfJ)OI2gpkP=InT5-SJRSyH5 zL>HScTO|1onJ*{m5>E`)q0*=;vVe1UB-Vtdx}j!%a{TDF-lWrQ6B%p*cYffZzKg54 z02`eG#SkIo3dbX|^z!bXB#x{yJ6-=(3D5!jw|&R|kT@Y%10&m?iol;bqMVdW_p6TB zqXO;s0h}Bmm*t(o4tfs=Qx_bp-zuu6o|KuCOX)L}3?a_byJym!I=H9sR7c|jr~S6X z^v1hH6@Y=Fg6K|Vv<50g$`iON^#^fQpd*XD=7n?xKrOf$tBE<`CgTrjyu@@of}-i9 zD#<9>j+1SOu-(r791R}*DrZe<m~aSI=fVi~T6@DIy6kb@I#AfckXkmq{C;~)+CC5r zaw%0SH&4}G6!q0Wxmb^yZ1S005xZ@ADpGz-@#<lAg4YrWvM)WOsChh>Z3D8j_DNVF zybKCQ6EOTO2O!U)fjHoO=gN`Y(NNQ>&;rr2KPFhSugL6>n}ntIu1L-a##1*{gh0gd zST!{Js=9Fl5U?1+>zX3%q~|ahCLLyD_mUzfxiZ!UFgAv-sdqm|HN<zbLyp4RBcp0! z&xboSe2wTq*XJ2B=TwXuyxq5wpts;dS!b3FrA){@8iW1k2z7`VR*d~m)lS&b$-(sR zs$KNhPt`79Vo_QXYbH-@rY_$XMLe|y0VNojXYB(yo>~=vl4x1lW?dt_vk^xym~M|n z)e$>|_fOr9mh%tY&WzCHEZt^54gK-p{M-cKOn-zAWWl1z*9j97rliSiCm}+L&j>B* zih!^1j+hl@BdA^chgUk}qun>#172M&u?=BA_pF%1?}u7E!`f!Vrl3b3!eP55j~)rh z1o$ih5uCaybGNoBai>|uMfZ|BWjR@UKGLF&CMJg2cgdf}=mk`Hjc?PkearMl6C?=` zM^snDEfz%f0IXFxQ^F!MuLL!7K7`F}y$}fqEp%toNJ~5-#T0xLPn|D3jC8iG4sM88 zp|&iuJw~sfPGC}RALXA+a&9}s75T(pb+KW-xOrE~|03y`vxWt%;yR-D89<9>k;}vK z%xQr;w|=GVu2a3bou50!{^4LD2?P}DnIpWDeV$Zx=ZHHM^}eYIGRzYBx=5kL4+et} zw0zn0%FrCKPP88KE(7W!Mb3h`6}PH?odwNLLA9$%u~=>*&6VW{z>@w;-xG7Z`yQ0U z?hU>3qCmbq1{a;qT5q4pY}vL~_DCQ59Q{!|{h8Z4m8O1DO*s{(7r=i`grbV1`nFf; zcH}io0PQz_OG?l7Pu(g)$wJ{(xAK-2tw}Y6Uj-0vLn7}RLkM>ff+GhPhn{2>FR4$2 z#_FD~O0{N|Mjyb<;o)t+f7f9<g+3s|z7u8sm?0IuWT=svoEGb~e&99k!LbDUvCSQ5 z6H6Q-+<>2Q0Wqmp5pZKOFx(7+!A{Ulp}%bL0N7ii`xF=<DQXA29r*&g+7P7SgMl0; z<<Px!|DD~Fk0zFgokF)3#2p%8E&UfY=SDQeSEj^CPp`B<X@nAf<@)uVfNQ_@9+Z~a z%y!t^7@*4;MgRhy`Mfrr_(-5Z=mGm;wOJg<Qf1HN0f|jK4?E$HSqQC6LU&3N6sn$b z_TIx8KvMjg!<17?4C<cZh9-*%q8@T%`w9bfp=rZB<m7tIAbO>JsxS@)qFnhc<Us9? zm(K$T)WiZZu~zGQkz31=w8&@=E0M_+Dfvp&CqMXNZcZYBMWtO6W_+7LjU0-Z4v44a z^*&WLad)r_+O6a`ybG+(%6%y`b?mN_bctE6%ug^gTy?6&CpY2f8^x$>f}Vnm-eLRl zwd{gTp^k^RlYw8pyT;FZ7x^jp5dnwv9s-u=scaK<7o9&UQ+De)e;tx~i+=A`wX5=8 z%J<z@Y5J^pkjk>MwEhl$&EzN*x>A!%h#*2`Gh#>YAmtI+pgtRj`xWZ~bttSYU+W!O zmxBouo*Pz@Ggi=}!tb)e!&np-=p!<oIb5;UsAWRg0m*j>6gA{JW-dew<G;ib<_I^B zmMaCym3#Rw7k-_&2&9_m5P5&*9R0=RUOCLN)3a_EXTkV+gfjN5My_O9b+AIKwgGf1 z=|%e^jX7&Q!Ij9IvzXpJL-iaU)HKh&T(ArpT}lTHTsNJ&I$#9wsn`!}q#pp`TV#0` z%-z^D;AgMePcF`$MOv0p@su5c&NTO?0I1nZXggk7jzHjG4~IXI7>VS4!ZQwhgTR14 z8q8$ZXKXg!q%HIubHf9soV&XZRC!8nsMVaw+fX*qs*=aKV6tepQ_W!l-yQF6v>f-i z>c04TD}I$M4I1)7{VJ_41(|)?afeZyR%q)BmG6i`-sUZhKp*}dEx*(WB#}<!7_ed+ zuU~fu17|8sEU#PvP=!`#6^Tra{06YdG1)O(79ucOAjOeiTMjf>X(!X{0u1vB>e3>B zJ*=sz;Kq72mrKxNA@~`qX1NyH%n-MYgDO4givMe=+_7)4&H)+x{A?_>jtup5;xo^n z{U`-r`6av;tQQSecOg(gsycQyXNCJMolP5P#4YPmuf(Gx<Lw*UZ}&M4RPc4lXM+L& zVE(q`W%SKorTV{Cy`qEyA|Ko{F)T9#rtbxUP#5aw2!u{Bae#o&00_ZG@>t(^p_}~k zyQ$Bt%eJlK_hdG|2D}Gr%`%F|svpMPk&*Ra4kNa#<1{QNEPOmZKRz03#Lbij2*=0e zW9Y|kir_#v6Sjrj>2}begzdHCrzEpWi=!pdOUX9UE2yeU7@shj&*0S39H*@k3N&4w zq)I)$C8tqQ<jKCH^KU9P)>d{+*0UvT9MicpOg_#x^!CzNt5VRGc|sTXVAU#HEGa!R z7e74SVvh3NJ(;sQt-5QZbal3O$>||n&TfYffyDqSX52-QqJs>avob_HvDqkpyS~ED z%G^B!A-Nx}?#@{$>~ou#<B<=29gF07Nud}k^_(>9d>*|N#Fn4(bh8#6neb%|5?@3J zvyGjFgd>GT67WV=kDWWZG29Ha^-@@Bt@+ZVgz^+z8Cw6#4`S;mj2mWM4gf3Yl$pIP z9m)d#(Qk%!-C;~WaIs3j?bOjzh?%r%&7gh=Tq^MyO5`RUj-wlsH5aQpzq*4)sG^f0 zNa3N)*~UzlfHlXsC?JNMy#x>p^v2P~rd%t!5DxV8gTqM!e&Ir#3Dy2-;YMYHO(7by zSAj~$RVCcp<)P=D4<igyi!QSUV@bptxwc}p^c-JqahMvc8O`Z6#_Pgj#7o-v8N`bO zE`?(e+0(HKqZkSChHYb4j^(8@>y>JaDJ7uD$L!}Boq-!%RD16zj3e~2qNOXtp8b0} z-giy{q022#ObrF00K*GYEDs_Q$V7T_FLT6I1{1gQLt=f{<WWQz&<&Cn<|v0J*=N^V z<popIn!|F80U7v89JWO@uE3S~=?U~*Fi)BP6@0sw|5N4`kG!<$*!M#B_*j=<BKP?9 zY6D=%O0Sd6gS%e%fX8${I&sjz5cil9_+GKkq^mM_IVT`7grtPF@NLqbu&>rn?l3o2 z(&MHg^Ohnqyp-?}L#${Rr%<a`FrFrubO4;a<m0iGJ+*@L5V>kx-1~ApDBVe=!L@ZK zL{Skx*_24UQv%A-N%+Uyg5`F%?Kat&c5765Re`*!gfADQhDyyOhax(GBV0%Ju;jRK z-X8<6<)IHgFwq{3b_OFdJ-q+t^L87BNv`pgcs;*T<KMT76dd&oEEMha4E|C%z2vkc zF!_+U5MwQCtV`<6F?qhK;Kpz}4%Om|%7XhNr4Y$JFsc>WofxASoBYsP=BGk_0D8#n z<w&(c1ZshGIU8s`NE>->d-(yz`~F;$wMa#-J1|Vja;fTcvs@y*<r8+Gc;N!9wEL+- z;Fxup$g@f`8V?iw)nj1L2H==LG!}haR9?(}l3w-{7A?}sWwWm8S8*cuBUe(#&LDUv z<rcfa+;<Dp^KP}K)Q0?!nes-vs*bbql7v#yaiP#G^vaBDsWZ5ev?kRsMI>{<nu>Yi zP%3zK)+{L#7!@QhBa!BX>hF#G-c#MP^;qYA&-WOrY{Io;N>SsC=uNU!J|Ydj3S09| z`zo6z<}rK~J`5(Y)zz011X%*(%ypu-(erM8uru~7*ogeu&XtV+y69%Yn99@ABVIZ~ zBzkUHG>MFZjdV%}42`*rVmLG|Rt#xVZcm}_kgBZ%<V$v*4@RH;{OZ8_&~;#+d`mC3 z%=Wy-P~_H}RRk*|(wvvbZYN^aJu`XDKJ`e;y_j(t$|u3gSK*6^;OlM<a#`%o(8Igz z(?-{z=>v_pk6E@1g(hvS<E9&&|Be0pBb=fX($%x{b-Z(413$@rGq?(l_GZ>54upT+ z6>Y?A%>ML>A{3-#5ap1#D$|{p^~hC8RYA&;s&r)e1oK4!!66F10{XpUkzO%zV@)r< z&aQFT%CsE`q#}kCMp!l5?$_DckUg)11}=vPbGtrUXg<ieTffuEi~<PXsqh02?2)Cz z-%$rA1M$v7Hv9~YM`EDJ2i~(zzfa|czC%xpX1G%AFISJ=l8Mw<m#D725N__BzePn0 zY~qiXrWUxanCj{t!KY43k(OOc3iUi$9^X`767P5=7-p<Cv%o0f>O4Zmmg<)xlmc*D z;<kYV`l-bdZB>1eX=NV?hdM=>=_Pzcdfmx?-P{B=y#(KRnqte6K0I$()`A7PmP`E< z(68Mn&^F*WrytuoT1!9pC6@CXvaOq{<j7RKQMV<qC#x)}LTO*3J5}Ba9{ajP$#E+% z)Zx$&jnh|S-bs7z8(Znu`KB$(cIxXE0!f72mkbepxDfv~vle$Ey(H<JUc|uCW1Qu@ z@Ko{w+pu>~UN6~2+stQ0Ny2>nPy$y_G4zh<K3wEhm-JHmGHwG{7KL=*J*0ca)e;({ z$Va-h%jVKgJ7}a4>prh%mFCYKuNKjUXB^#2`@^ys&j_t4SWU3aJ1cAEAHe$-s?Bo1 zEPuZU{KmO)0U%-ccvxu&(@DP+b<t+C>p0^cxsI5{#}A<wHzlBK!+=Sr34p-?8*dG> z-L%;KB<95TaDBoe2(zUVB@PDeIppbcj_7v|7e4F}1YVB&;i=OBXY8RcFNv}0liftP z7~+htCg%lmwyQ3xZ&54k9$jDlFidxInMqsx;@LTFvzOxu_RJU@`X(Fvv>gN!q232* zM8u+8A5_xrZqOx}Ek@yFq8Jd(>{V~z&pm{ow#k7++XFjxp?5Q?Vxt6n`VZiCpr7In z3cYHkJixu6@eZLk*&&dgfqq%JpV7{k^&{a$uU78c>#QgL|C#ZMHhi|WM%IRZ2mulD ze;B-4wb~))xqD;{D<<>VB%iK>&<}nefFD0+)q5>l_8WG$P<%mr3B`?i07IG$&Eo0A zC2Fe;EHd-w9<}WlXS-WZE<AV?0iaN&%{Jf+VdYM}_k#e6C2rqN^(71R|F!@N+pJ=M zM$L3e@a1q>yG=F0_u}gY`gUnIqJ4xO<(-YYSrFgGg+-cP6(MK)8hg=ImcEKs#i8eb zv&#uDX$SVKk$^uG5DjpAWJCR)8|R|!DeZ2Y4(WHkwx$UIHA}IrhMVpa548G1vCI;W z`gsd9;aTG)8xWWcq!R2>sn)VkDndG|F5Yh5{%$B^book3o)W1uQ6LADnk19KXPGdl z>a=C~k}sIcocTRkc$l~+x2Sy{;*+_o?FWl7dUSVRX4mv8r_7RAy#ReOgrG$egh?P` z@iPaP33Y@<pKz-@w?LPb6b+`he9+bg{CV(t$sUFzIusSG!GkILhVh@HnGa<6i%KN% zK0=?OR5Ro~;$)roLGE#B^$oimexcNKjvFm{#!_f<&5b!KGNi>QHbo1gHOs?CvhwHt z_95ou-vpnZ<2`_W#VqtnDWP7y$lodDpO)><0alVwn2|+#woYYa1oZ_JiVK3|hlnEQ zmhBwwK~?3Y{G_1u>Y+(W(Tb(porm|xbVe{(FE({T)3dYh^at?t;bv!~_Ae&{zp9Z3 zm+21e9%o~BnYbMQO+MjJ@C$_D^SYA4P&)_}Bj9*_EG&kSy7Jv|;iLuMZDV1{AQ}y4 zw;TL9=)c+~a!5)f>9J<mS@mdY)DW|<I61`gCDTc*WsF-y=5j#Q3$@i6j;RL@eLx>C zFHAjqAGj~*F5po?be+<iK&c*a!=(>bP_C4oO>LF*;JI}aYE5HC;TF?7tt>r4W6{uc z*Z!GJ(+(h*&r`Wdll~9_5^+~nuc@jg`(PDPKt~X-eE2hw5TQvj+nCXz6el-UDU#x( z<(JfKy3UL^w>3f{f)oKzD#DQ&**?pF>>Ge}#je51ugrI=7lSzEgSm>WMwLXFhmon2 zO~UJ_9Bas6LTE7xNQy=(;#@i3Nw_fvFZB4H9p7iqHsz0pgku(L6`*y8v>TOlX|a&H zO3)%S52Kgr9(-E?JqPMbguPTm8r{Yb@M0<y)U5QYJuI0-=0eV+E6l>iM%YL0t>&$M z>8kPzYs%Z?JY#Ug_LZ{k7@YJ%l5RQ$YQgqx5Jb4?P5E*b&A2nAqDaR`1jtcVj9@z5 zP><@52x}?V;{EBR8Fa231@@$R@8jyZk-M+{H`fc9oJ68X6xy_`HMFtteb5_BLnqji zSAzt`e~%3zV46?2jqbQj7$H7|RyZl_5SN(>>xk-Cc>EztA$kJbsHfVNn4&1TOf<~P zR<S`Npd=yNIWF7zp=ja9H;lPTxJEe%bm3b(_&9ZFr(&oQ_(HqDeX4aQ?pe&5$Vtwe zvs`0L{FNX6rnf-5b?ht`M9A&<jPFlv;Bie+0!8|smF-{$aN3a;$18Dvc*s5nhRNmg zhF-PuNlNOX#cCfSb!8H`yO~DI9}2RZ3J5x5x=)7Dx;5hSQJnGkaZlS*djtn~i`%~k zLi-l`8nN2?`H*DRcn+3TTkBL`tzHfa?`Z7cC=C{1*3Rd_+(!i&pa<s~&%4XhCvT!v zbR7D;G|go=O-QpJS%zmjLS<?<8YzcIIovdO8kaKASn%WDtnGh7@X+@*lV7cE*{ikv zm(}Oy;Amv^r$c8YHzeId3+F{$2Z0wSf9pjP00eIWhv0{gN6rg;6FRLMTKZWrGHkPw z7mF9`9)KH?4n_}=Yq9ozER`kWKRPR>Djl7k9)bdBfz+t#VOJRlq63%X7^W(1)!^q! z94w{rwc(-hqw%FnGJ)#lZ`Pb77u|t7<Ye9b!~!}W_|L8qNVt&20<*8oNmTEw9lOvU zO8vRbbrzaAufM)q$csJ)VUmHwE))|sxkr`Sn?Il;%K4mRuYr$bo|;|Ss!pKqM5G@$ zWlo4WP81bCql|C6`bG8fIO$?P0XGjh0kb}T;x6D!ukf?eT42GPL)n1NCp6WX>TrY} zT`=^#$r`#~JWS>XOVvZ7E^K64ByaG@W2v)Jo?;m^0h>>yi0JiAiY`$3S1&Rr7nOAq zu?b+b;TG__PSHeCaYG7qA_>v;p(p6ck3IT#UI-@91csnLb`OSt_DLCFm$@L3mi*~S zd3^AN(7DWq5A(v8>PZZ7V??B4Bx3T<_1E;#2n?mdy-_EKX?!ljR|&#{1i#CCM_Mz0 z*t-Y&_5A!fqC_uLi4d=BF%$gXf+`hF?QLBCCeKDFtvIg;z5;P1<VvP8E);y8l;Gc$ zFp!4~VD&Gso+)4@n<Z}J<EtiVkXI8YVw2_e`FM!>Exx^pj#8ELda>^gz+~5ByG3<` zVVX_E<lM`6{IK$)_Ya^>1Q<onP$OirvZADJ69Lt}1N){DU8(T}q&%Zhr=#|4U9CPi zYw?M4Jj=}ntae#=Vc|aFhP<6ftaimq<g;PC(rrd-@<Fou6uz0ey8tCo6)X`|?TTIS zw$C@;o?_E-4}`{v!+v~fH-HRGN?4kK{gzj((Puc4@s-w?YoIE$_>ftE)C%=5eJflq zq+Hxhgtgf{VJbX*Va#fcZr7n_kTWnOV+mb4K0u}BJzJ_N+j@&ZqEU=N7F5Z~_86^v zRFP|7@+ew`$n%i(uF0d+x83N)_==OUG!{v@0)%{JvN^?emo~KhI-DEU@c_9)NgcF6 zAG!hB^~<wB60Ega>?<K>=-3QFUu&+%3epv@I6GPkB&xMiR>#a|T)}l}#}=&_=u(T= zNqkc-e=2N-c5K2{ebvCmVYu0+@|}37#4X8w=g=XoE%zJEa;~l6`tfCC5}JAFX73)W zg`8gbsxdp*J7msH*I*H>a|6CE7OahJx&fE_jIDI;JXXgO+EMPWBWVOtfCFHv`e+ss z+74Jhl4r**@u(fZPsmB_<8*CLwjhE+Y5>D}`nd-b*jQc5I`=MQqan^2(!67xmzS*M zU7T+P*DbnTTwr=aaxT~#_tmJDb>OL7SS**Br2uIy!)yhJL-dmt*kfnWzb$W(e4(lv zcF(RdP65tw5^Thip9%ur#^8bYNMK1znsKTUD_xwC#buede5&jveN3Z%))YK-NXbsv za%&?p5P{Q(&=YfJ9fHf1S)FI|9d>7oP^4(e&+;K?DM1@Wq(}W=aZnC(PMWj)keI65 ze?Aum7%OjE{)OY2PqxzjPQD@Fi+rWfYdFQ#C|nSWaKT|1qma(~@9*{CW>|sDvE3ig z`C5Eb%OIVDJB{(ZgLR>^0nYjmLNGwlyhWNoiF|nAi}f#vgupJTBXZ;3&&I%0>Ox`U zIF5bZv*aQ$zRZY1BN$=p4%_6^LWS$ZQga)jmqAf#U>=K^u}A?k9mnDydkV}3tL$Xi zVM^0oY*FnI3p@y(9-}1?-`bP4WLNAHMJ~)BcmnJRIg*9W?S1L%_&6Zeg|^oJ(X2Wn zfZxEcNrw<7%s-`fV76?*7NW6uF5hp&zk~NCCWSwbN(^JWy(GL+Ncj?FuZb6fwL-q2 zphPU?xcz&A%vTLU9iOYBt2DDiP8s;CLLB|pP>7Ot!y(TEy$zTA%XOlM8N6B5TEeku z4mgj1p+s-q$9N+hfJ(4Uf*4{2?aN&5?{9QIb@-;VfLBr$@=D5nkIYtdvo-pAG;V;> ziu{T)lGXs)2s0!cn5krnU>+e8^P*WQMN^$Wzl6T1#+STZsRrcS@Xz!ys}PwnG=ml# zGlAKoby3Mf5<J=GKZ1#m2Zj4lW5Ci!xHT-!>u=|$QeR%4-glZT%3TN{0J6lO4U7S+ zG$O4=?noo_G?nVog|J#j>O%CvdxjXXc@lYbNb7^#30H;MAeE7+q6R-aPC)tA<`+KD zxOYvT3hT{HbJ>V}kYmPdIAhVukh#e~rHIcrV(%+?j0e!en*pO!v0oM53fcM|P++4D za@1t4-oAC!cUYouU|~Qs!`zVKq101;s1%l<I8=Nz-*A><zrif+gb6Xry-2ByA_MHL z>SaFrl)u+*sQx`8LvFCpbh)5|l9tYAqG8rz;Tv$lhREp^SZ<!oNEE!j44{gy<O*4* zsuN|{sN?`~NMy62JNKnOfzxp;-v|BinBfpqX7KXINJ)nMW9y!ap6%Oy_~1r)y03sc zKlo;VbSR98x|VS6wtX<BP9Jnb5pomvsvQfFS~q4D{9)W($YP8NkLC@%3|XAT;}d-V z4`e9vL&KT~gKU)YY^68FNj^abnjg-Gu9%*oH+0;#8gs@*gV@Jw36usDo3`iHGtRea z6`IX4tz6cZWG_jL#B6Rrq#YktZMQtMBMEc`hCaGxW##E3YLMe>dm!^{ihvj)BR}Qo zYV;92jSk<C6WAX8m<ES3G9;1CIGL_FPjMzVoDAV(GH6UXUDp>e+6TSUEZHE>I{CVu zaJdS*&ArcJ43-*V@cAquvex92OyIPm8`g$~0T;2jt~*5ri4DU#`f)`q%l)<S;nZ1y zfv|hqdafWxZ1X_U)*Q$90cB>~3E((lYYstDFC0Qrw}@tDp;3fK7n>b$bu1U}u8MWw z=Y6#IFctbKxy$yDSw8Qz62!)-E~40KzAsNIjl++Nb;B4reEjgB5zIA=K8PQRMYsP6 zO@Zn)-3k=ARCyb<W!$*CcIfjgas_vnCC6DuFV4Q^cw2um0n~Y(KA7w?H^1irK*-oC zUJRhd`ye!US6@!ll1_a_Y_EvLk;WIJk6;Uxw)@D!I=tyJBCvEQUAc)iFUjY@3{q}B z8ie+#Lu-6EF3lQ-g{VOEEJ^$sf)(2sV%odU3Wk8wd!KdD9pZeXhBkB~@dW`()DM{u z-KqSw-Q4R%QM>1yp56DJzH|JO1zeHu`TM<k&qc2<qTjq|Witn}*Tjm~1YX70Ea6uP z=@0*k<Hlxz8x#~&094u;l-U{7*%=f@7_?&ZX*y?Dv2ip_Q5dwkYIJ)vFHN!WDd+R- zcFbt2V_R8oji4~-_op1kAB<U_z0JgoBe?_Vg+bqa=Kqn_+v@1`l2<mni;zX^FRQPu z?JcG+X6&8OPLNjIKiE0g3EVph_2KmnNSKVK`d`=Z_nd9m*G~L5XWL58*~psauO9zi z_@_GhrtoV@G_{eQgPY?Y9sWNm|CHJOe=7gXt)_aDG`-TA&#CViFs%5>r0HL`M`-_F zU~Fxys9mir(-nuTS7_n5NO+%pC)e`QFhuoeAw%)W<QGk&^G#*mQArtMAds1o(tOm3 ziNP9nUcmf*zfLK`u+6ek^TDD>&fEz*!VC*uws<^mxH9*k@XOTWA#pS7fl|53XAJ!# z$jaP&y1BS&`7%B^xe!MP#Ray<2cvOfMrS=vhZdn`6B}mC7PkYpL_1F7je}Yd3d%lF zaz_4qIIT29eIkW#_mYL(_ubD)QBR>;zEkd32pzqSVdx>29MsS>PN02_4L7}DTb4d< z%G$>TEfWZsVSb(I?-=K?#vi~Y5bC2V@tJO)%^`C82mNXRZpy|F3?&D?#nd__iG(1; zd|4SFxjLzTKGUJ^tV@Vzz_+uRJ`sg5E@mKv<`+ic*bZp8F96u3RJ@0qc0aD<;hha( zdI_z?+c%TaB215}2&>XLATo*EOpY(&L;v`!5f!P$PH(C!CpiFyQvHE~Ccue*k0Auq z!_LP^*5;(VJe0HEC|ahXq*G6(v<}&6?6D?#U;O}NQZbRL8??=>OFMF`+pXQ_W9VhU zGMM@7O8}%(I`+wA)Vt}HemW`-Z%_+TN01wl@;EJLlUA>cZFMOvGE<9c6AeC4iK(m& znmfE?%w_{CRAw&hQ<kpjT(m7iam{X+z;2;(7VtK2o`SOTNQqw1ef|)vVO@K>Akg96 z>mNN}64o>WWGXc%B-hRL?`P77^{vWzjczN+-))qgRcQsKohF*jk($A%98j*NN7~hK znmnE+PnK?-HHk=`-id|lwBD{x4Dm6&n@q3_YWwkH<yz*iRRaE>V-Q9XCyi}iXQut@ zi{<}yhT7WO*c#b8ni)ALILnMlP>EBDNy&+pC|*cWN{sF7$-{uzdm&OFLrEfshnGu^ zm4{Oz18VXkg+oC>yEYHYhlMg+Ut2=oK;4A9Hcy9LNxbJ&u)GeNzL7@^qmYmflc2wz zc56lm6Q`d+h?VfMH{+#Sn~oX9(x!eD#oqxU0sZgO9A10!dcgsl^8LL3clG|N_V1@V z{4D(Q%JU_8egAK@zn%5)3*l9beD$vWQ~b}jS10Sw>*p7LdHwvy$qc`m`nJYvaQfeB zto>Qz&yyN{Rr~42{Z;Vi{pVQ?e_TJm2>8`q|L*}0e;T2`>i+xL4S&_n^QHZ*?!TSn z@T=4Rp40gY&-ArN|7^>D@cvW`{*Ln>vEfa=-!GiF*9@qC;=IlNdyDlpYwQ<R3iNMS z|C&Sg7V&L1)-S}k*8zCby8j~nkFLJWMfe4_gZLKgZ<z^i+w?XX?iWlE_P@fsiH&=U z_cnIx7oPa*GxMK)d>hI27VB;J&o3+myti1tf`Q(myp1UMg(CdQTmIRif5aEO1$w(X z`U|Ls^exbDd!>H|`?+Y}ZoB;gYkb|4_-CvBk4?C@uy6M^e!&(~{ok<v-066W`&L8$ zg_}(CKXCtGe18Y}H#zVZ5GuoOKz|np-vYf=p?(1!F}?+Qt4Y1Zdh3k-!lGvT4eO0- z`WEXgFaCvf{%UgnIk5kOCI5o_op}CasefEQEp;8&-ySM|an`>~_3xE`vesXfw|=ku z+PpU$_J4!@WU;@%aJYYK$y>0$bK1XP!2$k_)&2#X=WF!;0{bV&{q^(xJ0tmp4)*#m n|L-&TkDu><H~J^~FMc8`0rE=00RXUG|7c%@(9u^Y0D%7w962Z= diff --git a/graphics/AtlantisJava/lib/test/jcip-annotations-1.0.jar b/graphics/AtlantisJava/lib/test/jcip-annotations-1.0.jar deleted file mode 100644 index 9ca41331f9d84cd668a8620850fdc5b1724a10b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2255 zcmWIWW@h1H0D<%f6EiRaN^ml;F!;KLIO=-(x#|Bq#lR2%RmuTY`sf$azBr)LEFcyE zVz^RYM?X(D*WeI6U$@V`XHNTg>*`(P_14uocjo-&AcHH$51tmCaTY4n@$fn45z5fT zsCxE`Pvy=z-9f_MLBS<+wH#mhe&u<@d!}SEkB_KHllNzl8so{`pSrcXy@QIoMQuJ$ z`f5_SvtlRQJ(x~s0lFtIwL~B0VoVjBP!(CpnFV;1i6SdY%*)F!Ni50C&nt#&frP~w zomf3?Mh1p0K&*mGi+gEeQA%oxQ>9*VPGWI!>jZ!QLk<E*?<Xwm>iY5gk)x_yM_i6g z^`(d@EJvoiI(j)s?W|d<_bpw{__NLO2l!KEY#7*u_^p3$`dppA>GR*uKUp7$9oL(s z#}_LjxXO6yG#`tdyWXj0E!z_^^M>@TnAt!20_4+D<qF-GA2ONeHMPI;kHP-P1ud5s zn1uQNh!wAz@@cQ(%+Rp(WeRiF9$lGwm^)N%^VBD&&(_*M<&>5_w_GP+>*cT2{Vh@V z`RB7MMa_<7j5h2P^8YRW#MHagMEnBpy|_bp_tob}Z;KOp`Eu6657YLmnuJem4m>nb zH6~}yrYOhR4l7RFoHTc`b3uS;sN>u9yKYR|t(xU7@tj%IO?G$pruM%_g%>wA$HSrt z5|~R8d)EB|2I4w=f$5o>TUwHsl#>bz%=2E%h62a-uUxx2H2do_$JKIGB_H2-ZfI?) zKedbNk!G*+$w|Im=Fu-!SAJlu(RjJ0{o3KC#*-<}em|9-@qYe!eTM56eFYK=r5|=& zsQdOb=JSOJwGy|=I5yLbHB(o%D$P+@%B}W1JXqr8J*(%<T*r1d6%@uBZVb(nTD?`^ zer4>lH%#?+1pHpl3^}`8#wA~Oif-zMR9o{6F_BA8OLE`wxqpoLP^Inc0)db?r*Hoq zkKL2nD`MakCwKW`^Nx9ze1*%-zB%8n6!*UQ!rcfvU!!Y{7go>R6d5$%A;TkQp%t%5 z{d=)(s^6DLd)^bQ{VsbXBbonq=ur!YbXL@`+j3KO?>}JJZ3Bj#2CjtYmtPW+QIwjP z5}cTZ6n=*tz~OiC*ZObI99P+X$@l;aKPSg*&&3M!w!Mrn&nfrbr1|Bl%@2lJjlxF< zwOC?i%)R-y?lbS1U!VUnA5gu;*vGVmNk({9a(D{o{j9?+-!A<8p_^<fyE=TI$JHP~ zzeR_tY@e&oeckymJ9}<;ob_zsbML*>OirD1`l{SwuBZ7d$JT#6$MUN_Yc@$%UzGMv z<&wO&_SvsC@6{Ds6B=KC{Jg^7Vs)DGw<a&ul=t!}PkQ{qnAk2pHjum1oqc^1|792b zI@2c)=g$?0lD^&Ud8$*rL`ywa?5eUrmQb{YKkwJ~yBl*)%Kqe4dEc?`H&c?y#`eFT zj#?aeD2^J2s_hRd{s6;n127C#afKmf0Q!0Z6JXo@E7vmqW&ji5Do6s%Xl;^Dm1g}o zWm)psNol9^wq4l&?4bMwdDU}O1-3d89%{z#jo%;0*=J|R81pb<k@Cf<7D5^Rmz0c4 zvSm3-u2j2KnO)2;nfYR>m_;YI{F|nExp~X`^7i;Q^O=3!dEjU4Nf*E0l}qYdGbYSR za<sefChEbKd4X25gA?{{y|nJZN%60DE(B&Sz2=>?V`bbi=f=%dX3Gv}{GajWe{)Z8 z`q^2IlJ>SMF52$?X49%+SoU+dV*jdEjuP$j$1|PO3WDFx$nvgbY-GEyJ7sy}v-7tP znH`r4S3NF!tvp_lBlk_>{xclx7Jt|RycwB9m~mGkz%T>?0fx7ZAR1mzK&lj&R_v7u zNCOBgY19UiaIHvH3_i<2)c^#5EZ+@eLMjEAo!F}dgpRvV9neYww>D5U0RbS3Sbzx! zWD!^!YNY`)0(-RqGh|7lIW8m6DiMV5v6r0)6I+;YI0~&KMK=+>L_wH%fEkC0Sjrc4 hQ&rLO7{XK*Rvf0H=ePiGRyL3}P9Q7;dd?Zl0|0#=814W7 diff --git a/graphics/AtlantisJava/lib/ws-commons-util-1.0.2.jar b/graphics/AtlantisJava/lib/ws-commons-util-1.0.2.jar deleted file mode 100644 index 3fc364e7f605b580850530c281998a1f861cc0c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34407 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 b7v1ZoM@AeJ>=!c8%a=P00KlB<uiyS3FvepM diff --git a/graphics/AtlantisJava/lib/xml-apis-ext.jar b/graphics/AtlantisJava/lib/xml-apis-ext.jar deleted file mode 100644 index a7869d68aacd655c782bb373c7334e5ff667ca58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85686 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 KSr6gFI^h3trdb>S diff --git a/graphics/AtlantisJava/lib/xmlrpc-client-3.1.jar b/graphics/AtlantisJava/lib/xmlrpc-client-3.1.jar deleted file mode 100644 index a76e6ec96dd62265a199eb3ab72c54b7ebb99368..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45124 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 J03a6D{{SgA>IVP- diff --git a/graphics/AtlantisJava/lib/xmlrpc-server-3.1.jar b/graphics/AtlantisJava/lib/xmlrpc-server-3.1.jar deleted file mode 100644 index bb64a504ee8997cca1f08ae0814b6cdf90d0cdbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75310 zcmcG$1#l$Wk|ii+W@hFTV~LrWnM=$pm6(~CnVF>$Gc!|(nMy2e{eHh^_Vxb$Gh<_$ z7MT%d;nytVm|ypMj{6M-X;3g2pnrVA=;1j2<Kmw`(0|UdqAG&)l5%2<3jZ{N0t)?O zHp+f}c=YFX1TYW~+W*^3R!~k-OjKEgK~~H~VZyeb38_o_j{h07&NOV0m_tBCN|Z)L zYf;;DEpvZ=b#B=I;W{%&yizHKhlPiwv;D5+2lpMlflZ+NnudgwS()2!pl8rp{3h8c z1~771F!a8g7xi(o<ar*0cJ3dgCfgdAkni^v@`Zb`W;<T;!QQE;QYkiIJ3RN4szT!+ zzEEs!VJ*%YmWrSVT$-9(RDI&;UN0D3(C*QjK_mp|AYM?>9D%>4VP+<;)BIG9rBMMT zCd&RT!Aq1^Lt-n*-V^HY9^KCqdNkdx$?D^oR^`YOT^Ox*PO~E8K@-&S9ihs1@c)Sm z5Reh=-{AxMgNvP``Ts!f|7!vJPYXkPLt_ime`AR9cSCm@Ye#$Ie`AmPFYRqioefP4 zoelrZK<s}x(8<)%)ztCd48!}E!`w`b{>w<H{{Tr#M!Ys31PEvt5(r4(Uyl4A|5VA; z%-Yo0+0xZi!^T?4-dOg}BZ&NY1PMc16KhjP24ibOC#OTzb2(H&w9k^(;1(*P)(8%? zX8Kf7!DtLwI4LGz#$Y5=U-*sss<o?{Ms1Mmy+8{Rz-=hvZs9Z1Fv~)-nx+)l`~Apd z7MD}cbykj@+1uqvYORD31gvI};+ZInDVr>I8atD*K?*VMs!M99EHy|-es%Ryt9NQ9 zg4_9#CzVaBUVd5#lv~$&guQo2Ut8E@!R7iMDX0@%q3Uf7b-+#W106D0j?R(V$(T>b zJIe~X<Jg{{z?z1i!&0J4;@jpr@{!&^e2*!F&=rj3w`~L=$+imj11Q=iw;>oetC%>e z%_r4qtg=HkoE$6Li#MY&r*Lw#UPpEAh~<}q8^try@z|6x(iqz8?8NGdDYmUvDIIl0 zFR4tpa`IXVtm&Hd8ux8$YuNU_R{Z>qE6vTdU-N2jqv<ei)=D;jqt-a1u3=%@Putz| z5amaDnsEO7z_RQj-B`lMq<m@h81x{+)mSUOz?WF9IhVU;2{_PDXXVG1bp7m(hz@)$ zw()P<qRJszz1z3Wj>uJy60c_@7rgk?DKYL^@=tVop)JP{5Vp-fvPFc4l<2IttfZvr zHqLNl2nuhjNJdFRH$1RT#tJbtLm(-8S>c>?Uq30EaEr1T*(3cuLNH6|m<9$7ht*zN zP~djHQW+Cpk2ZM>zsbz%OX56e#sAFf&;+V>Znuz4;16wNeOkEU8!B6<zgv8eAy$>} zgP_G^hLlKx9R^MyJf-soj+UR}m0ty4-|3^eN<b`Yx#0{Y7SJBRB6c;6o|mww{BfV8 zsd><rmp*KdoLVMjs!I_Q)l#Dn4Utc2pBz^ql;|2kulpG^80yM}ec4qjJ=zLVfKoFj z5pSL_?6Mh_FZn5ZUq>qo!r|hLY;G}?z$owRlfIq%pE2Su_vdJHnPP<l0wVk~*~tIB z`>Q%zTL0za$?DMVDof~}*Cx!@Q#T-EaY!gBa7aXBCKN$ibwT7J1;j*xNOLKvW75n_ z>ESG>P-R<9>+4IlYBu%z0WC`qvvsOEutwEeo9kMs%PlP}uKG4MGwn}PCKT9vv`p9A zPBVU2e8-!OIys)l&yv50iPXI8kwRJVmT!JQA{vbfPl)qE9hBjY*l$J?WX;~nB1R*g za-I$ke7{A;k3Dmrj2=P%2#T>g<s4dA;Lcfe2q~36eP++SVMX1UyN!yuzI*WE?x{V1 z<o(ExG57G68@cD!+dYls_ANRXv3&;{aq0RsEWd=!c<wGbQfb>&a*})c+#a*C^&DK_ zSAL+*y={N667d-w!{PFtQrf$4n-a5g|A5H-IeL)m{H{5m&#Mt$XuYjJvTOIu<M)}r z2SM;vzNb&n742vBj2L^(bkX~OOw@vuVeej-Q@j$%tIO#zc^oT^i4)twuxZkBb7BN% z^RqBN5=1v@X^7LYfy%@-o}w!Qt2WXIky|93g5sn=1rwD`u_WBlzaRfdU?d}K$x1Y_ zlGKcZSYfeaVAFJ2bkf2tTStpT0cT&5oP{P`aScUQYfDY%=T;A8#zlR?Ufj>1__7iW zKk>nF;vO1|NDVXAPzf()f*9AtFznb&FB<Jou5%t&jr<}3hY$%rX1sE1cuEV8_t8Ta zGkpa6#B{P?iWnU|8?h>jQb`EQvt8A-2B~vCI&EgD!yFCXbkJ=aV_~trOi}<#dJ8Yc zb<HLpqskigd9`(<%lzjdHprfaX(u{jX8etwvgdp=D;_*$D(o*+RXYs(niP@)tpUZ# z>fY9Y2s<TCJ1aU9G4@O{>89=zncqRD0j16J`7UO;*k|=;5T2yBJqo(D$*eq6MVf8^ zk3fd5x(%t8(9S}$27X(c^#$>HmP#>jF_+<p4o;M*Yh`y*Cs_a23LET`wk7oZjVf(( zaxbH7>55jHiDp$j5*Y%#+(gR$2P@>+w?zVz)uP5MftpC|@J}d@9)<kp?Q>4oFm-ho z_AN*J+O?5+pX^J8!kMVd?s;tt%ag4X(snQw$81Fb0u`R>W)ieXTCts<Yu*`F(&n+7 zWAP_>WLV%DOFK)ZLu=|jt^f->pI=`d`xjMS>XPpa9qG4MgJI__w<>6b%U3BDB$i^r z$1y`qNkkV9a3Sl&*zAdW8qQM!qh|+W3CMX8gJ<ldw8F%+@uOfK^I+wtN|xM0m>X$l zcq<oJWi#Kznb(cRjx_w5Snlyge&R)(7w3m%p9g%eEah7!MAV!zlr!Nlw~TX}A0!i& z8SVz@ak8Ofa>1I%NX(<Cl=k1h)zCpzh6AXoV6|yIp9DTx8f6fd7?=7(xhk0(ybw)5 zUcTDx5`5!f#FPDQ6yi@c0269h4zYWdget3o6BfNnvjy9Pz{WDmVU($&Y)}4c@FzN4 z9jK__1ue&*3}8Ya>&2Knb%D1`OQeVH5&~tC9_wgauFvZ!Gyx)k)TG@Q>*QGV`sU1j zfU2m&(gx;9tIwXK#eFZ!6SNcSVpWW9aLJIOD)^oaka@H$Ak2z4Cz9;HH4sWgIl7!6 zA7<Z8Q2`IfWS|oQtCAQW)}B!Ys52kLsMwPDX(am$e}P{gyyfmJ<b1pMGkJby5k6os z;2%c?xMdaf6x>BzC{p^Z9FskIEyhIlK)r!$C=S1lj(S7q+9O2GNOVRSn}`4yydvch zR)OARF`wg-kL)DNpm+UG1b>+vVvGn;h?=2LcyHu4xO$B&@oH8#d=`<wUF+{Rx7O5t zDT>S<aP>MWaRu~qy7k#={o*s2`n6RCVAdunQ1i7BB33>R<rL%Cm$4#n^#SrbjA~}Z z+E)caKCaH0-9;P?^^8gW>6_L{Vs5Vq0DaEx=)=V3U?+vD@ozNdmMCQn*x!^Ly*s_C zEQUjVp?FDeXo3nVQLQ4!xI$b?qnB}xR1%$YE5+73kX9fJ$*I$AoBb{!6})4A95n7! z^>#N=mL{9DC5fnXbPY(*A$MuiWmA%CCCr<a)#j)go2OTGW}ZF8QO1(1k|BFm6^c7@ zuS#{n+LC5yW|5}1jS1#y#87E5TeUSehY&F}h8Udgsb8~0tjIPqKZc4_mQ84~r|9>h ze_1aqjY)|bODcGqUQ=;mpANrXt{D?_M#p{jF(N<RlZb5z>WbH~L-UQWZaN{yRE_Pt zRc+VOA;@1%Ny(a8HU0glI924P#cnXTQTQA0<H7pI%}1|j&yzXji~`59l0>yM9lvJ{ zIeodCB2=lGYd^CeZQ;bv(GW<K>iAWXCHsvM%oA8rw6RPBV<}ZsH(qq8u}lObd9vWO zu}oKU@rv#{QRI4}=;c&F&16B%cpfin;W3EMj=TzfbinX?2B|%MQ8*}JUad5P+yLaM z6&298AS(-JCqec87?x4voWg=5q^3@$bcheuVUI2Gy){p)SKu~_L)*44V~B8bDhXiW zVHyelAT%ZuJYg90qA+4TaO#9Ol8`8K3BbJ+TCK)iL^_Az4U$wkn_|5bd1aFslxb_; zKGJwPhve-zd2N;lN8*VIN_PK6c?6$mLut_}`rvPXSBB9W*+%NN2lu@h)wc6kW)4cV zNw7JyU&{VW(tCQ<jrEc0ZB>Rj+qfftpcVQmW1nvb7#5039Cyg1VjMSgxv>PF@Da@@ zZ^)#2oCgYXEHNxrgMuIiz@$EaE+I}7jw?3G#$Xv`=zCmMNRps*c=rVw%xR{UmYj4n zUA>Sbt5o<fn%D0<ESb<H7c`}xM$h&HW_iGs^<YyP5e#&NbUJdx%MyLfAc%(O1jJX; z7X7puq*4w&R3lmdM0z7)ts&+rRN7gJ7UOOx!@xEO%<%I%#m#6}2S)aAmNpIE=&5~p zYh=59lv{QN^y^(_aV`conZDn9b*?ILay+IQ`mwRATn@OF=SB6mU~0B}0jkv=6BH|1 zoAS1qyiZhWt>AKoQT+CBvIy4g%ftxpPcFS*SeBCCIS2<{5R`oAKXBQ-Xjosb@<cYn zg=iRylOht!>L!UgGR7e)m4(Gq5|jvs;FDAdRCbM@ImZ%lp25CRFSsLr3zknzsJe)5 zX^=<Z&K)*$beFFDDsp-gZZp6~#v~B6(%xmg8#1ub%j2`lZyY?Oq%C=s&T?XLCzm_^ zE%4SX*Kp9hZkUZ(@S{h4ep`L+;(L<97*!!EWqb>|v*MBp{8>2$T^_8q$m`7^Tl{b9 z3GajqIlna!R}+?RfivSc4Jf$-$CCFTFhDJff^W+Qux;U0_6xMPW~Rv&4b|)B`h6W; zhsqir`q6$c)V(!*nn%3gg)Nho`oaX|U*D^{f@|Y9=`2HEmBsjL3=&t7M`nkgocea5 zt4gCenk0Lv`aYn*R&j;fETn&SIzU}&gZv_(W)6~Vas|{%s`H^@^&c79u_=QBZ$-;J zDM>7+#CI!?Ew70{j&`UuRKd3z(e}WhzLiC9iVeNfnw($$D*OoA77yboep*&)N;0Ig zCFY_O?T0%Z;dM@^O%|7xO4Yt4*CIuni{UBGely8Z2qg1!%;GE(e_C_6OSzmQ*tl_N z-ln&fr4Jq_cii8if&4;ZP<>!02(wm{gNgepP3C;+Q$FvOAsN+nvavi(O10`vl@?2} z!x_ccJuh1E!3uo?An)Ws;fSCkD7|rs%sHkN90N-|K{^1(7_iKx?qLaW=ERhUrlrS} z<TMTOG1si_U(ORE^iQWEr%*cmV&C}vA<|fzVZEUY&F999eV{(9V4ExEzw<^wfsi*U z4=e0$H_j_}Z~m_7I#s~(L;Un%<Ybyq9FUWD!6{09#rn=EjQojpc(pJOkvn+`ewt-l z(Aled^q^GEb^PGFDagD0gwT+vXmw)Sg4mKHFrudIWEa*{Zx@wxODK3ep!r@i=iQ#1 zm}N2UKtZ?h1DcsAr})}w@g|pY8rEbn(lS`rS=MczLCH2HYm0utBKq<Z)RDs<fq9=` z)2eb?%+Wii^@s|rGN(1U>xehtJ+zqhd~ej#gf8V+HjfQ6xwls7^{yfn<cI=CnKA8c zo)IHa>|6fmhOD@b#8!!_j)oJ~1cH<xrU$c&0GFbUrfyQ8Z3imi_tP+<Ej8U&1;mf5 zq|gov-(FT(g`hin#81S((~g2n?Q)Pma?RnNFW<kX9e;6c8A~T;LnCX`e{yYELwkEm zTl2r@h)-OfT)zNP$X9+c4Gc**;?JQZ(5tyXb9l(Ga2**=`VC3ywU*3FA$NAfZ$A)C zbpiy1aS;=@Uhe(ACa;cH-XKAu0AaI{_W1eoC&d>fnulf=YNkrawg+=Y9Vyz>O>{~C zH+I^2aiL?&($%&qx(X<cAb&{2Szc+_Q}z^S2OV+o$l<Q5_}n`7piYV=hj@?n`iNYX zOGtzr$B*xepWu$=9wd<>joFgMT`#`!s031(FqTDH^{a>LIOLA5%<*y&U-m*@ZtoM0 zQ{%|Pk9853DVOq#mV<Ry{8+I&YZORYJs?1W5>O6Doh{cweqwrDBSYcyeTVu(E6KgB zvmX$D2N&DFN@M#EsHT6wW&hs+_g@MbF0lY<P(h^N9WryZ!Z|b}LsD1Cd@H+3;$Y%k zHlYd!yH%al4IXyfF}uba$mhaAcz-Ia$dMa@>rBIMz1#e=!|<;#lrVh3%0e?zlhWs0 zH34+cn1OrNzngYBmSeh?Jm893pMtIq)+JCU))~>KTXseEyBLP|ar$2j+At^1RhgJ+ zvXL0{X`VLIf^I>@2^tx*f;QmA+A0H=HtW(O_0$<y#nj6+iVC(TkYD*BOKV{P@%E2y z6ByfqD_?A`h^|mUYD%~Qw4^4S5;ciBDJ4>4#4)~<l3TKvBRhXb4AGT7=kyO+ZhvGl zw*MW(ls%lBO>HD??5)WFWPrciFk5-U78QWRCpT~1Sj5`&(4XB8BB`)O4{|#jks2X| zuBgpcwhuk#P;FA#ZOEf~uTJDIz<UGijb_vp?hYklQE%ck%;I!(^m2Q@;g(b%-V({R zS(P84&2Z$f(T5M|hQDcCmLXWy{nLL0DCE^QL82Mgp}N@YhNt}OjrYKa=p&L-DgDOS z@|l`r(+^jCB>g0&DgM?sOLTjgUAUS@YEmFW0qM6~TF?>sz=D}z)-trPDF<INTx2#= zJmf$d<r408<cVo{A`C&cJ-U|fokqO}lQp_iQfSv^>XAkdp_EOG3Qf^+xsm&4YuX4D z>fxo@aa67o|Gwl7|3$W>A=H$jG4;SOKQPv&I;M~rg$(NDF7WM^b6L<Ptc@J)0x*C5 z=b6UO0d72<iUZ_~#i9Ue7S@sj*I6UZcT{m{7lveh-E2MvnF_JQiA-WMjZEq_Iy9Cg zM>T4{mDv2vrk&x#{@1$zA_I5z=L7V)($DVanGE7Q!>mI8%6YwpsipzQPN^nL`}Akg zf*fQ!{mtK)b-xd0sC*_}aGbTYciC!YHD@eS>rxCMUue`MCP*%j%#n{aaur@9?n0^G z0ylkKs#xk<7ipFydgPpgudK*=bF{aK7>PP$xLvCgH)|mFY<7K{f5ZOWcOoz$pBDZI zh@TKZKrH{KzVnyoRI6Ia|IrNj7E%~&FkwXr`Y1ar2xo0>{WV13kwtL<i%7SDV|Dlw z370Kb3}C(yy+3Q8f12;BqxvP?PBReY3n=YVY_&VNU2#2abFqAU9KXp20YcsYWO3ob zqH0?0SYm+XaPKTJ-40lo2nS~)UVjE1WqaK|cyJDE&*k>w_RJc}v)DG>=AZ#4HCs-$ zY>xJNl85MyLss~1241~Gf))M6>fjQ^ThgO5*~&qrO6&FQh#Q$eV&YpprvWR@Ot{2Q zqV|4G%$Odc?JDRMuOn8ty$*PD_OLZ<C^l}>^%9OLgOZK$<H4kK(U4J@LK>_D(*+Fq zm9vR{kLgtUyP|RUK<&s)z@hgD_N|&sDlptxmJO`=@O};LXklw&y;{-t(C_^`B>dp0 zaG>JeCS@fPmEPIs7_C+vxq{SA^8^;+-YFY%5A~7&dS|#>NZb$$PqP76^vwb;4wEi5 zDl{y;=4QXe=z)2DIlp{(qi}T`s~BQ4*>->rr23)hG>sf_c>!i3jc1&ay|yUy036r; z1f=)N560e!RQ|9cBN#UonF9tJCv6u?(J>$SAx)h;;bk>C;iul38OB<e0pm2zJqDJ^ zFLNIzxK<Jf)eGuC;;a;Lx)rfKI8k9KnL;f3u(<#%8xAq6=x_)C9O+xE*pQP<r`Z1Y zWV@t_eGJP^J3oQhBc(r6(|rR)PsE?WD7hwtAt)|koU{}7PEzvma;pE~e8@86DV|NT zvY0acBS3+@6+Q)jOYE7iUFf9LEeQhz5g=f<)S8Gjh&`$u79?6p79~nVi~~!E^b%}R zaX?!jO^ECfO6B30o8J}u3Ysk~g1Ry8E5!K(e~Z-e+g<L(l9ytV600v@W`)q;>PGUM zBqaO^WepjJae+TdtTGVK`EK-`8!E>JUs(XM=J|&pzfjv*?*dkVL)g5;^QT}|p<Yhx zaG1!qEkEGD&ykF=PZy3qu{GyUZ3pmwHb?#$Th*-8H^h*-t)fg#Zo^P5UZsfH!s`R^ zwIrnSC6xm}%ZaH=$dY=3x>gGsen|y{5YFz**Pg;A9A*7Bo;i&@JFQw?MNk_T{-$N= zW_~rfnT`FD>-Y7Hs*5EqI|OHj?p?H-60z~DQGCcl6LKSo$T~@Gk9luI6}FcX0ZvEL zRy)643KK!|dLuyhE$V<JzYaxQ(z>SN8P5ua06@jot;cZ*GvGYuK<m+6gR7e3r_{LF z5nt<|&v@RG<EPW8b|yCW;O(=p58I*J($-0)YK}z#C;ilg23$lYAO%u{0IY<P*L3{S z)uK_U4R;)|@miD9>fD)-i+UEcpuFDrLGvUVNX%}vUg8&N$nIk{GrWvd;3SvM@_;Fu z$#}iU-rh+=hMgcfGF#2I#WvJckM&qtGQ#BBHKs=Q%e|||dDNJHOf}natZKER_W;F= zdkf?Hm>cK}J3BWfwn}+d)d~pY0NGJ4R@YT#%q6w^=Ay=~TK1k)S}{{nkZ2G+cm~>~ zfhXN!CUCb-iXpqZX&M|4Tx@6O<`lnkHn-bHcbsq<XER3eQHt$zOebbe2K*)Z=Lf=* zHwd8Zn9El1jFlj0{=6GcK&FId-~^z9e`NA&3~b=A5O*R*-`@4Y@tzfA?A)1v+<b)1 zy$@}T)tyz<5k#!7BZQG@h{+p|W}rA_v;h@r>rh*1)CFI?FC>KVHaVpArWvbe?goc} z=2<N;MiD-9^g9z%O<tA1aU`)<#3DwRoibOJ5V@$czo2%L%@qWKll)H=Ru#i};8D=I z8}9A6>0e}yawNwH@lM&(GDcE;Eg{ze@FsaflYvt<w$E^+*}hV7>_Ts`_6#Uf4yHrd zc9+#^y2p@fsEaVATDQF2LW!`avjI486BJVKHBDG{IraXEh)~vqmQ>wSqME;bSQ%R| zA0BAW52s6xJ5}&#y(dV<C$|tHNx^=9sSYs-lVx?2O`)<rv|M?bNe8?jUq4$2@iS3! z#Pge46$TabtXoSM@^u!%M^_sLecKcUB6%o;DQ#_|BBp8PAg;mcR;-_Q4>t=IKu}<T z3^Q%$6@KBG^$8vR_KFFtBZ#Ix7swi7$xc>0Hhu^sJJe|sIL8>QxQ?3EiklWbX{XRI zgB-hSiK>zY>1bmRPN5MHrCa>L+AV&{CFTaPrvCG{bH7|R)^D5-n}oVV|EB=p03U>8 zm%M3+vW%qfc`bFGRB7Iz=i<(gSzD7Aq>A3aHrW=Jy5n5}JFm?bz^_k$ILVwh@Uh;x zT;4A@%w<2(JIX-|Q^G*{vrs6gw9<Nk5&PH}TX>EeDti-+45Izog+|<K!vNa~TgM|G zM~3+$9i68B5T}VE$}mZ@9DhFY>yG8dw=jadw_2hmDnn5{n0MdAX{=zsK<kJlvTsD( za}uRcC4slX{g@9>{DUsH{C|%^Ta`BsPk*9M!=II&>c5Oa|Ev%S8aX*T8X7zQ&w}6I zX$P60i?fBPt+S=Ep|ho(?ceHu*@}Hq0|H1s%2r0ki+b-s`2hs1=C>+?1$k)uqFpwv z#vP`enr<BV&z1!5K>SjhKiuO<I8)O(?9x19U!J|aMlhzCWa5igNq>#UX4aKudmeHb zIy<U&Rv@X3f@7X1yQ*Qt(&}ny-boL9)5-aU+;HA(f~#WV9q|!Hcs4AVLp2q2a61V} zX+rg)*$7v0h--M1vDICtmVV|<trfrjgXzO(ve9Y{-R~01rD6??T$J)4lMK)H<hXUX zu5-TM>vxbLW&Uix%8+wQ6eN^*X4IEExz4+`oe<H(Eche!XCC3LtB9@~N#bxvDE=>i z`AG@nsw{;5-;sucAHeeaQ&oZ`1_I*$zd`!1=zpl;<*mGg|CPf&CcChK0Rs*KLJ!h% zO8Nt8o+N;`Xda^oou28KyxZnro{WMTWPvZsc6y47BYS*vbCcq1b`R8|8sv%?^_V?Z zx%FlJ$jY{%y>y}dy8Velb|F(?_G`E_%jwGF-FIi_Eer4U+UG4UR?DFR^2w+*fDh)k z=WM7iV(ImL9yBP-)ssM<0I=E~F!&qqO&Z}FI`4^K{L3xr+WTrC_H#HS;$EJ$@7dnw zfa8?{FhSqUuM@@g>tow@p_&gRM<1CO0`;39$V329Cgqm9)Rm8x?|TK(%&sQ*1{&{i zU+pdK%ZK(FuYMTjjS;b4|3t$}cEAp10fe8zO~i$Mva^2T)OmwPArj<`IJliB6Q-Zi zjXC1c9z7z$#NmLuaGyTf`%-i(pT$ofn9rj=66*II*jvPRW%jRxsb2Ih(y@<Hq{!PE z-0QK=UfVADb}%$zwD{66Z&6OL@stOOjz@bEtXY&k3HM@*E2vWda5DgJ*;rawi??P3 ze3+s|?6Elh#*8mz)|j?QfCOcOX4fuau;X1z1=jielb$bMgLM~C#M6_+&@Xe!9|Bmu zbu3>q5+;c?yVhp;y*u1sbOxFs)$+Ifbdw?4igD4Eegkz*Sp26}H%k#DO5fD$I9j9y z(<a-Nn$TSa$^zrb(m^;|y@WvQ2&rTe^(lslc?bKkA_`$Q7s`djGU`@*%%P!;vcxqK z(mD7rc#%}8bbDziYk_w6sdvE<urj9Ov|U-Y2#i*1NO<-vxDIUKo`F%kfUoHiH}J^3 zL?{Cr7Th^~H(%z1M&>UPg>^J&i+mR?I;!4kN$~<630ii%PK<CfZyotnO;rQAL&aDB zq@Vb**@QdE(RUZ)6@{+#F#D4>g#N*<Vd7@m;oSx2qjWgd`LT<B6mh~Sv({6h&uN8* zLcFvCEqLSHV!le@2L+nX$zTVPBw|3&GBq-hF==Dtb`0z)fQlpw$K$~Z+;m+dPjx0a zbIpZLYBadC`>4qD(_h-CfYa-NenlbIN4oGKRvfqa5FKwFJ`5ajjdOsJBbEn*8`<KV zbv&xzryZKT67IZP*2GkgwM9Udt;~HDX<A$aPG-yID0cKTsd{0hvm_Y}Xb^Ov_>opI zC3Us=OUe&|WSm&qerhI~Dt&i3c?%oXxQ3r+<A(dkNUPKMp-4$I;W#EHtEG!Mgov(+ zVeq&Yiw7sm!YHn#*eDV90C^MW%&bRZw=&t81{p9K;X1Ze^ktN8fNn{F4ow|qK^WO2 zJ}tZ@24S(DjfAHJvuSCfHJ%&UvO?i<+t7`?x=id-h(-{Nn0-qcPzIJLHA{-B+L|`g zpssT*D`oOA&c(r$n#SDJuH-4x6jrh;+Jy}h1(rTX7e-?Qvt5+we50nbN=@pV9!|5S zQ#!bg!7y@=1jcO_eIs~@DMOP83N1<ZUW^JI4v+a<Pj&pZhJZeDl8e`H{Jd2*StXPx zy6q;lf-f0E*CU**WjI!5%4zmdi3S~tvWPzoZ-K&4yO3#M?EHOf1qjD)5n-C?L9J~| z2>M>7NH^5R2(>2a0*T#CM69}MMLwhpIEaSjopjQTvVH5U!hO0bWzl*n#X&07D2(C? ztO1DDeRkC-bkhi|(umvDvIyt`nIQ=4B4g>(vm%P~N$IQz9{W<7E~A17&Xd;zX8d1G z+tYG<B@vSQoZN2NG!)7UMiEphgDR>?kub}9)~5o<3n~s>X*ChpMkO?INXZdpO2P6f zv;|`5%_x@HHw$|<-$Q83#)=iwf2aVopH;n))hpT%Rw~<oH&g-QSyW84q5cWeoMapl zsp+%|{O@?uvCH}7O@@@z=`B&PmS}QHgS`Ib;-kVcKAL;!xY{Ju-Tt;#UKwApw&6)5 z?Mk+MB4-n!7L!z?vSRxUiULwd+RqVbwGoL!AgYUzD5|Vs!DKdxi7MXs97;<CaeES+ z4fDxP%1mTVG9Kn+YPJ~Xua2r&B<{z#!@82&Ypw<OlNPWsFD2}QJPEZ4FXD^-i^*V# zlGcx*-lirF<435L%Tv>jt2Mw~QD#Ld9^~N~E>4rXTH0=Oj`=UEcUa)G1S=iSfR_1| zy5u$VSeKSp0%YI&mU+BWgOUYfhr*uQZ(MT}=^9?{sIbFRUUhWt(G7TxC2aZFGgBl7 z!2?FP?2PfoG?(ACZ+DaElF1gAd(5~3qe@dxtCEzMq-}Ck@M9-neN?Y-S#<>w6Ah-q zYGBOt4!MG5WH#DRk)5I&;3UHq;W<oogk<~(h1N1~GFV&h9%lzSJ1G`Kh)|06eb}9G zY)Wv7eeMgpO?(=r;*kR!a2bQtsDGXmNy3eBE-{Iy7{~Hh@WE<Cg;>jbF(e`67L#-~ zyGQnr6YnsIaV*9wyX!0#->%y`)ycs=Dm|h$_Qrs7hv@sqzGP<|+<gv1x;L(W$RwOo zh8lwSoZS8LB&$L-TKtNvbLH@U6Z!7sFM(ducyczjne3Uu#NHee6E&F?C2}Mt&f6B< zQ%y#)oZ0O->c!N)U^XpNQa&QR2_?!SiHEKcOaa9@5X|cl46z%>VfNeOF5>$`S1k_T zIiFW+SJd64IMG-1UYMI}%kixh=^Yn{+3WBAL);(pJ(yQpRJ*eShI_VUco+^EUAW|K z*eYx-#lK)w>a#;pCPzf*eo{=AQLur{_UQ?TmkwDX%OBOdy;Mm0#U+fS>B3Q_V4)4C zchbQ)E{alnV2W`BV9@v8!gKmO6&R>TBu%98^1+9(fdBILo<xw4q=>`F(ac64<$^ds z^0fYuWCCK@2#z8)cyv=XIdE=+DDL2&jaJB9%o%I`N7WrXA#+xH`K+_p5}}OiR8zg~ zJNcGm8_MEW%0=K5i1+r};KDV@zT(0*s&hz-z>k9hPeii36%lpgx-SUd-eFk7<w6EH zBOIg!AFM<<ivi?p7%ZbO0;0TxM7~rEhkBK0Rh7D~ayD`bVimSN*b0nxJKut!2ET>3 zsn`sWVu|POm}??SZ=@&FA$>*hC`<YJ&O_JBe$%zhm5BAn*d|YKUTI27W4tu_#gl<n zx6--ltAjTIf&ur}8Eh9gBw+m($gJtuOSk&*3cu_I<H9LxB;B*Mm1yUD`q+)o%=4u= zR$Jod`PB&Y3+J0s>FVw0^181I%tK*>9e(M`8e;Blqh&pwD(qc(xtoXXM_KYgho@-F z2g%ruteZl2MD6hTcAzH38vgYTzs3IJBI=Fi@Z+&U)WqJ<v0@Bu*&JgYgt}6uI^eE% zlBzeO=2i9k4USHLRr>*VOX|I4J-%DxRw%9m)XvYwXNv72)UIGVY_+x=Wc(s&>ml|# zs#5rGaySh0HvOV)STMaMT9ua?Ve<AWKjw<QB)ub+*Fw3yadP*<h11Nk-BUb9cpYfz zeW@7^zO6Hvo(?1(8x5=>Dpy1&Ek>_|HAizs+%l7IiZQnJkGcjpa{mfke1Lk0?~MGA zBGff>jjYYs%JK|_8$0vON)yLj{07##;(%lf$<(?<*(lb$qS=T^d5QD0t1n!u)|l}K zF=SsP@aodKS00V$#RoEGBs(p#6Hb<%`K6>tBb*UCT`i`DWS_StS4>*RMnW;RRzVE1 zd~uFOzYt>naBpKBW(54g6pyp=&EC;W??f6F%{-!h!GIDpxYj9hlKE;Z^|-?7wT>up z+BZ<Hy`7YvhYZ|a69no7r5UX|`QgyF_hI%st=U<o6@t+?5YBov5v}g%&kFWHD@M6B zeU{PnDjY;*%ur5Wux58w_z-^Z0r}dbZG|Y9*CSb8pI~5WMEJ$zyj<Un0OudwMePni zk)!X66wo$IuNhWVtCba!A$ro)$kvEPxA0i1x>h2F{3*Z2h`bsyl(H#qfX-g)Ris*@ z`~sg#=V<*$R=>sEx(Br71|iDVLwt)ac88$7$s&%8P4kYD#s+`cJmuik%djpaFU-vG zVd)XpgzypAf3G255lyK$el8n3oMMC6EXV-W*o;L7>70M`c~$T+w|Mh7y97tu6Ww>G zmfdhtTF)`I+!(sJ?M`Y*OtbBaK{n7z_b&%fmZ*=Os~UMmr|I!S$oxs4nK+)q26F(P zcbg3yPo6-o#t^ynXclIxlTO}yy%d~|M9DNnoENK{;w+5Hkd)U~B3CweqTcK~mTb-^ z+;{w<6b>+5`G}TCEWaPR!`9Tw6GInM6IukQ&DPg_I0GMezZzjGb-`68SlWU<*qrCB z)-db8h+#e<|ITg5S$utj{%E~BfB4P6t`+=epQ)pry{V(K$KSc*UyLSM-BKA%9gPn$ z<kZlD0}ZJ)3Je{>-be^V)Oa5!oC(Wbe_^s|cHLRt(^H|5(ToGo33yXGTq&Xn7A=dA zJQS|DL%gH@B0K6@;Tr%dOi`J;p7L?~qyFAsJ-mPH)b{4%=sp8tTsZMYknxu6Wd?3J zNjUKapxbkjVwD|ezM+q3Vc~=vlqH^Fn;cFj?Ju}s^;zK4Wt9(TuHFGk`pO4T+Hf2l zeY9vinbq`$@7T~-qeko*V$eAW2ZFJ3;y28#%I~tApS|&--34Dg6$hko^f1C~>+vRb zXcV@VeHDlr2BtDVU|;D*WH5(AWbJwZ*2+pd$7XPEd3&07PE=9Pg=%^R!nx<sMNwJt z*lfzjBi4+ml83T(n-5BFyd379pTT?~iOsULJEMnm<|Zt%HY=kr&MlAGfZ^yQ8&1-4 z{FeBcCq-M&%!xta9!eWBUOx2_(phI%WB>KdymU8MJu$)DgUC}1UTp(k`(J6kXFm-H zhi-L`S<I$ebwWLww+M9Rq?YJMvIS&gUgjGBvsBM1x^(`gN2k3XzZsH&Ba6J3(_*f5 zcROe`9`!~5e5NMMVgoXXYQ^L%JXTVL4g(BK9`VQ;tUM)Ey@wMp41Z*3>F~YI2Jd)0 zJ}I0@5z%nt99XY%UTEv~NCdT?#9{TOExebnom&Bk^lZYe6c#?~ScRgSqh`WbAXXbk zAsMLD7V~<V85Rsd-)2}wHXRy&mE{MJT2fBm?HDZ*50!1D{QA5bU({pdJFyV%3{iLP ziiiY>Oje(eeMCrNCJ{FqS=ZzA(dyT5{TaVPyVnVwnL5pZsyBKV6ti;E5yNp)0tYA} z4UV=pB5$yCmmb-07eCWUh^5EbUb-b<uyWTQfqYgN5a<3jOv(LiD4AqD-Ff~tomYz! zw<4ypt)LK7{^S`Cl)L9=Do8j_v!cP{rlf=WB*CQVIIMC`Z@jEYQEg7p<TI^@DK%-3 zKo$|XCPD8mml^vWnzdK=;+xh8$7<n$w$Ab`e$UD+=sLKP8&@e9`_{bChW++aR208O zPRmr3U9!7MgH4$`BiNakjGrfWvkJ-9MLk-v{6ab(Bdt!QBgGuUQKx?pnPq0BID9uR z3iUKICogL>AZDc?yr?FT_PGzZI;BOGH!jt58x99KAj3$wWQI%Sp;V4~omW`*bg;@E zCLWSyaiT=|L#O-)`}bc9M;`h<iTH=6Zi}JmmWXh<hP5VwYoKg!Mw@tWVy1!SF&ZA+ zo9b9C)iS-Ou^pN*;aX$;_9j*B!XJ^w^d4{NO@50`Gm;6F32ZHoY6QHub1217=}x-I zR5?%ZGc$w@?{nIdbR~rFX1Hqi_=fnuav_LEP;w=Gr5w<8tP)m;eUD0D@V&*7>(H~k z&-_93EtZ`QFZ+BJ6NWKgU{Lqg*XFqVE1XyKHQ0jBNR`9z+G8?aPrz6SEKtLA#V?~x z#8<%f7XUb?s1N8v5Q7f<%Xyi1kgAg=yBtx}Zn$N{i&wyBs&n7zT?qHz76xGK(A{X! zI--d?8j~a#WtGcF3HY`|neHi=^no>*;EVLi`9iQ-42fG%S7VrwWXb>ISRI^IZPNHb zU|j=bBn`DsC}pJc#zR@JV1N<{Hm{plhKZNWw@HWbj4$m;G8He$I_hIAAHB%|{$|lo znC_ypUPzv4m7zI)WX1876|#-ODGoX>Veq5w3GhXkK1x)2hxA&fU(77g4VL){wGgGy zkbtvQ^(97U)V~$f6OF@Dm-sMS-U!<Xt>ei+v7;~5Ll|p}crcMfnpCx$xC3O^?>Ad{ zasK1iV8a7j(}PG!U4ckM@<NeCjLt{}u8C}=N*TlVP1Ns;lo6YnK85F$=-d%nbco9O zqGdl7$K@0}qwFR}#?BLEuF!~aXl&Ar@DsNtghurclIF3gidh6Me<*ZU04<q@*Q@g) zqMRRw(}kxbrL)OD5ly4lof^o1%YuC`R>1L^uNJbrn4HE=M!lF+a7Smn6$!YI`wU2t z+{A4VWfreDRW%<?8Fp450n@52NJ(G=S+V`(c~kSyh~Qn@yZ1$RHy)M_vhDMBEXc&d zyzwP8$gNb#kFe+zZc^ne^Csvoq!Eu%_;g&wss14Rdr~Tq<|60#Q-rMfQ)ChRcY@ph zlr;b9tN3SfBKy+<U}0zSkKGJ^C8%PRtv}lsu=pCcT=VG^XjH4h!q7YEFG&>bBDNQi zBw=uf27@Y3U9D3u^h=~kpT322P;94%iJ`s$^@P^u`)cF#ty0)bnlbNq`yG3mn?JqH z)ani@^oyaOwy{COPe^VKM}+Xq5px80YAnUA7%-9PAh*0j2)DRS@@zV{t*{omA41Wx zx_Q>a49K|SgjHO-1i=McvtWs{>9flc*jJKIuGEl%PBeM1Jo4S|Ix?VBvfIoc<T5SZ z4FJTfTZgJ=Q%lhg;smQ-;rp1h8~N(J_LqZscU?kxPc!Tsj^m_xxSz5oOPXa>4JS%~ z6OP;DJw~w~Y-Ug!&Td?_6)tXpm~Du|{oCE9*RR4-YZ@^%X4+QlgC=#I3;ml7N*TXX zU=8N<;W_CPVA+pt@uMw>rxsm!P*b*F=SoOhug!Hu3YVo6a^o*hour8<2`i4^NWoPW zD$WDIb%ixU!(HH?uxY;XF@(>IVvZk;$IZeH3s*XsE^3%2*+id7=7o{+!|<t@b2%U^ zm2jjj3WTe_B4)i`{9bVicRn8-mim}|ico>jiV8SH)M)0jT*a(#Sej-M9tj*ge@yk8 z*9qOiN$rs)$%kEHNNw3E%pk?`DY1Mnf5Xs(8DcrpqAs-c78L6H#7*vgdpr;(gw!}S z+zyQ3&BsX-2G&H2FWk6|`wcVx3zPuqNS2N`nl?%LByEH(&zv4fd%3YjxmxH&bn_?4 zM>JYRcwCBo@^30>(ki%w-v3he^G#0oC4mA0()zP2>t8pb{Bx=F-+1L;uGp+$=dG=Z z?Q83lm|5h8dp_D>U1zG1FN<5C3e#k*Fiw-)f@_nW1mc;wS+bU}d2v+Y91K{D2>4P! z!Y=?RP`;g+tu}13N~fZ^>y!6=jLdz$jh{Jlvb9~X?$lg?_j`NHa+-O|Irf>k@44op z^m^jAW9SdW+J-d(y#pR}kYFtd2sojiLko-psK(0iq71SktQf<wzz{qh)DxXK6cNN8 zlm$?Vd<_v{dQ<-d*RL6&>mkXY96DAH-nD|sQMz$P(vEvNI4}4TL)sZ^9X#0(WZjqe zBm45e^qh}08a-zb?!fMQ@KOftsNaC{$56Wyhnc-A^hNr<kH!*0-lBG)iKtL@Rqdif z_W^HZuqL=!rcel8P8>QnQWm1acnSt2EZx00Gmz(3?l37k(ASbvJU%<K8y}(G2H47- znss?~8Ki6V<IGbsd-hAopSoGKn}~5hjz@Na#n=Rfb&h-otp?i6oq{_=MUYvD2n@QT zU|ye$3X1-KY@(*mnR6^}yJR$tF7YiZ!>sZtiJyf9AGj#i4)M_Ft3*R+hb7<i0;KA! zaOx_<19We<Ql^Wmw@|k2dO(hJQYfOVmq&-h5sn`TNX5~lYty=aB*c0f8>>=GHmuw_ zx_4;(mX7m^Dq=7c_Tw%^#ArO|;3|kV=UkYzBWs%Uosx;PGgp$juZ^v&8e>&1^qEQ* z%=vinKSYB++>(e#(kG3C)7vhQ&r?^hu;2=9)eQoNex%+yn?R?dPu(T3bA<KtKt&kQ zrB}7^8bL&w+)gD;sdG{V!??{k4a#Yq7n4(|{#H#Hkz()+6yK1MoYsV$K#*tFQnBf# zYY2cqo%l6p9jR^EiA*msAF*5nTE1%zr^iA0kd-WFVT2iTQqbJ4^~l;TG~ZU0PW{?x zIhp+IOzsMA>!{DoVTxDe-1Z{maM@*Fe~9B2KDwd`{mP8ZS8UpWT7W<+SYnhInUGFn z*1q?hEgTxHLJ2>eHCkNcMG?cvp*6OX_MS~B<-w^A<R!UFEz2>k?$Kyycgk%;2QoCe zAbr+rq2Q{vJYJgvh6ug$#tA*Qzf^TIO56QjM=+wI4H}=ucE|?gcUy$MfkGdn>N`wr z`7@jE07!Luqv@>R0E&l6+9@`lrlD}ZCk%;}D9Mdq<*plz+^!3>dN!dJdhZCK3Y>w$ zkYp4MXR#3iIlA3$Qv^r6A|M7VvRkcMJ$<_i<ePQ+<O5G6Dr$j73nEUuqlb7(<hKGY zNyU?>vb2$a02UgI`l5aMEY%xv!zUZ)_$4Jdp;crNR&A7enqif9Xmjje65N=QVTmjS zyE6gtZfTR1rPM41AeW;gs3Gl94EZkb9u@nH&$Nt*s{I`eJ>${z-8iVM)UIkZcj%aB z-0h{k<?ia%52#kMlF&TghngLsK6U%IW1l;Eu=WqLb5MAv_6x4<YIGm1x@^HWDa3Bx z`6SvN8?w!*!ZnN`2d3!1LZwAzG1aD_31(95ukYCrRPQwy%rfILPL({+t$#s0S(XgL z9R_Yu9ntZyd&`wCp%@m-JeFwMsfq`hKRl*la6q5WgCAGE$H2C41{pa;+;bB(Wrmzz zX1Lg*6P_+R;Wf1bocmN>z%CrgW8$<DQU%|?(PmRGuw=;{vQ}Emzu;!5w`bsIdSh#d zdC={hnW;z9H-8Ukzv%y2+yjl~$vbL)XXvvHsxPz{Ot5mUXQB$~Kh4AN(s`2At<sCg z-Y#>WbbJS_R+h3qGL`CKWJu|^ZwnNw^to+=)XMiWr?q+Oe!taAZ}Y<R?6TjsrS<-t z?>VpTIy!|&R9ilu0fz@%p7lbP7xV?KYmP}fw{!sWPE@|X^BJZF-Di{o(Svoer@I== z)P0!}|LeL}k5UQ$%D{^c#QHj~**4~C(DUIY^|$V744;K4qs{eRZznalb})}cff{0W zKI7sB=xU+fm1u)_ZoXbN-`RmL@9&ew&3NnBD?$FQq<hJqY8Mx-zlC~pu3oj|2lPiq z1{=J-;XV*-ydO1a4O#I0HX=NH;x=Ksv$Mcfd;MV+kmN0~+Q9_|vA!*6jC&jC;tqU% zq{zRXmr`dNu6$0O)fXZtABvY?Y{GyBJ628n!dg=?a8o5SydB$;Qdh71+u2=MFLbAn zy?6V!oc^jC3VgPdHK2;F2Tb<r#)}&y|HqGrpk#$SzTw`5RWdqAUi{Aks7VMBJfTlx zi`o<0LapT2rT#XBHx6T3nII!_>u-Sb!^L<H)|hGI2@B}GkZLELSBM%zj!-M<)gF~S zI}pPbuRTiT%rO<PfiR<>zK+;CWQbo*a6=#NK!p-@d_Mqb?nt7%L51#EGrRZh82Uf& z-+kk87)ird@)B#vw#8t+cGvy(^YC-A%fjZinHGeHSy4r!K-|%JvJ~S_NSiJwl`!5c zH^d`R2eC}QUk)U?e)kYvq*45w4R0VMob3&5tEI{%MO<J+<l~pyVb#(e^XI-TaCS6E za3WE}T-P#oT6HK;t|_sheEFU^;BtZUZ8&7_VKTpb(ny10??C#Pp>0nIBj}K;$=P#Y zyU~I-L}2v|11I$exjL_DS;TVpp{33Z0RTC#-5)LO3LU;5yZS*-r#V+TcQMHM{n#T1 zCv>!4GMa=NAR0XoH3?@<VETrY^Yg$pD`d3zS-+F)fJ#|8ih`3_vxHhE;VbYL%h+Rq z2_{XvhCvl;Cjn+ze0`;ZzXMu)*%80Fd9J_fZ*A&C%e};hdQ^VVRK}lpX~Tg%Kfi$f zz80=?E=m2zcJR^vRheJO)WOBn$yveC&e+t+$<9&iPs!iT(c_;dvj67xUyG7#MZSM@ z$NHciRC5(V&{c`T(mT`EOHe~Y`3J48)=bz_SliC5$%gq&^%L&KqC634kYxogba`|c zZhL$C_<0*4a-2~Af)Ni|2slXENx|C}={iK}Lb|FE(}S_0G1k|t#gwC|%*C|TT9bA7 z@?_<pEzG8d<?~H%jP?=wrlDQ4Kbb1H$9YTHi#9QkZrnfAGBdk+a_9rv>cSt4+V8%? zQ&*+&u!GNlYtpY-IPXIzodRhtv@398!zjvW*D-iq6ZGaMmxT;PzbI%Um1{}aldBP} zsiZQl%_+cP7}L=aI8b#D`gdTzGmUY>{2>_&;6OlT|DI(0?*OZ8Z)$95W@-H2;s4LJ z+GZ6Sy9FjB-_0ZwdVg2^I)L6tzr}(LHX)Lbu!KbciqcRCx~#WQ+i+9*JQ=5D^9OAl zd))I+#9eXXY2pk8abS2hC2zN$d#9dzW52i0Lt3~h!)`d#R%y;qa=y(!4XX{{BmKIt zPgvum1e~{OKNEutTe@e&H(}jZ?;FZxLzIr0WZsw`!2{EOe+;hG%^GN|C0~a!OY+pC zee&pElu3+|g{wqHvMPnP8`R~7=Br?572(;f$Deud9u+Wl2MXpH?U5@*7u`7yLQ72d zk{8iu#(vDo=Q0&NT2k^X)eRE}JJ5R4V$<00CozTu)~GOgaO9<H@u2Xo9*nQJe$!l( zH3brO8}D?vQg%A>WX2aacE9PA>&5}=tRD^J!0lb^*xE`ZA#Y0ObYr3WK=)t$eIYQ) z`B=zQznicX9wIfGQj1&veoV6B;)$!uYLg{CGz=%jj!`F-mEpRBRdFz+tzo?SIWu@* z8}bsKv$8;+fM7rWl8uKGsJH@Vw<Lf2Y5m~gKAce}XqPUjJ}d;xHU&06F{>||crZva zt3O1y#x_q7ZxdJ5mfN>^1c13Z14PAY?&3w`pg=i<i}5VbwncfIY_$KV)MVbJ_P5xD zy+S6&>$C6`x*foh$nw{D!A=Xbut8oK^~-)B8N>b6oBn4*N+cO3^!hN&(CG@!+7*4n zx!LJ|(P7<S$RdgVcq7>#E!O1!cW?YB6;aXtN2BhioE@xmG6;+oqXPYEWZmr;BphS3 ztOO3=hlpO(!l?#EYv=hD+O7U6su-%@5B_m?*R{M;(dhNiY!;{KmmVkAqs*7r%LUA$ z`WSdrF1kz&!LgtCi9V*Fl@QBto20)8)@rI-p-!b9f5ch3<BO)*tkrnVUpK4PF|H$c z9ckyFP5VP#SY&guypAG3TXmkv>IZwysL%VFPL%pns$zKxDob2~U!w?*+I7~z;KV=) z54EMzGoEPmW8O(<mhw^F6r)${ih!&2bB2_^n}c&e!|E18wnI%xooi%4O(5H@L~N|# z&5hsZG@eg@b!&b=H!OTpQ)2O%j-3l?Cl=~Y$~Ay4-kC?894S?LS^vE`D-f)JH|Ke0 z3{eqO3=kADe}1a?>R1ZgE8F9%C6ridBBkE^V4D(KR3K1JV^^3cjCu2ZPvrZ!0|hBa zI1j>1q!*=viwL~AVYF({8V)}cA`Z&_^3Dl5G#t*EFCcBI%dy-bo@_h2Y{C7$C-v=i zNs$KELEPDNe#N^j7BngD&^*=v=zU+Yh?hWCPt#fxdvtkPfY3dmA1=0i)nhawTm_YK z7X`+eC2fG$Tyz&gd|t8Y6S@2ebaw^de#lD<EZzvNBMDV&6pt(opx(prTXA5?-!{^Z zsD8md9nkuKOBeLzIMU~x>Dc8!{UofS-i(NE1x&PzewcU=GTbAet!<CWj^Kj?U;jN| z8WvDq-TlczntuYO!T*JeDmxoGn_B<LQUA+Osc(fUi1a1PFvbR810<_iEiLC{=qyzt zk|^C4HxYr+%2JDZuVqO)9y+>R*$BOH4PNIPAba0{KIadvJzNM|)1fuk|9Sg~-xG(^ z+xb&$Zru%*l_{EiYY=bBREyC;PP8iS6Lh06GIw}{PkKo`$)a|s5mlFhh^}3!6O~W5 zAXRfL=~g254YcSMtdjZGuyDVlHY~lctIr!pf6I+aRSe7jL)$xcX}T_1qm{O8+qP}n zw(YF6ZQHE0ZMzbcwr!kTy?3APy+*(N?(^Y{k<Smvz>MpTh&e;BtTTqNoK+~kgps7v zYN+BYT=<#i1m{60`B|58NuJV9%@=!ASuSi}J1Js<x*NKHzlU%z`lR>;E%%U@pa;V* zF36H9Y(G<=hiED1IB0$w<Bf0wjgsEcHH{4&k>8!KNie%KYE)b8^oBji?5NLa7S0Wc zk7?69hYgfTqJ*?c8~vyJCg-h5K_I)N4YRuK2++aAMK6Ed>(?0%!wFScfrbEv8dV*` zzycFb9eC3X*1A0eSE>w$fQ))t8AsakL#tlmn#(d#z!H7p`+I_jezsl;V5~C&$D&M6 z8eLyiyTwj=(q3%@=EO>xSKlua*^MiFw+mp7r#XnKTA~5YD-l*;UW1sY@vz!m&O?LG z9FPtD$_096NNxL`zE{S>caME;Kg&1{tV>c<4Zp}2?gf(NEnJVyKI#RLnlngjS<6l7 z221RjzCgp1zp<(;>0&u4zaeq(JKl8ve~h>P1jBXP1%7y*#3EJ)AQ>cbcv=|?e{D&c z9C*sz;sV8Deg(~f{`Fyv;u`Gr-<gVoeAhqt0O^o_4uV}Pgw<QIkfX&>zUt3-9%eC} zrLTUxoUOwZIlz?w;FthOwVLn`{ECVA34M9oT3J|8C_4KWCgLK^FKK4RX*{(j(62P= zyjag(jp~azV?QEi<d9@FgP$LBIhZcy;2@5#OOl_A(tG2&qhithhEKT-XbC6SXVp;y zJ^Mz(u_!eey5sbIwB;OTxHs8tEmQJ9AdEDc7f*a47LoGXT4k#sL%9kCl>Q4#Cp~QN z1q9ofD7Ig!ZvzcWtEnl5&4(ib{qN{G`rI6iMYYy5FfNM_#SrBQ(Z}ZSv~m!L?TO7! zYX#B}cOea*b%4PVJyzCUfxQV>u8T7VJx3bR&m6`E$LeD@-Y8Dwd7~HHmA0yvNbn}w zB<DFQh=RV2^g&>ylcMUFW|xoIDR$YDum)#*ZW(p#HNR6Oor4h%p-i}fG}O9RorOrW zBegD6W-h^FW;Cj&+~S5)5q7Y9-H=3-2Cp<e8CM-M8I<?{eGWw;v|vNTrrp?M&4CSn z(CX*dkY;d-itLACONi7Ds}=D^$8C-52OIGV#;Bq>gzrJsBjYLh)@*AM{x;Ohu<71> z4!B>q8ttsA#WpZ4vl;ZnV;>n&@9~b}o0}nf#U!fT11$_qS8T;Nqh^F8XHeRUm~>#N z`9)))F+7C%_pYGg6j3SeH!5NS{hzph|8H0De|tv$BM7S#WTd{=Z9}#!tc)5hKSFYl zMeg%BJdYKq!Gk58P9)S<7)pvHHvXi%u5dpCy({c0M+6{3Ep>5oap7?_Ty=Nz^yEb; zox7KLsXx^T{D#VQ%&KczAzcWVY)o=Z_s9s4?~qhtMGOCxQXMMOuaJrtYORyj5OZau z6L)G5S;rOqfh%M#d=8oIHgeI8S&pw@f$Y8Uhugx86jHh79tdntz|av#ot21HKp>q0 z7HUJLfBrz->2jAkd8~N|wjqCRBLayO`(5|ZdLDnrd%6bvp%#Lx#b-HYHq&izm2va^ z=D{>f=J>sVJLn@9#VfEV^Gt530$30tQ3NF(Zo+V7umW6duz~Uoak&oPdi08J!UKf2 zLQt-i{J!#&>tD-}9)d2x^fxRpd>j9NW-9&D@Jjz7u_W&7Y%gSIYx|evk)7>7%xx1R zU<oJyFXG2>N<8dO>je1CN&(OY9rVX%-|k*O-5ZsDm|ci4n;--m%@?!`*cL<+>8t(H z`^ep@wIfd3;TXanQi>oj*s$NQSMsuOA9Ee~NuOQ=`)Dj<LBgg19lU?1b>Jd}Zt?m@ z$~c@Vh5HiX&xx29hVdslHeEyl1RX{wQm9E(Q+u!ub!TUjaQ|fJ#_zRuo=hi|khS!~ zEt|{W`-7&@*SkE*z74{xT1q;!AXHN=9ReS~{KCW^$IeYmp8l7-iYnl6)iEP~TMuu{ zMxdYiHjn22%{>1yIr$eRYH(baEua8&(8&7+AV3l;2@Z0d3Z*4H2p{4~(I4t%2lF;9 z8nE3}a(91j<)C<Ya>#FL`@swM<I2-X6yvKo6*ICfcyv%?_?T)8&`uZEpR~ZaY2)yi z$T-unI<_gHf@n6^sn=GQKCO>>7b!ct=6rrpv59W+JL}R}WpfFt>8HM1b{A>)H-j{c zt6=Wd8p3<OJvVGv?0Y7porie)n>GV2@pC`;JMPW(2N>sA$>VpIRUcA9c*#~&6>(lQ z1RWF<3AO-46(kkG55Rv7o+Ha@M#k^jQt>@uqWj-!%RjC29X$UCqkja>U*yQYip6@X zLq=MOj6^H4rey2BCeSWTSSn?)I6^X_vPx&$bONoUYjjsRp>H7BC!lWG_Rnu+Ecgaj zCHSHMR@F|Xy>utjn2{|%?~f4V4EMMpz-6b_;Am{y!mPe*=u6Z1KAyY%?&yeUN}<>A zI6*!Wag_=$=;f4Crx0&3@lQi;&g~tkD}C{JL9v%j`x&U<8@YfKUStHJuEPGGXCOI# zqkqQC(LuYhZmz>ZFF(zH!@T2E2kK&*Gf<0ZyLlj!W8C0eK6s4Q>7@hgRL+S@uu+_! z#Ca9ckdQnz$^TmN*u(L-oJ|Bu&4J)ZLtsEU0MovTaiL#^03LXQip$oBgHA(sepzRT zWnSt+U2qL@^fR+lF$=|T?4#oi2|con?}J4&4H-c@S@|JNLYci}(#&(?p$|@k#d7Oq ziT&!WmF7bJ`O?e=6A?)5$a)HkX}<Q`dAne&PPj2c>W{UQ-ouH_94E|XcyAvgB&@1^ zdj9K{mx$DJ?1piW#pAeh_fbbF5<}HTbUd<LFim(F&D7;ni^}gD`LFnR!cR|K25!!t zbK;<|oVg7$1;qZfyjo{~!&E?~)44wcGsTH>9C}=!Z^Faav~xT-U}z_R#X}IIMi6z> zg(NR2@rl1+#D#N2%-U{1oS^aKiHS_0OI7LAgI{LES5Bi38O~!%ks}u&z$^IqE6InI zn}A94BdQ4{8GJC*?2{>@U0_zqU0G}cc0fPuhRdw@{x(XY1s#i=`3^hY@8tYnw{HF( ze%}aYYVl8^cyRPz+zj-fBRNaeLYnzNG`(KJ_8I&HLU;Ic5zqCS9)}52x7EQ}v$K4- zZK3e+i~Iul&w<|etx0d+YBq6)z<7RIdrEs!dg3UVk5TN)DvLIIOM{o>I9-{;ASk7) ztn%0)Nhk9tHx`22m)J57OKPNV{_-34z0g7s#z@Lumz!Nlr%r_`LQ!n7vcQR3O6B-) zp2>&M*q2ez9WQycW3jg;wFX<z84yVi6se!ZMdf%$*BDJE0=R@51?Z0ifE{p*+4AG2 zH{2&)+3vqt=#hdUW9-{Huis_$e;u~{!$Q(_Mh4bO&W<MEOZ5K%_y5S#WF;B9?>zNM zEONlaQXCh1A#bG6V*r^9-BuhdE-2+!2&81UO(AhH@tRsI@9zmfq68aE#|utts+LSv z6sh0GnOT3zF*9rQ`}%l|=EUu@8|Y&}TX7iZtC;vLgVs`asQ*VGb=Dh&)ZjBi{_5o| zXt?>a3Ow64t;}uDy=)SUAqrjN(u$(M$3QSsO`nJloT<N|o3)U?ND#M7A5n}nS)gPx zp0RI)eND<FA7@`Q++BWK3s_7h3H#{$wt!7U5AtborGEUDrpJ#wMi@Ta82KC)E_re_ zKUsA>=u#St*Fpnv=LGrJqC-{ULdKJ*RI<sM>bfseJmr*7wlOR#JKk}9yd_zqjXKX> zQmoA!uBN)P{rUjT21#eu-4>VN;hOiIJ=_z{J-2h6usfsO07NDeap~%xhF6byu>Q5E z93)gR%B|(GRD0oTug@xiWaUfOP!|;y6`q;W3Nsm+G^GIA3~!xtC7{*5o3%sgZE<Wg z+;`v)@@5^~OpxRLy(KCL_Ru@*vFUIP)%S3t?7i_r2FoD6GQ2_o_qVvaV9f5^-%T6= zFr3x~G%HdXCKf%k`fYW#JA||hZ;XX7qBYkYiqF~~fBQ1n_Zd|Y{tgbLZv^N1zoWOT zosx@@`9F69MBI%`?EmWtkgYKFt+s%kbx^A*0FM$42E(?fuOJlFcMQN{7#B!>)1D-w zq0~IpOwyS`hV&nT3-9E(()75U-h7GacBCD6xpr6L1raidYZ*UXfJj0F@f-JT<&OD1 zPwQRAdTlWrW#m8z)C^)f;>FcsV=YTVn>d9Ir71CTn5xv)X1ph9QmIBxLo_K%>(`CM zS-O7ekG2#eW}7dfz5aaC5sa{zAtjP^ZS)H)w<iY*No+2~iG16@g|uRHY_iirwx(`; zV0OIn>DY52@^T+o>P30AG=$<SYJ~{_`H}?&a5D^S<A*j~iEN~)IasWIU#Sl)=ZqAw zreFL*357m%Vd{gEEuVkAIFJ_&;04wHEeL6Gim`@BZ*GV@QPeIx3Q~`_7~Qr1N%dPw zdR&pk$UW1TYjjRIW3DcW8(t2iYH%c?-t^&b403a=i@luhtfl*A$5Q>@o%1j0s^X`# zppMK_+Xxel@KZ&hlD14mlN`XWS}|p*ny?)N0sdhI9*-o0ltD)49o!cyTOmuwZ29X+ z=;GW*qO7=EkSqJ-E#7OI=W6pV!SCzs4evfb3<f1IP3gKa0{D=TJ;Vc~r(9elk_+;( z;&|lBPyx06NqJ+WAA!5KAdN@)TD%Vrk`fwdJ>+iw@H1h@BSpz%ma0Z?31)`ArL9}3 z!DnXiY{PHD=fh)4_hE9##~*RvW;=UiqDF`S;0X<y$^OI5k#M1UNn1=W^+y=FP5X3; z2xdg6g*p`40loH*BkB>zLyXtqJ1pq2UvCLa*p=$AdbZzu*B)EzwMHgw2bqCQdT*(! zy(!~5n<b1I=hVbs*_F53xLb^vuJAk_hp)9-u)I7uSKiJL0pwz*+;J$uJE!ikCdeSi zPZ`hOnSPiaXzY3{AL5*{M=CRs<Z_uXTkP(&E&aeX2T~pvR<OEDFy8swRK>yu_SRB4 zlhn8Dm8i6n5=`$$@RfZ7LR_ltD6&YI%4bR6nE-{Jhe;=k^SXV->)w>w2DGH0@_U-W zxjd+3YtzbLxo&pKC(}mUn@#|6n5W;!zOH_otWF<d^~y$w-7SdJMo#{+s$6)X1$*#< z@@P)yL*3yjX3QRN7n`TO3NTkV0;7;xozDThWGV~v9vMt5LxsM`08$mD`T~742F#iJ zc-&b;8iAiUkA%Z^M>CBfiP;7kR*UD5n~ZL4M-ckieuSwLI;76#=rt~M!ppj@c4C)1 zMf<>vA=^QR&rxy_NHQ=Z_CwoLH0PF<R4kcP{8lfz&nu|FV-cLGpfh@2{5wjFF*+vG zeO8s^mzjB!aD3FT^$wK!4izF@cit6K0<+8<^9RQG2z*xY7XTzEEn)aX(lO-pykz9| zH>5F>-Y|(8omw%t98$gN!TTHvC6eRtk~hK|8v<H#&<+CMA!ozS1w$y_>x5ul$}WWZ zks7mOhzvm+y2i^+9=k!brAfi9@K;<zjJXo5Xa*H!2+}S<5M5hW#-(@)AFtyGM=7<5 z%yZ-1iy=sMglUwAK}e5R<TtDB!5Un;!YdNvg$*j@`@0fYcEo`x65N~SkpuY38D$J> z8=#4$kh<m5ppkv{&jFhzCJyO9XUY1e$%r&8vO#{!Pq4B|G^bmqO#)WQN01@ci!#U! z3<lfttt{pas93@mwkl|kM90xZW<Cd>yHGV^7oyTv<m%J@9fLIkw|@kEr+4G`?|&x2 zJN-u?ru#>M{zsbs_vZ`OgWU=*s41upsH`g}t1GChD=4feXwCNfe8IkQ%Vd_aDCkYt zMpj<H{`O+QuSLS6_s+&i=dP;3U&5lG7w-kmAA<pd`%%gt5gS<r0mdJOb(B8RG*Qri z_%g2?;T|WipAs77V<b_~j%lF$&Vu)K42<-Q^Z*P@K;ZO@bw4CXK~?`YYQrg3S4{XW zD+S-^^>4h&{`<f5mv+iOpBxENQUmhv!7~?BtixhU&6YkYY)!lYR>k-t3e>d9!W%>G zOH>w)5{4(Sjzr`EP~RPO$*fG!BvwLOQ^rIm+3ug--rZe9(J;y`#tfNapeQPb%#&8? zvvp+#;Rb@hVp$V9V$RPwRyrK-89#LxlZ4^Fw|#n6n%ba)k3gZ@aCRc<`r>M;bC`@X zHd)NjtsqkI_!?_l{YtcxHg2saI9j~(58cxtu7FLfo4CK08;eY~92(YLy)7~Up13yH z=+>sg8|4b~PukdaAM0qcZ9>NULj%jw*NO|sNBh(U#oUs{QoO|#NUt80uKHSDy5)P5 zjdP~FDvdDELk#r6J%BiGp%3|L4b^d-?~C|EtiHlNuy*mG59Giq?$wOr1z|CllG?%Y zYQ%V;N~ViA1rsH*%WXbT&M6Y26{kcd7>CO+c>snL@?^gNNR6C`BFJ32ZUYuuv|^j3 z_RB>figPGs<>i!u3V6ALc7KdADaQKXQ-$Lf8^<~GjZ%7?_V_0m!Sf&x|AG6J1I~z3 zZrc4fCqpmI7G!+C8$`bcE&q1hs@XYO{ih^ywz8Je0zW#>I;i42J{p3sa#cVh1xWxt zWEk3T3>=7AuYjJA`ntZYtrDo-hX`jO`}6kmd935RV?KCNX5tv>)}gmqPs7&O=jYuX z**y79TLASiXC8iS-Vd34HW^U`0j%K$;IvV}kuGXd29mw*C<_cG=v%G<XzrVMgZAC< z3ft!pjlI_xBdD##Gi__9{2rHcl`ZYa0Ja?W84-@@3^Q}RI&CU-<Fu(SI01uf0nJ-h z4k5K6#}~<g)$QG;dV>XNyCEhRuRrjr=wykC@(riZ#gSE_E~f9d-Sg9wa4Fnu@HsY4 z0?IFfP>c&s*fTPtu-n2UcR04JfE6Ys$%pJl$$sY7p7eTU))?y{wpg|*eogg5Q}~pm zFOzXxi9a9NQHSYWdFKqGV|LzBv`l7a#yu=rGl{J^WWk-RZYC{;NF;((b<fi_;HYP+ zC*1jOGFIS8>9h<QKx3W^2{+(SbkbDj!lf8-E6{sYLgt(-ly1PC7!Osbx9g)sP~@(a zhnY|UTZiR4{i)E~V;@UQP(rinax=Ir%re&d;-*6%arw}U7P5Kvrw3>Z(yUKr7dqIz zLuz-w^wYsu?3{+|%QSpm{HEGb!_vx}^OMJZfB_cp?W3De(TM4|7(PG%a|D6m21>fw znG^d@3vi0e${4|km=qlYB42Q&slJCSqD3eMf#xqTAL8$@a@vEXQk=%l9S@-3d!CVD z7e=0^+sleD#LaaRHbveaks5h1^I<ZSGmsh><}*Q{9QqZQVeyDH>WKHuHgk7JJ|-(V zz%dTsGEz)R1R@6GP+;3XDQ5HMphFcY55PyvaV{{ZHS8k1I%Y3V%(?@yQFJ6);tkU% zatU)f6{!+7<;5dpY~WTqJkkAYi{sk7E%mSF570N7vH!d8uzv*lKX(TH322Hka^HGn zK2S}`5d~$>@#6gwkdjC&H~u?<{o(HLfu7o@q7^nR8jz<w^GM;OpFjMP9NrKR5v5OY zP2Ik=<GC7`w)pV$Mt9NQI8*A%4Wz_C*D)nAUBMTj)*Av*1*+E$cKeEWn?feN9dLHE z4#UDBkPfTQv|m)|95Y07`7Q3eMCFgya67O&fJkdjdgJ2_Q?(XPlng?B5tRe-c?j91 zo_b-><fNU;Q0#Bkh-cr~W$n`#g#xlha*S{Q3oWU)H8xz@Qm+lm_D^_tQBlu+8>}7h zHCS@bLre(`(F%Ovi3BI{1SEca0re?VV47YJ7r0I%tZhI6yJZy>A5pyVZQ&NiLLzgh z?~L<LBQaZ~7Oy1uie6e)^MZK9UOLU6D%|rsj^9Ej86vC3#VRXT8Om6alk4-$aV8^4 z@8`S;AJ(vnJlc?!ilQZpQ{n|8QUpYUtGt8!tH0{>R_xNgfobY{-0{EmGyhpo|J%pz ze`$7o4|EmaKV|8tZBn(0@!bWA%{$~#;cMZ2ddrp~f-rZ_eqpbZc$If(1$<)bdEW>i zRrZ1D$-FBJbF8~)P==TPadw@aeCeKMWBO}?;YO^`=ZUI8j$uqsHyJ>WVu0EpU!OF< zs2bEpYoO8(1Hp#j2$rE?ZNvUZRoGXj>9i42(Zt*}wj?y+tkqt@m2&X=RBB?w_QYlD zAfstYuchtCO~DE}{S|B7&T(rN;}<~wq34E)I(KkwCe({yNi}}6Yt%AztU+UQEsnY6 zI-7KpsXOlh*n7ziN-8>KDLvAVz~Dx8BW@6|{hvCRFWi9+MZM843vs^!FOd{CbVaOb zTr>1?4Aw1ct&R<!{EH0au@!6`CO764_#^r>L>Yr0f!a+rm$qpcM-CBXAL2B$krJ$} zUuGEN#kUmCNQeb6=!6?gmu%TxGE)T!!w^`<j4U1b^E2qpt*oLe&4bQuaweQM>t^C9 z<0=*0IR@lO6%GMM9dFujhg%hEUhi=~5lFS%)@r8lFbg0O{irmNff*rNN%o+JO-9iZ z7y=Y9j7FteY4#9lrCN#hXiZJ33}R3#Yg6VD9#zNa?_z5}GAzcSKF%QquE#|3+q{Og z6myD}4Z=SUHP-yG6-S}+_u+)RZv`FBh3AdPPNkeB7h3!wIOP(aeuU#QR(pde9de12 zL*Wo7OM+3DP%a6)BAFnuOS$^f_Yz6RCj<Fq<Uql5c_1(m6iV8~OHt*<zyAjE#Re)R zqMsrIt_|8204(j+&qLFT-T@<eN0|(Hek17Sf4+wkAA5=m_5u#y5rSJyMAsl7q%x!> zl$r(F2Oel6f+n5SnpyBSEbyW!g5OlpF7yU0-uA^fI-vngg}5#J`^01qwDp$`?Dxx& z=-;cr|1Hq}fk<8I5Z+o3K3|{K5^|oty!N}qkPf@>VAiX@437X0hzTHUama`@dUq-a zd)N(s6-hEWn1kJSAGZs%q&%#(qu5n7LgdRTqCq#xfSxzFcCDn$&(FIi{VJLDGWz)3 z@=D1?rT{B;;q|!s`uy7R`FePk%Jl_b0-pfIdD=n3<SpNci&<i?a(eT{QQHX%0dqEI zN9=X=mK<n}DP%7Z8ganM9TtY+4FqH1E-J)LJl!*Zi9I$SEX3rk+;QT}upf+_seFQH z@>8#tJxvSuTliMqh^5k$Gk<o&fw~6C*6vmh{2EMU_SP67^cK1BR;lhj99dZ!VFMie zpliCD!t{pPs_9F7mW9dbcVqFE6H7(hqu{RIdE;!q0Rp*;Li`N%eJ=y$8}_3joT(U* zOA44dd8WvD+Vf+6pNv(4+&wzI27#eFRgWb)-9tOQk$QMej?vrmaJj~Mc+qNl&E6G2 z{5l)?qL8I~x%uKoJ|<KwmS`fymFWyPHTD#roll*H6){X#_wK<6FAWV{DAx`m6AE9H zFQVgVl$7_v&m7HMovL@|&E_EwYgG^pO<a}cPGD*XS7&sHOpn%P%IaK;=7;=qV@#cD zMWR_5y=+<7gm_`fv@V&1lm0yIy&MH|)z}P-cK-*tg9BA!n0!PuSeEl=Hki`Ohbb=t z+OsN|V)(n}>D+R+*7j-|E;Go3Pk7QQA7kgr<YmN#jALm%9ZoEX+Xy*cPqvJluOA^9 zc<Rc&sa7On{HPut;~m%JN=#Z?C;qA`=z6n0LUUjpL-txKx~7R$vbdP1QhIzROnpTc zG)ZPqp!BB7VOidoNs>&V15=`0krFrZDf0@U;JG+0E9R=l3yZCPiADGN#+&AFid5bC zfq5bL?>7-@?TR^tbamEJ?lqN=Kp)krb5|?5a&F10RS`>_h9<jE46Mc&l%3!7e}3yb z;f|3d#CHdo&~)Vy&zzmGW(MM<1pxV_T{TDV&zyJeI+N3v=r@cb<wL=NAEKN{)_5=_ z_b{elN^7>d5?<0fVN{63ZaqU<?m$-Ac-b-Ty{J%DHbS>W6W>ur%L3)??42Mp5%pO4 zvHJ8*S532`=^NyVQnpljw^C%vm_-t;!{ljka`Ah8u|swY7EMP|k`{6~a643Pir4m9 zt<75un9`zQF-As<xKbAnro|f}+g^0Ex28QNDV<0!DTg1=AYYq7Cl{{$aeXYKrkQss z+8@{MJJZW)qT2m!vN%j&AHh&$y{emUyJ%eUvuw^|p;$;A%34Jk#NJEKegz|`lK(oH z8UrPwx7rUg@ktfAH*<CDS$|1pKkIhEtR&?24P`)h85_CETZ6FqDxYgofr&SP?BT<& zU{n!>nro>REk`Kvfh0unq-xxX(EV|E{u~zyvU$y(-cC1XY8W;JT}Dc7DBWz<@L+;d zrGY|sGfdFw`8;2|uJz*HaZcCtwH)&TRa@C}Hh0=iHns@#&rrFgGeqRzsrx)e{C)OG zy!FOLmOP5*<4K`RYC(DU3_Q$}Jt;R9RNuQr+-D<*b8y=XsN&Epd=D`6IYKs^_Qc6< z)KXY0!&+ry48}9lY;g7w6RWwRQ5Zo}ghw{%LkROINCq<|qmZehhg)FNS+ofz$fofq zb^3QR)gp$`I0hI)-0T9*`mPxF5B)E@+zf71+n711K$;il$YNorWZ0|U-StD^3+9mo zP6vWQhpV90rr~r<?Q;?fLC2$gj?RY@fYYr<47<&Yz4-K=>4F*)m8P-~bB5bGtwM>x zA=<=|z!yi{H{|E4Kpgup8q{b^zNJIWoE=iOURC+q?mVCUy_wgh!A{|%HX)5t;)$?A zoFr8esRRfRP#L8o-CBt0qbWRH>pC=paU_uDpC|m6_bPy{So1_uFz17`%{Zl!B3k`c zEE=Yxjv5Brf1ag)7|vO)eZRlOi$k<a`d<?O>yUzIFqk^%vT;g6+Tz`_fcm=Qjc>P; zkRnH5*t(NhX}}&A*p-;kS(G-JuTjG>pS3#eB+n!dMtiecCwj@#cv|*gGO8Gjo2nGn zuUL$$X9udg;%#V3GWA%iiCu0Yn_FS(Ijy%XwTX`NwmPhP+*W<Bei@aY-K#TRGi(%& zaSAO@9I&3Yg%C*XuIAyi9vm%*Hm_S&C{%YB_1A|i?0$TIBX#fFWM}M~HaDea9%PIs zpZ_sIDip_EQffFcRvfE2tkwZzGBq%_qT*`gc%~J<-SUZnxv$DzkWr<OFKN~&A7C_J zQOg(?PX~j1q8FG&=-5E1E<XpLd&&xqtYtfIurX`@Am2G`Ozz>iQgw<<h+!);B&>n7 z`-#!mRv9u)dt1{H_-dFQm5xc>Hj`vAeR(R&?Z<0#1ukepPo>KVh-}^Alx>rhFz%E8 zVIJ%y7`#QPoBwhOy>h3Bkc@iZB~#25dJ)rKgYTN7;1hD@KE&nxXksi2VtACJqFcEH zp_*!>YrH|YBx$$DHI35s#7#)&n4`o3g?86-T%ayqxNvEIM>WRvP`OYgY^x+W#@Nb{ z{fAld?(lrex?+7XIsfQ=AZ>^we!X9{hk+++Y|TbyR{x44ZdtXiTJXml`Ga!(b2ocw z^=|f9wQ;(h{K=<))77ZF#ESik%ZtW`rm`a>-?!3&k+WkY*+K<!$hdtaItbIm$?%)> zbUVyEMwfNGD)N;iTFVh5Cfe=#$a^z&UE@XLo3uhL)zd(O8A0<NWlSNLd~};7JCJ;F z4Y2py5`TXKKv|Dxjr-L09j9+K3HOmYb5Kk_T82NXJ@Tg<f&K6Po*cPsyF4sh>H!#S z3|4O2L96G-GJ#n5B9fH>uxKy5bbsDi1Wd6h1@w;*d8`Luo}In2O2JvCpRYfs3(eVM zpepD?+!wL#V~j)>(eAT*K?Jsl(mdDz1-1s#I5>W$10k6gh&N!G#Tvx~K;QDjv<X}( zXtQHHv<qb5z{g?{bH}_uTKDmn5mhy7!YXXEnTwHOR=WY-VXG9D?cFIZ?lR_xc(i96 zWrDYX>M$=kRt<nwjU;=M)*<-CP}zgAI%#hhrXO+wgEv4sK+hxVsDmKAZIf&W)`YYc zIA9NyFZn7WSh*k>RE$2!5;I7rGCPLJ63E<bj{SkwmD;E>u?@k??Iijw+H&mmoFnB$ zcYe$r6In6G_frH2$6y_(I#g1-4am|{?KZ@EGC<e~3UR7fm?((VJU-LGAF-{?N#C{A zFHTRgGDlwQh#l2!b`33dXSZzRB2_9$k9(o!j=TrE`FSzUw~*)$b>#eyr<%P>+>qZ* z&>d$q5~(*;eZO{jr4DlfCV4>8y|B}lPEk8+giUo5v*PsnS^_Fg)0(4Z3h2#mGE8z& z*_C%xH-?>J+lkooaf`TpbA|*LTV;k?P+FJ*affY`p)BF@e1hGeyH8Pci`&Ugov0W0 zVO|$y#nUCYrli*z(;F$6g3%+aAWcv6mH1UyKqYwsjZp`R(h27K@ihi}!RNpg+Rb5b zT4HLvV6t5TQOG$BSU``kUaU(z+%1YQ&#)URCZkc3Vo)YAsnS?XF$yx`yslAexc6I@ z^AY<cJ5lTk2}+}B-MKau%9vD8VKVZiUD~3NZQU@o)Zzw0-F}5YeBCHs%tokh`Lo^s z04(P9uB;UIfD(yNQzSDKEBBAcQ!SAU&Fk4?=LB&p43DhSL`OQt1jiF8;^UU-nCtgI zQ|bA>b<qKS<zOOjC9ts^u&N1hqc*5o@@ZxI<jg$X@avUUEXP1B=Wv=rpjCYre7+j^ zgkvAEC}z9&jePdaf#7qRMA%6n%rvq|or**@xk*u%8fCXD27bNj8kG4~my*2cgs<(l zIS8w!fZEiYO7&;Rj{IZ@+RglA<)=GDs2A0DZ%?4?{7-Y)QmJ_TPmJgMxB4oF7l*2{ z0O2lG$7*G}r605=%^*H|tyOwHA|A8~u>pD}ePCT=*OX_*&{zfC3{~N;izgX*SM1Bb z@E*Z@q%8!SIOXq<7p)Ijo-DI@>=yABNriCs)LZ&j_B*hcNb7RKz1t+e%KV^R5M9nO z9zr>}0zMra@4$G-6vP-lsIjp|^vjAXz|_j_WCVZo>{jw3Z~5<5R(5Hc&0tkSoF)of z0JADssnD~=8c8w3F9!T{&@RU%Mgj*#PWKlQRWpWeQad~MC~OiiO1O1UkFU-qvk&gV z9jN$Zs5*C3D^aT_42JSyv3A+yELfDucQ1VCYnLz?P}4%?ojlhYIcyDvX-ruvi?vHc zU_bY+ygn{WTzbQ=9LH+SHIY)<lH0Z59=Ixe2F*EmqIgH_*?DSkm-UgVY?LBXl?tSe zv-Q=Zv@+)D=`bmO@JZID@dB@%P;L7OP`26P_%(Ga>%q2T8@ImHg5>+eSS6s#NlLyN zXx=ZB7ArwLJizS%Y``5s@=R^w8-?fx`|-?OxdjojD>43sJ~4$v4ffTi{R+tIPq$n6 zjK~{8x5w+9tlSebBOjUgOe)tsl}+~YfUMj9RD>xf1>}q0a1%8-0A~W=OPzU*<iV1Y zSj{dn=10l4>mlhWc{vDmE6{0PJUYV=dOKxw=;vR)VAZs}-g;^#@*LMBiT1d;U-cfe zbZroWf%&DjcclUG{v7Xw*?X0x679@ErNhczsVUip{ly>k162y^K`GiLoS6$JFQr-S zU`mRLJIc?v{9575&$acBm@X<?+j72|Of{<dfP7Qu$ZDn933u|nHit<tRY#Sy8*<NU z_GG!nN0Lx-<nS!RXnr?@G8{b`hn728bwUAXVnqRAL!-R0w>7*`l48~TC*8T0eTfkt zk)b84uIU`u;h)&<#4@`LPv{RIvDuO4>1?CluD}z@WQl~hD$i<E?Yz@v@*gr~wXass zJpbC1F@vSv_5W_7b$&NyX#dA1+J9Z*`>*Y?|Ln&^$4mXyIve?dN){^z7-Hk4#fHaQ zViJuOMoJKcL%)*J_}&y7YsM$_rGOhA48-e&Gs&uc4x0-iZD?T1ewndz)7#3?iyMSx zl}1;ep7$k*R>Z7?E-#}RxWyG3f>>;tdfT{w^jf@A-fFTFp+dGKPtt+&)@zN2e#aDQ z_BayLL6As&g)5>f6bji32g$<X-EW3I581*Ko)U-HthCW(K!3=iLBEZ;A9~4KK|D=p z;U1sl{5jD@RZ|o*A|aH><lko**IePn4Gm&affSJRbV41DknQs+M;t=20wsu<TxHIE z=e!@$eF?pwUf7BOokTTVR5Ipwc4^4~g;AxICKyrUs)!phPc}N1w}2qo==XyGxrd&v zTOB=x@@s?q@wgb~m?~q5cz<D5FMv9bdWiHQhFmsbMx`aUw?ZpcoO@7&L(>I`K1k$D za3gJi8M0m)mWenkFM{xJ)T+MP9edR-{7t?8^_e3jjf{zWzCY681MzlWW}IXXA=vF- zeR+t%#1Q-K%cpN&3jF)N6f`gvu{E+Y{yxy~x7~r_@6ITa0y0lavov<ZM_w2Rvktrw zN>(ue2r4Q)Ni<aNrC#ZZ>*W2^^=9KO(mO{TqeCCuHCf$$DEw6vONPEQ65G{=m(%nZ z$Jm?i(*-76U9?$EFA|s)>@tMO1gX41Y%~nvN4^t(o>9Ld*F38N=SjJJe{kkHT`HH# zIzII|D5v-%#2a0EJccKw>StJ2q=UKP*4w1dP3Er~*=O&5Ru1`aOBcTK@>{{;&`k?N zKptxruOM$OO#1vq80Mbbs5k3rWxgb-CajkPaS7U0vk`AbNb3AYRT$VNJea|Q>;5D5 z_{AVYF)P*!d5wwwwKp^7@{(1#;7mU!D+EY~jLg}r4#IrIT#VuiG1eaJ1=6Psq>Tl0 zLvLQldClT21KrXMLfn3r>!jJ&SjZqYrwTKiPx+Lq+?*M+5Kzb4rXT&7x8&foqbY$z zNb`mPk&G@u$+ualwawiDHH?Z1x@z$3h^t)GV~fuc14PRH))j^vOiuCx5p_=PS><X9 zs8yz^oRZ>S?l@Q;Pk$rSygcSzgnfJa{@dI9|DU}5Po~`8oSm&GV}<$c?3FSh(h^J= zz69Uxf+X+spZEwBtz{B@h7D!QA5NVNNW*N2Y=u)><CJkCzWjd5C)we%!NuZ#Ihy0h z9=0>L2N$<K1aos0u$KB<(_MyK#G3m6ZdF(}ug7f${64sD6~Y;r3I{HkZ%_N8QJ2qR zQ4ZoIrL?P6#{B95kjX*0Y=g?xwzM1KTevxP&~AG8WtfdAW|s-2()3DmDtV8J$Kkd9 z=Dw(nkJy;2FAZWSr}V{;6{jAfES@gak<OkZK0*5zUCiq9cqDkToMmSnZ;uN{6bW<w z>{5ozh?>HnpydZsI`hIgY5$WSgB7BqK|)4dkE1}pDm%TTSgQ4O6IN8Q(Y#SPTi+!Z z)84Ha9fit!;sN^(Y8~u)zgGXqmmR-(6}hfzN{SqwDw7Zj#*5ky12m0&;JaTY`eQ*w zsoNpaItC=%XWQ4uxX!5wkhg0Ay=w6~`bs6INH8;XAVo?T$%~WytT|9zfoSEgB$5FK z_rC%O6X3c7*)-nR{xzq6YK>_1etY@od&u!WUtaki@%jJcVx9juT+m>>>RW{@JZJ|+ zP=xIAW{ONhtb&wK5s$f9I$+FYx~gMVs{WNsiiw2x4)9Li|Hon=Gy{_Ne6s7WlLeEj z9Ne!jP)hD$2Z%N;6ZQ@x13Ylw@)(-mM3BkO?GUCa7epLT?t=olz#ZQrB?Rw;F6mRC z^1$qcWtfl?GfLHxq1g&O^re?xICuCPcIbA|O7;!)brbvbu^i(vS7qug=tnQbo};cX zN;R(V?K#>N%9#<7m3x(8dagqs4rE3a%5aSL3-*+DoEz%I#T(;-Dp$cNLa>_mY2j3= zA|j!P6RUI+?nc8;_!)X6$p)w8zK2&6ZfYljFu&qeYsPb#M~8&%iAm=W=E}tn?96Uv z$+$3E##zB`#kP*61%}w$w^wrgwb0OvP?C_5uktv9&Gym+{kMzsQ^AibIl~7-rwvRV zbF?2HIojkRO7|Y*ip9cnT<pz?7TnJOrS+dU=Tyb8<Bik53y*-U6}rPAO_~(Ayp;j4 zrVwcw=CENL$TLQo7<~A>d{xc8f!-VixdE*;1pOB2NvRD1R?5$Ew@Z(DBT>BvC>`w= zYFfnk!285+bhI5NM*cN4VASb$Tu{Cj^S|ph^}h`O|L8DhYkKG_A0XteTHorj(h+FX zX!k}y5`aNassQ2o<Hy6t0SgX7W=;`lh`X-vuv^<KS@K+$X)4sI+(b0t`kMj`My#o7 zt!sMyUel_sM$uef>u4_SdD&d2(ja&id(3>&VcMFsGwpuaKKR0MPjM`pR>;3oN2}g* zz>HmS4;V($Nt!68wcKIMA9tyVYn~U8&Dk&DYGclAzB7JFC*;FL%k5QS;Z;~m)KTtV zDDr9_R+(oS5ZP<f^t5EIaZ$in85@y)DW}^8%^_K&pyf@LTX1&;@QadjyTR}-k&hOf zqS$WpPLVf5iwm7`xM|~_2^P5%xdg$?Ju1LNs189p?G)#nS#htA#B7y#*1_kKGPY=# zmNID-@l1he(msMJ)*;}lzFj!nP41K=Z9MDLJc2#x6hC62?M~yXxg(jcS#r;gL>>EF zUp?EEeQaxul+kF`^=&_B5HsqDWV4Sw2EfA-@#><z-20xdqJ=&yqUnqptP&SEC?g{z zUdjmCq!ep0Z&uuy&}vR4GJgh*-bzH%xhatONv8N{mQe-mCEt1^*L_4)b!+<8#OKb8 z&otdSWtY9Z0(SpwLAj3hPJG{}x}gC<KAahwspi}wMY2P~@zyQl+BfSs_bZ)tljsmS z%I4gn+33!@Lv!gCJMv=bmOIkn+^W3;`n4;tb03#>PK{8fjLKW(&=YC9FXsH2FdcjP zZjz0+@Zyl2JNqJ$?Pk>}w%3KpSM88xaqexm0(m!|h7nG?vCAZ+;78wU%nSl(>Ml^r zhR8r9y+?0h(2I6{3)a41iV~|`R%@-pRqG<4gp}Cf5$KlK(!GLpTw@m<Qtu3_v=g9@ zkN5yuP}$kVkVvtD_6Jk&Or0rL;_e~i=cPGZnSWc`3SKY2fg1hts#P;_H;W#9-5j%! zKFIhAR@CU}wkWCEAhaFh0L>=vebj2F$6cp-;|R3y2d^D6&r9aiv?@!Wg{Kq!hRzj? zhYyeGM@sjm{is^3fmPt^<Dl?pCK|*mYlcDz;u$jlljc@MJAK+2T#z9;mR<Bq;DgNk z&w-3hUJdLhk)<GrF^CCeIZM&Olrq{#;pT6RNKdsO@8yIf?d<x8Gn4#fBhQXW`Y7gM zL&V5eud`H7p)_Uq=5wbUwo{V~hee@UahV}WqIsl9QG;K10htCW-QcfUS8!qlcP$aL zPz8NMHZ~InKv87M(T(@e^`%Y%byC)I&=XCAubfl%nP|<(=D<Fin<|@idfgYY!&{9- z1*)Kg_44HCF&RYhU;x<)PEg31Y%6%zVl$?v<(S11u~IWc*1Sf^b(c4Li(+QrX<*X1 zG*wiKIsG}Pl7-gxZ3$un!$W^e7n?y{HLk8qE6O=>_bj?i*P|i54H~4hd)KM3#0EC` zfy*SwkvH+cK{FPkj+d3~x?44!>>I!>zO|MUCOK0+QN;=$0jfz1sV1E63i_f;u<Hn6 z%22h}j0gSFgU@-H){xEvu6cf2qU2QrO3AX5_Na^l>Ojt(kKh5y<n(aCLuX3xDYILj zL4dJA)zuXbWF_wuP0YtTACh0V&tL0@HbJkS^h&8UaPF|DQAkZv;lUO{<AWi`Ir;Rd z|FGFPtmCt+p(i5H2hf`4<D8s_$>kXi>vj}U1)deWyC?(5N5U>4UJ2)#feP)?3I!>z z$6%yUy#YnAx=&!CAn^Znt=b4x?domX$|>Oz`Qc>^+Ll>`yaVjy9V3;w6@+WYOm0sB z*(a=Up55CiCDB2T4Qn{pzNfN9e~vB0=2+7iHwATB<+)={fq=NiY0CwRBwQ}<n2ViU zuIw<%?h%mKAUQ=7E{;6Lyn0XllT+##RW^SxqcbkMd<37Q6c1OBc$=587G;F+kiG-i zz(>>5I3ul@o5>FKl`-{j%|bV|YO$Cxfp=xaD%4laiXQbbJ@P$4c(@4LwZyu{me}P~ z)bJXgXTo{joDrH;@?@y_DrhI;SJqfw?ZOPqrq~sFXD%Fl_Uv)|{`cQmXs!n$pu2Qt zbe~X~jNXwM^eZEe>8#Ryqd@Ee5~knKwiyT5s!5Un#LsAG-q8^2rz`=vdE1h4V$0+p zQ?+&%Xy2SWlSe4fi~KJBA@ZLTR^67fylZyyS)eSR8Q=YQ&yWyi-?{D7XDsQ5k#s!f z@7+qe1ujg#iETR}qIVqMq3x^NN=(0*?W>6qxM!6>ztLLr_l!Qiey|VK#t$Rk?DBIV zr|>?$e79}5iPWZMjCZ9^45dBtri=qw>eA43KLW&0MPJ{c+8^46C$AbzW*G0FJr>tm zgeSGZ7wA|6F3ZWybK5O1W}sgoepc69jvHGT@3eS~&vj`Xy{X2V;KCCiEz|2~TgI60 zUcA6ZH@mc0&~J2i6%?3XecMmZv8@s$j-EPz+S~VJpG*r`bGa_S?=Y{h0_#^;?`WTu z!+uQ9R{=MEVGN%Xd?NQw`@z&dCHMRovOf`+D*C<-;g~;T`@T?6I5BxJzh<_H<XZx< zt!EL6v@>l?aoLW4z!;Pa7|j0oW5@0Yj8%-6;ubHH6sajNjRXVA(<RXMf(-ZMkoITC zIKz37Tc6$W#U=1l`U)$C`#D(%>FE=a$BNw<%=-dCTv#t5H}s%X&(}3PiB|0AAw9HM zexbNi6a)6qEKS!Lxdb*N69*=2OW~k>RI-Cu{zM*F9T*&d!hM|eOP)1HjGoA|ZpEcM z?f`=>GRGJaxG2wOw|wm?n0SUx4yE-G!bqCJaep~aDGRgv58zlEgg~5taR?ipl2RIg zI$%j|^y_D$fu}4AuIRf-+q46VK5-?>Z<>lY|8szkPoMuccS=78#vXXDk&ziixJ#c4 zgbmOy6|9Zq93pS>&K*c62i|gVs;_RS2be7VKm+5N)Q#y_L16-TM0h}fGB1rm@%tW) zsUM!ArJ5!w;(988h$~^Gl~D28aeTiJD&-JKNR{*wI7W6bEe3^5U*}wd@P<cDYXfw& z44z`TjOQIsX)owR3b>91$f)QHH%W=v!~9`8$^@Fb>6CTc&dJ5ah0Dp14Usk4&08L| zo!yqkqjfrmjdM)e&o`57tl3JA@pRb_c$L2O9rlU9zRko8`%imz)CkRBZD1F7iIi?? zjXqF+7iFoP6U39Ufb-Y+?=yiI;qD#95!WGtra#gurc_;Gj(;)YUm|-ln?GzHrrR7; z2#?DJL#ezAYX#bT@-mT|cq0Ihwf1Lmof6WY$%ruw<)p7v{HlQK8C!|U$e*O01SdSj zHSu&v<akkMsnf|j6lxaUVPmm^u$+=p_0;gD8kiw@A!AKqRO@3^ag*iY1cIPYN5iPM zE#OOVSpA+og|?_IMWXd#5S?PLlCoFQBFf0{a+(Qq`xzVXUvD&#qwBVUXo*x=`Vc-& z^D<gXRP^%MAZw1h|EPoI%~G-)=p1aoh>7%M*OQcVfeC1?gNyhgRUx3e9;e}?de1Lz z;8P4wIOKalxKXNfrvvO_@A7qfBSHjKL2i@-=%YCa88a5aCrM=2cTD$mQ=CCu7SN6_ zW5bSad^<RPiB~rxKG~MhfN~%MXIGc76c<!!p$rq+v>&uiSfi};&7j_fskC7B%bVEv zWzD0w5E>*o*Cz=t@4rh=_klaoNSrwx3ljpz&}-bPEOjbSYBT6G)2J{cZC-K6t~-_o z>J)hrIX0lbY}Oier%uHrn{**_S+**G<Eq_^ACBJA&4wCZTFcxCfb%JCHF+e2DAB`L z66!d{cG`u7#F*ote3TUxFq=~v-o9kzl;WRpaDni-iWP*StxGZ{0Rsagty36%Oth67 zb0kyONO{%};3<=6Olx5_^<GkP-s>o8pWOd*sZvO5c035<GP^Ql)(}l2zj7r<^}#Vm zzEq{CJoT<W3Re1QosRQ1gPZ70D%Q)mmfO#Zh~^Z8=I&-Hh5(%5528S`CTMdmqjthF zlKtqFtVlKXgQlNoihdFax5=LB1`nZVQSsgVMlG&|Ec+oyq-@@WGa1J*?V7+|S=ME~ zmjciqu^`@Iwo~xg14XE^M}ZEXQCqy`b>9x3LE9eVme`7Ank)DUpR64Di^N8)CNJ|^ z%iMxelo<e)Edsh96@SFuR3cxcnr6zH(YXpge+GfwH2us%C&*B}IArH=WrK@vFbZ?z z0;Q-WmDS90cH{Nk-N!5n2viqI62m;uUvkQe<VUC$l;b*S%*Yv80ggIhPS?$=t$0~D zwwi_h`N`Q8#;~(4*S0O)nCBT6b(#S{Syh9RS8&=6fT{Gs98D3<GFaZ~879eDalj>e zDS*kvzc<U$J#d;%FOCFO<{ZnJ1<r(G9WMC$S#i9SJ}7clJz|b{O&I2$B10}$6;M^H z>V)JKG`^r40;QoqH-r%<;uUo<TWAaPV(_=+eZg(>pc}TR9<MC(4~KD1`;c3J3V-Ef zx?N`T#|7dN%cCDM!)gjyCEQ{;rg11NZzsSZ!6j>WWaA?ek0WEZ3{#(Jw0J7NJ%{Jl zQWt9y-Q;PnYJB1;t@f0=5{I<{=@KShhqvLEoEKpgZKQOvPBF7D(@mz?m#&Hu2rS{N zRgyTsES3c#BNiwat97QPRD9YTIF}CnFoBjyE?4KD>T!xV-p10AN*9o%@xT_CFz?21 zH_V319l$&+gUezTvP5MrK+Y%sh?xzYocp!|E=(&dloZ=ti9WSCWE{EEH~H~36}WY0 zXzNl5zvjG|3-DzJKpd4rs5A+xBN^Kp6zZ1rkdNpX<EY^k-NBKnI2-3XU&;a=LR9o! zH5t#k{1|^wmRR3jVpF8~BWyN5)fi@*ulkBzUAR70Gy|mR_CwWe?jY`iaxGlL&1l%? zcopQT2k-kVQq&_n{w+QI792f~AfG>951ji4(B~TfPoK1$Bf!NWL}RF2NtZVy&k&V` z|B7N3+bq7AIi8-tn+F!o_PTl4Rgu{<foG1}KxU5GHEr)2!@bUPQV7b+eMLcYUu{om z*}8qoRp9(LVdJ_74Hv3x&A#^F>?HIa6W`|6@fAT7q0b%hBTW}<<7y}T9_gNg;LYHb zqHKd1P5%|+V<Q5a!{c~js2j=g5D+mEq{!ogc>4PWP9XD7^5_MS*|!87W>lFw+4ML+ z7N@Uxwd%Rzy0+G#R(6^OiRXt~-&ac~KAfbPer0M+gi=)qF`MUlA*2GuELGK&^FkGt z81|-h?)s&9Bl=_DK&kx(BQg|lymR+ChULk@jMJ3;q76|q#}pB*1^yMB4Ir$^k~U}9 zrr9=UULAi|i0Zs#a|j|FX969G767@*c#&>!=%yb+vG~g^Kd9sYM3y^&%=JQa{K6ht zjz87RxANSM<9I%CeYxra8^P$6*7)YPPV~^f{Bg3RXsR3#Qn%lDqB>ItKViUAfrZ)O z-<hkZ`Fp7Z!!pD0*)WbPKx$4Ic(LB6i`fW1w8HLsKwI!;MdFSm_06#4ov`E`!Ri`t z?pzHvjnde{Jiz>u3B=z4KL9&=08X|BueA7=Y6*t0u7lY$3R~Q{yQ=M@!QnV6=)L%i z9cRn$rLs_ixraA<H8(~R7b}RHa2B<G&jF+#2CS?fuP0;sP)op&mJ>Wr+aW(_{<?}L zc43$B(O3E&W#$c&lJ|98$iaHtG&igvj4PFsfYVpS=jjwIFune$9^;q@7$0(~bc#cM zwUCx#%v-^!YR$x?jL>-s_mi$Ar|m=whsRRZz1WV>TBi*5bzO-+3Nd#HeM=C~^s*0I zmT=cfR602nxV;Q%waoww^xa^+B&6)S;*vkUio1q0y5|WB<ujb#VmOm?Cj7wAxb{JR zsbxmWKY@NFo67fF;KuGq|Ab2Wj9n)5CjNC0?mq(cTPne4me-xbw5w8jA9PD74;v$Y zm;Pf@bwacXsY$xZCx%n2!Ya<*+u^jLL3>P^#J**|3ZNQU5dm!u7&kGcj*JxPQTP=| zzCXeft_2^AFdl2<O-Z!h)Z?*9c)Nq1(3P8*d*|%zNx?14bKi>YC2<invqC|E%8$<G zytK1xF*9q{OkwoSmuhA&pext@!nS-}j$q6JEub~YA<Mq7VX`fkP_Wi&5{1)p&f`}q z&Trx_O@?Y}xw15rW$K&PSZ>vmR<xEMLtfuHJ_o#OS+t+1>ETdGufHQ=F^e826g6!G zs0nF<MJLLVCM+n`X4ADLp#C4u-Z4nCC|c7@SK79%O53(=+qP}n`K4KDRob>~+nF_a z`}V|*zR?psGZFjO`Fr-+JI-3~^DM+ChTXBnG3D}j-lkOf0&5Ry-f0SA{@j=xmRR_E zmv?yeIr;Xi?PD#k^otZxbm45@+o`{^I|WxYF4zHN?fcjsxBM!@XT7nv`4Pe(nZlA2 zcv4!|h`VgKOa!z3Hltv(6l@H2wH3{~^LYW$c!%M|$1YBHSck{V6)`vq3d(thx<3m( z;%`N*=Mm7m!y>L>W1VLwYGcG-oev(?%Ypz~<`;@;)JMtRt4ET-6}XJBI@j{0+E&)& zv*S54@bhKN;fGqw3p38Wj*8eLG`*$EJ@NXUE^+F<q;Ze34xf|o9XuOYb!qw5ansL# zicP$)A|zXYqQy_LNV*)Ah9i~gSLG-MTu%0cnh?{^9xT}y0G^v7(yt&|W74Nac7UfY z)aeb7Q-)$ZAEKuRXq^$QGn$_P7kgUI&~-&C?RXVdta!)p^vA3`nGDBP-yHeF>9=cL zX&Cohdc%4#ZsY%gOp-e}f_5f6dG#l@d}v;7w=PdUJV5!!yCq*T<)V=cZ+>06ky6qF z(A)?F(t+qHaoP%Oc7u>##>(Xn^?&}_+Eq#wim=e)K1SOqnEg~>qX{ytXw+MW2#p*f z?m1+J+7jiCDODY5HMa~8O4O$mf*d-2HK4q}SM}&XAd!JcxKvhGY{{=2DR@U^O6MLi zF}<Q#ImfedwtEttR1|4Z%Id0Sx=y#subJm75etjv)b12ojX<laUNzA~wWD#D8$@sg zp5eGncq+I0)7a?<ruv|HzA|&{v0748{|PNGL3Z0)PVnppF`<%<Xm$hV9YQwR&{1rs zKf_;IjZFfKsKU<64y<hlT)eU6oQs82XD_VEHLRVpAW1s38AUr3Hm*wT5qs^WFg>7( z*r{h@Ef;iazM~r_Y3CGgQw_3Fs$6Axd0KI+u0OZ|?a8g4)Hd0|gxhWe{XwOG2GxPp zT&o@PWmb4beQLK?ydrm(Y1ZD#SH41jsj1vL?U8NnzTQy1aQD}1#@Tc)e_rQ3CncU| zq3Tc^zhHq`$x<#yZ52Uql1H<vfP4I{V=N~w#|2tTxI*x&Q!yXu_{h+On{cmx$b#D! z_$t)t!mWdH67F%O%g0qWsWq|ll?s1!;@^MsSL`lyQiA;08OVPyQl|gc<=g*cvi`G( z+pK1*jH8O`XD89<rYYrFC0n|#Mn^<iUD}cwU>T?+C_D>BQp4biVmIKHblI_%@?7=` z^Sa4kI6Q5^|AF$k&+o|da&1Obk0K~;*5-Y)_HfU0lIPs`_utb*9i{+;yh_YLTu>)9 z@vF!XPoq(5fq~)>Bp;fz+z{`kdVPt3<`6V~Ip$#HtS_aWKY1D}_{IKPdk_QaA=ZAh z*@BBREa=!7ld#Ls`X20n=btf{E3r^+ZLw0hq`59t)^pQ=-$QE{Vq3a@h8VM3bF%DK z#az=b7_ePOYR|p9=J%(auTN>z{)|=CTCz$j)%O-$a{?yR@kX35smBl>DwixYWPLjo z8P=DQE*y##5BZxtC&=98r`CnOGw(KMWu<p)I^8y&RD3MAES4W@bVt@v7%{*Y#4IR4 zvY)1wFjVbeWJ1Imc=KTi{^5}J2U3`~VZukx+kDti2oWh!yTh&+WL#%U@!x_fp=rWO z%;Le0rJ#FG07w#j@Bf*&{<)92RsyIrP-%5uN3C-d_A<`z+hI&&v%7I5?p%Y8)4((A z8;;?|%HB+x(TNbx!mfvl!LrZbir=2~<MLt&Z5phVw^IGF8vEI>-?ONAjE-F$=Aji~ zP&y_VTt~WAs{(?3fG|m&xm&Uxqqh0($fI<6eJ9+5qd6L+EKxWz8>&|=VNDSnm<qcv zYl`0<D+H&MuVMpi_)xR)tTH5IY4)r>;Wt=zIknBKS&ICOB{NKr<?Hg5A07C^tSil( z9mZxf5}~8HXSaBq&G^idpTPtSmb&u7tk?K-X)2BWD^Dt8@rGo$+l7U>c{kp5jVTPc zawB%4^#4Z6FZyphG@O|S^OiSiw(Pzhv6Y&Y8`(UnOczfX<uaiyV^tdM)1T$`nUy*D zVndP}@+?=Tl#U;3O@#pO2k-!xTBDesYL0%&cSUR8E!&lg7n9ep(l3KL3zR-Gtpg>F zNU)l$vVaK>@hs)=<TS?bWI0E#G_!5Oq*(GIJlM~eu|*j!XCTiQvZBmKoI!4dXUBG$ zNSE8Rx|HkPO}^nj4J(*FDG{y(WJbR*->=ZXV@blv%K1t(-%)|KNzPbvMqKxA`2e>> zc6$(wO%sM;O=V|QM4`m<$X;<x>Wne&WAx+!@1%p*)Nh7P?zudohu5I@>;h~!ht5%> zWMqceQ%&<Kcb5P57U&;mdk%kd-6WG54SYzvQW*L4`S0Z4@u0{5UY7Jq#+*Sq&<=TI z8@rkHN_WAK@XpgPgSs>7<!}#iBr?!}#KZs@1|QedV$y>#%qf)6OHGj!UyPNC5ueY5 z7ekO1P0hRB!@ZUUqmpNis6q~oH_=J;n3S|l&6rG-f7eU&v-=14zcz%B?kFjee|m+l zKOJGN|HFy$AGV<XI7@6yf5xW%4{y_d5T5^ct|K>TLT*C<HSC`xEKwv9Dz@ET;~25* zI+p|*PNf<#2+|lxB;hm4i2%UK#+?UnX53It?b-)=tDriA8HE@mOPkAyk^eT$Z@lyM z<s41SXHW+6>%ugSU8+32o{G_0jM~-(jPI?X=iY=k7|Ao)u{^o=Lohhyk=62MHKSz4 zP~teI$2=u#n*-_veEcgv5i3y<_zz!|L?#1>pEGvGKUuw>%(EVY6w?BG)}hD0t<Zpl z*l^PN-Kq$=#=C&WcH9sh&HDp^FbpM{Y<^TcZ(?A`wr)z|EjZIGWc6nN;?n97Gdj5s ze>27r)FhZ;&i$&<f>aHz9Eem*RB=-X-Smee0F+BfP4nvri-2x*2)9Ld(jbk0h=mL5 zpZ>0(o2O(}n0yE{E&n*b?;>UWvd_`-+}_{8!0utPswiKmXR7+C!b#82;<_A+HFfP9 zf8nO}zY1+**_B=Evb|6`dg}MFs*}dQM^x^@`oOO>hP9v3m#0S>c*S#0AYZ<ZK#PWt z9nAWwJpW;%ud27HO^VZg|2MZQPfiK}`p;`d`ME&;f4*v_|Jeyt`cKo(MVn)C7JyVX zFig4-*vay|Tu3w`Djiy+1d=oe1QKz*jizz5A+{TSPu(Mc;1mWKd=QkNSDeT!netp% zFM`h7%uU?<I46_e-~USt8jj_U#&9Yut<Bla5^b#^cQjM2^-Wl4Haa!za)S3!UJO>$ zmAlU<9u@~3zl@5wXb{3RlL;4r?-GVo2dw2%x?}s8LlvHgJs!SOD?`p)Z?w?L8=+T2 zL>RFXJ~f)#=u?On@iqmqT8-c-lG?k#yV91ig*rNL#)e_@gaJN;co5M_T8~ExtQWD@ zxHo?8;l@wohd#a}t}Gm2)&~U9dGtZd_2_{M!?mVgP;rlc$5fF_5~fnRZe&1;N|N2p z?<87ovO9uaiRvCi>NEse;Y~RuzOe*rTU}%}FpPzRWkR=Tds$#;xH8O{)4Eq6NTN}q z9!95YcsQ6WZJy;Kr4ZIHb3DQfZR}L?xcyI^?0C~vR3>_%WU0M-_O!V^l=FZet|y+{ z_MHg`)UyUx)&u-~%=))^qTmj-6KY+ed-y);n$FcPjT%3Y;uhzi#TCbW&G#}Yq*G)_ zNU;x2)Oz4<0T%f2c}6HrxXp6k;5(FK3R<j@!?GUZvjP(zK}WAUEE*JsuWA<_nnp>} zfRn`s80vfE3y)CSE-^g&;ZSz+-G%;(Hh~**R)wNbQt!lThS)j!VhJ_p)?u5K@Biki zNs~E;zr_XuGX6;*{O?K2{|X`e?+=#$+-o&jPzE}xOMEA$Ei!spChJtWwF~oXXC_Ir z^Pzy0EIXErl4eV-jUYx@y`;jiNk-<gAaqng(G*cd8&i};${=(is#03Jrhot(>L3`( zg0|=l2KukR&O6!c$zw2J|MKTQuD!0;(z$&<`Cs@&$W+Q|=t?iz2jmG3YV@{`%aFIJ zneEffI$5~8x)x?m?zle>4<5RG0`tdTeKaHA<}UA@%JQk(q_GDkc=_T!UWNF<Jz8a+ z#-{xUC_bA)lJ(@?EUE3E?nLiprIYU*)zE*HtdVTINZIE<K1<&iopmc`xxc*z#53GI zlz!T2dd9P)Lt)=M-5v4u2zA^%Jbb)?^7SYM_|J~0d%g+teb?J`Yh_uREHv}=$n_B1 z-L>m|m&ez=EJ$5bAH?5{bo&TnvEEUbILyw3zb4Obo}OgCnsGWu16|+W)$qLs$MBO) z+0JiXAIX2bGV^^`+hC<s%s_4Dzue*ReFxnh$Pw(2Y52@d=qHs9%x}_7rThBC$KRxC zhj;N@mce*b?K%#Qyg-!{`}O3<d%gklyFLW_`9%<<Y4;GD|E0$1IX<YHc)^+H**`ka z<J&7k<)=OvIh-Hy{glPx**l;(`bc5fNy7Q7JG`@ZlXmy=YH8VXb3~9b2mD>gG6RXu zpLDFru=4iGIhRK8@ka5fY&bdN^Vt=ze|tak<wEwae}v)vm255}{p(ZuJC&tw^w!PN zk8aBTaCpb-&0X)iJN;kp;TS2mJB}uxG7ZMq+XxPdWMj4#pvLHVkZH3X@x(l(SoML; zB<3ZbZ}a=_ROF&Si|$pQoBr_jO<&oB1hee#zTsrJs$U(Qu}yQ$nl%O=B`QqGTd2|_ z@3Ga1(*^0jJ2E_e#Ti$!M+)}xY-312vh3!06p3F;mL{*6m^a2(m=NNbQ+HbQO5Cuo z{63#DQ`QFlohK6zrst|3R?#2Anh^WK+BB>LbQo{yXtpA-+}p@+S`1?6@@%vi+1DXr z-YDG%=SGgANs_4BP4K~v^VQ%XH08{U$cGYqsYzIAhDv~8W9n2R>4p^~#ADb5_jtoJ zuWi)%4ok$ihIO%lEj?mtBinHhNpDO*cmo_dc5Rn4^E@25yq{*$QAU&&<@$^b_woKQ zUojolJxre%m1wsL)Iry0!`7Q5)6&krMB()Fo1;X(MrIJyq96u6`$u{#LUN-W+x;0> zQ^qX0GZsuvmS#79?1HWl`LBj#@~?WdHnT(Qe;vNLV$?9eyE*bMg`#~~I)9v>KqwNu zl&fm0r00oa<~7t;Af!Vpt;O;&c}aAh0Z!&T6*Ub#z?&M48><MZr@tFzLD#nFK9s{o zN0ELFcWXhc%J*Kg5?}Z#%-ArDDx!>SISSgEO$FtOE)znp7}x>jI9=-DOki{B1i`;D zaQym=E%lZItys<5;M%dQBB>oqY-w;@2^A~LxCFz|!b!n84Rac#Zm*GseZ)D-kT46C zTnWqZT#WN=9Z;kUudi%05QZ_UFM5g4AMK%knj&ATNlT6P2w9klw3}5mjcqA0j+7z5 zTr*92Y7rvAARmB8)+{C=S;;UieZ<Sojvl6yQN}Z|tITm&sJ9iO+gPWWk1=1y-f9T! zxdfPS(ZHj$tk_3XUN&xJqbR7`D{&l3RT%g2@QJB+CL*0I+8~*&+32lQySC}VTo9`= z!~JYa(X!=B%n^EfE4WKWm_ZuHU`AV%*{hf`BZuMzr_C|U+}rZCFSuvoxak;kvEm-S z+)H*<d@;2@Kyu#e8XGA<!+Nryfe8!LG92*eXLm6L8#${vs3)i83T@lDOe>=QvYh<B zVr9o$aMjOi_NgnO<F(mXBrpA41StQ21Rbd|#bx8ph1OBa9=)g><H`|l7?FC3!1XFw z++7C!F<aHhmw6d!429+*@?RA(5t@nUon&!OLFWv!Z;(KXh1M;xT(eqs!aN4jncFMA zx}9oj0#NqE?O4-L254j^;TnYGUQ`4XrvHPyUjzh2>qcg*7JJ8^-SLuhXw<eNsX^M~ z8f#t07$~B;3@37{qBdiWTW&n;HRaB##0=6Fm$bQxv~6ina^@Ra2T+(c2&hlb0H$)S zlm}H&<v`s}&mf^P-(tAa<VFexP~5qOVA)wnV^v?c9;(<Wkj1=Y^=XrT-%AR@Z|XEl zUlP|cW~$V0=A;TFpk^hWn(pE_>uvPUHf9U#<v@>OojCOLA{nBgU#irpcq%ZLuWoNr z)zLDuKWBa~<}&^Dl5@@O=$Ho=PX7Bm>vI2gYIHpv&rVsEN09wNan${>?m><=K`ger zn)KUOej8OBPr0^ScwVcpZ7YiHNG*raQ=5bB_w5k#)qba_`h2fVyy7nC(<Eg2D+E;P z5t690Dw|@4?1yn~uEUJ8JU3kCL}S)Jay+!ZfUD%eGGBk<4QrEw+)#&fquD%M33u#^ zgZ)SVXK)3EkLx?gR>guY55{}C`V3ry3<HZs+01-_Tz>K~#5-8y348q2W~j{J5&s!a zpnhuh_vcQaX32seSINT4=>?>l@$sBfu>8s2S!=y-8lCftEt9Rrsa4bSKAnx`fM)Qo z#-)bZ`cRmKw78H(%sm^X>Mm6d+gg+UtveTToU|N%o#ZoF_(#`JcdWhhWmj!B8yy@m zHN@?D(+NNrFMwJ_e8Af{vwkjr{JIXK=^x->=L{;>u2fzyklog1r|99|tmNV6G#2v0 zqw9x~0!uNC4&6r8fY}@d+zaU+!`y#;b!VUQUO|=z|7fOT1HKr(Tc`i+C39`b<qOG^ z<nqPl4GZ<#p3a$v#3hA3DX63a-C1D|mZhF%MNha)(c#1|Kmo9ZRx`oN`YV6K;xsmf zbnv0AyS`)b-YoHeOis8+S=;D$`4{lJQ-iWXQgnv;P5mmvZGll_#1Ufch^h4w$u|P@ zgSs@Wur}9O+J&(+Dd|3d3g?X`@6wb!N&*frst$F_ZWa(S%#MgyUY@Xc8+x8;=LbNB zDlCF=_h<Du2o+|JmIPXBQ-ezqCI3#!%{D{V%vY(NX$fSPTPHUasApGOm(4zK)nQPj zv9Ph6`lJ~&D`lzbgh?DFxJaMF(ga<k$%}FP7A;E;-E)snc*GU{L%p?!MyLU{hoaWE zP_x*aK)GGbKAP*&k!Ux6mTZ*HzCb6l(ej9$h8!k-tiTG>{{=eR1jYdZE}V19Tu|O% zH%dl3jx)`VAL4E74SUIi4B(4slf!{pgH;7uhe3&YlJxD`;X#tW3}iU1TxqUYZ^HFP zEzTxw%HGVYodQ~WaD~4ktz%POF|*vuQOC-h%D{*entZl$cDYhf+-hIv$>l?+8?{S} z?lhiw?_hTEQVe0zd^9Z*?&w#^H#c8Dy$(KNb0O`BneM?1x=Gu1ajMG@1a`lfKfZVb zDX>}!y1mq(Uc$Ih;aaV)v%A^ucHKgh*b?ZFKN1v6pFRqjoi++{8%9PykPSP=)TjNS z(=zEz?3)Bo0i)-xd40^Te5ohrTCt}WAiB{O&3bf|)~=6PwM*7;B&&AjLLF{d%LUdj zrJAHRJi6Mj+%|HTiPU5{DuO6IqS{4tPgWBySFnXX?aQN0p0H>C@>Ryc8*&pLYKwow zzI@1$PjA`G@Rw0!9b)$|MPO=cz=VJFH)VGO$a_W*{gn@43JT1vXu8)mJ6fbpeWF=p zv1RO=Z_Q#oB1P@_<l-D`%<%hJ>?hY-ZaKztaA~-ZGXqmnw#3wHhpAnxMQ@yM`@q)@ zN0Z8r{*F7~21;_N!h74x0%GZwqqQEV2HgQ!S;u$FDy2}y`f9qMX&}uS`ha$dz^au& zCMA+S^jI*fi_<pzoJ)2%eYQ*(cD*ODcExRS>#U_<IWq(GVXYjUh0V)XJG5%YJcbE! z?f|8A5&LC}o{UJm*R4Rg?}o~VG2<?JulMT8^-!!u`#tu`FhRYk>7}WtT1z>~4P2-S z-)SKrMY^$W&Z2Q~4z$4m{JCzV8I<<PjWf@p2<PW6^VWvHy1cvbl#m-spni<}4diPS zd>cMVbj<hho-%Nup^kn#7hT_}<^m)dX);aa=DqF4%8IWn8mbA-z0r>mN*^iW0}347 z$F3Y#GbYAoHfGv7yzv4mGUgmQ+;VPdgB=}F_~uR<?uQ@&uMu%mbk=Z@a`)w%rCy>h zakk-dm6(odI_BV6jQ5ei?=%%b8Ciz>sF6>G7b!w1mlo9p9x@;5H*k<9Qkvu97Evkj zYLW~s+LY}<O8ksoYJPf=rt7=bhgf31VtlnHOQ`F$+bce&8ukzLl5W7n*)~i&bXHbw zT%!Yq(_qDU^n}$&?3H6^ob37e{k$AT-2hn9cO>+VC42gD%z+_$;bH=H@?$b{URFqF z8t8m9*mg51cs#{?GnVD3&;277d)2iu8NZ^*EXD@bod@V=7@}q4Ce8B&n~pp_F&Tm~ zXlRKB=@15LIUm+Bhb4@&+IQkL)eFj{#TT{<@6M;Mrl+r%CsC}Lo_u9}Sts$QZs8hh zrI3S-kdK=p2BS~1q9ofxB7XGXM3NHGIK{DNl0$4__nwPL3*o`Ub)tKGlAULXL%n-= z<uj!FRwL!LXNgD1Ghr3IqvBsawuv2vS+l2HVrUz}wInKQr||9J73YZHaf$}sX!<xA zm>Di1K?vd|e)ovE$Qd9JWw6Sph*PaExWyH1zFG$Fj8ly1=CBJgoaTYq+*TK~mr(6u zb~&4;P@dH4aLOJP?5AI(Q&Ay2WP%0!-Vw(I1dko`m;mK)i)%vJUJWxW64x=o4xv6w zfM+b9wHfZpJ2lQ>&%8l}+Xct7xKK}$0Tp9Et1t_}fI&s5$`hfg2ng$`2ndYHl^%6n zXFPFiZNde|6)I(O_$aePwovW3So;sQx+TL*LZmJ^`zwJ+eYVU1PT3{n90G5)f<egq z_AoY40tht+qHw2X@tAS_qXOR+roDg<ttksI&y^)w!;-#k@!NLDhCNr77jwvxTUX-u zx-6B{ykC?0tf;~m?Jn%BJL3baZj94GZaM0XXx%*U@~P7ET&JRn&aj{t!%Wdcdsgi( zoD13CSiaGXQ|fK;mD`Uqt)4u-e)d`MH}bbKut%t#X!!dtmk5FqoHvfG!JU%qH`5N) zhk0AdYWo%PK8cVh)KuVQ>~|)a0#tU`SzbnHf@zky?u>^>s98ifl!|Sn4DtmdzrgF_ z;@!TrPgD<}>;g7EL4@7v=#~f2M?zi^J1>aT`+<yyS(vVj9uN<`cWR(^Ad<*u>qpmx zO@jpdUcz%k&E>R3J{B1mb-D1Owzu2I^>DjV(dK4^T)nfuq3AKlOT-eA@HzMzIq56E zwHmuyOuP)vkhI)Z(N|P-NYcluw9r0#MOMFY3z~te`s3;&MdAz|dw};98kL!OgM8N^ zAAhdpN3bs#MyEY(O>P<UrbrrxmA=pP6ExGHpcv2IS|AtA$PDw#4eB#R#%R@>-;XSp z^u;4{G<}!sXHXX{pqMZ$<@`-QO5`gj!{oL!EswP2^2X7|a?7G{PWf+{+k8TH1`{=i z{&AwRv4llf2}^v5i9ZGFLgUeQ$<P&J2CK@eRfYfPa8kK^!1t1RGvBOvtj>|Z<=E5d z9AtLFDzn8gXeuK<M=Xw>do{%^mIg!-<xmA~HxPTIcm5FOfJ3fd2zjUoX4qUezFn4; zp-Iv*NTOFuH;9)g(jnWR0gJ`YYqMBYeNeOFl|Z@b7Xp%so3zY&grx5W<-!sm`yGQR zQg@fAcIR;uGBF&QeI1+04A|XxYQc0OzxYFrU}*eAX0%3W|Fmh*d*GI`!dh!<Pwte# zv?<#;pK!i6fFFvL@{1^%N4XT1&#_9BI^<pqy2iB)G^LmW?THKAa~8ZAm-owC^6}PP z^TJ#(2RzF&QizDz5*M>2F0myp&=H>;q<97$Va@e7fqILak&6YKM=hU1-CG48#%_yW z+%zHG(-8GQ0x_VSo{4;{M=m$xGag8~(oG!1x{3x5DYk-58OeQD1|-{MC-b)=h}R5Y zW8{Cj_DN3hy+u3beAXO{Vc;R<Y5Tms#6kWwA@DO^crPxt?7sB)%GtlrckTL4-!0~v z+^-v)gB1-sv!T?F_ONOLz}3tNFzY<FNbKT5cGO&h{mgXLE<F$~D}|H2P*TsuYT6QP zb%U8Ir-33K$=FiEaH-0GtI>dNc4hYh!6{@Y3}&G^t=x2>@%(*3tr^wE&s{&J0|lY0 z>Qn777R+|aDWa;_erUT<BnbAl&?@TqU?xcCg(=cB56^}0dxNwiTgc*Hl*TLjYwzC$ z)OUixSO1>?1NPD^KhdH8oDi4fL~p$6WD|U1XR2;fFs}=K=a~<EsowK~AH6W?3Q{4( zESyf{sE%l>bHMekqzeM^=hitre{TE@jRGCQ6)=f^u*r(>${KI|l2JRt*|~k{v^r7N zKX|P|;JWw)0+n73v2=lP_x?pS;J86OcI1mpbW{L;tiHBKRB=le7rpIXMcn$m`TIm$ zUH-MlS3Xga<1la@rx@-lP6ko=KRjYQ1~x-+n{QxKOokB7IK=Naa>7a1klQ+TV8b4g z5dXhWkgPvXL4`5vREVdQ`jVoiU*-Q8)b!)8sX~B1ELJkARh!L$7?`rvGtoB$wBr_6 zna7-tKgrFh`Z?4G;QnFii3OVX3tAQj(N>{$%So#ep`CRMY0;|CXwHlh-B19{Lt15% zvFDdab)BzZwN4larpVtL0HKN(`$;?MN$BZ`puD<369(r^NK=kWpTX)uF#O43yM^ZZ z#py=B649^BTT$%~v81)O4#tJzH!4HJz8>PCsF@MMqE-DQLAK%Nj)ap1-FDv4ejX^! z+<qP|&%D>9>F{Zm>S7-4R@Si)tWe+02zBgQV99G0^T&3T@6$IlT1C=Nron(gWe#_( zeC)_bv%6V9P4D9sthPQX+Bc1!0X*D2rvTf>EwAA0HOD()Jk=|Y;+)FU`wj6b<!Qj` z9gn0*t#oD+;*nj5G@CMF-V(i4nblo@b_2Rz!^$wR4n2cr?|Q^qn>*JArf`4FQJ7-} zIEb9TObgKu1QJ<h-Fm880l61NMG>clTk0fzwnb12$;mf04Yx!&eh$3+kI}smk`rF3 zF1Bq|Y}jVI?{|VUlVtUBR<tJ`lj|#pO4@Hm8w^>~;A02&B_{;BJw2@{3?=55IWsv* z7xsX@W(ig@QJ3OF>Siy2h2?HHk#Rv$wa!Lc*&04TQ%}mYVk7{jL=K_?@X8<6kf22u zh6U%+&lsv@nkD!qXXherC4AjMvdHRjpUU%2-Fy;lfm~*ZZGNgUJ@12G|FC1Jp!1uZ z{gp>GQ(LjazF2FjOru<lW`SzV5<;kooIhBr{2Qd6)L9EdRUWgpvpAK849y8#w>)&B zIQF_XGj`O7TwI#eK6C3-?7OJ3NGzUskB><R-%=bkAAtKT==d^ly)BvQ6F~kzhPp3J zHF;AA?t_&(oxY&eBZTBm&w<r{T@l4m^2Q^pdM7YRZkH>&$pvPS+~$hznA#*_ic7C0 zus}z--zP&ES~4SG!6xYs>@4K<@%ub1MWOX&)H##-u283-MV*P=B;>oG%;~!Z6+KAt zDteXCzl!Ho2C7{;j4BR<{}A4bj~HruckIAZY>|Wo(LcbY2YJ~WE#U((;vXa3aaBcP zU16#ZUd_pcC5b<-lxJ{F%0geBCgCVEfI4i+IpR?U{nUkRMy$kL5wU}KEVJ|WO2DtL zx$!7A0|o6bgxyL1K?0}J+?LXUH;6CYvb8bI@%zSkoH8YHjWBsGW(oA3oD?s)-lKy7 zG+RkHm2<)}c;hKT`M1-;!rRadUMtTQ{?VC^u!|jOCBAmt>^8AQ;whr82m5Gdc*H!A zi?YjayxtX)eRxcWJEGGOib7d-Ma~@=RUeqiLuG?gTb6A5GS5$}w!s-iQ2#V^rW~jp z;N?xp-#yW84_hhw-ls<R08k$W-Em<TvK?{t2gQvhbRlE?Jx_zFQa1$JMhylAqX$*6 zEIF*&FhrItSty$4-%80kn)%IA6K}g?e1`RzJWXO#m3&s}Pc?IMs=WL_g1i!FpNQ2* zhO?@#LQFeq!EapxdrF2&_YtbNds@<67@*DsZd(kP8v8a#GI2$O0rNUBPN4L!xiY`b zyj-@27;`~w9R|`R>?Mm~wxlx$`>6eS#-0f2*7T5_j2pTYyPZ1FSRYI)E9P+e^NSzt z$S=92ZsvfFm_8Y_Pa>fYx2Lvg<a6o^Cc@96HV4)!!>xsD6GrZ@C=Qxm=05IqG~p)5 z{lIiM;Ze8(eGU~XPev>_`Q>Ck!F=A5%f0f7bU*2$9$JY?Z)VXxb+Hf2&L%#6vG)m9 zRj1iJQYlvimmOcR?;i9zCiAMwCff1W<e}((WdkbRhsZl5?pEMD(=|T;b3}R}ml85J ze$vETzDVu!1>^E*t3=MJsZXj$EQT(}WqFvdnh7sDf{)dW2RBN3X29GQrv5bIRcNFt zhEftNm0$Jc8rr(K!2(hE+OOtqubvhgFtaWBByv3w26suh8>+$-q0&X(G`3sXmKS>6 zHQweN%cc*}e*o$^=S+Ijv1!8JJYd8&zS(CY%Nb(}js4YUU*qYk*XN*giN-ERZjQTY z=4YHj1h_?bPKz?-wb+T38IEVIx1@iC{cgS64*3ZS-%%dVRV(-SN#tK?oI?H%q<#-f zqn*slOgsl>31>C;w|pgnkNym6E%A?649KxGZKbi5qi^8QH2WTZ*fZ?t$jGOFdDS#~ zc&J_hc9cbejKveIZgjpBMTg9X+F$36o=!*2d09KzVM2#qi3JEba~I7%auJFt?zw_B zc+pbxDanXdkf2$6TzSAq%Mu9JUeLDJx_kWH){qekUHD*)N@FLQp%$03!EEKB;BqQj zqo2Pz8A{qu7A!jv<r}GeU)Ea6vO`-Wz)NhU5igf5WTI2)mE1Zmu~T2NKSGDu7rPLL zQdN~!Btj~|Jan0F#sU{?+Jw-w3ruMrNg;7|tSTm{qCdW;{Uv^Uz(%UJUOu2RNU354 z9<I2s$5_dwM98*5n5OlVhQ9`nSzC)IT!$b@04ymSOL>LP2d6&<g>XC4)~8&F4Eokw zHu(<GhGVLD_V2%qWP#{uJ@WhEHIsj&@tpr(+Vjp1_IA#u|7Bp#)%<}smzMY`GEMZz z2a<jP3u)x3F`5|mh8jgwAO?e>2=o(|FO40NVP#I@nCk^tRJm3y*Ic7-rbnq&8Pfzy zSZ_hsE_N_9*DPyo_%(OBy?o?;Y<FdbM6P~2-uOD-c%I}vxzG4MO#0*dg+x^Z`r{PT z@GQ+NfT#>APguanr%yu`a0}$Yr(8P&^F^4CF39i`R6EKBjC-mDP`9<@T(s$RK=98z zJ5vg9$<vid<sF=~GvO0&6$10cAYcF<LY^P)S@b(dN~}}t0$pUW38=uPu>A%72*|dC z);tpPwLw^t<I`%FW};1xGJvM`$^7hK6nN#AJSt*Fq*iJj!-pph9X$ioZymAg7Tc5$ zRI%%pJz~4s)ZDoAUaMhlz4!!MI28|)O@1WW6xKdb`2#|8Xa(qTqua9gf3&%j5Ab8X zj~e6;%45o`x&$YY7ut4a9Aj&M@J67{<dW$t9Ho|R&mc-RDC=yIIc;Ovt$E7t&am?f z@6uVm8;8xUeA0&X=U#1MXXajYVrLd!ePaJs-hpH5m*1_h^hg{;v-XG_NVE3H9MoC+ zv=6IW_>>N-TlzE)uUPoh46j&z!o{{)bg3R(u=WTZ;IQ^c9%Qrjh#qLO_Q)P=u=WTa z*hg`=TXo5rbV?s|4k_$VpLoA+JAJe5P;7nq$)zu(eg;t9;d#E-4kL_5Z?I0kdWPo{ z+&{<x?nSFG80>UCoy<4h)yVCPv6qa7l-)S&>Yzp-CXI-LGo+N&OoA<$Rh#m$w=v;| zWVshB0O*WwH7U6)179*IIZNeeT6_i+5SMbS45YqhZ5uLxjA0H^P&XFzb4UtwNPBJ@ z1cR|1dw|lOUb3WngwdXdJtR-jonB$IW}*XaYo$h06=yXBiSM3?HII>NF!o?}lH!I8 zld2bS4G@8MO%_CVS|gWk1%iERQg@*PG42_&aQ27sm<Vap*rinFSgaY-VkD8-`Wtlf z6NM46f-(z!b9UzN%B69trger7omwjuw)nwuW8gPEb366s5hbBg9TY|J{YLKNn(y4= zcZjCZ29$b1su?w~d}b}<w@BGVk-)`qL}q=l#^b|)jOpI>HTuLl;t=@)t|WW75`3}( z0cKc^D%l_YM6#N1R4Eat41BznDYEgpTc4>OdhK(@$)pt0LvXM)C2_#zXCJuUmb)0% zPhwoKui@=`B&LnHuqd^{BbYOSuDbAdQ`dzGGqH<lHz0S*-7L`891XgQFvK=`BOhRu z9l_3JG<4;_k~glThQ4mdn>3oj!K$9MHAi}=)!m5KLAJ=~LxmMQJDsC7!&mi|f^}mj zOHOBVRHaCqLcyiV#F@xm2&kziY8DY^Te5<lL-nJ{;8>RtO;SYDW^7JfA7m*t827eB zN5%TH9%F!XXT!0^{Yx>G>FTpQ>8xE!apv8?;)GK;jZ62F@+K0l<Q*OE@o`kjF_sY@ zJe-?3cWyzJ6($BJzEvv#V-K=qGB7MHVJwAo?sYo|^}rfhEFwg;Gg=OROu+|xfg4pg z!>lc&9hC-%mHwfbK1+6zY3J9>c(H?*zyD&(lwB$Lel@8jwdwd$2J2+`qC#>C#l3$l z+5%zRRNI!_u=f?;psUfVNS*i}D@GzUQ5E8g-Qc+&b#lyCG^usfL-jtUU21b*jPZgA zdJng(cLOV8_$SBhof^hMiSOhUWT(LG;F_Qiq4lSY&(X%VU?J_$>b6a<2bDtPCe@*; zqB4-X<ntwVkP4*GAB-SWpVZ<61U3nf7%8pX->c~H*<)!M9H~so+kGj#kO)dDAf~=+ zyY4!CeDSq#%!V7tS0iYM;5{*i8$HBHH?49DBFhk5HGw9BI=E=YGFW>&nRH#jDFB3C z($=pehf0JZh%@+ivxMssoM7BTMZtA3ckr{H>flUg(4+XbUV>fmMke4y5;HopdoKfX z`!SA!bckt!t!Q=jGCaeq)#mMi&_AE=@qt9}8<-#aaOBm|!?rEfFd#<<CVA|(AO}p) zFDO6cAS@3-@SEsMtnKRgA&-!sjF?|g9^%c?k4b_ba1!(w<x)3~GvAF?@^@ZbMp~=? zF4$HWXcBS+PB~!NK{~~YWZihx7m(;uWA+%TEXEO*a)r;*VPHv;G&Q^?=qCoNX_lRR zgn1PYo>@TN&G4}${=$s+&W}o1kH(Kv5+C|>nE0DR;%_lR=rd=|uTW>G78~S-tZdT9 ztnABjJm&1+PoA69YjH?(P{&zRC-f|#C>s?Z0IGO5;vvDp43eg-uG$M>#-ym^;jbl~ zSs<J&<S8YZP~`KIRX~C;fVQx$OM(FGjqEjRyO`qZ)9FW-2D>Hf9%!k3av%2gfWTj5 zXqRveum?ZWduLOg;Ii&LML@uoIL|N?+lwmM+cTM>9Z=$bm{Me}+CIgukL3`mooM_p zGZ(g?Od$?9lQ*hU4}N4vI`H+1t?)(j(d|VNV>x-s8Hf!H6VlO))fStKBH@k=NtF^+ zJfCu-0T=NRmN7L;@RRfg2i?-dS;HwYhoYxZ6ht{(IR(cw4n%T<FDJ>Y6bn&)wGK2v zCjNANryRAP4d>Wsw1;?;9Sdts0RKdRirtBNh(hlj5}k+#-|LS!EXyH2itgVU{w=X4 zyC?XvBK6P&th}oOI{q?Pg!D2OH(dI8-`b0QuG{VE3?lBQfxM-G3$ba?Xw#5-8Rg~< zgBa_Gg;Q1Z1z-i@>oKn8@Q~4Kv|55ThC@`>Lkl^@l_0GyG18{eNRJ6O9>=M#)czOa z$S5}!t|bh1%6P?BrTtq2Gg>p-q_JpV-NFrrX41r;173LqqPtzyjGs+VmfqQz8^Xv9 zwaujIQFAV0*VQ1?w2cC1VbN5r%Ww~fO<-1FBo;7-e$&vq1l%%brEV%w*1?br_2Qsh zzLF-)>!D}HrC|Iha&(e`wpW4|8n^9dtRC_!ltccnBaMQR=H2xvB8<FlViOwzHZk^S zG1AC)dn<W6Jd4Aoh%M$$V~m@Mrjz^_y(c_Yey(PB<5Xc2m}gn%0^_=rLFCyhBzLJ- zQCv&0TIKD_Aj80#F>N|&=;l60#-awEIFPvUG|mARyXch!LH}w1L<?GjQN1T3OI)Hn z#vVm=Tv=nGflEO-ERG#iJvL-D%Lw<lE8JR<!{@mNv85<jOG9E6+ikh7o%Ake4;+uT zS5ablMk`8ql`={>;bdN9*Z>@r68S@6`=1j`kXU;X^8kZK`?31D+738kWs+t8asCJ9 zxIgZ%y8Qo$M{gvVzLRzcoZLLc{S*9$ZhpOig5-T`MMPmQ;r|VM`ID1NXwUNOY!vfz zdT@&6(jeIhg4=n5Z_j{Ev>d%ryw*oE5YyI);HizJZK!eIGp-?{hZTom0{;@N>*709 zJKo+fL+cnvqaYPI!65us4eL;Y<3=);RQ&!}s=~=r&Gx8QyIS@R0>7@-!a+5o2Ogh# zVIfIs7A9C<4X8K$E~ELI((Fp|o7Q8D8jb=P0Hp9`-tp!Y>gHPbzN(Fvn@Z>{PNkTy zm$IDp+RkG63~HEY6>0*W+tEVQ>onfhijBmT&<Gq>(X80+5hIkkWJo6Kx=7SMvCo0G zgz(05xGguX1gcB5g1{H^RU|l3W>HWf)UE8hjqT)lp_1P!2A2usxmeSG6vSKQ;97gb zO+(PvUtx-fX*9IN_{erPq(+4-I5efPYr~OdbrCCUPGQMX-JZ{N{*p{3+*AT;0b@%B zxS$e9K85H&nqfy$MB0++K)vx;F11r9f%a(*!`6>2zg>!emWh37`>PmJfuu@1jJ2By z_;vfi{pw1Nb`W`*u#Pv_+*xk11y8*#*Ru}oWyPJkxXdR(hM;)ncE7T0OCjrLjYYj7 z7x)Wx=B6lL%<oY=As*WTb_xK68blt;l8ip9V^#F4fvayVv_&~gg7+$bO$K3aE!>e} zeV_@ZTVm-_3T;*N=;Cn~9{UN@zEx=!QZ&xG_W--#X6~h7`VsQ0_ox}H%O`*Qf^ujA zXiGsazTdAp55IWi4q_s7@aWxJA>9ae#Z*DOm%1k`mjw`k?W@|uTT&JIp3Bmbv20g- zOub{Q(hzEPO^o-9x1v$BTqT7YRGCD*BZsX|S`tXTQ>?P4p`@yGBXcy#lRZAyssM#2 zi?#@TgfWn5%lNL8B|c(QnyWU;q!s;*s#TGq1+p?(JoYHO9{aMal=%VH$16IJS7f*z zTt-}-FCo8If%#EgP<DoeSuY`_tNs>K6u2ky20vG-NA<Vb5Fyo}Ly)S9l}8Hg3}SAW z;$7AtgiWo=XNcR<2x+XcOq(u7rU_eTWmaR9GcPXO@4|w*rVNxw7A`j=;f)v%VoIcL zKtMAX70K3TJXF&*&Z(J7@Rql<2}{~J1%4>QH}AQFtLdQC$-{OlCEP+OtkNkBzP$cC zu-WSc2irTr2N|2c2t#K&`c`|JfG!LP=Bi{YDMUE<da(-#|H={n%E_$#&hOadlz<3J z&&9L*@XpG`l%^)sVCl@zr<#Ya6hB`nerDods7%?FI6xhGg2l8=rs8Y#k-Ga>XsxJP zrg>>8pc+;d?|Lrw_7s40=%pKI%ZJ-7W#5*QZX`!6P*qcV0xOF%{o-P>hUJ-9<mtnj zUdPj2QS`etSf0<AgZq{$LVc_p!<w1J7baH8jCHUYS%mux2%z=V3+oGyY;sB{GrcN| z60pL&vd0N@%jdy81>`d-6=vl&N2{3u?50tb47(}%)SCz4>lP-ogq2l1GX$Cu`Y1eW zdO8b>msZT>Ls037uR37I<dl*>;uDNGIb&Q*P#6ZwdTi4SnJM9dZu5k;JI*Ok>TFo| z;2@KO0Q*7B^diI+MlW=%A7gxmjBB6XZ<J0n!XRF)6ByGrKjEt}{^u?_FIL~hmR6o$ z@zs^b=Yj1DwPpI{a_01;*8GKFL_Hpn;imj`;^h6>-|<j~8>F`DU~imZljMZ=W|Xr} zw0a!3mbMpIQCpoKtV@ihhz_$AM67ORqkR5nf!0f5+-vsO#el`i4uF1>lg>}&V`1-z zM>*}G@>+15Z1lc8%gZY6y@XBNaLkT=A2ly2RWBCHVA(}*Bhih*K&GO!ZvG^ThUD6D zxMltpA#9#zl(i&xiN~3qj_&nu2W#}G-@$coUf)i|N9ixv>lm7MZu+1N^Og1adg}Pl zW2D9N;ct6kw&!MrPu#J%_?Us^eDY&Z_=^*CbfI@R#RRHNd6%pF6Vl3a>b=0c_M~jZ z!0Ae$SjUua+F2mbaU)94U1Sl56TeA+(4)W8`zHAsYj$8TGpzw;VA#Cc-zLU*0dhPD z6V8!2VaqHi*kzS?=OR3kMFq1jr1jvoUkC%Ce`Ed{+R_WqF3-xj8k&I_!ekDMYK+!e zrV^Q&oue<hE?B;5Qke6emr+C8>)d^VNt!7+NKjTrlFJttI3l&8CY;khD>j_YJe5$~ z+kM-oJAAPv(Z9QGd(*`~h|Kfl9}a`>OjZ#=kquuRk&w+VBx^?rMUtM!d+KGx`-U9* z4oP`sMm%It0e=Gs_HU{!bk}?z+cxW=X-G7Dl2p@OjBjnvrEE;xZSNS?`S*JN3wrs6 zo6bMHGWPiR+!{#u5@LIRe7!@!;Qv0m<C;5SE$ui(FSA%l=PIWbujoOg*lpnSbOm;O zE{vcnyt^#3qMz8XjA~s#J>9>2v}ZV@cTB8oP_y3=#Jh6sw2U)o>!B5%Xx$YN*Kl3D z0a(3g)Fh+0hI&8mtJv1zpquk#e(K1gctXqWRhZneWX=5YAPm=hkN3u8>qvS#Q_xWF z3;b-|lNc^8NPYDIA|8s0cX`ooiH_4&FRR-W%vItsu~<U4N_A}Bloh#UmAa+gNo-an zyEnECi<_D4fUVgPOIAS4aX<mbencVqUWf1`X>!}3;4T~O7FZ0#IuFC8t>oIxJUj@l zNU^qHnJEHoPcw7Gn>z5KToJg!Et1O<zIa1~elT2|3RfnWDfZ(FvawScXBW=YEHI<g z0#T+rBBocPer`mFqXFs4oh)_8Z!_+7UI((SwH)WDw>RY?mCRwZrjBXTiMwD|&iuSM zzNPXS8x#8eIP?w)*%4L`UyeN?6+=02#?0@>RP>PJ3An?G;l<1!@&FZ^y+sF~8k9HK zj8^3MhCH~ic(Pb2VlB{(W5c<kZbDqQYvQzUFPswf9x9D2)D0x(sTJv*@jZcUs+zMC z?u58fN`INMSSb{A|Atr}h?B7?v=!yXx$<g?#?8c1JHVN9E7%Ho_Dvs&wrDNjjdG(| zH*4aa+ZNggdsc4xTc8{8tlnf_<Qsx6`hh8H^T^)BJXC9OQuu{(h4)p`^gYz%=cL6? zRujJ9rLGlU@^szwgH7f&ZD%ik%zLra<Yz6jmpo}`-N;|uHQALuiD>cD)le*WQP*r( z`V!XI%Uop7zaKa8Wh~3fUznFXF_b<rlsz#oylYy1(O7<6Hu=eE@w3<Dr!UXQU+BwT zV3hm`y$g+a8>1{lx^CZ`O5i99?QBo=e#7KT-Dt~?KLT@ih)RDD<BR*%p8R*P>Wx-! z;^dZ#FJFEa=8d!`L;iSzV^ZBAq|Pk44m7+5_Xx)mbO(gK_0N#|y`>L3$JPX>55N8X zO~8g5UogQw!vnp8Psq&i$g7SYvd+sb_$RD?Z2qqkj8`SU$iLHdK_56iX#Ya$_VNwG z-92IcCDqLsGR1s#yl;!}WR0`|;|nvT8Uxmrx{LMxWtsSN`|t%pEicEjGPxwaU#Y{q z4>18f(QAfX3=VpIDY0%Pv}*9ooZzaaj}g7Ok_+bLx^Nb^b?fKV8lYyYv!$t}UYArI zwinISwW=EiSG6jfwaDwGg<9X{sg+(OMp8VMuBq<u=%)gDlyNomkD^>^uq&Hjb<<M~ zap)@N4^hN4@45s`3o2!NN7`b~!~d$NVJYad-f#0V^ltF2bzUXI16`y@?WoP&<3x4P z$5V5|Mka9s8z$jnD;dKoIUw)IExf^33Sx&OkcShA9+Ra0?R8hC@rUX4V4yp(S4KU9 z`Ma=|1Bg!aO22bI<0?6a<2bYzgWjG(nCq5U`{jvowSO~rATd(*hU5ih`AW_&_V;+? z3?U#b9*KbLQ#g(P+0`$K=FKuMOe3>z#tDyqB>Yy74<vy|F)`p|2Qc7CTSOdyZPW8k zsSIJ!ok-)sQ*dYFQHi{JUUuOin<oDoJ68rPuNS2hWcQfXWB*K_2kLj}9S``N=qyXG z>N$05j^9i&@Gc*9fBP@#J5>C#X;%OZQL3KS^S}R<xk3+7#AW?)Gw%Na0;2mr6m|b6 zXeDCkV)&mtM6B|L(t-l2uBEWFaDbEgT@;2CVo=mRxB@MqD(Wv>myA225M%EqStDdb zK2iT(3<4K1m*HRhz41<)6tQF_eRrn$CgyeBD_Z6!D>nrEiNl!q)C!I?;cT1edvTBp z#FLb$W@wv3yhz6)*FBI!w8wum5(+X}On)z&w2&3n+jN?4Il%tuf85eqa+UeQ+jz|A z9MI`rE$<>BdI|e&UOVod0cI&I1Q`B|>Lx4ners+pK2;r{zOe3@s9{oVRrT4?G_S>o zu`J8v`}1jPmih&~Cym^=-D1f!Q!KZzx&K`qGWQR_+(<7-zpg!4>YS;4Ip$`Y+&&XC zMU4_-vrt}(LyvJ|sPs&eV;1}A+)wS@ImP3@eG6CEM<rHm#lXz}UW@j<b&=p{yXoy> zpx?nL1W}3qKqA>*PozR6N4g@&oL(gMJU<K8%H5@*t6$hI<D#A`Z2Hy#I9)<y@5t#| zc@(5i5ebK<NW0nF{^HG_YOige_&lI5E*(`o8QBXu><T`qUKn+<zq)~-RGIUzbcMgS zer~aD6s5OgBxuidER-7pLRWn(k{9LXQgI=!EBduXJ#9!C{fjz{v80GpC|%-(gu(EY zpIxBe#JSXR#p=g{Sgxv$r|f|RGMb{^rBlhd)GNefRgR@2E-L-e-f9pDzNOW)6{>r$ zssl?!u)9r^ua4UwDVCbjJXeQcGD|12pe%I?FE@{w!@DOr4QB3t+l{w~K0=9K)`~V> zc6zzkBRsG4Az@kkA>j`NL_z5$4DiU?r#f^96w@6fG=0Bd%qigsDqDDr{kF{MTdQx! z?*gS;S1;jb*D?z#L2pvL05`;u+|&Tk_(lblCk>iG`OD?OmXbOL@j^sUt{8NQYG@~> zVuDT0R6<Vx+Y_<}Moj03#vCaEjcG|N)Y38-i3-K+4~7(5jS(#F$QdX>eJw$iIEp!( zj4L@5S&evnh9u&mMey6B$dMI>C{geV=Lhi@6@TVM<<jCOr11~QiCgf-FJxaWa3`BP z)Y&{tk6f=M&(4XqW`_FX8q#82IF=k~T{ftCD?+@IydoEg(g1aUD|jf@=B5mMd`$4a zet+O3Zk<m*Al%Qq?f-|NV*iCE{ZHQUzckkW`4y)Ak9miv-z}}Ph~+w}h+v{Hp~%;S zgazOw%y^Ep12H|J^}?V;6_U_hZ~UL2e9Xp%V&;!q1V<ihP>e#Q@Acl#IlSpNI&S{o z@9%huCW+~ZLTr&{F;TLqjN~L?j(su`87V~IlPNKllM)$dlQ}Ww8R_+ehKl{j!G}&K zqlfsy`iA=4^Ky#{1!+8W)poOLuwXE-P%Fy_A$HMqRazx#kD@MAoS(v>oi5q62WPeg z5^Qkr?mwjhr?9>bu|RT7D!Yn(&#>lJD*|oUOI{*v7TSSgAHeyWW*e}tMK)2|A9pB` zN&}5g*CU5;Zte9r$)x3=8tdbhW6U6g(BE|?ZLn5-ZqF(;KlYs3JlrffP4)P<xQIzS z)|m7^bkP@ihT6nCFsLfEPQPgZU2a7Wjk6A9T|dA-+Bh{ArNi%z8%V_LtmZPiRNN1Z z0L1^Rwzq()a@+ccNu|5HyStI@?(Xge2?goy?(S}+yBnkhB$ZAD<lEk($5)TnbI$$7 z|B>y(80<BFv({Wa*Mu;p>jTn|NZZ!F*BZh;mz^*kDjbS4aYZ(G1=RA?1cL+ir?jIH z{6v|}?E*hIXC~>-bskgAU7zWWC59-~`>}+yBKlBP#ghD8z^kH7hd!%?U><9?tgbGR zm-t7ds#9kggcfVBcpI(kK3hL;-c}yboie+5S@=3odRU2u+|06abS(@9Mr+(o*EJ@` zyLvbJYMn1-(}>0SaC78}vE$nLvnzH7A|kB|EQpXcyUp3$r}wI$50`5B&vt}yDhy45 zG+EgA3O?V(r%JF8afz}>ep+*X<^}J7f504yG;TW4&D5(R%tWjr%)Ei%ne@?bpL0uv zBsf8^F(>q0$w_6>H64jLJ|VdV2_uycha<OWtOHMeT1OY>v`-g5FVV9xeqOR<M3^Z~ z(OB~OOd{MKE|NBgX*?*boP_KIo>%vnGT>ZPSqS)_9S*rAV|oYp-%7_>XXZ02hiJr( zD>Op$rOVD(5of=`IJfZ>)JG@4vM`|&pg~5}lu1!X4HbWckx^@5ziXjYI7rIT?}yI@ zd&0gd%J5+&A{vk2j@C1BNBI1wEW>6|%AS3IqolHsf4?;OwHC>_INQ4bwj_MHk^cWI zO{!=qDXF1+c13a&<j@TccH_~cCnOS>)+{rJ)D0FzL@v>%&-BlTmbG<qJY|{{dwhm} z)qQZgC3H8F0>a#ocjA5YSn{wiOql=DWx$~JdfDovy~EDiGh<xu@%{`=AYGU;v^{x$ z08bmyNo9<caS>KpG&+(f9Gj^VvtT&bZM5r%LRwnH;pr^mY6MZ3Hp&eH@vha9yWVRJ zModsAM4sSWe0CTwqqkZC)mGf3M^u+)KGpb3!;ZY14f||pYvu3F+nx&$?(Y}&EJ?3X zk{$)>s80=(&xg)Zkl?@fQsR!Pk4tx66HT-gX>)U_Q>bEfX<aTpb>`?)r?C_xJS8a5 zZ!}fvH&kL!NyUarc&;?*#8fn;Q><2IvY6m;YuKXdN>8~OX(xLWhXFf5;ZJsWp=qF1 zs6E?+UgmN1?t@oAjC!GNH8pdiQeq1}Obhf*6x3TGm-7p71}sj!&Eo+o<bcXS*`<Vc zXY~w<9s&FF<lt-eqpMv?XHQG&n^0_}Y2HNoW0lngU}5SQMH-sav=DIa8t2tyA9>Jn z8_~8?xmLuJBso?H<HZbs1r$!c%6#{FsX6`q)`R3irlXUgjCbW3U+&VUT&1bS5u(1& z@F<)#=46ouV|@bZWY-3rA)puxXPA)`AJp61FO}Pb1M)aWEa%&`RcED48THln$N3vH zbr@+ZI+-0Hf@IQ>U*^TuxK(sGkI$1H4Rs)bZlt+Gr1h_lX5viB=FdJkCxc36&z2!k zKw+jT>0od`G=h4{t*AoPYOGdUd2|Suo8$z&?0BDc2j8#K5Ln?biabsAra^P9;e6TB zyhz=xR9hM2!GA)5gJdj|B(36V{F?GZxZP{Zmf1&<`>vv#>I56Au(+}a=hw{bRhI$X z<E>VApD<2dE-A|Cc<_8;&!apM*f7Os(~4c==Ku|>TGV|xsVn_FR9AX=1bfLG2XqE= zeMt6VAa5OG^8_POh)}j_$US=dxDQG>cd;ich7=5mJP|<}hL-R$&CM~o5nrd?8^Qp) zQJ)-;r9A8fq-cdITzVJ6TMzPK36FIK4e)((#vTQR7siD^gUlft(^oiJ>jXU5%&G_; zgU{Gs_%`wPiqjBN`4}d4w@metI-lH8HVv53TcKN3f7V@~o5v@LQ&{#NT<kS>;(Dbt zC$!1(fG}7+Xfd~U8JaGLqlC?Y>yGC2h$Muc<7)U=_Y!No-RJQJs~6Z2l$E{Miyn1D zCZAY4ByN@i6)7<U%`(j-l!sQX1!W@EuIqxY2>pXTUUb!**=J~@+|MkSSFgLoiR%6F zKIM2%PTxJ*Eoac{PF#d2F|ls%x3H&Zw830Snx?j*_xKntAz;{=geV23F{4Qs)Lw{b zKv;AOf5jq&NjhHF{LGMDVh3)bY2__P+BQ$eWw2b+XzK1d@%z3#?CqrJD=e@##9N)u z^oZ*Ha23Up5VS-$KGD4vr!vZS3~ALZtlY+Xy(GEy%2hDKN@$H-WQn!9=Ee`?aPvqz z$}PZMEyN|`Lc&$E71T~26mQ6C?6ITr)}65h7ryERTcZ_t+eU?f_0=)GP`FlK^5GD! z6|_61-bc(h921%PgO3dvBp<*}Tyc)i;i*T6+Z2D^weeb~=Ai|UR6zpJ$!GhU4*u8B zsAgjL<u?;Y62@-{6%t})>}H=K1a344rRV2B=IoSt#m@*SX4^uuBP3CYi|62kD|Xu) zMOvy&aA{UaHT&LjYjb2v5_D(a2PCtiDYx`59DkTNzL*%Z^m+Jv4N8Z%r3>v+&guZn z&bw+^V>jMw1MkLD4m~H6{w}Qz?-=S?_Jbhh%w5Tt(+Ie$XbRu;j<P7@$2y79qL|0X zp7cvf3x55$Sk8O~3f#0dIk41jPZL8XiM}m4<b-51kf={#P_P3a4G$lJ!MO5-rv(@x zB{~xgMl#na!i>2RxoYl4H0lx{KG0&6NVg)7-kTI!B+vNA8(=o^yHi)^o10P<bxFQp z;EE}lkt^W3)(ap<!3@+AP~8vCBxeho{|K>?Xl{gwZNoB!rcO@^6_@{601ZV!`vBey zQAQ?~(&t)43SobOe4ykWo<+Iezy7|gqdocgM>L}k_Mr1ELOgi9T97MY)mfuPn7He1 z9#<G}kI$^$!x+B*tj3||zV{YsGVv)NLsaaZR&zM&n+dJ{1j$WcEzjNNti7SAJ@Gw! z57b2}$Efz}@-y7yH0C*<iL<PUvxrbP`}TA@{Sccdwei|gx<#$!pK|uhQK@<51A3e1 zfGccS{<SlF>u%ZrlJFz=GzQ@DPJkpJA?lT?T0>uI3J42C5MoGRk(6|wI(Swt5-(ag ztqDrpzm=O2?iSD8cu*Kv+IHtY6FPC^ZmVOS<l$!a?0mex4dK{56%6t{APGEsCWZ&z zKy#SfT^`s%81GD?Z%Of9JU4eUC(r{H(4kzi=W1aRDp@|aiEC<^M=-5A_+&G>ihLD$ z>K0(PAl@w4fqbQzt!^s5aLv1fFjE6z(tn2YF+C^t1irAkpP_pBIX#AGX(TyY>v-$w z#(Aq$s&j*hgIm~Lq-M|vut+j6%s}fN<cs;8j7S2Rma3r^C|p7lXiQt{Q!?MEJ?MGd zj!~H;&qj^7j_oC5c30D;<@5Y~i9l=fWoGU{?p+aRM{Lq2myuDj8%Q0fECa4b`p*S~ zPgm%@+sYm7hfT?#%HJqKk;(156>O(k={8Y%(Pbox@jb7YzoI=GQIHrDo>fq^eKK%5 z^bCp^3k{ZMAl8@Mz0_c-3#t&qHp@Z7O~=3qu-b@X#Vb{>f&l_2mvyDdBsCCOR$BNn zOCjJBwR~mneQ}B8!$*a!N%xMD6Ns=8)~ilUZ+q)NcU{&kYkmicywzIaAUe5}!}=w= zZL!oMLX#CQ86k5CRP0=;r)%T(SAu#^B$+TmiZNL3^5dA3Sg|r3I`}i4WuUYuX6^d3 zvE2eX>JQ;#^W-N9yp8gSLs_(*h3h_}$MZuq>ma-iP-P6CO(wwBN5{m9(62NCiIZpl z$W<ulPa11UuW}#y#;p&Y!Tx3UBw~EK6Ge$qJa)6k2(b^&CPc_ly=!oe9-{w)l*ek% z5rRQXK9@weh|voe9`Z;xAvxC3E!nOIy5j(h3&OB>h_Ng2h`dl&2RI?d5U4_Q7$@6U z!z|;0uYmH55r;Z|9AiB+3GccAynX}FL*)6lUjOqgBT9hXvGRZ$oFCJk7;ARnqX@{) zLiF(?fV+rJ)u_MAm4A97yCMXM9GjfqWpqoRI~3j(K5+}g7r&jEuVht%{=BZu%&qgm z^(Osd8!+h+Y=kz6T1;UY^NOxNgT)kugn_zW`$^!O8|rGWw*{}b5nlv&AfcW+SyO4x zh0NeORRvQuYoIUc;5Df2Qx)3=VWhzee7?rU8w`~5C$um6Eg(i{7~f&_RCyL+Bcv1R zt#3bFt!`dpq4G6b9w!Z)tF=h$W_}_=oe`CFgHi?)61*w6RNud{;3MOn_SzJ3`0ZSY zo~+Jn%aJr#Tj6B1w}&$Nk?dTo4YXbVRtG&ry}Ik`!fqYi4b*|@j-3{lZTUI#PoSHa zsEUaY>miz?&eCpB3U{1MGptSnI_MpfX~w0;mNy?HmB2FIRI7ey3Kban2+Hy-^7!1L zLR?CPN_Mm?Osx>dHovKjQ$xL<0<UB!FWV4<7$&dXnO>8dyC=>gj0$fXa&6I{C2>Yw z)d5tAD$|e(wlz86Q43Cpkc1UCuYP(5clwha6|5LjzmD1)*g(b#XCDcL#ro0|ACb?Q zy0^GXtAL#n`v%4!<Rf{{ADM{B4&Y0Gyep_Nx(N0uXD9;+mpP8oKfKoFJ^<?%b%=RK z%Ed}SF7RADixYHqP!?g<Ob&q`ZaPUQJ-muAgk4^~u=RZ(@IE4(5yn%&_grVyQ>g@n z>gF=BsO0oIdTD2@BE}21>?Dno(Q};yuA$0&-l5?>fixvb6j|K&B@CX#@05v+)8Y(T zmF5X(jcT=DqraX9mv!x8cPNABxGs5m-vQ4NxRNtxA5kw@gM+t4Roe;lqeE-4C+NZh z+Vfh#q}|`8Ui-OC{}#ko6ahh;7g;c|JY*FNHP`QnIEX<vG!;Q;j1-L|<tvJ)v~h7& zL079f;CnE=OSO8*0?E>QApVhBvs&wBR6=@Y-u9xq^n;^=&PSg|0q7ZZIO1@~ghUBc zs$;6=BBJ1@RE4MV-NdL+c+|<N40-yAgs-d3>{nPTn1o2Q=$y!vW~fnh4dkg-mna>Q z4D@&MI`U2|GKHvHD=TPcW6L;AF$C*Omz?)7wn9YTT03SCCf7iv=Xm$iT&T?-@whEq zdWG=lP$%XjEw~J#m`!3jhmlcY>D8pm$TYd+4K=hM#TsER(@jE?9h>WZcH_y4gHxP$ z6(5<htkQ%#q8ZKplvGLK-ovn_UI%7w@+q;vq(k1`y?}|>cE&OcS?FX5q0}hlr1Btv z7F_OttjF*+mE(r$iaQ<ng5jh|%Fdd2k4t-l59|)gF|kIZHqOjnO{Xru0+q77+ESyS z89|szWrf@Xqa~Xwu=wcUlxS84vT*ASYY9w7(HynAXsdH?HrD_-85xG^B>hSWoH(29 zY8T!P>>gjj8j+jKD+njmdB)pZO023q;}M4#2ES4BsBBQinlU9Kwmd4nVIag?Z2>Yr zboK079Rh)Y+&zonO4RN!7^CrOCK#RlEGB7ImlWcQ?cFm&PkH=o{Sbp&L)hUd+P3cc z`Va4kQM^N(bhnJ_)&v-9wo{WhWS-5Q7KzGBvtqp@e=7Wt<i)^ll6wbhHgvEkVeks} zy{`b)E)`H}MDEEDR4m{CF4z$0>wG8ZBb$<Gj1{rB+)KdDv!yd|)-yx&TTmLHtT@l7 zpvB))?HJ9p2EO+{zNo#C3QQi<kD(X$d_k4CE+%DpNv?kQ^bN2dc8PcWXTf6GWzrlv z!Qw3>SBf1oiOkZ1)8RYsbDt<}b$0tW;RO>g2k0hVOgmo8X;2DmzpTD`?~4#2rllle zV}&f5Q10N-69pIp^;i)`zdpoT5*5M#g(zv_sIDfc+&GfiSQ150ed*YIQU#!G$9W1~ z3K!^k0_h<J)E98Ca;j0DIN$$tGZk&lK>84%desBw<o+%>)%U)#fU&WoiIbCzfwPgh ziQ^yDEJIlbkl_%+N49pDY!phuycl8u)dG@Grc_utn_^1U2$T{Qobt*j4kxx?)OK}^ z;Q7I&Aid{-iW!bs^FahN8jiz<cIM9@k6~B5*x4xdfoF!3nHT9d+aBu|nHPKfoe#bQ zblXbcdofYDPwm1CqzAYWUza`W@ifFpV$31%dkxrrZm-gfvaWUtTxc>jl&mrp;03nW z_xK!)z3)+I^DHJj%4F3zI<0ljVbBnw91WvKx7Yq@6$1>aO;P4-+Vh5PCoSy4+49|v zEz~6LwAEqS3(2J{83y4|JuTf=o}vk><glZsg&1T?W|#Dp@6(=7%vC(E{J<Hgl7*pb z7;Sn4IHN;_g_dP!qug9qtR^jpB+^!zCe>;be8oqh;WdivNp8r<@QM!!&3-ty%4Yf; z#%aTFx?_@d8(R+|Pkxw~vC>Y(W0u)E?3zRYJ#gYcb9}RsyT~(t)Ic6Ou|GpY$xTQ0 z&d5xO_tp?26yM@l$e9S6PqI$l(#7<)k|PE4Nr81!I#s6uM1Mw5POV>6sG5TE8Pq4` z*WtQ>>yL91Om#h8vi&@gFrbrHXwq?uE>6oOO>E6OxFc!~(9rLa5*@TeFvFORi`9FW zgl;J34fi>H;Fv2KSoyDBhRRh7uCZp%TOV5{9$CQI#o9|2A1oKzVzE}(OU<s#%R8V$ z`yH2td%}EtRMH82<HT1m!d0b64yKel9;isJwR;)(p?H~g^rCG4)B2pE!n7-2pFJI` zm*!1>q>;18Z4&KTKEZI_@XBklK8wMq^x&PdR(S-A!^lw!kFledIn6E4>xL_^gmzh8 zA<N&13-5Vc12-rM#odOPQE{_8&zS&)ARugwHievy)!%>Wh2tEHZvKGPMK=?NO7`yV zlCEK42pMeV{A2_f?1rGi7%4}`e~<p;St5Rp5qwO7j&RnK!TfxZ$6$qJ`2nGj$n`0> zIeY}EM?ZbVQ0DkXc(nE$y|bC#8PE_L{yQt|R~JM>c&!xjG>97lL_&JGX@R)uD<bCy zlfpEiScm&0rC17Sxr<22#P$9dI(~eBWcjND5NI)jxZ$&;&4DI@C!5SYmc`LGd**MU zy@IH8Z;bqhZ4p4<VG5!dv7pb~$#;>$OjB=UYg59^hKKsHw0}A^(>O;U9o>{{Grmo< z_E#ZuZ^$aOmw-5$960+x?%#xHM=$nC44)9i>z?3Q&toFqT>!cz-Lpc6hykuvN-Ow< zka_Q|I#CVUtP0UH&^}RnlosY7FQ&ddnJvUFEuTIGL7;$WJVhqIuAlmo5yGE}y<vfX zVsU_g0B0e9>>SPL4eSj7)t=tn#@f-|i2nPW{h#sSkATpwVWF?B=JGj`h1rhf`7%1a zqcvyZ_Oy8IRv$^E^<WJSJyYxl^-yF|I0ii4QRFDoKn+7qQ%aU-APq>Z?5TJ<Dt!Xk zt(YV<(40t#v_kB)Y?631L1>+96Y74iz4oH%aF$wF{;4RpCZ|c>z10(+o7HJ(e*Oo} z_&ljkptm3$=5IMc^`NrRUm)q<aDq-gecSsHDDZ3t$hO}DlpYMB>m$_leTmO!=|SDO z<*fI6q!0H2zMU}HcrOZ!UR3bD$Q!TP-?M|g*8zGF_2RVWGxZDBm#X)9zE!2Ci^{iI zFkWj>Nez#v4_-ptk4s(bpz0wnO8Pptv_5@w1*+QO2ENDstdq7eKYfCE8wJ#QnpOIt z(|P^H``it+X?%=Z{G-o$5BKu?{80MbKGtu^fy;Y6_<c%u9xe7J>#rYu?zKmu<59UD zN`nba0^^kmRC(i3st7w?V%(<a-7i;W_an)NNYc@p7AQ+J_*m9!yiekqSH+KhV!@I> z9BnFu22si$6<JvB{G1>?1gBmRq>di1Nm0vi(|K7Edc-J%QNZd25$gi3Y#`+<u0(hg z`PPALWVpz-(b_{u%~g6*qvDNvNsjQl=mbQX{Z4K#xn^!#lhz=pClvcpBD0v(l~(iI zf;9{cF!<6Mn+lPhu_40J)w%Y=A!q7Tm<JQ4xr}P|>;V)Xpv8z(W8cqnm0E}R&}D~; zR@@?nas)!QN}4+lwA$fE9Z84=GR^TECy#y<eFGVh?J<zT=d&8k*;v@zd^ufV%z+w7 zo||XA-aX76806OJGoETl-U32A5Tc@m(Jjr9xr7~QLfc7$;w;RvYg1n{Ui0PWsJdZ; zvF?b?>M{Dgw2rT;XI*i<;l4PJ)6|GCv0q`ci+iP--?9E3J?4|i#J*zE;)AGxitZ1$ zKGdu@>-cqZHNqq~E7-Ck4M(oenV#l_zbQoud-t$EahJp0Oo$a_YWr?XU++%Wm%U{r z@?c9}@1U4la5)zeF*UU&Ff_Y~><#<IoQHtL2Y4~KCHWhFn{nR?WT<kArjTw~trY88 z_XH*@!O8wHy32lMRjLFT)AH$iZA&ym4Od4exS+fgt?fSY6_~jmOs(g6XIqpC&&8e1 zF-Be;+L6M($rwx`cMoz^B{6H2-ovpD5vkxXV+G&ylP$W9ODkf;otkB&)kBW#M+yoV zZbnrg28-zSQ|DB$Brk8@9zphdPiOaHC3H!|TWYUHD?4@bbzM^1vnjZs*&rAVVfqF# zcM|s$`A-G<yo)VTvodK|`RWp~_=TnUWy>~BeIjBWRM?9)b!ly}DHUL&TT5YR$1UVW zo?0VI9%H8>gIggeF>}gexgovJkyHqdu#mHBhjMaY<RtNGr-cdi?_5zg>EqN&4MmJp zT17mxz^J9phqZIBi{MR}^Fn&VLm5RG$hGa`IMJU-ab>$-kv0`7hQx!oy<~ujqC|9f z?(oJN&Z(4<RA0}JVw7xXRBZweL)y5Jw6<TY#(K+=u7eQCNrH+YeyEUWp|RLe#|6); zOeKLZOva+yV&GOW6<o?p_z803)c69hm^d$+Nr<+=mM#z7{%efSW)tN`Arl_z{B~$8 zW7;8UN+qX=?dUT8H5<ah{1(-mP@{do;VB#t=dwx?f%$?OmRl9Ku*hzPS(Kxv<&+g1 zBW*P-5ty~B@zf>(ls2`sLu-mW7F&EctPbe9gK1u_vd_e9@%K-b>pZ2XLHROxizU=j z+{N45v3a<xUZ9F9(w4zMrq0k2Dsi2b6J``T4_gYg%Cu-MBs)fETa9RXM7%8>U4c}2 zo)J=HzuNcy>`9<@CA$eO9_hkf9uP7yhrt%;ZFWf1mV}aRbmqZZw5}F*&$llHJ6s8P z5OF6Xn+A|Jrx*HsRh1S-pD3{%c9f$NH5AO}+FH$F9a+n0xRsfl)hq<d+!k6ZI!C;9 zP_pgmofW6#dpVoNMz16-N4*PyELS$LlSBe8#1;p=nlT@Jm0BCnM#(<=blEkCP)lZs zY~`x1R~X6e9c0n+eB^(AKH{opY#1XK*)K=)#i5^AWk@86iXxu79xVnlb|)V!$3+Zg zG~co|z1OXKE+ZivpKDdSKqHy`{wWe*R*mBde8}A6xfM)fk|c)KuAJpi92qMNX<**A zDp6XE(^-$Hubz;Y`||-0aIxAFl$dNL&}nsPCpN%cvobt}i3xKgMn#sk^!alK2<7w{ zI@Zk}%39xD9&W*8K4C;nOBm(2Gb|#?biUNJ;;LpQ4}Fdi?gw-LKFg;EvY}qOu@vLg zi)_94F5hdcmbt9sy5-uQ{ish|PkQ}rM!V%kx1Q2g&k!pLSF&75X|Ug>xFdr@9V+w% zp|U|yJRA-;9rv`nn%AcBOsEq*7rjF_T5P;#b{Cu+2h}WFFg?-HBuP5n00WX#eoM=d zQ-rf_maX|vONufP+U)EK&x3w)L|N!Qi#O-fexF7T$f21qek+UMop<;-NCfHZR+J%c z+WUEw4I6AW#mQo3(93K{)H>NX$UQ7N=cI5(8N;;*-#{aWC5QpLUoMzx6snc$oa-7c z6)(Ni5nYWvc*#2v-bI&!@`kiZJrNqQm&0Z7r~~YNWW>7YLzXgD3!D>FW1Y2*5TwBY zKj_8~N_f!+&YRQsb$2KI20k)kPmno!6yJExWpqOB#6Jy}50mbG!Nbq1@75V+xo%Tt z?%Jn~s_BUwfu^;Treo46VX{NhCa6>lks<IBO(pXsr&0w}fMYSAZ>szr<XoVpY__fG zaDg%ukLY7<vB9JvofqkPn2I}2hI^KcXj$E}^>DgHn2Pp*X_{?oGI^T$Y(n>?CsdQ! zKKUjRizry8Pxo(Z8VJQ`sv4Q98j<XbD#j|?Goa&VrPeIFRj~&BM>Hf$Ta>}Yu07ZS z1#`?47JKAu;3CMU`ZSf`#_<d8%ID{ag1`r#Ce1y`^ly6qL4wAzZ|n3b(-gjJ;i|(_ zum6rOaM^T2f+oekX^`JzbLA#s_+5aUeFak>v3T&M0YcMTsKq4Rx$`um_as>MsSjop zH-qu_ILi)bYqvZLZ^QPxlP>r8Cji&7bxOnTVdkSlZl~i0;ja1-CZ2S0LjsC!`tWp# zU+F{EoB}=Anq_Z9+`Or70fld^SxSmp<>S^>L?E5MoL-A=!yt_~43$4(RZ<_Zr}4yt z4vAWbk$*U+)b;=wt!EBGWo|YP{G58Ll6vN%ylGPZ78~Y)9Xh(bN2kMnTI{qKdKCMp z+MyTK&Zds=vySDXE^wc>hniR479sZ52`LD!&O^LviKwPUX7@;p{2)ptSAdF1vrXeJ zz7w^NVs;B-RZEOHUK49)XZ~(!m=zj5R-c=~IG&6n?s#n|6JI25!EPgb?|aTdsdPd4 z>KfvpYaGE>JBuEvJW_m-Y`B)^>4IXIgmtxpZ9^*wLVL)kiTG`kLNGouxNf^>6O2+5 zXU$F{Q9HQRF;oo<`EaN+;$o>&MC0ah;Of-SH411($SYbqP#<Conlq}hUwMJGD<l$+ zUn5%7;cf_dRqmwRBQ(R67$roAz?V3;+R1f9Rqla0qu>vSVI)71T(`?>3LtrKy+=bl znilKUKHSGT*e7u*&lJI(;e&U%hqHon@k-}8ksmy9oIWS=`iuu3(9Umy{ibN_CN$RQ z22#6%{4EZiqq&jHiy-nKD>4N}gu^idn_#W$RC4>caVA!4ZT7B_d7ReIkhcXdkf=Q} z7h>$}icf|O+TnJq34<c8*lSaI0keOH96<%?tsY3wPspYjh8hp*+j%o9>*CPYmjT{o z-dWk;dM+qQ%Ng`!Fgwj6lzFRooh?K^Y7x<5Bux4GRxr$qSupIiSrjuIv^dGAJ?%*& ziuXys<hln|Q<FXPdiOP=F8OjL;Tlgct?NgMyR1GEzTxJNEe%DSpK){vY-~&(qCPa% z(Vx6)hiUOOP>;gmn?)NUqlwX_*#<3FVKXYQ7D=-1<ywlQtp(*aCO=NpaZmct|H=^> z&+ub0%r;{SD!%>$BxZM<BRScQ%WeLL-lBJOJfwGwq=@OeZ=7&EeU0cHKafUx2N=<h z7Dt4EPCeSXdvxCeS7;5UJx6-6zx)yMlcMM?Co6njY)_H3I$vLh(JhNrl*6$Z2Nlj) ztRw&EvedQ9y~Z6&=N8dKo}7M?(89_-$l-+kU2qR^5bl+?(i=|fRwM9t8hcclm3ES9 z3Nr;`Y)?bk$ZvxDKa6?5sIWcY1Y6C>aPgH&HRA?Vsx6N5oFWNo0Y_FR6ua;@nc2Kc zAv!p;`I!F>lP68ivQI)Chvf=C&E#Q4l8n`Bx$UB<MMCCk79+boGg1kIX3!d`9be`A z8E}Z|UX(qnoe=E3qxb7JF3+`KFy%eU4^(M+CkE$B#NeMmJiLLWTby4oWi`9B@f~)T zq_p#%(A!VFFFkwjv_e`Wu-N@+N@7Uq!Azbn*GIP7b0KrP<|MX<#Y}9S0sks<vt)Yx zc_G9$O~%;Fq_F`Okd@6tS8P$uoyXkVh9i=vXlD1Z#O)g=B%w+Dx6QcMJ**?imc`^* zgGY_mOqnMJs{`joZz4CYRqlT}&R(&!E4ly;1cZeL1VsNgqd0XNYejpbuT!aijN~fR zA-!-^a6jwTE-lFx+K5N7@HW|Kvh6jZP_Y18NC`!e(6*aX`K^o_*O@TajmgfSD8KFk zwNpS8p=&6922Ws7f`pO}q3f<!{MI+r?}qlaJ!NV9*fcg?@_f|uBJ$C@gXg;E0X`cg z!muDzZkrj3uk5WXYD2Ts&h;AAvV%R+vVAd5kV8Js&0Ag0)gpcQW0(?-P$R12K?m?G zrBe@7R1S<DP)EGP-d9wGTejeO5SxIh^q$_>i6lXH5`X0LeFbnmRYv%zfKzt}J%uwB zFB#JAs?kksM|Z*8$3j25fK!{6&yjv7l7Q1-9Ub&R_(PjPP(Jy&!zMR_gglfdpGo|) zB>niIHz`r23ZB`xYj#fx-3GinPI8Q+xtA1yhAVY{(wW$6_wH0n;%3S59<DQKbWfQl zihpP`>ij&5q=H{c^9ALg-WfaRy-q*>sT}yD;;Ef)Xt*t@QAtK?f<)>-BrG~aa0E!) zVyfssB<A&mdZ`>es3aP%$CZm5bbR5M|Fh=tdZcM}F0_;BJcqibq^3L`36com`f+I% zXt0oGy(X~4y$#%b8I1#X=d6xF-pJ!a85^0wCWn}rBby04U$eeXAMn<y<Ia+08W#q` zE8}e`Z{ed<?{Fc_v0;Ro777hh!ZQ(@hk{DQ9IrCNZTh#aRol4>29Jz8j|nZJ3T9EV z2a-TqQtb}ZE)Ot0!%POQqzCFXL;CBlJ>$AKjgZ&4=qO_3nr@0*EHjd9)<$x|KV>_k z;;kKnJ`<j9o)duWw$!f1LN6yPx=aNrfKFd%WM9A!D>P)u%zI{-Qg72KKr0W)Vj?vo zzPvYm8?&4N;@e=FM90uTYq5{(-R|jZ<!LP!%AH_inqG;LC**Ks^W;M&$&tc~bKPf$ z%*d@r+n6BKL=8o6WoJEcux+zZv<y|t)rxwClsL8^_};z=zRAPGNm$O1W|7hWCsmIx z%7iV6&kQb59V|dygzdYkcSejwnA;A29k$|0<CHZAG>LU_O}luIiyiJWdsTJB7&f!J z4TWK>Q0fF`on|x5?4i0q52~0g%nnw%itX*ngsNk9d3C5dCX|z}LkPATL7n$9HBUMM zEI-HM)VPO%R#D?ap0!&4$NPzq{c8+`7T)vP!5kJTii|u4YDTg%n~sU|M^oQ`c-MP# zG;>U`50Fg0)Vgr9J$-$1se^G&J$*_d9`}kNU6?+K;YnU3Cn_N|Q?xfGPWQ%a^HVnw zef2DdiI9HRC^JGTk>WYf;r))lwSv*R+Gygb)39k5dHMB|l9194a<EJtMpoEOWfJKF z5=y5J{qNMopzNZ0!}+07AfG$+q=PtDkFFY;CL=YXm9-Bx&H{G6@Yp=}S>V}hkWMWT zy}4g~g~ahdGF``1P{#pAW;&8bCXbGpA?tn7Fsjb|iZqb`k~M=n*Ty?~=uV(%7mDVr z?X8lo)RRPXG_<|!-g>QZzC7v;8_6e$F<FW3BW2x(Y;}{N?<*vVw$M17<AjUec4Fyv z+0fV_8<>ePI~Mdh)9GZpwI$Jv*0a1G8h~<GB?_X0<*rsj6htP?RYnAsi4VypLqRme z*Pv-6BZE{y+`+1nQ|&{Mkw!(u>sRPb8=M(46t?=*+Gg@r?TCSneau@_or)-ZV&SZs zOcpsIHF*Floxb)(0U7AJ0LN~+zfBy3Ng4KHuc@0l;w&qp(Ab=Cf-nd5>#CqsIA*cs zcckgpAf(d0<xo-;t9|Rcr15StV@UItaSIsJt}SzS<D)uI@r5h(=ON1eGI_zBOIVeH zRe^3>I#`P5@7LU;$aaHU%F&P$t$e|W^S2Z6>aOg4{1OCh;sj+bLSRRzcP*MRs%GpV zbt^U%wFd$(NKLh2s|2L86ZK{2)Z?HR;z6ybfM)H>F84G7CXOvAOUzgp^=R~4un=iT z6RLt}dAGr&+@;06fELY6Xvf~<Cq>aOu=>e7*M6gR>@ZtGgl6f^Te)y*`dXxS<<u4S zq{}5#JwK$MDcZ6RNrYy;?|>*bL{p(C<oR@Vi0CSTO|1^1OlokbNvb;CgnS>AOgiO+ z<CVMPAwH^i|AC_Z#po)1jUT!Rp(@EI_n_I$((rKY+zh;uD=YWCaHXS^=#ZT3ilktP zJg%^@BKFKp&u6lphAFO%?e7(z(}NFloMfzl>;&@Zd#3eU+pgCojS$R)8j6A?%F07K z647B+I0v<rmwu$%iw$QGGu8=<8Xq#}8=!U2Ky$rQ#Mxm`^p^-hRG~jV3Rt~sSrm?* z$i~(Ifh8w>owfprUMu5PlpWiwc&1#t$u(IYtjDS1-tAH%x#WXZsGS%Il6_yav?_Sg zD$njropQreI1rY`v{C8)I#HetqK?Su8f!;3=%f&>WQXyJZHAfcHrWSfC(~&}U_6|$ zV_2gqF2yAfrLb(iegXDPYmCE2>}*L}hG}h?PLt;t-3eS)a?G0IVJL{pJ|Go+<c$WJ z5lvgBt~Kj1TN|O=7Tc>C#uwO5b(iyp)0vxi!{`mtZ>`aZjaDfv>xQ#(;rGw@wCLwv zPIk85k}R53DbE>1!VL+QT@<X@ps~hlNFCF_$m8d>u&YFm*e9zqO4j!*`fczZR3q4! zKh4%><El=1m_VzPv`1W|;h138;xjXyb~9b@HZwig!-;K3xA!D?LG`hpFD7q71*P^C z$jD(J0?!8^7bh65H0qeQ#VzPluSm>%+nc>mPTS?-P=Tw?fazk|5yU{k(h#$yyDqK< zyVmR5H!;W{y};zogizfPc5tsE2D20NRkAB<xa?8l?1by`<8@eu`w0q-7cZiWEcYCg zo#8g?M@9sst=?@A6v7(}oC0gNmC`)E4mG2@FBedDQs7*9Rh-_N(`t<XjQ+aS8p0_^ zEn&FgW0~JaaWrFrp1f*KaX(^lKcrz_^gX=7+pv<Ccw^4Hat4`2jez@hYEV&|qYHH= zXCv-y_A<geJejXL0-Bn(;8Gt5U>|8*H#wcTEY~H8Peh<$l9jIod<q=EVI7_>I8JV@ zTl4tBSjQus<n3=KDL*pr5Aw|vVe%jkR{?)0TB>~K_VPmcvrYmlHXeB((4LITm5{o+ zni_ww$c;cuS-&Ev%d29{zF1Im^QzI(1LwnR!XhXi5jcV=LewP&|5k&NSf;U}BKm%! z^sozs_a*s|J2>>42L;K3dYPhfnR349Gg;`<VUwg%d$UPu7uTXt1S$$**Q!oFw5akU zT8LC{T_S_i9Eoht5o2Vs_7?We8eij=mvzEl5ewvSwY9$+u%{Szw%e(Ga`t2(3nqkp zONNh7Q4fa*bK}-<`(RL9h>`dX(rE`HT)P*H08%fk=@Y|@{MgWZM|kzeE2I3H<QOXm zr=#R>?Og;@_@iENBSzxIj|@oBRTPtVnmnR{gVVx`p=iB&S%ab!gQCSlt5Tfjyt|t` zJt~xYI%3ryzzS9A_(PewPP%JBAsmYw`w1qj%lLhV2W#r<&dUkQaS~-8LxqkUiQjMS zO*OT&jfC9s=-~@qFi<YcB;;|dY`d_vfb#`%HbX+6I%KYo%&t_!G;!Yt4No!+I&8cb zuN{puhQs~r?fxQ$#0%FW7Kc1N-e0>Ry3A<>JAV;&i^t+ZOr9?3-BE(#MU;N1Hj`(@ zi>?RbbItLD8_pe!1qc{Jn_dNNhF}-r+0;FDmwH}%aurW><b}0j!x@d2y~g_xiQBqZ zmeDR&!6om_Wl5M4nI($I#e-cwyt+lG(LKPZ@t4#bd4S)3B3H~NN1<}AB6m$sbKPkm zZP<d5le=47Tu#o;6`8Y@r|iy$ih1EB?5VqStU$@{cXd_%3|mq`dY5nlelLb{GKR7U z)+R`r)7EsE(m{S>D@S+xV>y)qe(yl6Lb9CvOR)<cc0C|;C-II--T>$5*4HW;ZYW#w z*b(az+hBq6Y#&Y$^xws!2=^~>t_ln+9NqfYX@$rkvA=F4=v$7pftqkW1$FW!-lAYz zdvz6*ff6H^2lf=F<+#f>$Vs5n`$<N(#N$u56bUon5v&6?4jlj%f@S{A5aH|g$*%*3 zKQ@{Fd~Bm4-b!f}a7WdKjTERwvwCs%7WmFgqLea<2ueaEx+xcv5{4*$p+k|sL|k&d z{A0pcFr3fn)7w0pNwS<mbbolCq2pcS4YSEiH}+1S$J-DRG=*5gJcgIRC?d>R-5_Xp zHSxZoZMiMv+kA<nJn_{;n~1O8oy)-<e}r+`@jiNHRf^{ZFMV9**>O^ASF!{Lnqa?$ zCDb{}JJ`rG5zViLGC`v9sl)*DGndegmqPQ5$Wnk#pz`o%@sBV`uwk86b7iY*)1_o0 zwI*7NV>;ukeV!=NA3XyH8Sr8ny_2l2Vr?|EZ(vsp<=HGgBubB8aLBCEtk}xT<H&4m zTh`gOMpojTmkx!u9p1HSI9w{JBBb%XqAA@|mX+drtE`z2Z&eY&jB*|T-4;{wKnpH( z1~QUJDul+rTAwZ&PligOSQc0@z&EA*QAKGl@{J$)CL?NUz7{NhVMegUwx0NEQCg!o zT?)GD@QQ2i{6{Mx4#w#`cPWrOeXu$x6c{Ruo@##;a5;j*y^BJ6>F87CZsu}o_egXk zT`Iu#Lx0#n_Qzq`z!-h8Leu%VibFmT%sJa;+r{^d1%cJJL*`}qS`}1G(v2%~$J8D| zjg216Ydh8?7VL+gFyG9AGQD%iioIyrIq`C(h=#5*YL@81P^E2F=#78Y*2`>WGG%b1 zUS%{@XaDF7u5<|<CqRw^Y1}UXR9w{i%o~f6iy&#=Dsi1}DxBo1xBo=H|DzE}DD<E> zo&tsM^s~fVSKnn3KRQI=ehd-Y0H${gz+idQ^)S$)Y6lWiw^(F(Cd!BXO&wcmBpvl{ z4+xrZfD-Hl!AQ96^MW{*D0L4gJ0w1mf}Fh)rwL1ti#FURDIb7v6i&`17l~Q9T<v!5 zqXKUOaU_bd-hiBe4Bmvy=TI%gbM9nPkIHf4opL@Ry3~x{)epOYeGtPPf)z|K9O|Ys z266Hwi#mHI@<Ot-%Y@>^PaBr1S&o-G0F?*<2?&Vw-&drsYo}@lZpbPqkL@Jm@y6yk z)&&LfiHY?VArO9w!r5rW@qRWXC<r(+gqTB2W76idp-{)zmBlUstM&rmNed&KBW90J z9?_z1WKCygWYIZsE;h%#PuA|*?mX#VJY3x2pXMR<5(-ZdZ|XzvUHVsJ1qpJ5i;?0$ zZd2ev3v@FUZb@GS=4^2&g&30bPT3Rr$BEb2w_;%G4xfikP#5(u=rc8;iXw38a_fZi zneHb6M%4)z`Uz(4?nM6N4yrv$NSSa3oSB<PP6p|Nb+0e9F($XcA?YRECG-`FEYoF6 zREtcCC0jYuhKn7fMoq!qspdxP#v7)VQX;IDo3L1gz2sM1q(v~FxGn`Lu+bE?nJkDZ z5lwQW5urA*S!#|wRE3Gyn=tH>wDhlOq_rY346W>ovn=P&V7hcKm*X{!g)Bwnj+S-V zcUZ*ptdP)G6+I%Zi?o9D&5LP79<eCkH{DG!lo*{cYBRUb=bBUEoUczk<U#4LJ8)*( zHaEZw;)GvMT~Nxec%y@=&MTy2Y$({Ejr=Oma#xY0W7Ab8`eM@_xZTiIs!Kag8__RW zj4>^Fsyjv0PLoY((o}k$c|@tuX`ZBifN@So-S^<g83rMG&WAO#PP}+K(o;-@4#K@4 zD9K|(^V4?e@f-Yb?vLkbrrOz8aDimXQ$~{RDVnOx78{Dps%fbb>JqNf%yYWF5itj$ zbnq{vmRRR;^EnP}+bcS8A-EulpI-0M@b0-2*k3n>r)ZPm7eSs`RMa73&DPe`d>YQL z=4<@a{>j|Z*q5kX2|F7Jp#sEde0up!0abe`At1LYIyvw-cA6qn2*!~`ivJ*#T4sKm z<Oms)e9OU_B$ZfU09PF+apm#UZ8Gf*ML8=CEph0Rk)tCV38v!#F375(H!sz|4Ij@q zVoy`U7aat8u$k8Tw3yZhxS7`bMIcXx-LuH?-{yAV6cuA@F`Ze{w@@0$4+Pzc_Y5-e zb(3OdG3gyNax@9~$_$uz4ZviL-ufwY#-E|m4K??SbeP`TsoP#RrYDSHEx+sui9Vz4 zKz`#9v>XrmI)S)eRuq{{s+npV*o(f}Yq?iQ|Db|AHZQlU>ka?VE#e}HcG4NLPvUeS zFOpBp8Fe6!5>o*(hzqkUkq()yXTveBk<&N}MCD~@@FH!@9wiPQ-mY}9)QwlF(9?0( z{<$sN&)~aahp(R-_s>0VX@s0e2WleNT8rJDTx)lwh>w3D$z`rzt<M71h4CE{5LM@D z5CMT^tt0J~D_qCb$ScUomgc*bU^nnQnH$?*80A-7B`#PP6{<p@OEb5hm{Dx>dk~g) zG2iuxOLl`Z|HML=kB|_9J+_oC^Zrtv$!1r+o5_)!tHq*mH&L3d0xQ(%nVK-!lA(zc zu8Ay!wT={zRs}--$NN|*sz9VBWuv)_YFuwOHadypH6BKZJZ_U#!{kHSr_o)<7WCpL z<hgDxqD5BXcYTg4OdlV$C#=;!z6p0Fjj+ZS8(N1V7d=t-eO?q{c6nNsN)ki&CjD%D zNaoFmq?K9WE3N^YqvUx!lY@k(pV}HyKR-RM!tk@x!NRs^jO_615V`6_SPVHefQ`79 zgDVz!*=Hy`>_N5~&~OQRI{zNXnoM?=wgXsilHq<43PV84w1~EoVRCzjxdHEH%I9Sj z+0z5NPn}rVcBOn={#}`$2vOFAtJ`xNz+$@)LQ_)vm4izdlpKZXt*;>@y>4L(gp!43 zTZk#P4_*_F*#$@H17FY@hlofgAdeb~<>ng9Ewe(*Hm8-_3PE0H;~c5`wxbk#J3H}( z2Tl3XId4HkkXLV9m-5-!b(h6&s~`;4Al@K3LY{2|$uycdKXPRr=cZ)kd4VSIP6ry$ zVB$BtV)JpyEPILXc$(6RuO%)xWz&(+5&k@-`PF5`=B-M@q8N5ywX;%ohl7JY#%N`> zv(hvy&54FKOE~HaUGixp8Upq*+<qy->Eh*qBmxOfatk#f@RqhvZKGF>Q?}rg8-Yj4 zF!`nWnljz>ScCNhi8(2LZ^`RL+!1KsUBayh;HzxQrXC5FAxHOK?tlQYjeFn<E4(d@ zd%?Z)DjGx$;Z%>-zoZXtoN~-hB4jjzvi8tVW<I`t%{6Aat`E?pr8>+|m3k!=Yun~J zLQt29R*yV|QlDqAtc;j-2;}hwG2!4Q+d&1#MU8|jTrSb}Vrz(k8nE-k&gQ*tcqK`G z@}970Oe)V~M?0m#C;X({DgX05MnVC2LO~;ufs&4L2w&PE*@)aFG1~-itRac7<l$Sc zq3@@1fPjK&Vb}p};GYjX;5Qi&WdT|VSy6f$16LDU`fuBP|N3RZzkV68{fO?5?MHN9 zw;%oY;$J4Zf5Q4}@js~0I{oJi(4V|O0L^zmu*)5MwD1OWiSGbgkG~uz`j^D)?QFg< znV_O&wZeenga3gaqi#^bF_lSFUVFftFxu9{Vst&!k~-3l7E=RoZ~5oD$Q>y!sknBH zJ+D3P8>8n=;)djVT*#6WYmnF4L8H$C1Vx>04$k1bUF`0o@Xbr-6Q2$MH;?Te4<tK_ ziuX9uF-mDvZ>k>z^W48CUwlJtPUGl0B>Zaq<i?%9p_zIzEqdc-6cvLE1~LVc3=~c^ zCD}x^Ss9p_t+Z|;T?vBv*~hD}o2^YDwASd*?J3~^9v`~6Yg$lJ+!T=lX(x*h?5~L` zTn~sYeH*WVFb`R>^Ho*E3nSF)x?bjs)(fK+Q?>B-BTJqqYE4<-3GH&e&^O&Sl2%MW z>7Y2Eunx~heK*B8(){Gu_XU+k&x0Ks^wZXtKD=ITs%Y<N`pZl|MIeRM>@Q{nr*+M` zqYJc^nh~3?Zx>K;11>?KUZ~PsYM`AhX2B@YD+*NW#nSZ7ey1tSZ8KP0P`&O4i&9HW z^W>F8&2GxUF!U>i*Sr{X(D*5xrVayy<&o8cBC^q}vbF`&em6%zQ}(&|BJfX;gWfk@ zzXZ)y83C<9+ri5*qZ2B4Ag|VC!sMcEVDrStnw$`Pk{qjWsWDLsp2;q<j?Quw$n($< zj>HRv?9`ds&nE`Bxt=DLWfwC11-IcGCXb}7A6;HqQ$AgyQ;{oEeK7JWIzkfa$IBwF z(&p5)PU3K*e(uPHHxQ^RGx)ZW18%^_VxFGw%~Wxdwzp=Zi=uJwu_BKnYnzA-+LwGK zk<_73${--}Hb<J!eSq-RrI_rmEAQ&mo?mJwI)rDY?Y;?jsc`FjWL}^hUFtq|9vi=N zP$lS7bdZSA^sBX*dduW~`}zND_We>5*VIX&9RZH)2KWH32mN0h+TPL5-o(+_!o*3* zRc>60R+2_SMnSw(`Ba8RYJ7V~5sq$L$(}|=je$jxfuVtkv4)97!QK@XPJw}mfnjfl zN{W_hVr;UGb%FWajwJmEJ?*J<%{aZ}q7;p|^o00)+0Zy8mH6(CBn{QDw3IX*@Q9$l zbC^=t%T$jRKtCH81O*gu1v}vRIj{f@Lw|h`fQ|&d{Q75Y{ay?LC<vg1A-4BByMQl* z0s{e|d@c0lmG4Uq`2WvhG6J#^q9RJlbTXpfDF6W(QvVpy0OxGJK3{<O0W`mCk^Ef= zz&hOjDPi!n#Me!gzbgnBQ2d{QU)cZaZp`16$Np9v=nJc@zbtQK;%s0HNP6;H2{3;k zbn#0<e@4{rHv3t1fGwq8pD+AS0V3^R<@vt5^t)sb|1pB5v{+RRpv(XuIzRhH2=LDL zHU1@~KP6K%F|{@^a<*_a`D3Y51|ag6JTKw~w#I-PKK~ei{fx%m>@v;*0|bN*ke&1g zG$X+I!oTwUCz^`0h4rsV=B8<tfB<y21NeNYjo+Sp-(|$#lKg{hX$vQ314C<*uWZX0 z*xOs!n*ACI)3;oG9YEg%0QIFM`}XAfvLpWksDGp(cvsrY0|0$DK#lk^?)~=U`&s~M z*>5!Thd4?ePR=I($xiV7B<{~f2t|K-GYc^8XTb29`5S$}JKwhe?O#ItT2HCNpIz7i z{AU7!4C4;~!vMSg3mJY*ey!}(;RZmq7N91TAIQrA7Uus-{%ai)Fm!TuG%x~O{{GEz zf3!J?fQz%aiLJARk%6;?o$YV^7zVZ%;|0Kvp$UP2_<vxb1^@pC3%{0^l-b8y5MZkf z0N{@<kwEhsF!?{)7>^&N{53?O6elS=z$GdHRulL^9x8x`{8yEJSLGkx_Z5l+;OXXe z#^19({p^802`N5A5I{hh0GIx;B6R@-{I_tw7OC2~FzHMCH1roQVdMKPhJ%ZVlQTeh zMu4L^c8;O|kFj&~`1&IGn$YU!KmVEqONL=CD1cUH0kO^W2dzc{oaQ%T{u36I>`ja; zOf8IlX5|~FjKAi|4T>a;5Wo`&z@dzP;0ago|20p)=ExwI{P-MTBn^O;^nc)}OZb21 zNXgm2*~A)P!hfkBOZq6TFKuWafE(Q(xM2|cf5*+QHKRCAT!aVE3=ZIA*^f=zg2eyK z%desI5OoPB0OB$N;C^fq<fMKB^<}xj#8KSY+5YFXil3`|eFh@KH~>KNF95dEzXA9m zuKc!f-m|P=VgeYh6cEC`j9I@u`M%+Rg_!?Z*}eh*B=|#?U#o}i$#B>tfFd7&`yWFv zwEVvy4p5S*#eeBsTvIZp4g<)40vP+pm`JPew-C~HMh4b@EE@ezjCbBcD#8E^WPqNy zzbOdt&i9p6`dbWHJ0%w*^RFTPr!($9TiaagXgd=i2tA+&@a4SIw<q6sPx)_wekXzE ztG7V@0BZGs&yQV;3H5(S_;*IYEl^jC1t=&N!26GO&e8Z+<iF>K`dKwF^HaI00R4*s z0`QL#1Zw?52sJxLtN+%+J~eMi`clV00TOV0Q#;_D?`sDLXMa--{?Pm%<iEBfzpf9} zdW&|+03pT!QS!%dfv^AfDF4Zz^#|6sY%xD;Y5PfYtqvT(&cr`!3Bu@K0sNYOGdP;9 zmjErj2FO77gO=(YentNK`00C``){o8Vlp#E0chU<Xbb#6`=!%ArY&e-EMjY9XABsN z{7qH+c%6L|41l`?z&-l`&erAMz<ur6{0*9~)}U4w0BsN8UOzTT%7E#Rzq;2i75C4e zVAbh2T~Gn7AHYC>e(s+Sz>_`xDb%m6|8};G0tC=ZkO86-)1P#|)DgO<e@gjxK??DV zf;<kOq+5VVzMKaC_T>A%jQc(PFD>a8%GM@;Vak7cfnNg2fAch+^mu$U00uHZmLGAf z68<L~reEtTQTh<>6blH*2w?FaW6Dy}|AO;tl%FpP`>r+ox_^Q4^VMNLN0y({*M5h& z9Qr-XSBw1jVa?B(Ilq&39{WA%uQvZ4Tz;*hpOY4T2WSQKPJUPWz5@I@h2hUC`Z)pE zcbNIPe+2XA5$69s3Gs7YsqYwD3;!15*UI`ihtGF}H%tE#;ctTC&&gH3BbBWFJEUJr z@^f~H@AM(w{+|AKL;Nb&#LssB`IP#19Ex}U5a-td{CsfYJK^KA-xK~itMx}n{5A2P zw_JTEj`;as5dR~flYFfxzutiLv%-Gfr1BkF6Bzin_3;O}{($~jy1&lO!+)dypP6SX z2;lG2?B5mvzfTkYJhe~wL*eAV76ycmzbp#=cXISUkX!sG<lO(0>EQb!;Wy&HUMBoT zKi`)G@-Kq^mDeAMe_b^EzxMjo%FTC-E9n0T!~V~89C;~lK!+X(ND%N(6)?-$0|V#) G0R4YsfpO>n diff --git a/graphics/AtlantisJava/share/InteractiveServer.py b/graphics/AtlantisJava/share/InteractiveServer.py deleted file mode 100755 index 1b1adeb2a9c..00000000000 --- a/graphics/AtlantisJava/share/InteractiveServer.py +++ /dev/null @@ -1,483 +0,0 @@ -#!/usr/bin/env python - -# InteractiveServer.py -# -# author: Zdenek Maxa, UCL HEP group (zdenek.maxa --at-- hep.ucl.ac.uk) -# -# CVS location: offline/graphics/AtlantisJava/share/InteractiveServer.py -# -# Interface between the Athena Python interactive prompt and the Atlantis -# event display. This server script takes over the interactive prompt of -# Athena. The Atlantis user can then type Athena commands directly in the -# Atlantis dialog from where they are sent to Athena through this server. -# Commands: e.g. changing/querying job options and executing .initialize(), -# .execute() and .finalize() methods of algorithms, etc. -# -# -# setting up Atlantis - Interactive Athena: -# 0) get_files InteractiveServer.py [from 'run' directory] -# 1) athena -i <job_options.py> [launch Athena in the interactive mode] -# 2) theApp.initialize() -# 3) execfile ("InteractiveServer.py") -# 4) if the server started successfully an info message is printed and -# denoted string has to be copied into the Atlantis Interactive Athena -# dialog (Atlantis menu: File -> Interactive Athena) -# -# Once the InteractiveServer is started, the Athena prompt is taken over -# by the server and the user can no longer access it. The server can be -# shut down by Ctrl+C after which the interactive prompt should be given -# back to the user. -# -# -# setting up for Athenaeum: -# argumentInteractiveServerNoAlgTools = True -# argumentInteractiveServerServerPort = 2323 -# argumentInteractiveServerServerKey = "someKey" -# execfile ("InteractiveServer.py") - -# Multithreaded version, modification made by Julius.Hrivnac -- at -- cern.ch -# Athenaeum commands can be executed in several parallel threads. -# Unlike in the single-thread version, all stdout and stderr output -# goes into system streams, so into the server log file. The result -# of the "remote script" should be put into answer array so that -# they are given to the client. - - -# --------------------------------------------------------------------------- - -import os, sys, math, traceback, random, time, StringIO, getopt, md5, base64 -import SocketServer -from SimpleXMLRPCServer import SimpleXMLRPCServer,SimpleXMLRPCRequestHandler -import cppyy - -class AsyncXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer): pass - -# --------------------------------------------------------------------------- -class InteractiveServer: - """ """ - - # <configuration attributes --------> - debug = False # debug messages to print (False / True) - keyLength = 15 - minCharValue = 33 # ascii table range (generating key) - maxCharValue = 126 # ascii table range (generating key) - minPortNumber = 2000 - maxPortNumber = 20000 - maxAttempts = 5 # number of attempts when creating the server - resultLengthLimit = 400 - # </configuration attributes --------> - - # other attributes - serverName = "" - serverPort = 0 - key = "" - server = None # XMLRPC server instance - - vxTool = None # access to vertexing tool (Athena AlgTool) - visTool = None # access to JiveXML (EventData2XML) (Athena AlgTool) - - keyForbiddenChars = ("'", '"', ':') - noAlgTools = False # if False, AlgTools will be initialised - - # answer in a multhreaded invironment are passed in the global array - global answer - answer = {} - - # ----------------------------------------------------------------------- - def __init__(self, noAlgTools = False, serverPort = 0, key = ""): - """ """ - - self.serverName = os.uname()[1] - self.noAlgTools = noAlgTools - self.serverPort = serverPort - self.key = key - SocketServer.ThreadingTCPServer.daemon_threads = True - - # __init__() ------------------------------------------------------------ - - - # ----------------------------------------------------------------------- - def makeServer(self): - """ """ - - try: - SimpleXMLRPCServer.allow_reuse_address = 1 - self.server = AsyncXMLRPCServer((self.serverName, self.serverPort), SimpleXMLRPCRequestHandler) - - except Exception, why: - print "\n%s\nCould not create the server on '%s' port: " \ - "'%s'" % (why, self.serverName, self.serverPort) - if self.debug: - trace = traceback.format_exception(*sys.exc_info()) - traceString = '\n '.join(trace) - errorMsg = "ERROR:\n%s\n" % (traceString) - print errorMsg - raise - else: - print "XMLRPC server created" - - # makeServer() ---------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def generatePortAndMakeServer(self): - """ """ - - alreadyTriedPorts = [] # already tried port numbers - - for i in range(self.maxAttempts): - while 1: - self.serverPort = random.randint(self.minPortNumber, - self.maxPortNumber) - if self.serverPort not in alreadyTriedPorts: - break - alreadyTriedPorts.append(self.serverPort) - - try: - self.makeServer() - except: - continue - else: - break - else: - # for loop iterated through exhaustion of the list and wasn't - # terminated by the break, so the server wasn't created, notify - # the caller by raising an exception - raise - - # generatePortAndMakeServer() ------------------------------------------- - - - # ----------------------------------------------------------------------- - def registerMethod(self, name): - """ """ - - methodName = name.__name__ - try: - self.server.register_function(name) - except Exception, why: - print "%s\nCould not register method (%s)" % (why, methodName) - raise - else: - if self.debug: - print "method '%s()' registered" % methodName - - # registerMethod() ------------------------------------------------------ - - - # ----------------------------------------------------------------------- - def runServer(self): - """ """ - # this will probably have to be in a thread if the interactive - # prompt is to remain at the user's disposal - - print "Waiting for requests..." - try: - self.server.serve_forever() - except KeyboardInterrupt: - try: - print "Stopped from keyboard, exit" - print "Closing InteractiveServer:", - self.server.server_close() - except: - print "can't close the server" - else: - print "server closed" - except Exception, why: - print "%s\nException occured" % why - raise - - # runServer() ----------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def execute(self, param = "<empty>"): - - print "execute(param = '%s')" % param - resultMsg = "SUCCESS" - - try: - exec param - except Exception, why: - trace = traceback.format_exception(*sys.exc_info()) - traceString = '\n '.join(trace) - resultMsg = "ERROR:\n%s\n%s\n" % (traceString, why) - print resultMsg - - return str(resultMsg) - - # execute() ------------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def get(self, name = "<empty>"): - """ """ - - print "get(name = '%s')" % name - resultMsg = "SUCCESS" - - try: - result = eval(name) - except Exception, why: - trace = traceback.format_exception(*sys.exc_info()) - traceString = '\n '.join(trace) - resultMsg = "ERROR:\n%s\n%s\n" % (traceString, why) - print resultMsg - return str(resultMsg) - else: - return str(result) - - # get() ----------------------------------------------------------------- - - - - # ----------------------------------------------------------------------- - def callVertexFit(self, tracksId): - """Track IDs (tracksId array) are passed to vertex fit algtool""" - - print "callVertexFit(tracksId = '%s')" % tracksId - - cppyy.loadDictionary('SealSTLDict') - - g.std.vector(int) - vi = g.std.vector(int)(0) - - for i in tracksId: - vi.push_back(i) - - print " calling vertexing tool: vxTool.fitAtlantisTracks(",vi,")" - - r = self.vxTool.fitAtlantisTracks(vi) - if r: - resultMsg = "SUCCESS (get updated event data)" - else: - resultMsg = "ERROR while calling vertexing tool" - - return resultMsg - - # callVertexFit() ------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def executeScript(self, param = "<empty>", pid = ""): - """Execute Python code snippets from Athenaeum plugin""" - - errorMsg = "SUCCESS" - resultMsg = "" - - try: - exec param - global answer - try: - resultMsg = answer[pid] - del answer[pid] - except: - resultMsg = "No resultMsg" - except Exception, why: - trace = traceback.format_exception(*sys.exc_info()) - traceString = '\n '.join(trace) - errorMsg = "ERROR:\n%s\n%s\n" % (traceString, why) - - return resultMsg + "\n" + str(errorMsg) - - # executeScript() ------------------------------------------------------- - - - # ----------------------------------------------------------------------- - # the only method which is exposed (registred) for remote calling - def process(self, digest = "", request = "<empty>", tracksId = ''): - """ """ - - print "\n\n<incoming request> " + 50 * '-' - if self.debug: - print "process(request = '%s', tracksId = '%s')" % (request, - tracksId) - result = "<empty_result>" - - # generate message digest and compare - md5My = md5.new() - md5My.update(request) - md5My.update(self.key) - myDigest = md5My.digest() - # received digest is BAE64 encoded, so encode mine as well - myDigest = base64.encodestring(myDigest)[:-1] # without list '\n' - - if digest == myDigest: - # determine the nature of the request - # request 'runVertexFit' -> pass tracksId to the algorithm - if str(request) == "runVertexFit": - result = self.callVertexFit(tracksId) - - # request to process Python code snippet (e.g. from Athenaeum) - # multiline request - # tracksId is the client identifier - elif len(str(request).split('\n')) > 1: - result = self.executeScript(request, tracksId) - - # get event data from JiveXML - elif str(request) == "eventData": - self.visTool.execute() - result = self.visTool.getXML() - - # two last characters must be '()' if it's a method to execute - elif request[-2:] == "()": - result = self.execute(request) - - # if the request contains '=' - it's an assignment to execute - elif request.find('=') > -1: - result = self.execute(request) - - # it's likely name of a variable to evaluate (or wrong request) - else: - result = self.get(request) - else: - result = "Request not processed, keys (digests) don't match" - - - # don't print out result messages longer than resultLengthLimit chars - # in such a case print just the beginning and the end of the message - limit = self.resultLengthLimit - print "result to send:" - if len(result) < limit: - print "%s" % result - else: - print "%s" % result[:limit/2] - print "\n+++ %s other characters +++\n" % (len(result) - limit) - print "%s" % result[-limit/2:] - - print "</incoming request> " + 50 * '-' - return result - - # process() ------------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def generateKey(self): - """ """ - - # generate keyLength characters long key - random.seed() - while len(self.key) < self.keyLength: - k = str(chr(random.randint(self.minCharValue, self.maxCharValue))) - if k in self.keyForbiddenChars: - continue - self.key += k - - # generateKey() --------------------------------------------------------- - - # ----------------------------------------------------------------------- - def printInfo(self): - """ """ - - print "String between the quotation marks to copy & paste", - print "into the dialog:" - print "\t '%s:%s:%s'" % (self.serverName, self.serverPort, self.key) - - # printInfo() ----------------------------------------------------------- - - - # ----------------------------------------------------------------------- - def createAlgTools(self): - - print "Getting vertexing AlgTool (ToolSvc.VxWrapperTool)" - # self.vxTool = \ - # theApp.toolsvc().retrieve('ToolSvc.VxWrapperTool')._itool - self.vxTool = \ - theApp.toolsvc().create('VxWrapperTool','VxWrapperTool', - cppyy.Pointer(g.IInterface)(0))._itool - - print "Getting JiveXML AlgTool (ToolSvc.EventData2XML)" - # self.visTool = \ - # theApp.toolsvc().retrieve('ToolSvc.EventData2XML')._itool - self.visTool = \ - theApp.toolsvc().create('EventData2XML','EventData2XML', - cppyy.Pointer(g.IInterface)(0))._itool - - # createAlgTools() ------------------------------------------------------ - - - # ----------------------------------------------------------------------- - def start(self): - """ """ - - print "Starting Multithreaded InteractiveServer:", - try: - # generate key if it wasn't specified as a command line option - if self.key == "": - self.generateKey() - - # choose random port before creating the server if the port number - # wasn't specified as a command line option - if self.serverPort == 0: - self.generatePortAndMakeServer() - else: - self.makeServer() - - self.registerMethod(self.process) - # self.server.register_introspection_functions() # what for? - - # don't initialise algtools if --no_algtools command line argument - if self.noAlgTools == False: - self.createAlgTools() - - self.printInfo() - self.runServer() - except Exception, why: - print "Exception occured." - print "Reason: %s" % why - - # start() --------------------------------------------------------------- - - -# class InteractiveServer =================================================== - - -# --------------------------------------------------------------------------- -def getArguments(): - """Reading arguments when executing by execfile()""" - - # default values - noAlgTools = False - serverPort = 0 - serverKey = "" - - if globals().has_key("argumentInteractiveServerNoAlgTools"): - if argumentInteractiveServerNoAlgTools: - noAlgTools = True - - if globals().has_key("argumentInteractiveServerServerPort"): - port = argumentInteractiveServerServerPort - try: - serverPort = int(port) - except ValueError: - msg = "Incorrectly specified port number: %s" % port - raise Exception(msg) - - if globals().has_key("argumentInteractiveServerServerKey"): - serverKey = argumentInteractiveServerServerKey - - return (noAlgTools, serverPort, serverKey) - -# getArguments() ------------------------------------------------------------ - - -# --------------------------------------------------------------------------- -def main(): - - try: - (noAlgTools, serverPort, key) = getArguments() - except Exception, why: - print "Exception occured while reading variable arguments, exit" - print "Reason: %s" % why - return - - server = InteractiveServer(noAlgTools, serverPort, key) - server.start() - -# main() -------------------------------------------------------------------- - - -# --------------------------------------------------------------------------- -if __name__ == "__main__": - main() -# --------------------------------------------------------------------------- diff --git a/graphics/AtlantisJava/share/MINERVA.jnlp b/graphics/AtlantisJava/share/MINERVA.jnlp deleted file mode 100644 index f3e3897fe74..00000000000 --- a/graphics/AtlantisJava/share/MINERVA.jnlp +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- JNLP webstart file for Atlantis event display for ATLAS --> -<!-- MINERVA version --> -<jnlp - spec="1.0+" - codebase="@CODEBASE@" - href="MINERVA.jnlp"> - <information> - <title>Atlantis event display for ATLAS</title> - <vendor>Atlantis team</vendor> - <homepage href=""/> <!-- should be used from codebase --> - <description>Atlantis event display for ATLAS</description> - <!-- <icon href="files/goofy_favicon.ico"/> - <icon kind="splash" href="files/logo.gif"/> --> - <offline-allowed/> - <shortcut online="false"> - <desktop/> - <menu submenu="Atlantis event display"/> - </shortcut> - </information> - <security> - <all-permissions/> - </security> - <resources> - <j2se version="1.6+" max-heap-size="512m"/> - - <jar href="lib/commons-cli-1.0.jar"/> - <jar href="lib/Jama.jar"/> - <jar href="lib/jas-aida-dev.jar"/> - <jar href="lib/jas-aida.jar"/> - <jar href="lib/jas-freehep-base.jar"/> - <jar href="lib/jas-freehep-hep.jar"/> - <jar href="lib/jas-jas-plotter.jar"/> - <jar href="lib/jas-jel.jar"/> - <jar href="lib/jas-JMinuit.jar"/> - <jar href="lib/jogl.jar"/> - <jar href="lib/jh.jar"/> - <jar href="lib/oncrpc.jar"/> - <jar href="lib/log4j-1.2.15.jar"/> - <jar href="lib/ostermillerutils_1_05_00.jar"/> - <jar href="lib/wired-base-4.0.beta.3-SNAPSHOT.jar"/> - <jar href="lib/ws-commons-util-1.0.2.jar"/> - <jar href="lib/xercesImpl.jar"/> - <jar href="lib/xml-apis.jar"/> - <jar href="lib/xmlrpc-client-3.1.jar"/> - <jar href="lib/xmlrpc-common-3.1.jar"/> - <jar href="lib/jlibeps.jar"/> - <jar href="lib/xmlrpc-server-3.1.jar"/> - <jar href="lib/commons-logging-1.1.jar"/> - <jar href="lib/commons-codec-1.4.jar"/> - <jar href="lib/xml-apis-ext.jar"/> - <jar href="lib/batik-dom.jar"/> - <jar href="lib/batik-anim.jar"/> - <jar href="lib/batik-svggen.jar"/> - <jar href="lib/batik-css.jar"/> - <jar href="lib/batik-bridge.jar"/> - <jar href="lib/batik-parser.jar"/> - <jar href="lib/batik-xml.jar"/> - <jar href="lib/batik-gui-util.jar"/> - <jar href="lib/batik-script.jar"/> - <jar href="lib/batik-transcoder.jar"/> - <jar href="lib/batik-svg-dom.jar"/> - <jar href="lib/batik-extension.jar"/> - <jar href="lib/batik-codec.jar"/> - <jar href="lib/batik-util.jar"/> - <jar href="lib/batik-swing.jar"/> - <jar href="lib/batik-ext.jar"/> - <jar href="lib/batik-gvt.jar"/> - <jar href="lib/batik-awt-util.jar"/> - <jar href="help/help.jar"/> - - <jar href="atlantis.jar" main="true"/> <!-- look for main class here --> - </resources> - - <application-desc main-class="atlantis.Atlantis"> - <argument>--config</argument> - <argument>configuration/config-MINERVA.xml</argument> - <argument>--debug</argument> - <argument>DEBUG</argument> - <argument>--source</argument> - <argument>http://www.cern.ch/atlas-minerva/MINERVA_tutorial_events.zip</argument> - </application-desc> - -</jnlp> diff --git a/graphics/AtlantisJava/share/atlantis b/graphics/AtlantisJava/share/atlantis deleted file mode 100755 index d9e99ce0a1c..00000000000 --- a/graphics/AtlantisJava/share/atlantis +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# running Atlantis in the Athena environment - -# Check JRE version. Workaround because "java -version:1.6+" does not work on lxplus -JAVAVERSION=`java -version 2>&1 | grep "java version" | awk '{print $3}' | tr -d \" | awk '{split($0, array, ".")} END{print array[2]}'` -if [[ $JAVAVERSION -lt 6 ]]; then - echo "Atlantis required Java version 1.6 or greater" - exit 1 -fi - -ATLANTISJAVA_HOME=`dirname $0`/../AtlantisJava -java -Xms128m -Xmx1024m -jar $ATLANTISJAVA_HOME/atlantis.jar $* diff --git a/graphics/AtlantisJava/share/atlantis.jnlp b/graphics/AtlantisJava/share/atlantis.jnlp deleted file mode 100644 index 39612b50c59..00000000000 --- a/graphics/AtlantisJava/share/atlantis.jnlp +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- JNLP webstart file for Atlantis event display for ATLAS --> -<jnlp - spec="1.0+" - codebase="@CODEBASE@" - href="atlantis.jnlp"> - <information> - <title>Atlantis event display for ATLAS</title> - <vendor>Atlantis team</vendor> - <homepage href=""/> <!-- should be used from codebase --> - <description>Atlantis event display for ATLAS</description> - <!-- <icon href="files/goofy_favicon.ico"/> - <icon kind="splash" href="files/logo.gif"/> --> - <offline-allowed/> - <shortcut online="false"> - <desktop/> - <menu submenu="Atlantis event display"/> - </shortcut> - </information> - <security> - <all-permissions/> - </security> - <resources> - <j2se version="1.6+" max-heap-size="512m"/> - - <jar href="lib/commons-cli-1.0.jar"/> - <jar href="lib/Jama.jar"/> - <jar href="lib/jas-aida-dev.jar"/> - <jar href="lib/jas-aida.jar"/> - <jar href="lib/jas-freehep-base.jar"/> - <jar href="lib/jas-freehep-hep.jar"/> - <jar href="lib/jas-jas-plotter.jar"/> - <jar href="lib/jas-jel.jar"/> - <jar href="lib/jas-JMinuit.jar"/> - <jar href="lib/jogl.jar"/> - <jar href="lib/jh.jar"/> - <jar href="lib/oncrpc.jar"/> - <jar href="lib/log4j-1.2.15.jar"/> - <jar href="lib/ostermillerutils_1_05_00.jar"/> - <jar href="lib/wired-base-4.0.beta.3-SNAPSHOT.jar"/> - <jar href="lib/ws-commons-util-1.0.2.jar"/> - <jar href="lib/xercesImpl.jar"/> - <jar href="lib/xml-apis.jar"/> - <jar href="lib/xmlrpc-client-3.1.jar"/> - <jar href="lib/xmlrpc-common-3.1.jar"/> - <jar href="lib/jlibeps.jar"/> - <jar href="lib/xmlrpc-server-3.1.jar"/> - <jar href="lib/commons-logging-1.1.jar"/> - <jar href="lib/commons-codec-1.4.jar"/> - <jar href="lib/xml-apis-ext.jar"/> - <jar href="lib/batik-dom.jar"/> - <jar href="lib/batik-anim.jar"/> - <jar href="lib/batik-svggen.jar"/> - <jar href="lib/batik-css.jar"/> - <jar href="lib/batik-bridge.jar"/> - <jar href="lib/batik-parser.jar"/> - <jar href="lib/batik-xml.jar"/> - <jar href="lib/batik-gui-util.jar"/> - <jar href="lib/batik-script.jar"/> - <jar href="lib/batik-transcoder.jar"/> - <jar href="lib/batik-svg-dom.jar"/> - <jar href="lib/batik-extension.jar"/> - <jar href="lib/batik-codec.jar"/> - <jar href="lib/batik-util.jar"/> - <jar href="lib/batik-swing.jar"/> - <jar href="lib/batik-ext.jar"/> - <jar href="lib/batik-gvt.jar"/> - <jar href="lib/batik-awt-util.jar"/> - - <jar href="help/help.jar"/> - - <jar href="atlantis.jar" main="true"/> <!-- look for main class here --> - </resources> - - <application-desc main-class="atlantis.Atlantis"> - <argument>--debug</argument> - <argument>DEBUG</argument> - </application-desc> - -</jnlp> - diff --git a/graphics/AtlantisJava/share/atlantis_online b/graphics/AtlantisJava/share/atlantis_online deleted file mode 100755 index 1d9cace7cfa..00000000000 --- a/graphics/AtlantisJava/share/atlantis_online +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# running Atlantis in the TDAQ online environment -# This requires the TDAQ_JAVA_HOME to be defined in the enviroment - -JAVA=$TDAQ_JAVA_HOME/bin/java - -# Check JRE version. Workaround because "java -version:1.6+" does not work on lxplus -JAVAVERSION=`$JAVA -version 2>&1 | grep "java version" | awk '{print $3}' | tr -d \" | awk '{split($0, array, ".")} END{print array[2]}'` -if [[ $JAVAVERSION -lt 6 ]]; then - echo "Atlantis required Java version 1.6 or greater" - exit 1 -fi - -exec $JAVA -Xms128m -Xmx1024m -jar $EVENTDISPLAY_SW_INST_PATH/share/AtlantisJava/atlantis.jar $* diff --git a/graphics/AtlantisJava/share/ntupleXML.h b/graphics/AtlantisJava/share/ntupleXML.h deleted file mode 100644 index c1282f14004..00000000000 --- a/graphics/AtlantisJava/share/ntupleXML.h +++ /dev/null @@ -1,1351 +0,0 @@ -//ntupleXML v1.0 - Tim Martin - Aug 07 - tamartin@cern.ch -//Classes TopViewXML and EventViewXML to output ntuple -//events to a Atlantis readable xml file - -#include "TXMLEngine.h" -#include <TChain.h> -#include <TFriendElement.h> -#include <TFile.h> - -#include <iostream> -#include <string> -#include <sstream> -#include <vector> -#include <iomanip> - -//Main class, TopView and EventView classes inherit from this -class ntupleXML { - protected: - std::string dataTypeCon, etaCon, labelCon, pdgIdCon, phiCon, ptCon, typeEVCon, mainTreeName; - Bool_t FR_Active, TR_Active, FRA_Active, TRA_Active, TA_Active, isTopView; - Int_t nParticles, Warn, truthPref, Append; - TChain* activeFile; - vector<TChain*> fileStore; - TTree* activeTree; - TFriendElement* friendTree; - TXMLEngine* TVXMLEng; - XMLNodePointer_t event; - Int_t FR_eventNumber; - Int_t FR_runNumber; - Double_t FR_MET_Final_ex; - Double_t FR_MET_Final_ey; - Double_t FR_MET_Final_et; - Double_t TR_MET_Truth_ex; - Double_t TR_MET_Truth_ey; - Double_t TR_MET_Truth_et; - Int_t FR_El_N; - vector<double>* FR_El_pdgId; - vector<double>* FR_El_p_T; - vector<double>* FR_El_phi; - vector<double>* FR_El_eta; - Int_t FR_Mu_N; - vector<double>* FR_Mu_pdgId; - vector<double>* FR_Mu_p_T; - vector<double>* FR_Mu_phi; - vector<double>* FR_Mu_eta; - Int_t FR_Tau_N; - vector<double>* FR_Tau_pdgId; - vector<double>* FR_Tau_p_T; - vector<double>* FR_Tau_phi; - vector<double>* FR_Tau_eta; - Int_t FR_Ph_N; - vector<double>* FR_Ph_pdgId; - vector<double>* FR_Ph_p_T; - vector<double>* FR_Ph_phi; - vector<double>* FR_Ph_eta; - Int_t FR_PJet_N; - vector<double>* FR_PJet_pdgId; - vector<double>* FR_PJet_p_T; - vector<double>* FR_PJet_phi; - vector<double>* FR_PJet_eta; - vector<int>* FR_PJet_BTagged; - Int_t FRA_El_N; - vector<double>* FRA_El_pdgId; - vector<double>* FRA_El_p_T; - vector<double>* FRA_El_phi; - vector<double>* FRA_El_eta; - Int_t FRA_Mu_N; - vector<double>* FRA_Mu_pdgId; - vector<double>* FRA_Mu_p_T; - vector<double>* FRA_Mu_phi; - vector<double>* FRA_Mu_eta; - Int_t FRA_Nu_N; - vector<double>* FRA_Nu_pdgId; - vector<double>* FRA_Nu_p_T; - vector<double>* FRA_Nu_phi; - vector<double>* FRA_Nu_eta; - Int_t FRA_HadW_N; - vector<double>* FRA_HadW_pdgId; - vector<double>* FRA_HadW_p_T; - vector<double>* FRA_HadW_phi; - vector<double>* FRA_HadW_eta; - Int_t FRA_LepW_N; - vector<double>* FRA_LepW_pdgId; - vector<double>* FRA_LepW_p_T; - vector<double>* FRA_LepW_phi; - vector<double>* FRA_LepW_eta; - Int_t FRA_HadTop_N; - vector<double>* FRA_HadTop_pdgId; - vector<double>* FRA_HadTop_p_T; - vector<double>* FRA_HadTop_phi; - vector<double>* FRA_HadTop_eta; - Int_t FRA_LepTop_N; - vector<double>* FRA_LepTop_pdgId; - vector<double>* FRA_LepTop_p_T; - vector<double>* FRA_LepTop_phi; - vector<double>* FRA_LepTop_eta; - Int_t FRA_Lepb_N; - vector<double>* FRA_Lepb_pdgId; - vector<double>* FRA_Lepb_p_T; - vector<double>* FRA_Lepb_phi; - vector<double>* FRA_Lepb_eta; - Int_t FRA_Hadb_N; - vector<double>* FRA_Hadb_pdgId; - vector<double>* FRA_Hadb_p_T; - vector<double>* FRA_Hadb_phi; - vector<double>* FRA_Hadb_eta; - Int_t FRA_Hadj_N; - vector<double>* FRA_Hadj_pdgId; - vector<double>* FRA_Hadj_p_T; - vector<double>* FRA_Hadj_phi; - vector<double>* FRA_Hadj_eta; - Int_t TRA_El_N; - vector<double>* TRA_El_pdgId; - vector<double>* TRA_El_p_T; - vector<double>* TRA_El_phi; - vector<double>* TRA_El_eta; - Int_t TRA_Mu_N; - vector<double>* TRA_Mu_pdgId; - vector<double>* TRA_Mu_p_T; - vector<double>* TRA_Mu_phi; - vector<double>* TRA_Mu_eta; - Int_t TRA_Tau_N; - vector<double>* TRA_Tau_pdgId; - vector<double>* TRA_Tau_p_T; - vector<double>* TRA_Tau_phi; - vector<double>* TRA_Tau_eta; - Int_t TRA_HadW_N; - vector<double>* TRA_HadW_pdgId; - vector<double>* TRA_HadW_p_T; - vector<double>* TRA_HadW_phi; - vector<double>* TRA_HadW_eta; - Int_t TRA_LepW_N; - vector<double>* TRA_LepW_pdgId; - vector<double>* TRA_LepW_p_T; - vector<double>* TRA_LepW_phi; - vector<double>* TRA_LepW_eta; - Int_t TRA_HadTop_N; - vector<double>* TRA_HadTop_pdgId; - vector<double>* TRA_HadTop_p_T; - vector<double>* TRA_HadTop_phi; - vector<double>* TRA_HadTop_eta; - Int_t TRA_LepTop_N; - vector<double>* TRA_LepTop_pdgId; - vector<double>* TRA_LepTop_p_T; - vector<double>* TRA_LepTop_phi; - vector<double>* TRA_LepTop_eta; - Int_t TRA_Bot_N; - vector<double>* TRA_Bot_pdgId; - vector<double>* TRA_Bot_p_T; - vector<double>* TRA_Bot_phi; - vector<double>* TRA_Bot_eta; - Int_t TRA_LQ_N; - vector<double>* TRA_LQ_pdgId; - vector<double>* TRA_LQ_p_T; - vector<double>* TRA_LQ_phi; - vector<double>* TRA_LQ_eta; - vector<double>* TA_Tru_p_T; - vector<double>* TA_Tru_phi; - vector<double>* TA_Tru_eta; - vector<double>* TA_Tru_pdgId; - vector<int>* TA_Tru_barcode; - TBranch* b_FR_eventNumber; - TBranch* b_FR_runNumber; - TBranch* b_FR_MET_Final_ex; - TBranch* b_FR_MET_Final_ey; - TBranch* b_FR_MET_Final_et; - TBranch* b_TR_MET_Truth_ex; - TBranch* b_TR_MET_Truth_ey; - TBranch* b_TR_MET_Truth_et; - TBranch* b_FR_El_N; - TBranch* b_FR_El_pdgId; - TBranch* b_FR_El_p_T; - TBranch* b_FR_El_phi; - TBranch* b_FR_El_eta; - TBranch* b_FR_Mu_N; - TBranch* b_FR_Mu_pdgId; - TBranch* b_FR_Mu_p_T; - TBranch* b_FR_Mu_phi; - TBranch* b_FR_Mu_eta; - TBranch* b_FR_Tau_N; - TBranch* b_FR_Tau_pdgId; - TBranch* b_FR_Tau_p_T; - TBranch* b_FR_Tau_phi; - TBranch* b_FR_Tau_eta; - TBranch* b_FR_Ph_N; - TBranch* b_FR_Ph_pdgId; - TBranch* b_FR_Ph_p_T; - TBranch* b_FR_Ph_phi; - TBranch* b_FR_Ph_eta; - TBranch* b_FR_PJet_N; - TBranch* b_FR_PJet_pdgId; - TBranch* b_FR_PJet_p_T; - TBranch* b_FR_PJet_phi; - TBranch* b_FR_PJet_eta; - TBranch* b_FR_PJet_BTagged; - TBranch* b_FRA_El_N; - TBranch* b_FRA_El_pdgId; - TBranch* b_FRA_El_p_T; - TBranch* b_FRA_El_phi; - TBranch* b_FRA_El_eta; - TBranch* b_FRA_Mu_N; - TBranch* b_FRA_Mu_pdgId; - TBranch* b_FRA_Mu_p_T; - TBranch* b_FRA_Mu_phi; - TBranch* b_FRA_Mu_eta; - TBranch* b_FRA_Nu_N; - TBranch* b_FRA_Nu_pdgId; - TBranch* b_FRA_Nu_p_T; - TBranch* b_FRA_Nu_phi; - TBranch* b_FRA_Nu_eta; - TBranch* b_FRA_HadW_N; - TBranch* b_FRA_HadW_pdgId; - TBranch* b_FRA_HadW_p_T; - TBranch* b_FRA_HadW_phi; - TBranch* b_FRA_HadW_eta; - TBranch* b_FRA_LepW_N; - TBranch* b_FRA_LepW_pdgId; - TBranch* b_FRA_LepW_p_T; - TBranch* b_FRA_LepW_phi; - TBranch* b_FRA_LepW_eta; - TBranch* b_FRA_HadTop_N; - TBranch* b_FRA_HadTop_pdgId; - TBranch* b_FRA_HadTop_p_T; - TBranch* b_FRA_HadTop_phi; - TBranch* b_FRA_HadTop_eta; - TBranch* b_FRA_LepTop_N; - TBranch* b_FRA_LepTop_pdgId; - TBranch* b_FRA_LepTop_p_T; - TBranch* b_FRA_LepTop_phi; - TBranch* b_FRA_LepTop_eta; - TBranch* b_FRA_Lepb_N; - TBranch* b_FRA_Lepb_pdgId; - TBranch* b_FRA_Lepb_p_T; - TBranch* b_FRA_Lepb_phi; - TBranch* b_FRA_Lepb_eta; - TBranch* b_FRA_Hadb_N; - TBranch* b_FRA_Hadb_pdgId; - TBranch* b_FRA_Hadb_p_T; - TBranch* b_FRA_Hadb_phi; - TBranch* b_FRA_Hadb_eta; - TBranch* b_FRA_Hadj_N; - TBranch* b_FRA_Hadj_pdgId; - TBranch* b_FRA_Hadj_p_T; - TBranch* b_FRA_Hadj_phi; - TBranch* b_FRA_Hadj_eta; - TBranch* b_TRA_El_N; - TBranch* b_TRA_El_pdgId; - TBranch* b_TRA_El_p_T; - TBranch* b_TRA_El_phi; - TBranch* b_TRA_El_eta; - TBranch* b_TRA_Mu_N; - TBranch* b_TRA_Mu_pdgId; - TBranch* b_TRA_Mu_p_T; - TBranch* b_TRA_Mu_phi; - TBranch* b_TRA_Mu_eta; - TBranch* b_TRA_Tau_N; - TBranch* b_TRA_Tau_pdgId; - TBranch* b_TRA_Tau_p_T; - TBranch* b_TRA_Tau_phi; - TBranch* b_TRA_Tau_eta; - TBranch* b_TRA_HadW_N; - TBranch* b_TRA_HadW_pdgId; - TBranch* b_TRA_HadW_p_T; - TBranch* b_TRA_HadW_phi; - TBranch* b_TRA_HadW_eta; - TBranch* b_TRA_LepW_N; - TBranch* b_TRA_LepW_pdgId; - TBranch* b_TRA_LepW_p_T; - TBranch* b_TRA_LepW_phi; - TBranch* b_TRA_LepW_eta; - TBranch* b_TRA_HadTop_N; - TBranch* b_TRA_HadTop_pdgId; - TBranch* b_TRA_HadTop_p_T; - TBranch* b_TRA_HadTop_phi; - TBranch* b_TRA_HadTop_eta; - TBranch* b_TRA_LepTop_N; - TBranch* b_TRA_LepTop_pdgId; - TBranch* b_TRA_LepTop_p_T; - TBranch* b_TRA_LepTop_phi; - TBranch* b_TRA_LepTop_eta; - TBranch* b_TRA_Bot_N; - TBranch* b_TRA_Bot_pdgId; - TBranch* b_TRA_Bot_p_T; - TBranch* b_TRA_Bot_phi; - TBranch* b_TRA_Bot_eta; - TBranch* b_TRA_LQ_N; - TBranch* b_TRA_LQ_pdgId; - TBranch* b_TRA_LQ_p_T; - TBranch* b_TRA_LQ_phi; - TBranch* b_TRA_LQ_eta; - TBranch* b_TA_Tru_p_T; - TBranch* b_TA_Tru_phi; - TBranch* b_TA_Tru_eta; - TBranch* b_TA_Tru_pdgId; - TBranch* b_TA_Tru_barcode; - //Protected memeber functions - template<typename TYPE> - std::string asString(const TYPE&); - void SetBranches(void); - void FillBranches(Int_t entryNumber); - void SetActiveFile(Int_t fileNumber); - void GetFullReco(void); - void GetFullRecoAna(void); - void GetTruthAll(Bool_t onlyMuons); - void GetTruthAna(Bool_t onlyMuons); - void GetMET(Bool_t getTruth); - void StartXML(void); - void FillXML_ParticleDump(Char_t* nodeName, Char_t* storeGateKey); - void FillXML_TruthDump(Char_t* nodeName, Char_t* storeGateKey); - void FillXML_MET(Char_t* storeGateKey); - void EndXML(Char_t* outputFilename); - public: - Bool_t ntuple2XML(Char_t* outputFilename, UInt_t entryNumber, UInt_t fileNumber); - void Add(Char_t* fileLocation); - void Clear(void); - Int_t GetNfiles(void) { return fileStore.size(); } - Int_t GetNentries(UInt_t fileNumber); - Bool_t SetWarnLevel(UInt_t warnLevel); - Bool_t SetTruthPreference(UInt_t truthPreference); - Bool_t SetFilenameAppend(UInt_t filenameAppend); - -}; - -struct TopViewXML: public ntupleXML { - TopViewXML(Char_t* fileLocation); - TopViewXML(void); - ~TopViewXML(void) {} -}; - -struct EventViewXML: public ntupleXML { - EventViewXML(Char_t* fileLocation); - EventViewXML(void); - ~EventViewXML(void) {} -}; - -//Constructors// - -TopViewXML::TopViewXML(Char_t* fileLocation) { - isTopView=1; - Append=1; Warn=1; truthPref=2; - mainTreeName = "FullReco0"; - ntupleXML::Add(fileLocation); -} - -TopViewXML::TopViewXML(void) { - isTopView=1; - Append=1; Warn=1; truthPref=2; - mainTreeName = "FullReco0"; -} - -EventViewXML::EventViewXML(Char_t* fileLocation) { - isTopView=0; - Append=1; Warn=1; truthPref=2; - mainTreeName = "CollectionTree"; - ntupleXML::Add(fileLocation); -} - -EventViewXML::EventViewXML(void) { - isTopView=0; - Append=1; Warn=1; truthPref=2; - mainTreeName = "CollectionTree"; -} - -//Inherited public methods// - -//ntuple2XML takes an entry from a file loaded in the internal File Chain and writes an -//atlantis xml file for the event. -Bool_t ntupleXML::ntuple2XML(Char_t* outputFilename, UInt_t entryNumber, UInt_t fileNumber) { - - if (fileNumber >= fileStore.size()) { - if (Warn>0) { std::cout << "\nntupleXML: Error cannot access file #" << fileNumber - << ", " << fileStore.size() << " file(s) currently loaded. "; - } - return 0; - } - - //Set the required file as activeFile, main tree as activeTree & associate branches - ntupleXML::SetActiveFile(fileNumber); - - if (entryNumber >= activeTree->GetEntries()) { - if (Warn>0) { std::cout << "\nntupleXML: Error cannot access entry #" << entryNumber - << ", file #" << fileNumber << " contains " << activeTree->GetEntries() << " entries. "; - } - return 0; - } - - //Cannot proceed without FullReco/CollectionTree branches set - if (!FR_Active) { - if (Warn>0) { std::cout << "\nntupleXML: Error unable to access " << mainTreeName << " Tree. "; } - return 0; - } - - //Retrieve event - ntupleXML::FillBranches(entryNumber); - nParticles=0; - - //Prepare XML document - ntupleXML::StartXML(); - - ntupleXML::GetFullReco(); - if (nParticles) { ntupleXML::FillXML_ParticleDump("CompositeParticle","RecoView"); } - - ntupleXML::GetMET(0); - ntupleXML::FillXML_MET("MET_Final"); - if (TR_Active) { - ntupleXML::GetMET(1); - ntupleXML::FillXML_MET("MET_Truth"); - } else if (Warn>1) { std::cout << "\nntupleXML: Warning unable to output MET_Truth. "; } - - if (FRA_Active) { - ntupleXML::GetFullRecoAna(); - if (nParticles) { ntupleXML::FillXML_ParticleDump("CompositeParticle","RecoAnaView"); } - } else if (Warn>1 && isTopView) { std::cout << "\nntupleXML: Warning unable to output FullRecoAna Tree. "; } - - if (TA_Active && truthPref == 1) { - ntupleXML::GetTruthAll(0); - if (nParticles) { ntupleXML::FillXML_TruthDump("STr",""); } - ntupleXML::GetTruthAll(1); //Get only muons - if (nParticles) { ntupleXML::FillXML_TruthDump("SMTr",""); } - } else if (TRA_Active && truthPref) { - ntupleXML::GetTruthAna(0); - if (nParticles) { ntupleXML::FillXML_TruthDump("STr",""); } - ntupleXML::GetTruthAna(1); - if (nParticles) { ntupleXML::FillXML_TruthDump("SMTr",""); } - } else if (Warn>1 && truthPref && isTopView) { - std::cout << "\nntupleXML: Warning unable to output TruthAna or TruthAll Tree. "; - } - - //Construct filename - std::string filenameStr(outputFilename), ext; - ext = filenameStr.substr(filenameStr.length() - 4, 4); - if (Append) { - if (ext == ".xml" || ext == ".Xml" || ext == ".XML") { - filenameStr = filenameStr.substr(0, filenameStr.length() - 4) ; - if (Append==1) { filenameStr += "_" + asString(FR_eventNumber) + ext; } - else { filenameStr += "_" + asString(entryNumber) + ext; } - } else { - if (Append==1) { filenameStr += "_" + asString(FR_eventNumber) + ".xml"; } - else { filenameStr += "_" + asString(entryNumber) + ".xml"; } - } - } else { - if (!(ext == ".xml" || ext == ".Xml" || ext == ".XML")) { - filenameStr += ".xml"; - } - } - - //Write .xml file - ntupleXML::EndXML((Char_t*) filenameStr.c_str()); - if (Warn>1) { std::cout << "\nntupleXML: Output to " << filenameStr; } - - //Return success - return 1; -} - -Bool_t ntupleXML::SetWarnLevel(UInt_t warnLevel) { - if (warnLevel <= 2) { - Warn=warnLevel; - return 1; - } else { return 0; } -} - -Bool_t ntupleXML::SetTruthPreference(UInt_t truthPreference) { - if (truthPreference <= 2) { - truthPref=truthPreference; - return 1; - } else { return 0; } -} - -Bool_t ntupleXML::SetFilenameAppend(UInt_t filenameAppend) { - if (filenameAppend <= 2) { - Append=filenameAppend; - return 1; - } else { return 0; } -} - -Int_t ntupleXML::GetNentries(UInt_t fileNumber) { - if (fileNumber >= fileStore.size()) { - if (Warn>0) { std::cout << "\nntupleXML: Error cannot access file #" << fileNumber - << ", " << fileStore.size() << " file(s) currently loaded. "; - } - return 0; - } else { - ntupleXML::SetActiveFile(fileNumber); - return activeTree->GetEntries(); - } -} - -void ntupleXML::Add(Char_t* fileLocation) { - TChain* tf; - if (isTopView) { - tf = new TChain("FullReco0"); - tf->Add(fileLocation); - tf->AddFriend("FullRecoAna0"); - tf->AddFriend("TruthAna0"); - tf->AddFriend("TruthAll0"); - tf->AddFriend("Truth0"); - if ( tf->LoadTree(0) < 0 ) { - if (Warn>0) { std::cout << "\nntupleXML: Error, file was not added. "; } - return; - } - } else { - tf = new TChain("CollectionTree"); - tf->Add(fileLocation); - if ( tf->LoadTree(0) < 0 ) { - if (Warn>0) { std::cout << "\nntupleXML: Error, file was not added. "; } - return; - } - - } - fileStore.push_back(tf); -} - -void ntupleXML::Clear(void) { - for (UInt_t i=0; i<fileStore.size(); i++) { - delete fileStore[i]; - } - fileStore.clear(); - activeFile = NULL; -} - -//XML File Construction Members// - -void ntupleXML::StartXML(void) { - //Create XML engine - TVXMLEng = new TXMLEngine(); - event = TVXMLEng->NewChild(0, 0, "Event"); - TVXMLEng->NewAttr(event, 0, "version", "ntuple"); - TVXMLEng->NewIntAttr(event, "runNumber", FR_runNumber); - TVXMLEng->NewIntAttr(event, "eventNumber", FR_eventNumber); - TDatime* makeTime = new TDatime(); - Char_t makeTimeStr[26]; - makeTime->AsString(makeTimeStr); //This 'AsString' is member of TDatime - delete makeTime; - TVXMLEng->NewAttr(event, 0, "dateTime", makeTimeStr); -} - -void ntupleXML::FillXML_ParticleDump(Char_t* nodeName, Char_t* storeGateKey) { - //Create Composite particle subnode - XMLNodePointer_t compPart = TVXMLEng->NewChild(event, 0, nodeName); - TVXMLEng->NewIntAttr(compPart, "count", nParticles); - TVXMLEng->NewAttr(compPart, 0, "storeGateKey", storeGateKey); - TVXMLEng->NewChild(compPart, 0, "dataType", dataTypeCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "eta", etaCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "label", labelCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "pdgId", pdgIdCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "phi", phiCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "pt", ptCon.c_str()); - TVXMLEng->NewChild(compPart, 0, "typeEV", typeEVCon.c_str()); - dataTypeCon=""; etaCon=""; phiCon=""; labelCon=""; pdgIdCon=""; ptCon=""; typeEVCon=""; - nParticles=0; -} - -void ntupleXML::FillXML_TruthDump(Char_t* nodeName, Char_t* storeGateKey) { - //Create truth subnode - XMLNodePointer_t truBlock = TVXMLEng->NewChild(event, 0, nodeName); - TVXMLEng->NewIntAttr(truBlock, "count", nParticles); - TVXMLEng->NewAttr(truBlock, 0, "storeGateKey", storeGateKey); - TVXMLEng->NewChild(truBlock, 0, "code", pdgIdCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "eta", etaCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "id", labelCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "phi", phiCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "phiVertex", dataTypeCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "pt", ptCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "rhoVertex", dataTypeCon.c_str()); - TVXMLEng->NewChild(truBlock, 0, "zVertex", dataTypeCon.c_str()); - dataTypeCon=""; etaCon=""; phiCon=""; labelCon=""; pdgIdCon=""; ptCon=""; - nParticles=0; -} - -void ntupleXML::FillXML_MET(Char_t* storeGateKey) { - //Create MET subnode - XMLNodePointer_t MET = TVXMLEng->NewChild(event, 0, "ETMis"); - TVXMLEng->NewIntAttr(MET, "count", 1); - TVXMLEng->NewAttr(MET, 0, "storeGateKey", storeGateKey); - TVXMLEng->NewChild(MET, 0, "et", etaCon.c_str()); - TVXMLEng->NewChild(MET, 0, "etx", phiCon.c_str()); - TVXMLEng->NewChild(MET, 0, "ety", ptCon.c_str()); - etaCon=""; phiCon=""; ptCon=""; -} - -void ntupleXML::EndXML(Char_t* outputFilename) { - //Create document - XMLDocPointer_t xmldoc = TVXMLEng->NewDoc(); - TVXMLEng->DocSetRootElement(xmldoc, event); - TVXMLEng->AddDocRawLine(xmldoc, "<?ATLAS Release: \"RELEASE#\"?>"); - TVXMLEng->AddDocRawLine(xmldoc, "<!DOCTYPE Event SYSTEM \"event.dtd\">"); - // Save document to file - TVXMLEng->SaveDoc(xmldoc, outputFilename); - // Release memory before exit - TVXMLEng->FreeDoc(xmldoc); - delete TVXMLEng; -} - -//String Filling Members// - -void ntupleXML::GetFullReco(void) { - std::string id; - if (isTopView) { id = "FR_"; } - else { id = "EV_"; } - for (Int_t i=0; i<FR_El_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVElectron "; - labelCon += id + "Electron "; - etaCon += asString(FR_El_eta->at(i)) + " "; - phiCon += asString(FR_El_phi->at(i)) + " "; - ptCon += asString(FR_El_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FR_El_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FR_Mu_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVMuon "; - labelCon += id + "Muon "; - etaCon += asString(FR_Mu_eta->at(i)) + " "; - phiCon += asString(FR_Mu_phi->at(i)) + " "; - ptCon += asString(FR_Mu_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FR_Mu_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FR_Tau_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVTauJet "; - labelCon += id + "Tau "; - etaCon += asString(FR_Tau_eta->at(i)) + " "; - phiCon += asString(FR_Tau_phi->at(i)) + " "; - ptCon += asString(FR_Tau_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FR_Tau_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FR_Ph_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVPhoton "; - labelCon += id + "Photon "; - etaCon += asString(FR_Ph_eta->at(i)) + " "; - phiCon += asString(FR_Ph_phi->at(i)) + " "; - ptCon += asString(FR_Ph_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FR_Ph_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FR_PJet_N; i++) { - if (isTopView) { - if (FR_PJet_BTagged->at(i)) { - typeEVCon += "EVBJet "; - labelCon += id + "BTaggedJet "; - pdgIdCon += "5 "; - } else { - typeEVCon += "EVParticleJet "; - labelCon += id + "ParticleJet "; - pdgIdCon += "0 "; - } - } else { - typeEVCon += "EVParticleJet "; - labelCon += id + "ParticleJet "; - pdgIdCon += "5 "; - } - nParticles++; - dataTypeCon += "1 "; - etaCon += asString(FR_PJet_eta->at(i)) + " "; - phiCon += asString(FR_PJet_phi->at(i)) + " "; - ptCon += asString(FR_PJet_p_T->at(i)/1000.) + " "; - } -} - -void ntupleXML::GetMET(Bool_t getTruth) { - if (!getTruth) { - etaCon += asString(FR_MET_Final_et/1000.) + " "; - phiCon += asString(FR_MET_Final_ex/1000.) + " "; - ptCon += asString(FR_MET_Final_ey/1000.) + " "; - } else { - etaCon += asString(TR_MET_Truth_et/1000.) + " "; - phiCon += asString(TR_MET_Truth_ex/1000.) + " "; - ptCon += asString(TR_MET_Truth_ey/1000.) + " "; - } -} - -void ntupleXML::GetFullRecoAna(void) { - for (Int_t i=0; i<FRA_El_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVElectron "; - labelCon += "FRA_Electron "; - etaCon += asString(FRA_El_eta->at(i)) + " "; - phiCon += asString(FRA_El_phi->at(i)) + " "; - ptCon += asString(FRA_El_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_El_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_Mu_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVMuon "; - labelCon += "FRA_Muon "; - etaCon += asString(FRA_Mu_eta->at(i)) + " "; - phiCon += asString(FRA_Mu_phi->at(i)) + " "; - ptCon += asString(FRA_Mu_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_Mu_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_Nu_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVNeutrino "; - labelCon += "FRA_Neutrino "; - etaCon += asString(FRA_Nu_eta->at(i)) + " "; - phiCon += asString(FRA_Nu_phi->at(i)) + " "; - ptCon += asString(FRA_Nu_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_Nu_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_HadW_N; i++) { - nParticles++; - dataTypeCon += "0 "; - typeEVCon += "EVCompositeParticle "; - labelCon += "FRA_HadronicW "; - etaCon += asString(FRA_HadW_eta->at(i)) + " "; - phiCon += asString(FRA_HadW_phi->at(i)) + " "; - ptCon += asString(FRA_HadW_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_HadW_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_LepW_N; i++) { - nParticles++; - dataTypeCon += "0 "; - typeEVCon += "EVCompositeParticle "; - labelCon += "FRA_LeptonicW "; - etaCon += asString(FRA_LepW_eta->at(i)) + " "; - phiCon += asString(FRA_LepW_phi->at(i)) + " "; - ptCon += asString(FRA_LepW_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_LepW_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_HadTop_N; i++) { - nParticles++; - dataTypeCon += "0 "; - typeEVCon += "EVCompositeParticle "; - labelCon += "FRA_HadronicTop "; - etaCon += asString(FRA_HadTop_eta->at(i)) + " "; - phiCon += asString(FRA_HadTop_phi->at(i)) + " "; - ptCon += asString(FRA_HadTop_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_HadTop_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_LepTop_N; i++) { - nParticles++; - dataTypeCon += "0 "; - typeEVCon += "EVCompositeParticle "; - labelCon += "FRA_LeptonicTop "; - etaCon += asString(FRA_LepTop_eta->at(i)) + " "; - phiCon += asString(FRA_LepTop_phi->at(i)) + " "; - ptCon += asString(FRA_LepTop_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)FRA_LepTop_pdgId->at(i)) + " "; - } - for (Int_t i=0; i<FRA_Lepb_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVBJet "; - labelCon += "FRA_LeptonicBJet "; - etaCon += asString(FRA_Lepb_eta->at(i)) + " "; - phiCon += asString(FRA_Lepb_phi->at(i)) + " "; - ptCon += asString(FRA_Lepb_p_T->at(i)/1000.) + " "; - pdgIdCon += "5 "; - } - for (Int_t i=0; i<FRA_Hadb_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVBJet "; - labelCon += "FRA_HadronicBJet "; - etaCon += asString(FRA_Hadb_eta->at(i)) + " "; - phiCon += asString(FRA_Hadb_phi->at(i)) + " "; - ptCon += asString(FRA_Hadb_p_T->at(i)/1000.) + " "; - pdgIdCon += "5 "; - } - for (Int_t i=0; i<FRA_Hadj_N; i++) { - nParticles++; - dataTypeCon += "1 "; - typeEVCon += "EVParticleJet "; - labelCon += "FRA_HadronicParticleJet "; - etaCon += asString(FRA_Hadj_eta->at(i)) + " "; - phiCon += asString(FRA_Hadj_phi->at(i)) + " "; - ptCon += asString(FRA_Hadj_p_T->at(i)/1000.) + " "; - pdgIdCon += "0 "; - } -} - -//onlyMouns is set true when filling SMTr -void ntupleXML::GetTruthAna(Bool_t onlyMuons) { - Int_t sign; - for (Int_t i=0; i<TRA_Mu_N; i++) { - nParticles++; - etaCon += asString(TRA_Mu_eta->at(i)) + " "; - phiCon += asString(TRA_Mu_phi->at(i)) + " "; - ptCon += asString(TRA_Mu_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)TRA_Mu_pdgId->at(i)) + " "; - labelCon += "0 "; //Barcode - dataTypeCon += "0.000001 "; //Used to fill vertexes - } - - if (onlyMuons) { return; } - - for (Int_t i=0; i<TRA_El_N; i++) { - nParticles++; - etaCon += asString(TRA_El_eta->at(i)) + " "; - phiCon += asString(TRA_El_phi->at(i)) + " "; - ptCon += asString(TRA_El_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)TRA_El_pdgId->at(i)) + " "; - labelCon += "0 "; - dataTypeCon += " 0.000001 "; - } - for (Int_t i=0; i<TRA_Tau_N; i++) { - nParticles++; - etaCon += asString(TRA_Tau_eta->at(i)) + " "; - phiCon += asString(TRA_Tau_phi->at(i)) + " "; - ptCon += asString(TRA_Tau_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)TRA_Tau_pdgId->at(i)) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_HadW_N; i++) { - nParticles++; - etaCon += asString(TRA_HadW_eta->at(i)) + " "; - phiCon += asString(TRA_HadW_phi->at(i)) + " "; - ptCon += asString(TRA_HadW_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)TRA_HadW_pdgId->at(i)) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_LepW_N; i++) { - nParticles++; - etaCon += asString(TRA_LepW_eta->at(i)) + " "; - phiCon += asString(TRA_LepW_phi->at(i)) + " "; - ptCon += asString(TRA_LepW_p_T->at(i)/1000.) + " "; - pdgIdCon += asString((Int_t)TRA_LepW_pdgId->at(i)) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_HadTop_N; i++) { - nParticles++; - etaCon += asString(TRA_HadTop_eta->at(i)) + " "; - phiCon += asString(TRA_HadTop_phi->at(i)) + " "; - ptCon += asString(TRA_HadTop_p_T->at(i)/1000.) + " "; - sign = (Int_t) (fabs(TRA_HadTop_pdgId->at(i))/TRA_HadTop_pdgId->at(i)); - pdgIdCon += asString((Int_t)(TRA_HadTop_pdgId->at(i)+(600*sign))) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_LepTop_N; i++) { - nParticles++; - etaCon += asString(TRA_LepTop_eta->at(i)) + " "; - phiCon += asString(TRA_LepTop_phi->at(i)) + " "; - ptCon += asString(TRA_LepTop_p_T->at(i)/1000.) + " "; - sign = (Int_t) (fabs(TRA_LepTop_pdgId->at(i))/TRA_LepTop_pdgId->at(i)); - pdgIdCon += asString((Int_t)(TRA_LepTop_pdgId->at(i)+(600*sign))) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_Bot_N; i++) { - nParticles++; - etaCon += asString(TRA_Bot_eta->at(i)) + " "; - phiCon += asString(TRA_Bot_phi->at(i)) + " "; - ptCon += asString(TRA_Bot_p_T->at(i)/1000.) + " "; - sign = (Int_t) (fabs(TRA_Bot_pdgId->at(i))/TRA_Bot_pdgId->at(i)); - pdgIdCon += asString((Int_t)(TRA_Bot_pdgId->at(i)+(600*sign))) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } - for (Int_t i=0; i<TRA_LQ_N; i++) { //LQ - Light Quarks - nParticles++; - etaCon += asString(TRA_LQ_eta->at(i)) + " "; - phiCon += asString(TRA_LQ_phi->at(i)) + " "; - ptCon += asString(TRA_LQ_p_T->at(i)/1000.) + " "; - sign = (Int_t) (fabs(TRA_LQ_pdgId->at(i))/TRA_LQ_pdgId->at(i)); - pdgIdCon += asString((Int_t)(TRA_LQ_pdgId->at(i)+(600*sign))) + " "; - labelCon += "0 "; - dataTypeCon += "0.000001 "; - } -} - -void ntupleXML::GetTruthAll(Bool_t onlyMuons) { - //Loop over entire truth block (if present) - Int_t id, sign; - for (UInt_t i=0; i<TA_Tru_p_T->size(); i++) { - if (!onlyMuons || (onlyMuons && fabs(TA_Tru_pdgId->at(i)) == 13)) { - nParticles++; - etaCon += asString(TA_Tru_eta->at(i)) + " "; - phiCon += asString(TA_Tru_phi->at(i)) + " "; - ptCon += asString(TA_Tru_p_T->at(i)/1000.) + " "; - id = (Int_t) TA_Tru_pdgId->at(i); - sign = (Int_t) (fabs(TA_Tru_pdgId->at(i))/TA_Tru_pdgId->at(i)); - //Atlantis' True Particle Simulation ignores quarks, however with TopView - //we are interested in t and b quarks, 6 special pdgIds have therefore - //been set up in Atlantis (601-606) so as to display quarks from ntuples - if (abs(id) <= 6) { id += (600 * sign); } - pdgIdCon += asString(id) + " "; - labelCon += asString(TA_Tru_barcode->at(i)) + " "; - dataTypeCon += "0.000001 "; //If zero, Atlantis crashes on eta-phi plot due to rhoVertex - } - } -} - -//Branch Association// - -void ntupleXML::SetBranches(void) { - FR_El_pdgId = 0; - FR_El_p_T = 0; - FR_El_phi = 0; - FR_El_eta = 0; - FR_Mu_pdgId = 0; - FR_Mu_p_T = 0; - FR_Mu_phi = 0; - FR_Mu_eta = 0; - FR_Tau_pdgId = 0; - FR_Tau_p_T = 0; - FR_Tau_phi = 0; - FR_Tau_eta = 0; - FR_Ph_pdgId = 0; - FR_Ph_p_T = 0; - FR_Ph_phi = 0; - FR_Ph_eta = 0; - FR_PJet_pdgId = 0; - FR_PJet_p_T = 0; - FR_PJet_phi = 0; - FR_PJet_eta = 0; - FR_PJet_BTagged = 0; - FRA_El_pdgId = 0; - FRA_El_p_T = 0; - FRA_El_phi = 0; - FRA_El_eta = 0; - FRA_Mu_pdgId = 0; - FRA_Mu_p_T = 0; - FRA_Mu_phi = 0; - FRA_Mu_eta = 0; - FRA_Nu_pdgId = 0; - FRA_Nu_p_T = 0; - FRA_Nu_phi = 0; - FRA_Nu_eta = 0; - FRA_HadW_pdgId = 0; - FRA_HadW_p_T = 0; - FRA_HadW_phi = 0; - FRA_HadW_eta = 0; - FRA_LepW_pdgId = 0; - FRA_LepW_p_T = 0; - FRA_LepW_phi = 0; - FRA_LepW_eta = 0; - FRA_HadTop_pdgId = 0; - FRA_HadTop_p_T = 0; - FRA_HadTop_phi = 0; - FRA_HadTop_eta = 0; - FRA_LepTop_pdgId = 0; - FRA_LepTop_p_T = 0; - FRA_LepTop_phi = 0; - FRA_LepTop_eta = 0; - FRA_Lepb_pdgId = 0; - FRA_Lepb_p_T = 0; - FRA_Lepb_phi = 0; - FRA_Lepb_eta = 0; - FRA_Hadb_pdgId = 0; - FRA_Hadb_p_T = 0; - FRA_Hadb_phi = 0; - FRA_Hadb_eta = 0; - FRA_Hadj_pdgId = 0; - FRA_Hadj_p_T = 0; - FRA_Hadj_phi = 0; - FRA_Hadj_eta = 0; - TRA_El_pdgId = 0; - TRA_El_p_T = 0; - TRA_El_phi = 0; - TRA_El_eta = 0; - TRA_Mu_pdgId = 0; - TRA_Mu_p_T = 0; - TRA_Mu_phi = 0; - TRA_Mu_eta = 0; - TRA_Tau_pdgId = 0; - TRA_Tau_p_T = 0; - TRA_Tau_phi = 0; - TRA_Tau_eta = 0; - TRA_HadW_pdgId = 0; - TRA_HadW_p_T = 0; - TRA_HadW_phi = 0; - TRA_HadW_eta = 0; - TRA_LepW_pdgId = 0; - TRA_LepW_p_T = 0; - TRA_LepW_phi = 0; - TRA_LepW_eta = 0; - TRA_HadTop_pdgId = 0; - TRA_HadTop_p_T = 0; - TRA_HadTop_phi = 0; - TRA_HadTop_eta = 0; - TRA_LepTop_pdgId = 0; - TRA_LepTop_p_T = 0; - TRA_LepTop_phi = 0; - TRA_LepTop_eta = 0; - TRA_Bot_pdgId = 0; - TRA_Bot_p_T = 0; - TRA_Bot_phi = 0; - TRA_Bot_eta = 0; - TRA_LQ_pdgId = 0; - TRA_LQ_p_T = 0; - TRA_LQ_phi = 0; - TRA_LQ_eta = 0; - TA_Tru_p_T = 0; - TA_Tru_phi = 0; - TA_Tru_eta = 0; - TA_Tru_pdgId = 0; - TA_Tru_barcode = 0; - FR_Active=0; - TR_Active=0; - FRA_Active=0; - TRA_Active=0; - TA_Active=0; - - activeTree = activeFile->GetTree(); - - if (activeTree) { - FR_Active = 1; - activeTree->SetBranchAddress("eventNumber", &FR_eventNumber, &b_FR_eventNumber); - activeTree->SetBranchAddress("runNumber", &FR_runNumber, &b_FR_runNumber); - activeTree->SetBranchAddress("MET_Final_ex", &FR_MET_Final_ex, &b_FR_MET_Final_ex); - activeTree->SetBranchAddress("MET_Final_ey", &FR_MET_Final_ey, &b_FR_MET_Final_ey); - activeTree->SetBranchAddress("MET_Final_et", &FR_MET_Final_et, &b_FR_MET_Final_et); - if (!isTopView) { - //With EventView ntuples, MET Truth is in the CollectionTree - activeTree->SetBranchAddress("MET_Truth_ex", &TR_MET_Truth_ex, &b_TR_MET_Truth_ex); - activeTree->SetBranchAddress("MET_Truth_ey", &TR_MET_Truth_ey, &b_TR_MET_Truth_ey); - activeTree->SetBranchAddress("MET_Truth_et", &TR_MET_Truth_et, &b_TR_MET_Truth_et); - TR_Active=1; - } - activeTree->SetBranchAddress("El_N", &FR_El_N, &b_FR_El_N); - activeTree->SetBranchAddress("El_p_T", &FR_El_p_T, &b_FR_El_p_T); - activeTree->SetBranchAddress("El_pdgId", &FR_El_pdgId, &b_FR_El_pdgId); - activeTree->SetBranchAddress("El_phi", &FR_El_phi, &b_FR_El_phi); - activeTree->SetBranchAddress("El_eta", &FR_El_eta, &b_FR_El_eta); - activeTree->SetBranchAddress("Mu_N", &FR_Mu_N, &b_FR_Mu_N); - activeTree->SetBranchAddress("Mu_p_T", &FR_Mu_p_T, &b_FR_Mu_p_T); - activeTree->SetBranchAddress("Mu_pdgId", &FR_Mu_pdgId, &b_FR_Mu_pdgId); - activeTree->SetBranchAddress("Mu_phi", &FR_Mu_phi, &b_FR_Mu_phi); - activeTree->SetBranchAddress("Mu_eta", &FR_Mu_eta, &b_FR_Mu_eta); - activeTree->SetBranchAddress("Tau_N", &FR_Tau_N, &b_FR_Tau_N); - activeTree->SetBranchAddress("Tau_p_T", &FR_Tau_p_T, &b_FR_Tau_p_T); - activeTree->SetBranchAddress("Tau_pdgId", &FR_Tau_pdgId, &b_FR_Tau_pdgId); - activeTree->SetBranchAddress("Tau_phi", &FR_Tau_phi, &b_FR_Tau_phi); - activeTree->SetBranchAddress("Tau_eta", &FR_Tau_eta, &b_FR_Tau_eta); - activeTree->SetBranchAddress("Ph_N", &FR_Ph_N, &b_FR_Ph_N); - activeTree->SetBranchAddress("Ph_p_T", &FR_Ph_p_T, &b_FR_Ph_p_T); - activeTree->SetBranchAddress("Ph_pdgId", &FR_Ph_pdgId, &b_FR_Ph_pdgId); - activeTree->SetBranchAddress("Ph_phi", &FR_Ph_phi, &b_FR_Ph_phi); - activeTree->SetBranchAddress("Ph_eta", &FR_Ph_eta, &b_FR_Ph_eta); - activeTree->SetBranchAddress("PJet_N", &FR_PJet_N, &b_FR_PJet_N); - activeTree->SetBranchAddress("PJet_p_T", &FR_PJet_p_T, &b_FR_PJet_p_T); - activeTree->SetBranchAddress("PJet_pdgId", &FR_PJet_pdgId, &b_FR_PJet_pdgId); - activeTree->SetBranchAddress("PJet_phi", &FR_PJet_phi, &b_FR_PJet_phi); - activeTree->SetBranchAddress("PJet_eta", &FR_PJet_eta, &b_FR_PJet_eta); - if (isTopView) { activeTree->SetBranchAddress("PJet_BTagged", &FR_PJet_BTagged, &b_FR_PJet_BTagged); } - } else if (Warn>1) { std::cout << "\nntupleXML: Warning cannot find " << mainTreeName << " tree. "; } - - //Stop here with EventView - if (!isTopView) { return; } - - friendTree = (TFriendElement*) (activeFile->GetListOfFriends()->FindObject("FullRecoAna0")); - activeTree = friendTree->GetTree(); - if (activeTree) { - FRA_Active=1; - activeTree->SetBranchAddress("El_N", &FRA_El_N, &b_FRA_El_N); - activeTree->SetBranchAddress("El_p_T", &FRA_El_p_T, &b_FRA_El_p_T); - activeTree->SetBranchAddress("El_pdgId", &FRA_El_pdgId, &b_FRA_El_pdgId); - activeTree->SetBranchAddress("El_phi", &FRA_El_phi, &b_FRA_El_phi); - activeTree->SetBranchAddress("El_eta", &FRA_El_eta, &b_FRA_El_eta); - activeTree->SetBranchAddress("Mu_N", &FRA_Mu_N, &b_FRA_Mu_N); - activeTree->SetBranchAddress("Mu_p_T", &FRA_Mu_p_T, &b_FRA_Mu_p_T); - activeTree->SetBranchAddress("Mu_pdgId", &FRA_Mu_pdgId, &b_FRA_Mu_pdgId); - activeTree->SetBranchAddress("Mu_phi", &FRA_Mu_phi, &b_FRA_Mu_phi); - activeTree->SetBranchAddress("Mu_eta", &FRA_Mu_eta, &b_FRA_Mu_eta); - activeTree->SetBranchAddress("Nu_N", &FRA_Nu_N, &b_FRA_Nu_N); - activeTree->SetBranchAddress("Nu_p_T", &FRA_Nu_p_T, &b_FRA_Nu_p_T); - activeTree->SetBranchAddress("Nu_pdgId", &FRA_Nu_pdgId, &b_FRA_Nu_pdgId); - activeTree->SetBranchAddress("Nu_phi", &FRA_Nu_phi, &b_FRA_Nu_phi); - activeTree->SetBranchAddress("Nu_eta", &FRA_Nu_eta, &b_FRA_Nu_eta); - activeTree->SetBranchAddress("HadW_N", &FRA_HadW_N, &b_FRA_HadW_N); - activeTree->SetBranchAddress("HadW_p_T", &FRA_HadW_p_T, &b_FRA_HadW_p_T); - activeTree->SetBranchAddress("HadW_pdgId", &FRA_HadW_pdgId, &b_FRA_HadW_pdgId); - activeTree->SetBranchAddress("HadW_phi", &FRA_HadW_phi, &b_FRA_HadW_phi); - activeTree->SetBranchAddress("HadW_eta", &FRA_HadW_eta, &b_FRA_HadW_eta); - activeTree->SetBranchAddress("LepW_N", &FRA_LepW_N, &b_FRA_LepW_N); - activeTree->SetBranchAddress("LepW_p_T", &FRA_LepW_p_T, &b_FRA_LepW_p_T); - activeTree->SetBranchAddress("LepW_pdgId", &FRA_LepW_pdgId, &b_FRA_LepW_pdgId); - activeTree->SetBranchAddress("LepW_phi", &FRA_LepW_phi, &b_FRA_LepW_phi); - activeTree->SetBranchAddress("LepW_eta", &FRA_LepW_eta, &b_FRA_LepW_eta); - activeTree->SetBranchAddress("HadTop_N", &FRA_HadTop_N, &b_FRA_HadTop_N); - activeTree->SetBranchAddress("HadTop_p_T", &FRA_HadTop_p_T, &b_FRA_HadTop_p_T); - activeTree->SetBranchAddress("HadTop_pdgId", &FRA_HadTop_pdgId, &b_FRA_HadTop_pdgId); - activeTree->SetBranchAddress("HadTop_phi", &FRA_HadTop_phi, &b_FRA_HadTop_phi); - activeTree->SetBranchAddress("HadTop_eta", &FRA_HadTop_eta, &b_FRA_HadTop_eta); - activeTree->SetBranchAddress("LepTop_N", &FRA_LepTop_N, &b_FRA_LepTop_N); - activeTree->SetBranchAddress("LepTop_p_T", &FRA_LepTop_p_T, &b_FRA_LepTop_p_T); - activeTree->SetBranchAddress("LepTop_pdgId", &FRA_LepTop_pdgId, &b_FRA_LepTop_pdgId); - activeTree->SetBranchAddress("LepTop_phi", &FRA_LepTop_phi, &b_FRA_LepTop_phi); - activeTree->SetBranchAddress("LepTop_eta", &FRA_LepTop_eta, &b_FRA_LepTop_eta); - activeTree->SetBranchAddress("Lepb_N", &FRA_Lepb_N, &b_FRA_Lepb_N); - activeTree->SetBranchAddress("Lepb_p_T", &FRA_Lepb_p_T, &b_FRA_Lepb_p_T); - activeTree->SetBranchAddress("Lepb_pdgId", &FRA_Lepb_pdgId, &b_FRA_Lepb_pdgId); - activeTree->SetBranchAddress("Lepb_phi", &FRA_Lepb_phi, &b_FRA_Lepb_phi); - activeTree->SetBranchAddress("Lepb_eta", &FRA_Lepb_eta, &b_FRA_Lepb_eta); - activeTree->SetBranchAddress("Hadb_N", &FRA_Hadb_N, &b_FRA_Hadb_N); - activeTree->SetBranchAddress("Hadb_p_T", &FRA_Hadb_p_T, &b_FRA_Hadb_p_T); - activeTree->SetBranchAddress("Hadb_pdgId", &FRA_Hadb_pdgId, &b_FRA_Hadb_pdgId); - activeTree->SetBranchAddress("Hadb_phi", &FRA_Hadb_phi, &b_FRA_Hadb_phi); - activeTree->SetBranchAddress("Hadb_eta", &FRA_Hadb_eta, &b_FRA_Hadb_eta); - activeTree->SetBranchAddress("Hadj_N", &FRA_Hadj_N, &b_FRA_Hadj_N); - activeTree->SetBranchAddress("Hadj_p_T", &FRA_Hadj_p_T, &b_FRA_Hadj_p_T); - activeTree->SetBranchAddress("Hadj_pdgId", &FRA_Hadj_pdgId, &b_FRA_Hadj_pdgId); - activeTree->SetBranchAddress("Hadj_phi", &FRA_Hadj_phi, &b_FRA_Hadj_phi); - activeTree->SetBranchAddress("Hadj_eta", &FRA_Hadj_eta, &b_FRA_Hadj_eta); - } else if (Warn>1) { std::cout << "\nntupleXML: Warning, cannot find FullRecoAna tree. "; } - - friendTree = (TFriendElement*) (activeFile->GetListOfFriends()->FindObject("TruthAna0")); - activeTree = friendTree->GetTree(); - if (activeTree) { - TRA_Active=1; - activeTree->SetBranchAddress("El_N", &TRA_El_N, &b_TRA_El_N); - activeTree->SetBranchAddress("El_p_T", &TRA_El_p_T, &b_TRA_El_p_T); - activeTree->SetBranchAddress("El_pdgId", &TRA_El_pdgId, &b_TRA_El_pdgId); - activeTree->SetBranchAddress("El_phi", &TRA_El_phi, &b_TRA_El_phi); - activeTree->SetBranchAddress("El_eta", &TRA_El_eta, &b_TRA_El_eta); - activeTree->SetBranchAddress("Mu_N", &TRA_Mu_N, &b_TRA_Mu_N); - activeTree->SetBranchAddress("Mu_p_T", &TRA_Mu_p_T, &b_TRA_Mu_p_T); - activeTree->SetBranchAddress("Mu_pdgId", &TRA_Mu_pdgId, &b_TRA_Mu_pdgId); - activeTree->SetBranchAddress("Mu_phi", &TRA_Mu_phi, &b_TRA_Mu_phi); - activeTree->SetBranchAddress("Mu_eta", &TRA_Mu_eta, &b_TRA_Mu_eta); - activeTree->SetBranchAddress("Tau_N", &TRA_Tau_N, &b_TRA_Tau_N); - activeTree->SetBranchAddress("Tau_p_T", &TRA_Tau_p_T, &b_TRA_Tau_p_T); - activeTree->SetBranchAddress("Tau_pdgId", &TRA_Tau_pdgId, &b_TRA_Tau_pdgId); - activeTree->SetBranchAddress("Tau_phi", &TRA_Tau_phi, &b_TRA_Tau_phi); - activeTree->SetBranchAddress("Tau_eta", &TRA_Tau_eta, &b_TRA_Tau_eta); - activeTree->SetBranchAddress("HadW_N", &TRA_HadW_N, &b_TRA_HadW_N); - activeTree->SetBranchAddress("HadW_p_T", &TRA_HadW_p_T, &b_TRA_HadW_p_T); - activeTree->SetBranchAddress("HadW_pdgId", &TRA_HadW_pdgId, &b_TRA_HadW_pdgId); - activeTree->SetBranchAddress("HadW_phi", &TRA_HadW_phi, &b_TRA_HadW_phi); - activeTree->SetBranchAddress("HadW_eta", &TRA_HadW_eta, &b_TRA_HadW_eta); - activeTree->SetBranchAddress("LepW_N", &TRA_LepW_N, &b_TRA_LepW_N); - activeTree->SetBranchAddress("LepW_p_T", &TRA_LepW_p_T, &b_TRA_LepW_p_T); - activeTree->SetBranchAddress("LepW_pdgId", &TRA_LepW_pdgId, &b_TRA_LepW_pdgId); - activeTree->SetBranchAddress("LepW_phi", &TRA_LepW_phi, &b_TRA_LepW_phi); - activeTree->SetBranchAddress("LepW_eta", &TRA_LepW_eta, &b_TRA_LepW_eta); - activeTree->SetBranchAddress("HadTop_N", &TRA_HadTop_N, &b_TRA_HadTop_N); - activeTree->SetBranchAddress("HadTop_p_T", &TRA_HadTop_p_T, &b_TRA_HadTop_p_T); - activeTree->SetBranchAddress("HadTop_pdgId", &TRA_HadTop_pdgId, &b_TRA_HadTop_pdgId); - activeTree->SetBranchAddress("HadTop_phi", &TRA_HadTop_phi, &b_TRA_HadTop_phi); - activeTree->SetBranchAddress("HadTop_eta", &TRA_HadTop_eta, &b_TRA_HadTop_eta); - activeTree->SetBranchAddress("LepTop_N", &TRA_LepTop_N, &b_TRA_LepTop_N); - activeTree->SetBranchAddress("LepTop_p_T", &TRA_LepTop_p_T, &b_TRA_LepTop_p_T); - activeTree->SetBranchAddress("LepTop_pdgId", &TRA_LepTop_pdgId, &b_TRA_LepTop_pdgId); - activeTree->SetBranchAddress("LepTop_phi", &TRA_LepTop_phi, &b_TRA_LepTop_phi); - activeTree->SetBranchAddress("LepTop_eta", &TRA_LepTop_eta, &b_TRA_LepTop_eta); - activeTree->SetBranchAddress("Bot_N", &TRA_Bot_N, &b_TRA_Bot_N); - activeTree->SetBranchAddress("Bot_p_T", &TRA_Bot_p_T, &b_TRA_Bot_p_T); - activeTree->SetBranchAddress("Bot_pdgId", &TRA_Bot_pdgId, &b_TRA_Bot_pdgId); - activeTree->SetBranchAddress("Bot_phi", &TRA_Bot_phi, &b_TRA_Bot_phi); - activeTree->SetBranchAddress("Bot_eta", &TRA_Bot_eta, &b_TRA_Bot_eta); - activeTree->SetBranchAddress("LQ_N", &TRA_LQ_N, &b_TRA_LQ_N); - activeTree->SetBranchAddress("LQ_p_T", &TRA_LQ_p_T, &b_TRA_LQ_p_T); - activeTree->SetBranchAddress("LQ_pdgId", &TRA_LQ_pdgId, &b_TRA_LQ_pdgId); - activeTree->SetBranchAddress("LQ_phi", &TRA_LQ_phi, &b_TRA_LQ_phi); - activeTree->SetBranchAddress("LQ_eta", &TRA_LQ_eta, &b_TRA_LQ_eta); - } else if (Warn>1) { std::cout << "\nntupleXML: Warning, cannot find TruthAna tree. "; } - - friendTree = (TFriendElement*) (activeFile->GetListOfFriends()->FindObject("TruthAll0")); - activeTree = friendTree->GetTree(); - if (activeTree) { - TA_Active=1; - activeTree->SetBranchAddress("Tru_p_T", &TA_Tru_p_T, &b_TA_Tru_p_T); - activeTree->SetBranchAddress("Tru_phi", &TA_Tru_phi, &b_TA_Tru_phi); - activeTree->SetBranchAddress("Tru_eta", &TA_Tru_eta, &b_TA_Tru_eta); - activeTree->SetBranchAddress("Tru_pdgId", &TA_Tru_pdgId, &b_TA_Tru_pdgId); - activeTree->SetBranchAddress("Tru_barcode", &TA_Tru_barcode, &b_TA_Tru_barcode); - } else if (Warn>1) { std::cout << "\nntupleXML: Warning, cannot find TruthAll tree. "; } - - //If using TopView ntuples, MET_Truth must be fetched from Truth0 - friendTree = (TFriendElement*) (activeFile->GetListOfFriends()->FindObject("Truth0")); - activeTree = friendTree->GetTree(); - if (activeTree) { - TR_Active=1; - activeTree->SetBranchAddress("MET_Truth_ex", &TR_MET_Truth_ex, &b_TR_MET_Truth_ex); - activeTree->SetBranchAddress("MET_Truth_ey", &TR_MET_Truth_ey, &b_TR_MET_Truth_ey); - activeTree->SetBranchAddress("MET_Truth_et", &TR_MET_Truth_et, &b_TR_MET_Truth_et); - } else if (Warn>1) { std::cout << "\nntupleXML: Warning, cannot find Truth tree. "; } -} - -void ntupleXML::FillBranches(Int_t entryNumber) { - if (FR_Active) { - b_FR_eventNumber->GetEntry(entryNumber); - b_FR_runNumber->GetEntry(entryNumber); - b_FR_MET_Final_ex->GetEntry(entryNumber); - b_FR_MET_Final_ey->GetEntry(entryNumber); - b_FR_MET_Final_et->GetEntry(entryNumber); - if (TR_Active) { - b_TR_MET_Truth_ex->GetEntry(entryNumber); - b_TR_MET_Truth_ey->GetEntry(entryNumber); - b_TR_MET_Truth_et->GetEntry(entryNumber); - } - b_FR_El_N->GetEntry(entryNumber); - b_FR_El_pdgId->GetEntry(entryNumber); - b_FR_El_p_T->GetEntry(entryNumber); - b_FR_El_phi->GetEntry(entryNumber); - b_FR_El_eta->GetEntry(entryNumber); - b_FR_Mu_N->GetEntry(entryNumber); - b_FR_Mu_pdgId->GetEntry(entryNumber); - b_FR_Mu_p_T->GetEntry(entryNumber); - b_FR_Mu_phi->GetEntry(entryNumber); - b_FR_Mu_eta->GetEntry(entryNumber); - b_FR_Tau_N->GetEntry(entryNumber); - b_FR_Tau_pdgId->GetEntry(entryNumber); - b_FR_Tau_p_T->GetEntry(entryNumber); - b_FR_Tau_phi->GetEntry(entryNumber); - b_FR_Tau_eta->GetEntry(entryNumber); - b_FR_Ph_N->GetEntry(entryNumber); - b_FR_Ph_pdgId->GetEntry(entryNumber); - b_FR_Ph_p_T->GetEntry(entryNumber); - b_FR_Ph_phi->GetEntry(entryNumber); - b_FR_Ph_eta->GetEntry(entryNumber); - b_FR_PJet_N->GetEntry(entryNumber); - b_FR_PJet_pdgId->GetEntry(entryNumber); - b_FR_PJet_p_T->GetEntry(entryNumber); - b_FR_PJet_phi->GetEntry(entryNumber); - b_FR_PJet_eta->GetEntry(entryNumber); - } - - if (!isTopView) { return; } - - if (FR_Active) { b_FR_PJet_BTagged->GetEntry(entryNumber); } - - if (FRA_Active) { - b_FRA_El_N->GetEntry(entryNumber); - b_FRA_El_pdgId->GetEntry(entryNumber); - b_FRA_El_p_T->GetEntry(entryNumber); - b_FRA_El_phi->GetEntry(entryNumber); - b_FRA_El_eta->GetEntry(entryNumber); - b_FRA_Mu_N->GetEntry(entryNumber); - b_FRA_Mu_pdgId->GetEntry(entryNumber); - b_FRA_Mu_p_T->GetEntry(entryNumber); - b_FRA_Mu_phi->GetEntry(entryNumber); - b_FRA_Mu_eta->GetEntry(entryNumber); - b_FRA_Nu_N->GetEntry(entryNumber); - b_FRA_Nu_pdgId->GetEntry(entryNumber); - b_FRA_Nu_p_T->GetEntry(entryNumber); - b_FRA_Nu_phi->GetEntry(entryNumber); - b_FRA_Nu_eta->GetEntry(entryNumber); - b_FRA_HadW_N->GetEntry(entryNumber); - b_FRA_HadW_pdgId->GetEntry(entryNumber); - b_FRA_HadW_p_T->GetEntry(entryNumber); - b_FRA_HadW_phi->GetEntry(entryNumber); - b_FRA_HadW_eta->GetEntry(entryNumber); - b_FRA_LepW_N->GetEntry(entryNumber); - b_FRA_LepW_pdgId->GetEntry(entryNumber); - b_FRA_LepW_p_T->GetEntry(entryNumber); - b_FRA_LepW_phi->GetEntry(entryNumber); - b_FRA_LepW_eta->GetEntry(entryNumber); - b_FRA_HadTop_N->GetEntry(entryNumber); - b_FRA_HadTop_pdgId->GetEntry(entryNumber); - b_FRA_HadTop_p_T->GetEntry(entryNumber); - b_FRA_HadTop_phi->GetEntry(entryNumber); - b_FRA_HadTop_eta->GetEntry(entryNumber); - b_FRA_LepTop_N->GetEntry(entryNumber); - b_FRA_LepTop_pdgId->GetEntry(entryNumber); - b_FRA_LepTop_p_T->GetEntry(entryNumber); - b_FRA_LepTop_phi->GetEntry(entryNumber); - b_FRA_LepTop_eta->GetEntry(entryNumber); - b_FRA_Lepb_N->GetEntry(entryNumber); - b_FRA_Lepb_pdgId->GetEntry(entryNumber); - b_FRA_Lepb_p_T->GetEntry(entryNumber); - b_FRA_Lepb_phi->GetEntry(entryNumber); - b_FRA_Lepb_eta->GetEntry(entryNumber); - b_FRA_Hadb_N->GetEntry(entryNumber); - b_FRA_Hadb_pdgId->GetEntry(entryNumber); - b_FRA_Hadb_p_T->GetEntry(entryNumber); - b_FRA_Hadb_phi->GetEntry(entryNumber); - b_FRA_Hadb_eta->GetEntry(entryNumber); - b_FRA_Hadj_N->GetEntry(entryNumber); - b_FRA_Hadj_pdgId->GetEntry(entryNumber); - b_FRA_Hadj_p_T->GetEntry(entryNumber); - b_FRA_Hadj_phi->GetEntry(entryNumber); - b_FRA_Hadj_eta->GetEntry(entryNumber); - } - if (TRA_Active) { - b_TRA_El_N->GetEntry(entryNumber); - b_TRA_El_pdgId->GetEntry(entryNumber); - b_TRA_El_p_T->GetEntry(entryNumber); - b_TRA_El_phi->GetEntry(entryNumber); - b_TRA_El_eta->GetEntry(entryNumber); - b_TRA_Mu_N->GetEntry(entryNumber); - b_TRA_Mu_pdgId->GetEntry(entryNumber); - b_TRA_Mu_p_T->GetEntry(entryNumber); - b_TRA_Mu_phi->GetEntry(entryNumber); - b_TRA_Mu_eta->GetEntry(entryNumber); - b_TRA_Tau_N->GetEntry(entryNumber); - b_TRA_Tau_pdgId->GetEntry(entryNumber); - b_TRA_Tau_p_T->GetEntry(entryNumber); - b_TRA_Tau_phi->GetEntry(entryNumber); - b_TRA_Tau_eta->GetEntry(entryNumber); - b_TRA_HadW_N->GetEntry(entryNumber); - b_TRA_HadW_pdgId->GetEntry(entryNumber); - b_TRA_HadW_p_T->GetEntry(entryNumber); - b_TRA_HadW_phi->GetEntry(entryNumber); - b_TRA_HadW_eta->GetEntry(entryNumber); - b_TRA_LepW_N->GetEntry(entryNumber); - b_TRA_LepW_pdgId->GetEntry(entryNumber); - b_TRA_LepW_p_T->GetEntry(entryNumber); - b_TRA_LepW_phi->GetEntry(entryNumber); - b_TRA_LepW_eta->GetEntry(entryNumber); - b_TRA_HadTop_N->GetEntry(entryNumber); - b_TRA_HadTop_pdgId->GetEntry(entryNumber); - b_TRA_HadTop_p_T->GetEntry(entryNumber); - b_TRA_HadTop_phi->GetEntry(entryNumber); - b_TRA_HadTop_eta->GetEntry(entryNumber); - b_TRA_LepTop_N->GetEntry(entryNumber); - b_TRA_LepTop_pdgId->GetEntry(entryNumber); - b_TRA_LepTop_p_T->GetEntry(entryNumber); - b_TRA_LepTop_phi->GetEntry(entryNumber); - b_TRA_LepTop_eta->GetEntry(entryNumber); - b_TRA_Bot_N->GetEntry(entryNumber); - b_TRA_Bot_pdgId->GetEntry(entryNumber); - b_TRA_Bot_p_T->GetEntry(entryNumber); - b_TRA_Bot_phi->GetEntry(entryNumber); - b_TRA_Bot_eta->GetEntry(entryNumber); - b_TRA_LQ_N->GetEntry(entryNumber); - b_TRA_LQ_pdgId->GetEntry(entryNumber); - b_TRA_LQ_p_T->GetEntry(entryNumber); - b_TRA_LQ_phi->GetEntry(entryNumber); - b_TRA_LQ_eta->GetEntry(entryNumber); - } - if (TA_Active) { - b_TA_Tru_p_T->GetEntry(entryNumber); - b_TA_Tru_phi->GetEntry(entryNumber); - b_TA_Tru_eta->GetEntry(entryNumber); - b_TA_Tru_pdgId->GetEntry(entryNumber); - b_TA_Tru_barcode->GetEntry(entryNumber); - } -} - -void ntupleXML::SetActiveFile(Int_t fileNumber) { - if (activeFile != fileStore[fileNumber]) { - activeFile = fileStore[fileNumber]; - if (Warn>1) { std::cout << "\nntupleXML: Setting New Active Tree. "; } - //Associates branches with their variables - ntupleXML::SetBranches(); - } -} - -template<typename TYPE> -std::string ntupleXML::asString(const TYPE& x) { - std::ostringstream o; - o << std::setiosflags(ios::fixed); - if (!(o << x)) { - if (Warn>0) { std::cout << "\nntupleXML: Error in toString Conversion Function. "; } - return "ERROR"; - } - return o.str(); -} - diff --git a/graphics/AtlantisJava/share/specificconfig.jnlp b/graphics/AtlantisJava/share/specificconfig.jnlp deleted file mode 100644 index 46f896703ee..00000000000 --- a/graphics/AtlantisJava/share/specificconfig.jnlp +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Template JNLP webstart file for Atlantis event display for ATLAS - with specific configuration file. --> -<jnlp - spec="1.0+" - codebase="@CODEBASE@" - href="@HREF@"> - <information> - <title>Atlantis event display for ATLAS</title> - <vendor>Atlantis team</vendor> - <homepage href=""/> <!-- should be used from codebase --> - <description>Atlantis event display for ATLAS</description> - <!-- <icon href="files/goofy_favicon.ico"/> - <icon kind="splash" href="files/logo.gif"/> --> - <offline-allowed/> - <shortcut online="false"> - <desktop/> - <menu submenu="Atlantis event display"/> - </shortcut> - </information> - <security> - <all-permissions/> - </security> - <resources> - <j2se version="1.6+" max-heap-size="512m"/> - - <jar href="lib/commons-cli-1.0.jar"/> - <jar href="lib/Jama.jar"/> - <jar href="lib/jas-aida-dev.jar"/> - <jar href="lib/jas-aida.jar"/> - <jar href="lib/jas-freehep-base.jar"/> - <jar href="lib/jas-freehep-hep.jar"/> - <jar href="lib/jas-jas-plotter.jar"/> - <jar href="lib/jas-jel.jar"/> - <jar href="lib/jas-JMinuit.jar"/> - <jar href="lib/jogl.jar"/> - <jar href="lib/jh.jar"/> - <jar href="lib/oncrpc.jar"/> - <jar href="lib/log4j-1.2.15.jar"/> - <jar href="lib/ostermillerutils_1_05_00.jar"/> - <jar href="lib/wired-base-4.0.beta.3-SNAPSHOT.jar"/> - <jar href="lib/ws-commons-util-1.0.2.jar"/> - <jar href="lib/xercesImpl.jar"/> - <jar href="lib/xml-apis.jar"/> - <jar href="lib/xmlrpc-client-3.1.jar"/> - <jar href="lib/xmlrpc-common-3.1.jar"/> - <jar href="lib/jlibeps.jar"/> - <jar href="lib/xmlrpc-server-3.1.jar"/> - <jar href="lib/commons-logging-1.1.jar"/> - <jar href="lib/commons-codec-1.4.jar"/> - <jar href="lib/xml-apis-ext.jar"/> - <jar href="lib/batik-dom.jar"/> - <jar href="lib/batik-anim.jar"/> - <jar href="lib/batik-svggen.jar"/> - <jar href="lib/batik-css.jar"/> - <jar href="lib/batik-bridge.jar"/> - <jar href="lib/batik-parser.jar"/> - <jar href="lib/batik-xml.jar"/> - <jar href="lib/batik-gui-util.jar"/> - <jar href="lib/batik-script.jar"/> - <jar href="lib/batik-transcoder.jar"/> - <jar href="lib/batik-svg-dom.jar"/> - <jar href="lib/batik-extension.jar"/> - <jar href="lib/batik-codec.jar"/> - <jar href="lib/batik-util.jar"/> - <jar href="lib/batik-swing.jar"/> - <jar href="lib/batik-ext.jar"/> - <jar href="lib/batik-gvt.jar"/> - <jar href="lib/batik-awt-util.jar"/> - <jar href="help/help.jar"/> - - <jar href="atlantis.jar" main="true"/> <!-- look for main class here --> - </resources> - - <application-desc main-class="atlantis.Atlantis"> - <argument>--config</argument> - <argument>configuration/@CONFIG@</argument> - <argument>--debug</argument> - <argument>DEBUG</argument> - </application-desc> - -</jnlp> - diff --git a/graphics/AtlantisJava/src/atlantis/ACommandLine.java b/graphics/AtlantisJava/src/atlantis/ACommandLine.java deleted file mode 100644 index 3c87dcf9106..00000000000 --- a/graphics/AtlantisJava/src/atlantis/ACommandLine.java +++ /dev/null @@ -1,399 +0,0 @@ -package atlantis; - -import atlantis.event.AEpsImageProducer; -import atlantis.event.AImageProducer; -import atlantis.event.AEventSource; -import atlantis.event.APngImageProducer; -import atlantis.event.ASvgImageProducer; -import atlantis.globals.AGlobals; -import atlantis.gui.AGUI; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; -import java.awt.Dimension; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.ParseException; - -/** - * This package-private class holds all the command line options - * as well as providing verification - * @author Sebastian Boeser - */ -class ACommandLine { - - //A help formatter - private final HelpFormatter formatter = new HelpFormatter(); - - private AGlobals globals = AGlobals.instance(); - - //The set of command-line options - private final Options options = new Options(); - - //The usage line - private static final String usage = "Atlantis [OPTIONS] [[-s]SOURCE]"; - - //The help message header and footer - private final String headerMsg; - private final String footerMsg; - - - /** - * Create all the options in the constructor. Options are sorted alphabetically in here. - */ - ACommandLine(){ - - //show HLTAutokey tracks - options.addOption(new Option("a", false, "show HLTAutoKey tracks")); - - //configuration file - options.addOption(OptionBuilder.withArgName("file") - .hasArg() - .withDescription("read configuration from specified file") - .withLongOpt("config") - .create("c") - ); - - - //debug - String debugDescr = "log messages of level to " + - "'stdout', optionally to file destination. " + - "Message levels are "+ ALogger.getStringLevels() + " (INFO is default)"; - options.addOption(OptionBuilder - .hasArg() - .hasOptionalArg() - .withArgName("level [destination]") - .withDescription(debugDescr) - .withLongOpt("debug") - .create('d') - ); - - - //help/usage - options.addOption(new Option("h", "help", false, "display this help message")); - - //demo mode - options.addOption(OptionBuilder.withArgName("projections") - .hasOptionalArg() - .withDescription("colon seperated list of projections for the demo mode (e.g \"-j YX:VP\"). " - + "Available projections/actions are YX, " - + "VP(" + AMath.PHI + AMath.ETA + "), " - + "RZ(" + AMath.RHO + "Z), " - + "FR(" + AMath.PHI + AMath.RHO + "), " - + "FZ(" + AMath.PHI + "Z), " - + "XZ(X'Z), " - + "YZ(Y'Z), " - + "LegoPlot, " - + "NE(next event)") - .withLongOpt("projection") - .create("j") - ); - - //loop mode - String loopDescr = "Set event navigation mode, supported values are " - +AEventSource.NavigationMode.LOOP.toString()+", " - +AEventSource.NavigationMode.RANDOM.toString()+", " - +AEventSource.NavigationMode.SEQUENTIAL.toString(); - options.addOption(OptionBuilder.withArgName("mode") - .hasArg() - .withDescription(loopDescr) - .withLongOpt("loop") - .create("l") - ); - - //color map - options.addOption(OptionBuilder.withArgName("file") - .hasArg() - .withDescription("read colourmap from specified file") - .withLongOpt("colormap") - .create("m") - ); - - // output image files - String outputDescr = "Output event image " + - "into directory dir (default: current directory) "+ - "of dimensions width x height (default: 800x828). "+ - "If height is not specified the aspect ratio of the canvas is used. " + - "If scale is given, images will be scaled by that factor (use for thumbnails). "+ - "If a filename is given, that file will be overwritten, "+ - "otherwise a new file will be created for each event. "+ - "The output format may be specified as PNG (the default) or EPS using" + - "the --outputformat option."; - options.addOption(OptionBuilder.hasOptionalArgs(4) - .withArgName("[dir] [width[xheight]] [scale] [filename]") - .withDescription(outputDescr) - .withLongOpt("output") - .create('o') - ); - - String outputFormatDescr = "output format for -o option (eps or png, default is png)"; - options.addOption(OptionBuilder.hasArg() - .withArgName("format") - .withDescription(outputFormatDescr) - .withLongOpt("outputformat") - .create('f') - ); - - //event loop intervall - options.addOption(OptionBuilder.withArgName("seconds") - .hasArg() - .withDescription("pause inbetween events and/or projections options") - .withLongOpt("pause") - .create("p") - ); - - //default source - String sourceDescr = "Set initial event source, e.g\n"+ - "* [file://]<filename>\n"+ - "* http://<url>\n"+ - "* xmlrpc://<server>:<port>\n"+ - "* oncrpc://<server>[:port][:stream]"; - options.addOption(OptionBuilder.withArgName("source") - .hasArg() - .withDescription(sourceDescr) - .withLongOpt("source") - .create("s") - ); - - //update config - options.addOption(new Option("x", "updateconfig", false, "update user's configuration file")); - - //max GUI width - options.addOption(OptionBuilder.withArgName("maxwidth") - .hasArg() - .withDescription("maximum screen width used by Atlantis") - .withLongOpt("maxwidth") - .create("w") - ); - - - //image server - options.addOption(OptionBuilder.hasArgs(1) - .withArgName("port") - .withDescription("Run a server on port <port> which accepts " + - "event data from a client and returns images") - .withLongOpt("imgserver") - .create('I') - ); - - - /** - * Now create header and footer Messages - */ - headerMsg = "\nMandatory arguments to long options are " + - "mandatory for short options too.\n"; - footerMsg = "\nAtlFast objects were supported up to " + - "AtlantisJava-09-05-28 via \"Fast\" option.\n" + - "Beginner simplified GUI was supported up to " + - "AtlantisJava-09-05-28 via \"Beginner\" option.\n" + - "CTB 2004 geometry was supported up to " + - "AtlantisJava-09-07-42 via -t, --testbeam option.\n"; - - } - - /** - * Parse and validate the command line options - */ - void process(String[] args){ - - //Create GNU style parse - CommandLineParser parser = new GnuParser(); - - //Now try parsing the options - try { - - //invoke GNU parser - CommandLine cmdLine = parser.parse(options, args); - - /** - * Now validate and process all options - */ - - //auto-keys - if(cmdLine.hasOption('a')) globals.setHLTAutoKeys(true); - - //config - if(cmdLine.hasOption('c')){ - Atlantis.configCommandLine = cmdLine.getOptionValue('c', null); - } - - //debug - if(cmdLine.hasOption('d')){ - //Get option values - String[] vals = cmdLine.getOptionValues('d'); - //this arg will always be there - String level = vals[0]; - if (! ALogger.getStringLevels().contains(level)) - throw new ParseException("Invalid logging level "+level); - //Check if there was also another argument - String destination = null; - if(vals.length == 2) destination = vals[1]; - - //Finally initialize the logger - ALogger.initialize(level,destination); - } - - //help - if(cmdLine.hasOption('h')) { - formatter.printHelp(usage, headerMsg, options, footerMsg); - System.exit(0); - } - - //image server - if(cmdLine.hasOption('I')){ - Atlantis.imageServerPort = Integer.parseInt(cmdLine.getOptionValue('I')); - if (Atlantis.imageServerPort < 0) - throw new ParseException("Port number "+cmdLine.getOptionValue('I')+ - " is not valid for -I option"); - //Check for other mutual exclusive options - if (cmdLine.hasOption('j') || cmdLine.hasOption('p')) - throw new ParseException("Can not use option -I with -j or -p options"); - } - - //demo mode projections - if(cmdLine.hasOption('j')){ - //NOTE: default is not null but "", so we can distinguish inbetween - //this flag being set or not w/o introducing more parameters - Atlantis.selectedProjections = cmdLine.getOptionValue('j', ""); - } - - //navigation mode - if(cmdLine.hasOption('l')){ - //Get arguments - String loopMode = cmdLine.getOptionValue('l',null); - if (loopMode == null) - throw new ParseException("Option -l needs an argument"); - Atlantis.initialMode = AEventSource.NavigationMode.valueOf(loopMode); - } - - - //color map - if(cmdLine.hasOption('m')){ - // retrieve the argument for options or assign default value - Atlantis.colormapCommandLine = cmdLine.getOptionValue('m', null); - } - - // generate PNG/EPS output files - if(cmdLine.hasOption('o')) - { - String format = "PNG"; - if (cmdLine.hasOption('f')) { - String formatVal = cmdLine.getOptionValue('f'); - format = formatVal.toUpperCase(); - if (!("EPS".equals(format)||"PNG".equals(format))) { - throw new ParseException("Invalid output format "+formatVal); - } - } - String[] vals = cmdLine.getOptionValues('o'); - this.processImageOutputOptions(vals,format); - } - - // generate PNG output files - if(cmdLine.hasOption('e')) - { - String[] vals = cmdLine.getOptionValues('e'); - this.processImageOutputOptions(vals,"EPS"); - } - - //source - if (cmdLine.hasOption('s')){ - //Simply set this as default event source - Atlantis.initialEventSource = cmdLine.getOptionValue('s'); - } - - //pause - if (cmdLine.hasOption('p')){ - //Check for integer value - String val = cmdLine.getOptionValue('p', null); - try { - Atlantis.loopInterval = Integer.parseInt(val); - } catch (NumberFormatException nfe) { - throw new ParseException("Invalid seconds value "+val+" for -p option"); - } - } - - //GUI width - if(cmdLine.hasOption('w')){ - String val = cmdLine.getOptionValue('w', null); - try { - int maxWidth = Integer.parseInt(val); - AGUI.getGUI().setMaxWidth(maxWidth); - } catch (NumberFormatException e) { - throw new ParseException("Invalid width value "+val+" for -w option"); - } - } - - //update config - if(cmdLine.hasOption('x')) Atlantis.updateConfig = true; - - //finally check for positional options (i.e w/o --opt) - String[] unspecifiedOpts=cmdLine.getArgs(); - if (unspecifiedOpts.length > 0){ - //We accept only one, which is a single string for the event source - if ((unspecifiedOpts.length != 1) - || cmdLine.hasOption('s') - || cmdLine.hasOption('I')){ - throw new ParseException("Can only specify one event source"); - } - Atlantis.initialEventSource = unspecifiedOpts[0]; - } - - } catch(ParseException ex) { - //Every error above should have thrown a parse exception - //Show help message and exit - System.err.println("\n" + ex.getMessage() + "\n"); - formatter.printHelp(usage, headerMsg, options, footerMsg); - System.exit(1); - } - - } - - private void processImageOutputOptions(String[] vals, String fileFormat) throws ParseException { - try - { - //vals[0] - directory to store events and png into - //Use current directory as default - String dir=System.getProperty("user.dir"); - if ((vals!=null)&&(vals.length > 0)) dir = vals[0]; - // vals[1] - WidthxHeight string - Dimension dim=new Dimension(800,828); - if ((vals!=null)&&(vals.length > 1)){ - short width = Short.parseShort(vals[1].split("x")[0]); - short height =-1; - if (vals[1].split("x").length > 1) - height = Short.parseShort(vals[1].split("x")[1]); - dim = new Dimension(width,height); - } - // vals[2] - scale factor, default is one - double scale = 1; - if ((vals!=null)&&(vals.length > 2)) scale = Double.parseDouble(vals[2]); - // vals[3] - fixed filename, default is null - String fixedFile = null; - if ((vals!=null)&&(vals.length > 3)) fixedFile = vals[3]; - //Now create a new image generator - if ("EPS".equals(fileFormat)) { - Atlantis.imageProducer = new AEpsImageProducer(dir,dim,scale,fixedFile); - } - else if ("PNG".equals(fileFormat)) { - Atlantis.imageProducer = new APngImageProducer(dir,dim,scale,fixedFile); - } - else if ("SVG".equals(fileFormat)) { - Atlantis.imageProducer = new ASvgImageProducer(dir,dim,scale,fixedFile); - } - else { - throw new Error("Invalid file format for output: "+fileFormat); - } - } catch (NumberFormatException nfe){ - throw new ParseException("Invalid parameters to option -o"); - } catch (IndexOutOfBoundsException iob){ - throw new ParseException("Invalid dimension parameter to option -o"); - } catch (AImageProducer.InstantiationException iex){ - throw new ParseException("Invalid configuration for option -o: "+iex.getMessage()); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/AOpenGLTools.java b/graphics/AtlantisJava/src/atlantis/AOpenGLTools.java deleted file mode 100644 index 02cbf863cc9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/AOpenGLTools.java +++ /dev/null @@ -1,22 +0,0 @@ -package atlantis; - -import javax.media.opengl.GLCanvas; -import javax.media.opengl.GLCapabilities; - -/** - * Provides utility method to check if OpenGL is available. - * @author Adam - */ -public class AOpenGLTools { - - public static boolean isOpenGLAvailable() { - try { - GLCapabilities cap = new GLCapabilities(); - GLCanvas canv = new GLCanvas(cap); - } catch (Error e) { - // Expect some kind of hard exception if the class can't be loaded - return false; - } - return true; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/Atlantis.java b/graphics/AtlantisJava/src/atlantis/Atlantis.java deleted file mode 100644 index e54be406c3a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/Atlantis.java +++ /dev/null @@ -1,770 +0,0 @@ -package atlantis; - -import java.awt.Toolkit; -import java.io.File; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; - -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Node; -import org.w3c.dom.Document; - -import atlantis.canvas.ACanvas; -import atlantis.config.ADefaultValues; -import atlantis.config.AConfigUpdater; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; - -import atlantis.geometry.AAtlasDetector; -import atlantis.geometry.ADetectorSystem; -import atlantis.globals.AGlobals; -import atlantis.graphics.colormap.AColorMap; -import atlantis.gui.ADemoDialog; -import atlantis.gui.AEventQueue; -import atlantis.gui.AGUI; -import atlantis.gui.AStartupWindow; -import atlantis.gui.AEventLoopDialog; -import atlantis.output.AExceptionHandler; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AUtilities; -import atlantis.utils.xml.AXMLErrorHandler; -import atlantis.utils.xml.AXMLEntityResolver; -import atlantis.utils.xml.AXMLUtils; -import atlantis.event.AImageProducer; -import atlantis.event.AEventSource; -import atlantis.utils.ALogger; -import atlantis.event.xmlrpc.AServerXMLRPC; -import atlantis.event.xmlrpc.AServerXMLRPCEventSource; -import atlantis.gui.ACrashReporter; -import atlantis.gui.ADemoLoop; -import atlantis.interactions.AInteractionsConfigReader; -import atlantis.utils.ANewIdHelper; -import atlantis.utils.xml.AXMLEntityResolver; - -import java.util.Arrays; -import java.util.Vector; -import javax.swing.JOptionPane; - - -/** - * Main class of Atlantis application. - * Initialises the application's main components and provides access to them. - */ -public class Atlantis -{ - // The main class logger gets initialized after command line options - // are processed. All other classes will just do - // logger = ALogger.getLogger(Class.class) in their attribute definitions - private static ALogger logger = null; - - /** Store for Atlantis global state. */ - private static AGlobals globals = AGlobals.instance(); - - // expands into SVN tag - private static String versionAtlantisJava = "$HeadURL: file:///atlas/scratch0/graemes/ao-mirror/graphics/AtlantisJava/tags/AtlantisJava-09-16-05-18/src/atlantis/Atlantis.java $"; - - private static final String FILE_SEPAR = System.getProperty("file.separator"); - private static final String USER_HOME_DIR = System.getProperty("user.home"); - - // This is the URL that is used as default for "Read events from URL" - // The stream is set to "Default" as this is the only one guaranteed to be there. - private static final String LIVE_POINT_1_EVENTS_URL = - "http://atlas-live.cern.ch/event_files/Default"; - - // expected file name of the user customised configuration file - // (stored in the user's home directory) - private static final String USER_CONFIG_FILE_PATH = - USER_HOME_DIR + FILE_SEPAR + ".Atlantis-config.xml"; - - // configuration file from the Atlantis distribution (default config) - private static final String DISTRIB_DEFAULT_CONFIG_FILE = - "configuration" + FILE_SEPAR + "config.xml"; - - // this is checksum file of the distribution's main configuration file - // if it doesn't match, Atlantis tries to update user's configuration - // or the --config <configfile> configuration - // it is an indicator that the master config.xml changed - private static final String CONFIG_CHECKSUM_FILE_PATH = - USER_HOME_DIR + FILE_SEPAR + ".Atlantis-config.chk"; - - // limit the total width of Atlantis to this number of pixels (0 = screen width) - private static int MAX_WIDTH = 0; - - /** - * The list of parameters that can be set from the command line - */ - // force Atlantis to update the personal configuration file - protected static boolean updateConfig = false; - // configuration file specified as command line argument - protected static String configCommandLine = null; - // colormap file specified as command line argument - protected static String colormapCommandLine = null; - // selected projections specified as command line argument for demo mode - protected static String selectedProjections = null; - // timer delay from command line for reading events in a loop - protected static Integer loopInterval = null; - // navigation mode from command line - protected static AEventSource.NavigationMode initialMode = null; - // initial event source, may be specified from command line - protected static String initialEventSource = "events"+FILE_SEPAR+"test_events.zip"; - // Object for saving event images in a directory - protected static AImageProducer imageProducer = null; - // Port number for image server from command line - protected static int imageServerPort = -1; - - private static final boolean atlantisWithOpenGL = false; - - private static final String INIT_ERROR_MSG = - "Error during Atlantis initialization.\n" + - "(configuration file related issues might be\n" + - "corrected by running with -x (updating customised configuration)).\n" + - "See console output for more information."; - - // main Atlantis components - private static APar parameterStore = null; - private static AEventManager eventManager = null; - private static ADetectorSystem detector = null; - private static ACanvas canvas = null; - private static AGUI gui = null; - - /** - * Returns the delay for timer for automatic event reading from server - * when this option was specified as command line argument - * @return the delay in seconds - */ - private static Integer getLoopInterval() - { - return loopInterval; - } - - - /** - * Set the default java look and feel ("metal") - */ - private static void setLookAndFeel() - { - try { - UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); - } catch(Exception e) { - AExceptionHandler.processException("Error setting default Look and Feel", e); - } - } - - - /** - * Check if the checksum file CONFIG_CHECKSUM_FILE_PATH is up-to-date. - * Create one if it does not exist or update it if it is not up-to-date. - */ - private static void checkAndUpdateConfigCheckSumFile(String distribFile) - throws AAtlantisException - { - if(Atlantis.updateConfig) - { - logger.info("Checksum not checked, run with -x, configuration update " + - "forced anyway."); - return; - } - - logger.info("Checking if the used configuration is up-to-date ..."); - - logger.debug("Checking checksum of the configuration file from the " + - "Atlantis distribution: " + distribFile); - logger.debug("Checksum file: " + CONFIG_CHECKSUM_FILE_PATH); - - boolean checkSumExists = new File(CONFIG_CHECKSUM_FILE_PATH).exists(); - - if(checkSumExists) - { - boolean comparison = AConfigUpdater.compareChecksums(distribFile, - CONFIG_CHECKSUM_FILE_PATH); - if(comparison) - { - logger.debug("Checksum file - checksum match, no update necessary."); - Atlantis.updateConfig = false; - return; - } - } - - // doesn't match, force update of custom configuration - // and re-generate checksum - AConfigUpdater.createChecksumFile(distribFile, CONFIG_CHECKSUM_FILE_PATH); - logger.debug("Checksum didn't match, updating customised " + - "configuration forced."); - Atlantis.updateConfig = true; - - } // checkAndUpdateConfigCheckSumFile() --------------------------------- - - - - /** - * Returns InputStream to read XML application configuration from. - * - * Evaluates sources from which Atlantis XML configuration is - * possibly loaded from (prioritised): - * 1) -c, --config <configfile.xml> specified on the command line - * here available in configCommandLine variable - * 2) if USER_CONFIG_FILE_PATH exists, read that one - * 3) or eventually read <ATLANTIS_DIRECTORY>/DISTRIB_DEFAULT_CONFIG_FILE - * - * User's customised (in the home directory) or --config <configfile> are - * also tried to be updated when the checksum configuration file doesn't - * match. Atlantis calculates checksum of the main distribution - * configuration file and stores that checksum in CONFIG_CHECKSUM_FILE_PATH. - * If this checksum doesn't match when Atlantis is run on the user's - * home directory configuration or --config <configfile> configuration, - * automatic configuration file update process is executed. - * - * Updating means that config.xml (main, base) contains some changes - * which are not consistent with the user's config or custom config - * and they need to be propagated there. - * Update process: - * AConfigUpdater.updateConfigurationFile(distribFilePath, configToUse) - * is then executed. - * - * Do not try to update custom configuration which is located in the same - * directory as the base config file - it means that such custom config - * comes with AtlantisJava distribution - no need updating this one. - */ - private static InputStream getXMLConfigAsStream() throws Exception - { - String configToUse = null; - - logger.info("Reading the XML configuration ..."); - - // configuration file from the Atlantis distribution - String distribFilePath = getHomeDirectory() + DISTRIB_DEFAULT_CONFIG_FILE; - - // distribution config file checksum only taken into account when having - // --config command line argument or when running from user's (home - // directory) configuration - - // option / source 1) - command line argument - highest priority - if(configCommandLine != null) - { - logger.info("Using configuration file specified on the command " + - "line: " + configCommandLine); - // sets Atlantis.updateConfig = true; accordingly - checkAndUpdateConfigCheckSumFile(distribFilePath); - configToUse = configCommandLine; - } - else - { - // check if we can read the user configuration file (in home dir.) - // option / source 2) - if(new File(USER_CONFIG_FILE_PATH).exists()) - { - logger.info("Using user's configuration file: " + - USER_CONFIG_FILE_PATH); - // sets Atlantis.updateConfig = true; accordingly - checkAndUpdateConfigCheckSumFile(distribFilePath); - configToUse = USER_CONFIG_FILE_PATH; - } - else - { - // // option / source 3) - logger.info("Using distribution configuration file: " + - distribFilePath); - if(Atlantis.updateConfig) - { - logger.warn("Update custom configuration flag is set, " + - "that doesn't make sence - no custom config " + - "file available, ignored."); - Atlantis.updateConfig = false; - } - configToUse = distribFilePath; - } - } - - - try - { - // try to update custom configuration before loading it - if(Atlantis.updateConfig) - { - logger.info("Updating customised configuration file ..."); - // check if configToUse comes from atlantis home directory, if - // so, then configToUse is from AtlantisJava distribution, should - // already be up-to-date and no automatic update will be performed - String atlantisHome = Atlantis.getHomeDirectory(); - String customConfigDir = new File(configToUse).getAbsolutePath(); - - logger.info("Updating configuration - customised config directory: " + - customConfigDir); - // if configToUse comes from AtlantisJava distribution, customConfigDir - // path start with atlantisHome path plus 'configuration' directory - // (does not filter off webstart since .getHomeDirectory() - // returns user's home directory when running via webstart, - // the condition below should be improved to cover webstart situation - // as well ...) - if(customConfigDir.startsWith(atlantisHome)) - { - logger.debug("Updating configuration - Atlantis home: " + atlantisHome); - logger.info("Updating configuration - customised config directory " + - "is in the Atlantis home, no need updating it."); - } - else - { - AConfigUpdater.updateConfigurationFile(distribFilePath, - configToUse); - } - } - } - catch(AAtlantisException aae) - { - logger.error(aae.getMessage()); - } - - - InputStream isConfig = null; // configuration file input stream - try - { - isConfig = AUtilities.getFileAsStream(configToUse); - } - catch(AAtlantisException aae) - { - String m = "Could not read " + configToUse + " reason: " + - aae.getMessage(); - throw new Exception(m); - } - - logger.info("Going to parse XML configuration: " + configToUse); - return isConfig; - - } // getXMLConfigAsStream() --------------------------------------------- - - - - private static void initAtlantis() { - - String homeDirectory = Atlantis.getHomeDirectory(); - globals.setHomeDirectory(homeDirectory); - - //Create startup window and set how often - //the progress bar will get update below - AStartupWindow startupWin = new AStartupWindow(9); - - try { - System.setProperty("sun.awt.exception.handler", - "AExceptionHandler"); - - startupWin.updateText("Atlantis initialisation"); - - //Show atlantis home - logger.info("Atlantis home: "+homeDirectory); - - //Create an event manager - eventManager = AEventManager.instance(); - - // reading Atlantis runtime configuration (text file in the home directory) - logger.info("Reading Atlantis runtime configuration, file: " + - ADefaultValues.CONFIGFILE); - ADefaultValues.readRuntimeValues(); - - - // read the configuration xml files ------------------------- - startupWin.updateText("Reading Atlantis configuration"); - - // evaluate configuration sources options and get the configuration - InputStream isConfig = getXMLConfigAsStream(); - - // prepare XML parser for parsing the XML configuration - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(true); - DocumentBuilder parser = factory.newDocumentBuilder(); - parser.setErrorHandler(new AXMLErrorHandler()); - parser.setEntityResolver(new AXMLEntityResolver()); - - // parse the XML configuration - String configBase = homeDirectory + FILE_SEPAR + "configuration" + FILE_SEPAR; - Document xmlConfigDoc = parser.parse(isConfig, configBase); - Node rootNode = xmlConfigDoc.getDocumentElement(); - // read the XML initialization node, and performs initialization - Node initializationNode = AXMLUtils.getChild(rootNode, "Initialization"); - - // parse the ID dictionary - String geometryBase = homeDirectory + FILE_SEPAR + "geometry" + FILE_SEPAR; - InputStream isIdDict = AUtilities.getFileAsStream(geometryBase+"ATLAS_IDS.xml"); - Document xmlDictDoc = parser.parse(isIdDict, geometryBase); - ANewIdHelper.construct(xmlDictDoc.getDocumentElement()); - - - // read colour map (colormap.xml) configuration ----------------- - startupWin.updateText( "Reading colour map"); - AColorMap.readColorMap(Atlantis.colormapCommandLine); - - - // creating canvas ---------------------------------------------- - startupWin.updateText("Building canvas and projections"); - Node canvasNode = AXMLUtils.getChild(initializationNode, "Canvas"); - canvas = ACanvas.construct(canvasNode); - - // reading parameters ------------------------------------------ - logger.info("Building parameters"); - parameterStore = APar.construct(AXMLUtils.getChild(rootNode, "Parameters")); - parameterStore.update(AXMLUtils.getChild(rootNode, "ParameterDifferences")); - eventManager.addNewEventListener(parameterStore); - // creating the Projections Manager (reading the projections) - Node interactionsNode = - AXMLUtils.getChild(initializationNode, "Interactions"); - AInteractionsConfigReader.readInteractions(interactionsNode); - AProjectionsManager.initialise(); - - //set the output flag: 0 normal 1 eta/phi/pt 2 px/py/pz 3 eta/phi/pt/px/py/pz - if(parameterStore.get("Minerva","alternativesimpleoutput").getStatus()){ - if(parameterStore.get("Minerva","simpleoutput").getStatus()){ - globals.setSimpleOutput(3); - }else{ - globals.setSimpleOutput(2); - } - }else if(parameterStore.get("Minerva","simpleoutput").getStatus()){ - globals.setSimpleOutput(1); - } - - // reading the geometry ---------------------------------------- - startupWin.updateText("Reading geometry"); - String geomPrefix = Atlantis.getHomeDirectory() + "geometry" + - Atlantis.FILE_SEPAR; - String geomName = ADefaultValues.get("GeometryName"); - if (!"".equals(geomName)) { - // name of the geometry considered after underscore - geomName = "_" + geomName; - - // do the geometry files exist - just try loading the files - String geomNameFull1 = geomPrefix + "AGeometry" + geomName + ".xml"; - String geomNameFull2 = geomPrefix + "AMuonGeometry" + geomName + ".xml"; - try { - // just accessibility test - @SuppressWarnings("unused") - InputStream i = AUtilities.getFileAsStream(geomNameFull1); - i = AUtilities.getFileAsStream(geomNameFull2); - i = null; - } catch (AAtlantisException ae) { - geomName = ""; // will fall back to default geometry - } - } - String geomIdCalo = geomPrefix + "AGeometry" + geomName + ".xml"; - String geomMuon = geomPrefix + "AMuonGeometry" + geomName + ".xml"; - detector = new AAtlasDetector(geomIdCalo, geomMuon); - AAtlasDetector.setDetector(detector); - - canvas.finalizeConstruction(); - canvas.readCorners(AXMLUtils.getChild(rootNode, "WindowCorners")); - // This is needed here, design should be changed to remove this problem - canvas.setCurrentWindow(canvas.getCurrentWindowName()); - - //Add the canvas as a NewEvent event listener - eventManager.addNewEventListener(canvas); - - // reading the first event -------------------------------------- - startupWin.updateText("Reading initial event"); - getInitialEvent(); - - // displaying GUI, Canvas --------------------------------------- - startupWin.updateText("Displaying GUI and Canvas"); - - // update colors to those selected in the config file - AColorMap.setColorMap(parameterStore.get("Prefs", "ColorMap").getI()); - // NB: must calculate the size of GUI after calling - // canvas.setVisible(true), in which the real final size of Canvas - // will be calculated - canvas.setCanvasVisible(true); - - // Now the canvas is on the screen and have a size, check if we need - // to rework the aspect ratio on YX projections at all as is the case - // when going to control room projectors for example - AD - canvas.correctAspectRatios(); - - //Create the GUI - gui = AGUI.getGUI(); - - //If we got one, show it (e.g. not in headless mode) - if (gui != null){ - gui.setMaxWidth(MAX_WIDTH); - gui.setName("Atlantis GUI"); // Name is used by JUnit/FEST tests - // Tell the parameter store about the GUI so it can inform the GUI of parameter changes - parameterStore.addParameterChangeListener(gui); - //Display it - gui.setVisible(true); - // and register as a layout change listener - canvas.addOverlay(); - canvas.addLayoutChangeListener(gui); - } - - //Before starting any loops, inform user we are ready to go - startupWin.updateText("Atlantis Ready"); - - // Set the navigation mode if given on the command line. - // Use SwingUtilities.invokeLater() to "defer until all pending events - // have been processed", avoiding the deadlock that otherwise occurs. - if (Atlantis.initialMode != null){ - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - eventManager.setNavigationMode(initialMode); - } catch (InvalidEventSourceException e) { - logger.error("Invalid event source", e); - } - } - }); - } - - //Set up event loop if requested - if ((Atlantis.loopInterval != null) - && (Atlantis.selectedProjections == null ) - && (!AGlobals.isAtlantisHeadless()) ) { - // A loop interval has been given, but no projections - - // so create an event loop dialog, but not in headless mode - AEventLoopDialog dialog = AEventLoopDialog.getInstance(); - - //set all properties - dialog.setUpdateInterval(getLoopInterval()); - dialog.showDialog(); - dialog.startEventLoop(); - } - - //setup demo loop if requested - if (Atlantis.selectedProjections != null) { - //If user just gave -j, use default settings - if (Atlantis.selectedProjections.equals("")) - ADemoDialog.getInstance().setDefaultSequence(); - //User may also give the update interval - if (getLoopInterval() != null) - ADemoDialog.getInstance().setTimerInterval(getLoopInterval()); - ADemoDialog.getInstance().setVisible(true); - ADemoDialog.getInstance().startDemo(); - } - - //Add an image server if requested on the command line - if (imageServerPort >= 0) { - AServerXMLRPC serv = new AServerXMLRPC(imageServerPort, AServerXMLRPCEventSource.class); - serv.start(); - } - - //If we have a image saver, add it now as new event listener - if (imageProducer != null){ - eventManager.addNewEventListener(imageProducer); - //if we are also running in headless mode, add an automatic event loop - if (AGlobals.isAtlantisHeadless()){ - //Check whether the event source is a file or an ONCRPC server - //For a server, start the loop in a "try hard" mode, i.e only stop on ReadEventException - boolean stopOnFailure = !(eventManager.getEventSource() instanceof atlantis.event.oncrpc.AONCRPCEventSource ); - //If a loop interval is given on the command line, use it, - //otherwise, run in "as fast as can mode" - int sleepTime = (Atlantis.loopInterval != null) ? Atlantis.loopInterval*1000 : 0; - //Show warning in case of "as fast as we can mode" - if (sleepTime == 0) logger.info("No loop intervall given - processing events as fast as possible"); - //Now create the loop - ADemoLoop loop = new ADemoLoop(sleepTime,new Vector<String>(Arrays.asList("NE")),stopOnFailure); - //And start it right away - loop.startDemoLoop(); - //also wait for it to finish before the program finishes - synchronized (loop) { loop.wait(); } - } - } - - } catch (Exception e) { - logger.fatal(INIT_ERROR_MSG); - logger.fatal(e.getMessage(), e); - AExceptionHandler.processException(INIT_ERROR_MSG, e); - } finally { - if (startupWin != null) { - startupWin.dispose(); - } - } - - } // initAtlantis() ----------------------------------------------------- - - - protected static String getHomeDirectory() - { - // where was this class loaded from - String temp = Atlantis.class.getResource("Atlantis.class").getFile(); - - // remove "file://" or "file:" - if (temp.startsWith("file://")) { - temp = temp.substring(7); - } else if (temp.startsWith("file:")) { - temp = temp.substring(5); - } - - if(temp.indexOf("!") > -1) - { - // atlantis is in a .jar file - temp = temp.substring(0, temp.indexOf("!")); - temp = temp.replaceAll("%20", " "); - return temp.substring(0, temp.lastIndexOf('/') + 1); - } - // must be the current working directory of the user - return System.getProperty("user.dir") + FILE_SEPAR; - - } // getHomeDirectory() ------------------------------------------------- - - /** - * Process the options passed on the command line - * @param args the command line arguments - */ - private static void processCommandLineParameters(String args[]) - { - - //echo the given command line options - System.out.println("Command line arguments:"); - for(String arg : args) System.out.print(arg + " "); - System.out.println("\n"); - - //Then go and process the command line - (new ACommandLine()).process(args); - - } // processCommandLineParameters() ------------------------------------- - - - /** - * Try to read the initial event - * - from the given event source - * - from the default event - */ - private static void getInitialEvent() - { - //Get the file where the default event is stored - //if not a special source - String eventPath = Atlantis.initialEventSource; - - // if this is not a special source then consider it - // a) to be a file with relative or absolute path - // b) to be a file relative to the Atlantis directory - if (! eventPath.contains("://") ) { - //This should be a file, see if it exists - if(! new File(eventPath).exists()) { - //try prepending atlantis home directory - logger.info("File "+eventPath+" does not exist - trying in "+Atlantis.getHomeDirectory()); - eventPath = Atlantis.getHomeDirectory()+eventPath; - } - - //All non specified sources are assumed to be files - eventPath = "file://" + eventPath; - } - - //be verbose - logger.info("Reading the default event from " + eventPath); - //set the event source and read an event - try { - eventManager.setEventSource(eventPath); - eventManager.nextEvent(); - } catch (InvalidEventSourceException ies){ - //Write error message - String msg = "Can not access "+eventPath+": "+ies.getMessage(); - logger.error(msg); - //Show error dialog - if (AGlobals.isAtlantisHeadless()) return; - JOptionPane.showMessageDialog(ACanvas.getCanvas(), msg, - "Invalid Event Source",JOptionPane.ERROR_MESSAGE); - } catch (NoMoreEventsException nme){ - String msg = "No events in "+eventPath+": "+nme.getMessage(); - logger.error(msg); - //Show error dialog - if (AGlobals.isAtlantisHeadless()) return; - JOptionPane.showMessageDialog(ACanvas.getCanvas(), msg, - "No Events found",JOptionPane.ERROR_MESSAGE); - } catch (ReadEventException rex){ - String msg = "Can not read events from "+eventPath+": "+rex.getMessage(); - logger.error(msg); - //Show error dialog - if (AGlobals.isAtlantisHeadless()) return; - JOptionPane.showMessageDialog(ACanvas.getCanvas(), msg, - "Can not read event",JOptionPane.ERROR_MESSAGE); - } - } - - /** - * Get the SVN tag version from the HeadURL, which is automatically - * substituted by SVN. - */ - private static void setSVNTagInfo() - { - // SVN expands into $HeadURL: file:///atlas/scratch0/graemes/ao-mirror/graphics/AtlantisJava/tags/AtlantisJava-09-16-05-18/src/atlantis/Atlantis.java $, - // we only want the tag name - String s = Atlantis.versionAtlantisJava; - // 0) Check we are in a tagged version - if (!s.contains("tags")){ - Atlantis.versionAtlantisJava = "AtlantisJava (SVN tag n/a)"; - return; - } - // 1) Replace anything after src - s=s.substring(0,s.indexOf("/src")); - // 2) Next find the "tags" subdir and cut after that - s=s.substring(s.indexOf("tags/")+5); - //this should be the version - Atlantis.versionAtlantisJava = s; - } - - public static void main(String[] args) - { - - /** - * First thing always: say hello with a version number - */ - //Retrieve the SVN version tag number - setSVNTagInfo(); - globals.setVersion(versionAtlantisJava); - globals.setLivePoint1EventsURL(LIVE_POINT_1_EVENTS_URL); - globals.setUserConfigFile(USER_CONFIG_FILE_PATH); - globals.setUseOpenGL(atlantisWithOpenGL); - System.out.println("AtlantisJava version (SVN tag): " + Atlantis.versionAtlantisJava); - - // Any uncaught exception should be reported to the developers - Thread.setDefaultUncaughtExceptionHandler(new ACrashReporter()); - - /** - * Now run all the checks for system properties - */ - - //Now set the default look and feel - setLookAndFeel(); - - // Disable rename file/make new directory from the file chooser - UIManager.put("FileChooser.readOnly", Boolean.TRUE); - - /** - * Process the command line parameters - */ - //process args - processCommandLineParameters(args); - - //Logger can be created only after cmdl opts to catch settings - logger = ALogger.getLogger(Atlantis.class); - - //Do some OGL checks - if (Atlantis.atlantisWithOpenGL) { - logger.info("Testing for OpenGL"); - logger.info(AOpenGLTools.isOpenGLAvailable() ? "Open GL Available" : "Open GL Unavailable"); - } - - /** - * Now go and create the manifold Atlantis classes and singletons. - * Has to run on main thread so display is updated during initialization. - */ - initAtlantis(); - // Replace event queue by AEventQueue, but only after initialization. - try { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - logger.debug("Waiting for AWT event queue to be empty."); - } - }); - } catch (InterruptedException e) { - logger.error("Interrupted while waiting for event queue.", e); - } catch (InvocationTargetException e) { - logger.error("Error while waiting for event queue.",e); - } - Toolkit.getDefaultToolkit().getSystemEventQueue().push(new AEventQueue()); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ACanvas.java b/graphics/AtlantisJava/src/atlantis/canvas/ACanvas.java deleted file mode 100755 index 41b32a59cbc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ACanvas.java +++ /dev/null @@ -1,1113 +0,0 @@ -package atlantis.canvas; - -import atlantis.event.AEvent; -import atlantis.event.ANewEventListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.Insets; -import java.awt.Toolkit; -import java.awt.geom.Point2D; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Stack; -import java.util.Vector; -import java.util.Set; - -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.globals.AGlobals; -import atlantis.graphics.ACursorFactory; -import atlantis.graphics.AIcon; -import atlantis.graphics.layout.AGridLayout; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.utils.xml.AXMLUtils; -import atlantis.gui.AClosingConfirmationDialog; -import atlantis.gui.AInteractionToolBar; -import atlantis.gui.APreferencesControl; -import atlantis.interactions.AZMRInteraction; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionEventInfo; -import atlantis.utils.ALogger; -import java.awt.Graphics; -import java.awt.event.WindowFocusListener; -import java.util.Iterator; -import javax.swing.JMenuBar; -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -/** - * ACanvas is a singleton class that acts as a sort of WindowManager It knows the currentLayout (of the - * windows), their history and the currentWindow. It also contains the title (Menu Bar). - * Window changes are given via two letter commands e.g. "W5" inserted into the - * CommandProcessor (static). The command processor informs ACanvas. - * Each window also has its own layer that is stored in a JLayeredPane object. - */ -public class ACanvas extends JPanel implements ANewEventListener { - - //Singleton instance - private static ACanvas instance; - - private final static ALogger logger = ALogger.getLogger(ACanvas.class); - - /** The fraction of the screen width used by default. */ - public final double SCREEN_USAGE = 0.73; - /** Temporary flag to set the window corners from config file. */ - protected boolean customisedCorner = false; - - //the layeredPane - private JLayeredPane layeredPane; - //from some reason we count or layers from 1000 on? - private final int baseLayer = 1000; - - //A list of layout names and layouts - private Hashtable<String, ALayout> layouts = new Hashtable<String, ALayout>(); - //The current canvas layout - private ALayout currentLayout; - //The name of the startup layout - private String startupLayoutName; - //Everyone that should get informed if the layout is changed - private Vector<ALayoutChangeListener> layoutChangeListeners = new Vector<ALayoutChangeListener>(); - - //Save a history of the windows layouts - // - this is used for "Zoom/Unzoom colorimters" in VPlot - private Stack<ALayout> windowLayoutHistory = new Stack<ALayout>(); //History of ALayout objects - private Stack<String> windowNameHistory = new Stack<String>(); //History of the selected window - private Stack<Vector<String>> windowsActive = new Stack<Vector<String>>(); //History of active (i.e. visible windows) - - private Hashtable<String,AWindow> windowsList; // A list of all window <name,object> pairs - private AWindow currentWindow; // The currently selected window - private AWindow paintingWindow; // The window we are currently painting in - //Everyone that should get informed about changes of the active window - private Vector<ChangeListener> windowChangeListeners = new Vector<ChangeListener>(); - //Everyone that should get informed about window freeze/unfreeze changes - private Vector<ChangeListener> lockChangeListeners = new Vector<ChangeListener>(); - - //The title bar showing Event/Run numbers etc. - private ATitleMenuBar title; - - //If constructed from a config file, this stores the aspect ratio of the - //canvas layout which was saved into the config file, this is then used - //later to correct if the current screen is different - private double oldaspect = 1.0; - - private JFrame parentWindow = null; - - private APar parameterStore; - - /** - * Get the singleton instance. - * @return - */ - public static synchronized ACanvas getCanvas() { - if (instance==null) throw new Error("Attempted to access ACanvas instance before initialization."); - return instance; - } - - /** - * Create and return the singleton instance. - * @param parameters - */ - public static synchronized ACanvas construct(Node node) { - instance = new ACanvas(node); - return instance; - } - - /** - * Constructs the singleton instance by reading the config file. - */ - private ACanvas(Node node) { - - if (!AGlobals.isAtlantisHeadless()) { - // Create parent window - parentWindow = new JFrame("Atlantis Canvas"); - parentWindow.add(this); - } - - //Create the title bar - title = new ATitleMenuBar(); - - if (!AGlobals.isAtlantisHeadless()) { - parentWindow.setJMenuBar(title); - } - - //instanciate instance pointer for singleton class - instance = this; - - if (!AGlobals.isAtlantisHeadless()) { - // AClosingConfirmationDialog class handles closing Atlantis - parentWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - parentWindow.addWindowListener(new AClosingConfirmationDialog(parentWindow)); - - //Set the window icon - AIcon.setIconImage(parentWindow); - } - - // building the Layered Pane - layeredPane = new JLayeredPane(); - - // reading all the content of Canvas configuration node - windowsList = new Hashtable<String,AWindow>(); - // Allow null Node to generate partially initialized instance for unit tests of - // other classes that depend on ACanvas. - if (node!=null) readConfig(node); - - } // ACanvas() ---------------------------------------------------------- - - /** - * For testing only: create instance without initializing. - * @return - */ - public static synchronized ACanvas constructDummyForTesting() { - instance = new ACanvas(null); - return instance; - } - - void addParentWindowFocusListener(WindowFocusListener wfl) { - if (parentWindow != null) { - parentWindow.addWindowFocusListener(wfl); - } - } - - public void setCanvasVisible(boolean v) { - if (parentWindow != null) { - parentWindow.setVisible(v); - } else { - setVisible(v); - } - } - - public Rectangle getScreenSize() { - if (parentWindow != null) { - return parentWindow.getGraphicsConfiguration().getBounds(); - } else { - // If we're headless then make up a size! - return new Rectangle(1024, 768); - } - } - - public Rectangle getStartupCanvasSize() { - if (parentWindow == null) { - return null; - } - Rectangle canvpos = parentWindow.getBounds(); - Dimension canvlayoutdim = parentWindow.getPreferredSize(); - Rectangle canvbound = new Rectangle(canvpos.x, canvpos.y, - canvlayoutdim.width, canvlayoutdim.height); - - return canvbound; - } - - public JMenuBar getTitleBar() { - if (parentWindow == null) { - return null; - } - return parentWindow.getJMenuBar(); - } - - public void bringToFront() { - if (parentWindow != null) { - parentWindow.toFront(); - } - } - - /*public JFrame getParentWindow() { - return parentWindow; - }*/ - - private void readConfig(Node node){ - - //Get a list of subnodes - NodeList children = node.getChildNodes(); - - //Loop over all subnodes - for (int i = 0; i < children.getLength(); i++) { - Node child = children.item(i); - //Check wether subnode is a Window or a Layout - if (child.getNodeType() == Node.ELEMENT_NODE) { - String nodeName = child.getNodeName(); - //Add a Window or a layout - if (nodeName.equals("UsedWindow")) readWindow(child); - else if (nodeName.equals("Layout")) readLayout(child); - } - } - - // reading all the attributes of Canvas node - NamedNodeMap attributes = node.getAttributes(); - // The startupLayout: - startupLayoutName = attributes.getNamedItem("startupLayout").getNodeValue().trim(); - - // Aspect ratio stuff: - oldaspect = Double.NaN; - Node n = attributes.getNamedItem("aspectRatio"); - - if (n != null) { - oldaspect = Double.parseDouble( - attributes.getNamedItem("aspectRatio").getNodeValue().trim()); - } - - logger.debug("Read config file with aspectRatio: " + oldaspect); - } - - //Read window configuration - private void readWindow(Node node) { - AWindow w = AWindow.createFromXMLConfigNode(node, getWindowsCount()); - - if (!windowsList.containsKey(w.getName())) { - windowsList.put(w.getName(), w); - } else - throw new Error("Redefinition of window: " + w.getName()); - } - - //Read layout configuration - private void readLayout(Node node) { - ALayout layout = new ALayout(node); - - if (!layouts.containsKey(layout.getName())) - layouts.put(layout.getName(), layout); - else - throw new Error("Redefinition of layout: " + layout.getName()); - } - - //Read window corners - public void readCorners(Node corners) { - if (corners == null) - return; - //Set flag to set default corners - customisedCorner = true; - //Get list of corners - NodeList children = corners.getChildNodes(); - //Loop over corners - for (int i = 0; i < children.getLength(); i++) { - Node corner = children.item(i); - if (corner.getNodeType() == Node.ELEMENT_NODE) { - //Get corner attributes - NamedNodeMap attributes = corner.getAttributes(); - String windowName = AXMLUtils.tryAttribut(attributes, "windowName"); - double x0 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "x0")); - double y0 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "y0")); - double x1 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "x1")); - double y1 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "y1")); - double x2 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "x2")); - double y2 = Double.parseDouble(AXMLUtils.tryAttribut(attributes, "y2")); - //Create an array with new window corners - Point2D.Double[] c = new Point2D.Double[] { new Point2D.Double(x0, y0), new Point2D.Double(x1, y1), new Point2D.Double(x2, y2) }; - //Set the corners for this window - - getWindow(windowName).setUserCorners(c); - } - } - customisedCorner = false; - } - - - //Finalize the canvas construction - public void finalizeConstruction() { - parameterStore = APar.instance(); - - if (!parameterStore.get("Prefs", "CanvasTitle").getStatus()) { - title.setVisible(false); - } - - //Bring the startup layout on screen - setCurrentLayout(startupLayoutName); - } - - public void addOverlay() { - - AOverlay overlay = new AOverlay(); - if(parentWindow != null) - parentWindow.setGlassPane(overlay); - overlay.setVisible(true); - } - - public void correctAspectRatios() { - - // If we didn't have a saved aspect ratio or didn't know it when - // the config was written - if (Double.isNaN(oldaspect)) { - return; - } - - // Only correct aspect ratio for the full screen layout, the other - // layouts have fixed aspect ratios and should always be okay - if (!currentLayout.getName().equals("FULL SCREEN")) { - return; - } - - // If aspect ratios are the same, we can stop - if (java.lang.Math.abs(getAspectRatio() - oldaspect) < 1e-2) { - logger.debug("Aspect ratio of config file same as this display, no correction required"); - return; - } - - logger.info("Aspect ratio of config file (" + oldaspect + ") does not match this display (" + getAspectRatio() + ") attempting to correct"); - - // Else, iterate over all windows - Iterator<AWindow> it = windowsList.values().iterator(); - while(it.hasNext()) { - AWindow w = (AWindow)(it.next()); - AProjection p = w.getProjection(); - if (p instanceof AProjection2D) { - ((AProjection2D)p).aspectRatioChange(w, oldaspect, getAspectRatio()); - } - } - } - - /** - * Mimics the behavior of a normal canvas paint, but with the canvas scaled to a predefined size. - * @param g Graphics object to draw on - * @param imageWidth width of the image - * @param imageHeight height of the image - * @param type extension of image - */ - public void drawScaledCanvas(Graphics g, int imageWidth, int imageHeight, String type) - { - //hide red ZMR center dot - AZMRInteraction.setPaintCenterDot(false); - - //anti-alias pictures by default - boolean aastatus = APreferencesControl.getAliasMenuItem(); - if(!aastatus) - APreferencesControl.setAliasMenuItem(true); - - // Calculate the scale factors. - double factorX = ((double)imageWidth) / (double)getWidth(); - double factorY = ((double)imageHeight) / (double)getHeight(); - - // Add the title bar, if required. - if (title != null && parameterStore.get("Prefs", "CanvasTitle").getStatus()) { - - //Get old dimensions - int titleWidth = title.getWidth(); - int titleHeight = title.getHeight(); - - if (AGlobals.isAtlantisHeadless()) { - Dimension d = title.getLayout().preferredLayoutSize(title); - titleWidth = (int)d.getWidth(); - titleHeight = (int)d.getHeight(); - } - - //Scale to image width (height is constant) and draw - title.setSize(imageWidth, titleHeight); - title.paint(g); - //restore old - title.setSize(titleWidth, titleHeight); - g.translate(0, titleHeight); - //Re-adjust y-scale for title height - factorY = ((double)(imageHeight-titleHeight))/(double)getHeight(); - } - - // Loop over all windows. - String[] windows = getCurrentLayout().getWindowNames(); - for (int i=0; i<windows.length; i++) - { - AWindow window = getWindow(windows[i]); - int x = window.getX(); - int y = window.getY(); - int width = window.getWidth(); - int height = window.getHeight(); - // If the window is visible resize it temporarily and then draw it. - if (isReallyOnScreen(window)){ - - g.translate((int)(factorX*x), (int)(factorY*y)); - - // Perhaps I should override window.setSize to automatically validate - // This is because AWindow is now a container with a view inside - // - Adam - window.setSize((int)(factorX*width), (int)(factorY*height)); - window.validate(); - - // Needed in headless mode because normally components don't - // do layout until they're really drawn - if (AGlobals.isAtlantisHeadless()) { - window.getLayout().layoutContainer(window); - window.invalidateQuietly(); - } - - //Now print the actual windows - window.print(g); - - // Show ATLAS logo only on the top left window if there's - // enough room and if the checkbox is selected - if(x == 0 && y == 0 && (imageWidth > 300 || imageHeight > 250) && - APreferencesControl.getAtlasLogoMenuItem()){ - g.drawImage(ACursorFactory.getInstance().getAtlasLogo(),32,4,null); - } - //reset old dimensions - window.setSize(width, height); - window.validate(); - g.translate(-(int)(factorX*x), -(int)(factorY*y)); - } - } - - // Overlay does not work in XMLRPC mode (no parentWindow) - if (this.parentWindow != null) { - //get the overlay, resize to our desired canvas size, draw it, then set it back to normal - AOverlay overlay = (AOverlay) this.parentWindow.getGlassPane(); - int width = overlay.getWidth(); - int height = overlay.getHeight(); - overlay.setSize(imageWidth, imageHeight); - overlay.paintComponent(g); - overlay.setSize(width, height); - } - - //do reset - AZMRInteraction.setPaintCenterDot(true); - if(!aastatus) - APreferencesControl.setAliasMenuItem(aastatus); - } - - - //Restore canvas defaults - public void restoreDefaults() { - //Current layout should never be null - if (currentLayout != null) { - if (!currentLayout.getName().equals(startupLayoutName)) { - setCurrentLayout(startupLayoutName); - } - String[] frontWindows = currentLayout.getStartupSequence(); - String[] windows = this.getKnownWindowNames(); - for (String window : windows) windowsList.get(window).restoreDefaults(); - for (String window : frontWindows) this.moveToFrontWindow(window); - setCurrentWindow(currentLayout.getStartupWindow()); - } else - throw new Error("Current layout is not defined"); - - // If an aspect ratio correction took place when we loaded this config - // make sure it is reapplied on a reset - AD - correctAspectRatios(); - } - - /* - * Return a string containing the list of currently visible windows - * that is then written to the config file by AConfigWriter - */ - public String getStartupString() { - StringBuilder s = new StringBuilder(); - //Loop over all windows in all layers - int maxLayer = baseLayer + currentLayout.getWindowNames().length; - for (int i = baseLayer; i <= maxLayer; i++) { - Component[] c = layeredPane.getComponentsInLayer(i); - for (int j = 0; j < c.length; j++) - if (c[j] instanceof AWindow) - if (isReallyOnScreen((AWindow) c[j])) - s.append(((AWindow) c[j]).getName()); - } - return s.toString(); - } - - /* - * Bring this window to the front, i.e. make it the topmost window - */ - public void moveToFrontWindow(String windowName) { - //Make sure the window exists - if (windowsList.containsKey(windowName)) { - //Get the window - AWindow w = windowsList.get(windowName); - //Get the current layer of the window - int layer = JLayeredPane.getLayer(w); - //Get the other components int the same layer - Component[] cc = layeredPane.getComponentsInLayer(layer); - //Check for the current uppermost window - int maxLayer = baseLayer + currentLayout.getWindowNames().length; - - //Now loop over all layers above the one the object is in - for (int i = layer + 1; i <= maxLayer; i++) { - //Get all components from this layers - Component[] c = layeredPane.getComponentsInLayer(i); - //Move them down one layer - for (int j = 0; j < c.length; j++) - layeredPane.setLayer(c[j], i - 1); - } - //Finaly move all component from the current layer to the top - for (int j = 0; j < cc.length; j++) - layeredPane.setLayer(cc[j], maxLayer); - //validate and repaint - this.validate(); - if (!w.isVisible()) { - w.setVisible(true); - } - hideNonVisible(); - w.repaintFromScratch(); - } else - throw new Error("Cannot find window: " + windowName); - } - - /* - * Return window by name - */ - public AWindow getWindow(String windowName) { - //Search for the window in the list an return it - if (windowsList.containsKey(windowName)) - return (AWindow) windowsList.get(windowName); - else - throw new Error("Cannot find window: " + windowName); - } - - /* - * Repaint all but the current window - * Used to update SynchroCursor in all windows. - */ - public void repaintOthers(Component current) { - //Fill all windows in an enumeration object - Enumeration<AWindow> myenum = windowsList.elements(); - - //Loop over windows - while (myenum.hasMoreElements()) { - AWindow window = (AWindow) myenum.nextElement(); - //repaint those that are visible - if ((window != current) && this.isReallyOnScreen(window)) - window.repaint(); - } - } - - private void hideNonVisible() { - for (AWindow window : windowsList.values()) { - if (this.isValidWindowName(window.getName())) { - if (!this.isReallyOnScreen(window)) { - if (window.isVisible()) { - window.setVisible(false); - } - } - } - } - } - - /* - * Repaint all windows from Scratch - */ - public void repaintAllFromScratch() { - Enumeration<AWindow> myenum = windowsList.elements(); - - hideNonVisible(); - - while (myenum.hasMoreElements()) { - AWindow window = (AWindow) myenum.nextElement(); - - if (this.isReallyOnScreen(window)) { - if (!window.isVisible()) { - window.setVisible(true); - } - window.repaintFromScratch(); - } - } - title.repaint(); - } - - /* - * Return a string will the names of all layouts - * to be shown in the layout dialog - */ - public String[] getLayoutNames() { - Enumeration<String> myenum = layouts.keys(); - String[] s = new String[layouts.size()]; - //Loop over all layouts and concatenate their names - for (int i = 0; i < s.length; i++) - s[i] = (String) myenum.nextElement(); - - return s; - } - - /* - * Get Layout by name - */ - public ALayout getLayout(String name) { - if (layouts.containsKey(name)) - return layouts.get(name); - else - throw new Error("getLayout, unknown: " + name); - } - - /* - * Return the current layout - */ - public ALayout getCurrentLayout() { - return currentLayout; - } - - /* - * Set the current layout and apply the changes right away - */ - public void setCurrentLayout(String newLayout) { - //Make sure the new layout exists - if (layouts.containsKey(newLayout)) { - - //get current layout and its dimension - currentLayout = layouts.get(newLayout); - Dimension dim = currentLayout.getSize(); - - // clear the frame - setLayout(null); - removeAll(); - layeredPane.removeAll(); - - //Toolkit is not aware of multi-screens, but "adds them all together". - // Dimension ScreenSize = Toolkit.getDefaultToolkit().getScreenSize(); - //getMaxWindowBounds gets max bounds, again added up over multiple screens. In contrast to the above, - //it will account for MenuBars, StatusBars, etc from the the WindowManager - // Rectangle ScreenSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); - //This is how to get the default screen, we should rather use the one we are on - // GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); - // GraphicsDevice gscreen = genv.getDefaultScreenDevice(); - // GraphicsConfiguration gconf = gscreen.getDefaultConfiguration(); - - //Final total Width, Height and position of the Canvas - int W, H, X, Y; - - //First get the screen size of the current screen - Rectangle ScreenSize = getScreenSize(); - - //This is not a real full screen mode, rather a maximised Window mode. - //In proper full screen, some window managers (such as Cacao) will allow - //to have the title bar/menues disappear, etc. - if(newLayout.equals("FULL SCREEN")) { - //Really take the full screen in this mode - W = ScreenSize.width; - H = ScreenSize.height; - X = ScreenSize.x; - Y = ScreenSize.y; - } else { - //if not full screen then have to take account of task bars - //First gets the insets (borders) from all sides - Insets borders = new Insets(0, 0, 0, 0); - if (!AGlobals.isAtlantisHeadless()) { - borders = Toolkit.getDefaultToolkit() - .getScreenInsets(parentWindow.getGraphicsConfiguration()); - } - //calculate new usable screen size - ScreenSize.width -= borders.left+borders.right; - ScreenSize.height -= borders.top+borders.bottom; - ScreenSize.x += borders.left; - ScreenSize.y += borders.top; - - W = (int) (ScreenSize.width * SCREEN_USAGE); - H = ScreenSize.height; - X = ScreenSize.x; - Y = ScreenSize.y; - } - - //Apply the new layout dimensions - layeredPane.setLayout(new AGridLayout(dim, null)); - - //Now check for the existing windows - String[] usedWindowNames = currentLayout.getWindowNames(); - - //Loop over windows and add them to the new layout - for (int i = 0; i < usedWindowNames.length; i++) { - //Get the window dimensions - Rectangle constraint = currentLayout.getWindowConstraints(usedWindowNames[i]); - //Get the window itself - AWindow window = windowsList.get(usedWindowNames[i]); - //Make sure its finalized - if (!window.finalized) { - window.finalizeConstruction(); - } - //Add window to a new layer with the given dimensions - layeredPane.setLayer(window, baseLayer + i); - layeredPane.add(window, constraint); - } - // adding the layeredPane to the frame - setLayout(new BorderLayout()); - add(layeredPane); - - if (parentWindow != null) { - //Set the new window dimensions and position - parentWindow.setLocation(X, Y); - parentWindow.setSize(W, H); - - //Validate and update - parentWindow.validate(); - parentWindow.repaint(); - - } else { - - // This is real voodoo to make the canvas lay itself out in the - // right way in headless mode - // It seems that because there's no repaint events things like - // layouts often don't work in the way you expect. I'm fully - // willing to believe I don't understand the best way to do this. - // This is rather a scattergun approach that seems to work... - // - Adam - - setSize(W, H); - layeredPane.setSize(W, H); - - Dimension d = layeredPane.getLayout().preferredLayoutSize(layeredPane); - - validate(); - repaint(); - - setSize(d); - layeredPane.setSize(d); - layeredPane.getLayout().layoutContainer(layeredPane); - } - - fireLayoutChange(); - - //Now apply window ordering - String[] ss = currentLayout.getStartupSequence(); - for (int i = 0; i < ss.length; i++) this.moveToFrontWindow(ss[i]); - - //Finally set the current window to the same it was before, if it exists - if ((currentWindow != null) && (currentLayout.hasWindow(currentWindow.getName()))) - setCurrentWindow(currentWindow.getName()); - else - setCurrentWindow(currentLayout.getStartupWindow()); - } else - throw new Error("setCurrentLayout: unknown layout name !?"); - } - - /* - * Inform everyone on the LayoutChangeListener list about the layout change - */ - private void fireLayoutChange() { - for (ALayoutChangeListener changeListener : layoutChangeListeners) { - changeListener.layoutChanged(getCanvas()); - } - } - - /* - * Store the current layout in the stack - * This is need for layout history, used by e.g. "Zoom/Unzoom LAr/Calorimeters" - */ - public void saveLayout() { - //Add the current layout and active window name - windowLayoutHistory.push(getCurrentLayout()); - windowNameHistory.push(currentWindow.getName()); - - //Also store all windows that are actually on screen - Vector<String> windowsOnScreen = new Vector<String>(); - String[] usedWindowNames = currentLayout.getWindowNames(); - for (String windowName : usedWindowNames) { - AWindow window = windowsList.get(windowName); - if(isReallyOnScreen(window)) { - windowsOnScreen.add(windowName); - } - } - windowsActive.push(windowsOnScreen); - } - - /* - * Revert to the previous layout in the layout history - */ - void unlayout() { - //Make sure there is a previous one - if(windowLayoutHistory.size() > 0) { - //Get the old layout and active window - ALayout newLayout=windowLayoutHistory.pop(); - String windowName=windowNameHistory.pop(); - //Only change layout if it has actually changed - if(!newLayout.getName().equals(currentLayout.getName())) { - //Set new layout and current window - setCurrentLayout(newLayout.getName()); - setCurrentWindow(windowName); - } - //now bring windows in the proper order - Vector<String> windowsOnScreen = windowsActive.pop(); - - for (String winName : windowsOnScreen) { - this.moveToFrontWindow(winName); - } - } - } - - /* - * Add objects that shall be informed if there is a change in the lock status - */ - public void addLockChangeListener(ChangeListener listener) { - lockChangeListeners.addElement(listener); - listener.stateChanged(new ChangeEvent(this)); - } - /* - * Add objects that shall be informed if there is a change in the layout - */ - public void addLayoutChangeListener(ALayoutChangeListener listener) { - layoutChangeListeners.addElement(listener); - listener.layoutChanged(getCanvas()); - } - - /* - * Add objects that shall be informed if there is a - * change in the current window - */ - public void addWindowChangeListener(ChangeListener listener) { - windowChangeListeners.addElement(listener); - listener.stateChanged(new ChangeEvent(this)); - } - - /* - * Check if the given window name exists in the list of windows - */ - public boolean isValidWindowName(String name) { - return windowsList.containsKey(name); - } - - /* - * Get a string with all the existing windows - */ - public String[] getKnownWindowNames() { - Set<String> windowNames = windowsList.keySet(); - return windowNames.toArray(new String[windowNames.size()]); - } - - /* - * Returns the name of the current window - */ - public String getCurrentWindowName() { - return currentWindow.getName(); - } - - /* - * Return the current window - */ - public AWindow getCurrentWindow() { - return currentWindow; - } - - /* - * Return the window we are currently painting in - */ - public AWindow getPaintingWindow() { - return paintingWindow; - } - - /* - * Notify everyone about a change in the active window - */ - private void fireWindowChange() { - ChangeEvent changeEvent = new ChangeEvent(this); - for (ChangeListener changeListener : windowChangeListeners) { - changeListener.stateChanged(changeEvent); - } - } - - /* - * Notify everyone about a change in the lock status - */ - void fireLockChange() { - ChangeEvent changeEvent = new ChangeEvent(this); - for (ChangeListener changeListener : lockChangeListeners) { - changeListener.stateChanged(changeEvent); - } - } - - /* - * Get number of windows - */ - public int getWindowsCount() { - return windowsList.size(); - } - - /** - * Sets the current window. Informs all registered listeners. - * - * @param newWindowName The name of the window to be set to current. - */ - public void setCurrentWindow(String newWindowName) { - //Make sure window does exist - if (windowsList.containsKey(newWindowName)) { - //Deselect the current window - if (currentWindow != null) currentWindow.deselect(); - //Get the new window - currentWindow = (AWindow) windowsList.get(newWindowName); - //Select it - currentWindow.select(); - //Inform APar class about the new current window - parameterStore.setCurrentWindowIndex(currentWindow.getIndex()); - //Move the current window on top of all others - moveToFrontWindow(currentWindow.getName()); - //Inform everyone about the change - fireWindowChange(); - } else - throw new Error("setCurrentWindow, window: " + newWindowName + " , doesn't exist !?"); - } - - /** - * Sets the currently window currently being painted - * - * @param window the window being painted - */ - public void setPaintingWindow(AWindow window) { - paintingWindow = window; - } - - /** - * Copy settings from one window to another window - * - * @param from the window to copy settings from - * @param to the window to copy settings to - */ - public void copyWindowSettings(String from, String to) { - AWindow fromW = getWindow(from); - AWindow toW = getWindow(to); - - parameterStore.copyParameters(from, to); - - // IMPORTANT! Do not change the order - // setCurrentWindow() should be always before setProjection() - setCurrentWindow(to); - - // copy the projection, group and scales - toW.setProjection(fromW.getProjection()); - toW.setGroup(fromW.getGroupName()); - toW.setScaleStatus(fromW.getScaleStatus()); - - // copy the interaction (no interactions valid for EventInfo projection) - if(!(fromW.getProjection() instanceof AProjectionEventInfo)) - { - AInteractionToolBar fromI = fromW.getInteractionToolBar(); - AInteractionToolBar toI = toW.getInteractionToolBar(); - - toI.setSelectedGroup(fromI.getSelectedGroupName()); - // copy the state of the panel - toI.getSelectedGroup().setGroupState(fromI.getSelectedGroup()); - } - // for LegoPlot windows we need to set the (x,y,z)-corners from the projection - // TODO: Check and understand this. Previously there was no check that toW was - // an instance of AProjectionLegoPlot, put perhaps this works because only - // ever copy settings from one projection to another of the same type? - if(fromW.getProjection() instanceof AProjectionLegoPlot - && toW.getProjection() instanceof AProjectionLegoPlot) { - AProjectionLegoPlot.setxz(toW.getIndex(), AProjectionLegoPlot.getxz(fromW.getIndex())); - AProjectionLegoPlot.setyz(toW.getIndex(), AProjectionLegoPlot.getyz(fromW.getIndex())); - //reset the center of detector dot on ZMR - toW.getInteractionManager().setContext(toW.getInteractionToolBar().getSelectedGroup()); - } - //copy the user corners - toW.setUserCorners(fromW.getUserCorners()); - } - - /** - * As each window has its own layer, find the window that is in this window - * - * @param layer the layer which the window is in - */ - private AWindow getWindowForLayer(int layer) { - //Get all the components in this layer - Component[] c = layeredPane.getComponentsInLayer(layer); - //Return the first instance of AWindow - for (int i = 0; i < c.length; i++) - if (c[i] instanceof AWindow) return (AWindow) c[i]; - //Otherwise return 0 - return null; - } - - /** - * Get the associated tile menu bar - */ - public ATitleMenuBar getATitle() { - return title; - } - - /** - * Get the top-most window at a certain point - * - * @param x x-coordinate in pixels - * @param y y-coordinate in pixels - */ - private AWindow getWindowForPoint(double x, double y) { - //Loop over all layers - int maxLayer = baseLayer + currentLayout.getWindowNames().length; - for (int lay = maxLayer; lay >= 0; lay--) { - //Get the window that is in this layer - AWindow w = getWindowForLayer(lay); - if (w == null || currentLayout == null) { - continue; - } - //Get the window rectangle - Rectangle r = currentLayout.getWindowConstraints(w.getName()); - //Check if x,y is inside the rectangle - if (r.contains(x, y)) - return w; - } - - return null; - } - - /** - * Check if a given window is partially visible - * - * @param window the window to check - */ - public boolean isReallyOnScreen(AWindow window) { - //The full area covered by the canvas - Dimension layoutSize = currentLayout.getSize(); - - //Run over every single point on the canvas - //until we hit one that belongs to the window -- aaaaaarrrrggghhh!!! (SB?) - - //This function almost always exits on the first pixel - //Profiling indicates it takes only a few miliseconds - //even in very rare worst cases - AD - for (int j = 0; j < layoutSize.height; j++) - for (int i = 0; i < layoutSize.width; i++) - if (getWindowForPoint(i + 0.5, j + 0.5).equals(window)) - return true; - - return false; - } - - /** - * Implementation of the new event listener: gets called for each new event - * and repaints all the windows. - * - * @param evt the new event - */ - @Override - public void newEvent(AEvent evt) { - repaintAllFromScratch(); - } - - /** Return the aspect ratio of the canvas drawing area (hopefully) as h/w. - * Sorry if this is usually defined as w/h? - AD */ - public double getAspectRatio() { - Dimension d = layeredPane.getSize(); - return d.getHeight() / d.getWidth(); - } - - /** - * Calculates the image height that will result if one resizes the current canvas to the given width. - * @param width target width - * @return corresponding height - */ - public int getRespectiveHeight(int width){ - - //Get rootpane dimensions - int canvasWidth = getWidth(); - int canvasHeight = getHeight(); - - //calculate factor - double factor = ((double)width) / canvasWidth; - - //Account for menu bar if its there - if (title != null && parameterStore.get("Prefs", "CanvasTitle").getStatus()) { - //if (getTitleBar() != null && getTitleBar().isVisible()){ - int height = title.getHeight(); - - if (AGlobals.isAtlantisHeadless()) { - // In headless mode the menu bar isn't really enabled - // So get the size it would be if it was - height = (int) (title.getLayout().preferredLayoutSize(title).getHeight()); - } - - return (int) (factor * canvasHeight) + height; - - } - - //Otherwise just scale - return (int)(factor*canvasHeight); - } - -} //ACanvas diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ADrawCalorimeterSummedEndcaps.java b/graphics/AtlantisJava/src/atlantis/canvas/ADrawCalorimeterSummedEndcaps.java deleted file mode 100755 index c7b6a307a49..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ADrawCalorimeterSummedEndcaps.java +++ /dev/null @@ -1,937 +0,0 @@ -package atlantis.canvas; - -import java.awt.Color; - -import atlantis.data.ACalorimeterData; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.utils.AMath; -import atlantis.utils.APolygon; - -/** - * Contains the function for drawing the summed LAr and HEC endcaps - * - * @author Mark Stockton - */ -public class ADrawCalorimeterSummedEndcaps -{ - static int minEtaIndex,minPhiIndex,maxEtaIndex,maxPhiIndex,numCombinedCells,binvalue=1,SmallestEtaBinNumber,LargestEtaBinNumber; - static double etaBin, phiBin, SmallestZMin,maxCellEnergy,minCellEnergy; - static String name; - - protected static APar parameterStore = APar.instance(); - - /** - * Draws the summed endcaps. This method is called - * from drawCalorimeters and should not be used directly. - * - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - * @param calorimeter ACalorimeterData current calorimeter - * @param etaIndex short[] index of eta values - * @param phiIndex short[] index of phi values - * @param side byte[] side of detector - */ - public static void drawCalorimeterSummedEndcaps(AWindow window, AGraphics ag, AProjection2D projection, ACalorimeterData calorimeter, short[] etaIndex, short[] phiIndex, byte[] side) - { - resetGlobalValues(calorimeter.getName()); - ACoord data; - double[][] EndcapBinnedEnergy = new double[(36/binvalue)][(64/binvalue)]; - calorimeter.makeDrawList(); - //loop over drawlist to find z of first plane and smallest and largest eta - setSmallestAndLargest(calorimeter); - //now loop over drawlist to draw - for (int k = 0; k < calorimeter.getNumDraw(); k++) - { - int j = calorimeter.getDrawIndex(k); - short detectorIndex = (short) ACalorimeterDetector.getDetectorIndex(calorimeter.getIdFromIndex(j)); - ACalorimeterDetector currentDetector=ACalorimeterDetector.get(detectorIndex); - if (detectorIndex >= 0) - { - ACoord coord = currentDetector.getCell(projection, etaIndex[j], phiIndex[j], side[j]); - if (coord.hv[0].length > 0) - { - //has a cell so get its energy - double cellEnergy=calorimeter.getEnergy(j); - //find the eta min and max of each cell - double[] etaminmax=findEtaMinAndMax(currentDetector,etaIndex[j],side[j]); - //test to see if the cell overlaps the eta border - if(etaminmax[2]==1) - { - //Only want cells upto the eta split - double middle=parameterStore.get("YX", "SplitEta").getD()-(0.5*etaBin); - //find the min and max of each cell - double[] minmax1=findMinAndMax(currentDetector,etaminmax[0],middle,phiIndex[j]); - //has to find out how many cells overlap new binning border - int totNumOfCells1 =findNumberOfCells(minmax1); - //Only want cells above the eta split - middle=parameterStore.get("YX", "SplitEta").getD()+(0.5*etaBin); - //find the min and max of each cell - double[] minmax2=findMinAndMax(currentDetector,middle,etaminmax[1],phiIndex[j]); - //has to find out how many cells overlap new binning border - int totNumOfCells2 =findNumberOfCells(minmax1); - //check found positive number of cells - int NumOfCellsTotal=0; - if(totNumOfCells1>0) - NumOfCellsTotal+=totNumOfCells1; - else - System.out.println("Found negative amount of cells!?!"); - if(totNumOfCells2>0) - NumOfCellsTotal+=totNumOfCells2; - else - System.out.println("Found negative amount of cells!?!"); - if(NumOfCellsTotal>0) - { - //split energy between the cells - cellEnergy/=NumOfCellsTotal; - //now add on energy - if(totNumOfCells1>0) - { - EndcapBinnedEnergy=AddOnToEnergy(EndcapBinnedEnergy, cellEnergy, minmax1); - } - if(totNumOfCells2>0) - { - EndcapBinnedEnergy=AddOnToEnergy(EndcapBinnedEnergy, cellEnergy, minmax2); - } - } - } - else - { - //find the min and max of each cell - double[] minmax=findMinAndMax(currentDetector,etaminmax[0],etaminmax[1],phiIndex[j]); - //has to find out how many cells overlap new binning border - int totNumOfCells =findNumberOfCells(minmax); - //if found cells - if(totNumOfCells>0) - { - //split energy between the cells - cellEnergy/=totNumOfCells; - //not overlapping eta split so just add on energy - EndcapBinnedEnergy=AddOnToEnergy(EndcapBinnedEnergy, cellEnergy, minmax); - } - else - System.out.println("Found negative amount of cells!?!"); - } - } - } - } - //if no cells then don't need to draw - if(numCombinedCells==0) - return; - //now need to order energy into a list aswell as get the geometry of cells with energy - double[] EndcapBinnedEnergyList; - double[] YXBinnedEnergyList=new double[numCombinedCells];//needed as could be FR projection - double[][][] YXhv=new double[2][numCombinedCells][0]; - int currentCount=0; - for(int a=minEtaIndex; a<=maxEtaIndex;a++) - { - for(int b=minPhiIndex; b<=maxPhiIndex;b++) - { - if(EndcapBinnedEnergy[a][b]>0.0) - { - //has an energy so store its cell coordinates - ACoord coord = calculateCellGeometry(a,b); - YXhv[0][currentCount]=coord.hv[0][0]; - YXhv[1][currentCount]=coord.hv[1][0]; - //sorts energy into a list less blank cells - YXBinnedEnergyList[currentCount]=EndcapBinnedEnergy[a][b]; - currentCount++; - //check if is largest/smallest cell energy - if(EndcapBinnedEnergy[a][b]>maxCellEnergy) - maxCellEnergy=EndcapBinnedEnergy[a][b]; - if(EndcapBinnedEnergy[a][b]<minCellEnergy) - minCellEnergy=EndcapBinnedEnergy[a][b]; - } - } - } - //store coords and scale for display - ACoord YXData = new ACoord(YXhv); - //now need to alter to FR projection if needed otherwise will continue with temp - if(projection instanceof AProjectionFR) - { - //convert data to FR and add data to loop in phi - data=convertToFR(YXData, window); - //now need to loop the energies - EndcapBinnedEnergyList=new double[3*numCombinedCells]; - for(int j=0; j<numCombinedCells;j++) - { - EndcapBinnedEnergyList[j]=YXBinnedEnergyList[j]; - EndcapBinnedEnergyList[j+numCombinedCells]=YXBinnedEnergyList[j]; - EndcapBinnedEnergyList[j+(2*numCombinedCells)]=YXBinnedEnergyList[j]; - } - numCombinedCells*=3;//now have 3 lots of cells - } - else - { - //If not FR then the YX values are correct - EndcapBinnedEnergyList=YXBinnedEnergyList; - data=YXData; - } - data = window.calculateDisplay(projection.nonLinearTransform(data)); - // Draw the cell frames - boolean drawCells = parameterStore.get( name, "Cells").getStatus(); - if (drawCells) - drawCells(window, ag, data, EndcapBinnedEnergyList); - // Draw the histograms. - ACalorimeterData.drawEndcapHistogram(calorimeter, window, ag, projection); - } - - /** - * Resets gobal values - * @param CalName name of calorimeter - */ - protected static void resetGlobalValues(String CalName) - { - name=CalName; - minEtaIndex=999; - minPhiIndex=999; - maxEtaIndex=0; - maxPhiIndex=0; - numCombinedCells=0; - SmallestZMin = 99999.0; - SmallestEtaBinNumber = 99999; - LargestEtaBinNumber = 0; - maxCellEnergy=0.0; - minCellEnergy = 99999.0; - //check if using 0.1 binning or 0.2 binning - if(name.equals("HEC")) - binvalue = parameterStore.get("YX", "HECBin").getI(); - else - binvalue = parameterStore.get("YX", "LArBin").getI(); - if(binvalue==3) - { - etaBin=0.1; - phiBin=(2*Math.PI/64); - binvalue=1; - } - else - { - etaBin=0.1*binvalue; - phiBin=(2*Math.PI/64)*binvalue;//(2*Math.PI/64)=0.098 - } - } - - /** - * Set the smallest Z, smallest and largest eta - * - * @param calorimeter ACalorimeterData current calorimeter - */ - protected static void setSmallestAndLargest(ACalorimeterData calorimeter) - { - double largestRho=0.0,smallestRho=99999.0; - double largestEtaValue=0.0,smallestEtaValue=99999.0; - //to shorten detectors to loop over - short prevDetectorIndex=999; - //loop over drawlist - for (int k = 0; k < calorimeter.getNumDraw(); k++) - { - int j = calorimeter.getDrawIndex(k); - short detectorIndex = (short) ACalorimeterDetector.getDetectorIndex(calorimeter.getIdFromIndex(j)); - ACalorimeterDetector currentDetector=ACalorimeterDetector.get(detectorIndex); - String detectorName=currentDetector.getName(); - if (detectorIndex!=prevDetectorIndex && detectorIndex >= 0 - && (detectorName.indexOf("Endcap")>0 || detectorName.indexOf("EC")>=0 || detectorName.equals("HEC"))) - { - //in a different detector - prevDetectorIndex=detectorIndex; - //find z of the first plane - if(currentDetector.getZMin()<SmallestZMin) - { - SmallestZMin=currentDetector.getZMin(); - } - //find smallest rho - if(currentDetector.getRMin()<smallestRho) - { - smallestRho=currentDetector.getRMin(); - largestEtaValue=AMath.etaAbs(currentDetector.getZMin(), smallestRho); - } - //find largest rho - if(currentDetector.getRMax()>largestRho) - { - largestRho=currentDetector.getRMax(); - smallestEtaValue=AMath.etaAbs(currentDetector.getZMin(), largestRho); - } - } - } - //if drawing cell outlines then this will have already been done - if (splitBinning() && !parameterStore.getUnknown("Det", "CaloDetail").getStatus()) - ACalorimeterDetector.setEtaSplit(); - //if using split binning and eta is in inner section - if(splitBinning() && smallestEtaValue>=parameterStore.get("YX", "SplitEta").getD()) - { - double belowSplit=parameterStore.get("YX", "SplitEta").getD()/0.1; - double aboveSplit=(smallestEtaValue-parameterStore.get("YX", "SplitEta").getD())/0.2; - SmallestEtaBinNumber=(int)Math.floor(belowSplit+aboveSplit); - } - else - { - SmallestEtaBinNumber=(int)Math.floor(smallestEtaValue/etaBin); - } - if(splitBinning() && largestEtaValue>=parameterStore.get("YX", "SplitEta").getD()) - { - double belowSplit=parameterStore.get("YX", "SplitEta").getD()/0.1; - double aboveSplit=(largestEtaValue-parameterStore.get("YX", "SplitEta").getD())/0.2; - LargestEtaBinNumber=(int)Math.floor(belowSplit+aboveSplit); - } - else - { - LargestEtaBinNumber=(int)Math.floor(largestEtaValue/etaBin); - } - } - - /** - * Test to see if using split binning - * - * @return Status of if using split binning - */ - protected static boolean splitBinning() - { - int test=0; - if(name.equals("HEC")) - test = parameterStore.get("YX", "HECBin").getI(); - else - test = parameterStore.get("YX", "LArBin").getI(); - if(test==3) - return true; - else - return false; - } - - /** - * Finds the max and min values of the hit cell - * Also tests and sets the min and max indicies for eta and phi - * - * @param currentDetector ACalorimeterDetector current detector - * @param etaIndex short index of eta values - * @param side byte side of detector - * - * @return minAndMax[0] double minEta of cell - * @return minAndMax[1] double maxEta of cell - * @return minAndMax[2] double status of if is an overlapping cell - */ - protected static double[] findEtaMinAndMax(ACalorimeterDetector currentDetector, short etaIndex, byte side) - { - double realEtaBin=etaBin; - //if using split binning and eta is in outer section - if(splitBinning() && Math.abs(currentDetector.getEtaMin(etaIndex, side))>=parameterStore.get("YX", "SplitEta").getD()) - { - realEtaBin=0.2; - } - //used for x when taking arsinh(x)=ln(x+sqrt(x*x+1)) - double asinhOf; - //have to alter eta so can be drawn at the front layer - double zFactor = SmallestZMin/currentDetector.getZMin(); - //do for minimum of cell - double calcEtaMin=Math.abs(currentDetector.getEtaMin(etaIndex, side)); - asinhOf = zFactor*Math.sinh(calcEtaMin); - calcEtaMin = Math.log(asinhOf + Math.sqrt(asinhOf*asinhOf+1)); - //do for center of cell - double calcEta=Math.abs(currentDetector.getEta(etaIndex, side)); - asinhOf = zFactor*Math.sinh(calcEta); - calcEta= Math.log(asinhOf + Math.sqrt(asinhOf*asinhOf+1)); - //find cell size in eta and phi - double deta=currentDetector.getDeltaEta(); - double minEta,maxEta; - //check for overlaping cells in eta and phi - if(deta>realEtaBin) - { - minEta=calcEtaMin; - maxEta=minEta+deta; - } - else - { - minEta=calcEta; - maxEta=minEta;//there is only 1 cell - } - - //make minEta in detector otherwise causes problems if SplitEta=SmallestEtaBinNumber*0.1 - if(minEta<SmallestEtaBinNumber*0.1) - { - minEta=SmallestEtaBinNumber*0.1; - } - - //now store in variable to return - double[] minAndMax=new double[3]; - minAndMax[0]= minEta; - minAndMax[1]= maxEta; - - if(splitBinning()) - { - if(minEta<parameterStore.get("YX", "SplitEta").getD() && - maxEta>parameterStore.get("YX", "SplitEta").getD()) - { - minAndMax[2]=1;//overlapping cell - } - else - minAndMax[2]=0; - } - else - minAndMax[2]=0; - return minAndMax; - } - - /** - * Finds the max and min values of the hit cell - * Also tests and sets the min and max indicies for eta and phi - * - * @param currentDetector ACalorimeterDetector current detector - * @param minEta double min eta of cell to draw - * @param maxEta double max eta of cell to draw - * @param phiIndex short index of phi values - * - * @return minAndMax[0] double minEta of cell - * @return minAndMax[1] double maxEta of cell - * @return minAndMax[2] double minPhi of cell - * @return minAndMax[3] double maxPhi of cell - */ - protected static double[] findMinAndMax(ACalorimeterDetector currentDetector, double minEta, double maxEta, short phiIndex) - { - double realEtaBin=etaBin, realPhiBin=phiBin; - //if using split binning - if(splitBinning()) - { - //if eta is in inner section - if(minEta>=parameterStore.get("YX", "SplitEta").getD()) - { - realEtaBin=0.2; - realPhiBin=(2*Math.PI/32); - } - } - //find cell size in eta and phi - double deta=currentDetector.getDeltaEta(); - double dphi=currentDetector.getDeltaPhi(); - double minPhi,maxPhi; - //check for overlaping cells in eta and phi - if(deta>realEtaBin) - { - if(realEtaBin==etaBin) - { - minEta=Math.floor(minEta/realEtaBin); - maxEta=Math.floor(maxEta/realEtaBin); - } - else - { - //inside split binning - double belowSplit=parameterStore.get("YX", "SplitEta").getD()/0.1; - double aboveSplit=(minEta-parameterStore.get("YX", "SplitEta").getD())/0.2; - minEta=Math.floor(belowSplit+aboveSplit); - aboveSplit=(maxEta-parameterStore.get("YX", "SplitEta").getD())/0.2; - maxEta=Math.floor(belowSplit+aboveSplit); - } - } - else - { - if(realEtaBin==etaBin) - { - minEta=Math.floor(minEta/realEtaBin); - } - else - { - //split binning - double belowSplit=parameterStore.get("YX", "SplitEta").getD()/0.1; - double aboveSplit=(minEta-parameterStore.get("YX", "SplitEta").getD())/0.2; - minEta=Math.floor(belowSplit+aboveSplit); - } - maxEta=minEta;//there is only 1 cell - } - if(dphi>realPhiBin) - { - minPhi=Math.abs(currentDetector.getPhiMin(phiIndex)); - minPhi=Math.floor(minPhi/realPhiBin); - maxPhi=Math.floor(minPhi+(dphi/realPhiBin)); - } - else - { - minPhi=Math.abs(currentDetector.getPhi(phiIndex)); - minPhi=Math.floor(minPhi/realPhiBin); - maxPhi=minPhi;//there is only 1 cell - } - //check for exceeding array limits - if(maxPhi>=(64/binvalue)) - { - maxPhi=(64/binvalue)-1; - if(minPhi>=(64/binvalue)-1) - minPhi=(64/binvalue)-1; - } - if(minPhi<0) - { - minPhi=0; - if(maxPhi<0) - maxPhi=0; - } - //check not out of eta array size range - if(maxEta>=(36/binvalue)) - { - maxEta=(36/binvalue)-1; - if(minEta>=(36/binvalue)) - minEta=(36/binvalue)-1; - } - //check physical eta conditions - if(maxEta>LargestEtaBinNumber) - { - maxEta=LargestEtaBinNumber; - if(minEta>LargestEtaBinNumber) - minEta=LargestEtaBinNumber; - } - if(minEta<SmallestEtaBinNumber) - { - minEta=SmallestEtaBinNumber; - if(maxEta<SmallestEtaBinNumber) - maxEta=SmallestEtaBinNumber; - } - //find min and max eta and phi indices - if(minEta<minEtaIndex) - minEtaIndex=(int)minEta; - if(maxEta>maxEtaIndex) - maxEtaIndex=(int)maxEta; - if(minPhi<minPhiIndex) - minPhiIndex=(int)minPhi; - if(maxPhi>maxPhiIndex) - maxPhiIndex=(int)maxPhi; - //now store in variable to return - double[] minAndMax=new double[4]; - minAndMax[0]= minEta; - minAndMax[1]= maxEta; - minAndMax[2]= minPhi; - minAndMax[3]= maxPhi; - return minAndMax; - } - - /** - * Finds the number of cells in the new binning - * - * @param minmax array containing: minEta, maxEta, minPhi, maxPhi - */ - protected static int findNumberOfCells(double[] minmax) - { - int numOfEtaCells=0; - int numOfPhiCells=0; - double minEta=minmax[0]; - double maxEta=minmax[1]; - double minPhi=minmax[2]; - double maxPhi=minmax[3]; - //calculate the number of cells - //add one as difference in index is 1 less than number of cells - numOfEtaCells+=maxEta-minEta+1; - numOfPhiCells+=maxPhi-minPhi+1; - //get total number of cells - int totNumOfCells = numOfEtaCells*numOfPhiCells; - return totNumOfCells; - } - - /** - * Adds on the energy to EndcapBinnedEnergy and then returns it - * - * @param EndcapBinnedEnergy double[][] energy listing of cells [eta][phi] - * @param cellEnergy double energy of each new cell - * @param minmax double[] min and max of cell in eta and phi - * - * @return EndcapBinnedEnergy double[][] altered energy listing of cells [eta][phi] - */ - protected static double[][] AddOnToEnergy(double[][] EndcapBinnedEnergy, double cellEnergy, double[] minmax) - { - //now loop over the min to max for eta and phi - for(int a= (int) minmax[0]; a<=(int) minmax[1]; a++) - { - for(int b=(int) minmax[2]; b<=(int) minmax[3]; b++) - { - //add to cell count if no energy already stored in cell - if(EndcapBinnedEnergy[a][b]==0.0) - numCombinedCells++; - //add energy to cell - EndcapBinnedEnergy[a][b]+= cellEnergy; - } - } - return EndcapBinnedEnergy; - } - - /** - * Calculates the cell geometry from its eta and phi bin numbers - * - * @param a int eta bin number - * @param b int phi bin number - * - * @return coord Acoord cell coords - */ - protected static ACoord calculateCellGeometry(int a, int b) - { - double realEtaBin=etaBin, realPhiBin=phiBin; - double eta=a*etaBin; - double phi=b*phiBin; - //if using split binning and eta is in inner section - if(splitBinning() && eta>=parameterStore.get("YX", "SplitEta").getD()) - { - realEtaBin=0.2; - realPhiBin=(2*Math.PI/32); - double belowSplit=parameterStore.get("YX", "SplitEta").getD()/0.1; - double aboveSplit=a-belowSplit; - eta=aboveSplit*0.2+belowSplit*0.1; - phi=b*realPhiBin; - } - double[][] temphv = new double[2][]; - - //all drawn on the front plane of the detector - double newrMax=SmallestZMin/Math.sinh(eta); - double newrMin=SmallestZMin/Math.sinh(eta+realEtaBin); - //store the cell coords - temphv[0] = new double[] {newrMax*Math.cos(phi), newrMax*Math.cos(phi+realPhiBin), - newrMin*Math.cos(phi+realPhiBin), newrMin*Math.cos(phi)}; - temphv[1] = new double[] {newrMax*Math.sin(phi), newrMax*Math.sin(phi+realPhiBin), - newrMin*Math.sin(phi+realPhiBin), newrMin*Math.sin(phi)}; - return new ACoord(temphv); - } - - /** - * Converts cells to FR using normal convertYXtoFR - * Then adds on data above and below so loops in phi - * - * @param YXData ACoord data in YX projection - * @param window AWindow current window - * - * @return coord Acoord cell coords - */ - protected static ACoord convertToFR(ACoord YXData, AWindow window) - { - //convert to FR then have to loop data - YXData.convertYXToFR(); - //new hv to store the values at + and - 2pi - double[][][] FRhv=new double[2][3*numCombinedCells][YXData.hv[0][0].length]; - //get corners and then shift data to be inside corners - double phiTop = window.getUserCorners()[0].y; - double phiBottom = window.getUserCorners()[2].y; - int factor=0; - if(phiTop>720.0) - //-2 as already draws upto 720 so doensn't need this extra 2*360 - factor=(int) Math.ceil(phiTop/360.0)-2; - if(phiBottom<-360.0) - //-1 as already draws down to -360 so doensn't need this extra -1*360 - factor=(int) Math.floor(phiBottom/360.0)-1; - for(int j=0; j<numCombinedCells;j++) - for(int k=0; k<YXData.hv[0][j].length; k++) - { - FRhv[1][j][k]=YXData.hv[1][j][k]+360.0*(factor-1); - FRhv[1][numCombinedCells+j][k]=YXData.hv[1][j][k]+360.0*factor; - FRhv[1][(2*numCombinedCells)+j][k]=YXData.hv[1][j][k]+360.0*(factor+1); - FRhv[0][j][k]=YXData.hv[0][j][k]; - FRhv[0][numCombinedCells+j][k]=YXData.hv[0][j][k]; - FRhv[0][(2*numCombinedCells)+j][k]=YXData.hv[0][j][k]; - } - //now store into data to be used to draw - return new ACoord(FRhv); - } - - /** - * Draws the cells - * - * @param ag AGraphics graphics to draw on - * @param data ACoord cell geometries - * @param EndcapBinnedEnergyList double[] energy of each cell - */ - protected static void drawCells(AWindow window, AGraphics ag, ACoord data, double[] EndcapBinnedEnergyList) - { - //Storage of parameters to be used later - Color[] colorMap = AColorMap.getColors(); - //AParameter frame = parameterStore.get(name, "Frame"); - boolean drawFrame = parameterStore.get(name, "Frame").getStatus(); - int frameColor = parameterStore.get(name, "Frame").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - drawFrame=true; - else - drawFrame=false; - AParameter cellGeometry = parameterStore.get(name, "CellGeometry"); - // Draw frames for the filled cells. - if (drawFrame && cellGeometry.getStatus()) - { - for (int j = 0; j < numCombinedCells; j++) - { - ag.setColor(colorMap[frameColor]); - ag.drawPolygon(data.hv[0][j], data.hv[1][j], data.hv[0][j].length); - } - } - // Draw the cell geometry. - AParameter cellOutline = parameterStore.get(name, "CellOutline"); - // Draw filled cells. - if (cellGeometry.getStatus()) - { - for (int j = 0; j < numCombinedCells; j++) - { - ag.setColor(colorMap[cellGeometry.getI()]); - ag.fillPolygon(data.hv[0][j], data.hv[1][j], data.hv[0][j].length); - } - } - // Draw cell outlines. - if (cellOutline.getStatus()) - { - ag.updateDrawParameters(new ADrawParameters(true, cellOutline.getI(), 0, 1, 0, 0, false, 1, 0)); - for (int j = 0; j < numCombinedCells; ++j) - { - ag.drawPolygon(data.hv[0][j], data.hv[1][j], data.hv[0][j].length); - } - } - //Scale the cell polygons. - data = scaleEndcapPolygons(EndcapBinnedEnergyList, data, minCellEnergy, maxCellEnergy); - //Get the colours of the cells - byte[] EndcapColor= internalEndcapColor(EndcapBinnedEnergyList, minCellEnergy, maxCellEnergy); - // And draw them. - AParameter colorFunction = parameterStore.get(name, "ColorFunction"); - if (colorFunction.getI() == ACalorimeterData.COLOR_FUNC_ENERGY) - { - switch (AColorMap.getColorMap()) - { - case AColorMap.COLOR_MAP_DEFAULT1: - case AColorMap.COLOR_MAP_DEFAULT2: - case AColorMap.COLOR_MAP_M4M5: - case AColorMap.COLOR_MAP_GRAYDET: - case AColorMap.COLOR_MAP_ORIGINAL: - // Use colors. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_HITCOL); - break; - case AColorMap.COLOR_MAP_GRAY: - case AColorMap.COLOR_MAP_BW: - // Use grayscale. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_GRAY_HITCOL); - break; - } - //draw the legend - if(ALegendWindow.exists()) - { - if (AColorMap.getColorMap() != AColorMap.COLOR_MAP_BW) - { - double[] colorEnergy = energyOfEndcapColor(minCellEnergy,maxCellEnergy); - ALegendWindow.getInstance().addEnergyText(window, colorEnergy,maxCellEnergy, colorMap); - } - else - ALegendWindow.getInstance().addEnergyText(window, minCellEnergy,maxCellEnergy); - } - } - else if(ALegendWindow.exists()) - ALegendWindow.getInstance().clearText(window); - //draw filled cell - for (int j = 0; j < numCombinedCells; j++) - { - ag.setColor(colorMap[EndcapColor[j]]); - ag.fillPolygon(data.hv[0][j],data.hv[1][j], data.hv[0][j].length); - } - //draw frame around cell - if (drawFrame && !cellGeometry.getStatus()) - { - for (int j = 0; j < numCombinedCells; j++) - { - ag.setColor(colorMap[frameColor]); - ag.drawPolygon(data.hv[0][j], data.hv[1][j], data.hv[0][j].length); - } - } - } - - /** - * Scales a series of polygons according to the user settings. - * Used for summing over layer in the Endcaps in the YX projection - * - * @param cellEnergy double[] list of each cells energy - * @param coord ACoord polygons to be scaled - * @param minEnergy double min Energy in a cell - * @param maxEnergy double max Energy in a cell - * - * @return ACoord scaled polygons - */ - protected static ACoord scaleEndcapPolygons(double[] cellEnergy, ACoord coord, double minEnergy, double maxEnergy) - { - int energyMode = parameterStore.get(name, "EnergyMode").getI(); - - for (int i = 0; i < cellEnergy.length; i++) - { - if (cellEnergy[i] == 0) - continue; - - double factor; - if (parameterStore.get(name, "ColorFunction").getI() != ACalorimeterData.COLOR_FUNC_ENERGY) - { - // The user has (implicitly) selected energy scaling. - - //each cell is scaled to the new 0.1*0.1 binning so - //density for each just depends on energy - double density = cellEnergy[i]; - double minDensity = minEnergy; - double maxDensity = maxEnergy; - - switch (energyMode) - { - case ACalorimeterData.ENERGY_MODE_MAX_LIN: - case ACalorimeterData.ENERGY_MODE_SUM_LIN: - factor = Math.sqrt(density / maxDensity); - break; - - case ACalorimeterData.ENERGY_MODE_MAX_LOG: - case ACalorimeterData.ENERGY_MODE_SUM_LOG: - double magnitude = Math.floor(Math.log10(Math.sqrt(maxDensity / minDensity)) + 1.0); - factor = (Math.log10(Math.sqrt(density / maxDensity)) + magnitude) / magnitude; - break; - - case ACalorimeterData.ENERGY_MODE_MAX_SQRT: - case ACalorimeterData.ENERGY_MODE_SUM_SQRT: - factor = Math.sqrt(Math.sqrt(density / maxDensity)); - break; - - default: - factor = ACalorimeterData.getNonScalingFactor(); - } - } - else - { - // No energy scaling, scale all cells by the same factor. - factor = ACalorimeterData.getNonScalingFactor(); - } - - if (factor <= 1.0) - { - APolygon.scale(coord.hv[0][i], coord.hv[1][i], factor); - } - } - return coord; - } - - /** - * Determines the color for each hit according to the color function set by - * the user. Used for summing over layer in the Endcaps in the YX projection - * - * @param cellEnergy double[] list of each cells energy - * @param minEnergy double min Energy in a cell - * @param maxEnergy double max Energy in a cell - * - * @return byte[] colors for each energy - */ - protected static byte[] internalEndcapColor(double[] cellEnergy, double minEnergy, double maxEnergy) - { - byte[] EndcapColor= new byte[cellEnergy.length]; - - int colorFunction = parameterStore.get(name, "ColorFunction").getI(); - int constantColor = parameterStore.get(name, "Constant").getI(); - switch (colorFunction) - { - case ACalorimeterData.COLOR_FUNC_CONSTANT: - //colorByConstant(); - for(int i = 0; i < cellEnergy.length; i++) - EndcapColor[i] = (byte) constantColor; - break; -/* case COLOR_FUNC_SUBDET: - colorBy(sub); - break; - - case COLOR_FUNC_CLUSTER: - colorBy(getClusters()); - break; - - case COLOR_FUNC_SAMPLING: - colorBy(sampling); - break; -*/ - case ACalorimeterData.COLOR_FUNC_ENERGY: - EndcapColor=colorEndcapByEnergy( cellEnergy, minEnergy, maxEnergy); - break; -/* - case COLOR_FUNC_JET: - colorBy(getJets()); - break; -*/ - default: - for(int i = 0; i < cellEnergy.length; i++) - EndcapColor[i] = (byte) constantColor; - } - - return EndcapColor; - } - - /** - * Color cells by energy. - * Used for summing over layer in the Endcaps in the YX projection - * - * @param cellEnergy double[] list of each cells energy - * @param minEnergy double min Energy in a cell - * @param maxEnergy double max Energy in a cell - * - * @return byte[] colors for each energy - */ - protected static byte[] colorEndcapByEnergy(double[] cellEnergy, double minEnergy, double maxEnergy) - { - byte[] EndcapColor= new byte[cellEnergy.length]; - int numColors = 17; - for (int i = 0; i < cellEnergy.length; i++) - { - if (AColorMap.getColorMap() == AColorMap.COLOR_MAP_BW) - { - // Black and white colormap. - EndcapColor[i] = AColorMap.BK; - } - else - { - // We have numColors colors available. - switch (parameterStore.get(name, "EnergyMode").getI()) - { - case ACalorimeterData.ENERGY_MODE_MAX_LIN: - case ACalorimeterData.ENERGY_MODE_SUM_LIN: - EndcapColor[i] = (byte) (numColors * (cellEnergy[i] - minEnergy) / (maxEnergy - minEnergy)); - break; - case ACalorimeterData.ENERGY_MODE_MAX_LOG: - case ACalorimeterData.ENERGY_MODE_SUM_LOG: - EndcapColor[i] = (byte) (numColors * (Math.log(cellEnergy[i]) - Math.log(minEnergy)) / (Math.log(maxEnergy) - Math.log(minEnergy))); - break; - case ACalorimeterData.ENERGY_MODE_MAX_SQRT: - case ACalorimeterData.ENERGY_MODE_SUM_SQRT: - EndcapColor[i] = (byte) (numColors * Math.sqrt((cellEnergy[i] - minEnergy) / (maxEnergy - minEnergy))); - break; - } - if (EndcapColor[i] >= numColors) - EndcapColor[i] = (byte) (numColors - 1); - } - } - return EndcapColor; - } - - /** - * Energy of each color. - * Used for summing over layer in the Endcaps in the YX projection - * - * @param minEnergy double min Energy in a cell - * @param maxEnergy double max Energy in a cell - * - * @return byte[] colors for each energy - */ - protected static double[] energyOfEndcapColor(double minEnergy, double maxEnergy) - { - int numColors = 17; - double[] colorEnergy= new double[numColors]; - for (int i = 0; i < numColors; i++) - { - // We have numColors colors available. - switch (parameterStore.get(name, "EnergyMode").getI()) - { - case ACalorimeterData.ENERGY_MODE_MAX_LIN: - case ACalorimeterData.ENERGY_MODE_SUM_LIN: - colorEnergy[i] = ((i * (maxEnergy - minEnergy))/numColors)+minEnergy; - break; - case ACalorimeterData.ENERGY_MODE_MAX_LOG: - case ACalorimeterData.ENERGY_MODE_SUM_LOG: - colorEnergy[i] = Math.exp(((i * (Math.log(maxEnergy) - Math.log(minEnergy)))/numColors)+Math.log(minEnergy)); - break; - case ACalorimeterData.ENERGY_MODE_MAX_SQRT: - case ACalorimeterData.ENERGY_MODE_SUM_SQRT: - colorEnergy[i] = (Math.pow(i/numColors,2) * (maxEnergy - minEnergy))+minEnergy; - break; - } - //may need check to see if lower or higher than min or max - if (colorEnergy[i] >= numColors) - colorEnergy[i] = (byte) (numColors -1); - } - return colorEnergy; - } - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AGLGraphics.java b/graphics/AtlantisJava/src/atlantis/canvas/AGLGraphics.java deleted file mode 100644 index ee0c032ad05..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AGLGraphics.java +++ /dev/null @@ -1,486 +0,0 @@ -package atlantis.canvas; - -import atlantis.graphics.AAbstractGraphics2D; -import com.sun.opengl.util.BufferUtil; -import java.awt.*; -import java.awt.RenderingHints.Key; -import java.awt.color.ColorSpace; -import java.awt.geom.AffineTransform; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.awt.image.ComponentColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferByte; -import java.awt.image.ImageObserver; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.text.AttributedCharacterIterator; -import javax.media.opengl.*; - -/** - * - * This class is an implementation of Graphics2D (although it actually subclasses - * AAbstractGraphics2D). It wraps a GLAutoDrawable object to allow Swing based - * components to paint and have their calls translated into OpenGL calls on the - * underlying context. - * - * Obviously emulating all the functionality of Graphics2D is a challenge - * so expect some visual issues initially... - * - * @author Adam Davison - */ -public class AGLGraphics extends AAbstractGraphics2D { - - private int m_clipx = 0; - private int m_clipy = 0; - private int m_clipw = 0; - private int m_cliph = 0; - private Color m_color = Color.BLACK; - private GLAutoDrawable m_d; - private GL m_gl; - private int m_depth = 1; - private ComponentColorModel m_colorModel = - new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), - new int[]{8, 8, 8, 8}, true, false, ComponentColorModel.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - - public AGLGraphics(AGLGraphics old) { - m_d = old.m_d; - m_gl = m_d.getGL(); - } - - /* - * Draw shapes, don't actually implement cubic or quadratic curves yet. - * For now we only draw straight lines. - * Having said that Atlantis uses such a huge number of segments that this - * doesn't seem to be an issue for visual quality as of yet... - */ - @Override - public void draw(Shape z) { - PathIterator pi = z.getPathIterator(null); - float[] c = new float[6]; - float xpos = 0.0f; - float ypos = 0.0f; - while (!pi.isDone()) { - int type = pi.currentSegment(c); - switch (type) { - case PathIterator.SEG_MOVETO: - xpos = c[0]; - ypos = c[1]; - break; - case PathIterator.SEG_CLOSE: - // Ignoring close lines for now I guess... - break; - case PathIterator.SEG_CUBICTO: - drawLine(c[2], c[3], c[4], c[5]); - case PathIterator.SEG_QUADTO: - drawLine(c[0], c[1], c[2], c[3]); - case PathIterator.SEG_LINETO: - // Just do lines... - drawLine(xpos, ypos, c[0], c[1]); - xpos = c[0]; - ypos = c[1]; - break; - } - pi.next(); - } - //super.draw(z); - } - - public AGLGraphics(GLAutoDrawable d) { - m_d = d; - m_gl = m_d.getGL(); - } - - /* - * This implementation of create()/dispose() is highly thread unsafe - * Since it's not trivial to duplicate the GL context we do the best we can - * and hopefully it's ok for Atlantis. - * - * Essentially where Java2D would create a whole new object which would then - * have it's own state, we push the modelview stack. This means that - * we can perform transformations and then pop the modelview stack in dispose - * to emulate this functionality. - * - * Obviously if you call create twice in two separate threads then one of - * you is destroying the other one's modelview matrix... - */ - @Override - public Graphics create() { - m_gl.glMatrixMode(GL.GL_MODELVIEW_MATRIX); - m_gl.glPushMatrix(); - m_depth++; - //System.err.println("PUSH: " + depth); - //return new AGLGraphics(this); //????? - return this; - } - - @Override - public void translate(int x, int y) { - m_gl.glMatrixMode(GL.GL_MODELVIEW_MATRIX); - m_gl.glTranslatef(x, y, 0.0f); - return; - } - - @Override - public Color getColor() { - return m_color; - } - - @Override - public void setColor(Color c) { - m_color = c; - //System.out.println(c.toString()); - float r = ((float) c.getRed()) / 255.0f; - float g = ((float) c.getGreen()) / 255.0f; - float b = ((float) c.getBlue()) / 255.0f; - float a = ((float) c.getAlpha()) / 255.0f; - m_d.getGL().glColor4f(r, g, b, a); - } - - @Override - public void setPaintMode() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void setXORMode(Color c1) { - throw new UnsupportedOperationException("Not supported yet."); - } - - private Font m_font = Font.decode("Arial-BOLD-18"); - - @Override - public Font getFont() { - return m_font; - } - - @Override - public void setFont(Font font) { - m_font = font; - } - - @Override - public FontMetrics getFontMetrics(Font f) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Rectangle getClipBounds() { - return new Rectangle(m_clipx, m_clipy, m_clipw, m_cliph); - } - - @Override - public void clipRect(int x, int y, int width, int height) { - throw new UnsupportedOperationException("Not supported yet."); - } - - /* - * Sort of ignoring clip here... - */ - @Override - public void setClip(int x, int y, int width, int height) { - m_clipx = x; - m_clipy = y; - m_clipw = width; - m_cliph = height; - //System.out.println("Who cares about clip for now??"); - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Shape getClip() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void setClip(Shape clip) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void copyArea(int x, int y, int width, int height, int dx, int dy) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void drawLine(int x1, int y1, int x2, int y2) { - drawLine((float) x1, (float) y1, (float) x2, (float) y2); - } - - public void drawLine(float x1, float y1, float x2, float y2) { - m_gl.glBegin(m_gl.GL_LINES); - m_gl.glVertex2f(x1, y1); - m_gl.glVertex2f(x2, y2); - m_gl.glEnd(); - } - - @Override - public void fillRect(int x, int y, int width, int height) { - GL gl = m_d.getGL(); - - gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL); - - gl.glBegin(gl.GL_QUADS); - gl.glVertex2f(x, y); - gl.glVertex2f(x + width, y); - gl.glVertex2f(x + width, y + height); - gl.glVertex2f(x, y + height); - gl.glEnd(); - } - - @Override - public void clearRect(int x, int y, int width, int height) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void drawOval(int x, int y, int width, int height) { - throw new UnsupportedOperationException("Not supported yet."); - - } - - @Override - public void fillOval(int x, int y, int width, int height) { - //throw new UnsupportedOperationException("Not supported yet."); - return; - } - - @Override - public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { - m_gl.glPolygonMode(m_gl.GL_FRONT_AND_BACK, m_gl.GL_LINE); - - m_gl.glBegin(m_gl.GL_POLYGON); - - for (int i = 0; i < nPoints; i++) { - m_gl.glVertex2f(xPoints[i], yPoints[i]); - } - - m_gl.glEnd(); - } - - public void fillPolygon(double[] xPoints, double[] yPoints, int nPoints) { - - m_gl.glPolygonMode(m_gl.GL_FRONT_AND_BACK, m_gl.GL_FILL); - - m_gl.glBegin(m_gl.GL_POLYGON); - - for (int i = 0; i < nPoints; i++) { - m_gl.glVertex2d(xPoints[i], yPoints[i]); - } - - m_gl.glEnd(); - } - - /* - * Bear in mind that although Java2D is capable of filling arbitrary - * polygons, OpenGL/graphics cards in general use a very simple fill - * algorithm which is only guaranteed to be valid for convex polygons - * If you want to render a concave polygon you have to tessellate it down - * into convex ones. - * - * So far I've been able to do this by modifying the way geometry is - * represented but you can also have a go at tessellating automatically - * using GLUT if you really need to... - */ - @Override - public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { - - // Prototype code for vertex arrays, actually slower for single polys - // but will definitely improve importance if we start passing in big - // arrays of polygons, say for complex geometry - if (false) { - IntBuffer ib = BufferUtil.newIntBuffer(nPoints * 2); - for (int i = 0; i < nPoints; i++) { - ib.put(xPoints[i]); - ib.put(yPoints[i]); - } - ib.rewind(); - m_gl.glEnableClientState(GL.GL_VERTEX_ARRAY); - m_gl.glVertexPointer(2, GL.GL_INT, 0, ib); - m_gl.glDrawArrays(GL.GL_POLYGON, 0, nPoints); - } else { - // Draw the simple way - - m_gl.glPolygonMode(m_gl.GL_FRONT_AND_BACK, m_gl.GL_FILL); - m_gl.glBegin(m_gl.GL_POLYGON); - - for (int i = 0; i < nPoints; i++) { - m_gl.glVertex2f(xPoints[i], yPoints[i]); - } - - m_gl.glEnd(); - } - } - - @Override - public Stroke getStroke() { - return null; - } - - @Override - public void setStroke(Stroke z) { - //super.setStroke(z); - } - - @Override - public void drawString(String str, int x, int y) { - //FontRenderContext frc = new FontRenderContext(null, true, true); - //GlyphVector gv = m_font.layoutGlyphVector(frc, str.toCharArray(), - // 0, str.length(), Font.LAYOUT_LEFT_TO_RIGHT); - //int ng = gv.getNumGlyphs(); - //Rectangle2D r = gv.getVisualBounds(); - //m_gl.glColor3f(1.0f, 0.0f, 0.0f); - //this.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(), (int) r.getHeight()); - //this.setColor(m_color); - - WritableRaster test = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - 32, 32, 4, null); - BufferedImage testi = new BufferedImage(m_colorModel, test, false, null); - Graphics testg = testi.getGraphics(); - FontMetrics fm = testg.getFontMetrics(m_font); - Rectangle2D r = fm.getStringBounds(str, testg); - - WritableRaster raster = - Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - (int)r.getWidth(), (int)r.getHeight(), 4, null); - - BufferedImage bi = new BufferedImage(m_colorModel, raster, false, null); - - Graphics big = bi.getGraphics(); - //big.setColor(Color.GREEN); - //big.fillRect(0, 0, bi.getWidth(), bi.getHeight()); - big.setColor(m_color); - big.setFont(m_font); - big.drawString(str, -(int)r.getX(), -(int)r.getY()); - drawImage(bi, x, (int)(y - r.getHeight()), null); - } - - @Override - public void drawString(AttributedCharacterIterator iterator, int x, int y) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - WritableRaster raster = - Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - img.getWidth(observer), img.getHeight(observer), 4, null); - - BufferedImage bi = new BufferedImage(m_colorModel, raster, false, null); - - Graphics2D g = bi.createGraphics(); - //g.setColor(Color.WHITE); - //g.drawLine(0, 0, bi.getWidth(), bi.getHeight()); - AffineTransform gt = new AffineTransform(); - gt.translate(0, img.getHeight(observer)); - gt.scale(1, -1d); - g.transform(gt); - g.drawImage(img, null, null); - - DataBufferByte imgbuf = (DataBufferByte) raster.getDataBuffer(); - - m_gl.glRasterPos2i(x, y + bi.getHeight()); - //System.out.println(img.getWidth(observer) + ":" + img.getHeight(observer)); - m_gl.glDrawPixels(img.getWidth(observer), img.getHeight(observer), - m_gl.GL_RGBA, m_gl.GL_UNSIGNED_BYTE, ByteBuffer.wrap(imgbuf.getData())); - - //System.out.println("Ignoring drawImage for now..."); - return true; - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { - // Needed to render JComponent backgrounds - //throw new UnsupportedOperationException("Not supported yet."); - return true; - } - - @Override - public Object getRenderingHint(Key z) { - return null; - } - - @Override - public void setRenderingHint(Key a, Object z) { - return; - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void dispose() { - m_depth--; - if (m_depth == 0) { - m_depth = 1; - // This happens when the object is really finally destroyed... - // When this is actually happening if we pop we'll cause a crash... - //System.err.println("DISPOSE CALLED TWICE ON ONE OBJECT!!!"); - //(new Exception()).printStackTrace(); - } else { - m_gl.glMatrixMode(GL.GL_MODELVIEW_MATRIX); - m_gl.glPopMatrix(); - } - return; - // We didn't create so no need to dispose... probably bad... - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void rotate(double a, double b, double z) { - super.rotate(a, b, z); - } - - @Override - public void rotate(double z) { - m_gl.glMatrixMode(GL.GL_MODELVIEW_MATRIX); - m_gl.glRotated(z * 360 / (2 * Math.PI), 0.0, 0.0, 1.0); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ALayout.java b/graphics/AtlantisJava/src/atlantis/canvas/ALayout.java deleted file mode 100755 index 7710aff90f8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ALayout.java +++ /dev/null @@ -1,231 +0,0 @@ -package atlantis.canvas; - - -import java.util.Hashtable; -import java.util.Enumeration; -import java.awt.Rectangle; -import java.awt.Dimension; -import org.w3c.dom.*; - - -/** - * This class is not an Layout Manager! It contains the possible window - * configuration - i.e. the possible subdivision of the canvas area in windows. - * Layouts are identified by names such as "SQUARE","FULL_SCREEN". - * Windows are identified by single characters such as "W","1", etc. - * Windows are furthermore grouped in pages such that they do not overlap. - * Pages are identified by the sum of the windows they contain, such as "Full","Vert" - * This class is used mainly by ACanvas and AWindowControl. - */ - -public class ALayout { - //The name of the layout - private String name; - //A table of the window constraints (i.e. corners) for all windows - private Hashtable windowConstraints; - //A table of the pages - private Hashtable pages; - //The default top window for this layout - private String startupWindow; - //The list of window names that by default are - //on the top in this layout - private String[] startupSequence; - - - /** - * Default constructor - * - * @param node XML node with the configuration - */ - public ALayout(Node node) { - //Create new hashtables for window corners and pages - windowConstraints=new Hashtable(); - pages=new Hashtable(); - - // reading the layout attributes - NamedNodeMap attributes=node.getAttributes(); - name=attributes.getNamedItem("name").getNodeValue(); - startupWindow=attributes.getNamedItem("startupWindow").getNodeValue(); - startupSequence=decompose(attributes.getNamedItem("startup").getNodeValue()); - - // reading all the content of Layout node - // - i.e pages and window settings - NodeList childrens=node.getChildNodes(); - for(int i=0; i<childrens.getLength(); i++) { - //get the subnode - Node child=childrens.item(i); - //read in window or page information - if(child.getNodeType()==Node.ELEMENT_NODE) { - //check wether it is a window or page configuration - String nodeName=child.getNodeName(); - if(nodeName.equals("Window")) - readWindow(child); - else if(nodeName.equals("Page")) - readPage(child); - } - } - } - - /** - * Read the window configuration (name/size/position) from an XML node - * - * @param node XML node with the configuration - */ - private void readWindow(Node child) { - //Get the nodes attributes - NamedNodeMap attributes=child.getAttributes(); - //retrieve window information - String name=attributes.getNamedItem("name").getNodeValue(); - int hPos=Integer.parseInt(attributes.getNamedItem("hPos").getNodeValue()); - int vPos=Integer.parseInt(attributes.getNamedItem("vPos").getNodeValue()); - int width=Integer.parseInt(attributes.getNamedItem("width").getNodeValue()); - int height=Integer.parseInt(attributes.getNamedItem("height").getNodeValue()); - //Check if this is a valid window name - if(!ACanvas.getCanvas().isValidWindowName(name)) - throw new Error("Undefined window name: "+name); - //Check if this window has been defined before - if(windowConstraints.containsKey(name)) - throw new Error("Multiple usage of window name: "+name); - //Validate window size and position - if((hPos<0)||(vPos<0)||(width<0)||(height<0)) - throw new Error("Wrong window constraints"); - //Add window constraints to the list - windowConstraints.put(name, new Rectangle(hPos, vPos, width, height)); - } - - /** - * Read the page configuration (windows it contains) from the XML node - */ - private void readPage(Node child) { - //get the attributes - NamedNodeMap attributes=child.getAttributes(); - //retrieve page configuration - String name=attributes.getNamedItem("name").getNodeValue(); - String content=attributes.getNamedItem("content").getNodeValue(); - - //Check if this page exists before - if(pages.containsKey(name)) - throw new Error("Redefinition of page: "+name); - //Split the list of windows in single window names - //('S789' -> 'S','7','8','9') - String[] wContent=decompose(content); - - //Check that each of this is a valid window - for(int i=0; i<wContent.length; i++) - if(!ACanvas.getCanvas().isValidWindowName(wContent[i])) - throw new Error("Unknown window name: "+wContent[i]); - //Add this page - pages.put(name, wContent); - } - - /** - * Break up a string of window names into a list of single window names - * - * @param s the string to break up - */ - private String[] decompose(String s) { - String[] strings=new String[s.length()]; - char[] characters=s.toCharArray(); - - for(int i=0; i<characters.length; i++) - strings[i]=new String(new char[] {characters[i]}); - - return strings; - } - - /** - * Return the layout name - */ - public String getName() { - return name; - } - - /** - * Return the window selected on startup - */ - public String getStartupWindow() { - return startupWindow; - } - - /** - * Return the list of window names that are on top by default - */ - public String[] getStartupSequence() { - return startupSequence; - } - - /** - * Check if window is part of this layout - */ - public boolean hasWindow(String wName) { - return windowConstraints.containsKey(wName); - } - - /** - * Return window names in this layout - */ - public String[] getWindowNames() { - // Loop over the window constraints and retrieve - // window names. - Enumeration wn=windowConstraints.keys(); - int size=windowConstraints.size(); - String[] names=new String[size]; - //Add them all to the array - for(int i=0; i<size; i++) - names[i]=(String)wn.nextElement(); - - return names; - } - - /** - * Return the constraints (i.e. position and size) - * for a particular window - * - * @param wName the name of the window - */ - public Rectangle getWindowConstraints(String wName) { - return(Rectangle)windowConstraints.get(wName); - } - - /** - * Calculate the size of the layout from all its subwindows - */ - public Dimension getSize() { - - Enumeration myenum=windowConstraints.elements(); - int w=0, h=0; - //Loop over all windows - while(myenum.hasMoreElements()) { - Rectangle r=(Rectangle)myenum.nextElement(); - //Check if they exceed the current size - if(r.x+r.width>w) - w=r.x+r.width; - if(r.y+r.height>h) - h=r.y+r.height; - } - - return new Dimension(w, h); - } - - /** - * Return a list of the page names - */ - public String[] getPageNames() { - Enumeration myenum=pages.keys(); - int size=pages.size(); - String[] names=new String[size]; - - for(int i=0; i<size; i++) - names[i]=(String)myenum.nextElement(); - - return names; - } - - /** - * Return a list of the windows that a certain page consists of - */ - public String[] getPageContent(String pageName) { - return(String[])pages.get(pageName); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ALayoutChangeListener.java b/graphics/AtlantisJava/src/atlantis/canvas/ALayoutChangeListener.java deleted file mode 100644 index 521e31440d1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ALayoutChangeListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package atlantis.canvas; - -/** - * Interface for all LayoutChangeListener classes. Each time the layout is - * changed, the layoutChanged method is called with the layout as an argument - * @author maillard - */ -public interface ALayoutChangeListener { - - /** - * This method gets called each time the layout is changed. - * @param canvas the canvas - */ - abstract public void layoutChanged(ACanvas canvas); - -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ALegendWindow.java b/graphics/AtlantisJava/src/atlantis/canvas/ALegendWindow.java deleted file mode 100755 index b6397cf61f9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ALegendWindow.java +++ /dev/null @@ -1,197 +0,0 @@ -package atlantis.canvas; - -import java.awt.Color; -import java.awt.Component; -import java.awt.GridLayout; -import java.awt.Toolkit; - -import javax.swing.JFrame; -import javax.swing.JTextField; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.graphics.colormap.AColorMap; - -/** - * The legend window appears when selected in the preferences menu - * It displays the energy scale for the summed endcaps as these do not - * have the pick interaction. - * - * Moved from package atlantis.gui to atlantis.canvas because of closer - * coupling with classes in atlantis.canvas and atlantis.data. Could move - * back later if can be decoupled. (Ben Waugh, 2011-10-01) - * - * @author Mark Stockton - */ -public class ALegendWindow extends JFrame -{ - private static JTextField[] titleField = new JTextField[2]; - private static JTextField[] textField; - private static ALegendWindow instance = null; - - public static ALegendWindow getInstance() - { - if (instance == null) - instance = new ALegendWindow(); - return instance; - } - - /** - * Check if ALegendWindow instance exists, without creating it if not. - * @return true if ALegendWindow instance exists - */ - public static boolean exists() { - return (instance != null); - } - - public void addEnergyText(AWindow window, double[] Energies, double Energy, Color[] colorMap) - { - if(window.equals(ACanvas.getCanvas().getCurrentWindow())) - { - getContentPane().removeAll(); - validate(); - getContentPane().setLayout(new GridLayout(Energies.length+titleField.length,1)); - - titleField[0].setText("Color Energy thresholds:"); - getContentPane().add(titleField[0]); - if(titleField[1]==null) - titleField[1]=new JTextField(); - titleField[1].setEditable(false); - titleField[1].setBackground(Color.white); - titleField[1].setForeground(Color.black); - titleField[1].setText("Maximum Cell Energy: " + (Math.rint(1000. * Energy)/1000) + " GeV "); - getContentPane().add(titleField[1]); - - String s=""; - for(int i=Energies.length-1;i>=0;i--) - { - if(textField[i]==null) - textField[i]=new JTextField(); - textField[i].setEditable(false); - //to even out the line spacing - if(i<10) - s="0" + i; - else - s="" + i; - s ="Color " + s + " Energy from: " + (Math.rint(1000. * Energies[i])/1000) + " GeV"; - textField[i].setText(s); - textField[i].setBackground(colorMap[i]); - //find out if too dark for black text - if( colorMap[i].getRed() + colorMap[i].getGreen() + - colorMap[i].getBlue()<=128) - textField[i].setForeground(Color.white); - else - textField[i].setForeground(Color.black); - getContentPane().add(textField[i]); - } - invalidate(); - pack(); - setVisible(true); - } - } - - public void addEnergyText(AWindow window, double minEnergy, double maxEnergy) - { - if(window.equals(ACanvas.getCanvas().getCurrentWindow())) - { - getContentPane().removeAll(); - validate(); - getContentPane().setLayout(new GridLayout(3,1)); - titleField[0].setText("Color Energy thresholds:"); - getContentPane().add(titleField[0]); - if(titleField[1]==null) - titleField[1]=new JTextField(); - titleField[1].setEditable(false); - titleField[1].setBackground(Color.white); - titleField[1].setForeground(Color.black); - titleField[1].setText("Maximum Cell Energy: " + (Math.rint(1000. * maxEnergy)/1000) + " GeV "); - getContentPane().add(titleField[1]); - - if(textField[0]==null) - textField[0]=new JTextField(); - textField[0].setEditable(false); - textField[0].setText("Minimum Cell Energy: " + (Math.rint(1000. * minEnergy)/1000) + " GeV "); - textField[0].setBackground(Color.white); - textField[0].setForeground(Color.black); - getContentPane().add(textField[0]); - invalidate(); - pack(); - setVisible(true); - } - } - - public void clearText(AWindow window) - { - if(!titleField[0].getText().equals("Select colour by Energy to bring up scale") - && window.equals(ACanvas.getCanvas().getCurrentWindow())) - { - getContentPane().removeAll(); - validate(); - getContentPane().setLayout(new GridLayout(1,1)); - titleField[0].setText("Select colour by Energy to bring up scale"); - getContentPane().add(titleField[0]); - invalidate(); - pack(); - setVisible(true); - } - } - - public void nothingToDisplay(AWindow window) - { - if(!titleField[0].getText().equals("Select LAr/HEC Summed and colour by Energy to bring up scale") - && window.equals(ACanvas.getCanvas().getCurrentWindow())) - { - getContentPane().removeAll(); - validate(); - getContentPane().setLayout(new GridLayout(1,1)); - titleField[0].setText("Select LAr/HEC Summed and colour by Energy to bring up scale"); - getContentPane().add(titleField[0]); - invalidate(); - pack(); - setVisible(true); - } - - } - - private ALegendWindow() - { - this.setTitle("Legend"); - AIcon.setIconImage(this); - this.setResizable(false); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - int numColors = AColorMap.getNumColors(); - getContentPane().setLayout(new GridLayout(1,1)); - textField = new JTextField[numColors]; - titleField[0] =new JTextField(); - titleField[0].setEditable(false); - titleField[0].setBackground(Color.white); - titleField[0].setForeground(Color.black); - titleField[0].setText("Select LAr/HEC Summed and colour by Energy to bring up scale"); - getContentPane().add(titleField[0]); - - // set the initial location - Component gui = AGlobals.instance().getGuiFrame(); - int guiWidth = gui.getWidth(); - int guiHeight = gui.getHeight(); - int guiX = gui.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit() - .getScreenSize().getWidth()); - if (guiX + guiWidth + (dialogWidth - guiWidth) / 2 > screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max( - 0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), - Math.max(0, (guiHeight - dialogHeight) / 3)); - - pack(); - setVisible(true); - } - - public void dispose() - { - instance = null; - super.dispose(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AOverlay.java b/graphics/AtlantisJava/src/atlantis/canvas/AOverlay.java deleted file mode 100644 index f4147695a91..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AOverlay.java +++ /dev/null @@ -1,193 +0,0 @@ -package atlantis.canvas; - -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; - -import javax.swing.ImageIcon; -import javax.swing.JPanel; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.globals.AGlobals; -import atlantis.graphics.AGraphics; -import atlantis.parameters.APar; -import atlantis.utils.AUtilities; - -/** - * AOverlay should be used within a GlassPane in the ACanvas. - * The overlay acts as a canvas on which images can be drawn over the existing display. - * This is currently only used to draw the ATLAS logo and Run/Event info as a floating image. - * Any drawing should be done with the paintComponent method, which is called as the Canvas is drawn. - * @author Tom McLaughlan - */ -public class AOverlay extends JPanel { - - protected static APar parameterStore = APar.instance(); - - public AOverlay() { - setOpaque(false); - } - - /** - * When the ACanvas GlassPane contains an Overlay instance, this is called - * after the Canvas is drawn. - */ - @Override public void paintComponent(Graphics g) { - super.paintComponent(g); - if(parameterStore.get("Logo","ShowATLAS").getStatus()) - drawATLASLogo(g); - } - - /** - * Draws a scaled version of the ATLAS PNG in the Overlay - * @param g The Graphics instance to draw to - */ - protected void drawATLASLogo(Graphics g) { - - int windowWidth = getWidth(); - int windowHeight = getHeight(); - - int logoWidth = 0; - int logoHeight = 0; - - double size = parameterStore.get("Logo", "LogoSize").getD(); - - logoWidth = (int) (windowWidth*size); - logoHeight = (int) (logoWidth*0.6); - - int logoX = 0; - int logoY = 0; - - double hpos = parameterStore.get("Logo", "LogoHPos").getD(); - logoX = (int) ((hpos * (windowWidth-logoWidth))); - - double vpos = parameterStore.get("Logo", "LogoVPos").getD(); - - int heightOffset = 0; - if(parameterStore.get("Prefs", "CanvasTitle").getStatus()) { - windowHeight = this.getParent().getHeight() - 40; - heightOffset = 40; - } - logoY = (int) ((vpos * (windowHeight-logoHeight))) + heightOffset; - - - long EventNumber = 0; - long RunNumber = 0; - String DateTime = ""; - Color textColor = Color.white, - backgroundColor = Color.black; - - AEvent event = AEventManager.instance().getCurrentEvent(); - - if (event != null) { - RunNumber = event.getRunNumber(); - EventNumber = event.getEventNumber(); - DateTime = event.getDateTime(); - } - - // Begin drawing - AGraphics ag = AGraphics.makeAGraphics(g); - // Fill the background - ag.setColor(backgroundColor); - //ag.fillRect(logoX, logoY, logoWidth, logoHeight); - - String iconPath = AGlobals.instance().getHomeDirectory() + "img" + System.getProperty("file.separator"); - - ImageIcon i = AUtilities.getFileAsImageIcon(iconPath + "atlas_logo_shadow.png"); - - - // Determine height and width of current window, and width of ATLAS logo - // These are then used to determine a scaling factor which is used in the - // scale function. - // - - int iwidth = i.getIconWidth(); - double factor = (double) logoWidth / (double) iwidth; - - // Call scale function to scale image to window size - ImageIcon iscale = AUtilities.scale(i.getImage(), factor, parameterStore.get("Prefs", "AntiAlias").getStatus()); - // x, y calculated to position image exactly centred - int x = (logoWidth / 2) - (iscale.getIconWidth() / 2); - int y = (logoHeight / 2) - ((3 * iscale.getIconHeight()) / 4); - - x += logoX; - y += logoY; - - int dpi = 72; - - // Set a scaling font size with window width - int fontSize = (int) Math.round(3.0 * logoWidth / (double) dpi) - 2; - - Font f = new Font("SansSerif", Font.PLAIN, fontSize); - - ag.drawImage(iscale.getImage(), x, y); - - ag.setColor(textColor); // Set colour for text - ag.updateColor(); // Update current colour for drawing - - String DateString = "", RunEventString = ""; - if (event != null) { - DateString = "Date: " + DateTime; - RunEventString = "Run Number: " + RunNumber + ", Event Number: " + EventNumber; - } else { - RunEventString = "No event data available"; - } - - FontMetrics fm = g.getFontMetrics(f); - int DateWidth = fm.stringWidth(DateString); - int RunEventWidth = fm.stringWidth(RunEventString); - - // Check if font is wider than the window and scale down til it fits. - while ((RunEventWidth > logoWidth - 20) || (DateWidth > logoWidth - 20)) - { - - fontSize = fontSize - 1; - f = new Font("SansSerif", Font.PLAIN, fontSize); - fm = g.getFontMetrics(f); - RunEventWidth = fm.stringWidth(RunEventString); - DateWidth = fm.stringWidth(DateString); - } - - ag.setFont(f); // set font as defined above - - if (event != null) { - drawStrokedString(ag, RunEventString, logoX + (logoWidth / 2) - RunEventWidth / 2, (int) (y + (1.1 * iscale.getIconHeight())), Color.WHITE, Color.BLACK); - //ag.drawString(RunEventString, - // logoX + (logoWidth / 2) - RunEventWidth / 2, y + (1.1 * iscale.getIconHeight())); - - if(!DateTime.equals("") && !DateTime.equals("n/a")) { - // If event contains Date/Time data, draw Run Number, Event Number and Date/Time - // and position text in centre of window - drawStrokedString(ag, DateString, logoX + (logoWidth / 2) - DateWidth / 2, (int) (y + (1.3 * iscale.getIconHeight())), Color.WHITE, Color.BLACK); - - //ag.drawString(DateString, - // logoX + (logoWidth / 2) - DateWidth / 2, y + (1.3 * iscale.getIconHeight())); - } - } - } - - /** - * Draws text with an outline, crudely. - * @param ag The AGraphics instance to draw to - * @param str The String to draw - * @param x x position of the string - * @param y y position of the string - * @param fg Text foreground colour - * @param bg Text outline colour - */ - protected void drawStrokedString(AGraphics ag, String str, int x, int y, Color fg, Color bg) { - ag.setColor(Color.BLACK); - ag.updateColor(); - ag.drawString(str, x-1, y-1); - ag.drawString(str, x+1, y+1); - ag.drawString(str, x+1, y-1); - ag.drawString(str, x-1, y+1); - ag.setColor(fg); - ag.updateColor(); - ag.drawString(str, x, y); - } - - -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AScale.java b/graphics/AtlantisJava/src/atlantis/canvas/AScale.java deleted file mode 100644 index 8359fe7cc7c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AScale.java +++ /dev/null @@ -1,356 +0,0 @@ -package atlantis.canvas; - -import java.awt.geom.GeneralPath; - -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjection; - -/** - * This class contains static methods which are useful for the - * AScaleBorder class and any potential subclasses. - * - * @author Charles Loomis, Ben Waugh - **/ -public class AScale { - final GeneralPath primaryTicks; - final GeneralPath secondaryTicks; - final double[] labelValues; // units are cm - final double[] labelPositions; // after transform - - final static public int LEFT_TICKS=0; - final static public int RIGHT_TICKS=1; - final static public int BOTH_TICKS=2; - - /** - * The size in pixels of the primary tick marks. This is a global - * property for all scales. */ - private static float primaryTickSize=8.f; - - /** - * The size in pixels of the secondary tick marks. This is a - * global property for all scales. */ - private static float secondaryTickSize=5.f; - - private AScale(GeneralPath primaryTicks, GeneralPath secondaryTicks, - double[] label, double[] position) { - this.primaryTicks = primaryTicks; - this.secondaryTicks = secondaryTicks; - this.labelValues = label; - this.labelPositions = position; - } - - /** - * Set the tick sizes (in pixels) for the primary and secondary - * tick marks. */ - static public void setTickSizes(float primaryTickSize, - float secondaryTickSize) { - AScale.primaryTickSize=primaryTickSize; - AScale.secondaryTickSize=secondaryTickSize; - } - - /** - * Get the primary tick size (in pixels). */ - static public float getPrimaryTickSize() { - return AScale.primaryTickSize; - } - - /** - * Get the secondary tick size (in pixels). */ - static public float getSecondaryTickSize() { - return AScale.secondaryTickSize; - } - - /** - * A utility method to add a tick mark to the given GeneralPath at - * the given position. */ - static private void addTickMark(GeneralPath gp, - int location, - float tickPosition, - float tickLength) { - - switch(location) { - - case(AScale.RIGHT_TICKS): - gp.moveTo(tickPosition, 0.f); - gp.lineTo(tickPosition, tickLength); - break; - - case(AScale.LEFT_TICKS): - gp.moveTo(tickPosition, 0.f); - gp.lineTo(tickPosition, -tickLength); - break; - - case(AScale.BOTH_TICKS): - gp.moveTo(tickPosition, -tickLength); - gp.lineTo(tickPosition, tickLength); - break; - } - } - - /** - * Get scale with given parameters. - * - * @param minValueTransformed min value after (fish-eye) transformation - * @param maxValueTransformed max value after (fish-eye) transformation - * @param scaleSize length of the scale border - * @param minPrimary minimum number of primary tick marks - * @param minSeparation minimum separation between tick marks - * @param location left,right,top,bottom - * @param isVertical whether this is a horizontal or vertical scale - * @param proj the projection this scale is drawn for - * @return - */ - public static AScale calculateScale( - double minValueTransformed, - double maxValueTransformed, - int scaleSize, - int minPrimary, - int minSeparation, - int location, - int isVertical, - AProjection proj - ){ - // Setup the two paths which will contain the primary and secondary tick marks. - GeneralPath primaryTicks = new GeneralPath(); - GeneralPath secondaryTicks = new GeneralPath(); - resetScale(primaryTicks,scaleSize); - resetScale(secondaryTicks,scaleSize); - - double minValue = invertTransformation(minValueTransformed,proj,isVertical); - double maxValue = invertTransformation(maxValueTransformed,proj,isVertical); - - double[] labelValues; - double[] labelPositions; - double[] intervals = getScaleIntervals(minValue,maxValue); - if (intervals!=null) { - double labelInterval = intervals[0]; - double primarySpacing = intervals[1]; - double secondarySpacing = intervals[2]; - addTickMarks(primaryTicks, proj, minValue, maxValue, primarySpacing, isVertical, location, primaryTickSize, scaleSize); - addTickMarks(secondaryTicks, proj, minValue, maxValue, secondarySpacing, isVertical, location, secondaryTickSize, scaleSize); - - // Now the labels with the correct precision must be made. - labelValues = getScaleValues(minValue,maxValue,labelInterval); - int numLabels = labelValues.length; - labelPositions = new double[numLabels]; - int ndigits=(int)(Math.floor(Math.log10(primarySpacing))); - ndigits=-Math.min(ndigits, 0); - - for (int i=0; i<labelValues.length; ++i) { - double valueTrans = applyTransformation(labelValues[i],proj,isVertical); - labelPositions[i] = (double) interpolate(valueTrans, scaleSize, minValueTransformed, maxValueTransformed); - } - } else { - labelValues = new double[] {}; - labelPositions = new double[] {}; - } - - return new AScale(primaryTicks,secondaryTicks,labelValues,labelPositions); - } - - /** - * Add tick marks at multiples of given spacing. - * - * @param path - * @param proj - * @param min - * @param max - * @param spacing - * @param isVertical - * @param location - * @param tickSize - * @param scaleSize - */ - private static void addTickMarks(GeneralPath path, - AProjection proj, double min, double max, double spacing, int isVertical, int location, float tickSize, double scaleSize) { - int minMultiplier = (int) Math.ceil(min/spacing); - int maxMultiplier = (int) Math.floor(max/spacing); - double minTrans = applyTransformation(min,proj,isVertical); - double maxTrans = applyTransformation(max,proj,isVertical); - for (int i=minMultiplier; i<=maxMultiplier; ++i) { - double value = i * spacing; - double valTrans = applyTransformation(value,proj,isVertical); - float tickPosition=interpolate(valTrans, scaleSize, minTrans, maxTrans); - addTickMark(path, location, tickPosition, tickSize); - } - - } - - private static void resetScale(GeneralPath path, double length) { - path.reset(); - path.moveTo(0.f, 0.f); - path.lineTo((float)length, 0.f); - } - - /** - * Convert from physical detector coordinate to transformed (fish-eye) coordinate. - * - * @param value - * @param proj - * @param isVertical - * @return - */ - private static double applyTransformation(double value, AProjection proj, int isVertical) { - double valueTransformed = value; - //Apply non-linear transforms if necessary - if (proj instanceof AProjection2D) { - if (isVertical==1) { - valueTransformed = ((AProjection2D)proj).nonLinearTransform(0,value).getY(); - } else { - valueTransformed = ((AProjection2D)proj).nonLinearTransform(value,0).getX(); - } - } - return valueTransformed; - } - - /** - * Convert from transformed (fish-eye) coordinate back to physical detector coordinate. - * - * @param valueTransformed - * @param proj - * @param isVertical - * @return - */ - private static double invertTransformation(double valueTransformed, AProjection proj, int isVertical) { - double value = valueTransformed; - //Apply non-linear transforms if necessary - if (proj instanceof AProjection2D) { - if (isVertical==1) { - value = ((AProjection2D)proj).inverseNonLinearTransform(0,valueTransformed).getY(); - } else { - value = ((AProjection2D)proj).inverseNonLinearTransform(valueTransformed,0).getX(); - } - } - return value; - } - - static float interpolate(double value, double size, - double value0, double value1) { - return(float)(size*(value-value0)/(value1-value0)); - } - - /** - * Title is put between last two value labels on axis. - * @return the position for the title on the scale - */ - public double getTitlePosition() { - double axisPosition; - int numLabels = labelPositions.length; - if (numLabels>=2) { - axisPosition = 0.5 * (labelPositions[numLabels-1] + labelPositions[numLabels-2]); - } else { - axisPosition = 0.0; // default to 0 if only one label (shouldn't happen) - } - return axisPosition; - } - - /** - * Get array of three intervals to use on scale. - * @param min minimum value on scale - * @param max maximum value on scale - * @return intervals to use for [labels, primary tick marks, secondary tick marks] - */ - static double[] getScaleIntervals(double min, double max) { - if (min>=max) return null; - boolean rangeIncludesZero = (min<0.0 && max>0.0); - double labelInterval; - double labelIntervalUnit; - int labelIntervalMultiplier; - if (rangeIncludesZero) { - double maxAbsValue = Math.max(Math.abs(min), Math.abs(max)); - double m=Math.floor(Math.log10(maxAbsValue)); - labelIntervalUnit = Math.pow(10., m); - labelInterval = getRoundNumber(maxAbsValue); - labelIntervalMultiplier = (int) Math.round(labelInterval / labelIntervalUnit); - if (labelIntervalMultiplier==2 && 2*labelInterval<maxAbsValue) { - labelIntervalMultiplier = 4; - labelInterval = labelIntervalMultiplier * labelIntervalUnit; - } - } else { - double range = Math.abs(max-min); - labelInterval = getRoundNumber(range); - int minMultiplier = (int) Math.ceil(min/labelInterval); - int maxMultiplier = (int) Math.floor(max/labelInterval); - while (maxMultiplier==minMultiplier) { - labelInterval = getRoundNumber(labelInterval*0.99); - minMultiplier = (int) Math.ceil(min/labelInterval); - maxMultiplier = (int) Math.floor(max/labelInterval); - } - double m=Math.floor(Math.log10(labelInterval)); - labelIntervalUnit = Math.pow(10., m); - minMultiplier = (int) Math.ceil(min/labelInterval); - maxMultiplier = (int) Math.floor(max/labelInterval); - labelIntervalMultiplier = (int) (labelInterval/labelIntervalUnit); - } - - double primaryInterval, secondaryInterval; - switch (labelIntervalMultiplier) { - case 1: - primaryInterval = labelIntervalUnit * 0.5; - secondaryInterval = labelIntervalUnit * 0.1; - break; - case 2: - primaryInterval = labelIntervalUnit * 1.0; - secondaryInterval = labelIntervalUnit * 0.2; - break; - case 3: - primaryInterval = labelIntervalUnit * 0.2; - secondaryInterval = labelIntervalUnit * 0.1; - break; - case 4: - primaryInterval = labelIntervalUnit * 2.0; - secondaryInterval = labelIntervalUnit * 0.5; - break; - case 5: - primaryInterval = labelIntervalUnit * 1.0; - secondaryInterval = labelIntervalUnit * 0.5; - break; - default: // Should not happen - primaryInterval = labelIntervalUnit * 0.5; - secondaryInterval = labelIntervalUnit * 0.1; - } - return new double[] {labelInterval, primaryInterval, secondaryInterval}; - } - - /** - * Get array of multiples of the given interval that lie in the given range. - * @param minValue minimum value on scale - * @param maxValue maximum value on scale - * @param labelInterval interval between values - * @return array of calculate values - */ - static double[] getScaleValues(double minValue, double maxValue, - double interval) { - int min = (int) Math.ceil(minValue/interval); - int max = (int) Math.floor(maxValue/interval); - int numValues = 1 + max - min; - double[] values = new double[numValues]; - for (int i=0; i<numValues; ++i) { - values[i] = (min + i) * interval; - } - return values; - } - - /** - * Rounds number towards zero to nearest "round number", i.e. a power of ten - * multiplied by 1, 2 or 5. - * - * @param d number to round - * @return next round number towards zero from input - */ - static double getRoundNumber(double d) { - double magnitude = Math.abs(d); - double m=Math.floor(Math.log10(magnitude)); - double unit = Math.pow(10., m); - double multIn = magnitude / unit; - double multOut; - if (multIn >= 5.0) multOut = 5.0; - else if (multIn >= 2.0) multOut = 2.0; - else multOut = 1.0; - double magRound = unit * multOut; - double round; - if (d<0.0) round = -magRound; - else round = magRound; - return round; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AScaleBorder.java b/graphics/AtlantisJava/src/atlantis/canvas/AScaleBorder.java deleted file mode 100755 index 8610ee38bfa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AScaleBorder.java +++ /dev/null @@ -1,1282 +0,0 @@ -package atlantis.canvas; - -import atlantis.graphics.AAbstractGraphics2D; -import atlantis.graphics.ACursorFactory; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Rectangle; -import java.awt.Stroke; -import java.awt.Image; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; - -import javax.swing.border.Border; - -import atlantis.gui.APreferencesControl; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.parameters.ALinkParameter; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjectionEventInfo; -import atlantis.projection.AProjectionNGE; -import atlantis.projection.AProjectionTrackResidual; -import atlantis.utils.AMath; -import java.awt.RenderingHints; - -/** - * This class implements a Border in which the left and bottom sides contain - * numerical scales. - * - * @author Charles Loomis, Sebastian Boeser - */ -public class AScaleBorder implements Border -{ - // Constants giving horizontal and vertical index of the data arrays. - final static private int HORIZONTAL = 0; - final static private int VERTICAL = 1; - - /** - * Constant describing a transform in which the transformed x and y axes are - * parallel (or antiparallel) to the original axes. - */ - final static public int TYPE_PARALLEL_TRANSFORM = 0; - - /** - * Constant describing a transform in which the transformed x and y axes are - * parallel (or antiparallel) to the original y and x axes, respectively. - */ - final static public int TYPE_SWITCHED_TRANSFORM = 1; - - /** - * Constant describing a transform in which the transformed x-axis is - * parallel (or antiparallel) to the original x-axis and the transformed - * y-axis forms a non-zero angle with the original one. - */ - final static public int TYPE_X_SKEW_TRANSFORM = 2; - - /** - * Constant describing a transform in which the transformed y-axis is - * parallel (or antiparallel) to the original y-axis and the transformed - * x-axis forms a non-zero angle with the original one. - */ - final static public int TYPE_Y_SKEW_TRANSFORM = 3; - - /** - * Constant describing a transform in which the transformed x-axis is - * parallel (or antiparallel) to the original y-axis and the transformed - * y-axis forms a non-zero angle with the original x-axis. - */ - final static public int TYPE_SWITCHED_X_SKEW_TRANSFORM = 4; - - /** - * Constant describing a transform in which the transformed y-axis is - * parallel (or antiparallel) to the original x-axis and the transformed - * x-axis forms a non-zero angle with the original y-axis. - */ - final static public int TYPE_SWITCHED_Y_SKEW_TRANSFORM = 5; - - /** - * Constant describing a transform which does not fall into one of the other - * categories. - */ - final static public int TYPE_GENERAL_TRANSFORM = 6; - - /** - * Constant indicating that a string should be aligned vertically with the - * baseline of the text. This is the default in drawString calls which do - * not specify an alignment. - */ - public static final int TEXT_BASELINE = 0; - - /** - * Constant indicating that a string should be aligned vertically with the - * top of the text. - */ - public static final int TEXT_TOP = 1; - - /** - * Constant indicating that a string should be aligned vertically with the - * bottom of the text. - */ - public static final int TEXT_BOTTOM = 3; - - /** - * Constant indicating that a string should be aligned by the center. This - * is used for both horizontal and vertical alignment. - */ - public static final int TEXT_CENTER = 2; - - /** - * Constant indicating that a string should be aligned horizontally with the - * left side of the text. This is the default for drawString calls which do - * not specify an alignment. - */ - public static final int TEXT_LEFT = 1; - - /** - * Constant indicating that the string should be aligned horizontally with - * the right side of the text. - */ - public static final int TEXT_RIGHT = 3; - - private AScale horizontalScale; // holds tick marks and labels - private AScale verticalScale; - - /** - * String giving the axis labels. - */ - private String[] axisLabels = new String[2]; - - /** - * String giving the axis units. - */ - private String[] axisUnits = new String[2]; - - /** - * The initial font size for labeling. - */ - private int fontSize = 12; - - /** - * The initial font to use. - */ - private Font labelFont = new Font("SansSerif", Font.BOLD, 12); - - /** - * The width of the line used for the secondary tick marks. - */ - final static private Stroke thinStroke = new BasicStroke(1.f); - - /** - * The width of the line used for the primary tick marks. - */ - final static private Stroke thickStroke = new BasicStroke(2.f); - - /** - * An array to hold temporary point values for transformation. - */ - private double[] axisPts = new double[6]; - - /** - * Flag to indicate that the scale has changed and that it needs to be - * redrawn. - */ - private boolean scaleChanged; - - - /** - * The current width of the horizontal scale. - */ - private int currentWidth; - - /** - * The current width of the vertical scale. - */ - private int currentHeight; - - /** - * Minimum value on the horizontal axis. - */ - private double minHoriz; - - /** - * Maximum value of the horizontal axis. - */ - private double maxHoriz; - - /** - * Minimum value of the vertical axis. - */ - private double minVert; - - /** - * Maximum value on the vertical axis. - */ - private double maxVert; - - /** - * The calculated Insets for this border. - */ - private Insets insets; - - private boolean selected; - - /** - * Wether to draw the scales for this window or not - */ - private boolean drawScaleBorder; - - /** - * Wether to draw the scales for this window or not - * independant of the projection being displayed - */ - private boolean drawScaleBorder_preference; - - - /** - * The window this scale is drawn in. - */ - private final AWindow aWindow; - - /** - * Constructs a AScaleBorder - * @param theWindow the window this scale belongs to - */ - public AScaleBorder(AWindow theWindow) - { - aWindow = theWindow; - - // Give default values for the size of the axes. - minHoriz = 0.; - maxHoriz = 0.; - minVert = 0.; - maxVert = 0.; - - // Make the new insets. - resetInsets(); - - // Set the current width and height. - currentWidth = 0; - currentHeight = 0; - scaleChanged = false; - - selected = false; - drawScaleBorder = true; - drawScaleBorder_preference = true; - } - - public void forceDraw() - { - scaleChanged = true; - } - - public void toggleScale() - { - drawScaleBorder_preference = !drawScaleBorder_preference; - //only actually toggle scale if on a window with scale - AProjection p = aWindow.getProjection(); - - if(p instanceof AProjectionLegoPlot || p instanceof AProjectionNGE || p instanceof AProjectionEventInfo) - return; - - drawScaleBorder = !drawScaleBorder; - scaleChanged = true; - resetInsets(); - } - - public void hideScale() - { - //upon window change of projection check if scales need to hide or not - AProjection p = aWindow.getProjection(); - - // Check global 'Hide Scales' option (in preferences menu) - // If hiding scales, set all scales to false - // - if(APreferencesControl.getHideScalesMenuItem()) - { - drawScaleBorder=false; - resetInsets(); - } - else - if(p instanceof AProjectionLegoPlot || p instanceof AProjectionNGE || p instanceof AProjectionEventInfo){ - if(drawScaleBorder){ - drawScaleBorder=false; - resetInsets(); - } - }else if(drawScaleBorder!=drawScaleBorder_preference){ - drawScaleBorder=drawScaleBorder_preference; - resetInsets(); - } - } - - public boolean getScaleStatus() - { - return drawScaleBorder_preference; - } - - /** - * Set the font for the labels. - */ - public void setLabelFont(Font labelFont) - { - this.labelFont = labelFont; - fontSize = labelFont.getSize(); - resetInsets(); - } - - public void setSelected() - { - selected = true; - } - - public void setDeselected() - { - selected = false; - } - - /** - * Get the current font for the labels. - */ - public Font getLabelFont() - { - return labelFont; - } - - /** - * Set the horizontal and vertical limits for the scales. - */ - public void setLimits(double minHoriz, double maxHoriz, double minVert, double maxVert) - { - this.minHoriz = minHoriz; - this.maxHoriz = maxHoriz; - this.minVert = minVert; - this.maxVert = maxVert; - scaleChanged = true; - } - - /** - * Set the axis labels. - */ - public void setAxisLabels(String horizontalLabel, String verticalLabel) - { - axisLabels[HORIZONTAL] = horizontalLabel; - axisLabels[VERTICAL] = verticalLabel; - } - - public String getHorizontalAxisLabel() - { - return axisLabels[HORIZONTAL]; - } - - public String getVerticalAxisLabel() - { - return axisLabels[VERTICAL]; - } - - /** - * Set the axis units. - */ - public void setAxisUnits(String horizontalUnits, String verticalUnits) - { - if (horizontalUnits != null) - { - axisUnits[HORIZONTAL] = horizontalUnits; - } - else - { - axisUnits[HORIZONTAL] = ""; - } - - if (verticalUnits != null) - { - axisUnits[VERTICAL] = verticalUnits; - } - else - { - axisUnits[VERTICAL] = ""; - } - } - - /** - * Returns the insets of this border. - */ - @Override - public Insets getBorderInsets(Component c) - { - return (Insets) insets.clone(); - } - - /** - * Returns whether or not the border is opaque. This always returns true. - */ - @Override - public boolean isBorderOpaque() {return true;} - - /** - * Paints the border and window decorations for the specified component with the specified graphics - * context, position, and size. - */ - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) - { - //Get the graphics context - Graphics2D vg = (Graphics2D) g; - //Sanity check - if (vg==null) return; - - //Select background and frame colors - Color bg = AWindow.BORDER_BACKGROUND_COLOR ; - - //Paint the border frame - paintBorderFrame(vg,bg,width,height); - - //If drawing the border draw scales - if (drawScaleBorder) - { - //Now check which projection we have - AProjection p = aWindow.getProjection(); - - // Set the flag indicating that the scales must be remade. - scaleChanged = (scaleChanged || width != currentWidth || height != currentHeight); - - //set the Scales - setScales(p.getXLabel(), p.getYLabel(), p.getXUnits(), p.getYUnits(), makeTransform(aWindow.getUserCorners()), aWindow.getWidth(), aWindow.getHeight()); - - //Paint the grid if there is one for this projection - paintGrid(vg,p,width,height); - - //Paint the scales themselves - paintScales(vg,p,width,height); - - // Reset the current width and height. - currentWidth = width; - currentHeight = height; - scaleChanged = false; - } - - //Check whether Window Title needs to be drawn - if(APreferencesControl.getWindowTitleMenuItem()) { - paintWindowTitle(g, width, height,true); - } - - //Check whether FishEye Indicator needs to be drawn - if(APreferencesControl.getFisheyeIndicatorMenuItem()) { - paintFishEyeIndicator(g, false, width, height); - } - } - - /** - * Paints the part of the border that appears when the window is printed - */ - void printBorder(Component c, Graphics g, int x, int y, int width, int height) - { - paintBorder(c,g,x,y,width,height); - } - - - /** - * Draw the part of the scales that shows up in printing - */ - private void paintScales(Graphics2D g, AProjection p, int width, int height){ - APar parameterStore = APar.instance(); - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - - Color foregroundColour = selected ? AWindow.BORDER_SELECTED_FOREGROUND_COLOR : AWindow.BORDER_FOREGROUND_COLOR; - - // Get the horizontal scale. - if (scaleChanged) - { - int scaleLength = width - (insets.left + insets.right); - horizontalScale = AScale.calculateScale(minHoriz, maxHoriz, scaleLength, 3, 7, AScale.RIGHT_TICKS, - HORIZONTAL, p); - } - - svg.translate(insets.left, height - insets.bottom + 2); - - svg.setColor(foregroundColour); - svg.setFont(new Font("SansSerif", Font.BOLD, 12)); - - // Draw the primary and secondary tick marks. - svg.setStroke(thickStroke); - svg.draw(horizontalScale.primaryTicks); - svg.setStroke(thinStroke); - svg.draw(horizontalScale.secondaryTicks); - - ScaleUnits hScaleUnits = new ScaleUnits(axisUnits[HORIZONTAL],minHoriz,maxHoriz); - double factorH = hScaleUnits.scaleFactor; - String unitsH = hScaleUnits.units; - - ScaleUnits vScaleUnits = new ScaleUnits(axisUnits[VERTICAL],minVert,maxVert); - double factorV = vScaleUnits.scaleFactor; - String unitsV = vScaleUnits.units; - - // Paint the tick labels. - int numLabelsH = horizontalScale.labelValues.length; - for (int i = 0; i < numLabelsH; i++) - { - double valueScaled = horizontalScale.labelValues[i] * factorH; - int nDecPlaces = getNumDecimalPlaces(valueScaled); - String label = String.format("%."+nDecPlaces+"f", valueScaled); - drawString(svg, label, - (float) horizontalScale.labelPositions[i], AScale.getPrimaryTickSize() + 0.2f * fontSize, TEXT_CENTER, TEXT_TOP, width - insets.left - insets.right); - } - - // Paint the axis label. - float axisPositionX = (float) horizontalScale.getTitlePosition(); - drawString(svg, axisLabels[HORIZONTAL] + " " + unitsH, axisPositionX, AScale.getPrimaryTickSize() + 0.2f * fontSize, TEXT_CENTER, TEXT_TOP, width - insets.left - insets.right); - - // End this context. - svg.dispose(); - - // Now create a new graphics context for the vertical axis. - svg = (Graphics2D) (g.create()); - - // Create the vertical scale. - if (scaleChanged) - { - int scaleLength = height - (insets.top + insets.bottom); - verticalScale = AScale.calculateScale(minVert, maxVert, scaleLength, 3, 7, AScale.LEFT_TICKS, - VERTICAL, p); - } - - svg.translate(insets.left - 2, height - insets.bottom); - svg.rotate(-Math.PI / 2.); - - svg.setColor(foregroundColour); - svg.setFont(new Font("SansSerif", Font.BOLD, 12)); - - // Draw the primary and secondary tick marks. - svg.setStroke(thickStroke); - svg.draw(verticalScale.primaryTicks); - svg.setStroke(thinStroke); - svg.draw(verticalScale.secondaryTicks); - - // Paint the tick labels. - int numLabelsV = verticalScale.labelValues.length; - for (int i = 0; i < numLabelsV; i++) - { - double valueScaled = verticalScale.labelValues[i] * factorV; - int nDecPlaces = getNumDecimalPlaces(valueScaled); - String label = String.format("%."+nDecPlaces+"f", valueScaled); - if(p instanceof AProjectionTrackResidual && parameterStore.get("TrackResidual", "Scale").getI() == 1) - { - if(!label.equals("0")) - { - long tmp = Math.round(((AProjectionTrackResidual)p).getResidual().getLogMagnitudeMin() + Math.abs(Double.parseDouble(label))); - if(label.indexOf("-") == -1) //positive - label = "1E" + tmp; - else - label = "-1E" + tmp; - } - } - drawString(svg, label, (float) verticalScale.labelPositions[i], -(AScale.getPrimaryTickSize() + 0.2f * fontSize), TEXT_CENTER, TEXT_BOTTOM, height - insets.top - insets.bottom); - } - - // Paint the axis label. - float axisPositionY = (float) verticalScale.getTitlePosition(); - drawString(svg, axisLabels[VERTICAL] + " " + unitsV, axisPositionY, -(AScale.getPrimaryTickSize() + 0.2f * fontSize), TEXT_CENTER, TEXT_BOTTOM, height - insets.top - insets.bottom); - - // End this context. - svg.dispose(); - - } - - /** - * Calculate number of decimal places needed in formatting number. - * @param x number to format - * @return number of decimal places needed - */ - static int getNumDecimalPlaces(double x) { - int m = - (int) Math.floor(Math.log10(Math.abs(x))); - return Math.max(0, m); - } - - /** - * Draw the grid for the V-Plot - **/ - private void paintGrid(Graphics2D g, AProjection p, int width, int height){ - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - - // next part draws the grid for the V-plot - if (p.getName().equals("VP")) - { - //Set color for grid lines - svg.setColor(Color.LIGHT_GRAY); - - // eta grid projections values - these particular values - // will be useful for calo people to see the eta grid lines at - float[] etaGridPositions = { -4.9f, -3.2f, -2.5f, -1.375f, -0.8f, - 0.8f, 1.375f, 2.5f, 3.2f, 4.9f }; - - for(int i = 0; i < etaGridPositions.length; i++) - { - if (etaGridPositions[i] > minHoriz && etaGridPositions[i] < maxHoriz) { - Point2D.Double startp = aWindow.calculateDisplay(etaGridPositions[i],minVert); - Point2D.Double endp = aWindow.calculateDisplay(etaGridPositions[i],maxVert); - svg.drawLine((int)startp.x,(int)startp.y,(int)endp.x,(int)endp.y); - } - } - - for (int i = (int)Math.ceil(minVert/90.)*90; i <= maxVert; i += 90) - { - Point2D.Double startp = aWindow.calculateDisplay(minHoriz,i); - Point2D.Double endp = aWindow.calculateDisplay(maxHoriz,i); - if (Math.abs(i) % 360 == 0) { - svg.setColor(Color.WHITE); - svg.setStroke(thickStroke); - } else { - svg.setColor(Color.LIGHT_GRAY); - svg.setStroke(thinStroke); - } - svg.drawLine((int)startp.x,(int)startp.y,(int)endp.x,(int)endp.y); - } - } - - svg.dispose(); - - } - - /** - * This bit of the frame that is drawn when printing (appart from scales) - */ - private void printBorderFrame(Graphics2D g, Color bg, int width, int height){ - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - - svg.setColor(bg); - //simply draw rectangles all around window - svg.fillRect(0, 0, width, insets.top); - // Added -insets.bottom because sometimes this stuff is transparent -Adam - svg.fillRect(0, 0, insets.left, height - insets.bottom); - svg.fillRect(width - insets.right, 0, insets.right, height); - svg.fillRect(0, height - insets.bottom, width, insets.bottom); - - svg.dispose(); - } - - /** - * Paint the Frame of the border with the given colors - */ - private void paintBorderFrame(Graphics2D g, Color bg, int width, int height){ - //Draw the frame same as for printing - printBorderFrame(g,bg,width,height); - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - - // Add a bit of GUI-look-and-feel frame - if (selected){ - //white triangle bottom left corner - clears any background colour - svg.setColor(AWindow.BORDER_SELECTED_FRAMELIGHT_COLOR); - int xp[]={0,0,11,0}; - int yp[]={height-12,height,height,height-12}; - svg.fillPolygon(xp,yp,4); - //blue border around window - svg.setColor(AWindow.BORDER_SELECTED_FRAME_COLOR); - svg.drawLine(0, 0, width-1, 0); - svg.drawLine(0, 0, 0, height-10); - svg.drawLine(width-1, 0, width-1, height-1); - svg.drawLine(10, height-1, width-1, height-1); - svg.drawLine(0, height-10, 9, height-1); - //white inner border - svg.setColor(AWindow.BORDER_SELECTED_FRAMELIGHT_COLOR); - svg.drawLine(10, height-2, width-2, height-2); - svg.drawLine(1, 1, 1, height-10); - //grey triangle bottom left corner - svg.setColor(AWindow.BORDER_BACKGROUND_COLOR); - xp[2]=8; - yp[0]=height-9; - yp[3]=height-9; - svg.fillPolygon(xp,yp,4); - } - - svg.dispose(); - } - - /** - * Paint a small box at the top of each window to describe what is on the window - */ - private void paintWindowTitle(Graphics g, int width, int height, boolean highlight) - { - APar parameterStore = APar.instance(); - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - //Get Mode parameter - String s=aWindow.getProjection().getName(); - parameterStore.selectWindowParameters(aWindow.getName()); - AParameter param=parameterStore.get(s, "Mode"); - int mode=param.getI(); - s=aWindow.getProjection().getScreenName(); - s+=" Projection"; - //Add mode text if not on standard view - if (param != null) - { - if(mode != 0) - { - s+=" viewing: "; - if(param instanceof ALinkParameter){ - s+=((ALinkParameter) param).getCurrentText(); - }else{ - s+=((AEnumeratorParameter) param).getCurrentText(); - } - } - } - parameterStore.restoreWindowParameters(); - //Offset if indicator to window frame - int Offset=2; - - int boxsize,y; - // get the width of the text - boxsize = svg.getFontMetrics().stringWidth(s)+Offset*2; - //Get y position from offset - y = Offset+svg.getFontMetrics().getHeight(); - - //Get the x position from width of window - int x = insets.left + (int) Math.round(((width-insets.left-boxsize)/2.0)); - //Draw background box and set text color - //highlighting the active window if desired - if(selected&&highlight) - { - //If selected and not printing eps - //add a bit of GUI-look-and-feel frame - svg.setColor(AWindow.BORDER_SELECTED_BACKGROUND_COLOR); - svg.fillRect(x-2, 1, boxsize+4, y+1); - svg.setColor(AWindow.BORDER_SELECTED_FRAME_COLOR); - svg.fillRect(x-1, 0, boxsize+2, y+1); - svg.setColor(AWindow.BORDER_SELECTED_FRAMELIGHT_COLOR); - svg.fillRect(x, 1, boxsize, y-1); - svg.setColor(AWindow.BORDER_SELECTED_BACKGROUND_COLOR); - svg.fillRect(x+1, 1, boxsize-1, y-2); - svg.setColor(AWindow.BORDER_SELECTED_FOREGROUND_COLOR); - } - else - { - //If not selected draw background box - svg.setColor(AWindow.BORDER_BACKGROUND_COLOR); - svg.fillRect(x-2, 0, boxsize+4, y+2); - svg.setColor(AWindow.BORDER_FOREGROUND_COLOR); - } - //Draw text - svg.drawString(s, x+Offset, y-3); - //cleanup - svg.dispose(); - } - - /** - * Paint a small FishEye Indicator if FishEye projection is active. - * At the moment, the indicator is drawn in the top right corner of the canvas. - * One might as well put it in on the scale. Eventually, if the scales shows - * proper fisheyed coordinates, it might not be needed anymore at all. - */ - private void paintFishEyeIndicator(Graphics g, boolean forceText, int width, int height){ - APar parameterStore = APar.instance(); - - //Probe for fishEye status - boolean fishEyeStatus=false; - - //Check if FishEye is on for this particular window - parameterStore.selectWindowParameters(aWindow.getName()); - - //Get FishEye parameter - AParameter fishEyePar = parameterStore.get(aWindow.getProjection().getName(), "FishEye"); - - //Check if there is a fish-eye parameter for this projection, and get status (enabled or not) - if (fishEyePar != null) fishEyeStatus=fishEyePar.getStatus(); - - //Restore to active window - parameterStore.restoreWindowParameters(); - - // Now draw indicator if fisheye was on - if (fishEyeStatus){ - - // Make our own graphics contex, so we don't cause trouble elsewhere - Graphics2D svg = (Graphics2D) g.create(); - //Offset if indicator to window frame - int Offset=4; - //Check if we have custom cursors - only then use indicator image - if (!forceText ){ - //FishEye indicator image is provided by ACursorFactory as it is the same - //as the cursor used in FishEye transformation. - Image IndicatorImg = ACursorFactory.getInstance().getFishEyeIndicator(); - //Get the x position from width of window and width of image - int x = width-Offset-IndicatorImg.getWidth(null); - //Get y position from offset - int y = Offset; - //Draw an fisheye indicator in top right corner with some space - svg.drawImage(IndicatorImg,x,y,null); - } else { - int x,y; - //Get the x position from width of window and width of image - x = width-Offset-svg.getFontMetrics().stringWidth("FishEye"); - //Get y position from offset - y = Offset+svg.getFontMetrics().getHeight(); - //Set color to red - svg.setColor(Color.red); - //Use small label to indicate fisheye - svg.drawString("FishEye",x,y); - - } - //cleanup - svg.dispose(); - } - } - - /** - * Recalculate the insets based on the current font size. - */ - private void resetInsets() - { - int lb = (int) (2 + 2 + AScale.getPrimaryTickSize() + 1.5 * fontSize); - // int tr = (int) (2+2+AScale.getPrimaryTickSize()); - int tr = 2; - - if (drawScaleBorder) - insets = new Insets(tr, lb, lb, tr); - else - insets = new Insets(tr, tr, tr, tr); - } - - /** - * Set the scale labels taking into account the given linear transformation. - */ - public void setScales(String horizLabel, String vertLabel, String horizUnits, String vertUnits, AffineTransform transform, int panelWidth, int panelHeight) - { - - // Determine the type of the tranform. - int type = classifyTransform(transform); - - switch (type) - { - case TYPE_PARALLEL_TRANSFORM: - setAxisLabels(horizLabel, vertLabel); - setAxisUnits(horizUnits, vertUnits); - break; - - case TYPE_SWITCHED_TRANSFORM: - setAxisLabels(vertLabel, horizLabel); - setAxisUnits(vertUnits, horizUnits); - break; - - case TYPE_Y_SKEW_TRANSFORM: - setAxisLabels(horizLabel + AMath.PRIME, AMath.DELTA + vertLabel); - if (horizUnits.equals(vertUnits)) - { - setAxisUnits(horizUnits, vertUnits); - } - else - { - setAxisUnits(horizUnits + AMath.DOT + vertUnits, vertUnits); - } - break; - - case TYPE_X_SKEW_TRANSFORM: - setAxisLabels(AMath.DELTA + horizLabel, vertLabel + AMath.PRIME); - if (vertUnits.equals(horizUnits)) - { - setAxisUnits(horizUnits, vertUnits); - } - else - { - setAxisUnits(horizUnits, vertUnits + AMath.DOT + horizUnits); - } - break; - - case TYPE_SWITCHED_Y_SKEW_TRANSFORM: - setAxisLabels(vertLabel + AMath.PRIME, AMath.DELTA + horizLabel); - if (vertUnits.equals(horizUnits)) - { - setAxisUnits(vertUnits, horizUnits); - } - else - { - setAxisUnits(vertUnits + AMath.DOT + horizUnits, horizUnits); - } - break; - - case TYPE_SWITCHED_X_SKEW_TRANSFORM: - setAxisLabels(AMath.DELTA + vertLabel, horizLabel + AMath.PRIME); - if (horizUnits.equals(vertUnits)) - { - setAxisUnits(vertUnits, horizUnits); - } - else - { - setAxisUnits(vertUnits, horizUnits + AMath.DOT + vertUnits); - } - break; - - default: - setAxisLabels(horizLabel + AMath.PRIME, vertLabel + AMath.PRIME); - if (horizUnits.equals(vertUnits)) - { - setAxisUnits(horizUnits, vertUnits); - } - else - { - setAxisUnits(horizUnits + AMath.DOT + vertUnits, vertUnits + AMath.DOT + horizUnits); - } - break; - } - - // Get the size of the scales. - axisPts[0] = 0.; - axisPts[1] = panelHeight; - axisPts[2] = 0.; - axisPts[3] = panelHeight; - axisPts[4] = panelWidth; - axisPts[5] = 0.; - try - { - // Avoid using the following call because of a bug in - // AffineTransform. Instead create the inverse matrix - // explicitly as done below. - // transform.inverseTransform(physicsPt,0,physicsPt,0,3); - AffineTransform ixform = transform.createInverse(); - - ixform.transform(axisPts, 0, axisPts, 0, 1); - ixform.deltaTransform(axisPts, 2, axisPts, 2, 2); - - // Calculate the values for the vertical axis and the distance. - double vdy = axisPts[3]; - double vdx = axisPts[2]; - double vdist = Math.sqrt(vdx * vdx + vdy * vdy); - - // Calculate the values for the horizontal axis and the distance. - double hdy = axisPts[5]; - double hdx = axisPts[4]; - double hdist = Math.sqrt(hdx * hdx + hdy * hdy); - - // Initialize the endpoints of the axes. - double vmin = 0.; - double vmax = 0.; - double hmin = 0.; - double hmax = 0.; - - // Do what is necessary for the different types of transformations. - switch (type) - { - case (TYPE_PARALLEL_TRANSFORM): - { - double vsign = (vdy < 0.) ? 1. : -1.; - - vmin = axisPts[1]; - vmax = axisPts[1] + vsign * vdist; - - double hsign = (hdx > 0.) ? 1. : -1.; - - hmin = axisPts[0]; - hmax = axisPts[0] + hsign * hdist; - break; - } - - case (TYPE_SWITCHED_TRANSFORM): - { - double hsign = (hdy > 0.) ? 1. : -1.; - - hmin = axisPts[1]; - hmax = axisPts[1] + hsign * hdist; - - double vsign = (vdx < 0.) ? 1. : -1.; - - vmin = axisPts[0]; - vmax = axisPts[0] + vsign * vdist; - break; - } - - case (TYPE_Y_SKEW_TRANSFORM): - { - double vsign = (vdy > 0.) ? 1. : -1.; - - vmax = -vsign * vdist / 2.; - vmin = -vmax; - - hmin = 0.; - hmax = hdist; - break; - } - - case (TYPE_X_SKEW_TRANSFORM): - { - double hsign = (hdx > 0.) ? 1. : -1.; - - hmax = hsign * hdist / 2.; - hmin = -hmax; - - vmin = 0.; - vmax = vdist; - break; - } - - case (TYPE_SWITCHED_Y_SKEW_TRANSFORM): - { - double vsign = (vdx > 0.) ? 1. : -1.; - - vmax = -vsign * vdist / 2.; - vmin = -vmax; - - hmin = 0.; - hmax = hdist; - break; - } - - case (TYPE_SWITCHED_X_SKEW_TRANSFORM): - { - double hsign = (hdy > 0.) ? 1. : -1.; - - hmax = hsign * hdist / 2.; - hmin = -hmax; - - vmin = 0.; - vmax = vdist; - break; - } - - default: - { - vmin = 0.; - vmax = 0.; - hmin = 0.; - hmax = 0.; - break; - } - } - - // Actually set the limits. - setLimits(hmin, hmax, vmin, vmax); - } - catch (NoninvertibleTransformException e) - { - setLimits(0., 0., 0., 0.); - } - } - - /** - * This is a protected utility method which classifies the given transform - * into seven categories: parallel, switched, x-skew, y-skew, switched - * x-skew, switched y-skew, and general. The parallel category describes - * transformations in which the transformed x and y axes are parallel or - * antiparallel to the original x and y axes, respectively. The switched - * category describes transformations in which the transformed x and y axes - * are parallel or antiparallel to the original y and x axes, respectively. - * That is, the x and y axes have been switched. The x-skew describes - * transformations in which the transformed x-axis is parallel (or - * antiparallel) to the original one while the transformed y-axis forms some - * non-zero angle to the original one. The y-skew is similar; the switch - * skews are just rotated (counter)clockwise by 90 degrees. The general - * category encompasses all transforms not falling into one of the other - * categories. - */ - static protected int classifyTransform(AffineTransform xform) - { - // Set the default return type to a general matrix. - int category = TYPE_GENERAL_TRANSFORM; - - // Get the four non-translation quantities from the transformation. - double sx = xform.getScaleX(); - double sy = xform.getScaleY(); - double kx = xform.getShearX(); - double ky = xform.getShearY(); - - // Check the type. - if (kx == 0. && ky == 0.) - { - category = TYPE_PARALLEL_TRANSFORM; - } - else if (sx == 0. && sy == 0.) - { - category = TYPE_SWITCHED_TRANSFORM; - } - else if (kx == 0.) - { - category = TYPE_Y_SKEW_TRANSFORM; - } - else if (ky == 0.) - { - category = TYPE_X_SKEW_TRANSFORM; - } - else if (sx == 0.) - { - category = TYPE_SWITCHED_Y_SKEW_TRANSFORM; - } - else if (sy == 0.) - { - category = TYPE_SWITCHED_X_SKEW_TRANSFORM; - } - - // Return the transformtion type. - return category; - } - - /** - * A utility which makes an AffineTransform given three corner - * points. The first point must be the upper, left-hand corner - * point, the second, the upper, right-hand corner point, and the - * third, the lower, right-hand corner point. - * - * @return AffineTransform which does the appropriate mapping */ - protected AffineTransform makeTransform(Point2D.Double[] corners) - { - double x0 = corners[0].x; - double y0 = corners[0].y; - double x1 = corners[1].x; - double y1 = corners[1].y; - double x2 = corners[2].x; - double y2 = corners[2].y; - - double sx = 0.; - double kx = 0.; - double tx = 0.; - double sy = 0.; - double ky = 0.; - double ty = 0.; - - double delta = (x2 * (y1 - y0) - x1 * (y2 - y0) + x0 * (y2 - y1)); - - if (delta == 0) - { - // cannot successfully create an AffineTransform - System.err.println("Fatal Error: AffineTransform creating failed."); - System.err.println("Possible cause: wrong user corner values are set."); - System.exit(1); - return null; - } - else - { - delta = 1. / delta; - - double w = aWindow.getWidth(); - double h = aWindow.getHeight(); - - sx = -(delta * w) * (y2 - y1); - kx = (delta * w) * (x2 - x1); - tx = -(x0 * sx + y0 * kx); - - ky = (delta * h) * (y1 - y0); - sy = -(delta * h) * (x1 - x0); - ty = -(x0 * ky + y0 * sy); - - return new AffineTransform(sx, ky, kx, sy, tx, ty); - } - - } - - public void drawString(Graphics2D g, String str, double x, double y, int horizontal, int vertical, int maxSize) - { - drawString(g, str, x, y, horizontal, vertical, false, null, 0, false, null, maxSize); - } - - private void drawString(Graphics2D g, String str, double x, double y, int horizontal, int vertical, boolean framed, Color frameColor, double frameWidth, boolean banner, Color bannerColor, int maxSize) - { - Font sf = g.getFont(); - int width = sf.getSize(); - int descent = 0; - int height = sf.getSize(); - int adjustment = 0; - - // The metrics stuff did not work, so I made a work around and now - // even ps-printing works (CT 27/7/2004) - double xx = Math.min(x, maxSize - width / 2); - Rectangle textSize = new Rectangle(0, descent - height, width, height); - Point2D textUL = drawFrameAndBanner(xx, y, textSize, adjustment, framed, frameColor, frameWidth, banner, bannerColor, horizontal, vertical); - - if (g instanceof AAbstractGraphics2D) { - // No antialiasing support needed for EPS output. - g.drawString(str, (int) textUL.getX(), (int) textUL.getY()); - } else { - // For pixel graphics, switch on antialiasing for text. - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g.drawString(str, (int) textUL.getX(), (int) textUL.getY()); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - } - } - - /** Draws frame and banner around a string. The method calculates and returns - * the point to which the text curser should be set before drawing the string. */ - private Point2D drawFrameAndBanner(double x, double y, Rectangle textSize, int adjustment, boolean framed, Color frameColor, double frameWidth, boolean banner, Color bannerColor, int horizontal, int vertical) - { - double descent = textSize.y + textSize.height; - x = getXalignment(x, textSize.width, horizontal); - y = getYalignment(y, textSize.height, (int) descent, vertical); - return new Point2D.Double(x, y); - } - - private static double getYalignment(double y, int ascent, int descent, int alignment) - { - // vertical alignment - switch (alignment) - { - case TEXT_TOP: - y = y + ascent - descent; - break; - - case TEXT_CENTER: - y = y + ((ascent + descent) / 2) - descent; - break; - - case TEXT_BOTTOM: - y = y - descent; - break; - - case TEXT_BASELINE: - default: - break; - } - return y; - } - - private static double getXalignment(double x, int width, int alignment) - { - // horizontal alignment - switch (alignment) - { - case TEXT_CENTER: - x = x - (width / 2); - break; - - case TEXT_RIGHT: - x = x - width; - break; - - case TEXT_LEFT: - default: - break; - } - return x; - } - - /** - * Encapsulates units and range for an axis. - * Used for m->cm->mm->um autoscaling. - */ - private static class ScaleUnits { - final String units; - final double scaleFactor; - - ScaleUnits(String units, double min, double max) { - double maxMod = Math.max(Math.abs(max), Math.abs(min)); - if (!units.equals("(cm)")) { - this.units = units; - this.scaleFactor = 1.0; - return; - } - else { - if (maxMod > 200.) - { - this.scaleFactor= 0.01; - this.units = "(m) "; - } - else if (maxMod > 2.) - { - this.scaleFactor = 1.0; - this.units = "(cm)"; - } - else if (maxMod > .2) - { - this.scaleFactor = 10.; - this.units = "(mm)"; - } - else - { - this.scaleFactor = 10000.; - this.units = "(" + AMath.MICRO + "m)"; - } - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/ATitleMenuBar.java b/graphics/AtlantisJava/src/atlantis/canvas/ATitleMenuBar.java deleted file mode 100755 index 85ad9daab25..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/ATitleMenuBar.java +++ /dev/null @@ -1,92 +0,0 @@ -package atlantis.canvas; - -import javax.swing.JLabel; -import javax.swing.JMenuBar; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.graphics.AGraphics; -import atlantis.parameters.APar; - - -public class ATitleMenuBar extends JMenuBar -{ - - public ATitleMenuBar() - { - // just to set the height of the title bar - - JLabel atlas = new JLabel(" Atlantis "); - atlas.setFont(new Font("Courier", Font.PLAIN, 25)); - add(atlas); - } - - @Override - public void paint(Graphics g) - { - AEventManager eventManager = AEventManager.instance(); - AEvent event = eventManager.getCurrentEvent(); - Font titleFont=new Font("Dialog", Font.BOLD, 15); - int availableSpace = (int) Math.floor(getWidth()-10); - FontMetrics fm = ACanvas.getCanvas().getFontMetrics(titleFont); - - AGraphics ag=AGraphics.makeAGraphics(g); - ag.setColor(AWindow.BORDER_BACKGROUND_COLOR); - ag.fillRect(0, 0, getWidth(), getHeight()); - ag.setColor(AWindow.BORDER_FOREGROUND_COLOR); - ag.updateColor(); - ag.setFont(titleFont); - availableSpace -= fm.stringWidth("ATLAS Atlantis"); - ag.drawString("ATLAS ", 5, getHeight()-10); - ag.drawString(" Atlantis", getWidth()-fm.stringWidth(" Atlantis")-5, getHeight()-10); - - String[] titleSections = new String[6]; - if(event != null) - { - titleSections[0] = !event.getDateTime().equals("n/a") ? event.getDateTime() : ""; - titleSections[1] = " source:" + event.getSourceName(); - int extension_dot = titleSections[1].toLowerCase().lastIndexOf("."); - if(extension_dot > 0) - titleSections[1] = titleSections[1].substring(0,extension_dot); - titleSections[2] = " run:" + event.getRunNumber(); - titleSections[3] = " ev:" + event.getEventNumber(); - titleSections[4] = " lumiBlock:" + event.getLumiBlock(); - titleSections[5] = " eventProperties: " + event.getEventProperties(); - } - else - { - titleSections[0]=""; - titleSections[1]=" event:n/a"; - titleSections[2]=" run:n/a"; - titleSections[3]=" ev:n/a"; - titleSections[4]=""; - titleSections[5]=""; - } - - - //for masterclass turn off some of the canvas title parts - APar parameterStore = APar.instance(); - if(parameterStore.get("Minerva","hiderun").getStatus()) - titleSections[2]=""; - if(parameterStore.get("Minerva","hideev").getStatus()) - titleSections[3]=""; - - - StringBuilder outputString = new StringBuilder(); - int titleSectionSize=0; - for(int i=0; i<6; i++) - { - if(titleSectionSize+fm.stringWidth(titleSections[i])<availableSpace) - { - if(!titleSections[i].endsWith("default")){ - titleSectionSize+=fm.stringWidth(titleSections[i]); - outputString.append(titleSections[i]); - } - } - } - ag.drawString(outputString.toString(), (getWidth()-titleSectionSize)/2, getHeight()-10); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AWindow.java b/graphics/AtlantisJava/src/atlantis/canvas/AWindow.java deleted file mode 100755 index 159623e227c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AWindow.java +++ /dev/null @@ -1,1549 +0,0 @@ -package atlantis.canvas; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsEnvironment; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceEvent; -import java.awt.dnd.DragSourceListener; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetEvent; -import java.awt.dnd.DropTargetListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.Point2D; -import java.awt.geom.Point2D.Double; -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; - -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.Stack; -import java.util.Vector; - -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JSeparator; -import javax.swing.JToolTip; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.dnd.ACallBack; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.AObjectTransferable; -import atlantis.gui.AColorHelpDialog; -import atlantis.gui.AInteractionToolBar; -import atlantis.gui.APreferencesControl; -import atlantis.interactions.AInteraction; -import atlantis.interactions.AInteractionsManager; -import atlantis.interactions.ASelection; -import atlantis.interactions.ARectangleVPSelection; -import atlantis.interactions.ARectangleYXSelection; -import atlantis.interactions.AZMRInteraction; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionNPhysics; -import atlantis.projection.AProjectionTrackResidual; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.AMath; - -import atlantis.utils.ALogger; -import java.awt.BorderLayout; -import javax.swing.JComponent; - -/** - * The objects of this class are single windows managed by ACanvas - * This class manages the painting of each picture and is always - * called by the java awt event thread. Programatic requests for - * picture updates are handled by calls to repaintFromScratch() which - * adds requests to the awt event thread. - * It paints first into an off-screen buffer which is then copied - * onto the screen. - * It handles the linear transformation from user to display - * coordinates and vice-versa. Non-linear transformations are handled by - * by the projections. Windows have a scale (and scale border) which - * may be visible or not. Each window has an associated projection - * and an interactionManager which knows about the current interaction - * and the state of all other interactions for this window. - * - * @author taylorg - */ -public class AWindow extends JPanel implements DropTargetListener, - DragSourceListener, DragGestureListener, ACallBack -{ - - private static ALogger logger = ALogger.getLogger(AWindow.class); - private static AGlobals globals = AGlobals.instance(); - - //Whether horizontal or vertical scale is copied when window is dragged - private static enum dragActionType { COPY_VERTICAL_SCALE, COPY_HORIZONTAL_SCALE }; - - //these colors are used on the scale border and title bar - static final Color BORDER_FOREGROUND_COLOR = new Color(48,48,48); - static final Color BORDER_SELECTED_FOREGROUND_COLOR = new Color(48,48,48); - static final Color BORDER_SELECTED_FRAME_COLOR = new Color(99,130,191); - static final Color BORDER_SELECTED_FRAMELIGHT_COLOR = new Color(255,255,255); - // These ones must be public and cannot be final because AOpenGLControl messes with them. - public static Color BORDER_BACKGROUND_COLOR = new Color(224,224,224); - public static Color BORDER_SELECTED_BACKGROUND_COLOR = new Color(200,221,242); - private dragActionType dragAction; - private boolean canCopyScales = false; - private DragSource dragSource = null; - private Graphics2D backingGraphics = null; - private BufferedImage backingImage = null; - private Dimension backingDimension = new Dimension(); - - /** - * The border of the window holds a scale with units - **/ - private AScaleBorder scaleBorder; - - private boolean bufferValid = false; - private boolean borderValid = false; - private Insets insets = new Insets(0, 0, 0, 0); - private double m00, m01, m02, m10, m11, m12, n00, n01, n02, n10, n11, n12; - private AInteractionsManager interactionsManager; - private Hashtable<String, Double[]> corners; - private Point2D.Double[] userCorners; - private Point2D.Double[] defaultCorners; - private AProjection projection; - private String group; - private String defaultGroup; - private String defaultProjectionName; - private int index; - boolean finalized; - private Stack<Point2D.Double[]> cornersHistory = new Stack<Point2D.Double[]>(); - private AProjection projectionHistory = null; - private Stack<Integer> zoomSummed = new Stack<Integer>(); - private Stack<Integer> zoomLayers = new Stack<Integer>(); - private Stack<Integer> zoomCalo = new Stack<Integer>(); - private Stack<Integer> zoomCaloLAr = new Stack<Integer>(); - private Stack<Integer> modeHistory = new Stack<Integer>(); - private Stack<Integer> cutHistoryLAr = new Stack<Integer>(); - private Stack<Integer> cutHistoryHEC = new Stack<Integer>(); - private Stack<Integer> layoutHistory = new Stack<Integer>(); - private boolean locked; - private static JPopupMenu popupMenu; - private final static String LOCK = "Freeze"; - private final static String UNLOCK = "Unfreeze"; - private final static String HORIZONTAL_FLIP = "Horizontal Flip"; - private final static String VERTICAL_FLIP = "Vertical Flip"; - private final static String ROTATE_BY_90_CLOCKWISE = "Rotate by 90"; - private final static String ROTATE_BY_90_ANTICLOCKWISE = "Rotate by -90"; - private final static String TOGGLE_SCALE = "Toggle Scale"; - private final static String RESTORE_DEFAULTS = "Restore Initial Size"; - - private JComponent m_view = null; - - static - { - popupMenu = new JPopupMenu(); - ActionListener actionListener = new PopupMenuActionListener(); - popupMenu.add(HORIZONTAL_FLIP).addActionListener(actionListener); - popupMenu.add(VERTICAL_FLIP).addActionListener(actionListener); - popupMenu.add(new JSeparator()); - popupMenu.add(ROTATE_BY_90_CLOCKWISE).addActionListener(actionListener); - popupMenu.add(ROTATE_BY_90_ANTICLOCKWISE).addActionListener( - actionListener); - popupMenu.add(new JSeparator()); - popupMenu.add(TOGGLE_SCALE).addActionListener(actionListener); - popupMenu.add(RESTORE_DEFAULTS).addActionListener(actionListener); - popupMenu.add(LOCK).addActionListener(actionListener); - popupMenu.add(UNLOCK).addActionListener(actionListener); - } - - - private static class PopupMenuActionListener - implements ActionListener - { - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - AWindow window = ACanvas.getCanvas().getCurrentWindow(); - if(action.equals(LOCK)) - { - window.setLocked(true); - } - else if(action.equals(UNLOCK)) - { - window.setLocked(false); - } - else if(action.equals(TOGGLE_SCALE)) - { - window.toggleScale(); - } - // temporary fix to avoid crashes - if(window.getProjection() instanceof AProjection2D) - { - if(action.equals(RESTORE_DEFAULTS)) - { - window.unzoomFull(); - } - else if(action.equals(HORIZONTAL_FLIP)) - { - AZMRInteraction.performFlip(AZMRInteraction. - getMiddleVerticalLine(window), - window); - } - else if(action.equals(VERTICAL_FLIP)) - { - AZMRInteraction.performFlip(AZMRInteraction. - getMiddleHorizontalLine(window), - window); - } - else if(action.equals(ROTATE_BY_90_CLOCKWISE)) - { - AZMRInteraction.performPlus90Rotation(window); - } - else if(action.equals(ROTATE_BY_90_ANTICLOCKWISE)) - { - AZMRInteraction.performMinus90Rotation(window); - } - } - } - } - - /** - * Construct AWindow using information in XML configuration file. - * - * @param node the XML configuration node for this window - * @param index identifier for the window - * @return the constructed window - */ - static AWindow createFromXMLConfigNode(Node node, int index) { - NamedNodeMap attributes = node.getAttributes(); - String name = attributes.getNamedItem("name").getNodeValue(); - String defaultProjectionName = attributes.getNamedItem("projection"). - getNodeValue(); - String defaultGroup = attributes.getNamedItem("group").getNodeValue(); - return new AWindow(name,defaultProjectionName,defaultGroup,index); - } - - /** - * Construct AWindow with given name, default projection and group name. - * Only non-private in order to allow test code to create an AWindow instance. - * - * @param name title of window - * @param defaultProjection name of default projection - * @param defaultGroup name of group - * @param index identifier for window - */ - AWindow(String name, String defaultProjection, String defaultGroup, int index) - { - super(new BorderLayout()); - setName(name); - this.defaultProjectionName = defaultProjection; - this.defaultGroup = defaultGroup; - setOpaque(false); - if (!globals.getUseOpenGL()) { - m_view = new AWindowSwingView(this); - } else { - m_view = new AWindowGLView(this); - } - this.index = index; - scaleBorder = new AScaleBorder(this); - scaleBorder.setLabelFont(new Font("Dialog", Font.PLAIN, 12)); - m_view.setBorder(scaleBorder); - add(m_view, BorderLayout.CENTER); - finalized = false; - - if (!AGlobals.isAtlantisHeadless()) { - dragSource = new DragSource(); - dragSource.createDefaultDragGestureRecognizer(this, - DnDConstants.ACTION_MOVE, this); - - this.setDropTarget(new DropTarget(this, this)); - } - } - - /** - * Perform the steps that have to follow the ACanvas initialization. - * Despite its name, this method is called from ACanvas.setCurrentLayout() - * so may be called multiple times on the same window. - */ - void finalizeConstruction() - { - setInteractionManager(new AInteractionsManager(this)); - corners = new Hashtable<String, Double[]>(); - String[] pName = AProjectionsManager.getKnownProjectionNames(); - Point2D.Double[] pCorners; - ALayout l = ACanvas.getCanvas().getCurrentLayout(); - Dimension size = l.getWindowConstraints(getName()).getSize(); - for(int i = 0; i < pName.length; i++) - { - AProjection proj = AProjectionsManager.getProjection(pName[i]); - if(proj instanceof AProjection2D) - { - pCorners = ((AProjection2D) proj).calculateNoZoomCorners(size); - corners.put(pName[i], pCorners); - } - } - AProjection defaultProjection = AProjectionsManager.getProjection( - defaultProjectionName); - setGroup(defaultGroup); - setProjection(defaultProjection); - - if (!AGlobals.isAtlantisHeadless()) { - interactionsManager.setContext(getInteractionToolBar().getSelectedGroup()); - } - - finalized = true; - } - - - void restoreDefaults() - { - if(finalized) - { - corners = new Hashtable<String, Double[]>(); - String[] pName = AProjectionsManager.getKnownProjectionNames(); - Point2D.Double[] pCorners; - ALayout l = ACanvas.getCanvas().getCurrentLayout(); - Rectangle r = l.getWindowConstraints(getName()); - Dimension size = new Dimension(1, 1); - if(r != null) - size = r.getSize(); - for(int i = 0; i < pName.length; i++) - { - AProjection proj = AProjectionsManager.getProjection(pName[i]); - if(proj instanceof AProjection2D) - { - if(pName[i].equals(defaultProjectionName) && defaultCorners != null) - pCorners = getDefaultCorners(); - else - pCorners = ((AProjection2D) proj).calculateNoZoomCorners(size); - corners.put(pName[i], pCorners); - } - } - AProjection defaultProjection = AProjectionsManager.getProjection( - defaultProjectionName); - setGroup(defaultGroup); - projection = null; - setProjection(defaultProjection); - getInteractionManager().forgetContext(); - AInteractionToolBar itb = getInteractionToolBar(); - if (itb != null) { - itb.setDefaultGroup(); - interactionsManager.setContext(itb.getSelectedGroup()); - } - setScaleStatus(true); - } - } - - - public boolean isCurrent() - { - return ACanvas.getCanvas().getCurrentWindowName().equals(getName()); - } - - - public static JPopupMenu getPopupMenu() - { - return popupMenu; - } - - - public int getIndex() - { - return index; - } - - - public String getGroupName() - { - return group; - } - - - public void setGroup(String group) - { - this.group = group; - this.fireGroupChange(); - } - - - public synchronized AProjection getProjection() - { - return projection; - } - - - public AInteractionToolBar getInteractionToolBar() - { - return AInteractionToolBar.getInteractionToolBar(getName(), - projection.getName()); - } - - - public synchronized void setProjection(AProjection newProjection) - { - if((projection == null) || (!newProjection.equals(projection)) - || (newProjection instanceof AProjectionTrackResidual) - || (newProjection instanceof AProjectionNPhysics)) - { - if(projection != null && projection instanceof AProjection2D) - corners.put(projection.getName(), userCorners); - this.projection = newProjection; - if(projection instanceof AProjection2D) - userCorners = (Point2D.Double[]) corners.get(projection.getName()); - //check to see if the scales need hiding or not - this.scaleBorder.hideScale(); - this.repaintFromScratch(); - this.fireProjectionChange(); - } - } - - - private Point2D.Double[] clonedCopy(Point2D.Double[] corners) - { - if(corners == null)return null; - Point2D.Double[] newCorners = new Point2D.Double[corners.length]; - for(int i = 0; i < corners.length; i++) - newCorners[i] = new Point2D.Double(corners[i].x, corners[i].y); - return newCorners; - } - - - public synchronized void setUserCorners(Point2D.Double[] corners) - { - if(projection != null) - { - Point2D.Double[] validCorners = null; - try - { - validCorners = ((AProjection2D) projection).validateCorners( - clonedCopy(corners)); - } - catch(ClassCastException e) - { - logger.error("Not a 2D projection..."); - validCorners = corners; - } - if(validCorners != null) - { - this.userCorners = validCorners; - if(ACanvas.getCanvas().customisedCorner) - { - this.defaultCorners = validCorners; - } - repaintFromScratch(); - } - } - } - - - public boolean getUnzoomPossible() - { - if(zoomSummed.size()>0 && ((Integer) zoomSummed.peek()).intValue()==cornersHistory.size()) - return false; - else if(zoomLayers.size()>0 && ((Integer) zoomLayers.peek()).intValue()==cornersHistory.size()) - return false; - else if(zoomCalo.size()>0 && ((Integer) zoomCalo.peek()).intValue()==cornersHistory.size()) - return false; - else if(zoomCaloLAr.size()>0 && ((Integer) zoomCaloLAr.peek()).intValue()==cornersHistory.size()) - return false; - else - return projection == projectionHistory && cornersHistory.size() > 0; - } - - public boolean getUnzoomFullPossible() - { - return projection == projectionHistory && cornersHistory.size() > 0; - } - - - public boolean getUnzoomAllPossible(String typeOfZoom) - { - if(cornersHistory.size()<=0) - return false; - else if(ARectangleVPSelection.ZOOM_LAR.equals(typeOfZoom) || - ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - int indexOfZoomCalo=-1; - if(zoomCalo.size()>0) - indexOfZoomCalo=((Integer) zoomCalo.peek()).intValue(); - int indexOfZoomCaloLAr=-1; - if(zoomCaloLAr.size()>0) - indexOfZoomCaloLAr=((Integer) zoomCaloLAr.peek()).intValue(); - //make sure summed/layers is last in list - if(ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom) && - indexOfZoomCalo > indexOfZoomCaloLAr) - { - return true; - } - else if(typeOfZoom.equals(ARectangleVPSelection.ZOOM_LAR) && - indexOfZoomCaloLAr > indexOfZoomCalo) - { - return true; - } - else - return false; - } - else - { - int indexOfZoomSummed=-1; - if(zoomSummed.size()>0) - indexOfZoomSummed=((Integer) zoomSummed.peek()).intValue(); - int indexOfZoomLayers=-1; - if(zoomLayers.size()>0) - indexOfZoomLayers=((Integer) zoomLayers.peek()).intValue(); - //make sure summed/layers is last in list - if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_SUMMED) && indexOfZoomSummed>indexOfZoomLayers) - { - return true; - } - else if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_LAYERS) && indexOfZoomLayers>indexOfZoomSummed) - { - return true; - } - else - return false; - } - } - - - public void unzoom(String typeOfZoom) - { - //do unzoom of which item is selected - int numberOfWindows=0,indexOfZoom; - if(typeOfZoom.equals(ARectangleVPSelection.ZOOM_LAR) || - typeOfZoom.equals(ARectangleYXSelection.ZOOM_SUMMED)) - { - numberOfWindows=4; - } - else if(ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom) || - typeOfZoom.equals(ARectangleYXSelection.ZOOM_LAYERS)) - { - numberOfWindows=8; - } - int numberOfUnlayouts=0; - for (int i = 0; i < numberOfWindows; i++) - { - String wName = Integer.toString(i+1); - AWindow w = ACanvas.getCanvas().getWindow(wName); - //find if can do unzoom and what index it is - indexOfZoom=findUnzoomIndex(typeOfZoom, w); - if(indexOfZoom>0) - { - //do all unzooms upto and including index of this zoom to unzoom - while(w.cornersHistory.size()>=indexOfZoom) - w.unzoom(); - //also need to reset parameters - setParameters(typeOfZoom, w, wName); - //find out how many unlayouts to do - int count=0; - while(w.layoutHistory.size()>0 && ((Integer)w.layoutHistory.peek()).intValue()>=indexOfZoom) - { - w.layoutHistory.pop(); - count++; - } - if(count>numberOfUnlayouts) - numberOfUnlayouts=count; - } - } - //do as many unlayouts as needed - for(int i=0; i<numberOfUnlayouts; i++) - ACanvas.getCanvas().unlayout(); - } - - - private int findUnzoomIndex(String typeOfZoom, AWindow w) - { - int indexOfZoom=0;//if returns 0 then no unzoom is to be performed - if(ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - if(w.zoomCalo.size()==0) - indexOfZoom=0; - else - { - indexOfZoom=((Integer) w.zoomCalo.pop()).intValue(); - //check if other zooms done on this window - while(w.zoomCaloLAr.size()>0 && ((Integer) w.zoomCaloLAr.peek()).intValue()>indexOfZoom) - { - w.zoomCaloLAr.pop(); - w.modeHistory.pop(); - } - } - } - else if(typeOfZoom.equals(ARectangleVPSelection.ZOOM_LAR)) - { - if(w.zoomCaloLAr.size()==0) - indexOfZoom=0; - else - { - indexOfZoom=((Integer) w.zoomCaloLAr.pop()).intValue(); - while(w.zoomCalo.size()>0 && ((Integer) w.zoomCalo.peek()).intValue()>indexOfZoom) - { - w.zoomCalo.pop(); - w.modeHistory.pop(); - } - } - } - if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_SUMMED)) - { - if(w.zoomSummed.size()==0) - indexOfZoom=0; - else - { - indexOfZoom=((Integer) w.zoomSummed.pop()).intValue(); - //check if other zooms done on this window - while(w.zoomLayers.size()>0 && ((Integer) w.zoomLayers.peek()).intValue()>indexOfZoom) - { - w.zoomLayers.pop(); - w.modeHistory.pop(); - w.cutHistoryHEC.pop(); - w.cutHistoryLAr.pop(); - } - } - } - else if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_LAYERS)) - { - if(w.zoomLayers.size()==0) - indexOfZoom=0; - else - { - indexOfZoom=((Integer) w.zoomLayers.pop()).intValue(); - while(w.zoomSummed.size()>0 && ((Integer) w.zoomSummed.peek()).intValue()>indexOfZoom) - { - w.zoomSummed.pop(); - w.modeHistory.pop(); - w.cutHistoryHEC.pop(); - w.cutHistoryLAr.pop(); - } - } - } - return indexOfZoom; - } - - - private void setParameters(String typeOfZoom, AWindow w, String wName) - { - APar parameterStore = APar.instance(); - parameterStore.selectWindowParameters(wName); - if(ARectangleVPSelection.ZOOM_LAR.equals(typeOfZoom) || - ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - parameterStore.get("VP", "Mode").setI( w.modeHistory.pop() ); - } - else - { - parameterStore.get("YX", "Mode").setI( w.modeHistory.pop() ); - parameterStore.get("CutsCalo","HEC").setI( w.cutHistoryHEC.pop() ); - parameterStore.get("CutsCalo","LAr").setI( w.cutHistoryLAr.pop() ); - } - parameterStore.restoreWindowParameters(); - } - - - public void saveParameters(String typeOfZoom) - { - APar parameterStore = APar.instance(); - //save window parameters of current windows - if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_SUMMED) || typeOfZoom.equals(ARectangleYXSelection.ZOOM_LAYERS)) - { - parameterStore.selectWindowParameters(this.getName()); - this.modeHistory.push(new Integer(parameterStore.get("YX", "Mode").getI())); - this.cutHistoryHEC.push(new Integer(parameterStore.get("CutsCalo","HEC").getI())); - this.cutHistoryLAr.push(new Integer(parameterStore.get("CutsCalo","LAr").getI())); - parameterStore.restoreWindowParameters(); - } - else if(ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom) || - ARectangleVPSelection.ZOOM_LAR.equals(typeOfZoom)) - { - parameterStore.selectWindowParameters(this.getName()); - this.modeHistory.push(new Integer(parameterStore.get("VP", "Mode").getI())); - parameterStore.restoreWindowParameters(); - } - } - - - public void unzoomFull() - { - //perform unzoom to initial state - setUserCorners(((AProjection2D) getProjection()).calculateNoZoomCorners(getSize())); - //clear all variables for this window - cornersHistory.clear(); - zoomSummed.clear(); - zoomLayers.clear(); - zoomCaloLAr.clear(); - zoomCalo.clear(); - layoutHistory.clear(); - modeHistory.clear(); - cutHistoryHEC.clear(); - cutHistoryLAr.clear(); - } - - - public void unzoom() - { - if(projection == projectionHistory && cornersHistory.size() > 0) - { - setUserCorners((Point2D.Double[]) (cornersHistory.pop())); - } - } - - - public void saveLayout() - { - if(userCorners != null) - { - ACanvas.getCanvas().saveLayout(); - } - } - - - public void saveCorners() - { - if(projection != projectionHistory) - { - cornersHistory.clear(); - String wName = this.getName(); - int temp; - if(wName.equals("1") || wName.equals("2") || wName.equals("3") || wName.equals("4") || - wName.equals("5") || wName.equals("6") || wName.equals("7") || wName.equals("8")) - { - zoomSummed.clear(); - zoomLayers.clear(); - zoomCaloLAr.clear(); - zoomCalo.clear(); - layoutHistory.clear(); - //will have already done saveParameters so only - //want the last saved parameters of mode and cuts - if(modeHistory.size()>0) - { - temp = ((Integer) modeHistory.pop()).intValue(); - modeHistory.clear(); - modeHistory.push(new Integer(temp)); - } - - if(cutHistoryHEC.size()>0) - { - temp = ((Integer) cutHistoryHEC.pop()).intValue(); - cutHistoryHEC.clear(); - cutHistoryHEC.push(new Integer(temp)); - } - - if(cutHistoryLAr.size()>0) - { - temp = ((Integer) cutHistoryLAr.pop()).intValue(); - cutHistoryLAr.clear(); - cutHistoryLAr.push(new Integer(temp)); - } - } - } - projectionHistory = projection; - if(userCorners != null) - { - cornersHistory.push(clonedCopy(userCorners)); - } - } - - - public void saveCorners(String typeOfZoom) - { - saveCorners(); - //save zoom just done - if(userCorners != null) - { - if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_SUMMED)) - { - zoomSummed.push(new Integer(cornersHistory.size())); - } - else if(typeOfZoom.equals(ARectangleYXSelection.ZOOM_LAYERS)) - { - zoomLayers.push(new Integer(cornersHistory.size())); - } - else if(ARectangleVPSelection.ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - zoomCalo.push(new Integer(cornersHistory.size())); - } - else if(ARectangleVPSelection.ZOOM_LAR.equals(typeOfZoom)) - { - zoomCaloLAr.push(new Integer(cornersHistory.size())); - } - layoutHistory.push(new Integer(cornersHistory.size())); - } - } - - - public void setUserCornersNoRepaint(Point2D.Double[] corners) - { - Point2D.Double[] validCorners = ((AProjection2D) projection). - validateCorners(clonedCopy(corners)); - if(validCorners != null) - { - this.userCorners = validCorners; - } - } - - - public void setUserCorners(double x0, double x1, double y0, double y1) - { - Point2D.Double[] corners = new Point2D.Double[3]; - corners[0] = new Point2D.Double(x0, y1); - corners[1] = new Point2D.Double(x1, y1); - corners[2] = new Point2D.Double(x1, y0); - if(projection instanceof AProjection2D) corners = ((AProjection2D) - projection).validateCorners(corners); - if(corners != null) - this.userCorners = corners; - } - - - public Point2D.Double[] getDefaultCorners() - { - return clonedCopy(defaultCorners); - } - - - public Point2D.Double[] getUserCorners() - { - return clonedCopy(userCorners); - } - - - public void setInteractionManager(AInteractionsManager interactionsManager) - { - this.interactionsManager = interactionsManager; - //Make the interactions Manager aware of canvas changes - ACanvas.getCanvas().addParentWindowFocusListener(interactionsManager); - } - - - public void setScaleStatus(boolean statusWanted) - { - if(getScaleStatus() != statusWanted) toggleScale(); - } - - - public boolean getScaleStatus() - { - return scaleBorder.getScaleStatus(); - } - - - private void toggleScale() - { - scaleBorder.toggleScale(); - repaintFromScratch(); - } - - - public AInteractionsManager getInteractionManager() - { - return interactionsManager; - } - - - public void paintComponent(Graphics g) { - // Don't draw anything for ourself - } - - void paintWindow(Graphics g, boolean doubleBuffer) - { - if(!ACanvas.getCanvas().isReallyOnScreen(this)) - return; - //Why is this checked in paintComponent, and not already in - //setProjection() ? FIXIT / CLEANUP S.B - if(projection instanceof AProjectionTrackResidual) - { - if (((AProjectionTrackResidual) projection).getResidual() != null) - userCorners = ((AProjectionTrackResidual)projection).calculateNoZoomCorners(); - else - { - AOutput.append("\nTrackResidual Projection is not available, using YX instead in window " - + this.getName() + ".\n", ALogInterface.WARNING); - projection = AProjectionsManager.getProjection("YX"); - userCorners = (Point2D.Double[]) corners.get(projection.getName()); - } - } - - //Make sure the offscreen buffer is there if we need one - Graphics paint = g; - if (doubleBuffer) { - createOffScreenBuffer(); - paint = backingGraphics; - } - - // Means either we're using g or backingGraphics was something valid - if (paint != null) - { - if(!bufferValid) - { - setLocked(false); - paintWindowFromScratch(paint); - LinkedList<AInteraction> interactions = interactionsManager.getInteractions(); - for (int i = 0; i < interactions.size(); i++) { - if (interactions.get(i) instanceof ASelection) { - ((ASelection) interactions.get(i)).invalidate(); - } - } - bufferValid = true; - - } - - if (!isLocked() && !borderValid) { - //m_view.getBorder().paintBorder(paint); - borderValid = true; - } - - } - - // If we painted into a context which wasn't the target graphics context - // then we need to paint our buffer to the screen - if (g != paint) { - imageComponent(g); - } - - LinkedList<AInteraction> interactions = interactionsManager.getInteractions(); - for(int i = 0; i < interactions.size(); i++) - ((AInteraction) interactions.get(i)).paint((Graphics2D) g); - } - - // I suppose this function is intended to be called before every printing, - // but it is actually only called for EPS printing!!! FIX / CLEANUP S.B. - public void printComponent(Graphics g) - { - setLocked(false); - if(!ACanvas.getCanvas().isReallyOnScreen(this)) - return; - ((AScaleBorder) getView().getBorder()).forceDraw(); - //Double border painting needed here for EPS - probably something wrong in - //projection drawing -> graphics context left unclean? FIXIT. S.B. - ((AScaleBorder) getView().getBorder()).printBorder(this,g,this.getX(),this.getY(),this.getWidth(),this.getHeight()); - paintWindowFromScratch(g); - ((AScaleBorder) getView().getBorder()).printBorder(this,g,this.getX(),this.getY(),this.getWidth(),this.getHeight()); - borderValid = true; - LinkedList<AInteraction> interactions = interactionsManager.getInteractions(); - for(int i = 0; i < interactions.size(); i++) - { - AInteraction inter = (AInteraction) interactions.get(i); - if(inter.isPrintable()) - inter.paint((Graphics2D) g); - } - } - - - public void printBorder(Graphics g){} - - - // must call paint border myself since the border is backed too - public void paintBorder(Graphics g) - {} - - - public void repaintFromScratch() - { - if(locked)return; - bufferValid = false; - borderValid = false; - - // Check whether to draw scales on repaint - scaleBorder.hideScale(); - - // For some reason need to repaint the view too when using heavyweight - // component inside... - Adam - repaint(); - m_view.repaint(); - - } - - - // Attention: for efficiency this routine overwrites and returns its input - public ACoord calculateUser(ACoord user) - { - double[] h; - double[] v; - double hTemp; - double vTemp; - if(validTransform()) - { - for(int j = 0; j < user.hv[0].length; ++j) - { - h = user.hv[0][j]; - v = user.hv[1][j]; - for(int i = 0; i < h.length; ++i) - { - hTemp = h[i]; - vTemp = v[i]; - h[i] = m00 * hTemp + m01 * vTemp + m02; - v[i] = m10 * hTemp + m11 * vTemp + m12; - } - } - } - else - { - for(int j = 0; j < user.hv[0].length; ++j) - { - h = user.hv[0][j]; - v = user.hv[1][j]; - for(int i = 0; i < h.length; ++i) - { - h[i] = 0.; - v[i] = 0.; - } - } - } - return user; - } - - - public Point2D.Double calculateUser(double x, double y) - { - double[][][] hv = new double[2][1][1]; - hv[0][0][0] = x; - hv[1][0][0] = y; - ACoord p = calculateUser(new ACoord(hv)); - return new Point2D.Double(p.hv[0][0][0], p.hv[1][0][0]); - } - - - public Point2D.Double calculateUser(Point2D.Double p) - { - return calculateUser(p.x, p.y); - } - - - public Point2D.Double calculateUser(Point p) - { - return calculateUser(p.x, p.y); - } - - - // Attention! For efficiency this routine overwrites and returns its input - public ACoord calculateDisplay(ACoord user) - { - if(user == null) - return null; - double[] h; - double[] v; - double hTemp; - double vTemp; - if(validTransform()) - { - for(int j = 0; j < user.hv[0].length; ++j) - { - h = user.hv[0][j]; - v = user.hv[1][j]; - for(int i = 0; i < h.length; ++i) - { - hTemp = h[i]; - vTemp = v[i]; - h[i] = n00 * hTemp + n01 * vTemp + n02; - v[i] = n10 * hTemp + n11 * vTemp + n12; - } - } - } - else - { - for(int j = 0; j < user.hv[0].length; ++j) - { - h = user.hv[0][j]; - v = user.hv[1][j]; - for(int i = 0; i < h.length; ++i) - { - h[i] = 0.; - v[i] = 0.; - } - } - } - return user; - } - - - public Point2D.Double calculateDisplay(double x, double y) - { - double[][][] hv = new double[2][1][1]; - hv[0][0][0] = x; - hv[1][0][0] = y; - ACoord p = calculateDisplay(new ACoord(hv)); - return new Point2D.Double(p.hv[0][0][0], p.hv[1][0][0]); - } - - - public Point2D.Double calculateDisplay(Point2D.Double p) - { - return calculateDisplay(p.x, p.y); - } - - /** - * Called when the window is selected - */ - void select() - { - scaleBorder.setSelected(); - //redraw border to indicate this window is selected - borderValid = false; - repaint(); - } - - /** - * Called when the window is deselected - */ - void deselect() - { - scaleBorder.setDeselected(); - //redraw border to indicate this window is deselected - borderValid = false; - repaint(); - } - - /** - * Draws the image from the backup buffer on screen - */ - private void imageComponent(Graphics g) - { - Graphics2D g2d = (Graphics2D) g; - if(g2d != null) - { - Rectangle clipRect = g2d.getClipBounds(); - // Repaint only what is necessary. Except when running on MacOSX Tiger. - // (see http://lists.apple.com/archives/Java-dev/2005/Jun/msg00611.html) - if(clipRect != null && !(System.getProperty("os.name").equals("Mac OS X") - && System.getProperty("os.version").startsWith("10.4."))) - { - int x = clipRect.x; - int y = clipRect.y; - int w = clipRect.width; - int h = clipRect.height; - BufferedImage subImage = backingImage.getSubimage(x, y, w, h); - g2d.drawImage(subImage, x, y, this); - } - else - { - g2d.drawImage(backingImage, 0, 0, this); - } - } - } - - - public Rectangle getCurrDisp() - { - int width = m_view.getWidth(); - int height = m_view.getHeight(); - insets = m_view.getInsets(insets); - int x = insets.left; - int y = insets.top; - int w = width - insets.left - insets.right; - int h = height - insets.top - insets.bottom; - return new Rectangle(x, y, w, h); - } - - - public void paintWindowFromScratch(Graphics g) - { - APar parameterStore = APar.instance(); - ACanvas.getCanvas().setPaintingWindow(this); - parameterStore.selectWindowParameters(getName()); - Rectangle currDisp = getCurrDisp(); - int x = (int) Math.rint(currDisp.getX()); - int y = (int) Math.rint(currDisp.getY()); - int width = (int) Math.rint(currDisp.getWidth()); - int height = (int) Math.rint(currDisp.getHeight()); - g.setClip(x, y, width, height); - Graphics2D g2 = (Graphics2D)g; - if(APreferencesControl.getAliasMenuItem()) - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - else - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - - projection.paint(this, g); - - g.setClip(0, 0, m_view.getWidth(), m_view.getHeight()); - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().setPaintingWindow(null); - - if(AColorHelpDialog.getInstance() != null && AColorHelpDialog.getInstance().isVisible()) - AColorHelpDialog.getInstance().update(); - } - - - private void createOffScreenBuffer() - { - int w = m_view.getWidth(); - int h = m_view.getHeight(); - Dimension dim = new Dimension(w, h); - // Check that the current size is positive. - if(w > 0 && h > 0) - { - if(!backingDimension.equals(dim)) - { - // Usinig ABufferedPixelGraphics is not a good idea in MacOSX Tiger. - // So instead we use createGraphics() to create a normal Graphics2D - // object to draw on. - if(System.getProperty("os.name").equals("Mac OS X") - && System.getProperty("os.version").startsWith("10.4.")) - { - backingImage = getGraphicsConfiguration().createCompatibleImage(w, h); - } else if(GraphicsEnvironment.getLocalGraphicsEnvironment(). - getDefaultScreenDevice().getDefaultConfiguration(). - getColorModel().getTransferType() - == DataBuffer.TYPE_USHORT) - { - backingImage = new BufferedImage(w, h, - BufferedImage.TYPE_USHORT_565_RGB); - } - else - { - if(System.getProperty("os.name").equals("Mac OS X")) - backingImage = new BufferedImage(w, h, - BufferedImage.TYPE_INT_ARGB_PRE); - else - backingImage = new BufferedImage(w, h, - BufferedImage.TYPE_INT_RGB); - } - backingGraphics = backingImage.createGraphics(); - backingDimension.setSize(dim); - bufferValid = false; - borderValid = false; - } - } - else - { - backingImage = null; - backingGraphics = null; - } - } - - - public Point2D.Double[] getDisplayCorners() - { - Point2D.Double[] corners = new Point2D.Double[3]; - insets = m_view.getInsets(insets); - int x = insets.left; - int y = insets.top; - int w = m_view.getWidth() - insets.left - insets.right; - int h = m_view.getHeight() - insets.top - insets.bottom; - Point2D.Double upperLeft = new Point2D.Double(x, y); - Point2D.Double lowerRight = new Point2D.Double(x + w, y + h); - Point2D.Double upperRight = new Point2D.Double(x + w, y); - corners[0] = upperLeft; - corners[1] = upperRight; - corners[2] = lowerRight; - return corners; - } - - - private boolean validTransform() - { - double x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3; - x1 = userCorners[0].x; - y1 = userCorners[0].y; - x2 = userCorners[1].x; - y2 = userCorners[1].y; - x3 = userCorners[2].x; - y3 = userCorners[2].y; - Point2D.Double[] displayCorners = getDisplayCorners(); - u1 = displayCorners[0].x; - v1 = displayCorners[0].y; - u2 = displayCorners[1].x; - v2 = displayCorners[1].y; - u3 = displayCorners[2].x; - v3 = displayCorners[2].y; - if(v1 * (u3 - u2) + v2 * (u1 - u3) + v3 * (u2 - u1) == 0.)return false; - if((u1 - u2) == 0.)return false; - m01 = (u1 * (x2 - x3) + u2 * (x3 - x1) + u3 * (x1 - x2)) / - (v1 * (u3 - u2) + v2 * (u1 - u3) + v3 * (u2 - u1)); - m00 = ((x1 - x2) - m01 * (v1 - v2)) / (u1 - u2); - m02 = x1 - m00 * u1 - m01 * v1; - m11 = (u1 * (y2 - y3) + u2 * (y3 - y1) + u3 * (y1 - y2)) / - (v1 * (u3 - u2) + v2 * (u1 - u3) + v3 * (u2 - u1)); - m10 = ((y1 - y2) - m11 * (v1 - v2)) / (u1 - u2); - m12 = y1 - m10 * u1 - m11 * v1; - if((x1 - x2) == 0.) - { - n01 = (u2 - u1) / (y2 - y1); - n11 = (v2 - v1) / (y2 - y1); - n00 = ((u3 - u2) - n01 * (y3 - y2)) / (x3 - x1); - n10 = ((v3 - v2) - n11 * (y3 - y2)) / (x3 - x1); - n02 = u1 - n00 * x1 - n01 * y1; - n12 = v1 - n10 * x1 - n11 * y1; - return true; - } - else - { - if(y1 * (x3 - x2) + y2 * (x1 - x3) + y3 * (x2 - x1) == 0.)return false; - n01 = (x1 * (u2 - u3) + x2 * (u3 - u1) + x3 * (u1 - u2)) / - (y1 * (x3 - x2) + y2 * (x1 - x3) + y3 * (x2 - x1)); - n00 = ((u1 - u2) - n01 * (y1 - y2)) / (x1 - x2); - n02 = u1 - n00 * x1 - n01 * y1; - n11 = (x1 * (v2 - v3) + x2 * (v3 - v1) + x3 * (v1 - v2)) / - (y1 * (x3 - x2) + y2 * (x1 - x3) + y3 * (x2 - x1)); - n10 = ((v1 - v2) - n11 * (y1 - y2)) / (x1 - x2); - n12 = v1 - n10 * x1 - n11 * y1; - return true; - } - } - - - public JToolTip createToolTip() - { - JToolTip tip = new JToolTip(); - tip.setFont(new Font(null, Font.PLAIN, 20)); - return tip; - } - - - // implementation of DropTargetListener - - // Called when a drag operation has encountered the DropTarget. - public void dragEnter(DropTargetDragEvent dtde) - { - dtde.acceptDrag(DnDConstants.ACTION_MOVE); - } - - - // The drag operation has departed the DropTarget without dropping. - public void dragExit(DropTargetEvent dte) - {} - - - // Called when a drag operation is ongoing on the DropTarget. - public void dragOver(DropTargetDragEvent dtde) - {} - - - // The drag operation has terminated with a drop on this DropTarget. - public void drop(DropTargetDropEvent dtde) - { - try - { - Transferable transferable = dtde.getTransferable(); - DataFlavor javaObjectDataFlavor = new DataFlavor(DataFlavor. - javaJVMLocalObjectMimeType); - if(transferable.isDataFlavorSupported(javaObjectDataFlavor)) - { - dtde.acceptDrop(DnDConstants.ACTION_MOVE); - Object object = transferable.getTransferData( - javaObjectDataFlavor); - if(object instanceof ACallBack) - ((ACallBack) object).callBack(this); - else - ACanvas.getCanvas().copyWindowSettings(((ADnDLabel) object).getText(), - getName()); - dtde.getDropTargetContext().dropComplete(true); - } - else - AOutput.append("Cannot accept drop\n", ALogInterface.BAD_COMMAND); - } - catch(Exception e) - { - e.printStackTrace(); - dtde.rejectDrop(); - } - } - - - // Called if the user has modified the current drop gesture. - public void dropActionChanged(DropTargetDragEvent dtde) - {} - - - private Vector<ChangeListener> projectionChangeListeners = new Vector<ChangeListener>(); - public void addProjectionChangeListener(ChangeListener listener) - { - projectionChangeListeners.addElement(listener); - listener.stateChanged(new ChangeEvent(this)); - } - - - private void fireProjectionChange() - { - ChangeEvent changeEvent = new ChangeEvent(this); - for(int i = 0; i < projectionChangeListeners.size(); i++) - { - ChangeListener changeListener = (ChangeListener) - projectionChangeListeners.elementAt( - i); - changeListener.stateChanged(changeEvent); - } - } - - - private Vector<ChangeListener> groupChangeListeners = new Vector<ChangeListener>(); - public void addGroupChangeListener(ChangeListener listener) - { - groupChangeListeners.addElement(listener); - listener.stateChanged(new ChangeEvent(this)); - } - - - private void fireGroupChange() - { - ChangeEvent changeEvent = new ChangeEvent(this); - for(int i = 0; i < groupChangeListeners.size(); i++) - { - ChangeListener changeListener = (ChangeListener) - groupChangeListeners.elementAt(i); - changeListener.stateChanged(changeEvent); - } - } - - - // implementation of DragSourceListener - - // This method is invoked to signify that the Drag and Drop operation is complete. - public void dragDropEnd(DragSourceDropEvent dsde) - {} - - - // Called as the hotspot enters a platform dependent drop site. - public void dragEnter(DragSourceDragEvent dsde) - { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_INVALID); - } - - - // Called as the hotspot exits a platform dependent drop site. - public void dragExit(DragSourceEvent dse) - { - dse.getDragSourceContext().setCursor(ADnDLabel.DROP_INVALID); - } - - - // Called as the hotspot moves over a platform dependent drop site. - public void dragOver(DragSourceDragEvent dsde) - { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_VALID); - } - - - // Called when the user has modified the drop gesture. - public void dropActionChanged(DragSourceDragEvent dsde) - {} - - - // implementation of DragGestureListener - - public void dragGestureRecognized(DragGestureEvent dge) - { - if(!canCopyScales)return; - Point p = dge.getDragOrigin(); - Insets i = m_view.getInsets(); - int w = m_view.getWidth(); - int h = m_view.getHeight(); - Rectangle vScale = new Rectangle(0, 0, i.left, h - i.bottom); - Rectangle hScale = new Rectangle(i.left, h - i.bottom, w - i.left, - i.bottom); - if(vScale.contains(p)) - dragAction = dragActionType.COPY_VERTICAL_SCALE; - else if(hScale.contains(p)) - dragAction = dragActionType.COPY_HORIZONTAL_SCALE; - else - return; - dragSource.startDrag(dge, ADnDLabel.DROP_INVALID, - new AObjectTransferable(this), this); - } - - - public void setScaleCopyStatus(boolean canCopyScales) - { - this.canCopyScales = canCopyScales; - } - - - public void callBack(Object to) - { - AWindow targetWindow; - if(to instanceof ADnDLabel) - targetWindow = ACanvas.getCanvas().getWindow(((ADnDLabel) to). - getText()); - else if(to instanceof AWindow) - targetWindow = (AWindow) to; - else - return; - if(dragAction == dragActionType.COPY_VERTICAL_SCALE) - { - String labelSource = ((AScaleBorder) getBorder()). - getVerticalAxisLabel(); - String labelTarget = ((AScaleBorder) (targetWindow.getBorder())). - getVerticalAxisLabel(); - if(labelSource.equals(labelTarget) && labelSource.equals(AMath.PHI)) - { - Point2D.Double[] sourceCorners = getUserCorners(); - Point2D.Double[] targetCorners = targetWindow.getUserCorners(); - for(int i = 0; i < sourceCorners.length; ++i) - targetCorners[i].setLocation(targetCorners[i].getX(), - sourceCorners[i].getY()); - targetWindow.setUserCorners(targetCorners); - AOutput.append("Copy " + AMath.PHI + " Scale from " + getName() + - " to " + targetWindow.getName() + "\n", - ALogInterface.NORMAL); - } - } - else if(dragAction == dragActionType.COPY_HORIZONTAL_SCALE) - { - String labelSource = ((AScaleBorder) getBorder()). - getHorizontalAxisLabel(); - String labelTarget = ((AScaleBorder) targetWindow.getBorder()). - getHorizontalAxisLabel(); - if(labelSource.equals(labelTarget) && labelSource.equals("Z")) - { - Point2D.Double[] sourceCorners = getUserCorners(); - Point2D.Double[] targetCorners = targetWindow.getUserCorners(); - for(int i = 0; i < sourceCorners.length; ++i) - targetCorners[i].setLocation(sourceCorners[i].getX(), - targetCorners[i].getY()); - targetWindow.setUserCorners(targetCorners); - AOutput.append("Copy Z Scale from " + getName() + " to " + - targetWindow.getName() + "\n", - ALogInterface.NORMAL); - } - } - } - - - private void setLocked(boolean locked) - { - if(locked == this.locked)return; - boolean wasLocked = this.locked; - this.locked = locked; - ACanvas.getCanvas().fireLockChange(); - if(wasLocked && !locked) - this.repaintFromScratch(); - ACanvas.getCanvas().fireLockChange(); - } - - - public boolean isLocked() - { - return locked; - } - - public JComponent getView() { - return m_view; - } - - public void invalidateQuietly() { - // When you get told to paint in OpenGL you better paint otherwise - // you're going to get your empty backbuffer painted to screen a lot - // of the time ... could fix this by managing our buffer swaps by hand - // see AWindowGLView.display() for more... - Adam - bufferValid = false; - borderValid = false; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AWindowGLView.java b/graphics/AtlantisJava/src/atlantis/canvas/AWindowGLView.java deleted file mode 100644 index bd94b901375..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AWindowGLView.java +++ /dev/null @@ -1,337 +0,0 @@ -package atlantis.canvas; - -import atlantis.interactions.AInteractionsManager; -import atlantis.utils.ALogger; -import java.awt.BorderLayout; -import java.awt.BufferCapabilities; -import java.awt.Canvas; -import java.awt.Component; -import java.awt.Graphics; -import java.awt.GraphicsEnvironment; -import java.awt.event.MouseListener; -import java.lang.ref.WeakReference; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import javax.media.opengl.AWTGraphicsDevice; -import javax.media.opengl.DefaultGLCapabilitiesChooser; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCanvas; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLCapabilitiesChooser; -import javax.media.opengl.GLContext; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLJPanel; -import javax.media.opengl.glu.GLU; -import javax.swing.JPanel; -import javax.swing.border.Border; - -/** - * This class provides an OpenGL context. When the parent AWindow repaints - * this is propagated down to this view component, which then calls back to - * the parent AWindow requesting everything be copied in. - * - * @author Adam Davison - */ -public class AWindowGLView extends JPanel implements GLEventListener { - - private static ALogger logger = ALogger.getLogger(AWindowGLView.class); - - private GLCanvas m_panel; - //private JPanel m_children; - private long m_start = 0; - private int m_count = 0; - private AWindow m_parent; - private Graphics m_g = null; - - private static GLContext m_ocontext; - - // Keep track of all initialized OpenGL contexts without forcing them - // to stay in memory when we aren't using them any more... - // This is a debugging thing - private static ArrayList<WeakReference> m_all = new ArrayList<WeakReference>(); - - private static int m_maxFSAA = -1; - private static int m_FSAA = 0; - - public static int getCurrentFSAA() { - return m_FSAA; - } - - public static void setCurrentFSAA(int FSAA) { - logger.info("Changing anti-aliasing to " + FSAA + "x"); - m_FSAA = FSAA; - for (int i = 0; i < m_all.size(); i++) { - AWindowGLView v = (AWindowGLView)(m_all.get(i).get()); - if (v != null) { - v.restartDisplay(); - } - } - } - - public static int getMaxFSAA() { - return m_maxFSAA; - } - - public void restartDisplay() { - System.out.println("RESTART DISPLAY!"); - remove(m_panel); - m_panel = null; - startDisplay(); - validate(); - m_panel.setBounds(0, 0, getWidth(), getHeight()); - } - - private void startDisplay() { - GLCapabilities cap = new GLCapabilities(); - - if (m_FSAA > 0) { - cap.setSampleBuffers(true); - cap.setNumSamples(m_FSAA); - logger.info("Requesting " + m_FSAA + "x"); - } - - cap.setDoubleBuffered(true); - - if (m_ocontext != null) { - m_panel = new GLCanvas(cap, null, m_ocontext, null); - } else { - m_panel = new GLCanvas(cap); - } - - m_ocontext = m_panel.getContext(); - - m_panel.addGLEventListener(this); - - //m_FSAA = m_panel.getChosenGLCapabilities().getNumSamples(); - - //m_children = new JPanel(); - - add(m_panel, BorderLayout.CENTER); - - } - - public AWindowGLView(AWindow parent) { - m_parent = parent; - setLayout(null); - - startDisplay(); - //m_panel.add(m_but); - //add(m_but, BorderLayout.NORTH); - - - m_all.add(new WeakReference(this)); - - } - - private void checkListeners() { - AInteractionsManager lt = m_parent.getInteractionManager(); - MouseListener[] lr = m_panel.getMouseListeners(); - boolean found = false; - for (int i = 0; i < lr.length; i++) { - if (lr[i] == lt) { - found = true; - } - } - - if (!found) { - m_panel.addMouseListener(lt); - m_panel.addMouseMotionListener(lt); - } - } - - public void init(GLAutoDrawable drawable) { - - System.out.println("INIT CALLED!"); - System.out.println(getWidth() + ":" + getHeight()); - //(new Exception()).printStackTrace(); - - checkListeners(); - - //drawable.setGL(new TraceGL(drawable.getGL(), System.err)); - GL gl = drawable.getGL(); - logger.debug("INIT GL IS: " + gl.getClass().getName()); - - int[] buffer = new int[2]; - gl.glGetIntegerv(GL.GL_MAX_SAMPLES_EXT, buffer, 0); - m_maxFSAA = buffer[0]; - logger.debug("Graphics card supports max anti-alias of: " + buffer[0] + "x"); - - BufferCapabilities bc = m_panel.getGraphicsConfiguration().getBufferCapabilities(); - boolean frontacc = bc.getFrontBufferCapabilities().isAccelerated(); - boolean backacc = bc.getBackBufferCapabilities().isAccelerated(); - logger.info("OpenGL Acceleration Status: Front - " + frontacc + " and Back - " + backacc); - - // All polygons in Atlantis are uniformly coloured, this speeds things up in theory at least... - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl.glShadeModel(GL.GL_FLAT); - - // Old style antialiasing like this is apparently not supported by - // modern graphics cards although we may want to enable it on older - // hardware where people do not have FSAA but still want AA - /*gl.glHint(gl.GL_POLYGON_SMOOTH_HINT, gl.GL_NICEST); - gl.glEnable(gl.GL_POLYGON_SMOOTH); - gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST); - gl.glEnable(gl.GL_LINE_SMOOTH);*/ - - // We do our own Z-ordering - gl.glDisable(gl.GL_DEPTH_TEST); - - // Enable transparency, even if nothing in Atlantis is actually - // transparent yet... - gl.glEnable(gl.GL_BLEND); - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA); - - } - - private static int countContexts() { - int count = 0; - for (int i = 0; i < m_all.size(); i++) { - if (m_all.get(i).get() != null) { - count++; - } - // Could throw away dead weak refs here... - } - return count; - } - - public void display(GLAutoDrawable d) { - - /*if (m_parent.isValid()) { - System.out.println("VALID PARENT - RETURNING"); - return; - }*/ - // Perhaps we could not do this and turn off buffer swaps? - // Currently we're probably doing some unnecessary repaints when - // you change window - m_parent.invalidateQuietly(); - - GL gl = d.getGL(); - //System.out.println("DISPLAY " + this); - //System.out.println("ACTIVE: " + countContexts()); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadIdentity(); - - // Can we avoid this? We probably fill with bg colour later anyway... - gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f); - gl.glClear(gl.GL_COLOR_BUFFER_BIT); - - if (m_parent != null) { - AGLGraphics glg = new AGLGraphics(d); - m_parent.paintWindow(glg, false); - super.paintBorder(glg); - /*for (int i = 0; i < m_panel.getComponentCount(); i++) { - m_panel.getComponent(i).paint(glg); - }*/ - } - - gl.glFlush(); - - m_count++; - long tnow = System.currentTimeMillis(); - if (tnow - 1000 > m_start) { - logger.info("OpenGL FPS: " + m_count); - m_count = 0; - m_start = tnow; - } - } - - /*@Override - public Graphics getGraphics() { - if (m_g == null) { - System.out.println("PAINT OUT OF VALID"); - return new ADummyGraphics2D(); - } else { - return m_g; - } - }*/ - public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - //System.out.println("GLRESIZE: " + x + ":" + y + ":" + width + ":" + height); - GL gl = drawable.getGL(); - GLU glu = new GLU(); - - if (height <= 0) // avoid a divide by zero error! - { - height = 1; - } - final float h = (float) width / (float) height; - gl.glViewport(0, 0, width, height); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glLoadIdentity(); - gl.glOrtho(x, x + width, y + height, y, -100.0, 100.0); - //gl.glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadIdentity(); - - m_count = 0; - m_start = System.currentTimeMillis(); - } - - // Should implement this for multi-screen people some time... - public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void setBounds(int x, int y, int width, int height) { - //Border b = getBorder(); - //setBorder(null); - super.setBounds(x, y, width, height); - m_panel.setBounds(0, 0, getWidth(), getHeight()); - //setBorder(b); - //System.out.println("RESIZE " + x + ":" + y + ":" + width + ":" + height); - } - - // Need to paint our own border to make sure it gets drawn in GL - public void paintBorder(Graphics g) { - - } - - // Need to make sure our heavyweight child is invalidated - public void repaint() { - super.repaint(); - if (m_panel != null) { - m_panel.repaint(); - } - } - - public Component getRealPanel() { - return m_panel; - } -} - -class OurGLCapChooser implements GLCapabilitiesChooser { - - private int m_maxAA; - private boolean m_canAA; - - public OurGLCapChooser() { - } - - public int chooseCapabilities(GLCapabilities req, GLCapabilities[] all, int recommended) { - System.out.println("CALLED!"); - m_canAA = false; - m_maxAA = 0; - - for (int i = 0; i < all.length; i++) { - System.out.println(all[i]); - if (all[i].getSampleBuffers()) { - m_canAA = true; - if (all[i].getNumSamples() > m_maxAA) { - m_maxAA = all[i].getNumSamples(); - } - } - } - - return (new DefaultGLCapabilitiesChooser()).chooseCapabilities(req, all, recommended); - } - - public boolean getCanAA() { - return m_canAA; - } - - public int getMaxAA() { - return m_maxAA; - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/canvas/AWindowSwingView.java b/graphics/AtlantisJava/src/atlantis/canvas/AWindowSwingView.java deleted file mode 100644 index cc27fad13af..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/AWindowSwingView.java +++ /dev/null @@ -1,57 +0,0 @@ -package atlantis.canvas; - -import atlantis.globals.AGlobals; - -import java.awt.Graphics; -import javax.swing.JPanel; - -/** - * - * This class provides an Java2D/Swing context. When the parent AWindow repaints - * this is propagated down to this view component, which then calls back to - * the parent AWindow requesting everything be copied in. - * - * @author Adam Davison - */ -public class AWindowSwingView extends JPanel { - - private AWindow m_parent; - - public AWindowSwingView(AWindow parent) { - setLayout(null); - m_parent = parent; - } - - @Override - protected void paintComponent(Graphics g) { - //System.out.println(getX() + ":" + getY() + ":" + getWidth() + ":" + getHeight()); - g.setClip(0, 0, getWidth(), getHeight()); - //g.setColor(Color.RED); - //g.fillRect(10, 10, getWidth() - 10, getHeight() - 10); - if (AGlobals.isAtlantisHeadless()) { - // Don't need to paint to a backing buffer ever in headless - // since we're already painting offscreen - m_parent.paintWindow(g, false); - } else { - m_parent.paintWindow(g, true); - } - } - - @Override - protected void printComponent(Graphics g) { - //System.out.println(getX() + ":" + getY() + ":" + getWidth() + ":" + getHeight()); - g.setClip(0, 0, getWidth(), getHeight()); - //g.setColor(Color.RED); - //g.fillRect(10, 10, getWidth() - 10, getHeight() - 10); - m_parent.printComponent(g); - } - - @Override - public void setBounds(int x, int y, int width, int height) { - super.setBounds(x, y, width, height); - //System.out.println("RESIZE " + x + ":" + y + ":" + width + ":" + height); - } - - - -} diff --git a/graphics/AtlantisJava/src/atlantis/canvas/package.html b/graphics/AtlantisJava/src/atlantis/canvas/package.html deleted file mode 100644 index c09fd6d63f2..00000000000 --- a/graphics/AtlantisJava/src/atlantis/canvas/package.html +++ /dev/null @@ -1,23 +0,0 @@ -<html> -<head></head> -<body> -<p>Provides classes representing the Atlantis canvas and the windows - displayed within it.</p> -<p>The ACanvas is a JFrame containing a JlayeredPane of AWindows. Windows -are placed into the JLayeredPane depending on the current layout. The -canvas class contains a HashTable of all possible windows and a -HashTable of all available layouts. Windows needed by the current -layout are added to the JLayeredPane according to the size and the -order defined by the layout. An AWindow is a JPanel into which the -Atlantis graphics are drawn. Each window has an associated projection -and also an interaction manager. The interaction manager is a mouse -listener which deals with all mouse events on the window. The window -manages the drawing of the Atlantis picture and deals with the linear -transformations from user to display co-ordinates. Non-linear -transformations are dealt with by the projection. ALayout defines the -size and position (in the 3x3 grid layout scheme of the layered pane) -of each window, and also describes combinations of these windows -called pages. pages is an array of characters where each character -represents a window.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/config/AConfig.java b/graphics/AtlantisJava/src/atlantis/config/AConfig.java deleted file mode 100755 index f35dbb07ed5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/config/AConfig.java +++ /dev/null @@ -1,432 +0,0 @@ -package atlantis.config; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Iterator; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import atlantis.Atlantis; -import atlantis.utils.xml.AXMLErrorHandler; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; - -/** - * AConfig acts as a container of the configuration file. - * The whole file can be accessed through a tree structure. - * - * @author ql - * - */ - -// by Zdenek, remark, 2008-08-14 -// since the attributes are stored in something like HashMap -// their order is not ensured?, e.g. having in WindowCorners source -// configuration (master copy according to which synchronization is done) -// <CORNERS windowName="W" x0="-1320.0" y0="1320.0" x1="1320.0" y1="1320.0" x2="1320.0" y2="-1320.0"/> -// line order this way, after updating it result in something like this -// <CORNERS x2="1320.0" windowName="W" y0="1320.0" x1="1320.0" y2="-1320.0" y1="1320.0" x0="-1320.0"/> -// the same data, but the order of attributes is not the same -public class AConfig -{ - private static ALogger logger = ALogger.getLogger(AConfig.class); - - // A map defining the key attribute for each modifiable element - static Hashtable keyMap; - - // Define modifiable attributes - public static String[] CANVAS_ATT = {"startupLayout", "aspectRatio"}; //<Canvas> - public static String[] WINDOW_ATT = {"projection", "group"}; //<UsedWindow> - public static String[] LAYOUT_ATT = {"startup", "startupWindow"}; //<Layout> - public static String[] PAR_ATT = {"va", "st", "dop", "scope", "ul"}; //<Others> - public static String[] GROUP_ATT = {"userLevel"}; //<Group> - - // Define used greek letters in configuration file - static String[] GREEK_LETTER = {"\u03B7", "\u03C1", "\u03A6", "\u0394", "\u03BB", "\u03C3"}; - static String[] GREEK_ENTITY = {"η", "ρ", "φ", "δ", "λ", "σ"}; - - // The name of the configuration file - private String filename; - - // If isCustomised is true, the configuration file contains two exclusive - // blocks, <ParameterDifferences> and <WindowCorners>. - private boolean isCustomised; - - // This field contains the whole DTD section of the configuration file. - private String dtdSection = null; - - // Root node of the configuration tree - private AConfigNode rootNode; - - // A list containing all element nodes in the file - private ArrayList nodeList; - - // A list containing all user exclusive element nodes in the file - // <ParameterDifferences> and <WindowCorners> - private ArrayList userExclusiveNodeList; - - public AConfig(String configFilename, boolean isCustomised) throws Exception - { - if(AConfig.keyMap == null) - AConfig.createKeyMap(); - this.filename = configFilename; - this.isCustomised = isCustomised; - parseXML(); - } - - /** - * @return Returns the dtdSection. - */ - public String getDtdSection() throws Exception - { - if(this.dtdSection == null) - createDTDSection(this.filename); - return this.dtdSection; - } - - public Iterator getIterator() - { - return nodeList.iterator(); - } - - void addNode(AConfigNode node) - { - nodeList.add(node); - } - - void addUserExclusiveNode(AConfigNode node) - { - userExclusiveNodeList.add(node); - } - - /** - * initialise <code>keyMap</code>. - */ - private static void createKeyMap() - { - keyMap = new Hashtable(); - keyMap.put("Canvas", "startupLayout"); - keyMap.put("UsedWindow", "name"); - keyMap.put("Layout", "name"); - keyMap.put("ENUM", "fn"); - keyMap.put("SENUM", "fn"); - keyMap.put("ICUT", "fn"); - keyMap.put("SICUT", "fn"); - keyMap.put("FCUT", "fn"); - keyMap.put("SFCUT", "fn"); - keyMap.put("INT", "fn"); - keyMap.put("SINT", "fn"); - keyMap.put("FLOAT", "fn"); - keyMap.put("SFLOAT", "fn"); - keyMap.put("LINT", "fn"); - keyMap.put("SLINT", "fn"); - keyMap.put("COLOR", "fn"); - keyMap.put("SCOLOR", "fn"); - keyMap.put("STATUS", "fn"); - } - - /** - * initialise <code>dtdSection</code> based on the dtd part from the - * configuration file. - */ - private void createDTDSection(String configFilename) throws Exception - { - String dtdStart = "<?xml version=\"1.0\"?>"; - String dtdEnd = "]>"; - String LINE_SEPAR = System.getProperty("line.separator"); - - this.dtdSection = ""; - try - { - - InputStream is = AUtilities.getFileAsStream(configFilename); - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - - String currentLine; - boolean isInsideDTD = false; - while(true) - { - currentLine = br.readLine(); - if(currentLine == null) return; - if(dtdStart.equals(currentLine.trim())) - { - isInsideDTD = true; - this.dtdSection += currentLine + LINE_SEPAR; - } - else if(dtdEnd.equals(currentLine.trim())) - { - isInsideDTD = false; - this.dtdSection += currentLine + LINE_SEPAR; - } - else if(isInsideDTD) - { - this.dtdSection += currentLine + LINE_SEPAR; - } - } - } - catch(FileNotFoundException e) - { - String m = "File " + configFilename + " not found, fatal."; - throw new Exception(m); - } - catch(IOException e) - { - String m = "I/O exception while reading file " + configFilename; - throw new Exception(m); - } - } - - public void createConfigTree(Element rootElement) - { - this.nodeList = new ArrayList(); - if(this.isCustomised) - this.userExclusiveNodeList = new ArrayList(); - this.rootNode = new AConfigNode(null, rootElement, 0, this); - } - - public void parseXML() throws Exception - { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(true); - DocumentBuilder parser; - try - { - parser = factory.newDocumentBuilder(); - parser.setErrorHandler(new AXMLErrorHandler()); - - InputStream isConfig = AUtilities.getFileAsStream(this.filename); - Document xmlConfigDoc = parser.parse(isConfig); - createConfigTree(xmlConfigDoc.getDocumentElement()); - } - catch (Exception e) - { - throw e; - } - } - - // Find a node match the sampleNode in the configuration file - // Return the node if found, null otherwise - public AConfigNode find(AConfigNode sampleNode) - { - for(int i=0; i<nodeList.size(); ++i) - { - AConfigNode testNode = (AConfigNode) nodeList.get(i); - if("Canvas".equals(sampleNode.getNodeName()) - && (testNode.getFullNodeName().equals(sampleNode.getFullNodeName()))) - { - return testNode; - } - else if((testNode.getFullNodeName().equals(sampleNode.getFullNodeName())) - && (testNode.getKeyValue().equals(sampleNode.getKeyValue()))) - { - return testNode; - } - } - return null; - } - - // Find a node based on the node name, attribute name and value - // Return the node if found, null otherwise - public AConfigNode find(String name, String attName, String attValue) - { - for(int i=0; i<nodeList.size(); ++i) - { - AConfigNode testNode = (AConfigNode) nodeList.get(i); - if(name.equals(testNode.getNodeName()) - && attValue.equals(testNode.getAttValue(attName))) - return testNode; - } - return null; - } - - // Find a node based on the node name, attribute name and value, - // and its parent's node name, attribute name and value. - // Return the node if found, null otherwise - public AConfigNode find(String name, String attName, String attValue, - String parName, String parAttName, String parAttValue) - { - for(int i=0; i<nodeList.size(); ++i) - { - AConfigNode testNode = (AConfigNode) nodeList.get(i); - if(name.equals(testNode.getNodeName()) - && attValue.equals(testNode.getAttValue(attName))) - { - AConfigNode parNode = testNode.getParent(); - - if(parName.equals(parNode.getNodeName()) - && parAttValue.equals(parNode.getAttValue(parAttName))) - return testNode; - } - } - return null; - } - - // Find a parameter node based on the attribute name and value, - // and its group's name - // Return the node if found, null otherwise - // - // NB: This method is for finding a parameter node with uncertain - // parameter type, but with a certain parent node name - public AConfigNode findPar(String attName, String attValue, String parAttValue) - { - for(int i=0; i<nodeList.size(); ++i) - { - AConfigNode testNode = (AConfigNode) nodeList.get(i); - if(attValue.equals(testNode.getAttValue(attName))) - { - AConfigNode parNode = testNode.getParent(); - - // <StatusRoot> and <StatusGroup> are skipped when finding parent node - while("StatusRoot".equals(parNode.getNodeName()) - || "StatusGroup".equals(parNode.getNodeName())) - { - parNode = parNode.getParent(); - } - - if("Group".equals(parNode.getNodeName()) - && parAttValue.equals(parNode.getAttValue("name"))) - return testNode; - } - } - return null; - } - - /** - * validate the attribute value - */ - public boolean validate(AConfigNode node, String attName, String attValue) - { - if("Canvas".equals(node.getNodeName()) && "startupLayout".equals(attName)) - { - if(find("Layout", "name", attValue) == null) - return false; - } - else if("UsedWindow".equals(node.getNodeName()) && "projection".equals(attName)) - { - if(find("Group", "name", attValue, "SuperGroup", "name", "Projection") == null) - return false; - } - else if("UsedWindow".equals(node.getNodeName()) && "group".equals(attName)) - { - if(find("Group", "name", attValue) == null) - return false; - } - else if("Layout".equals(node.getNodeName())) - { - int numWindows = attValue.length(); - for(int i=0; i<numWindows; ++i) - { - String windowName = attValue.substring(i, i+1); - if(find("Window", "name", windowName, "Layout", "name", node.getKeyValue()) == null) - return false; - } - } - return true; - } - - public void validateUserExclusiveNode(AConfigNode node) - { - if("ParameterDifferences".equals(node.getNodeName())) - { - // check validity of each child of <ParameterDifferences> - Iterator it = node.getChildren().iterator(); - while(it.hasNext()) - { - // a <DIFFERENCE> node - AConfigNode childNode = (AConfigNode) it.next(); - String group = childNode.getAttValue("group"); - String window = childNode.getAttValue("windowName"); - String parameter = childNode.getAttValue("name"); - if(find("UsedWindow", "name", window) == null) - it.remove(); - else - { - if(find("Group", "name", group) == null) - it.remove(); - else - { - if(findPar("fn", parameter, group) == null) - it.remove(); - } - } - } - } - else if("WindowCorners".equals(node.getNodeName())) - { - // check validity of each child of <WindowCorners> - Iterator it = node.getChildren().iterator(); - while(it.hasNext()) - { - // a <CORNERS> node - AConfigNode childNode = (AConfigNode) it.next(); - String window = childNode.getAttValue("windowName"); - if(find("UsedWindow", "name", window) == null) - it.remove(); - } - } - } - - /** - * Replace the greek letters in the source string with UTF entities - * - * @param testStr a source string - * @return the resulting string - */ - static String replaceGreekLetter(String testStr) - { - for (int i=0; i<GREEK_LETTER.length; ++i) - { - if (testStr.indexOf(GREEK_LETTER[i]) >= 0) - testStr = testStr.replaceAll(GREEK_LETTER[i], GREEK_ENTITY[i]); - } - - return testStr; - } - - /** - * Converts to a string representing the xml data in this configuration - * file. - */ - public String convertToString() throws Exception - { - return getDtdSection() + "\n\n" + this.rootNode.toString(); - } - - /** - * Converts to a string representing the xml data in this configuration - * file plus the user exclusive section fom <code>userConfig</code>. - */ - public String convertToString(AConfig userConfig) throws Exception - { - if(!this.isCustomised && userConfig.isCustomised) - { - StringBuffer str = new StringBuffer("\n"); - for(int i=0; i<userConfig.userExclusiveNodeList.size(); ++i) - { - AConfigNode userExclusiveNode = (AConfigNode) userConfig.userExclusiveNodeList.get(i); - validateUserExclusiveNode(userExclusiveNode); - str.append(userExclusiveNode.toString()); - str.append("\n"); - } - return getDtdSection() + "\n\n" + this.rootNode.toString(str.toString()); - } - else - { - // only add user exclusive section to non-customized configuration - return toString(); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/config/AConfigNode.java b/graphics/AtlantisJava/src/atlantis/config/AConfigNode.java deleted file mode 100755 index 751ae988505..00000000000 --- a/graphics/AtlantisJava/src/atlantis/config/AConfigNode.java +++ /dev/null @@ -1,263 +0,0 @@ -package atlantis.config; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.jar.Attributes; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class AConfigNode -{ - private String nodeName; - - // use fullNodeName combined with keyValue to uniquely identify a parameter - // in the configuration file - // NB: keyValue is not empty only if attributes is not empty - private String fullNodeName; - private String keyValue = null; - - // Layer 0 represents the root node of the xml file, - // and layer 1 reprensents the layer inside layer 0, - // and so on. - private int layer; - - private Attributes attributes = null; - private ArrayList children = null; - private AConfigNode parent = null; - - // if parent is null, elementNode is the root node - AConfigNode(AConfigNode parent, Node elementNode, int layer, AConfig configObject) - { - // add this node into the node list - configObject.addNode(this); - this.layer = layer; - - // set the full name - this.parent = parent; - String parentName = (this.parent != null) ? this.parent.getFullNodeName() + "-" : ""; - this.nodeName = elementNode.getNodeName(); - if("ParameterDifferences".equals(this.nodeName) - || "WindowCorners".equals(this.nodeName)) - configObject.addUserExclusiveNode(this); - this.fullNodeName = parentName + this.nodeName; - - // set the attributes map - if(elementNode.hasAttributes()) - { - NamedNodeMap attMap = elementNode.getAttributes(); - int numAttributes = attMap.getLength(); - this.attributes = new Attributes(numAttributes); - for(int i=0; i<numAttributes; ++i) - { - // each node returned from item(i) is an Attr - String name = attMap.item(i).getNodeName(); - String value = attMap.item(i).getNodeValue(); - // replace special math operator characters with entity references - if("=".equals(value)) - value = "&intEqual;"; - else if(">".equals(value)) - value = ">"; - else if("<".equals(value)) - value = "<"; - else if("<,>".equals(value)) - value = "ℜ"; - else if("<=".equals(value)) - value = "≤"; - else if(">=".equals(value)) - value = "≥"; - else if("=,!=,<,<=,>,>=".equals(value)) - value = "∫"; - - // replace greek letters with entity references - value = AConfig.replaceGreekLetter(value); - - this.attributes.putValue(name, value); - } - } - - // set the key value - String keyAttr = (String) AConfig.keyMap.get(this.nodeName); - if(keyAttr != null) - { - String groupName = this.parent.getAttValue("name"); - this.keyValue = ((groupName == null) ? "" : (groupName + "-")) + this.attributes.getValue(keyAttr); - } - - // set the children list - if(elementNode.hasChildNodes()) - { - NodeList childList = elementNode.getChildNodes(); - int numChildren = childList.getLength()/2; - this.children = new ArrayList(numChildren); - int idx = 0; - for(int i=0; i<childList.getLength(); ++i) - { - // each node returned from item(i) is an Attr - Node childNode = childList.item(i); - if (childNode.getNodeType() == Node.ELEMENT_NODE) - { - this.children.add(idx++, new AConfigNode(this, childNode, this.layer+1, configObject)); - } - } - } - } - - /** - * @return Returns the nodeName. - */ - public String getNodeName() - { - return this.nodeName; - } - - /** - * @return Returns the fullNodeName. - */ - public String getFullNodeName() - { - return this.fullNodeName; - } - - /** - * @return Returns the parent. - */ - public AConfigNode getParent() - { - return this.parent; - } - - /** - * @return Returns the children. - */ - public List getChildren() - { - return this.children; - } - - /** - * @return Returns the keyValue. - */ - public String getKeyValue() - { - return this.keyValue; - } - - /** - * @return Returns the string value of the specified attribute name, - * or null if not found. - */ - public String getAttValue(String name) - { - if(this.attributes != null) - return this.attributes.getValue(name); - else - return null; - } - - public String setAttValue(String name, String value) - { - return this.attributes.putValue(name, value); - } - - // the start line of this xml node - // e.g. <Nodename att1="value1" att2="value2"> - private String selfStartString() - { - StringBuffer str = new StringBuffer(); - for(int i=0; i<this.layer; ++i) - { - str.append("\t"); - } - str.append("<"); - str.append(this.nodeName); - if(this.attributes != null) - { - Set attSet = this.attributes.keySet(); - Iterator it = attSet.iterator(); - while(it.hasNext()) - { - String attName = it.next().toString(); - String attValue = this.attributes.getValue(attName); - str.append(" "); - str.append(attName); - str.append("=\""); - str.append(attValue); - str.append("\""); - } - } - if(this.children == null) - { - str.append("/>"); - } - return str.toString(); - } - - private String selfEndString() - { - StringBuffer str = new StringBuffer(); - if(this.children == null) - { - // if no children, use simplified format (<.../>) - // so selfStartString contains everything about this node - return ""; - } - else - { - for(int i=0; i<this.layer; ++i) - { - str.append("\t"); - } - str.append("</"); - str.append(this.nodeName); - str.append(">"); - } - return str.toString(); - } - - private String childrenString() - { - StringBuffer str = new StringBuffer(); - if(this.children == null) - { - return ""; - } - else - { - str.append(">\n"); - for(int i=0; i<this.children.size(); ++i) - { - AConfigNode child = (AConfigNode) this.children.get(i); - str.append(child.toString()); - str.append("\n"); - } - } - return str.toString(); - } - - /** - * Converts to a string representing the xml data containing this node and - * all its children. - */ - public String toString() - { - return selfStartString()+childrenString()+selfEndString(); - } - - // userExclusiveSection is noly under root node (layer 0) - public String toString(String userExclusiveSection) - { - if(this.layer == 0) - { - return selfStartString()+childrenString()+userExclusiveSection+selfEndString(); - } - else - { - return toString(); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/config/AConfigUpdater.java b/graphics/AtlantisJava/src/atlantis/config/AConfigUpdater.java deleted file mode 100644 index ee87efb78bc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/config/AConfigUpdater.java +++ /dev/null @@ -1,405 +0,0 @@ -package atlantis.config; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.io.InputStream; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import java.util.Iterator; - -import atlantis.utils.AUtilities; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; - - - -/** - * This class encapsulates a few static methods which ensure updating - * of the user's customised Atlantis configuration (or special Atlantis - * configurations) according to the base Atlantis configuration file - * configuration/config.xml - * - * Updating means synchronising special / customised configurations if - * XML elements were added/removed from the base configuration file while - * keeping unchanged specially defined user cuts, views, projections, etc. - * - * Methods in this class are also called by an external configuration - * synchronization tool, so methods should remain static, special treatment - * of logger, etc. - * - * @author - * Zdenek Maxa - initial update mechanism, creating this extra class, refactoring - * Qiang Lu - improved reliable updating mechanism as done in AConfig - * - */ -public final class AConfigUpdater -{ - // when AConfigUpdater is called from Atlantis code, logger would behave - // as configured there. If AConfigUpdater is called externally, logger - // should be initialised with default values from ALogger - private static ALogger logger = ALogger.getLogger(AConfigUpdater.class); - - - - - /** - * Methods creates checksum file (name in fileNameChk) of a given file - * (file name in fileName). - */ - public static void createChecksumFile(String fileName, String fileNameChk) - throws AAtlantisException - { - try - { - logger.debug("Creating checksum file " + fileNameChk + - " of a file " + fileName); - byte[] chk = calculateChecksum(fileName); - File fileChk = new File(fileNameChk); - OutputStream os = new FileOutputStream(fileChk); - os.write(chk); - os.close(); - } - catch(AAtlantisException ae) - { - String m = "Error while creating MD5 checksum file, reason: " + - ae.getMessage(); - throw new AAtlantisException(m); - } - catch(FileNotFoundException fnfe) - { - String m = "File not found exception: " + fnfe.getMessage(); - throw new AAtlantisException(m); - } - catch(IOException ioe) - { - String m = "I/O error while creating file " + fileNameChk; - throw new AAtlantisException(m); - } - - } // createChecksumFile() ----------------------------------------------- - - - - /** - * Calculates checksum of a file fileName. - */ - private static byte[] calculateChecksum(String fileName) - throws AAtlantisException - { - InputStream fis = null; - try - { - logger.debug("Calculating checksum of file: " + fileName); - fis = AUtilities.getFileAsStream(fileName); - } - catch(AAtlantisException ae) - { - throw ae; - } - - MessageDigest complete = null; - - try - { - byte[] buffer = new byte[1024]; - complete = MessageDigest.getInstance("MD5"); - int numRead; - do - { - numRead = fis.read(buffer); - if (numRead > 0) - { - complete.update(buffer, 0, numRead); - } - } while (numRead != -1); - - fis.close(); - } - catch(IOException ioe) - { - throw new AAtlantisException("Error while reading data from file " + - fileName); - } - catch(NoSuchAlgorithmException nsae) - { - throw new AAtlantisException(nsae.getMessage()); - } - - logger.debug("Checksum calculated."); - return complete.digest(); - - } // calculateChecksum() ------------------------------------------------ - - - - /** - * Method checks the checksum of input file fileName if its checksum matches - * checksum stored in the checksum file fileNameChk. - * Return true if matches, false otherwise. - */ - public static boolean compareChecksums(String fileName, String fileNameChk) - throws AAtlantisException - { - boolean result = false; - try - { - // checksum of the input file - byte[] inputFileChecksum = calculateChecksum(fileName); - // checksum to read stored checksum from file fileNameChk - // assume the lenght is the same as of the input data file - byte[] storedChecksum = new byte[inputFileChecksum.length]; - File fileChk = new File(fileNameChk); - InputStream is = new FileInputStream(fileChk); - is.read(storedChecksum); - - // compare both checksums - if(new String(storedChecksum).equals(new String(inputFileChecksum))) - { - result = true; - } - else - { - result = false; - } - - is.close(); - } - catch(Exception e) - { - String m = "Error while checking MD5 checksum file, reason: " + - e.getMessage(); - throw new AAtlantisException(m); - } - - return result; - - } // compareChecksums() ------------------------------------------------- - - - - /** - * @param distConfig - configuration instance from Atlantis distribution - * (master copy) - * @param userConfig - user's customised or special configuration which - * gets updated according to distribution configuration - */ - private static void updateConfiguration(AConfig distConfig, AConfig userConfig) - { - logger.debug("Updating customised configuration ..."); - Iterator distIt = distConfig.getIterator(); - while(distIt.hasNext()) - { - // For each key node (keyValue is not empty) inside distConfig, - // test if there is a same node in userConfig. - AConfigNode testDistNode = (AConfigNode) distIt.next(); - if(testDistNode.getKeyValue() != null) - { - AConfigNode matchUserNode = userConfig.find(testDistNode); - if(matchUserNode != null) - { - // update testDistNode based on matchUserNode - updateNode(distConfig, testDistNode, matchUserNode); - } - } - } - - logger.debug("Update finished."); - - } // updateConfiguration() ---------------------------------------------- - - - - /** - * Update a node from configuration. - */ - private static void updateNode(AConfig distConfig, - AConfigNode distNode, AConfigNode userNode) - { - String[] attStrArray = null; - if("Canvas".equals(distNode.getNodeName())) - { - attStrArray = AConfig.CANVAS_ATT; - } - else if("UsedWindow".equals(distNode.getNodeName())) - { - attStrArray = AConfig.WINDOW_ATT; - } - else if("Layout".equals(distNode.getNodeName())) - { - attStrArray = AConfig.LAYOUT_ATT; - } - else - { - //check the parent Group values - if(distNode.getParent().getNodeName().equals("Group")){ - attStrArray = AConfig.GROUP_ATT; - //update the value - for(int i = 0; i < attStrArray.length; ++i) - { - String att = attStrArray[i]; - String distValue = distNode.getParent().getAttValue(att); - String userValue = userNode.getParent().getAttValue(att); - - if(distValue != null && userValue != null && !distValue.equals(userValue)) - { - if(distConfig.validate(distNode.getParent(), att, userValue)) - { - distNode.getParent().setAttValue(att, userValue); - } - } - } - } - - //now update parameters inside the Group - attStrArray = AConfig.PAR_ATT; - } - - // update the value - for(int i = 0; i < attStrArray.length; ++i) - { - String att = attStrArray[i]; - String distValue = distNode.getAttValue(att); - String userValue = userNode.getAttValue(att); - if(distValue != null && userValue != null && !distValue.equals(userValue)) - { - if(distConfig.validate(distNode, att, userValue)) - { - distNode.setAttValue(att, userValue); - } - } - } - - } // updateNode() ------------------------------------------------------- - - - - private static void writeUpdatedConfigurationFile(AConfig distConfig, - AConfig userConfig, - String filename) - throws Exception - { - FileOutputStream fo = null; - fo = new FileOutputStream(filename); - String updatedConfiguration = distConfig.convertToString(userConfig); - fo.write(updatedConfiguration.getBytes()); - fo.close(); - - } // writeUpdatedConfigurationFile() ------------------------------------ - - - - /** - * Updates customised configuration file to be consistent with the - * distribution configuration file. - * @param fileNameDist - distribution configuration file path - * @param fileNameCustom - customised configuration file path - * @throws AAException - */ - public static void updateConfigurationFile(String fileNameDist, - String fileNameCustom) - throws AAtlantisException - { - - logger.info("Updating configuration - master " + - "configuration: " + fileNameDist); - logger.info("Updating configuration - customised (being updated) " + - "configuration: " + fileNameCustom); - - AConfig distConfig = null; - AConfig customConfig = null; - - // read master (distribution) and customised configurations - try - { - distConfig = new AConfig(fileNameDist, false); // false - is not customised - } - catch(Exception e) - { - // these however seem to be never thrown because of AXMLErrorHandler - // in AConfig - String m = "Could not read/parse distribution configuration " + - fileNameDist + " reason: " + e.getMessage(); - throw new AAtlantisException(m); - } - - try - { - customConfig = new AConfig(fileNameCustom, true); // true - is customised - } - catch(Exception e) - { - // these however seem to be never thrown because of AXMLErrorHandler - // in AConfig - String m = "Could not read/parse customised configuration " + - fileNameCustom + " reason: " + e.getMessage(); - throw new AAtlantisException(m); - } - - - // actual update - try - { - updateConfiguration(distConfig, customConfig); - } - catch(Throwable t) - { - String m = "Updating customised configuration failed, reason: " + - t.getMessage(); - logger.debug(m, t); - throw new AAtlantisException(m); - } - - - // write updated data, first create backup of the source file - - logger.info("Creating backup of the customised configuration file ..."); - // file name to backup (rename) the file to - String fileNameUserBackup = fileNameCustom + "-backup_on_" + - AUtilities.getDateTimeString(); - File fileCustom = new File(fileNameCustom); - File fileBackup = new File(fileNameUserBackup); - boolean renameResult = fileCustom.renameTo(fileBackup); - if(! renameResult) - { - String m = "Could not backup customised configuration " + - "file, updating configuration failed."; - - // if fileNameDist path starts with "//", then it is run from within - // JAR archive via webstart. update process can't be performed in this - // case - can't create a backup copy of the fileNameCustom (and can't - // create an updated file when all is packed in a single JAR file either) - if(fileNameDist.startsWith("//")) - { - m += " Running via webstart, update can't be perfomed in this mode."; - } - throw new AAtlantisException(m); - } - logger.info(fileNameCustom + " backup created: " + fileNameUserBackup); - - - try - { - writeUpdatedConfigurationFile(distConfig, customConfig, - fileNameCustom); - } - catch(Throwable t) - { - String m = "Saving updated customised configuration into file " + - "failed, reason: " + t.getMessage(); - logger.debug(m, t); - throw new AAtlantisException(m); - } - - - logger.info(fileNameCustom + " configuration was successfully updated."); - - } // updateConfigurationFile() ------------------------------------------ - - -} // class AConfigUpdater =================================================== \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/config/ADefaultValues.java b/graphics/AtlantisJava/src/atlantis/config/ADefaultValues.java deleted file mode 100755 index b2e764499cd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/config/ADefaultValues.java +++ /dev/null @@ -1,206 +0,0 @@ -package atlantis.config; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Hashtable; -import java.util.Enumeration; -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import atlantis.globals.AGlobals; -import atlantis.utils.ALogger; - -/** - * The class maintains a few values which are to be remembered - * from session to session. The class tries to read in values from runtime - * configuration file $HOME/.Atlantis-runtime_values.txt. The values are - * stored in a Hashtable and are used as default initialize values. This - * Hashtable is updated whenever user changes these values. Values are - * into file at the end of Atlantis session. - * - * TODO: - * last used geometry (will be simpler when TB mode (and Atlantis.mode in - * general is discontinued), geometry names will be considered - * after '_' up to the file extension (.xml) - * last event file - * - * @author Zdenek Maxa - */ -public class ADefaultValues -{ - // file where the cross-session runtime values are stored - public static final String CONFIGFILE = System.getProperty("user.home") + - System.getProperty("file.separator") + - ".Atlantis-runtime_values.txt"; - // main attribute which holds all data - private static Hashtable v = new Hashtable(); - - private static ALogger logger = ALogger.getLogger(ADefaultValues.class); - - private ADefaultValues() {} - - - - /** - * Variables controled by this class and their default values if the - * runtime config does not exist or if some values are missing in the file. - */ - private static void setDefaultValues() - { - String FILE_SEPAR = System.getProperty("file.separator"); - String homeDirectory = AGlobals.instance().getHomeDirectory(); - v.put("LastEventFilesSourceDir", homeDirectory + "events" + FILE_SEPAR); - v.put("LastEventFilesSaveDir", homeDirectory); - v.put("LastCanvasPlotSaveDir", homeDirectory); - v.put("JiveXMLServerName", ""); - v.put("JiveXMLServerPort", "48965"); - v.put("GeometryName", ""); - - } // setDefaultValues() ------------------------------------------------- - - - - private static Hashtable readRuntimeConfigFile() - { - Hashtable helpTable = null; - String line = null; - String[] l = null; - String patternLine = ".*=.*"; - Pattern pattern = Pattern.compile(patternLine); - - try - { - BufferedReader in = new BufferedReader(new FileReader(CONFIGFILE)); - helpTable = new Hashtable(); - logger.info("Atlantis runtime configuration file: " + CONFIGFILE); - - while((line = in.readLine()) != null) - { - Matcher matcher = pattern.matcher(line); - if(matcher.matches()) - { - l = line.split("="); - if(l != null && l.length == 2) - { - logger.debug("Configuration value: " + - l[0] + " : " + l[1] + " read in"); - - // remove quotes - l[1] = l[1].replaceAll("\"", ""); - helpTable.put(l[0].trim(), l[1].trim()); - } - else - { - logger.warn("Line: " + line + " from runtime " + - "configuration file: " + CONFIGFILE + - " does not match, line is ignored"); - } - } - } // while - - // file is successfully read in a helper Hash table - in.close(); - - return helpTable; - - } // try - catch(FileNotFoundException ex) - { - logger.warn("Runtime configuration file: " + CONFIGFILE + - " not found, using default runtime values"); - } - catch(IOException ex) - { - logger.error("I/O error while reading " + CONFIGFILE + - " file, using default runtime values"); - } - - return null; - - } // readRuntimeConfigFile() -------------------------------------------- - - - - public static void readRuntimeValues() - { - setDefaultValues(); - Hashtable help = readRuntimeConfigFile(); - if(help != null) - { - for(Enumeration e = v.keys() ; e.hasMoreElements() ;) - { - String s = (String) e.nextElement(); - if(help.containsKey(s)) - { - // keys match, update the value - v.remove(s); - v.put(s, help.get(s)); - } - } - } - - } // readRuntimeValues() ------------------------------------------------ - - - - public static void saveRuntimeValues() - { - try - { - // if exists, shall be overwritten - BufferedWriter out = new BufferedWriter(new FileWriter(CONFIGFILE)); - - for(Enumeration e = v.keys() ; e.hasMoreElements() ;) - { - String s = (String) e.nextElement(); - out.write(s + " = \"" + v.get(s) + "\"\n"); - } - out.close(); - } - catch(IOException ex) - { - logger.error("Can't open " + CONFIGFILE + " for writing, runtime " + - "configuration values not saved"); - } - - } // saveRuntimeValues() ------------------------------------------------ - - - - public static String get(String key) - { - if(v.containsKey(key)) - { - return(String) v.get(key); - } - else - { - logger.warn("Runtime configuration value: " + key + " does not exist", new Exception()); - return null; - } - - } // get() -------------------------------------------------------------- - - - - public static void set(String key, String value) - { - if(v.containsKey(key)) - { - v.remove(key); - v.put(key, value); - } - else - { - logger.warn("Runtime configuration value: " + key + " does not exist", new Exception()); - } - - } // set() -------------------------------------------------------------- - - - -} // class ADefaultValues =================================================== diff --git a/graphics/AtlantisJava/src/atlantis/config/package.html b/graphics/AtlantisJava/src/atlantis/config/package.html deleted file mode 100644 index 96bd70b4cac..00000000000 --- a/graphics/AtlantisJava/src/atlantis/config/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<html> -<head></head> -<body> -<p>Classes for handling the configuration file and its contents.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/data/A3DPointData.java b/graphics/AtlantisJava/src/atlantis/data/A3DPointData.java deleted file mode 100755 index b4354b3e564..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/A3DPointData.java +++ /dev/null @@ -1,254 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.*; -import atlantis.utils.*; - - -public abstract class A3DPointData extends AHitData { - - protected float[] rho; - protected float[] phi; - protected float[] z; - protected float[] x; - protected float[] y; - - - A3DPointData(AHashMap p, AEvent e) { - super(p,e); - if(p.get("x")!=null) { - x=p.getFloatArray("x"); - y=p.getFloatArray("y"); - z=p.getFloatArray("z"); - rho=new float[numData]; - phi=new float[numData]; - - // this is needed for the moment so that S3D sub and layer can be - // calculated from rph,phi,z rho phi from x y - for(int i=0; i<rho.length; ++i) { - double dx=x[i]; - double dy=y[i]; - - rho[i]=(float)(Math.sqrt(dx*dx+dy*dy)); - phi[i]=(float)(Math.atan2(dy, dx)); - if(phi[i]<0.) phi[i]+=AMath.TWO_PI; - } - } else { - rho=p.getFloatArray("rho"); - phi=p.getFloatArray("phi"); - z=p.getFloatArray("z"); - x=new float[numData]; - y=new float[numData]; - calculateXY(rho, phi, x, y); - } - } - - - public float[] getRho() - { - return rho; - } - - - public float[] getPhi() - { - return phi; - } - - - public float[] getX() - { - return x; - } - - - public float[] getY() - { - return y; - } - - - public float[] getZ() - { - return z; - } - - - protected void calculateRhoPhi() - { - calculateRhoPhi(x, y, rho, phi); - } - - protected ACoord getYXUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=x[list]; - v[i]=y[list]; - index[i]=list; - } - return new ACoord(h, v, index, this); - } - - protected ACoord getRZUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - if(phiMid>AMath.TWO_PI) phiMid-=AMath.TWO_PI; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=z[list]; - double phiDiff=Math.abs(phi[list]-phiMid); - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - { - v[i] = rho[list]; - } - else - { - v[i] = -rho[list]; - } - index[i]=list; - - } - return new ACoord(h, v, index, this); - } - - protected ACoord getXZUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - double phi0=Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0=Math.cos(phi0); - double sinPhi0=Math.sin(phi0); - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=z[list]; - v[i]=x[list]*cosPhi0+y[list]*sinPhi0; - index[i]=list; - } - return new ACoord(h, v, index, this); - } - - protected ACoord getYZUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - double phi0=Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0=Math.cos(phi0); - double sinPhi0=Math.sin(phi0); - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=z[list]; - v[i]=y[list]*cosPhi0-x[list]*sinPhi0; - index[i]=list; - } - return new ACoord(h, v, index, this); - } - - protected ACoord get3DUser() { - makeDrawList(); - double[][] hvo=AProjection3D.getRotated(numDraw, listdl, x, y, z); - double[] h=hvo[0]; - double[] v=hvo[1]; - int[] index=new int[numDraw]; - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - index[i]=list; - } - return new ACoord(h, v, index, this); - } - -// does not fit in normal scheme - public double[][] get3DPoints() { - makeDrawList(); - double[][] xyz =new double[numDraw][3]; - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - xyz[i][0]=x[list]; - xyz[i][1]=y[list]; - xyz[i][2]=z[list]; - } - return xyz; - } - -// does not fit in normal scheme - public int[] get3DPointsIndex() { - makeDrawList(); - int[] index=new int[numDraw]; - for(int i=0; i<numDraw; i++) - index[i]=listdl[i]; - return index; - } - - protected ACoord getFZUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=z[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FZ"); - } - - protected ACoord getFRUser() { - makeDrawList(); - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - h[i]=rho[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FR"); - } - - protected ACoord getVPUser() { - makeDrawList(); - // each point is drawn twice - int numTotal=2*numDraw; - double[] h=new double[numTotal]; - double[] v=new double[numTotal]; - int[] index=new int[numTotal]; - - double[] sign=new double[] {-1., 1.}; - int num=0; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - double eta=AParameterUtilities.eta(z[list], rho[list]); - double delEta=AProjectionVP.getDeltaEta(rho[list], z[list]); - for(int j=0; j<2; j++) { - h[num]=eta+sign[j]*delEta; - v[num]=AParameterUtilities.phi(x[list], y[list]); - index[num]=list; - num++; - } - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AAODData.java b/graphics/AtlantisJava/src/atlantis/data/AAODData.java deleted file mode 100644 index 8c412fd1139..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AAODData.java +++ /dev/null @@ -1,359 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.event.*; -import java.util.Vector; - -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -public abstract class AAODData extends AData -{ - protected float[] eta; - protected float[] phi; - protected float[] pT; - - AAODData(AHashMap p, AEvent e) - { - super(p,e); - eta = p.getFloatArray("eta"); - phi = p.getFloatArray("phi"); - pT = p.getFloatArray("pt"); - int[] pdgId = p.getUnsureIntArray("pdgId"); - if(pdgId != null) - { - for(int i=0; i<pT.length; i++) - pT[i] *= -AMath.getSign(pdgId[i]); - } - - if (p.get("clusterKey") != null) - { - int[] clusterLinkCount = p.getUnsureIntArray("clusterLinkCount"); - event.getAssociationManager().add(new AObjectsAssociation(getFullName(), "Cluster", - p.getStringArray("clusterKey"), p.getIntArray("clusterIndex"), clusterLinkCount, event)); - } - if (p.get("trackKey") != null) - { - int[] trackLinkCount = p.getUnsureIntArray("trackLinkCount"); - event.getAssociationManager().add(new AObjectsAssociation(getFullName(), "Track", - p.getStringArray("trackKey"), p.getIntArray("trackIndex"), trackLinkCount, event)); - } - } - - - public float getEta(int index) - { - return eta[index]; - } - - - public float getPhi(int index) - { - return phi[index]; - } - - - public float getPT(int index) - { - return pT[index]; - } - - - public float[] getEta() - { - return eta; - } - - - public float[] getPhi() - { - return phi; - } - - - public float[] getPT() - { - return pT; - } - - - protected int internalColor() - { - int colorFunction=parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction==0) - colorByConstant(); - else if(colorFunction==1) - colorByIndex(); - - return 1; - } - - public String getNameScreenName() - { - return getParameterGroup(); - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - protected void applyCuts() - { - cutIndex(); - cutPhi(phi); - cutEta(eta); - } - - // info on AOD data contained in V-Plot rubberband selection - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumP = 0.; - double sumPt = 0.; - - for (int i = 0; i < numDraw; ++i) - { - sumPt += Math.abs(pT[listdl[i]]); - sumP += Math.abs(pT[listdl[i]] / Math.cos(AMath.lambda(eta[listdl[i]]))); - } - - StringBuffer msg = new StringBuffer(""); - msg.append(numDraw); - msg.append(" "); - msg.append(getFullName()); - msg.append(" sum(PT) = "); - msg.append(String.format("%.1f", sumPt)); - msg.append(" sum(P) = "); - msg.append(String.format("%.1f",sumP)); - - return msg.toString(); - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP) - { - drawVP(window, ag, projection); - } - else - { - super.draw(window, ag, projection); - } - } - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - double dphi = Math.toRadians(0.5); - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - double cosPlus = Math.cos(phiPlus); - double sinPlus = Math.sin(phiPlus); - double cosMinus = Math.cos(phiMinus); - double sinMinus = Math.sin(phiMinus); - //same rhoMax/Minus values used in AJetData - double rhoMax = 1200; - double rhoMinus = 400; - //if no composite particles increase AOD size - Vector<String> keys = event.getCollections().get("CompositeParticle"); - if(keys == null || !parameterStore.get("Data", "CompositeParticle").getStatus()) - rhoMax=1200; - else if(PARAMETER_GROUP.equals("CompositeParticle")) - { - // display composite particle outside of normal AOD data - rhoMax=1200; - rhoMinus=800; - } - - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double rhoPlus = rhoMax; - double s = 10; - if(Math.abs(pT[list]) < maxEnergy) - rhoPlus = rhoMinus + (rhoMax - rhoMinus) * s *Math.abs(pT[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = rhoMinus * cosPlus; - hv[1][i][0] = rhoMinus * sinPlus; - // x1, y1 - hv[0][i][1] = rhoPlus * cosPlus; - hv[1][i][1] = rhoPlus * sinPlus; - // x2, y2 - hv[0][i][2] = rhoPlus * cosMinus; - hv[1][i][2] = rhoPlus * sinMinus; - // x3, y3 - hv[0][i][3] = rhoMinus * cosMinus; - hv[1][i][3] = rhoMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getFRUser() - { - ACoord coordFR = getYXUser().convertYXToFR().includePhiWrapAround("FR"); - return coordFR; - } - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - double dtheta = Math.toRadians(0.5); - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list]-phiMid); - double rSign; - if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) - rSign = -1; - else - rSign = 1; - - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta[list]))) * 2.0; - if ((eta[list] > 0.) && (rSign == -1)) - theta = 2 * Math.PI - theta; - else if ((eta[list] < 0.) && (rSign == -1)) - theta += Math.PI; - else if ((eta[list] < 0.) && (rSign == 1)) - theta = Math.PI - theta; - - double thetaPlus = theta + dtheta; - double thetaMinus = theta - dtheta; - double cosPlus = Math.cos(thetaPlus); - double sinPlus = Math.sin(thetaPlus); - double cosMinus = Math.cos(thetaMinus); - double sinMinus = Math.sin(thetaMinus); - - // decide the region based on the theta value - final byte TOP_BOTTOM = 0; - final byte LEFT_RIGHT = 1; - byte region = TOP_BOTTOM; - // hard-coded value is based on the values in Geometry - if(Math.abs(Math.tan(theta)) < 0.8) - region = LEFT_RIGHT; - - double radiusMinus = 0.; - switch(region) - { - case TOP_BOTTOM: - if(PARAMETER_GROUP.equals("CompositeParticle")) - radiusMinus = 750 / Math.abs(Math.sin(theta)); - else - radiusMinus = 550 / Math.abs(Math.sin(theta)); - break; - case LEFT_RIGHT: - if(PARAMETER_GROUP.equals("CompositeParticle")) - radiusMinus = 850 / Math.abs(Math.cos(theta)); - else - radiusMinus = 700 / Math.abs(Math.cos(theta)); - break; - } - //same rhoMax/Minus values used in AJetData - double radiusMax = radiusMinus + 500; - //if no composite particles increase AOD size - Vector keys = (Vector) event.getCollections().get("CompositeParticle"); - if(keys == null || !parameterStore.get("Data", "CompositeParticle").getStatus()) - radiusMax+=200; - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double radiusPlus = radiusMax; - double s = 10; - if(Math.abs(pT[list]) < maxEnergy) - radiusPlus = radiusMinus + (radiusMax - radiusMinus) * s * Math.abs(pT[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = radiusMinus * cosPlus; - hv[1][i][0] = radiusMinus * sinPlus; - // x1, y1 - hv[0][i][1] = radiusPlus * cosPlus; - hv[1][i][1] = radiusPlus * sinPlus; - // x2, y2 - hv[0][i][2] = radiusPlus * cosMinus; - hv[1][i][2] = radiusPlus * sinMinus; - // x3, y3 - hv[0][i][3] = radiusMinus * cosMinus; - hv[1][i][3] = radiusMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getVPUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - h[i]=eta[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - private void drawVP(AWindow window, AGraphics ag, AProjection2D projection) - { - ACoord centers = window.calculateDisplay(getUser(projection)); - int[] drawlist = centers.index; - double eLimit = 0.025; - int numPoints = 25; - if(PARAMETER_GROUP.equals("CompositeParticle")) - numPoints = 5; - double[][][] hv = new double[2][drawlist.length][numPoints]; //circle - // a cross at centre - double[][][] hv_cross1 = new double[2][drawlist.length][2]; - double[][][] hv_cross2 = new double[2][drawlist.length][2]; - int crossLength = 6; - - for(int i=0; i<drawlist.length; ++i) - { - int list = drawlist[i]; - double e; - e = Math.abs(pT[list]); - int d = (int)(Math.sqrt((e/eLimit)/Math.PI)); - if(d == 0) d = 1; - for(int j=0; j<numPoints; j++) - { - hv[0][i][j]=centers.hv[0][0][i]+d*Math.cos(Math.PI*2*j/(numPoints-1)); - hv[1][i][j]=centers.hv[1][0][i]+d*Math.sin(Math.PI*2*j/(numPoints-1)); - } - for(int j=0; j<2; j++) - { - hv_cross1[0][i][j]=centers.hv[0][0][i]+crossLength/2*Math.cos(Math.PI*(1+4*j)/4); - hv_cross1[1][i][j]=centers.hv[1][0][i]+crossLength/2*Math.sin(Math.PI*(1+4*j)/4); - hv_cross2[0][i][j]=centers.hv[0][0][i]+crossLength/2*Math.cos(Math.PI*(3+4*j)/4); - hv_cross2[1][i][j]=centers.hv[1][0][i]+crossLength/2*Math.sin(Math.PI*(3+4*j)/4); - } - } - ag.draw(new ACoord(hv, drawlist, this, ACoord.POLYLINES)); - ag.draw(new ACoord(hv_cross1, drawlist, this, ACoord.POLYLINES)); - ag.draw(new ACoord(hv_cross2, drawlist, this, ACoord.POLYLINES)); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ABJetData.java b/graphics/AtlantisJava/src/atlantis/data/ABJetData.java deleted file mode 100755 index 7c047a26efa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ABJetData.java +++ /dev/null @@ -1,134 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.A3Vector; -import atlantis.utils.A4Vector; - -/** - * Reconstructed B-Jet - */ -public class ABJetData extends AAODData -{ - private float[] lhSig; - private float[] weight; - private String[] label; - private float[] mass; - //Variable to ensure backwards compatability - protected boolean has4Vect = false; - - ABJetData(AHashMap p, AEvent e) - { - super(p,e); - lhSig=p.getFloatArray("lhSig"); - weight=p.getFloatArray("weight"); - label=p.getUnsureStringArray("label"); - if (p.get("mass") != null) { - mass=p.getFloatArray("mass"); - has4Vect = true; - } - } - - public String getParameterGroup() - { - return "BJet"; - } - - public float getweight(int index) - { - return weight[index]; - } - - public float getlhSig(int index) - { - return lhSig[index]; - } - - public String getLabel(int index) - { - return label[index]; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - if(has4Vect){ - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM(pT[k],eta[k],phi[k],mass[k]); - sum.add(start); - } - }else{ - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A3Vector start = A3Vector.fromRhoPhiZ(0., 0., 0.); - double tL = AMath.tanLambda(eta[k]); - A3Vector stop = A3Vector.fromRhoPhiZ(1., phi[k], tL); - A3Vector v = (stop.subtract(start)).normalize(); - double p = pT[k] / Math.sqrt(1. - v.z * v.z); - sum.add(new A4Vector(v.scale(p), 0.)); - } - } - return sum; - } - - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsObjects", "BJetPt", " |ET|", pT); - cut("CutsObjects", "BJetlhSig", " |lhSig|", lhSig); - cut("CutsObjects", "BJetweight", " |weight|", weight); - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",phi[index])+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - if(label != null) - { - msg.append("\n label = "); - msg.append(label[index]); - } - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",phi[index])); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - msg.append("\n lhSig = "); - msg.append(lhSig[index]); - msg.append("\n weight = "); - msg.append(weight[index]); - - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ACSCDData.java b/graphics/AtlantisJava/src/atlantis/data/ACSCDData.java deleted file mode 100755 index d724dfe7fc7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ACSCDData.java +++ /dev/null @@ -1,304 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; - -public class ACSCDData extends AMuonHitData -{ - private static final double CSC_TILT_ANGLE = Math.toRadians(-11.59); - - float[] charge; - float[] length; - int[] gasGap; - - private static ALogger logger = ALogger.getLogger(ACSCDData.class); - - public String getParameterGroup() - { - return "CSC"; - } - - public String getName() - { - return "CSCD"; - } - - public String getNameScreenName() - { - return "CSC Digits"; - } - - ACSCDData(AHashMap p, AEvent e) - { - super(p,e); - - if (p.get("length") != null) { - length=p.getFloatArray("length"); - } else { - // If no length is given, just use an arbitrary minimum length - length = new float[numData]; - for (int i=0; i<numData; i++) - length[i] = 10.f; - } - - charge=p.getFloatArray("charge"); - - gasGap = new int[numData]; - for (int i=0; i<numData; i++) { - try { - gasGap[i] = AIdHelper.cscWireLayer(id[i]); - } catch (AAtlantisException aex) { - gasGap[i] = 0; - } - } - } - - protected int getStation(int index) - { - return 0; - } - - protected int getSub(int index) - { - try { - if (AIdHelper.stationEta(id[index]) < 0) { - return 0; - } else { - return 1; - } - - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - } - - public int getSector(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(2) == 'L') { - return 2 * (AIdHelper.stationPhi(id[index]) - 1); - } else { - return 2 * (AIdHelper.stationPhi(id[index]) - 1) + 1; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding CSCD identifier", e); - } - - return 0; - } - - protected boolean getMeasuresPhi(int index) - { - try { - if (AIdHelper.cscMeasuresPhi(id[index]) == 1) { - return true; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding CSCD identifier", e); - } - - return false; - } - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsMuon", "Charge", " Charge", charge); - cutPhi(phi); - cutEta(rho, z); - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - protected ACoord getYXUser() - { - makeDrawList(); - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_MDT_INNER) - return ACoord.NO_DATA; - - AParameter cscGasGap = parameterStore.get("YX", "CSCGasGap"); - if (cscGasGap.getStatus()) - cutArray(gasGap, cscGasGap.getI(), "CSC Gas Gap"); - - double[][][] hv = new double[2][numDraw][2]; - int index[] = new int[numDraw]; - - try { - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - if (AIdHelper.cscMeasuresPhi(id[j]) == 1) { - double phi = Math.atan2(y[j], x[j]); - double rho = Math.sqrt(x[j]*x[j] + y[j]*y[j]); - double drho = length[j]/2.; - - hv[0][i][0] = (rho - Math.cos(CSC_TILT_ANGLE) * drho) * Math.cos(phi); - hv[1][i][0] = (rho - Math.cos(CSC_TILT_ANGLE) * drho) * Math.sin(phi); - hv[0][i][1] = (rho + Math.cos(CSC_TILT_ANGLE) * drho) * Math.cos(phi); - hv[1][i][1] = (rho + Math.cos(CSC_TILT_ANGLE) * drho) * Math.sin(phi); - } else { - double phi = Math.atan2(y[j], x[j]); - double rho = Math.sqrt(x[j]*x[j] + y[j]*y[j] + length[j]*length[j]/4.); - double dphi = Math.asin((length[j]/2.) / rho); - - hv[0][i][0] = rho * Math.cos(phi - dphi); - hv[1][i][0] = rho * Math.sin(phi - dphi); - hv[0][i][1] = rho * Math.cos(phi + dphi); - hv[1][i][1] = rho * Math.sin(phi + dphi); - } - } - - return new ACoord(hv, index, this); - } catch (AAtlantisException e) { - AOutput.append("Error decoding CSC identifier: " + e.getMessage(), ALogInterface.BAD_COMMAND); - return ACoord.NO_DATA; - } - } - - protected ACoord getFRUser() - { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - protected ACoord getXZRZUser(int sign[]) - { - double[][][] hv = new double[2][numDraw][]; - int index[] = new int[numDraw]; - - try { - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - double rho = Math.sqrt(x[j]*x[j] + y[j]*y[j]); - - if (AIdHelper.cscMeasuresPhi(id[j]) == 1) { - double drho = length[j]/2.; - if(z[j] < 0){ - hv[0][i] = new double[] {z[j] - sign[i]*Math.sin(CSC_TILT_ANGLE) * drho, - z[j] + sign[i]*Math.sin(CSC_TILT_ANGLE) * drho }; - - hv[1][i] = new double[] { sign[i] * (rho + sign[i]*Math.cos(CSC_TILT_ANGLE) * drho), - sign[i] * (rho - sign[i]*Math.cos(CSC_TILT_ANGLE) * drho) }; - - }else{ - hv[0][i] = new double[] {z[j] - Math.sin(CSC_TILT_ANGLE) * drho, - z[j] + Math.sin(CSC_TILT_ANGLE) * drho }; - - - hv[1][i] = new double[] { sign[i] * (rho - Math.cos(CSC_TILT_ANGLE) * drho), - sign[i] * (rho + Math.cos(CSC_TILT_ANGLE) * drho) }; - } - - - - } else { - hv[0][i] = new double[] { z[j] }; - hv[1][i] = new double[] { sign[i] * rho }; - } - - } - - return new ACoord(hv, index, this); - } - catch (AAtlantisException e) { - AOutput.append("Error decoding CSC identifier: " + e.getMessage(), ALogInterface.BAD_COMMAND); - return ACoord.NO_DATA; - } - - } - - - - - protected ACoord getXZUser() { - makeDrawList(); - cutMuonSector(sector); - - int[] sign = new int[numDraw]; - int sect = (int) Math.round(parameterStore.get("XZ", "Phi").getD() / 22.5); - - for(int i=0; i<numDraw; i++) { - if (sector[listdl[i]] == sect) - sign[i] = 1; - else - sign[i] = -1; - } - - return getXZRZUser(sign); - } - - protected ACoord getRZUser() { - makeDrawList(); - - int[] sign = new int[numDraw]; - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - sign[i] = AParameterUtilities.getRhoSign(x[j], y[j]); - } - - return getXZRZUser(sign); - } - - protected ACoord getFZUser() - { - double[][][] hv = new double[2][numDraw][]; - int index[] = new int[numDraw]; - - try { - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - double rho = Math.sqrt(x[j]*x[j] + y[j]*y[j]); - double phi = Math.toDegrees(Math.atan2(y[j], x[j])); - - if (AIdHelper.cscMeasuresPhi(id[j]) == 1) { - double drho = length[j]/2.; - - hv[0][i] = new double[] { z[j] - Math.sin(CSC_TILT_ANGLE) * drho, - z[j] + Math.sin(CSC_TILT_ANGLE) * drho }; - hv[1][i] = new double[] { phi, phi }; - } else { - double dphi = Math.toDegrees(Math.atan2(length[j]/2., rho)); - - hv[0][i] = new double[] { z[j], z[j] }; - hv[1][i] = new double[] { phi-dphi, phi+dphi }; - } - } - - return new ACoord(hv, index, this); - } catch (AAtlantisException e) { - AOutput.append("Error decoding CSCD identifier: " + e.getMessage(), ALogInterface.BAD_COMMAND); - return ACoord.NO_DATA; - } - } - - // only constant color possible for the strips - protected int internalColor() - { - int constantColor=parameterStore.get(PARAMETER_GROUP, "Strip").getI(); - for(int i=0; i<numData; i++) - color[i]=(byte)constantColor; - return 0; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ACSCData.java b/graphics/AtlantisJava/src/atlantis/data/ACSCData.java deleted file mode 100755 index 5149a5133bd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ACSCData.java +++ /dev/null @@ -1,197 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; - -public class ACSCData extends AMuonHitData -{ - float[] sigma; - - private static ALogger logger = ALogger.getLogger(ACSCData.class); - - public String getParameterGroup() - { - return "CSC"; - } - - public String getName() - { - return "CSC"; - } - - public String getNameScreenName() - { - return "CSC"; - } - - ACSCData(AHashMap p, AEvent e) - { - super(p,e); - sigma=p.getFloatArray("sigma"); - } - - protected int getStation(int index) - { - return 0; - } - - protected int getSub(int index) - { - try { - if (AIdHelper.stationEta(id[index]) < 0) { - return 0; - } else { - return 1; - } - - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - } - - public int getSector(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(2) == 'L') { - return 2 * (AIdHelper.stationPhi(id[index]) - 1); - } else { - return 2 * (AIdHelper.stationPhi(id[index]) - 1) + 1; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding CSC identifier", e); - } - - return 0; - } - - protected boolean getMeasuresPhi(int index) - { - try { - if (AIdHelper.cscMeasuresPhi(id[index]) == 1) { - return true; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding CSC identifier", e); - } - - return false; - } - - protected void applyCuts() - { - super.applyCuts(); - cutPhi(phi); - cutEta(rho, z); - } - - protected ACoord getYXUser() - { - makeDrawList(); - int mode=parameterStore.get("YX", "Mode").getI(); - if(mode!=5) - numDraw=0; - - double[] h=new double[numDraw]; - double[] v=new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - h[i]=x[list]; - v[i]=y[list]; - index[i]=list; - } - return new ACoord(h, v, index, this); - } - - protected ACoord getXZRZUser(int[] sign) - { - int numPoints=2; - - double[][][] hv=new double[2][numDraw][numPoints]; - int[] index=new int[numDraw]; - - // space point resolution is 60um in rz and 5mm in rphi (due to no uniform b field) - // from muonTDR page 201 - // double dRho=0.254; - // double dZMax=1.25; - - double alpha=-11.59; - double sinAlphaCopy=Math.sin(Math.toRadians(alpha)); - double cosAlphaCopy=Math.cos(Math.toRadians(alpha)); - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - - double rMid=sign[i]*getSectorRho(sector[list], rho[list], phi[list]); - double zMid=z[list]; - // double dZ = 2. * dZMax * Math.min(charge[list] / (25. * 75000.), 0.9); - double dRho=sigma[list]; - - double sinAlpha=sinAlphaCopy; - double cosAlpha=cosAlphaCopy; - - if(zMid>0.) - cosAlpha*=-1.; - if(rMid<0.) - sinAlpha*=-1.; - - hv[0][i][0]=zMid-sinAlpha*dRho; - hv[0][i][1]=zMid+sinAlpha*dRho; - hv[1][i][0]=rMid+cosAlpha*dRho; - hv[1][i][1]=rMid-cosAlpha*dRho; - index[i]=list; - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - protected int getDrawOrFill() - { - return AGraphics.DRAW; - } - - protected ACoord getRZUser() - { - makeDrawList(); - int[] sign=new int[numDraw]; - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for(int i=0; i<numDraw; i++) - { - double phiDiff=Math.abs(phi[listdl[i]]-phiMid); - - sign[i]=-1; - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - sign[i]=1; - } - return getXZRZUser(sign); - } - - protected ACoord getXZUser() - { - makeDrawList(); - cutMuonSector(sector); - int[] sign=new int[numDraw]; - int sect=(int)Math.round(parameterStore.get("XZ", "Phi").getD() / 22.5); - - for(int i=0; i<numDraw; i++) - { - sign[i]=1; - if(sector[listdl[i]]!=sect) - sign[i]=-1; - } - return getXZRZUser(sign); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ACalorimeterData.java b/graphics/AtlantisJava/src/atlantis/data/ACalorimeterData.java deleted file mode 100644 index e82e3d4a07e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ACalorimeterData.java +++ /dev/null @@ -1,2662 +0,0 @@ -package atlantis.data; - -import atlantis.event.AEvent; -import java.awt.Color; -import java.util.Vector; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.ADrawCalorimeterSummedEndcaps; -import atlantis.canvas.ALegendWindow; -import atlantis.canvas.AWindow; -import atlantis.event.AData; -import atlantis.geometry.ABarrelCalorimeterDetector; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.geometry.AEndcapCalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.ADrawnGraphics2D; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.utils.APolygon; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; - -/** - * The superclass of all the ATLAS calorimeters. Contains also methods for - * drawing groups of calorimeters together. Calorimeters can not be drawn - * individually due to coupling of energy scale and the standard v-plot picture. - * Each calorimeter also provides histograms. - * - * @author Eric Jansen - */ -public abstract class ACalorimeterData extends AHitData implements AHistogramData -{ - private static ALogger logger = ALogger.getLogger(ACalorimeterData.class); - - // Constants as defined in the configuration file. - // Energy mode options. - public static final int ENERGY_MODE_SUM_LIN = 0; - public static final int ENERGY_MODE_MAX_LIN = 1; - public static final int ENERGY_MODE_SUM_LOG = 2; - public static final int ENERGY_MODE_MAX_LOG = 3; - public static final int ENERGY_MODE_SUM_SQRT = 4; - public static final int ENERGY_MODE_MAX_SQRT = 5; - - // Energy calibration options. - public static final int ENERGY_CALIB_UNKNOWN = -1; - public static final int ENERGY_CALIB_OVERALL = 0; - public static final int ENERGY_CALIB_BY_TYPE = 1; - public static final int ENERGY_CALIB_BY_CALO = 2; - - // Color functions. - public static final int COLOR_FUNC_CONSTANT = 0; - public static final int COLOR_FUNC_SUBDET = 1; - public static final int COLOR_FUNC_CLUSTER = 2; - public static final int COLOR_FUNC_SAMPLING = 3; - public static final int COLOR_FUNC_ENERGY = 4; - public static final int COLOR_FUNC_JET = 5; - public static final int COLOR_FUNC_TYPE = 6; - public static final int COLOR_FUNC_TIME = 7; - - private static final float SCALE_FACTOR_VPLOT = 20; - - public String CALORIMETER_NAME; - - // Properties needed for the histograms. - protected double innerR; - protected double outerR; - protected double innerZ; - protected double outerZ; - protected double outerEta; - - protected double phiGranularity = 0.0; - protected double etaGranularity = 0.0; - protected AParameter histoScale; - - // This constant contains the highest phi or eta index for this data type. - // Its value determines the amount of memory that is allocated for certain - // data structures. - protected short MAX_HIT_INDEX = 512; - protected static final double NON_SCALING_FACTOR = 0.85; - - protected float[] phi; - protected float[] eta; - protected float[] dphi; - protected float[] deta; - protected float[] energy; - protected float[] et; - protected float[] etSum; - - // Et is more useful than pure Energy, so use Et to replace Energy - // protected float[] energySum; - - protected byte[] side; - protected short[] etaIndex; - protected short[] phiIndex; - protected int[] sampling; - protected short[] detector; - - private int[][] cellTable; - - protected double minDensityECAL; - protected double maxDensityECAL; - protected double minDensityHCAL; - protected double maxDensityHCAL; - - // following attributes occur at majority of calorimeter subdetectors - // which inherit from here, but not at all of them (TILE is usually - // the exception), checks are always done, so it's save ; - // retrieving the data from XML is pre-checked so that not to spit out - // unnecessary complaints - protected int[] feedThrough = null; - protected int[] channel = null; - protected int[] slot = null; - protected int[] BadCell = null; - - - ACalorimeterData(AHashMap p, AEvent e) - { - super(p,e); - - CALORIMETER_NAME = getName(); - - energy = p.getFloatArray("energy"); - et = new float[numData]; - - phi = new float[numData]; - eta = new float[numData]; - deta = new float[numData]; - dphi = new float[numData]; - - // energySum = new float[numData]; - etSum = new float[numData]; - - side = new byte[numData]; - etaIndex = new short[numData]; - phiIndex = new short[numData]; - sampling = new int[numData]; - detector = new short[numData]; - - histoScale = parameterStore.get(CALORIMETER_NAME, "HistoScale"); - - // using AHashMap.getUnsureIntArray() does not complain if key is - // not found - these parameters may not be present in all calorimetry - // classes inherited from ACalorimeterData and using this call - // also covers backwards compatibility, and is safe - null is returned - // if key does not exist - feedThrough = p.getUnsureIntArray("feedThrough"); - channel = p.getUnsureIntArray("channel"); - slot = p.getUnsureIntArray("slot"); - BadCell = p.getUnsureIntArray("BadCell"); - - } - - /** - * Get the name used for associating this datatype/collection. For the - * calorimeter cells no storegate key is used. - * @return - */ - public String getFullName() { - return getName(); - } - - /** - * getADCCountsData() - * reads in adcCounts array from XML data. This method is currently used - * for LAr, FCAL, HEC and MBTS (TILE has two adcCounts arrays) - * @param p AHashMap - */ - protected int[][] getADCCountsData(AHashMap p) - { - int[][] adcCounts = null; - int[] adc = (p.get("adcCounts") != null) ? p.getIntArray("adcCounts") : null; - if(adc != null) - { - adcCounts = new int[numData][0]; - // multiple numbers are associated with each cell - int multiple = adc.length / numData; - int num = 0; - for(int i = 0; i < numData; i++) - { - adcCounts[i] = new int[multiple]; - for (int j = 0; j < multiple; j++) - { - adcCounts[i][j] = adc[num]; // fill in array for each cell - num++; - } - } - } // if(adc != null) - - return adcCounts; - - } // getADCCountsData() ------------------------------------------------- - - - - /** - * Class used to merge ACoord[] objects. - */ - public static class ACoordArray - { - private Vector<ACoord> v = new Vector<ACoord>(); - - public void add(ACoord[] c) - { - for (int i = 0; i < c.length; i++) - { - v.addElement(c[i]); - } - } - - public ACoord[] getArray() - { - ACoord[] c = new ACoord[v.size()]; - for (int i = 0; i < v.size(); i++) - { - c[i] = (ACoord) v.elementAt(i); - } - return c; - } - } - - - - /** - * Assigns the hits to a geometry object. - */ - public void makeHitToGeometryMapping() - { - int numNotFound = 0; - - // In detector[] we store the hit-to-geometry object mapping. - for (int i = 0; i < numData; i++) - { - detector[i] = (short) ACalorimeterDetector.getDetectorIndex(id[i]); - - if (detector[i] >= 0) - { - eta[i] = (float) ACalorimeterDetector.get(detector[i]).getEta(etaIndex[i], side[i]); - deta[i] = (float) ACalorimeterDetector.get(detector[i]).getDeltaEta(); - phi[i] = (float) ACalorimeterDetector.get(detector[i]).getPhi(phiIndex[i]); - dphi[i] = (float) ACalorimeterDetector.get(detector[i]).getDeltaPhi(); - } - else if (!CALORIMETER_NAME.equals("FCAL")) - { - eta[i] = 0.0f; - deta[i] = 0.0f; - phi[i] = 0.0f; - dphi[i] = 0.0f; - numNotFound++; - } - } - if (numNotFound > 0) - { - System.err.println(numNotFound + "/" + numData + " cells in " + - CALORIMETER_NAME + " not mapped to a geometry object. These will not be drawn."); - } - - // This depends on the number of geometry objects. - cellTable = new int[2 * ACalorimeterDetector.count()][2 * MAX_HIT_INDEX]; - } - - /** - * Returns the name of the calorimeter this data object belongs to. - * - * @return calorimeter name - */ - public String getCalorimeterName() - { - return CALORIMETER_NAME; - } - - - /** - * Method is called from APickInteraction and plots pulse shapes plots - * for a cell when picked. - * @param index int - */ - public void plotPulseShapes(int index, boolean withcurve) { - int[][] adc = getADCCounts(index); - if (adc == null) { - logger.warn("Pulse shape plot requested but no adc data available"); - return; - } - - if (!withcurve) { - APulseShapePlot.plotADCCounts(adc, getPulseTitleString(index), null); - } else { - double[][] ps = getPulseShape(index); - if (ps == null) { - logger.warn("No pulse shape information available, just plotting adc instead"); - APulseShapePlot.plotADCCounts(adc, getPulseTitleString(index), null); - } else { - APulseShapePlot.plotRealPulseShapes(adc, ps, - getPulseStep(index), getPulseSubtitle(index), getPulseTitleString(index)); - } - } - } - - /** - * - */ - protected int[][] getADCCounts(int index) { return null; } - - protected double[][] getPulseShape(int index) { return null; } - - protected double getPulseStep(int index) { return 1.0; } - - protected String[] getPulseSubtitle(int index) { return null; } - - /** - * Returns calorimeter type (ECAL or HCAL) of a certain hit. - * - * @param index int hit index - * @return String calorimeter type - */ - public abstract String getCalorimeterType(int index); - - /** - * Returns the ACalorimeterDetector of a certain hit. - * - * @param index int hit index - * @return ACalorimeterDetector - */ - public ACalorimeterDetector getDetector(int index) { - return ACalorimeterDetector.get(detector[index]); - } - - /** - * Recalculates eta from r and z in case the user wants to have their eta - * with respect to the primary vertex instead of 0. The calculation is a - * little different from the other calorimeter classes because this one - * contains both barrel and endcap data. - * - * @param index int index of hit in data - * @return double eta value - */ - public double getEta(int index) - { - double r, z; - - if (!parameterStore.get("VP", "EtaVertex").getStatus() || detector[index] < 0) - { - return this.eta[index]; - } - - if (ACalorimeterDetector.get(detector[index]) instanceof ABarrelCalorimeterDetector) - { - r = ACalorimeterDetector.get(detector[index]).getR(); - z = r * AMath.tanLambda(eta[index]); - } - else - { - z = ACalorimeterDetector.get(detector[index]).getZ(); - r = z / AMath.tanLambda(eta[index]); - } - - return AParameterUtilities.eta(z, r); - } - - /** - * Returns the calorimeter sampling (or layer) of a certain hit. - * - * @param index int hit index - * @return int sampling/layer - */ - public int getSampling(int index) - { - return sampling[index]; - } - - /** - * Returns the side of the calorimeter of a certain hit. - * - * @param index int hit index - * @return int side - */ - public int getSide(int index) - { - return side[index]; - } - - /** - * Returns the cell size in eta of a certain hit. - * - * @param index int hit index - * @return double cell size in eta - */ - public double getdEta(int index) - { - return deta[index]; - } - - /** - * Returns the cell size in phi of a certain hit. - * - * @param index int hit index - * @return double cell size in phi - */ - public double getdPhi(int index) - { - return dphi[index]; - } - - /** - * Returns the phi coordinate of a certain hit. - * - * @param index int hit index - * @return double phi coordinate. - */ - public double getPhi(int index) - { - return phi[index]; - } - - /** - * Returns the transverse energy of a hit. - * - * @param index int hit index - * @return float transverse energy - */ - public float getET(int index) - { - return et[index]; - } - - /** - * Returns the transverse energy of a list of hits. - * - * @param index int[] list of hit indices - * @return float[] list of transverse energies - */ - public float[] getET(int[] index) - { - float[] temp = new float[index.length]; - - for (int i = 0; i < index.length; i++) - { - temp[i] = et[index[i]]; - } - return temp; - } - - /** - * Returns the calorimeter sampling (or layer) of a list of hits. - * - * @param index int[] list of hit indices - * @return int[] list of samplings - */ - public int[] getSampling(int[] index) - { - int[] temp = new int[index.length]; - - for (int i = 0; i < index.length; i++) - { - temp[i] = sampling[index[i]]; - } - return temp; - } - - /** - * Returns the energy of a hit. - * - * @param index int hit index - * @return float energy - */ - public float getEnergy(int index) - { - return energy[index]; - } - - /** - * Returns the depositied energy of a list of hits. - * - * @param index int[] list of hit indices - * @return float[] list of energies - */ - public float[] getEnergy(int[] index) - { - float[] temp = new float[index.length]; - - for (int i = 0; i < index.length; i++) - { - temp[i] = energy[index[i]]; - } - return temp; - } - - public static double getNonScalingFactor() - { - return NON_SCALING_FACTOR; - } - - /** - * Returns the lowest density for the cell type of the specified hit. - * - * @param index int hit index - * @return double minimum density - */ - protected double getMinDensity(int index) - { - return getMinDensity(getCalorimeterType(index)); - } - - /** - * Returns the lowest densityfor the specified calorimeter type. - * - * @param type String either "ECAL", "HCAL" or "ALL" - * @return double minimum density - */ - protected double getMinDensity(String type) - { - if (type.equals("ECAL")) - { - return minDensityECAL; - } - else if (type.equals("HCAL")) - { - return minDensityHCAL; - } - else if (type.equals("ALL")) - { - // Return the lowest non-zero value. - if (minDensityECAL == 0.0 || minDensityHCAL == 0.0) - { - return Math.max(minDensityECAL, minDensityHCAL); - } - else - { - return Math.min(minDensityECAL, minDensityHCAL); - } - } - else - { - return 0.0; - } - } - - /** - * Returns the highest density for the cell type of the specified hit. - * - * @param index int hit index - * @return double maximum density - */ - protected double getMaxDensity(int index) - { - return getMaxDensity(getCalorimeterType(index)); - } - - /** - * Returns the highest densityfor the specified calorimeter type. - * - * @param type String either "ECAL", "HCAL" or "ALL" - * @return double maximum density - */ - protected double getMaxDensity(String type) - { - if (type.equals("ECAL")) - { - return maxDensityECAL; - } - else if (type.equals("HCAL")) - { - return maxDensityHCAL; - } - else if (type.equals("ALL")) - { - return Math.max(maxDensityECAL, maxDensityHCAL); - } - else - { - return 0.0; - } - } - - /** - * Sets the minimum density for the specified calorimeter type. - * - * @param type String either "ECAL", "HCAL" or "ALL" - * @param density double minimum density to set - */ - protected void setMinDensity(String type, double density) - { - if (type.equals("ECAL")) - { - minDensityECAL = density; - } - else if (type.equals("HCAL")) - { - minDensityHCAL = density; - } - else if (type.equals("ALL")) - { - minDensityECAL = density; - minDensityHCAL = density; - } - } - - /** - * Sets the maximum density for the specified calorimeter type. - * - * @param type String either "ECAL", "HCAL" or "ALL" - * @param density double maximum density to set - */ - protected void setMaxDensity(String type, double density) - { - if (type.equals("ECAL")) - { - maxDensityECAL = density; - } - else if (type.equals("HCAL")) - { - maxDensityHCAL = density; - } - else if (type.equals("ALL")) - { - maxDensityECAL = density; - maxDensityHCAL = density; - } - - parameterStore.get(CALORIMETER_NAME, "Area/Energy").setD(1. / Math.max(maxDensityECAL, maxDensityHCAL)); - } - - /** - * Returns the data that needs to be drawn in the specificied projection. - * - * @param projection AProjection projection - * @return ACoord data to be drawn - */ - protected ACoord getUserNoTransform(AProjection projection) - { - if (CALORIMETER_NAME.equals("FCAL") || CALORIMETER_NAME.equals("MBTS")) - { - // FCAL and MBTS data are not linked to the geometry objects, so use the old method. - return super.getUserNoTransform(projection); - } - else - { - // For all the other types we can simply get the geometry from the - // geometry objects. - makeDrawList(); - filterDrawList(projection); - double[][][] hv = new double[2][numDraw][0]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (detector[j] >= 0) - { - ACoord coord = ACalorimeterDetector.get(detector[j]).getCell(projection, etaIndex[j], phiIndex[j], side[j]); - if (coord.hv[0].length > 0) - { - hv[0][i] = coord.hv[0][0]; - hv[1][i] = coord.hv[1][0]; - } - } - else - { - // Alternative setups compatibility mode based on eta, deta, - // r or z, dr or dz, phi, dphi from event file could be - // implemented here. - } - index[i] = j; - } - - // Apply the wrap arounds for phi in certain projections. - if (projection instanceof AProjectionVP) - { - return new ACoord(hv, index, this).includePhiWrapAround("VP"); - } - else if (projection instanceof AProjectionFR) - { - return new ACoord(hv, index, this).includePhiWrapAround("FR"); - } - else if (projection instanceof AProjectionFZ) - { - return new ACoord(hv, index, this).includePhiWrapAround("FZ"); - } - else - { - return new ACoord(hv, index, this); - } - } - } - - /** - * Returns the data points for the "standard" mode v-plot. - * - * @return ACoord v-plot points - */ - public ACoord getVPPoints() - { - makeDrawList(); - double[][] hv = new double[2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - hv[0][i] = getEta(j); - hv[1][i] = Math.toDegrees(phi[j]); - index[i] = j; - } - return new ACoord(hv, index, this, ACoord.SYMBOLS).includePhiWrapAround("VP"); - } - - /** - * Cleans up the drawList. From all cells that are drawn at a certain place - * only the one that has the highest deposited transverse energy will remain. - * It also sums the transverse energy of the cells it removes. This is stored - * in etSum[] at the index of the "most energetic" cell. - * - * @param projection AProjection projection to be drawn - */ - protected void filterDrawList(AProjection projection) - { - // In the v-plot every cell is drawn, unless we're in one of the special - // modes. - if (projection instanceof AProjectionVP) - { - switch (parameterStore.get("VP", "Mode").getI()) - { - case AProjectionVP.MODE_STANDARD: - // Everything is drawn in the standard mode v-plot. - return; - case AProjectionVP.MODE_ECAL_LAYER_0: - case AProjectionVP.MODE_ECAL_LAYER_1: - case AProjectionVP.MODE_ECAL_LAYER_2: - case AProjectionVP.MODE_ECAL_LAYER_3: - if (!CALORIMETER_NAME.equals("LAr")) - { - // Don't draw HCAL in ECAL mode. - numDraw = 0; - } - return; - case AProjectionVP.MODE_HCAL_LAYER_0: - case AProjectionVP.MODE_HCAL_LAYER_1: - case AProjectionVP.MODE_HCAL_LAYER_2: - case AProjectionVP.MODE_HCAL_LAYER_3: - if (!CALORIMETER_NAME.equals("TILE") && !CALORIMETER_NAME.equals("HEC")) - { - // Don't draw ECAL in HCAL mode. - numDraw = 0; - } - return; - default: - numDraw = 0; - return; - } - } - - // The phi-z projection has special modes as well. - if (projection instanceof AProjectionFZ) - { - if (parameterStore.get(projection.getName(), "Mode").getI() != AProjectionYX.MODE_STANDARD) - { - numDraw = 0; - return; - } - } - // Also the y-x and phi-rho projections have special modes (they share the same mode list). - int mode = parameterStore.get("YX", "Mode").getI(); - if (projection instanceof AProjectionYX || projection instanceof AProjectionFR) - { - if (mode != AProjectionYX.MODE_STANDARD && - (mode < AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER || mode > AProjectionYX.MODE_HEC_SUMMED)) - { - numDraw = 0; - return; - } - else if (mode >= AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && mode <= AProjectionYX.MODE_HEC_SUMMED) - { - if ((mode >= AProjectionYX.MODE_HEC_1 && mode <= AProjectionYX.MODE_HEC_4 && !CALORIMETER_NAME.equals("HEC")) || - (mode < AProjectionYX.MODE_HEC_1 && !CALORIMETER_NAME.equals("LAr")) || - (mode == AProjectionYX.MODE_HEC_SUMMED && !CALORIMETER_NAME.equals("HEC")) || - (mode == AProjectionYX.MODE_LAR_ENDCAP_SUMMED && !CALORIMETER_NAME.equals("LAr"))) - { - numDraw = 0; - return; - } - } - else if(mode == AProjectionYX.MODE_MBTS && !CALORIMETER_NAME.equals("MBTS")) - { - numDraw = 0; - return; - } - } - - float[][] etTable = new float[2 * ACalorimeterDetector.count()][2 * MAX_HIT_INDEX]; - for (int i = 0; i < 2 * ACalorimeterDetector.count(); i++) - { - for (int j = 0; j < 2 * MAX_HIT_INDEX; j++) - { - cellTable[i][j] = -1; - etTable[i][j] = 0.0f; - } - } - - for (int i = 0; i < numDraw; i++) - { - int detIndex = getDetectorIndex(listdl[i]); - int hitIndex = getHitIndex(listdl[i], projection); - - if (detIndex >= 0 && hitIndex >= 0) - { - etTable[detIndex][hitIndex] += et[listdl[i]]; - if (cellTable[detIndex][hitIndex] < 0 || et[cellTable[detIndex][hitIndex]] < et[listdl[i]]) - cellTable[detIndex][hitIndex] = listdl[i]; - } - } - - numDraw = 0; - for (int i = 0; i < 2 * ACalorimeterDetector.count(); i++) - { - for (int j = 0; j < 2 * MAX_HIT_INDEX; j++) - { - if (cellTable[i][j] > 0) - { - listdl[numDraw] = cellTable[i][j]; - etSum[listdl[numDraw]] = etTable[i][j]; - numDraw++; - } - } - } - } - - /** - * This function maps a hit to an index. This index is such that two hits - * get the same index when they are in the same detector and on the same - * side. - * - * @param index int number of the hit in the current dataset - * @return int detector index - */ - protected int getDetectorIndex(int index) - { - if (detector[index] >= 0) - { - if (side[index] > 0) - { - return ACalorimeterDetector.count() + detector[index]; - } - else - { - return detector[index]; - } - } - return -1; - } - - /** - * This function maps a hit to an index. This index is such that two hits in - * the same detector will receive the same index if they will be drawn in - * the same place. - * - * @param index int number of the hit in the current dataset - * @param projection AProjection projection the hit index should be - * calculated for - * @return int hit index - */ - protected int getHitIndex(int index, AProjection projection) - { - if (detector[index] >= 0) - { - if (projection instanceof AProjectionYX) - { - return phiIndex[index]; - } - else if (projection instanceof AProjectionRZ) - { - if (ACalorimeterDetector.get(detector[index]).getRSign(phiIndex[index]) > 0) - { - return MAX_HIT_INDEX + etaIndex[index]; - } - else - { - return etaIndex[index]; - } - } - else if (projection instanceof AProjectionFR) - { - return phiIndex[index]; - } - else if (projection instanceof AProjectionFZ) - { - return phiIndex[index]; - } - } - return -1; - } - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - return ACoord.NO_HISTOGRAMS; - } - - /** - * Returns the histograms in the YX projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getYXHistograms() - { - AHistogram hist = new AHistogram(0., 2. * Math.PI, phiGranularity, histoScale.getD(), this); - int mode = parameterStore.get("YX", "Mode").getI(); - double newInnerR = innerR; - boolean hasAddedToHistogram = false; - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (detector[j] >= 0) - { - if ((mode == AProjectionYX.MODE_STANDARD && ACalorimeterDetector.get(detector[j]) instanceof ABarrelCalorimeterDetector) || - (mode != AProjectionYX.MODE_STANDARD && ACalorimeterDetector.get(detector[j]) instanceof AEndcapCalorimeterDetector)) - { - String name = ACalorimeterDetector.get(detector[j]).getName(); - if (mode == AProjectionYX.MODE_STANDARD || (mode == AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && (name.equals("LAr Endcap Presampler")||name.equals("LAr_EC_Presampler"))) || - (name.equals("LAr Outer Endcap") && getSampling(j) == mode - AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER) || - (name.equals("LAr Inner Endcap") && getSampling(j) == mode - AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER - 1) || - (name.equals("HEC") && getSampling(j) == mode - AProjectionYX.MODE_HEC_1) || - (mode == AProjectionYX.MODE_LAR_ENDCAP_SUMMED && name.indexOf("LAr") >= 0) || (mode == AProjectionYX.MODE_HEC_SUMMED && name.equals("HEC"))) - { - hasAddedToHistogram = true; - double phiMin = ACalorimeterDetector.get(detector[j]).getPhiMin(phiIndex[j]); - double phiMax = ACalorimeterDetector.get(detector[j]).getPhiMax(phiIndex[j]); - - if (phiMin < -1e-9 && phiMax > 1e-9) - { - hist.fill(phiMin + 2. * Math.PI, 2. * Math.PI, etSum[j] / 2.); - hist.fill(0., phiMax, etSum[j] / 2.); - } - else - { - hist.fill(phiMin, phiMax, etSum[j]); - } - if (mode != AProjectionYX.MODE_STANDARD) - { - if (name.equals("HEC")) - { - if (mode != AProjectionYX.MODE_HEC_SUMMED) - { - //can use the get RMin accurately for the HEC - newInnerR = ACalorimeterDetector.get(detector[j]).getRMin(); - } - else if (ACalorimeterDetector.get(detector[j]).getRMin() < newInnerR) - { - //only want to assign HEC ALL minimum if is smaller - newInnerR = ACalorimeterDetector.get(detector[j]).getRMin(); - } - } - else - { - //calculate RMin as not accurate in geometry file - double etaMax = ACalorimeterDetector.get(detector[j]).getEtaMax(); - double zMin = ACalorimeterDetector.get(detector[j]).getZMin(); - double temp = zMin / Math.sinh(etaMax); - //save calculated if smallest - if (temp < newInnerR) - newInnerR = temp; - } - } - } - } - } - } - if (hasAddedToHistogram) - return new ACoord[] { hist.getYXUser(newInnerR) }; - else - return ACoord.NO_HISTOGRAMS; - } - - /** - * Returns the histograms in the phi-rho projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getFRHistograms() - { - AHistogram hist = new AHistogram(0., 2. * Math.PI, phiGranularity, histoScale.getD(), this); - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (detector[j] >= 0) - { - if (ACalorimeterDetector.get(detector[j]) instanceof ABarrelCalorimeterDetector) - { - double phiMin = ACalorimeterDetector.get(detector[j]).getPhiMin(phiIndex[j]); - double phiMax = ACalorimeterDetector.get(detector[j]).getPhiMax(phiIndex[j]); - - if (phiMin < -1e-9 && phiMax > 1e-9) - { - hist.fill(phiMin + 2. * Math.PI, 2. * Math.PI, etSum[j] / 2.); - hist.fill(0., phiMax, etSum[j] / 2.); - } - else - { - hist.fill(phiMin, phiMax, etSum[j]); - } - } - } - } - return new ACoord[] { hist.getFRUser(innerR).includePhiWrapAround("FR") }; - } - - /** - * Returns the histograms in the RZ projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getRZHistograms() - { - AHistogram histUp = new AHistogram(-outerEta, outerEta, etaGranularity, histoScale.getD(), this); - AHistogram histDown = new AHistogram(-outerEta, outerEta, etaGranularity, histoScale.getD(), this); - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (detector[j] >= 0) - { - int sign = ACalorimeterDetector.get(detector[j]).getRSign(phiIndex[j]); - double etaMin = ACalorimeterDetector.get(detector[j]).getEtaMin(etaIndex[j], side[j]); - double etaMax = ACalorimeterDetector.get(detector[j]).getEtaMax(etaIndex[j], side[j]); - - if (sign > 0) - { - histUp.fill(etaMin, etaMax, etSum[j]); - } - else - { - histDown.fill(etaMin, etaMax, etSum[j]); - } - } - } - - ACoordArray c = new ACoordArray(); - c.add(histUp.getRZUser(outerZ, outerR, AHistogram.UP)); - c.add(histDown.getRZUser(outerZ, outerR, AHistogram.DOWN)); - return c.getArray(); - } - - /** - * Returns the histograms in the phi-z projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getFZHistograms() - { - AHistogram hist; - AHistogram histLeft = new AHistogram(0., 2. * Math.PI, phiGranularity, histoScale.getD(), this); - AHistogram histRight = new AHistogram(0., 2. * Math.PI, phiGranularity, histoScale.getD(), this); - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (detector[j] >= 0) - { - if (ACalorimeterDetector.get(detector[j]) instanceof AEndcapCalorimeterDetector) - { - double phiMin = ACalorimeterDetector.get(detector[j]).getPhiMin(phiIndex[j]); - double phiMax = ACalorimeterDetector.get(detector[j]).getPhiMax(phiIndex[j]); - - if (side[j] > 0) - { - hist = histRight; - } - else - { - hist = histLeft; - } - - if (phiMin < -1e-9 && phiMax > 1e-9) - { - hist.fill(phiMin + 2. * Math.PI, 2. * Math.PI, etSum[j] / 2.); - hist.fill(0., phiMax, etSum[j] / 2.); - } - else - { - hist.fill(phiMin, phiMax, etSum[j]); - } - } - } - } - - return new ACoord[] { histLeft.getFZUser(innerZ, AHistogram.LEFT).includePhiWrapAround("FZ"), - histRight.getFZUser(innerZ, AHistogram.RIGHT).includePhiWrapAround("FZ") }; - } - - /** - * Returns the histograms in the x'-z projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getXZHistograms() - { - return ACoord.NO_HISTOGRAMS; - } - - /** - * Returns the histograms in the y'-z projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getYZHistograms() - { - return ACoord.NO_HISTOGRAMS; - } - - /** - * Returns the histograms in the eta-phi projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getVPHistograms() - { - return ACoord.NO_HISTOGRAMS; - } - - /** - * Sets the type of the hits (associated, unassociated). - */ - protected void setType() - { - int[][] cluster = event.getAssociationManager().get(getName(), "Cluster"); - for (int i = 0; i < numData; i++) - { - if (cluster != null && cluster[i] != null) - { - type[i] = 1; - } - else - { - type[i] = 0; - } - } - } - - /** - * Determines if the cells need to be scaled by energy or not. This will be - * true for most cases, but not if the user has selected the color by energy - * color function. - * - * @return boolean true for energy scaling, false for constant cell size - */ - protected boolean energyScaling() - { - return parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI() != COLOR_FUNC_ENERGY; - } - - /** - * Determines the color for each hit according to the color function set by - * the user. - * - * @return int number of coloring options? - */ - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - switch (colorFunction) - { - case COLOR_FUNC_CONSTANT: - colorByConstant(); - break; - - case COLOR_FUNC_SUBDET: - colorBy(sub); - break; - - case COLOR_FUNC_CLUSTER: - colorBy(getClusters()); - break; - - case COLOR_FUNC_SAMPLING: - colorBy(sampling); - break; - - case COLOR_FUNC_ENERGY: - colorByEnergy(); - break; - - case COLOR_FUNC_JET: - if(parameterStore.get("Jet", "ColorFunction").getI()!=1) - { - parameterStore.get("Jet", "ColorFunction").setI(1); - String msg = "Coloring Calo by jet so "; - msg += "ATLAS->Jet->Color Function changed to color by index"; - AOutput.append("\n" + msg + "\n", ALogInterface.WARNING); - } - colorBy(getJets()); - break; - - case COLOR_FUNC_TYPE: - colorByType(); - break; - - case COLOR_FUNC_TIME: - colorByTime(); - break; - } - - return colorFunction + 8; - } - - /** - * Colors cells by energy. - */ - protected void colorByEnergy() - { - double min = 0.0, max = 0.0; - boolean first = true; - int numColors = 17; - float[] en = null; - - switch (parameterStore.get(CALORIMETER_NAME, "EnergyMode").getI()) - { - case ENERGY_MODE_SUM_LIN: - case ENERGY_MODE_SUM_LOG: - case ENERGY_MODE_SUM_SQRT: - en = etSum; - break; - - case ENERGY_MODE_MAX_LIN: - case ENERGY_MODE_MAX_LOG: - case ENERGY_MODE_MAX_SQRT: - en = et; - break; - } - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (first) - { - min = en[j]; - max = en[j]; - first = false; - } - - if (en[j] > max) - max = en[j]; - if (en[j] < min) - min = en[j]; - } - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - if (AColorMap.getColorMap() == AColorMap.COLOR_MAP_BW) - { - // Black and white colormap. - color[j] = AColorMap.BK; - } - else - { - int colorIndex = 0; - - // We have numColors colors available. - switch (parameterStore.get(CALORIMETER_NAME, "EnergyMode").getI()) - { - case ENERGY_MODE_MAX_LIN: - case ENERGY_MODE_SUM_LIN: - colorIndex = (int) (numColors * (en[j] - min) / (max - min)); - break; - case ENERGY_MODE_MAX_LOG: - case ENERGY_MODE_SUM_LOG: - colorIndex = (int) (numColors * (Math.log(en[j]) - Math.log(min)) / (Math.log(max) - Math.log(min))); - break; - case ENERGY_MODE_MAX_SQRT: - case ENERGY_MODE_SUM_SQRT: - colorIndex = (int) (numColors * Math.sqrt((en[j] - min) / (max - min))); - break; - } - - if (colorIndex >= numColors) - colorIndex = (byte) (numColors - 1); - - color[j] = (byte) colorIndex; - } - } - } - - /** - * Colors cells by type (ECAL/HCAL). - */ - protected void colorByType() - { - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - String cellType = getCalorimeterType(j); - //Use detector color but add on 12 to get different shade of same color - color[j] = (byte) (parameterStore.get("Det", cellType + "Fill").getI() + 12); - } - } - - //Gets the measured time for a calorimeter cell. - //It's 0 by default, but can and should be overriden by subclasses. - protected double getTime(int hit) - { - return 0.0; - } - - //Color cells by their measured time, on a blue-red scale. - //Unmeasured cells are grey. - protected void colorByTime() - { - double min = 0.0, max = 0.0; - boolean first = true; - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - double t=getTime(j); - if (t==0.0) continue;//ignore unmeasured hits - if (first) - { - min = t; max = t; - first = false; - } - - if (t > max) max = t; - if (t < min) min = t; - } - - int numColors = 127; - double scale = (max - min); - if (scale<5) scale=5;//smallest scale is 5 ns - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - double t = getTime(j); - - int colorIndex = (int) (numColors * (t-min) / scale); - if (colorIndex >= numColors) { - colorIndex = numColors;//red - } - if (colorIndex < 1) { - colorIndex = 1;//blue - } - - if (t==0.0) colorIndex=0;//gets grey color - color[j] = (byte) colorIndex; - - } - } - - /** - * Applies cuts to the data. - */ - protected void applyCuts() - { - cutIndex(); - cut("CutsCalo", "Layer", "Layer", sampling); - cut("CutsCalo", "CellQuality", "CellQuality", BadCell); - cutPhi(phi, dphi); - cutEtaDEta(eta, deta); - } - - /** - * Performs the local density calibration. This function determines the - * highest and lowest energy density values ans stores them. - * - * @param index int[] hits to be used in calibration - * @param area double[] cell areas - */ - public void calibrateLocalDensity(int[] index, double[] area) - { - float[] en = null; - double density; - boolean firstECAL = true; - boolean firstHCAL = true; - - AParameter par = parameterStore.get(CALORIMETER_NAME, "Area/Energy"); - if (par.getStatus() && par.getD() > 0) - { - minDensityECAL = 0.0; - minDensityHCAL = 0.0; - maxDensityECAL = 1. / par.getD(); - maxDensityHCAL = 1. / par.getD(); - } - else - { - // Otherwise we need to do calculate it ourselves. - switch (parameterStore.get(CALORIMETER_NAME, "EnergyMode").getI()) - { - case ENERGY_MODE_SUM_LIN: - case ENERGY_MODE_SUM_LOG: - case ENERGY_MODE_SUM_SQRT: - en = etSum; - break; - - case ENERGY_MODE_MAX_LIN: - case ENERGY_MODE_MAX_LOG: - case ENERGY_MODE_MAX_SQRT: - en = et; - break; - } - - // The default for an empty list of cells or only zero area cells is - // 0.0. - minDensityECAL = 0.0; - maxDensityECAL = 0.0; - minDensityHCAL = 0.0; - maxDensityHCAL = 0.0; - - // Calculate density and determine the highest and lowest values. - for (int i = 0; i < index.length; i++) - { - if (area[i] > 0) - { - density = (en[index[i]] / area[i]); - - if (density > 0) - { - if (getCalorimeterType(index[i]).equals("ECAL")) - { - if (firstECAL) - { - // First cell with a sensible density, take this - // as initial value. - minDensityECAL = density; - maxDensityECAL = density; - firstECAL = false; - } - - if (density < minDensityECAL) - minDensityECAL = density; - if (density > maxDensityECAL) - maxDensityECAL = density; - - } - else if (getCalorimeterType(index[i]).equals("HCAL")) - { - if (firstHCAL) - { - // First cell with a sensible density, take this - // as initial value. - minDensityHCAL = density; - maxDensityHCAL = density; - firstHCAL = false; - } - - if (density < minDensityHCAL) - minDensityHCAL = density; - if (density > maxDensityHCAL) - maxDensityHCAL = density; - } - } - } - } - } - } - - /** - * - */ - public double[] getScaleFactors(int[] dl, double[] area) { - double[] factors = new double[area.length]; - - float[] en = null; - int energyMode = parameterStore.get(CALORIMETER_NAME, "EnergyMode").getI(); - - switch (energyMode) - { - case ENERGY_MODE_SUM_LIN: - case ENERGY_MODE_SUM_LOG: - case ENERGY_MODE_SUM_SQRT: - en = etSum; - break; - - case ENERGY_MODE_MAX_LIN: - case ENERGY_MODE_MAX_LOG: - case ENERGY_MODE_MAX_SQRT: - en = et; - break; - } - - for (int i = 0; i < area.length; i++) - { - factors[i] = 1.0f; - - if (area[i] == 0) - continue; - - if (energyScaling()) - { - // The user has (implicitly) selected energy scaling. - double density = en[dl[i]] / area[i]; - double minDensity = getMinDensity(dl[i]); - double maxDensity = getMaxDensity(dl[i]); - - switch (energyMode) - { - case ENERGY_MODE_MAX_LIN: - case ENERGY_MODE_SUM_LIN: - factors[i] = Math.sqrt(density / maxDensity); - break; - - case ENERGY_MODE_MAX_LOG: - case ENERGY_MODE_SUM_LOG: - double magnitude = Math.floor(Math.log10(Math.sqrt(maxDensity / minDensity)) + 1.0); - factors[i] = (Math.log10(Math.sqrt(density / maxDensity)) + magnitude) / magnitude; - break; - - case ENERGY_MODE_MAX_SQRT: - case ENERGY_MODE_SUM_SQRT: - factors[i] = Math.sqrt(Math.sqrt(density / maxDensity)); - break; - - default: - factors[i] = NON_SCALING_FACTOR; - } - } - else - { - // No energy scaling, scale all cells by the same factor. - factors[i] = NON_SCALING_FACTOR; - } - - if (factors[i] > 1.0) { - factors[i] = 1.0; - } - } - - return factors; - } - - /** - * Scales a series of polygons according to the user settings. - * - * @param coord ACoord polygons to be scaled - * @param area double[] surface area of these polygons - * @return ACoord scaled polygons - */ - protected ACoord scalePolygons(ACoord coord, double[] area) - { - double[] factors = getScaleFactors(coord.index, area); - - for (int i = 0; i < area.length; i++) - { - if (area[i] == 0) - continue; - - APolygon.scale(coord.hv[0][i], coord.hv[1][i], factors[i]); - } - return coord; - } - - private String getCellString(int index, String idstr) { - StringBuffer msg = new StringBuffer(); - msg.append(CALORIMETER_NAME + " cell"); - msg.append(" (id: " + idstr + " index: " + index + ")"); - return msg.toString(); - } - - private String getHitString(int index) { - StringBuffer msg = new StringBuffer(); - - msg.append("\n E Max = "); - msg.append(String.format("%.2f",energy[index])); - msg.append(" GeV\n ET Max = "); - msg.append(String.format("%.2f",et[index])); - msg.append(" GeV\n ET Sum = "); - msg.append(String.format("%.2f",etSum[index])); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.4f",eta[index])); - msg.append(" "); - msg.append(AMath.PLUSMINUS); - msg.append(" "); - // deta is step (i.e. size of a cell), with +- we want to see half of it - msg.append(String.format("%.3f",deta[index] / 2.0)); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.1f",Math.toDegrees(phi[index]))); - msg.append(" " + AMath.PLUSMINUS + " "); - // dphi is step (i.e. size of a cell), with +- we want to see half of it - msg.append(String.format("%.1f",Math.toDegrees(dphi[index] / 2.0))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.1f",phi[index]) + " "); - msg.append(AMath.PLUSMINUS + " " + String.format("%.1f",dphi[index] / 2.0) + " rad)"); - - if(feedThrough != null && slot != null && channel != null) - { - String s = "\n feed through/slot/channel = " + - feedThrough[index] + "/" + slot[index] + "/" + - channel[index]; - msg.append(s); - } - if(BadCell != null){ - if(BadCell[index] == 0) - msg.append("\n Cell is good"); - if(BadCell[index] == 1) - msg.append("\n Cell is bad"); - if(BadCell[index] == -1) - msg.append("\n Cell is below 50 MeV"); - } - - return msg.toString(); - } - - /** - * Getting title string for pulse shape windows - * - * Relies on decodedId[1] being some useful high level string describing - * the calorimeter part. This isn't the case for ATILEData where this function - * is overridden to do something different. - * - * Maybe this is a slightly unreasonable plan... but then the first thing - * you decode out of the id should usually be the "biggest" sort of division... - * - Adam - */ - protected String getPulseTitleString(int index) { - - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - - String title = null; - - if (feedThrough == null || slot == null || channel == null) { - // Old style title - logger.warn("Calo FT/slot/channel info not available, using old style title"); - title = decodedId[1] + " cell: " + decodedId[0]; - } else { - // New title as requested by Andre N. Aug 09 - title = decodedId[1] + " cell: " + - this.feedThrough[index] + "/" + this.slot[index] + - "/" + this.channel[index]; - } - - return title; - } - - // Some calo stuff wants to decode the id it's own way... - public String getHitInfoNoDecode(int index) { - - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - return getCellString(index, decodedId[0]) + getHitString(index); - - } - - /** - * Returns information about a certain hit for display in the information - * box. - * - * @param index int hit index - * @return String hit information - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",et[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",et[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",et[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",et[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - StringBuffer msg = new StringBuffer(); - msg.append(getCellString(index, decodedId[0])); - // iterate over decodedId to get further details (if available), - // first item [0] was already printed out above, thus start from 1 - for(int i = 1; i < decodedId.length; i++) - { - msg.append("\n " + decodedId[i]); - } - - msg.append(getHitString(index)); - // by zdenek 2009-01-20 - // layer is already present as sampling in the decodedId - // sub[] should gradually be removed, don't print it for now - // (see mess in AHashMap - !name.equals("sub")) grrrr - /* - msg.append("\n "); - msg.append("layer = " + sampling[index]); - msg.append("\n "); - msg.append("subdetector = " + sub[index]); - */ - - return msg.toString(); - } - - /** - * Returns the total transverse energy for this data type. - * - * @return double total transverse energy - */ - public double getTotalTransverseEnergy() - { - double sumEt = 0.; - for (int i = 0; i < numData; i++) - { - sumEt += et[i]; - } - return sumEt; - } - - /** - * Returns information about the drawn hits, used for the v-plot. - * - * @return String information - */ - public String getVPHitInfo() - { - applyCuts(); - if (numDraw == 0) - return ""; - double sumE = 0.; - double sumEt = 0.; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - sumEt += et[j]; - sumE += energy[j]; - } - - String msg = numDraw + " " + getNameScreenName(); - msg += " sum(ET) = " + String.format("%.1f",sumEt) + " sum(E) = " + String.format("%.1f",sumE); - return msg; - } - - /** - * Returns the specified hits in the form of a four vector. Used by the list - * manager. - * - * @param num int number of hits - * @param list int[] indices of the hits - * @return A4Vector four vector - */ - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - - for (int i = 0; i < num; ++i) - { - int j = list[i]; - double lambda = AMath.lambda(eta[j]); - - double pt = energy[j] * Math.cos(lambda); - double pz = energy[j] * Math.sin(lambda); - - double px = pt * Math.cos(phi[j]); - double py = pt * Math.sin(phi[j]); - - sum.add(px, py, pz, 0.); - } - return sum; - } - - /** - * Calorimeter cells can be drawn either explicitly or implicitly. In most - * views cells that are located behind eachother are consolidated and only - * the most energetic one is drawn explicitly. The other cells are drawn - * implicitly, since their energy value is still added to the energy sum of - * the explicitly drawn cell. The list manager does not know about the - * implicitly drawn cells though, so this poses a problem when the user - * requests information about a certain area of the canvas. This is solved - * using this method. This function receives the list of explicitly drawn - * cells and then adds the ones that were implicitly drawn in this - * selection. - * - * @param drawn boolean[] initial drawn list containing only the explicitly - * drawn cells - * @return boolean[] drawn list containing the explicitly and the implicitly - * drawn cells. - */ - public boolean[] expandDrawn(boolean[] drawn) - { - makeDrawList(); - AProjection projection = ACanvas.getCanvas().getCurrentWindow().getProjection(); - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - - if (drawn[j]) - continue; - - int detIndex = getDetectorIndex(j); - int hitIndex = getHitIndex(j, projection); - - if (detIndex >= 0 && hitIndex >= 0) { - if (cellTable != null && detIndex < cellTable.length - && hitIndex < cellTable[detIndex].length) { - - int mappedTo = cellTable[detIndex][hitIndex]; - - if (mappedTo >= 0 && drawn[mappedTo] == true) { - drawn[j] = true; - } - } - } - } - - return drawn; - } - - /** - * Rebuilds the hit to geometry mapping for all calorimeters. Used when the - * user has loaded a different geometry file. - */ - public static void remakeHitToGeometryMapping() - { - //Get current event - AEvent event = eventManager.getCurrentEvent(); - if (event != null){ - ACalorimeterData[] calorimeters = new ACalorimeterData[event.getCalorimeters().size()]; - event.getCalorimeters().toArray(calorimeters); - for (int i = 0; i < calorimeters.length; i++) - { - calorimeters[i].makeHitToGeometryMapping(); - } - } - } - - /** - * Draws the calorimeters. This method is called from AProjection2D.paint(). - * - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - * @param event AEvent drawn event reference - */ - public static void drawCalorimeters(AWindow window, AGraphics ag, AProjection2D projection, AEvent event) - { - int mode = parameterStore.get(projection.getName(), "Mode").getI(); - - if(projection instanceof AProjectionYX || projection instanceof AProjectionFR) - { - //only grey out the GUI if relevant for the current window - boolean changeGUI = false; - if(window.equals(ACanvas.getCanvas().getCurrentWindow())) - changeGUI = true; - - //grey out draw FCAL option if not on right layer of HEC - AParameter drawFCAL = parameterStore.get("YX", "DrawFCAL"); - if(changeGUI) - { - if(!drawFCAL.isInitialized()) - drawFCAL.initialize(); - if(mode < AProjectionYX.MODE_HEC_2 || mode > AProjectionYX.MODE_HEC_4) - drawFCAL.getNameComponent().setEnabled(false); - else - drawFCAL.getNameComponent().setEnabled(true); - } - - - //grey out split ETA, LAr bin and HEC bin options if not on summed endcaps option - AParameter splitEta = parameterStore.get("YX", "SplitEta"); - AParameter LArBin = parameterStore.get("YX", "LArBin"); - AParameter HECBin = parameterStore.get("YX", "HECBin"); - if(changeGUI) - { - if(!HECBin.isInitialized()) - HECBin.initialize(); - if(!LArBin.isInitialized()) - LArBin.initialize(); - if(!splitEta.isInitialized()) - splitEta.initialize(); - } - //Summed Endcaps has a different draw method - if(mode == AProjectionYX.MODE_LAR_ENDCAP_SUMMED || mode == AProjectionYX.MODE_HEC_SUMMED) - { - if(changeGUI) - { - LArBin.getValueComponent().setEnabled(true); - HECBin.getValueComponent().setEnabled(true); - LArBin.getNameComponent().setEnabled(true); - HECBin.getNameComponent().setEnabled(true); - if(LArBin.getI()==3 || HECBin.getI()==3) - { - splitEta.getValueComponent().setEnabled(true); - splitEta.getNameComponent().setEnabled(true); - } - else - { - splitEta.getValueComponent().setEnabled(false); - splitEta.getNameComponent().setEnabled(false); - } - } - ACalorimeterData[] calorimeters = new ACalorimeterData[event.getCalorimeters().size()]; - event.getCalorimeters().toArray(calorimeters); - for (int i = 0; i < calorimeters.length; i++) - { - //check if in right calorimeter - if ((mode == AProjectionYX.MODE_LAR_ENDCAP_SUMMED && !calorimeters[i].getName().equals("LAr")) || - (mode == AProjectionYX.MODE_HEC_SUMMED && !calorimeters[i].getName().equals("HEC"))) - continue; - ADrawCalorimeterSummedEndcaps.drawCalorimeterSummedEndcaps(window, - ag, projection, calorimeters[i], calorimeters[i].etaIndex, - calorimeters[i].phiIndex, calorimeters[i].side); - } - return; - } - else - { - if(changeGUI) - { - LArBin.getValueComponent().setEnabled(false); - HECBin.getValueComponent().setEnabled(false); - splitEta.getValueComponent().setEnabled(false); - LArBin.getNameComponent().setEnabled(false); - HECBin.getNameComponent().setEnabled(false); - splitEta.getNameComponent().setEnabled(false); - } - if (ALegendWindow.exists()) - ALegendWindow.getInstance().nothingToDisplay(window); - } - } - else if (ALegendWindow.exists()) - ALegendWindow.getInstance().nothingToDisplay(window); - - if (projection instanceof AProjectionVP && mode == 0) - { - // The standard mode of the v-plot uses a different function. - drawCalorimetersVPlot(window, ag, projection, event); - return; - } - - ACalorimeterData[] calorimeters = new ACalorimeterData[event.getCalorimeters().size()]; - event.getCalorimeters().toArray(calorimeters); - ACoord[] data = new ACoord[calorimeters.length]; - double[][] area = new double[calorimeters.length][]; - - for (int i = 0; i < calorimeters.length; i++) - { - // Retrieve the cell coordinates. - data[i] = calorimeters[i].getUserNoTransform(projection); - - // Calculate the cell areas. - area[i] = new double[data[i].index.length]; - for (int j = 0; j < data[i].index.length; j++) - { - area[i][j] = APolygon.getArea(data[i].hv[0][j], data[i].hv[1][j]); - } - - // Let the calorimeter determine its minimum and maximum energy - // density. - calorimeters[i].calibrateLocalDensity(data[i].index, area[i]); - } - - if (window.getProjection() instanceof AProjectionVP) - { - // In case of the v-plot we force the overall energy density - // calibration. - calibrateDensity(calorimeters, ENERGY_CALIB_OVERALL); - } - else - { - // Calibrate the energy density according to the user settings. - calibrateDensity(calorimeters, ENERGY_CALIB_UNKNOWN); - } - - for (int i = 0; i < calorimeters.length; i++) - { - // Apply the non linear transforms and convert to screen - // coordinates. - data[i] = window.calculateDisplay(projection.nonLinearTransform(data[i])); - - // Draw the cell frames. - if (parameterStore.get(calorimeters[i].getName(), "Cells").getStatus()) - { - drawFrames(calorimeters[i], data[i], window, ag); - } - } - - for (int i = 0; i < calorimeters.length; i++) - { - // Draw the cell geometry. - if (parameterStore.get(calorimeters[i].getName(), "Cells").getStatus()) - { - drawGeometry(calorimeters[i], data[i], window, ag); - } - } - - String[] histograms = { "TILE", "HEC", "LAr", "FCAL", "MBTS" }; - for (int j = 0; j < histograms.length; j++) - { - for (int i = 0; i < calorimeters.length; i++) - { - if (calorimeters[i].getCalorimeterName().equals(histograms[j])) - { - // Draw the histograms. - drawHistogram(calorimeters[i], window, ag, projection); - } - } - } - for (int j = 0; j < histograms.length; j++) - { - for (int i = 0; i < calorimeters.length; i++) - { - if (calorimeters[i].getCalorimeterName().equals(histograms[j])) - { - // Draw the frames for the histograms. - frameHistogram(calorimeters[i], window, ag, projection); - } - } - } - - for (int i = 0; i < calorimeters.length; i++) - { - if (parameterStore.get(calorimeters[i].getName(), "Cells").getStatus()) - { - // Scale the cell polygons. - data[i] = calorimeters[i].scalePolygons(data[i], area[i]); - // And draw them. - drawHits(calorimeters[i], data[i], window, ag); - } - } - - } - - /** - * Draws the calorimeters in the standard mode v-plot. This method is called - * from drawCalorimeters and should not be used directly. - * - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - * @param event AEvent drawn event reference - */ - private static void drawCalorimetersVPlot(AWindow window, AGraphics ag, AProjection2D projection, AEvent event) - { - ACalorimeterData[] calorimeters = new ACalorimeterData[event.getCalorimeters().size()]; - event.getCalorimeters().toArray(calorimeters); - - float[][] energies = new float[calorimeters.length][]; - int[] sizes = new int[calorimeters.length]; - ACoord[] points = new ACoord[calorimeters.length]; - Color[] colorMap = AColorMap.getColors(); - //if color by energy use different colormap - for (int i = 0; i < calorimeters.length; i++) - { - if(calorimeters[i].CALORIMETER_NAME.equals("MBTS")) continue; - if (parameterStore.get(calorimeters[i].getParameterGroup(), "ColorFunction").getI() - == ACalorimeterData.COLOR_FUNC_ENERGY) { - switch (AColorMap.getColorMap()) { - case AColorMap.COLOR_MAP_DEFAULT1: - case AColorMap.COLOR_MAP_DEFAULT2: - case AColorMap.COLOR_MAP_M4M5: - case AColorMap.COLOR_MAP_GRAYDET: - case AColorMap.COLOR_MAP_ORIGINAL: - // Use colors. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_HITCOL); - break; - case AColorMap.COLOR_MAP_GRAY: - case AColorMap.COLOR_MAP_BW: - // Use grayscale. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_GRAY_HITCOL); - break; - } - } else if (parameterStore.get(calorimeters[i].getParameterGroup(), "ColorFunction").getI() == COLOR_FUNC_TIME) { - colorMap = AColorMap.getShades(128); - } - - points[i] = window.calculateDisplay(calorimeters[i].getVPPoints()); - energies[i] = calorimeters[i].getET(points[i].index); - sizes[i] = energies[i].length; - calorimeters[i].color(); - } - - for (int i = 0; i < calorimeters.length; i++) - { - for (int j = 0; j < sizes[i]; j++) - { - int size = (int) Math.sqrt(energies[i][j] * SCALE_FACTOR_VPLOT); - if (size == 0) - size++; - - int cellColor = calorimeters[i].color[points[i].index[j]]; - ag.setColor(colorMap[cellColor]); - ag.drawPoint(calorimeters[i], points[i].index[j], points[i].hv[0][0][j], - points[i].hv[1][0][j], size, size); - } - } - - } - - /** - * Calibrating involves finding the minimum and maximum energy density - * values. This function takes the local (per calorimeter) values and - * calculates the overall values (if needed). - * - * @param calorimeters ACalorimeterData[] calorimeter data objects - * @param mode int calibration mode, use APar.EN_CALIB_UNKNOWN to retrieve - * the user setting - */ - protected static void calibrateDensity(ACalorimeterData[] calorimeters, int mode) - { - if (mode == ENERGY_CALIB_UNKNOWN) - { - mode = parameterStore.get("LAr", "EnergyCalibration").getI(); - } - - // This array contains the calorimeter "types" to combine in the - // calibration. - String types[]; - switch (mode) - { - case ENERGY_CALIB_OVERALL: - types = new String[] { "ALL" }; - break; - - case ENERGY_CALIB_BY_TYPE: - types = new String[] { "ECAL", "HCAL" }; - break; - - case ENERGY_CALIB_BY_CALO: - default: - // Nothing to be done here. - types = new String[0]; - break; - } - - for (int i = 0; i < types.length; i++) - { - boolean first = true; - double min = 0.0; - double max = 0.0; - for (int j = 0; j < calorimeters.length; j++) - { - if (calorimeters[j].getMaxDensity(types[i]) > 0) - { - if (first) - { - min = calorimeters[j].getMinDensity(types[i]); - max = calorimeters[j].getMaxDensity(types[i]); - first = false; - } - - if (calorimeters[j].getMinDensity(types[i]) < min) - { - min = calorimeters[j].getMinDensity(types[i]); - } - if (calorimeters[j].getMaxDensity(types[i]) > max) - { - max = calorimeters[j].getMaxDensity(types[i]); - } - } - } - for (int j = 0; j < calorimeters.length; j++) - { - calorimeters[j].setMinDensity(types[i], min); - calorimeters[j].setMaxDensity(types[i], max); - } - } - } - - /** - * Draws the frame for the cell geometry of a calorimeter. All frames are - * drawn before drawing the cells themselves. This way a frame can never be - * put on top of a cell from another calorimeter. - * - * @param calorimeter ACalorimeterData data collection to which this - * function applies - * @param display ACoord cell coordinates to be drawn - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - */ - protected static void drawFrames(ACalorimeterData calorimeter, ACoord display, AWindow window, AGraphics ag) - { - - String name = calorimeter.getCalorimeterName(); - Color[] colorMap = AColorMap.getColors(); - int[] index = display.index; - int[] type = calorimeter.getType(index); - - boolean drawCellGeometry = parameterStore.get(name, "CellGeometry").getStatus(); - boolean drawFrame = parameterStore.get(name, "Frame").getStatus(); - int frameColor = parameterStore.get(name, "Frame").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - drawFrame=true; - else - drawFrame=false; - - // For the v-plot we override these settings. - if (window.getProjection() instanceof AProjectionVP) - { - drawCellGeometry = parameterStore.get("VP", "VPlotIsland").getStatus(); - drawFrame = true; - frameColor = AColorMap.WH; - } - - // Draw frames for the filled cells. - if (drawFrame && drawCellGeometry) - { - for (int i = 0; i < index.length; i++) - { - ag.updateDrawParameters(calorimeter.getDrawParameters(0, type[i])); - ag.setColor(colorMap[frameColor]); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - - /** - * Draws the frame for the cell geometry and outline of a calorimeter. All - * frames are drawn before drawing the cells themselves. This way a frame - * can never be put on top of a cell from another calorimeter. - * - * @param calorimeter ACalorimeterData data collection to which this - * function applies - * @param display ACoord cell coordinates to be drawn - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - */ - protected static void drawGeometry(ACalorimeterData calorimeter, ACoord display, AWindow window, AGraphics ag) - { - String name = calorimeter.getCalorimeterName(); - Color[] colorMap = AColorMap.getColors(); - int[] index = display.index; - int[] type = calorimeter.getType(index); - - boolean drawCellGeometry = parameterStore.get(name, "CellGeometry").getStatus(); - boolean drawCellOutline = parameterStore.get(name, "CellOutline").getStatus(); - boolean cutByLayer = false; - int cellGeometryColor = parameterStore.get(name, "CellGeometry").getI(); - int cellOutlineColor = parameterStore.get(name, "CellOutline").getI(); - int cutLayer = 0; - - // For the v-plot we override some of these settings. - if (window.getProjection() instanceof AProjectionVP) - { - drawCellGeometry = parameterStore.get("VP", "VPlotIsland").getStatus(); - cellGeometryColor = parameterStore.get("VP", "VPlotIsland").getI(); - - int mode = parameterStore.get("VP", "Mode").getI(); - - if (mode >= AProjectionVP.MODE_HCAL_LAYER_0) - { - cutByLayer = true; - cutLayer = mode - AProjectionVP.MODE_HCAL_LAYER_0; - } - else if (mode >= AProjectionVP.MODE_ECAL_LAYER_0) - { - cutByLayer = true; - cutLayer = mode - AProjectionVP.MODE_ECAL_LAYER_0; - } - } - - // Draw filled cells. - if (drawCellGeometry) - { - for (int i = 0; i < index.length; i++) - { - ag.updateDrawParameters(calorimeter.getDrawParameters(1, type[i])); - ag.setColor(colorMap[cellGeometryColor]); - ag.fillPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - - // Draw cell outlines. - if (drawCellOutline) - { - ag.updateDrawParameters(new ADrawParameters(true, cellOutlineColor, 0, 1, 0, 0, false, 1, 0)); - for (int i = 0; i < index.length; ++i) - { - if (!cutByLayer || calorimeter.getSampling(index[i]) == cutLayer) - { - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - } - - /** - * Draws the calorimeter hits. - * - * @param calorimeter ACalorimeterData calorimeter object the hits belong to - * @param display ACoord cell coordinates to be drawn - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - */ - protected static void drawHits(ACalorimeterData calorimeter, ACoord display, AWindow window, AGraphics ag) - { - String name = calorimeter.getCalorimeterName(); - int[] index = display.index; - int[] color = calorimeter.getColor(index); - int[] type = calorimeter.getType(index); - int[] sampling = calorimeter.getSampling(index); - - // This cut is performed just before drawing the hits, the geometry has - // been drawn already. - // This results in the irregular v-plot islands that help the user - // locate a certain position in different views. - boolean cutByLayer = false; - int cutLayer = 0; - - if (window.getProjection() instanceof AProjectionVP) - { - int mode = parameterStore.get("VP", "Mode").getI(); - - if (mode >= AProjectionVP.MODE_HCAL_LAYER_0) - { - cutByLayer = true; - cutLayer = mode - AProjectionVP.MODE_HCAL_LAYER_0; - } - else if (mode >= AProjectionVP.MODE_ECAL_LAYER_0) - { - cutByLayer = true; - cutLayer = mode - AProjectionVP.MODE_ECAL_LAYER_0; - } - } - - AParameter cellGeometry = parameterStore.get(name, "CellGeometry"); - AParameter colorFunction = parameterStore.get(name, "ColorFunction"); - boolean drawFrame = parameterStore.get(name, "Frame").getStatus(); - int frameColor = parameterStore.get(name, "Frame").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - drawFrame=true; - else - drawFrame=false; - - Color[] colorMap = AColorMap.getColors(); - if (colorFunction.getI() == COLOR_FUNC_ENERGY) - { - switch (AColorMap.getColorMap()) - { - case AColorMap.COLOR_MAP_DEFAULT1: - case AColorMap.COLOR_MAP_DEFAULT2: - case AColorMap.COLOR_MAP_M4M5: - case AColorMap.COLOR_MAP_GRAYDET: - case AColorMap.COLOR_MAP_ORIGINAL: - // Use colors. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_HITCOL); - break; - case AColorMap.COLOR_MAP_GRAY: - case AColorMap.COLOR_MAP_BW: - // Use grayscale. - colorMap = AColorMap.getColors(AColorMap.COLOR_MAP_GRAY_HITCOL); - break; - } - } - else if (colorFunction.getI() == COLOR_FUNC_TIME) - { - colorMap = AColorMap.getShades(128); - } - - if (drawFrame && !cellGeometry.getStatus()) - { - for (int i = 0; i < index.length; i++) - { - if (!cutByLayer || sampling[i] == cutLayer) - { - ag.updateDrawParameters(calorimeter.getDrawParameters(0, type[i])); - ag.setColor(colorMap[frameColor]); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - - for (int i = 0; i < index.length; i++) - { - if (!cutByLayer || sampling[i] == cutLayer) - { - ag.updateDrawParameters(calorimeter.getDrawParameters(1, type[i])); - ag.setColor(colorMap[color[i]]); - ag.fillPolygon(calorimeter, index[i], display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - - /** - * Draws the calorimeter histograms. - * - * @param calorimeter ACalorimeterData calorimeter object the histograms - * belong to - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - protected static void drawHistogram(ACalorimeterData calorimeter, AWindow window, AGraphics ag, AProjection2D projection) - { - String name = calorimeter.getCalorimeterName(); - if (!parameterStore.get(name, "Histogram").getStatus()) - return; - - ACoord[] histograms = calorimeter.getUserHistograms(projection); - for (int i = 0; i < histograms.length; i++) - { - ACoord display = window.calculateDisplay(histograms[i]); - AHistogram hist = (AHistogram) histograms[i].source; - hist.completeTowers(display); - - // for rubberband "new list" or "summarize" feature - if (ag.getGraphics2D() instanceof ADrawnGraphics2D) - ((ADrawnGraphics2D) ag.getGraphics2D()).addHistogramData(hist); - - boolean onTop; - if (parameterStore.getUnknown(name, "OnTopHistoFrame") != null) - { - onTop = parameterStore.get(name, "OnTopHistoFrame").getStatus(); - } - else - { - onTop = false; - } - - // Draw frame for the histogram. - if (parameterStore.get(name, "HistoFrame").getStatus() && !onTop) - { - int frameColor = parameterStore.get(name, "HistoFrame").getI(); - - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 0, 0, 1, 0)); - for (int j = 0; j < display.hv[0].length; j++) - { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - - // Draw histogram towers. - int fillColor = parameterStore.get(name, "Histogram").getI(); - ag.updateDrawParameters(new ADrawParameters(true, fillColor, 0, 1, 0, 0)); - for (int j = 0; j < display.hv[0].length; j++) - { - ag.fillPolygon(hist, display.index[j], display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - - /** - * Draws the calorimeter histogram frames. - * - * @param calorimeter ACalorimeterData calorimeter object the histograms - * belong to - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - protected static void frameHistogram(ACalorimeterData calorimeter, AWindow window, AGraphics ag, AProjection2D projection) - { - String name = calorimeter.getCalorimeterName(); - if (!parameterStore.get(name, "Histogram").getStatus()) - return; - - ACoord[] histograms = calorimeter.getUserHistograms(projection); - for (int i = 0; i < histograms.length; i++) - { - ACoord display = window.calculateDisplay(histograms[i]); - AHistogram hist = (AHistogram) display.source; - - hist.completeTowers(display); - - boolean onTop = false; - if (parameterStore.getUnknown(name, "OnTopHistoFrame") != null) - { - onTop = parameterStore.get(name, "OnTopHistoFrame").getStatus(); - } - - // Draw frame for the histogram. - if (parameterStore.get(name, "HistoFrame").getStatus() && onTop) - { - int frameColor = parameterStore.get(name, "HistoFrame").getI(); - - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 0, 1, 0, 0)); - for (int j = 0; j < display.hv[0].length; j++) - { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - - public static void drawEndcapHistogram(ACalorimeterData calorimeter, AWindow window, AGraphics ag, AProjection2D projection) - { - //filter the draw list for the histograms - calorimeter.filterDrawList(projection); - //Draw the histograms. - drawHistogram(calorimeter, window, ag, projection); - // Draw the frames for the histograms. - frameHistogram(calorimeter, window, ag, projection); - } - - - - /** - * getLookupTableArray() parses String[][] s with comma separated values - * (CSV) and converts each number to float lookup table value which is used - * for calorimeter real pulse shapes plots - * @param s String[][] - * @param numLookupTableValues int - * @return float[] - * @throws AAtlantisException - */ - protected static float[] getLookupTableArray(String[][] s, int numLookupTableValues) - throws AAtlantisException - { - float[] r = new float[numLookupTableValues]; - int i = 0; - for(int k = 0; k < s.length; k++) - { - for(int l = 0; l < s[k].length; l++) - { - if("".equals(s[k][l])) - { - // command and new line results into empty value - ignore - continue; - } - try - { - // there shouldn't be more than NUMBER_OF_LOOKUP_VALUES - // i.e. numLookupTableValues - if(i >= numLookupTableValues) - { - String m = "more lookup values than NUMBER_OF_LOOKUP_VALUES: " + - i + " >= " + numLookupTableValues; - throw new AAtlantisException(m); - } - r[i] = Float.valueOf(s[k][l]).floatValue(); - i++; - } - catch(NumberFormatException ex) - { - throw new AAtlantisException("number format exception: " + s[k][l]); - } - } - } - - // now the i counter shall be equal to numLookupTableValues - if(i != numLookupTableValues) - { - throw new AAtlantisException("incorrect number to items (" + i + ") " + - "in the lookup table, should be " + numLookupTableValues); - } - - // all right, return the result float array - return r; - - } // getLookupTableArray() ---------------------------------------------- - - - - /** - * Calculate real pulse shapes values based on the values in the - * lookup tables (parameters amplitude and time, etc) - - * @param xTime double - * @param cellTime double - * @param cellPedestal double - * @param energy double - * @param amplitude float[] lookup table - * @param time float[] lookup table - * @param numerOfLookupValues int - * @return double - * @throws AAtlantisException - */ - protected double getPhysicsPulseShape(double localTime, - double cellPedestal, double energy, - float[] amplitude, float[] time, - int numerOfLookupValues) - throws AAtlantisException - { - double tdiv = 0.0; - int lookup = 0; - double xpulse = 0.0; - - tdiv = time[1] - time[0]; - lookup = (int) ((localTime - time[0]) / tdiv); - - if(lookup < 0) - { - lookup = 0; - } - if(lookup >= numerOfLookupValues - 1) - { - lookup = numerOfLookupValues - 2; // -1 was off by 1 - } - - try - { - if(lookup == 0 || lookup == numerOfLookupValues - 2) - { - xpulse = amplitude[lookup]; - } - else - { - xpulse = amplitude[lookup] + ((amplitude[lookup + 1] - - amplitude[lookup]) / tdiv) * (localTime - time[lookup]); - } - } - catch(ArrayIndexOutOfBoundsException ex) - { - String m = CALORIMETER_NAME + " getPhysicsPulseShape():\n" + - " lookup index out of bound: lookup = " + lookup; - throw new AAtlantisException(m); - } - - return (xpulse * energy) + cellPedestal; - - } // getPhysicsPulseShape() --------------------------------------------- - - - - /** - * - * Events from DPD don't contain all necessary data - * if all adc counts are 0, then print info message and - * no pulse shape plot window as it may lead to confusion. - * This method is aimed to check availability of adc counts digits. - * - * @param adcCountsLocal - * @return true if any ADC counts are non-zero - */ - protected static boolean checkADCCountsAvailability(int[][] adcCountsLocal) - { - boolean adcCountsAvailable = false; - - for(int x = 0; x < adcCountsLocal.length; x++) - { - for(int y = 0; y < adcCountsLocal[0].length; y++) - { - if(adcCountsLocal[x][y] != 0) - { - adcCountsAvailable = true; - break; - } - } - if(adcCountsAvailable) - { - break; - } - } - - return adcCountsAvailable; - - } // checkADCCountsAvailability() --------------------------------------- - - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ACalorimeterRPSPLT.java b/graphics/AtlantisJava/src/atlantis/data/ACalorimeterRPSPLT.java deleted file mode 100644 index 9f8890bec80..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ACalorimeterRPSPLT.java +++ /dev/null @@ -1,260 +0,0 @@ -package atlantis.data; - -import java.util.HashMap; - -import atlantis.utils.ALogger; -import atlantis.utils.AAtlantisException; - -/** - * - * Calorimeter Real Pulse Shape Plot Lookup - * Tables. The class accommodates lookup tables (arrays) for the Tile and LAr, - * FCAL and HEC calorimeters. If the real pulse shape plots data are found in - * the event files, the corresponding arrays within this class are initialised - * from A[TILE|LAr|FCAL|HEC]Data class(es). The arrays are initialised from - * CSV (comma separated values files) just once per Atlantis session. - * - * @author Zdenek Maxa - */ -public final class ACalorimeterRPSPLT -{ - private static ALogger logger = ALogger.getLogger(ACalorimeterRPSPLT.class); - - // TILE calorimeter, lookup table time values - protected static float[] TILE_TIME = null; - // TILE calorimeter, lookup table amplitude values - protected static float[] TILE_AMPLITUDE = null; - - - // FCAL calorimeter, lookup table time values - protected static float[] FCAL_TIME = null; - // FCAL calorimeter, lookup table layer 0, amplitude values - protected static float[] FCAL_LAYER0_AMPLITUDE = null; - // FCAL calorimeter, lookup table layer 1, amplitude values - protected static float[] FCAL_LAYER1_AMPLITUDE = null; - // FCAL calorimeter, lookup table layer 2, amplitude values - protected static float[] FCAL_LAYER2_AMPLITUDE = null; - - - // HEC calorimeter, lookup table time values - protected static float[] HEC_TIME = null; - // HEC calorimeter, lookup table amplitude values - protected static float[] HEC_AMPLITUDE = null; - - - - - // LAr calorimeter, lookup tables - // for time (the same array for both - // barrel/endcap, all layer and regions and eta ranges - // currently (2009-02-11) there are 58 various arrays for LAr, it - // is not sustainable to have all these in separate arrays - for LAr - // there will be defined a container - keys are lookup tables names - // as defined in the lookup table file and values are float[] arrays - private static HashMap<String, float[]> larTables = null; - - // set the LAr table keys in a static block - // explanation of the LAr lookup tables names (the names are identical - // to comma separated values array names as in the look up table file): - // LAR_TIME - time constants - used for barrel/endcap, all layers, - // all regions, all eta ranges - // LAR_BARREL_L1_R0_AMPLITUDE - barrel, layer 1, region 0, etc, etc - // LAR_ENDCAP_L0_R0_ETA0_AMPLITUDE - endcap, layer 0, region 0, eta - // range 0 - very many of these - // bother to define the array names here to be really safe ... otherwise - // could just rely on the CSV file ... - static - { - larTables = new HashMap<String, float[]>(70); // not more arrays than 70 - - larTables.put("LAR_TIME", null); - larTables.put("LAR_BARREL_LAYER1_REGION0_AMPLITUDE", null); - larTables.put("LAR_BARREL_LAYER1_REGION1_AMPLITUDE", null); - larTables.put("LAR_BARREL_LAYER2_REGION0_AMPLITUDE", null); - larTables.put("LAR_BARREL_LAYER2_REGION1_AMPLITUDE", null); - larTables.put("LAR_BARREL_LAYER3_REGION0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER0_REGION0_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA4_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA5_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA6_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION0_ETA7_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION1_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION2_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION2_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION2_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION2_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION3_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION3_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION3_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION4_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION4_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION4_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION4_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION4_ETA4_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER1_REGION5_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA4_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA5_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA6_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION0_ETA7_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA4_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA5_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA6_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA7_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA8_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA9_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER2_REGION1_ETA10_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA0_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA1_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA2_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA3_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA4_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA5_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA6_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA7_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA8_AMPLITUDE", null); - larTables.put("LAR_ENDCAP_LAYER3_REGION0_ETA9_AMPLITUDE", null); - } - - - - - public static boolean areFCALLookupTablesInitialized() - { - if(FCAL_LAYER0_AMPLITUDE != null && - FCAL_LAYER1_AMPLITUDE != null && - FCAL_LAYER2_AMPLITUDE != null && - FCAL_TIME != null) - { - return true; - } - else - { - return false; - } - - } // areFCALLookupTablesInitialized() ----------------------------------- - - - - public static boolean areHECLookupTablesInitialized() - { - if(HEC_TIME != null && HEC_AMPLITUDE != null) - { - return true; - } - else - { - return false; - } - - } // areHECLookupTablesInitialized() ------------------------------------ - - - - public static boolean areTileLookupTablesInitialized() - { - if(TILE_TIME != null && TILE_AMPLITUDE != null) - { - return true; - } - else - { - return false; - } - - } // areTileLookupTablesInitialized() ----------------------------------- - - - - /** - * Method is called at LAr constructor, i.e. at the beginning of each - * event to check if all lookup tables for LAr are properly initialised. - * The check is performed only when other necessary LAr are is available - * in a given event file. - * @return true if all float arrays were properly initialised - */ - public static boolean areLarLookupTablesInitialized() - { - // iterate over all keys in the container and check if all - // float arrays were properly initialised - for(String key : larTables.keySet()) - { - if(larTables.get(key) == null) - { - logger.error("LAr real pulse shapes plots lookup table " + - "\"" + key + "\" was not initialised."); - return false; - } - } - - return true; - - } // areLarLookupTablesInitialized() ------------------------------------ - - - - public static void setLarTable(String key, float[] array) throws AAtlantisException - { - logger.debug("Setting LAr pulse shapes lookup table \"" + key + "\""); - - if(larTables.containsKey(key)) - { - // it certainly already should contain the key (defined above) - if(larTables.get(key) != null) - { - throw new AAtlantisException("LAr pulse shapes lookup table \"" + - key + "\" has already been defined."); - } - else - { - larTables.put(key, array); - } - } - else - { - throw new AAtlantisException("LAr pulse shapes lookup table - " + - "entry \"" + key + "\" has not been created."); - } - - } // setLarTable() ------------------------------------------------------ - - - - public static float[] getLarTable(String key) throws AAtlantisException - { - logger.debug("Getting LAr pulse shapes lookup table \"" + key + "\""); - if(larTables.containsKey(key)) - { - float[] r = larTables.get(key); - if(r == null) - { - throw new AAtlantisException("LAr pulse shape lookup table " + - "key \"" + key + "\" is null."); - } - else - { - return r; - } - } - else - { - throw new AAtlantisException("LAr pulse shape lookup table " + - "entry \"" + key + "\" has not been created."); - } - - } // getLarTable() ------------------------------------------------------ - - -} // class ACalorimeterRPSPLT =============================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/AClusterData.java b/graphics/AtlantisJava/src/atlantis/data/AClusterData.java deleted file mode 100644 index 9428320eec9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AClusterData.java +++ /dev/null @@ -1,385 +0,0 @@ -package atlantis.data; - -import atlantis.canvas.AWindow; -import atlantis.event.AAssociation; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.A3Vector; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Calo Clusters for the moment made from LAr cells - * - * Also contain AOD Calo Clusters from 24/10/2006 - */ -public class AClusterData extends AData -{ - protected float[] eT; - protected float[] eta; - protected float[] phi; - - public String getParameterGroup() - { - return "Cluster"; - } - - @Override - public String getName() - { - return "Cluster"; - } - - public String getNameScreenName() - { - return "Cluster"; - } - - public float getET(int index) - { - return eT[index]; - } - - public float getEta(int index) - { - return eta[index]; - } - - public float getPhi(int index) - { - return phi[index]; - } - - AClusterData(AHashMap p, AEvent e) - { - super(p,e); - - eta = p.getFloatArray("eta"); - phi = p.getFloatArray("phi"); - if (p.get("et") != null) - eT = p.getFloatArray("et"); - else - { - float[] energy = p.getFloatArray("energy"); - eT = new float[numData]; - for (int i = 0; i < numData; ++i) - eT[i] = (float) Math.abs(energy[i] * Math.cos(AMath.lambda(eta[i]))); - } - - String assocKey = getName() + getStoreGateKey(); - if (p.get("numCells") != null) - { - event.getAssociationManager().add(new AAssociation(assocKey, "LAr", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - event.getAssociationManager().add(new AAssociation(assocKey, "TILE", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - } - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - protected void applyCuts() - { - cutIndex(); - cut("CutsCalo", "ClusterET", " |ET|", eT); - cutPhi(phi); - cutEta(eta); - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - switch (colorFunction) - { - case 0: // by constant - colorByConstant(); - break; - case 1: // by index - colorByIndex(); - break; - case 2: // by objects - colorByObjects(); - break; - } - return 3; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",eT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",eT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",eT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",eT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n ET = "); - msg.append(String.format("%.3f",eT[index])); - msg.append(" GeV\n E = "); - msg.append(String.format("%.3f",Math.abs(eT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index])) + AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - return msg.toString(); - } - - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumE = 0.; - double sumET = 0.; - - for (int i = 0; i < numDraw; ++i) - { - sumET += Math.abs(eT[listdl[i]]); - sumE += Math.abs(eT[listdl[i]] / Math.cos(AMath.lambda(eta[listdl[i]]))); - } - - StringBuffer msg = new StringBuffer(""); - msg.append(numDraw); - msg.append(" "); - msg.append(getStoreGateKey() != null ? getStoreGateKey() : getNameScreenName()); - msg.append(" sum(ET) = "); - msg.append(String.format("%.1f",sumET)); - msg.append(" sum(E) = "); - msg.append(String.format("%.1f",sumE)); - - return msg.toString(); - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A3Vector start = A3Vector.fromRhoPhiZ(0., 0., 0.); - double tL = AMath.tanLambda(eta[k]); - A3Vector stop = A3Vector.fromRhoPhiZ(1., phi[k], tL); - A3Vector v = (stop.subtract(start)).normalize(); - double p = eT[k] / Math.sqrt(1. - v.z * v.z); - sum.add(new A4Vector(v.scale(p), 0.)); - } - - return sum; - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP) - { - drawVP(window, ag, projection); - } - else - { - super.draw(window, ag, projection); - } - } - - private void drawVP(AWindow window, AGraphics ag, AProjection2D projection) - { - ACoord centers=window.calculateDisplay(getUser(projection)); - int[] drawlist=centers.index; - double eLimit=0.025; - int numPoints=25; - double[][][] hv=new double[2][drawlist.length][numPoints]; //circle - - for(int i=0; i<drawlist.length; ++i) - { - int list=drawlist[i]; - double e; - e = Math.abs(eT[list]); - int d=(int)(Math.sqrt((e/eLimit)/Math.PI)); - if(d==0) d=1; - for(int j=0; j<numPoints; j++) - { - hv[0][i][j]=centers.hv[0][0][i]+d*Math.cos(Math.PI*2*j/(numPoints-1)); - hv[1][i][j]=centers.hv[1][0][i]+d*Math.sin(Math.PI*2*j/(numPoints-1)); - } - } - ag.draw(new ACoord(hv, drawlist, this, ACoord.POLYLINES)); - } - - protected ACoord getVPUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - h[i]=eta[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - double dphi = Math.toRadians(0.5); - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - double cosPlus = Math.cos(phiPlus); - double sinPlus = Math.sin(phiPlus); - double cosMinus = Math.cos(phiMinus); - double sinMinus = Math.sin(phiMinus); - - // Rho range of LAr Detector (EM) is about between [148.175, 198.47] - // Rho range of TILE Detector (Had) is about between [229, 386] - double rhoMax = 380; - double rhoMinus = 155; - - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double rhoPlus = rhoMax; - if(Math.abs(eT[list]) < maxEnergy) - rhoPlus = rhoMinus + (rhoMax - rhoMinus) * Math.abs(eT[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = rhoMinus * cosPlus; - hv[1][i][0] = rhoMinus * sinPlus; - // x1, y1 - hv[0][i][1] = rhoPlus * cosPlus; - hv[1][i][1] = rhoPlus * sinPlus; - // x2, y2 - hv[0][i][2] = rhoPlus * cosMinus; - hv[1][i][2] = rhoPlus * sinMinus; - // x3, y3 - hv[0][i][3] = rhoMinus * cosMinus; - hv[1][i][3] = rhoMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getFRUser() - { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - double dtheta = Math.toRadians(0.5); - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list]-phiMid); - double rSign; - if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) - rSign = -1; - else - rSign = 1; - - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta[list]))) * 2.0; - if ((eta[list] > 0.) && (rSign == -1)) - theta = 2 * Math.PI - theta; - else if ((eta[list] < 0.) && (rSign == -1)) - theta += Math.PI; - else if ((eta[list] < 0.) && (rSign == 1)) - theta = Math.PI - theta; - - double thetaPlus = theta + dtheta; - double thetaMinus = theta - dtheta; - double cosPlus = Math.cos(thetaPlus); - double sinPlus = Math.sin(thetaPlus); - double cosMinus = Math.cos(thetaMinus); - double sinMinus = Math.sin(thetaMinus); - - // decide the region based on the theta value - final byte LAR = 0; - final byte LAR_ENDCAP = 1; - final byte FCAL_EM = 2; - byte region = LAR; - // hard-coded value is based on the values in AGeometry.xml - if(Math.abs(Math.tan(theta)) >= 0.0778 && Math.abs(Math.tan(theta)) < 0.4828) - region = LAR_ENDCAP; - else if(Math.abs(Math.tan(theta)) < 0.0778) - region = FCAL_EM; - - double radiusMinus = 0.; - switch(region) - { - // use fixed rho/z to determine the lower radius value - case LAR: - radiusMinus = 155 / Math.abs(Math.sin(theta)); - break; - case LAR_ENDCAP: - radiusMinus = 380 / Math.abs(Math.cos(theta)); - break; - case FCAL_EM: - radiusMinus = 470 / Math.abs(Math.cos(theta)); - break; - } - double radiusMax = radiusMinus + 200; - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double radiusPlus = radiusMax; - if(Math.abs(eT[list]) < maxEnergy) - radiusPlus = radiusMinus + (radiusMax - radiusMinus) * Math.abs(eT[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = radiusMinus * cosPlus; - hv[1][i][0] = radiusMinus * sinPlus; - // x1, y1 - hv[0][i][1] = radiusPlus * cosPlus; - hv[1][i][1] = radiusPlus * sinPlus; - // x2, y2 - hv[0][i][2] = radiusPlus * cosMinus; - hv[1][i][2] = radiusPlus * sinMinus; - // x3, y3 - hv[0][i][3] = radiusMinus * cosMinus; - hv[1][i][3] = radiusMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ACompositeParticleData.java b/graphics/AtlantisJava/src/atlantis/data/ACompositeParticleData.java deleted file mode 100755 index 5537e5b0331..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ACompositeParticleData.java +++ /dev/null @@ -1,114 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Reconstructed CompositeParticle - */ -public class ACompositeParticleData extends AAODData -{ - private int[] pdgId; - private float[] charge; - private String[] label; - private String[] typeEV; - - ACompositeParticleData(AHashMap p, AEvent e) - { - super(p,e); - pdgId = p.getUnsureIntArray("pdgId"); - charge=p.getUnsureFloatArray("charge"); - label=p.getStringArray("label"); - typeEV=p.getStringArray("typeEV"); - } - - public String getParameterGroup() - { - return "CompositeParticle"; - } - - @Override - public String getName() - { - return "CompositeParticle"; - } - - public int getPdgId(int index) - { - return pdgId[index]; - } - - public float getCharge(int index) - { - return charge[index]; - } - - public String getLabel(int index) - { - return label[index]; - } - - public String getTypeEV(int index) - { - return typeEV[index]; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" = "); - msg.append(id[index]); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - if (charge != null) - { - msg.append("\n Charge = "); - msg.append(charge[index]); - } - if(pdgId != null) - { - if(pdgId[index]!=0) - msg.append("\n Type = " + APDGTable.getName(pdgId[index]) + " (type code " + pdgId[index] + ")" ); - else - msg.append("\n Type = unknown (type code " + pdgId[index] + ")" ); - } - msg.append("\n TypeEV = " + typeEV[index]); - if (label != null) - msg.append("\n Label = " + label[index]); - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ADHelix.java b/graphics/AtlantisJava/src/atlantis/data/ADHelix.java deleted file mode 100755 index 6e1228528da..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ADHelix.java +++ /dev/null @@ -1,539 +0,0 @@ -package atlantis.data; - -import java.awt.geom.Point2D; -import java.util.Vector; -import java.awt.Rectangle; - -import atlantis.canvas.AWindow; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.graphics.ACoord; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjection3D; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -/** - * Helix in a format suitable for drawing given as a circle with - * centre point and radius etc. - * - * phi is the angle seen from the primary vertex - * a = alpha = the angle as seen for the center of the circle - * - */ -public class ADHelix -{ - private final static ALogger logger = ALogger.getLogger(ADHelix.class); - - // parameters used internally - private static final APar parameterStore = APar.instance(); - private static final AParameter rToPar = parameterStore.get("RTr", "RadiusTr"); - private static final AParameter lToPar = parameterStore.get("RTr", "LineTr"); - private static final AParameter zToPar = parameterStore.get("RTr", "ZTr"); - private static final int callDepthCut = parameterStore.get("RTr", "CallDepth").getI();; - - /** The associated helix object. */ - public final AHelix helix; - - // description of helix - private final double rC, xC, yC, ch, a0, x0, y0, z0, bz, cosA0, sinA0; - // position along helix - private final double aStart, aEnd; - - /** Attempt to encapsulate the "current position" variables. */ - private static class HelixPoint { - double x, y, z, rho, phi; - } - - private double startPhi; // the phi value of starting point of "v" - // TODO: Would prefer this not to be part of the state of the helix object. - private boolean startMark; // true when calculating start point, false otherwise - - ADHelix(AOldHelix h) { - this(new AHelix(h)); - } - - ADHelix(AHelix h) - { - helix = h; - double[] perigee = h.getPar(); // d0, z0, phi0, cotanTheta, q/pT - - AParameter curvatureParameter = parameterStore.get("Event", "Curvature"); - if (curvatureParameter != null) { - rC = curvatureParameter.getD() / Math.abs(perigee[4]); - } else { - rC = (100/0.6) / Math.abs(perigee[4]); - } - ch = AMath.getSign(perigee[4]); - a0 = Math.toDegrees(perigee[2]) + ch * 90.; - double a0Rad = Math.toRadians(a0); - cosA0 = Math.cos(a0Rad); - sinA0 = Math.sin(a0Rad); - z0 = perigee[1]; - double d0 = perigee[0]; - double signD0 = ch; - d0 *= signD0; - x0 = d0 * cosA0; - y0 = d0 * sinA0; - double SD0 = 1.; - double SRC = 1.; - double r0 = SD0 * d0 - SRC * rC; - xC = r0 * cosA0; - yC = r0 * sinA0; - bz = rC * Math.toRadians(perigee[3]); - double rTo = rToPar.getD(); - //Check if track is limited by end vertex - if ( helix.getRhoEndVertex() > 0. ) - rTo = Math.min(rTo,helix.getRhoEndVertex()); - double zTo = zToPar.getD(); - /*******************************************************************************/ - //Adrian Vatchinsky, Andy Haas (NYU) - //Import the coordinates of the primary vertex in order to calculate new starting angle - AEventManager eventManager = AEventManager.instance(); - AEvent currentEvent = eventManager.getCurrentEvent(); - if (helix.getRho(helix.getAlphaMin())!=0 || currentEvent==null) { // FIXME: doubles compared for equality - aStart = helix.getAlphaMin(); // old, DCA to 0,0 - } else { // new, DCA to PV - double[] primaryVertex = currentEvent.getPrimaryVertex(); - double xV = primaryVertex[0]; double yV = primaryVertex[1]; - aStart = helix.getAlphaMin() + ch*Math.toDegrees(Math.atan2(yC,xC)-Math.atan2(yC-yV,xC-xV)); - } - /*******************************************************************************/ - HelixPoint point = pointAt(aStart); - // don't draw tracks starting outside the tracking region - if(Math.abs(point.rho) > rTo || Math.abs(point.z) > zTo) - { - this.aEnd = aStart; - return; - } - //Calculate max phi angle -> no track can have more than 180 deg - double aEndMax = Math.min(aStart + 180., 180.); - //Also the track should not stick out of the rTo zylinder - double aEndR = intersectWithRadialCylinder(rTo, aStart, aEndMax); - // nor should it go beyond the max. z-extension - double aEndZ = intersectWithZPlanes(zTo, aStart, aEndMax); // or beyond the end-vertex radius, if given - double aEndTmp = Math.min(aEndMax, aEndR); - if(aEndZ > aStart) aEndTmp = Math.min(aEndTmp, aEndZ); - this.aEnd = Math.min(aEndTmp, aEndMax); - } - - - // calculate phi on track at intersection - // Cylinder is infinite in Z direction - public double intersectWithRadialCylinder(double rCyl, double aStart, - double aEnd) - { - if(rC <= 0.) return aStart; - double r0 = Math.sqrt(xC * xC + yC * yC); - double bb = (rCyl * rCyl - rC * rC - r0 * r0) / (2. * rC * r0); - double rhoStart = getRho(aStart); - double rhoEnd = getRho(aEnd); - if(rCyl >= rhoStart && rCyl >= rhoEnd) return aEnd; - if(rCyl <= rhoStart && rCyl <= rhoEnd) return aStart; - if(Math.abs(bb) > 1.) - { - // needs to be understood better (Hans) - // event file: acr_muontrack_problem_event.xml - logger.warn("Bug in ADHelix " + rCyl + " " + rhoStart + " " + rhoEnd); - return aEnd; - } - double cc = Math.toDegrees(Math.acos(bb)); - if(Math.abs(cc) > 360) - throw new Error("error in cc in dhelix"); - double gA = Math.toDegrees(Math.atan2(yC, xC)); - double a1 = ch * (a0 - gA + cc); - double a2 = ch * (a0 - gA - cc); - if(a1 < 0.) a1 += 360.; - if(a2 < 0.) a2 += 360.; - if(a1 >= 360.) a1 -= 360.; - if(a2 >= 360.) a2 -= 360.; - return Math.min(a1, a2); - } - - - // calculate phi on track at intersection - public double intersectWithZPlanes(double zCyl, double aStart, double aEnd) - { - double zMin = 20.; - double aZ = aEnd; - if(zCyl >= zMin && bz != 0.) - { - double aZPlus = (zCyl - z0) / bz; - double aZMinus = ( -zCyl - z0) / bz; - if(aZPlus < aZ && aZPlus > aStart) aZ = aZPlus; - if(aZMinus < aZ && aZMinus > aStart) aZ = aZMinus; - } - return aZ; - } - - - // calculate phi on track at intersection - // cylinder finite in Z - public double intersectWithCylinder(boolean useR, double rCyl, boolean useZ, - double zCyl) - { - double aStart = 0.; - double aEndMax = 180.; - double zMin = 20.; - double aEndR = 0.; - if(useR) - aEndR = intersectWithRadialCylinder(rCyl, aStart, aEndMax); - double aEndZ = 0.; - if(useZ && zCyl >= zMin && bz != 0.) - { - aEndZ = intersectWithZPlanes(zCyl, aStart, aEndMax); - return Math.min(aEndR, aEndZ); - } - else - return aEndR; - } - - - // a... angle in deg starting with 0 meaning point of closest approach - private HelixPoint pointAt(double a) - { - HelixPoint point = new HelixPoint(); - double aRad = Math.toRadians(a0 - ch * a); - point.x = x0 + rC * (Math.cos(aRad) - cosA0); - point.y = y0 + rC * (Math.sin(aRad) - sinA0); - point.z = z0 + bz * a; - double[] primaryVtx = AParameterUtilities.getPrimaryVertex(); - double dx = point.x - primaryVtx[0]; - double dy = point.y - primaryVtx[1]; - point.rho = Math.sqrt(dx * dx + dy * dy); - double phi0 = Math.toDegrees(Math.atan2(dy, dx)); - double phiMid2 = parameterStore.get("RZ", "Phi").getD(); - point.phi = AMath.nearestPhiDegrees(phi0,phiMid2); - return point; - } - - - // s1 and s2 are the extreme values of phi - // used to avoid tracks being drawn with phi discontinuity - // in phi projections - // = FiMid in atlantis fortran ask Hans Drevermann - public double setPhiStart(double s1, double s2) - { - double phi1 = getPhi(s1); - double phi2 = getPhi(s2); - double phiM = getPhi((s1 + s2) / 2); - // doesn't work for all tracks but for most - if(Math.abs(phi1 - phi2) > 180. || Math.abs(phi1 - phiM) > 180. || - Math.abs(phi2 - phiM) > 180.) - { - if(phi1 - phiM > 180.) phi1 -= 360.; - if(phi2 - phiM > 180.) phi2 -= 360.; - if(phi1 - phiM < -180.) phi1 += 360.; - if(phi2 - phiM < -180.) phi2 += 360.; - - // must be something wrong here, phiM is the same using the - // following code, then why use if ... else ... - if(phi1 < phiM && phiM < phi2) - phiM = (phi1 + phi2) / 2.; - else if(phi1 > phiM && phiM > phi2) - phiM = (phi1 + phi2) / 2.; - else - { - phiM = (phi1 + phi2) / 2.; - } - } - if(phiM > 360.) - phiM -= 360.; - if(phiM < 0.) - phiM += 360.; - return phiM; - } - - - public double getAStart() - { - return aStart; - } - - - public double getAEnd() - { - return aEnd; - } - - - public ACoord getYXPoint(double a) - { - HelixPoint point = pointAt(a); - return new ACoord(point.x, point.y, -1); - } - - - public ACoord getRZPoint(double a) - { - HelixPoint point = pointAt(a); - double phiMid2 = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(Math.toRadians(point.phi) - phiMid2); - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - return new ACoord(point.z, point.rho, -1); - else - return new ACoord(point.z, -point.rho, -1); - } - - - public ACoord get3DPoint(double a) - { - HelixPoint point = pointAt(a); - double[] point3D = {point.x,point.y,point.z}; - point3D = AProjection3D.getRotated(point3D); - return new ACoord(point3D[0], point3D[1], -1); - } - - - public double[] get3DPointAsArray(double a) - { - HelixPoint point = pointAt(a); - double[] point3D = new double[] {point.x, point.y, point.z }; - point3D = AProjection3D.getRotated(point3D); - return point3D; - } - - - public ACoord getXZPoint(double a) - { - HelixPoint point = pointAt(a); - double phiC = AProjectionXZ.getPhi(); - return new ACoord(point.z, point.rho * Math.cos(Math.toRadians(point.phi - phiC)), -1); - } - - - public ACoord getYZPoint(double a) - { - HelixPoint point = pointAt(a); - double phiC = AProjectionXZ.getPhi(); - return new ACoord(point.z, point.rho * Math.sin(Math.toRadians(point.phi - phiC)), -1); - } - - - public ACoord getFZPoint(double a) - { - HelixPoint point = pointAt(a); - double temp = Math.toDegrees(AParameterUtilities.getPhiStereo(point.rho, Math.toRadians(point.phi), point.z)); - return new ACoord(point.z, temp, -1); - } - - - public ACoord getFRPoint(double a) - { - HelixPoint point = pointAt(a); - double temp = Math.toDegrees(AParameterUtilities.getPhiStereo(point.rho, Math.toRadians(point.phi), point.z)); - return new ACoord(point.rho, temp, -1); - } - - - public ACoord getVPPoint(double a, int sign) - { - HelixPoint point = pointAt(a); - if(startMark) // start point - { - startPhi = point.phi; // phi is between 0 and 360 - } - else - { - point.phi = AMath.nearestPhiDegrees(point.phi, startPhi); - } - return new ACoord(AParameterUtilities.eta(point.z, point.rho) + - sign * AProjectionVP.getDeltaEta(point.rho, point.z), point.phi, -1); - } - - - public ACoord getLEGOPoint(double a) - { - //added by Mark Stockton - HelixPoint point = pointAt(a); - double temp = Math.toDegrees(AParameterUtilities.getPhiStereo(point.rho, Math.toRadians(point.phi), point.z)); - return new ACoord(AParameterUtilities.eta(point.z, point.rho), temp, -1); - } - - - public double getPhi(double a) - { - HelixPoint point = pointAt(a); - return point.phi; - } - - - public double getEta(double a) - { - HelixPoint point = pointAt(a); - return AParameterUtilities.eta(point.z, point.rho); - } - - - private double getRho(double a) - { - HelixPoint point = pointAt(a); - return point.rho; - } - - - /** Draw helix in display space in an iterative manner. */ - public ACoord drawHelix(AWindow window, AProjection2D projection, double s1, double s2) - { - Vector<Point2D.Double> pointsOnHelix = new Vector<Point2D.Double>(100); - double dPrevious = 999.; - int callDepth = 0; - // get the point at the beginning and end of the helix, defined by the phi-values (s1,s2) - startMark = true; - ACoord d1 = window.calculateDisplay(projection.getUserPoint(this, s1)); - double h1 = d1.hv[0][0][0]; - double v1 = d1.hv[1][0][0]; - startMark = false; - ACoord d2 = window.calculateDisplay(projection.getUserPoint(this, s2)); - double h2 = d2.hv[0][0][0]; - double v2 = d2.hv[1][0][0]; - pointsOnHelix.add(new Point2D.Double(h1, v1)); - // We are simply adding points here, in the end the helix is drawn as a polyline - drawHelix(pointsOnHelix, window, projection, s1, h1, v1, s2, h2, v2, - dPrevious, callDepth); - int numPoints; - if(projection instanceof AProjectionVP) - { - numPoints = pointsOnHelix.size(); - } - else - { - numPoints = pointsOnHelix.size() + 1; // add 1 to add a point for the line - } - double[][][] hv = new double[2][1][numPoints]; - int[] index = new int[1]; - Point2D.Double p; - if(projection instanceof AProjectionVP) - { - for(int k = 0; k < numPoints; ++k) - { - p = (Point2D.Double) pointsOnHelix.elementAt(k); - hv[0][0][k] = p.getX(); - hv[1][0][k] = p.getY(); - } - } - else - { - for(int k = 0; k < numPoints - 1; ++k) - { - p = (Point2D.Double) pointsOnHelix.elementAt(k); - hv[0][0][k] = p.getX(); - hv[1][0][k] = p.getY(); - } // first attempt for line... - if(numPoints > 2) - { - double dx = hv[0][0][numPoints - 2] - hv[0][0][numPoints - 3]; - double dy = hv[1][0][numPoints - 2] - hv[1][0][numPoints - 3]; - double x0 = hv[0][0][numPoints - 2] - hv[0][0][0]; - double y0 = hv[1][0][numPoints - 2] - hv[1][0][0]; - - // InDet -> Track -> Rho Track linearly is 0 by default - // and the value is meant beyond Rho Track as Helix parameter, - // hence rToPar + lToPar is used instead of former lToPar only - double dtopar = ( (rToPar.getD() + lToPar.getD()) / rToPar.getD()) * - Math.sqrt(x0 * x0 + y0 * y0); - double cophi = dx / Math.sqrt(dx * dx + dy * dy); - double siphi = dy / Math.sqrt(dx * dx + dy * dy); - double addl = Math.sqrt((y0 * siphi + x0 * cophi) * - (y0 * siphi + x0 * cophi) - - x0 * x0 - y0 * y0 + dtopar * dtopar); - double addlen = Math.min(Math.abs( -(y0 * siphi + x0 * cophi) + - addl), - Math.abs( -(y0 * siphi + x0 * cophi) - - addl)); - hv[0][0][numPoints - 1] = x0 + addlen * cophi + hv[0][0][0]; - hv[1][0][numPoints - 1] = y0 + addlen * siphi + hv[1][0][0]; - } - } - return new ACoord(hv, index); - } - - - /** Called recursively. */ - private void drawHelix(Vector<Point2D.Double> pointsOnHelix, AWindow window, AProjection2D projection, - double s1, double h1, double v1, double s2, double h2, double v2, - double dPrevious, int callDepth) - { - double D_MAX = 1.; - double h21 = h2 - h1; - double v21 = v2 - v1; - // nothing left to draw - if(h21 == 0. && v21 == 0.) - return; - // calculate midpoint - double sM = 0.5 * (s1 + s2); - ACoord dispM = window.calculateDisplay(projection.getUserPoint(this, sM)); - double hM = dispM.hv[0][0][0]; - double vM = dispM.hv[1][0][0]; - - // For speed reasons we make sure we aren't doing a lot of subdivison - // on helix segments outside the view area - boolean isinview = true; - - if (callDepth > 2) { - // Check if bounding box of segment is on the screen anywhere - // Don't try this until we've divided a few times just in case we - // have a really curly helix to deal with - Rectangle wdim = window.getCurrDisp(); - - int left = (int)h1; - int top = (int)v1; - int width = (int)(h2 - h1); - int height = (int)(v2 - v1); - - // Make sure the box isn't upside down or zero in size as this - // seemed to be causing a few problems - if (width < 0) { left += width; width = -width; } - if (height < 0) { top += height; height = -height; } - if (width == 0) { width = 1; } - if (height == 0) { height = 1; } - - Rectangle bound = new Rectangle(left, top, width, height); - - if (!wdim.intersects(bound)) { - // Prevent any further sub-division - isinview = false; - } - } - - // calculate distance of midpoint from straight line approximation - double hM1 = hM - h1; - double vM1 = vM - v1; - double temp = (v21 * hM1 - h21 * vM1); - double dM = temp * temp / (v21 * v21 + h21 * h21); - // this iteration and previous one within tolerance - if(dPrevious < D_MAX && dM < D_MAX) - { - pointsOnHelix.add(new Point2D.Double(h2, v2)); - } - else - { - if(callDepth < callDepthCut && isinview) - { - // split track in two and iterate - drawHelix(pointsOnHelix, window, projection, s1, h1, v1, sM, hM, - vM, dM, callDepth + 1); - drawHelix(pointsOnHelix, window, projection, sM, hM, vM, s2, h2, - v2, dM, callDepth + 1); - } - else - { - pointsOnHelix.add(new Point2D.Double(hM, vM)); - pointsOnHelix.add(new Point2D.Double(h2, v2)); - } - } - } - - public double getxC() { - return xC; - } - - public double getyC() { - return yC; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AETMisData.java b/graphics/AtlantisJava/src/atlantis/data/AETMisData.java deleted file mode 100644 index 2bba9e11185..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AETMisData.java +++ /dev/null @@ -1,562 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.canvas.AWindow; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -import java.awt.Stroke; -import java.awt.BasicStroke; -import java.awt.geom.Point2D; - -/** - * AETMisData - Missing ET class implementation. Although it is always - * supposed that there will be only 1 item of the datatype, it's now done - * generically as a normal datatype (assuming there is numData items, this - * numData shall always be 1 for ETMis) - */ -public class AETMisData extends AData { - // data read in from the event file - - protected float[] et; - protected float[] etx; - protected float[] ety; - // calculated data - protected float[] sumet; - protected float[] phi; // in radians - protected final int YX_NUMPOINTS = 200; - - AETMisData(AHashMap p, AEvent e) throws AAtlantisException { - super(p, e); - - sumet = p.getFloatArray("et"); - etx = p.getFloatArray("etx"); - ety = p.getFloatArray("ety"); - - et = new float[numData]; - phi = new float[numData]; - for (int i = 0; i < numData; i++) { - et[i] = (float) Math.sqrt(etx[i] * etx[i] + ety[i] * ety[i]); - - phi[i] = (float) Math.atan2(ety[i], etx[i]); - if (phi[i] < 0.0) { - phi[i] += AMath.TWO_PI; - } - } - - } // AETMisData() ------------------------------------------------------- - - /** - * Assuming there is only one item in the ETMis datatype which shall - * always be, but the rest of the class is more generic (the 0 index) - * @return float - */ - public float getET() { - return et[0]; - - } // getET() ------------------------------------------------------------ - - /** - * Assuming there is only one item in the ETMis datatype which shall - * always be, but the rest of the class is more generic (the 0 index) - * @return float - */ - public float getETx() { - return etx[0]; - - } // getETx() ----------------------------------------------------------- - - /** - * Assuming there is only one item in the ETMis datatype which shall - * always be, but the rest of the class is more generic (the 0 index) - * @return float - */ - public float getETy() { - return ety[0]; - - } // getETy() ----------------------------------------------------------- - - /** - * Assuming there is only one item in the ETMis datatype which shall - * always be, but the rest of the class is more generic (the 0 index) - * @return float - */ - public float getPhi() { - return phi[0]; - - } // getPhi() ----------------------------------------------------------- - - /** - * Returns info string for picking. - * @param index - * @return info string - */ - public String getHitInfo(int index) { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if (simpleOutput > 0) { - String output = getNameScreenName() + " index: " + index; - if (simpleOutput == 1 || simpleOutput == 3) { - output += "\n ET=" + String.format("%.3f", et[index]) + " GeV\n " - + AMath.PHI + " = " + String.format("%.3f", Math.toDegrees(phi[index])) + AMath.DEGREES; - } - if (simpleOutput == 2 || simpleOutput == 3) { - output += "\n Ex=" + String.format("%.3f", et[index] * Math.cos(phi[index])) + " GeV " - + "\n Ey=" + String.format("%.3f", et[index] * Math.sin(phi[index])) + " GeV "; - } - return output; - } - - String msg; - - msg = getNameScreenName() + "\n"; - msg += " storegate key: "; - msg += (storeGateKey == null ? "n/a" : storeGateKey) + "\n"; - msg += " Sum-ET = " + String.format("%.3f", sumet[index]) + " GeV" + "\n" - + " ET-Mis = " + String.format("%.3f", et[index]) + " GeV" + "\n" - + " ETx-Mis = " + String.format("%.3f", etx[index]) + " GeV" + "\n" - + " ETy-Mis = " + String.format("%.3f", ety[index]) + " GeV" + "\n" - + " " + AMath.PHI + " = " - + String.format("%.3f", Math.toDegrees(phi[index])) - + AMath.DEGREES + " (" + String.format("%.3f", phi[index]) + " rad)"; - - return msg; - - } // getHitInfo() ------------------------------------------------------- - - /** - * Info on ETMis contained in v-plot rubberband selection - * @return String - */ - public String getVPHitInfo() { - makeDrawList(); - if (numDraw == 0) { - return ""; - } - - double sumEt = 0.0; - for (int i = 0; i < numDraw; i++) { - sumEt += Math.abs(et[i]); - } - - String key = getStoreGateKey(); - String msg = numDraw + " " + (key != null ? "" + key : getNameScreenName()); - msg += " ET = " + String.format("%.1f", sumEt); - return msg; - - } // getVPHitInfo() ----------------------------------------------------- - - /** - * getParameterGroup() - * @return parameter group - */ - public String getParameterGroup() { - return "ETMis"; - - } // getParameterGroup() ------------------------------------------------ - - public String getName() { - return "ETMis"; - - } // getName() ---------------------------------------------------------- - - public String getNameScreenName() { - return "ETMis"; - - } // getNameScreenName() ------------------------------------------------ - - /** - * internalColor() - * Implement this atlantis.event.AData method - * Coloring of the graphical object on the canvas - * @return number of color types - */ - protected int internalColor() { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if (colorFunction == 0) { - colorByConstant(); - } else if (colorFunction == 1) { - colorByIndex(); - } else if (colorFunction == 2) { - colorByCollection(); - } - - return 3; - - } // internalColor() ---------------------------------------------------- - - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - //option to scale line width by energy - Stroke origStroke = ag.getGraphics2D().getStroke(); - if(parameterStore.getUnknown("ETMis", "LineWidth").getI()==0){ - float factor=0.f; - if(et[0]<5){ - factor=1.0f; - }else if(et[0]<10.){ - factor=1.5f; - }else if(et[0]<15.){ - factor=2.0f; - }else if(et[0]<20.){ - factor=2.5f; - }else if(et[0]<25.){ - factor=3.0f; - }else if(et[0]<30.){ - factor=3.5f; - }else if(et[0]<35.){ - factor=4.0f; - }else if(et[0]<40.){ - factor=4.5f; - }else{ - factor=5.0f; - } - ag.getGraphics2D().setStroke(new BasicStroke(factor)); - } - - if(projection instanceof AProjectionYX) - { - // check config whether to draw as arrow or dashed line.. - if(parameterStore.get("ETMis", "Drawas").getI() == 0) // Arrow = 0, Dashed = 1 - { - drawArrow(window, ag, projection); - } - else - { - drawDashed(window, ag, projection); - } - } - else if(projection instanceof AProjectionVP) - { - // Draw ETMis in VPlot... - ACoord centers = window.calculateDisplay(getUser(projection)); - int[] drawlist = centers.index; - double eLimit = 0.05; - final int numPoints = 25; - // hv will contain all the coordinates - // [2] - x and y value - // [drawlist.length] - should be "3" for ET Miss object by default - // after the PhiWrap - // [numPoints] - number of points required for drawing Et missing - // object in V-Plot - double[][][] hv = new double[2][drawlist.length][numPoints]; - - for(int i = 0; i < drawlist.length; ++i) - { - int list = drawlist[i]; - - int d = (int) (Math.sqrt((this.et[list] / eLimit) / Math.PI)); - if(d == 0) - { - d = 1; - } - - for(int j = 0; j < numPoints; j++) - { - hv[0][i][j] = centers.hv[0][list][i] + - d * Math.cos(Math.PI * 2 * j / (numPoints - 1)); - hv[1][i][j] = centers.hv[1][list][i] + - d * Math.sin(Math.PI * 2 * j / (numPoints - 1)); - } - } - ag.draw(new ACoord(hv, drawlist, this, ACoord.DOTTED_POLYGONS)); - } - else - { - super.draw(window, ag, projection); - } - //reset stroke if have changed to scale with energy - if(parameterStore.getUnknown("ETMis", "LineWidth").getI()==0) - ag.getGraphics2D().setStroke(origStroke); - } - - /** - * drawArrow() - * Method performs the drawing of the object on the canvas as arrow. - * @param window - * @param ag - * @param projection - */ - public void drawArrow(AWindow window, AGraphics ag, AProjection2D projection) - { - ACoord centers = window.calculateDisplay(getUser(projection)); - - int[] drawlist = centers.index; // draw everything in array - - // scale the arrowhead with zoom... - double zoomScaling=0; - Point2D.Double[] corners = window.getUserCorners(); - double widthx=corners[1].x-corners[0].x; - double widthy=corners[0].y-corners[2].y; - //average width of window - double width=Math.sqrt(widthx*widthx+widthy*widthy); - //calculate scaling (100 is arbitrary constant) - zoomScaling=100/width; - double arrowheadScale = 10+10*zoomScaling*Math.log(et[0]+1); - - // phiPrime represents the angle of the missingET arrow - double phiPrime = -1*Math.atan2(ety[0],etx[0]); - - // arrowMain contains the start point and end point of the arrow - double[][][]arrowMain = new double[2][drawlist.length][2]; - - // scale arrow length with etmiss - double arrowScale = et[0]*et[0]/250.0; //arbitrary scaling factor - double arrowCenter = 2.02; // this sets the starting point of the arrow. 2.02 ~ edge of ID - if (arrowScale > 8) { - arrowScale = 8; - } - for (int i = 0; i < drawlist.length; i++) { - for (int j = 0; j < 2; j++) { - arrowMain[0][i][j] = centers.hv[0][i][0] + (arrowCenter + arrowScale * j)*(centers.hv[0][i][1]-centers.hv[0][i][0]); - arrowMain[1][i][j] = centers.hv[1][i][0] + (arrowCenter + arrowScale * j)*(centers.hv[1][i][1]-centers.hv[1][i][0]); - } - } - double[][][]arrowHead1 = new double[2][drawlist.length][2]; - double[][][]arrowHead2 = new double[2][drawlist.length][2]; - for(int i = 0; i < drawlist.length; i++) - { - for(int j=0;j<2;j++) - { - // set the points for the two parts of the arrow head - // 2.591 and 3.691 are the factors to add to the arrow's angle for the correct arrowhead orientation... - arrowHead1[0][i][j] = arrowMain[0][0][1] + j*(arrowheadScale*Math.cos(2.591+phiPrime)); - arrowHead1[1][i][j] = arrowMain[1][0][1] + j*(arrowheadScale*Math.sin(2.591+phiPrime)); - arrowHead2[0][i][j] = arrowMain[0][0][1] + j*(arrowheadScale*Math.cos(3.691+phiPrime)); - arrowHead2[1][i][j] = arrowMain[1][0][1] + j*(arrowheadScale*Math.sin(3.691+phiPrime)); - } - } - // draw arrow, 3 parts, main arrow body and two lines for arrowhead - ag.draw(new ACoord(arrowMain, drawlist, this, ACoord.DOTTED_POLYGONS)); - ag.draw(new ACoord(arrowHead1, drawlist, this, ACoord.DOTTED_POLYGONS)); - ag.draw(new ACoord(arrowHead2, drawlist, this, ACoord.DOTTED_POLYGONS)); - - } // drawArrow() ------------------------------------------------------------- - - /** - * drawDashed() - * Method performs the drawing of the object on the canvas as a dashed line. - * @param window - * @param ag - * @param projection - */ - public void drawDashed(AWindow window, AGraphics ag, AProjection2D projection) - { - //Stop Etmiss being scaled by Fisheye - boolean origStatus = parameterStore.get(projection.getName(), "FishEye").getStatus(); - parameterStore.get(projection.getName(), "FishEye").setStatus(false); - ACoord centers = window.calculateDisplay(getUser(projection)); - if(origStatus) parameterStore.get(projection.getName(), "FishEye").setStatus(origStatus); - - int[] drawlist = centers.index; // draw everything in array - // hv will contain all the the coordinates - // [2] - x and y value - // [numData] - should be "1" for ETMis datatype - // [YX_NUMPOINTS] - number of points required for ET Miss object - - // length of drawlist should always be 1 -> only 1 iteration - double[][][] hv = new double[2][drawlist.length][YX_NUMPOINTS]; - for(int i = 0; i < drawlist.length; i++) - { - for(int j = 0; j < YX_NUMPOINTS; j++) - { - hv[0][i][j] = centers.hv[0][i][j]; // x - hv[1][i][j] = centers.hv[1][i][j]; // y - } - } - ag.draw(new ACoord(hv, drawlist, this, ACoord.DOTTED_POLYGONS)); - - } // drawDashed() ------------------------------------------------------------- - /** - * getYXUser() - * calculates coordinates for the Et missing graphical object which - * consists of one arrowed line, i.e. one line and two smaller lines - * forming the arrow, all together NUM_POINTS points - * @return coordinates - */ - protected ACoord getYXUser() - { - if (etx[0] == 0.f && ety[0] == 0.f) return ACoord.NO_DATA; - - makeDrawList(); // applycuts will be called here - - // Et missing graphical object consists of one dashed line from center - // to the border of canvas, or an arrow. - - // hv will contain all the coordinates - // [2] - x and y value - // [numData] - should be "1" for ETMis datatype - // YX_NUMPOINTS - number of points required for ET Miss object - double[][][] hv = new double[2][numDraw][YX_NUMPOINTS]; - int[] index = new int[numDraw]; - // i counter, here should have just one item in the coordinate array - // (index.length = 1), numDraw should be 1 - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - // main line (dashed) - // to be properly done: geting border values over canvas/window - double inc = 10000 / YX_NUMPOINTS; - double x = Math.cos(phi[list]); - double y = Math.sin(phi[list]); - for(int ii = 0; ii < YX_NUMPOINTS; ii++) - { - hv[0][i][ii] = x * (inc * ii); - hv[1][i][ii] = y * (inc * ii); - } - - index[i] = list; - } - return new ACoord(hv, index, this); - - } // getYXUser() -------------------------------------------------------- - - @Override - protected ACoord getRZUser() { - if (etx[0] == 0.f && ety[0] == 0.f) return ACoord.NO_DATA; - - double s = 1+Math.sqrt(et[0]);//4*parameterStore.get("ETMis", "Scale").getD(); - if (0 == s || parameterStore.get("ETMis", "Drawas").getI() == 1) { - return ACoord.NO_DATA; - } - makeDrawList(); // applycuts will be called here - double[][][] hv = new double[2][numDraw][YX_NUMPOINTS + 4]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) { - int list = listdl[i]; - double rhoMinus = 500; - double rhoMax = 1500; - double inc = 1. / YX_NUMPOINTS; - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double rhoPlus = rhoMax; - if (Math.abs(et[list]) < maxEnergy) { - rhoPlus = (rhoMax - rhoMinus) * s * Math.abs(et[list]) / maxEnergy; - } - - double updown = 0; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - if (phiMid > AMath.TWO_PI) { - phiMid -= AMath.TWO_PI; - } - double phiDiff = Math.abs(phi[list] - phiMid); - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) { - updown = 1; - } else { - updown = -1; - } - - //double y = rhoPlus*Math.cos(phiDiff);//to change with cos of phiDiff - double y = rhoPlus * updown;//to change just by up or down - for (int ii = 0; ii <= YX_NUMPOINTS; ii++) { - hv[0][i][ii] = 0; - hv[1][i][ii] = rhoMinus * updown + y * (inc * ii); - } - hv[0][i][YX_NUMPOINTS + 1] = rhoMinus * .1; - hv[1][i][YX_NUMPOINTS + 1] = rhoMinus * updown + 0.8 * y; - hv[0][i][YX_NUMPOINTS + 2] = -rhoMinus * .1; - hv[1][i][YX_NUMPOINTS + 2] = rhoMinus * updown + 0.8 * y; - hv[0][i][YX_NUMPOINTS + 3] = 0; - hv[1][i][YX_NUMPOINTS + 3] = rhoMinus * updown + y; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - - } // getRZUser() -------------------------------------------------------- - - /** - * calculate coordinates for the Et missing graphical object - * in V-Plot (eta-phi projection) - * @return coordinates - */ - protected ACoord getVPUser() - { - if (etx[0] == 0.f && ety[0] == 0.f) return ACoord.NO_DATA; - - makeDrawList(); // applycuts will be called here - - // numDraw for ET Miss object should be 1 - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[0] = 0.0; // h[0] is the eta value, ETMis always drawn in the - // centre of VPlot - at eta 0 - v[0] = Math.toDegrees(phi[list]); // v[0] is the phi value - index[i] = list; - } - - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - - } // getVPUser() -------------------------------------------------------- - - /** - * this method is defined as an abstract method in AData, so must be - * implemented in this child class - */ - protected void applyCuts() { - - // no need to cut index (always 0), and transverse momentum for ET Miss - // assuming only 1 item in the ETMis datatype, thus index 0 - cutPhi(phi[0]); - - // eta value for ET Miss is 0 - cutEta(0.0f); - - // cut on ETMiss (default cut of 15 GeV) - cut("CutsObjects", "ETMis", " |ETMis|", et); - - } // applyCuts() -------------------------------------------------------- - - /** - * phi cut implementation for ETMis object - * @param phi float - */ - protected void cutPhi(float phi) { - AParameter par = parameterStore.get("CutsATLAS", "CutPhi"); - boolean usePhiCut = par.getStatus(); - if (usePhiCut) { - double phiCut = Math.toRadians(Math.abs(par.getD())); - double phiMid = Math.toRadians( - AMath.nearestPhiDegrees(parameterStore.get("CutsATLAS", "PhiMiddle").getD())); - double phiDiff = Math.abs(AMath.nearestPhiRadians(phi, phiMid) - - phiMid); - - if (phiDiff - phiCut > 1.0e-6) { - numDraw = 0; - } - } - - } // cutPhi() ----------------------------------------------------------- - - /** - * eta cut implementation for ETMis object - * @param eta float - */ - protected void cutEta(float eta) { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - boolean useEtaCut = par.getStatus(); - if (useEtaCut) { - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaDiff = Math.abs(eta - etaMid); - if (etaDiff - etaCut > 1.0e-6) { - numDraw = 0; - } - } - - } // cutEta() ----------------------------------------------------------- -} // class AETMisData ======================================================= - diff --git a/graphics/AtlantisJava/src/atlantis/data/AElectronData.java b/graphics/AtlantisJava/src/atlantis/data/AElectronData.java deleted file mode 100755 index 29967a8fc34..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AElectronData.java +++ /dev/null @@ -1,180 +0,0 @@ -package atlantis.data; - -import java.util.Vector; -import atlantis.utils.A4Vector; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Reconstructed Electron - */ -public class AElectronData extends AHelixAODData -{ - private enum isEMe { TightPP, Tight, Medium, Loose, none } - - private int[] isEM; - private Vector<Enum> isEMEnum = new Vector<Enum>(); - private String[] label; - private float[] eOverp; - private int[] hasTrack; - - AElectronData(AHashMap p, AEvent e) - { - super(p,e); - isEM=p.getUnsureIntArray("isEM"); - String[] isEMString=p.getUnsureStringArray("isEMString"); - eOverp = p.getUnsureFloatArray("eOverp"); - hasTrack=p.getUnsureIntArray("hasTrack"); - label=p.getUnsureStringArray("label"); - - if(isEMString!=null) - { - for(String s : isEMString) - { - try { - isEMEnum.add(isEMe.valueOf(s)); - } - catch(IllegalArgumentException q) { - isEMEnum.add(isEMe.none); - } - } - } - else - { - for(int i=0;i<numData;i++) - { - isEMEnum.add(isEMe.none); - } - } - } - - public String getParameterGroup() - { - return "Electron"; - } - - public float geteOverp(int index) - { - return eOverp[index]; - } - - public String getisEMEnum(int index) - { - return isEMEnum.get(index).toString(); - } - - public int getisEM(int index) - { - return isEM[index]; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM((double)pT[k],(double)eta[k],(double)phi[k],0.00051); - sum.add(start); - } - - return sum; - } - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsObjects", "ElectronPt", " |ET|", pT); - - // because of the retriever bug, currently 2048 means 0 for isEM - // remove this for block when the bug is fixed - if(isEM != null) - { - for(int i=0; i<isEM.length; i++) - { - if(isEM[i]==2048) - isEM[i] = 0; - } - } - - cut("CutsObjects", "ElectronisEM", " isEM", isEM); - - if (parameterStore.get("CutsObjects", "ElectronisEMString").getStatus()) - { - int cutSub = parameterStore.get("CutsObjects", "ElectronisEMString").getI(); - - cutArrayEnum(isEMEnum, cutSub, "Electron isEMString"); - } - - cut("CutsObjects", "ElectroneOverp", " |eOverp|", eOverp); - if (parameterStore.get("CutsObjects", "ElectronhasTrack").getStatus() && hasTrack!=null) - cutArray(hasTrack, 1, "hasTrack"); - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - - if (isEM != null) - { - msg.append("\n isEM = "); - msg.append(isEM[index]); - } - if (label != null) - { - msg.append("\n label = "); - msg.append(label[index]); - } - if (eOverp != null) - { - msg.append("\n eOverp = "); - msg.append(eOverp[index]); - } - if (hasTrack != null) - { - msg.append("\n hasTrack = "); - msg.append(hasTrack[index]); - } - - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AEmTauROIData.java b/graphics/AtlantisJava/src/atlantis/data/AEmTauROIData.java deleted file mode 100755 index a2c8dc64699..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AEmTauROIData.java +++ /dev/null @@ -1,34 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.utils.AHashMap; - -/** - * - * Em Tau Region Of Interest - * - * @author Zdenek Maxa, Qiang Lu - */ -public class AEmTauROIData extends AROIData -{ - AEmTauROIData(AHashMap p, AEvent e) - { - super(p,e); - } // AEmTauROIData() ---------------------------------------------------- - - public String getParameterGroup() - { - return "EmTauROI"; - } - - public String getName() - { - return "EmTauROI"; - } - - public String getNameScreenName() - { - return "EmTauROI"; - } - -} // class AEmTauROIData ==================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/AEventFromXML.java b/graphics/AtlantisJava/src/atlantis/data/AEventFromXML.java deleted file mode 100755 index b89196931d3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AEventFromXML.java +++ /dev/null @@ -1,786 +0,0 @@ -package atlantis.data; - -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import atlantis.utils.xml.AArrayParser; -import atlantis.utils.xml.AFloatArrayParser; -import atlantis.utils.xml.AIntArrayParser; -import atlantis.utils.xml.AStringArrayParser; -import atlantis.utils.xml.AXMLErrorHandler; -import atlantis.utils.xml.AXMLErrorHandler.ErrorState; -import java.util.Iterator; -import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXNotRecognizedException; - - -/** - * The reader which is used to read XML Event Files. The reader function creates - * and returns an AEvent class. Event comes with tags which are arrays of - * numbers. These arrays are treated by xml as character strings. The conversion - * of the character strings to arrays of number is done here. - */ -public class AEventFromXML extends DefaultHandler { - - //the logger - private final static ALogger logger = ALogger.getLogger(AEventFromXML.class); - - // Create an instance of this object - this makes sure the constructor is called. - // FIXME: should not use constructor to initialize static state. - private static final AEventFromXML instance = new AEventFromXML(); - - //We also have our private error handler - private static final AXMLErrorHandler xmlErrorHandler = new AXMLErrorHandler(); - - //Parsing states at different XML levels - private enum ParseState { - WAITING_EVENT, - WAITING_DATA, - WAITING_ARRAY - } - private static ParseState parseState; - - //The XMLReader object - private static XMLReader xmlReader; - //The event that is being build - private static AEvent event = null; - //the source name - private static String sourceName = null; - - //non-static parsing data members - private AHashMap parameters = null; - private String currentDataName = null; - private String currentArrayName = null; - private String currentFullName = null; - private int arrayLength = 0; - private int currentArraySize = 0; - private String storeGateKey = null; - private AArrayParser arrayParser = null; - - private static boolean HLTIgnoredWarning = false; - - - /** - * Constructor - * Creates an instance of AEventFromXML. It just sets up the XML reading - * stuff but does not do any parsing of any XML file. - */ - private AEventFromXML() { - - try { - //setup all the xml reader stuff - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setValidating(true); - factory.setNamespaceAware(true); - xmlReader = factory.newSAXParser().getXMLReader(); - xmlReader.setErrorHandler(xmlErrorHandler); - xmlReader.setEntityResolver(this); - xmlReader.setContentHandler(this); - } catch (ParserConfigurationException pce){ - logger.error("Unable to initialize XML reader!", pce); - } catch (SAXException sxe){ - logger.error("Unable to initialize XML reader!", sxe); - } - } // AEventFromXML() ---------------------------------------------------- - - - /** - * Checks if there was an error. - * @return true or false - */ - private boolean hasError() { - return (xmlErrorHandler.getErrorState() != ErrorState.NO_ERROR); - } - - - /** - * Reads an XML event data (from files, from string converted to stream) and - * returns the coresponding AEvent object. - * - * @param eventInputStream the XML data input stream. - * @param sourceName the name of the event source that provided this data - * @return an AEvent object containing all the data found in the file. - * @throws ReadEventException - */ - public static AEvent read(InputStream eventInputStream, String sourceName) throws ReadEventException { - - //be verbose - logger.info("Parsing event from " + sourceName); - - //set the initial error state - xmlErrorHandler.setError(ErrorState.NO_ERROR,null); - - //store the source Name - AEventFromXML.sourceName = sourceName; - - //Try to parse input stream - try { - xmlReader.parse(new InputSource(eventInputStream)); - } catch (Exception e) { - //In case of an error repackage as ReadEventException - logger.error("Parsing exception " + e.getMessage(),e); - throw new ReadEventException("XML parsing exception", e); - } - - //Finally construct the full event (including associations, etc.) - //Check for runtime exceptions here in case we fail to finalize the event - try { - event.finalizeEvent(); - } catch (RuntimeException rte) { - //rethrow as can not read event exception - throw new ReadEventException("Inconsistent event data",rte); - } - - return event; - } - - /** - * DefaultHandler Implementation (have a look at - * org.xml.sax.helpers.DefaultHandler for more info) - */ - @Override - public void startDocument() { - - //if we are already in error state return immediately - if (hasError()) return; - - //Clean up all local variables - event = null; - parameters = null; - currentDataName = null; - currentArrayName = null; - currentFullName = null; - arrayLength = 0; - currentArraySize = 0; - storeGateKey = null; - arrayParser = null; - - //Set parse state to new event - parseState = ParseState.WAITING_EVENT; - - //be verbose - logger.debug("Start parsing document"); - - } // startDocument() ---------------------------------------------------- - - @Override - public void endDocument() { - - //if we are already in error state return immediatly - if (hasError()) return; - - //be verbose - logger.debug("Finished parsing document w/o error"); - - } - - /** - * Implementation of DefaultHandler: start a new xml element - * @param namespaceURI the namespace - * @param localName the local name - * @param qName the qualified name - * @param atts the default or specified attributes - */ - @Override - public void startElement(String namespaceURI, String localName, - String qName, Attributes atts) throws SAXException { - - //stop here if errors have occured before - if (hasError()) return; - - try { - //Now act depending on parse state - switch (parseState) { - - //Waiting for an event to begin - case WAITING_EVENT: - //Try to read in event data - if (localName.equals("Event")) { - - //Create a new event - event = new AEvent(atts.getValue("eventNumber"), - atts.getValue("runNumber"), - atts.getValue("dateTime"), - sourceName, - atts.getValue("lumiBlock"), - atts.getValue("eventProperty")); - - - //create a new data hashmap - parameters = new AHashMap(15); - - //Advance to next parsing state - parseState = ParseState.WAITING_DATA; - - } else { - //The Event tag does not seem to be the first tag in this event - logger.warn("Encountered tag "+localName+ " while waiting for <event/>!"); - } - //Done waiting for event - break; - - //Waiting for a data tag - case WAITING_DATA: - - //Store the current object name - currentDataName = localName; - //Get number of entries expected here - arrayLength = Integer.parseInt(atts.getValue("count")); - - // if storegate key doesn't exists as an attribute - // at datatype, an empty string "" is retrieved (not null) - storeGateKey = atts.getValue("storeGateKey"); - //Construct full name from datatype name and storeGateKey - currentFullName = currentDataName + "-" + storeGateKey; - - // ignore data with storeGateKey containing "HLTAutoKey" - // Its important that parseState is not set before, - // so we arrive waiting for a new data tag when this error is cleared - if (!AGlobals.instance().showHLTAutoKeys() && storeGateKey.indexOf("HLTAutoKey") >= 0) { - //Set appropiate error state and continue - xmlErrorHandler.setError(ErrorState.IGNORED_DATA, new Exception("Ignored HLTAutoKey data "+currentFullName)); - return; - } - - parameters.clear(); - // add numData - number of data within the subtags, - // extracted from count attribute - parameters.put("numData", new Integer(arrayLength)); - parameters.put("storeGateKey", storeGateKey); - parseState = ParseState.WAITING_ARRAY; - break; - - //Waiting for an data value array - case WAITING_ARRAY: - - //store name of the array we are looking at - currentArrayName = localName; - - if ((atts.getValue("type") == null) || - (atts.getValue("multiple") == null)) - throw new SAXNotRecognizedException("No array type or multiplicity available for "+localName); - - String type = atts.getValue("type"); - - //get multiplicity if needed - float multiple = Float.parseFloat(atts.getValue("multiple")); - currentArraySize = Math.round(arrayLength * multiple); - - - //Instanciate a new array parser - if (type.equals("FLOAT")) { - arrayParser = new AFloatArrayParser(currentArraySize); - } else if (type.equals("INT")) { - arrayParser = new AIntArrayParser(currentArraySize); - } else if (type.equals("STRING")) { - arrayParser = new AStringArrayParser(currentArraySize); - } else { - throw new SAXNotRecognizedException("Invalid array type: " + type); - } - - break; - - } // switch - } catch (SAXNotRecognizedException sre){ - //Catch unknown array tags - xmlErrorHandler.setError(ErrorState.INVALID_DATA,sre); - logger.debug("Encountered invalid subtag "+localName, sre); - } catch (Exception e) { - //Catch any other error here: - String msg = "Error reading file at " + currentFullName + ":" + currentArrayName; - xmlErrorHandler.setError(ErrorState.FATAL_ERROR,e); - logger.debug(msg, e); - //Rethrow readevent exception with proper cause - throw new SAXException(msg, e); - } - - } - - /** - * Called at the end of each tag - this is where we actually construct the data - * @param namespaceURI - the current namespace - * @param localName - the local element name - * @param qName - the qualified element name - */ - @Override - public void endElement(String namespaceURI, String localName, String qName) throws SAXException { - - /** - * Check if an error had occured reading this element - */ - if (hasError()) { - - String msg = null; - - switch (xmlErrorHandler.getErrorState()) { - - case UNKNOWN_TAG: - //Ignore unknown tags, but show an error - - if (parseState == ParseState.WAITING_DATA) - msg = "Unknown or obsolete data type <" + currentDataName + "> found"; - else if (parseState == ParseState.WAITING_ARRAY) - //rely on exception error message for this one - msg = xmlErrorHandler.getErrorCause().getMessage(); - else - //unknown tag at event level - msg = "Unknown tag <" + currentDataName + "> while waiting for event."; - - //Clear the error state and continue - xmlErrorHandler.setError(ErrorState.NO_ERROR, null); - break; - - case INVALID_DATA: - msg = "Invalid data encountered reading "+currentDataName; - //Clear the error state and continue - xmlErrorHandler.setError(ErrorState.NO_ERROR, null); - break; - - case IGNORED_DATA: - - //Only show warning message in the LogPane once - if (!HLTIgnoredWarning) { - AOutput.append("\"HLTAutoKey\" data is hidden, option '-a' to see them.", - ALogInterface.WARNING); - //tell about each one also in the log - logger.warn(xmlErrorHandler.getErrorCause().getMessage()); - HLTIgnoredWarning = true; - } - - //Clear the error only when we reach the end of the data tag - if (localName.equals(currentDataName)) - xmlErrorHandler.setError(ErrorState.NO_ERROR, null); - - break; - } - - //If there was a message, show it - if (msg != null){ - // Now show this error in the log pane and console output - logger.warn(msg,xmlErrorHandler.getErrorCause()); - } - //Return to parsing (if error cleared) or stop - return; - } - - /** - * No error so far - check what we have been parsing - */ - switch (parseState) { - - case WAITING_ARRAY: - - /** - * End of data array - add to parameter list - */ - if (localName.equals(currentArrayName)) { - - //Check for proper Array size - if (arrayParser.getCount() != currentArraySize) { - - xmlErrorHandler.setError(ErrorState.INVALID_DATA, new Exception("Invalid array size")); - - String msg = "The number of data in <" + currentFullName + ">-<" + currentArrayName + "> is different than declared"; - logger.error(msg); - AOutput.append("\n"+msg+"\n", ALogInterface.WARNING); - return; - } - //Otherwise add to parameter list - parameters.put(currentArrayName, arrayParser.getArray()); - - //done with that, return - return; - } - - /** - * End of data tag - construct object - */ - if (localName.equals(currentDataName)) { - try { - // Calo and muon datatypes sometimes provide a - // storeGateKey, thus are (incorrectly !) - // regarded as multiple collection datatypes - // -> remove this storeGateKey - if ("TILE".equals(currentDataName) || - "LAr".equals(currentDataName) || - "HEC".equals(currentDataName) || - "FCAL".equals(currentDataName) || - "MBTS".equals(currentDataName) || - "MDT".equals(currentDataName) || - "CSC".equals(currentDataName) || - "RPC".equals(currentDataName) || - "TGC".equals(currentDataName)) { - parameters.put("storeGateKey", null); - } - - // RDOs originally implemented as multiple collections, - // then changed to non-mul-col. this is for backwards - // compatibility with events where storeGateKey is - // provided for PixelRDO and SCTRDO - if ("PixelRDO".equals(currentDataName) || - "SCTRDO".equals(currentDataName)) { - parameters.put("storeGateKey", null); - } - - checkPhiRange(parameters, currentFullName); - - if (currentDataName.equals("STr")) { - event.add(new ASVxData(ASVxData.createSVx(parameters), event)); - event.add(new ASTrData(ASTrData.createSTr(parameters), event)); - event.add(new ASNPData(ASNPData.createSNP(parameters), event)); - } // STC - silicon cluster datatype - else if (currentDataName.equals("STC")) { - event.add(new ASiClusterData(parameters, event)); - } // SCTRDO - silicon cluster raw data object - // discrepancy in naming STC x SCT ... - else if (currentDataName.equals("SCTRDO")) { - event.add(new ASiClusterRDOData(parameters, event)); - } // PixCluster - pixel cluster datatype - else if (currentDataName.equals("PixCluster")) { - event.add(new APixelClusterData(parameters, event)); - } - // ETMis backwards compatibility (after ETMis collections) - // datatypes ETMis, CaloETMis, MuonETMis - storeGateKey - // attribute is added here - else if (currentDataName.equals("ETMis") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "ETMis"); - event.add(new AETMisData(parameters, event)); - } else if (currentDataName.equals("CaloETMis")) { - parameters.put("storeGateKey", "CaloETMis"); - event.add(new AETMisData(parameters, event)); - } else if (currentDataName.equals("MuonETMis")) { - parameters.put("storeGateKey", "MuonETMis"); - event.add(new AETMisData(parameters, event)); - } // Track collections, backwards compatibility for - // IDScan, iPat, xKal datatypes - storeGateKey attribute - // is added here - else if (currentDataName.equals("Track")) { - - String key = (String) parameters.get("storeGateKey"); - if (key != null) { - if (key.toLowerCase().indexOf("mboy") >= 0 || key.toLowerCase().indexOf("mugirl") >=0 || key.toLowerCase().indexOf("moore") >= 0 || key.toLowerCase().indexOf("momu") >= 0 || key.toLowerCase().indexOf("muon") >= 0 || key.toLowerCase().indexOf("staco") >= 0 || key.toLowerCase().indexOf("muid") >= 0 || key.toLowerCase().indexOf("mutag") >= 0 ) { - event.add(new AMuonTrackData(parameters, event)); - } else { - event.add(new AInDetTrackData(parameters, event)); - } - } else { - int[] trackAuthor = parameters.getUnsureIntArray("trackAuthor"); - if (trackAuthor != null && trackAuthor.length > 0) { - if ((trackAuthor[0] >= 7 && trackAuthor[0] <= 9) || (trackAuthor[0] >= 13 && trackAuthor[0] <= 17)) { - event.add(new AMuonTrackData(parameters, event)); - } else { - event.add(new AInDetTrackData(parameters, event)); - } - } else { - event.add(new AInDetTrackData(parameters, event)); - } - } - } else if (currentDataName.equals("IDScan")) { - parameters.put("storeGateKey", "TrigInDetTrack"); - event.add(new AInDetTrackData(parameters, event)); - } else if (currentDataName.equals("iPat")) { - parameters.put("storeGateKey", "iPatTrack"); - event.add(new AInDetTrackData(parameters, event)); - } else if (currentDataName.equals("xKal")) { - parameters.put("storeGateKey", "xKalTrack"); - event.add(new AInDetTrackData(parameters, event)); - } else if (currentDataName.equals("RTr")) // old tag - { - parameters.put("storeGateKey", "RTrTrack"); - event.add(new AInDetTrackData(parameters, event)); - } else if (currentDataName.equals("RMTr")) // old tag - { - parameters.put("storeGateKey", "RMTrTrack"); - event.add(new AMuonTrackData(parameters, event)); - } // ParticleJet backwards compatibility - else if (currentDataName.equals("ParticleJet") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "ParticleJet cone4"); - // treat PatricleJet as Jet (JetRecJet) - event.add(new AJetData(parameters, event)); - } else if (currentDataName.equals("Jet") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "JetRecJet"); - event.add(new AJetData(parameters, event)); - } // MSeg backwards compatibility - else if (currentDataName.equals("MSeg")) { - parameters.put("storeGateKey", "MooreSegment"); - - // Instead of cotan(theta) we store theta itself. - float[] cotTheta = parameters.getFloatArray("cotTheta"); - float[] theta = new float[cotTheta.length]; - for (int i = 0; i < cotTheta.length; i++) { - theta[i] = (float) Math.atan(1. / cotTheta[i]); - } - parameters.put("theta", theta); - - // And phi0 is now called phi - parameters.put("phi", parameters.getFloatArray("phi0")); - - event.add(new AMuonSegmentData(parameters, event)); - } // Segment backwards compatibility - else if (currentDataName.equals("Segment")) { - String key = (String) parameters.get("storeGateKey"); - if (key != null) { - if (key.toLowerCase().indexOf("mboy") >= 0 || key.toLowerCase().indexOf("moore") >= 0 || key.toLowerCase().indexOf("momu") >= 0 || key.toLowerCase().indexOf("mdt") >= 0 || key.toLowerCase().indexOf("muon") >= 0) { - event.add(new AMuonSegmentData(parameters, event)); - } else { - event.add(new AInDetSegmentData(parameters, event)); - } - } - } // Cluster backwards compatibility - // datatypes Cluster - storeGateKey attribute is added - else if (currentDataName.equals("Cluster") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "DefaultCluster"); - event.add(new AClusterData(parameters, event)); - } //Electron backwards compatibility - else if (currentDataName.equals("Electron") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "ElectronCollection"); - event.add(new AElectronData(parameters, event)); - } //Muon backwards compatibility - else if (currentDataName.equals("Muon") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "MuonCollection"); - event.add(new AMuonData(parameters, event)); - } //Photon backwards compatibility - else if (currentDataName.equals("Photon") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "PhotonCollection"); - event.add(new APhotonData(parameters, event)); - } //BJet backwards compatibility - else if (currentDataName.equals("BJet") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "BJetCollection"); - event.add(new ABJetData(parameters, event)); - } //TauJet backwards compatibility - else if (currentDataName.equals("TauJet") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "TauJetCollection"); - event.add(new ATauJetData(parameters, event)); - } //CompositeParticle backwards compatibility - else if (currentDataName.equals("CompositeParticle") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "CompositeParticleCollection"); - event.add(new ACompositeParticleData(parameters, event)); - } //LVL1Result backwards compatibility - else if (currentDataName.equals("LVL1Result") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "LVL1Result"); - event.add(new ALVL1ResultData(parameters, event)); - } //LVL1TriggerTower backwards compatibility - else if (currentDataName.equals("LVL1TriggerTower") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "LVL1TriggerTower"); - event.add(new ALVL1TriggerTowerData(parameters, event)); - } //LVL1JetElement backwards compatibility - else if (currentDataName.equals("LVL1JetElement") && - "".equals(storeGateKey)) { - parameters.put("storeGateKey", "LVL1JetElement"); - event.add(new ALVL1JetElementData(parameters, event)); - } else { - //try to autoconstruct the corresponding data type - //First of all get all constructors for this class name - Constructor[] cons = Class.forName("atlantis.data.A" + currentDataName + "Data").getDeclaredConstructors(); - //Flag if we found on - boolean foundConstructor = false; - //Now loop over constructors and pick the one that fits - for (Constructor constructor : cons) { - //Check for parameters - Class[] params = constructor.getParameterTypes(); - if (params.length != 2) { - continue; - //Check both types - } - if (!params[0].getName().endsWith("AHashMap")) { - continue; - } - if (!params[1].getName().endsWith("AEvent")) { - continue; - //seems we found the proper constructor - go and build the class - } - foundConstructor = true; - event.add((AData) constructor.newInstance(new Object[]{parameters, event})); - //also end the loop here - break; - } - if (!foundConstructor) { - throw new ClassNotFoundException("Found no valid constructor for data type " + currentDataName); - } - } // End of autoconstructor - - - //Collect all possible errors here - } catch (Throwable t) { - //Will hold the error message - String msg = null; - - //Could not find a class for this data type - if (t instanceof ClassNotFoundException) { - msg = "Class handling the type " + currentDataName + " not found"; - xmlErrorHandler.setError(ErrorState.INVALID_DATA, t); - //Ran out ouf memory - } else if (t instanceof OutOfMemoryError) { - msg = "Atlantis ran out of memory while\n" + "reading in event data"; - xmlErrorHandler.setError(ErrorState.FATAL_ERROR, t); - //Some weird Atlantis exception - check its error state - } else if (t instanceof AAtlantisException) { - msg = t.getMessage(); - //check Atlantis exception level - if (((AAtlantisException)t).isFatal()) - xmlErrorHandler.setError(ErrorState.FATAL_ERROR, t); - else - xmlErrorHandler.setError(ErrorState.OTHER_ERROR, t); - } else if (t instanceof InvocationTargetException) { - msg = "Error when constructing " + currentFullName; - xmlErrorHandler.setError(ErrorState.OTHER_ERROR, t); - } else { - msg = "Caught exception "+t.toString()+ " while constructing "+currentFullName; - xmlErrorHandler.setError(ErrorState.OTHER_ERROR, t); - } - - AOutput.append("\n" + msg + "\n", ALogInterface.WARNING); - logger.error(msg, t); - } - - /** - * Now handle potential errors - */ - //if we can proceed processing, throw an error - if (xmlErrorHandler.getErrorState() == ErrorState.FATAL_ERROR) - throw new SAXException("Error parsing event at tag <"+currentDataName+">", - (Exception)xmlErrorHandler.getErrorCause()); - - //Otherwise clear error state and continue - xmlErrorHandler.setError(ErrorState.NO_ERROR, null); - parseState = ParseState.WAITING_DATA; - return; - } - - } - } - - /** - * xml calls this routine whenever it finds CONTENT of type character array - * (CDATA) this routine fills an array stored in the arrayParser * - * - * @param ch char[] - * @param start int - * @param length int - */ - @Override - public void characters(char[] ch, int start, int length) { - - //return immediately if we had an error before - if (hasError()) return; - - //Make sure an arrayParser has been set before - if (arrayParser == null){ - xmlErrorHandler.setError(ErrorState.FATAL_ERROR,new NullPointerException("ArrayParser object not defined")); - logger.error("arrayParser is NULL in SAX DefaultHandler:characters"); - return; - } - - //try to parse the value array - try { - arrayParser.parse(ch, start, length); - } catch (NumberFormatException nfe) { - xmlErrorHandler.setError(ErrorState.INVALID_DATA,nfe); - String msg = "Data in <" + currentFullName + ">-<" + currentArrayName + - "> contains invalid character \'" + nfe.getMessage() + "\'"; - logger.error(msg); - - } catch (IndexOutOfBoundsException oob) { - xmlErrorHandler.setError(ErrorState.INVALID_DATA,oob); - String msg = "The number of data in <" + currentFullName + ">-<" - + currentArrayName + "> is more than declared"; - logger.error(msg); - } - - } // characters() -------------------------------------------------------- - - /** - * Returns an entity resolver - should be event.dtd in case we read an event file - * otherwise return null to use the default - * @param publicId - * @param systemId - * @return an input source for the entity resolver - */ - @Override - public InputSource resolveEntity(String publicId, String systemId) { - InputSource inputSource = null; - String FILE_SEPAR = System.getProperty("file.separator"); - - if (systemId.endsWith("event.dtd")) { - String dtdFile = AGlobals.instance().getHomeDirectory() + "events" + FILE_SEPAR + "event.dtd"; - try { - InputStream is = AUtilities.getFileAsStream(dtdFile); - inputSource = new InputSource(is); - } catch (AAtlantisException ae) { - logger.error("reading " + dtdFile + " error: " + ae.getMessage(), ae); - } - } - - return inputSource; - - } // resolveEntity() ---------------------------------------------------- - - /** - * Corrects the Phi values to be in the range (0:2pi). - * NOTE: This can still be done much nicer - but have you seen what it looked like before?! - * @param p The AHashMap containing the float arrays to be checked. - */ - private static void checkPhiRange(AHashMap p, String fullDataName) { - - //Loop over all keys in the Hashmap - Iterator keyIter = p.keySet().iterator(); - while (keyIter.hasNext()) { - //Check if this is a phi collection - String keyName = (String) keyIter.next(); - //Only run on phi value arrays - if (!keyName.startsWith("phi")) { - continue; - //Now get the actual array of values - } - float[] phi = null; - try { - phi = (float[]) p.get(keyName); - } catch (ClassCastException cce) { - //ignore any non-floar arrays that start with "phi" - continue; - } - //Check that we didn't get an empty entry - if (phi == null) { - continue; //Now loop over all entries and correct them - } - for (int i = 0; i < phi.length; i++) { - //Bring it down to the modulus of 2*Pi - phi[i] = phi[i] % (float)AMath.TWO_PI; - //Smaller zero is still possible - if (phi[i] < 0.) phi[i] += AMath.TWO_PI; - } - } - } // checkPhiRange() ----------------------------------------------------- -} // class AEventFromXML ==================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/AFCALData.java b/graphics/AtlantisJava/src/atlantis/data/AFCALData.java deleted file mode 100755 index 9e8d233d12e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AFCALData.java +++ /dev/null @@ -1,1228 +0,0 @@ -package atlantis.data; - -import atlantis.canvas.ACanvas; -import atlantis.event.AEvent; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.utils.AUtilities; -import atlantis.utils.ALogger; -import java.io.IOException; -import com.Ostermiller.util.CSVParser; -import java.io.StringReader; -import java.io.InputStream; -import java.io.FileNotFoundException; - -/** - * The Forward calorimeter implementation. - * - * @author Eric Jansen - */ -public class AFCALData extends ACalorimeterData -{ - private static ALogger logger = ALogger.getLogger(AFCALData.class); - - protected float[] x; - protected float[] y; - protected float[] z; - protected float[] r; - protected float[] dx; - protected float[] dy; - protected float[] dz; - protected float[] dr; - - private int[][] cellTable; - - // data for real pulse shapes plots - private int numSamplings = 0; - private int[][] adcCounts = null; - private float[] cellTime = null; - private int[] cellGain = null; - private float[] cellPedestal = null; - private float[] adc2Mev = null; - private static boolean pulseShapesDataAvailable = false; - private static final String LOOKUP_TABLE_FILE = - AGlobals.instance().getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - "rpsplt_fcal.csv"; - // number of lookup table values for real pulse shapes plots calculation - private static final short NUMBER_OF_LOOKUP_VALUES = 600; - - - - AFCALData(AHashMap p, AEvent e) - { - super(p,e); - - x = p.getFloatArray("x"); - dx = p.getFloatArray("dx"); - y = p.getFloatArray("y"); - dy = p.getFloatArray("dy"); - - r = new float[numData]; - dr = new float[numData]; - - cellTable = new int[MAX_HIT_INDEX][MAX_HIT_INDEX]; - - for (int i = 0; i < numData; i++) - { - try - { - side[i] = (byte) AIdHelper.larBarrelEndcap(id[i]); - etaIndex[i] = (short) AIdHelper.larEta(id[i]); - phiIndex[i] = (short) AIdHelper.larPhi(id[i]); - sampling[i] = 0; //AIdHelper.larSampling(id[i]); - } - catch (AAtlantisException ex) - { - logger.error("Problem decoding ID " + id[i] + " in " + - CALORIMETER_NAME + ": " + ex.getMessage()); - side[i] = 0; - etaIndex[i] = -1; - phiIndex[i] = -1; - sampling[i] = -1; - } - } - - // Events produced by older JiveXML versions don't have z and dz yet. - // Use the old hardcoded values in that case for backwards - // compatibility. - if (p.get("z") == null || p.get("dz") == null) - { - z = new float[numData]; - dz = new float[numData]; - for (int i = 0; i < numData; i++) - { - switch (sampling[i]) - { - case 0: - z[i] = (side[i] / Math.abs(side[i])) * 489.4f; - dz[i] = 45.2f; - break; - case 1: - z[i] = (side[i] / Math.abs(side[i])) * 534.8f; - dz[i] = 45.0f; - break; - case 2: - z[i] = (side[i] / Math.abs(side[i])) * 582.2f; - dz[i] = 45.0f; - break; - } - } - } - else - { - z = p.getFloatArray("z"); - dz = p.getFloatArray("dz"); - } - - float drMin = 0.0f, zMin = 0.0f, zMax = 0.0f, rMin = 0.0f, rMax = 0.0f; - for (int i = 0; i < numData; i++) - { - - if (side[i] < 0) - { - sub[i] = 0; - } - else - { - sub[i] = 1; - } - - float etaMin = (float) AMath.etaAbs(z[i], Math.sqrt(Math.pow(Math.abs(x[i]) - dx[i], 2) + - Math.pow(Math.abs(y[i]) - dy[i], 2))); - float etaMax = (float) AMath.etaAbs(z[i], Math.sqrt(Math.pow(Math.abs(x[i]) + dx[i], 2) + - Math.pow(Math.abs(y[i]) + dy[i], 2))); - eta[i] = (etaMin + etaMax) / 2.f; - //TODO check calculation original: deta[i] = etaMax - etaMin; - deta[i] = Math.abs(etaMax - etaMin); - phi[i] = (float) Math.atan2(y[i], x[i]); - dphi[i] = (float) Math.abs(Math.atan2(y[i] + dy[i], x[i] - dx[i]) - - Math.atan2(y[i] - dy[i], x[i] + dx[i])); - if (phi[i] < 0) - { - phi[i] += 2. * Math.PI; - } - - r[i] = (float) Math.sqrt(x[i] * x[i] + y[i] * y[i]); - dr[i] = (float) Math.sqrt(dx[i] * dx[i] + dy[i] * dy[i]); - - // Collect some constants needed for binning the histograms. - if (rMin == 0.0 || Math.abs(r[i]) - dr[i] / 2. < rMin) - { - rMin = Math.abs(r[i]) - dr[i] / 2.f; - } - if (rMax == 0.0 || Math.abs(r[i]) + dr[i] / 2. > rMax) - { - rMax = Math.abs(r[i]) + dr[i] / 2.f; - } - if (zMax == 0.0 || Math.abs(z[i]) + dz[i] / 2. > zMax) - { - zMax = Math.abs(z[i]) + dz[i] / 2.f; - } - if (zMin == 0.0 || Math.abs(z[i]) - dz[i] / 2. < zMin) - { - zMin = Math.abs(z[i]) - dz[i] / 2.f; - } - if (drMin == 0.0 || dr[i] < drMin) - { - drMin = dr[i]; - } - } - - etaGranularity = AParameterUtilities.eta(zMin, rMax - drMin) - AParameterUtilities.eta(zMin, rMax); - outerEta = AParameterUtilities.eta(zMax, rMin); - - // Collect some constants needed for drawing the histograms. - for (int i = 0; i < ACalorimeterDetector.count(); i++) - { - if (outerR == 0.0 || ACalorimeterDetector.get(i).getRMax() > outerR) - { - outerR = ACalorimeterDetector.get(i).getRMax(); - } - if (outerZ == 0.0 || ACalorimeterDetector.get(i).getZMax() > outerZ) - { - outerZ = ACalorimeterDetector.get(i).getZMax(); - } - } - - for (int i = 0; i < et.length; ++i) - { - et[i] = Math.abs(energy[i] / (float) Math.cosh(eta[i])); - } - - // read in FCAL data from real pulse shapes plots - readPulseShapePlotData(p); - - } - - - - /** - * readLookupTableFile() reads in comma separated values (CSV) file - * with FCAL real pulse shapes plots time and amplitude lookup values - * @param fileName String - * @throws AAtlantisException - */ - private void readLookupTableFile() throws AAtlantisException - { - try - { - InputStream is = AUtilities.getFileAsStream(LOOKUP_TABLE_FILE); - CSVParser parser = new CSVParser(is); - parser.setCommentStart("#"); - String arrayName = null; - - while((arrayName = parser.nextValue()) != null) - { - String valueArray = parser.nextValue(); // shall now contain all values - CSVParser parserArray = new CSVParser(new StringReader(valueArray)); - String[][] s = parserArray.getAllValues(); - - if("FCAL_LAYER0_AMPLITUDE".equals(arrayName)) - { - ACalorimeterRPSPLT.FCAL_LAYER0_AMPLITUDE = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - else if("FCAL_LAYER1_AMPLITUDE".equals(arrayName)) - { - ACalorimeterRPSPLT.FCAL_LAYER1_AMPLITUDE = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - else if("FCAL_LAYER2_AMPLITUDE".equals(arrayName)) - { - ACalorimeterRPSPLT.FCAL_LAYER2_AMPLITUDE = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - else if("FCAL_TIME".equals(arrayName)) - { - ACalorimeterRPSPLT.FCAL_TIME = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - } // while - } - catch(FileNotFoundException e) - { - throw new AAtlantisException("could not find file: " + - LOOKUP_TABLE_FILE); - } - catch(IOException e) - { - throw new AAtlantisException("exception while reading file: " + - LOOKUP_TABLE_FILE); - } - catch(AAtlantisException e) - { - throw e; - } - - } // readLookupTableFile() ---------------------------------------------- - - - - private void readPulseShapePlotData(AHashMap p) - { - // read ADCCounts and cell data for real pulse shapes plots - adcCounts = super.getADCCountsData(p); - - // read LAr digits (cell data) for real pulse shapes plots - cellTime = (p.get("cellTime") != null) ? p.getFloatArray("cellTime") : null; - cellGain = (p.get("cellGain") != null) ? p.getIntArray("cellGain") : null; - cellPedestal = (p.get("cellPedestal") != null) ? p.getFloatArray("cellPedestal") : null; - adc2Mev = (p.get("adc2Mev") != null) ? p.getFloatArray("adc2Mev") : null; - - pulseShapesDataAvailable = false; - if(adcCounts != null && cellTime != null && cellGain != null && - cellPedestal != null && adc2Mev != null) - { - pulseShapesDataAvailable = true; - numSamplings = adcCounts[0].length; - - logger.debug(CALORIMETER_NAME + - ": data for real pulse shape plots available"); - - - if(ACalorimeterRPSPLT.areFCALLookupTablesInitialized()) - { - logger.debug(CALORIMETER_NAME + - ": lookup tables have already been read in"); - } - else - { - logger.debug(CALORIMETER_NAME + - ": lookup table values have not been read in yet\n" + - " trying to read file: " + LOOKUP_TABLE_FILE); - try - { - readLookupTableFile(); - - logger.debug(CALORIMETER_NAME + - ": values from " + LOOKUP_TABLE_FILE + - " successfully read in"); - - } - catch(AAtlantisException ex) - { - logger.debug(CALORIMETER_NAME + - ": reading " + LOOKUP_TABLE_FILE + - " failed, real pulse shapes plots will not " + - "be available, reason: " + ex.getMessage(), ex); - pulseShapesDataAvailable = false; - } - } - } - - } // readPulseShapePlotData() ------------------------------------------- - - - - - /** - * Returns the name of the parameter group. - * - * @return String parameter group - */ - public String getParameterGroup() - { - return "FCAL"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getName() - { - return "FCAL"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getNameScreenName() - { - return "FCAL"; - } - - /** - * Returns the type of calorimeter (ECAL/HCAL) for a hit. - * - * @param index int hit index - * @return String calorimeter type - */ - public String getCalorimeterType(int index) - { - if (sampling[index] == 0) - { - return "ECAL"; - } - else - { - return "HCAL"; - } - } - - /** - * Calorimeter cells can be drawn either explicitly or implicitly. In most - * views cells that are located behind eachother are consolidated and only - * the most energetic one is drawn explicitly. The other cells are drawn - * implicitly, since their energy value is still added to the energy sum of - * the explicitly drawn cell. The list manager does not know about the - * implicitly drawn cells though, so this poses a problem when the user - * requests information about a certain area of the canvas. This is solved - * using this method. This function receives the list of explicitly drawn - * cells and then adds the ones that were implicitly drawn in this - * selection. - * - * @param drawn boolean[] initial drawn list containing only the explicitly - * drawn cells - * @return boolean[] drawn list containing the explicitly and the implicitly - * drawn cells. - */ - public boolean[] expandDrawn(boolean[] drawn) - { - AProjection projection = ACanvas.getCanvas().getCurrentWindow().getProjection(); - - if (projection instanceof AProjectionYX) - { - return expandDrawnYX(drawn); - } - else if (projection instanceof AProjectionRZ) - { - return expandDrawnRZ(drawn); - } - else - { - return drawn; - } - } - - /** - * Filters the drawList for the y-x projection. Hits from both endcaps are - * combined. - */ - protected void filterDrawListYX() - { - float etTable[][] = new float[MAX_HIT_INDEX][MAX_HIT_INDEX]; - for (int i = 0; i < MAX_HIT_INDEX; i++) - { - for (int j = 0; j < MAX_HIT_INDEX; j++) - { - cellTable[i][j] = -1; - etTable[i][j] = 0.0f; - } - } - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - int eta = etaIndex[j]; - int phi = phiIndex[j]; - etTable[eta][phi] += et[j]; - if (cellTable[eta][phi] < 0 || et[cellTable[eta][phi]] < et[j]) - cellTable[eta][phi] = j; - } - - numDraw = 0; - for (int i = 0; i < MAX_HIT_INDEX; i++) - { - for (int j = 0; j < MAX_HIT_INDEX; j++) - { - if (cellTable[i][j] > 0) - { - listdl[numDraw] = cellTable[i][j]; - etSum[listdl[numDraw]] = etTable[i][j]; - numDraw++; - } - } - } - } - - /** - * See expandDrawn. - * - * @param drawn boolean[] initial drawn list containing only the explicitly - * drawn cells - * @return boolean[] drawn list containing the explicitly and the implicitly - * drawn cells. - */ - private boolean[] expandDrawnYX(boolean[] drawn) - { - makeDrawList(); - - int mode = parameterStore.get("YX", "Mode").getI(); - if (parameterStore.get("YX", "DrawFCAL").getStatus() && mode >= AProjectionYX.MODE_HEC_2 && - mode <= AProjectionYX.MODE_HEC_4) - { - cutArray(sampling, mode - AProjectionYX.MODE_HEC_2, "Layer"); - } - else if (mode >= AProjectionYX.MODE_FCAL_EM || mode <= AProjectionYX.MODE_FCAL_HAD_2) - { - cutArray(sampling, mode - AProjectionYX.MODE_FCAL_EM, "Layer"); - } - else - { - return drawn; - } - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - - if (drawn[j]) - continue; - - int eta = etaIndex[j]; - int phi = phiIndex[j]; - - if (eta >= 0 && phi >= 0) - { - int mappedTo = cellTable[eta][phi]; - - if (mappedTo >= 0 && drawn[mappedTo] == true) - { - drawn[j] = true; - } - } - } - - return drawn; - } - - /** - * The rho-z projection is a bit difficult for FCAL. Because of the y-x - * geometry of the cells there isn't really a nice way to project them in - * rho-z. This prodedure takes the most energetic cell and the consolidates - * it with all cells that overlap it. This is repeated until all cells are - * assigned to such a most energetic cell. We are then left with a series of - * "important" cells that do not overlap in rho-z. These can be drawn - * nicely. - */ - protected void filterDrawListRZ() - { - boolean available[] = new boolean[numDraw]; - int numCells = numDraw; - int newNumDraw = 0; - - // Initialize the variables. - for (int i = 0; i < numDraw; i++) - { - available[i] = true; - } - for (int i = 0; i < numData; i++) - { - etSum[i] = 0.0f; - } - - while (numCells > 0) - { - - // Loop through all available cells and find the highest energy. - int max = -1; - for (int i = 0; i < numDraw; i++) - { - if (available[i]) - { - if (max < 0 || et[listdl[i]] > et[listdl[max]]) - max = i; - } - } - - // This is a cell we want to draw, store it and remove it from the - // available cells list. - available[max] = false; - numCells--; - listdl[newNumDraw++] = listdl[max]; - - // Now find all available cells that overlap this one. This loop - // will be processed - // quite a lot, so it is very important to do the "easy" rejects - // first. - for (int i = 0; i < numDraw; i++) - { - if (available[i]) - { - int j = listdl[i]; - - double zDist = Math.abs(z[j] - z[listdl[max]]); - if (zDist >= (dz[j] + dz[listdl[max]]) / 2.) - continue; - - double rDist = Math.abs(r[j] - r[listdl[max]]); - if (rDist >= (dr[j] + dr[listdl[max]]) / 2.) - continue; - - if (AParameterUtilities.getRhoSign(x[j], y[j]) != AParameterUtilities.getRhoSign(x[listdl[max]], y[listdl[max]])) - continue; - - available[i] = false; - etSum[listdl[max]] += et[j]; - numCells--; - } - } - } - - numDraw = newNumDraw; - } - - /** - * See expandDrawn. - * - * @param drawn boolean[] initial drawn list containing only the explicitly - * drawn cells - * @return boolean[] drawn list containing the explicitly and the implicitly - * drawn cells. - */ - private boolean[] expandDrawnRZ(boolean[] drawn) - { - makeDrawList(); - - boolean available[] = new boolean[numDraw]; - int numCells = numDraw; - - // Initialize the variables. - for (int i = 0; i < numDraw; i++) - { - available[i] = true; - } - - while (numCells > 0) - { - - // Loop through all available cells and find the highest energy. - int max = -1; - for (int i = 0; i < numDraw; i++) - { - if (available[i]) - { - if (max < 0 || et[listdl[i]] > et[listdl[max]]) - max = i; - } - } - - // This is a cell we want to draw, store it and remove it from the - // available cells list. - available[max] = false; - numCells--; - - // Now find all available cells that overlap this one. This loop - // will be processed - // quite a lot, so it is very important to do the "easy" rejects - // first. - for (int i = 0; i < numDraw; i++) - { - if (available[i]) - { - int j = listdl[i]; - - double zDist = Math.abs(z[j] - z[listdl[max]]); - if (zDist >= (dz[j] + dz[listdl[max]]) / 2.) - continue; - - double rDist = Math.abs(r[j] - r[listdl[max]]); - if (rDist >= (dr[j] + dr[listdl[max]]) / 2.) - continue; - - if (AParameterUtilities.getRhoSign(x[j], y[j]) != AParameterUtilities.getRhoSign(x[listdl[max]], y[listdl[max]])) - continue; - - available[i] = false; - if (drawn[listdl[max]]) - drawn[j] = true; - numCells--; - } - } - } - - return drawn; - } - - /** - * Draws the FCAL data in the y-x projection. - * - * @return ACoord cell geometry polygons - */ - protected ACoord getYXUser() - { - makeDrawList(); - - int mode = parameterStore.get("YX", "Mode").getI(); - if (parameterStore.get("YX", "DrawFCAL").getStatus() && mode >= AProjectionYX.MODE_HEC_2 && - mode <= AProjectionYX.MODE_HEC_4) - { - cutArray(sampling, mode - AProjectionYX.MODE_HEC_2, "Layer"); - } - else if (mode >= AProjectionYX.MODE_FCAL_EM || mode <= AProjectionYX.MODE_FCAL_HAD_2) - { - cutArray(sampling, mode - AProjectionYX.MODE_FCAL_EM, "Layer"); - } - else - { - return ACoord.NO_DATA; - } - - filterDrawListYX(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - double xMin = x[j] - dx[j] / 2.; - double xMax = x[j] + dx[j] / 2.; - double yMin = y[j] - dy[j] / 2.; - double yMax = y[j] + dy[j] / 2.; - - hv[0][i] = new double[] { xMax, xMin, xMin, xMax }; - hv[1][i] = new double[] { yMax, yMax, yMin, yMin }; - - index[i] = j; - } - - return new ACoord(hv, index, this); - } - - /** - * Draws the FCAL data in the rho-z projection. See the description of - * filterDrawListRZ() for an explanation of the drawing method. - * - * @return ACoord cell geometry polygons - */ - protected ACoord getRZUser() - { - makeDrawList(); - filterDrawListRZ(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - - double zMin = z[j] - dz[j] / 2.; - double zMax = z[j] + dz[j] / 2.; - double rMin = Math.sqrt(Math.pow(Math.abs(x[j]) - Math.abs(dx[j] / 2.), 2) + Math.pow(Math.abs(y[j]) - Math.abs(dy[j] / 2.), 2)); - double rMax = Math.sqrt(Math.pow(Math.abs(x[j]) + Math.abs(dx[j] / 2.), 2) + Math.pow(Math.abs(y[j]) + Math.abs(dy[j] / 2.), 2)); - - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[j] - phiMid); - if (phiDiff > Math.PI / 2. && phiDiff <= 3 * Math.PI / 2.) - { - rMin *= -1; - rMax *= -1; - } - - hv[0][i] = new double[] { zMax, zMin, zMin, zMax }; - hv[1][i] = new double[] { rMax, rMax, rMin, rMin }; - - index[i] = j; - } - - return new ACoord(hv, index, this); - } - - /** - * Applies cuts to the data. - */ - protected void applyCuts() - { - super.applyCuts(); - cut("CutsCalo", "FCALET", "FCALET", et); - cut("CutsCalo", "FCALEnergy", "FCALEnergy", energy); - - int cutSub = parameterStore.get("CutsCalo", "FCAL").getI(); - if(cutSub != -1) - { - cutArray(sub, cutSub, "Endcap"); - } - } - - /** - * Returns the data in the phi-rho projection. - * - * @return ACoord polygons representing calorimeter cells - */ - public ACoord getFRUser() - { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - /** - * Returns the data in the phi-eta projection. - * - * @return ACoord polygons representing calorimeter cells - */ - protected ACoord getVPUser() - { - makeDrawList(); - - switch (parameterStore.get("VP", "Mode").getI()) - { - case AProjectionVP.MODE_ECAL_LAYER_0: - case AProjectionVP.MODE_ECAL_LAYER_1: - case AProjectionVP.MODE_ECAL_LAYER_2: - case AProjectionVP.MODE_ECAL_LAYER_3: - cutArray(sampling, 0, "EM"); - break; - case AProjectionVP.MODE_HCAL_LAYER_0: - case AProjectionVP.MODE_HCAL_LAYER_1: - case AProjectionVP.MODE_HCAL_LAYER_2: - case AProjectionVP.MODE_HCAL_LAYER_3: - cutArrayOR(sampling, 1, 2, "Hadronic"); - break; - default: - return ACoord.NO_DATA; - } - - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - etSum[j] = et[j]; - - double eta0 = AMath.etaAbs(z[j], (float) Math.sqrt(Math.pow(x[j] + dx[j] / 2., 2) + Math.pow(y[j] + dy[j] / 2., 2))); - double eta1 = AMath.etaAbs(z[j], (float) Math.sqrt(Math.pow(x[j] - dx[j] / 2., 2) + Math.pow(y[j] + dy[j] / 2., 2))); - double eta2 = AMath.etaAbs(z[j], (float) Math.sqrt(Math.pow(x[j] - dx[j] / 2., 2) + Math.pow(y[j] - dy[j] / 2., 2))); - double eta3 = AMath.etaAbs(z[j], (float) Math.sqrt(Math.pow(x[j] + dx[j] / 2., 2) + Math.pow(y[j] - dy[j] / 2., 2))); - - // Calculate phi between 0 and 360. - double phi0 = Math.toDegrees(Math.atan2(y[j] + dy[j] / 2., x[j] + dx[j] / 2.) + 360.) % 360.; - double phi1 = Math.toDegrees(Math.atan2(y[j] + dy[j] / 2., x[j] - dx[j] / 2.) + 360.) % 360.; - double phi2 = Math.toDegrees(Math.atan2(y[j] - dy[j] / 2., x[j] - dx[j] / 2.) + 360.) % 360.; - double phi3 = Math.toDegrees(Math.atan2(y[j] - dy[j] / 2., x[j] + dx[j] / 2.) + 360.) % 360.; - - // Some code to prevent problems with cells going across the 0/360 - // border. - if (phi1 - phi0 > 180.) - phi1 -= 360.; - else if (phi0 - phi1 > 180.) - phi1 += 360; - if (phi2 - phi1 > 180.) - phi2 -= 360.; - else if (phi1 - phi2 > 180.) - phi2 += 360; - if (phi3 - phi2 > 180.) - phi3 -= 360.; - else if (phi2 - phi3 > 180.) - phi3 += 360; - - hv[0][i] = new double[] { eta0, eta1, eta2, eta3 }; - hv[1][i] = new double[] { phi0, phi1, phi2, phi3 }; - - index[i] = j; - } - - return new ACoord(hv, index, this).includePhiWrapAround("VP"); - } - - /** - * Returns the histograms in the RZ projection. - * - * @return ACoord[] histograms - */ - public ACoord[] getRZHistograms() - { - AHistogram histUp = new AHistogram(-outerEta, outerEta, etaGranularity, histoScale.getD(), this); - AHistogram histDown = new AHistogram(-outerEta, outerEta, etaGranularity, histoScale.getD(), this); - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - int sign = AParameterUtilities.getRhoSign(x[j], y[j]); - double etaMin; - double etaMax; - - if (side[j] < 0) - { - etaMin = AParameterUtilities.eta(z[j] + dz[j] / 2.f, r[j] - dr[j] / 2.f); - etaMax = AParameterUtilities.eta(z[j] - dz[j] / 2.f, r[j] + dr[j] / 2.f); - } - else - { - etaMin = AParameterUtilities.eta(z[j] - dz[j] / 2.f, r[j] + dr[j] / 2.f); - etaMax = AParameterUtilities.eta(z[j] + dz[j] / 2.f, r[j] - dr[j] / 2.f); - } - - if (sign > 0) - { - histUp.fill(etaMin, etaMax, etSum[j]); - } - else - { - histDown.fill(etaMin, etaMax, etSum[j]); - } - } - - ACoordArray c = new ACoordArray(); - c.add(histUp.getRZUser(outerZ, outerR, AHistogram.UP)); - c.add(histDown.getRZUser(outerZ, outerR, AHistogram.DOWN)); - return c.getArray(); - } - - - -// /** -// * Determines adc2Mev factor value for a cell. The number either comes -// * with the event file (adc2Mev subtag), but sometimes is not available -// * in Athena (in the database) which is indicated by -1 in the event file -// * for a particular cell. In this case, use predefined constant in this -// * method. -// * -// * zdenek (2008-09-15): -// * These predefined values (which are used if adc2Mev factor is -1) should -// * no longer be used. if the factor is not present, do not plot the pulse -// * shape, just the ADC counts as these values are non-sense. The method -// * and references to it should be removed after some time (if calo people -// * don't change their mind to pre-define some other values and use those) -// * -// * @param index int -// * @return String -// */ - /* - private float getADC2MevFactorPredefined(int index) - { - int layer = sampling[index]; - float r = Float.NaN; - switch(layer) - { - case 0: r = 87.0f; - break; - case 1: r = 117.0f; - break; - case 2: r = 193.0f; - break; - } - - return r; - - } // getADC2MevFactorPredefined() --------------------------------------- - */ - - - /** - * Returns info about a selected hit (for picking) - * - * @param index int hit index - * @return String info - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",et[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",et[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",et[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",et[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String t = ""; - String cellInfo = ""; - - t = super.getHitInfo(index); - cellInfo += "\n x = " + x[index] + " cm"; - cellInfo += "\n y = " + y[index] + " cm"; - - cellInfo += "\n cell time = "; - cellInfo += (cellTime != null) ? Float.toString(cellTime[index]) + - " ns" : "n/a"; - cellInfo += "\n cell gain = "; - cellInfo += (cellGain != null) ? Integer.toString(cellGain[index]) : "n/a"; - cellInfo += "\n cell pedestal = "; - cellInfo += (cellPedestal != null) ? Float.toString(cellPedestal[index]) + - " ADC counts" : "n/a"; - - cellInfo += "\n ADC 2 MeV = "; - if(adc2Mev == null) - { - cellInfo += "n/a"; - } - else - { - // subtag adc2Mev was available in the event file - if(adc2Mev[index] != -1) - { - // other than -1: the factor was available in - // Athena (database) for this particular cell - cellInfo += Float.toString(adc2Mev[index]) + " (from database)"; - } - else - { - // -1 -> the factor wasn't available in Athena (database), - // use hardcoded constant for this particular cell - cellInfo += "-1 (n/a in database)"; - // see comment at the getADC2MevFactorPredefined() method - // (was printing the predefined value) using predefined " + - // Float.toString(getADC2MevFactorPredefined(index)); - } - } - - cellInfo += pulseShapesDataAvailable ? "" : - "\n data for real pulse shapes plot n/a"; - - return t + cellInfo; - - } // getHitInfo() ------------------------------------------------------- - - @Override //ACalorimeterData - //Gives the hit time for this cell - protected double getTime(int hit) - { - if (cellTime == null) return 0.0; - else return cellTime[hit]; - } - - /** - * Recalculates eta from r and z in case the user wants to have their eta - * with respect to the primary vertex instead of 0. The calculation is a - * little different from the other calorimeter classes because this one - * contains both barrel and endcap data. - * - * @param index int index of hit in data - * @return double eta value - */ - public double getEta(int index) - { - if (!parameterStore.get("VP", "EtaVertex").getStatus()) - { - return this.eta[index]; - } - - return AParameterUtilities.eta(z[index], Math.sqrt(x[index] * x[index] + y[index] * y[index])); - } - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - ACoord[] data = ACoord.NO_HISTOGRAMS; - if (projection instanceof AProjectionRZ) - data = getRZHistograms(); - return projection.nonLinearTransform(data); - } - - - -// /** -// * Call util class which plots cell pulse shapes provided that -// * all real pulse shapes data is available -// * Functions calculates values of real pulse shape calculated in the method -// * getPhysicsPulseShape(). -// * This method is called from pick interaction. -// * -// * @param index int -// */ - /*public void plotPulseShapes(int index) - { - - if(pulseShapesDataAvailable) - { - String title = getPulseTitleString(index); - - int[][] adcCountsLocal = new int[][] { adcCounts[index] }; - - if(super.checkADCCountsAvailability(adcCountsLocal)) - { - // adc counts are available - logger.debug(CALORIMETER_NAME + " adc counts (digits) are " + - "available for pulse shapes plots for this cell."); - } - else - { - AOutput.append("\nADC counts are not available for this cell, " + - "can't plot pulse shapes.", ALogPane.WARNING); - return; - } - - - float[] time = ACalorimeterRPSPLT.FCAL_TIME; // lookup tables - float[] amplitude = null; // lookup tables - switch(sampling[index]) - { - // use correct amplitude lookup table for this layer (sampling) - case 0: amplitude = ACalorimeterRPSPLT.FCAL_LAYER0_AMPLITUDE; - break; - case 1: amplitude = ACalorimeterRPSPLT.FCAL_LAYER1_AMPLITUDE; - break; - case 2: amplitude = ACalorimeterRPSPLT.FCAL_LAYER2_AMPLITUDE; - break; - default: AOutput.append("\nADC counts plot only, pulse shape " + - "plot not implemented for " + - CALORIMETER_NAME + " layer " + - sampling[index] + "\n", ALogPane.WARNING); - APulseShapePlot.plotADCCounts(adcCountsLocal, title, null); - return; - } - - // step - starting from 1, need to get step numbers within - // number of ADC samples (adcCounts[0].length) - double step = (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try - { - if(factor != -1) - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - realPulse[0][i] = super.getPhysicsPulseShape(d, cellTime[index], - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogPane.WARNING); - return; - } - - if(factor != -1) - { - logger.debug("adc2Mev factor available, plotting full plot."); - APulseShapePlot.plotRealPulseShapes(adcCountsLocal, realPulse, - step, null, title); - } - else - { - logger.debug("adc2Mev factor not available, plotting just adc counts."); - APulseShapePlot.plotADCCounts(adcCountsLocal, title, null); - } - - } // if(pulseShapesDataAvailable) - else - { - return; - } - - }*/ // plotPulseShapes() -------------------------------------------------- - - @Override - protected int[][] getADCCounts(int index) { - - if (pulseShapesDataAvailable) { - return new int[][]{adcCounts[index]}; - } else { - return null; - } - } - - /** - * Calculate local time for pulse shape plots - */ - protected double getLocalTime(double xTime, double cellTime, int numSamplings) { - int nominalPeakSample = (int)(numSamplings / 2.); - return ((xTime - nominalPeakSample + 3) * 25.0) - cellTime; - } - - @Override - protected double[][] getPulseShape(int index) { - - float[] time = ACalorimeterRPSPLT.FCAL_TIME; // lookup tables - float[] amplitude = null; // lookup tables - switch(sampling[index]) - { - // use correct amplitude lookup table for this layer (sampling) - case 0: amplitude = ACalorimeterRPSPLT.FCAL_LAYER0_AMPLITUDE; - break; - case 1: amplitude = ACalorimeterRPSPLT.FCAL_LAYER1_AMPLITUDE; - break; - case 2: amplitude = ACalorimeterRPSPLT.FCAL_LAYER2_AMPLITUDE; - break; - default: AOutput.append("\nADC counts plot only, pulse shape " + - "plot not implemented for " + - CALORIMETER_NAME + " layer " + - sampling[index] + "\n", ALogInterface.WARNING); - return null; - } - - // step - starting from 1, need to get step numbers within - // number of ADC samples (adcCounts[0].length) - double step = getPulseStep(index); - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try - { - if(factor != -1) - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - double localTime = getLocalTime(d, cellTime[index], this.numSamplings); - realPulse[0][i] = super.getPhysicsPulseShape(localTime, - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - return null; - } - - if(factor != -1) - { - logger.debug("adc2Mev factor available, plotting full plot."); - return realPulse; - } - else - { - logger.debug("adc2Mev factor not available, plotting just adc counts."); - return null; - } - - } - - @Override - protected double getPulseStep(int index) { - return (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AG4StepData.java b/graphics/AtlantisJava/src/atlantis/data/AG4StepData.java deleted file mode 100755 index 7f962718d03..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AG4StepData.java +++ /dev/null @@ -1,559 +0,0 @@ -package atlantis.data; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.InputStreamReader; -import java.util.Enumeration; -import java.util.Scanner; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import atlantis.parameters.AParameterUtilities; -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.utils.AAtlantisException; -import atlantis.event.ABufferedEventSource; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.utils.AHashMap; - -/** - * This class holds the data from GEANT4 (G4) steps which - * represent the path of simulated particles. The steps - * are read in from a (zipped) text file via the File menu - * or by pressing "/". - * The file (named "G4Atlantis_run_event.txt(.zip)") can be - * made by running AtlasG4 with a special plugin: - * AtlasG4_trf.py postInitInclude="G4UserActions/G4AtlantisDumper_options.py" - * - * @author Andy Haas (ahaas) - */ -public class AG4StepData extends AData { - - protected int[] nsteps; - protected int[] gid; - protected int[] pid; - protected int[] fs; - protected int[] ls; - protected int[] stepn; - protected String[] pn; - protected int[] nsec; - protected float[] tedep; - protected float[] tnedep; - protected float[] length; - protected int[] pdg; - protected float[] mass; - protected float[] charge; - protected float[] x1; - protected float[] y1; - protected float[] z1; - protected float[] t1; - protected float[] x2; - protected float[] y2; - protected float[] z2; - protected float[] t2; - protected float[] px1; - protected float[] py1; - protected float[] pz1; - protected float[] ke1; - protected float[] px2; - protected float[] py2; - protected float[] pz2; - protected float[] ke2; - - protected float[] eta1; - protected float[] p1; - - public AG4StepData(AHashMap p, AEvent e) { - super(p, e); - - nsteps = p.getIntArray("nsteps"); - gid = p.getIntArray("id"); - pid = p.getIntArray("pid"); - fs = p.getIntArray("fs"); - ls = p.getIntArray("ls"); - stepn = p.getIntArray("stepn"); - pn = p.getStringArray("pn"); - nsec= p.getIntArray("nsec"); - tedep = p.getFloatArray("tedep"); - tnedep = p.getFloatArray("tnedep"); - length = p.getFloatArray("length"); - pdg = p.getIntArray("pdg"); - mass = p.getFloatArray("mass"); - charge = p.getFloatArray("charge"); - x1 = p.getFloatArray("x1"); - y1 = p.getFloatArray("y1"); - z1 = p.getFloatArray("z1"); - t1 = p.getFloatArray("t1"); - x2 = p.getFloatArray("x2"); - y2 = p.getFloatArray("y2"); - z2 = p.getFloatArray("z2"); - t2 = p.getFloatArray("t2"); - px1 = p.getFloatArray("px1"); - py1 = p.getFloatArray("py1"); - pz1 = p.getFloatArray("pz1"); - ke1 = p.getFloatArray("ke1"); - px2 = p.getFloatArray("px2"); - py2 = p.getFloatArray("py2"); - pz2 = p.getFloatArray("pz2"); - ke2 = p.getFloatArray("ke2"); - - eta1 = new float[numData]; - p1 = new float[numData]; - for (int i=0; i<numData; ++i) { - eta1[i]=(float)(-1.0*Math.log(Math.tan( - Math.acos( z1[i]/Math.sqrt(x1[i]*x1[i]+y1[i]*y1[i]+z1[i]*z1[i]) )/2.0 - ))); - p1[i]=(float)Math.sqrt(px1[i]*px1[i]+py1[i]*py1[i]+pz1[i]*pz1[i]); - } - } - - /** - * The color of the step displayed... mostly determined - * by the particle type (pdgid) for now. - */ - @Override - protected void colorByIndex() { - int numColors = parameterStore.get("HitColors", "Number").getI(); - if (numColors<6) return;//not enough colors! - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) { - - if (charge[i]==0) color[i] = (byte)col[0];//neutral - else color[i] = (byte)col[1];//charged - - if (pdg[i]==22) color[i] = (byte)col[2];//photons - if (Math.abs(pdg[i])==11) color[i] = (byte)col[3];//electrons - if (Math.abs(pdg[i])==13) color[i] = (byte)col[4];//muons - if (Math.abs(pdg[i])>=1000000000) color[i] = (byte)col[5];//nuclei - } - } - - /** - * Can choose to color by constant color, or using the - * function above (by type / index). - */ - protected int internalColor() { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - switch (colorFunction) { - case 0: - colorByConstant(); - break; - case 1: - colorByIndex(); - break; - } - return 1; - } - - /** - * Cuts on the particle type, energy, etc. - * Adjusted via the gui, and in the config-G4.xml file. - */ - protected void applyCuts() { - cutIndex(); - - cut("CutsObjects", "G4StepKE1", " ke1", ke1);//starting kinetic energy (MeV) - cut("CutsObjects", "G4StepP1", " p1", p1);//starting momentum (MeV) - - cut("CutsObjects", "G4StepPhotons", " |pdg|", pdg);//22 - cut("CutsObjects", "G4StepElectrons", " |pdg|", pdg);//11 - cut("CutsObjects", "G4StepMuons", " |pdg|", pdg);//13 - cut("CutsObjects", "G4StepPions", " |pdg|", pdg);//211 - cut("CutsObjects", "G4StepProtons", " |pdg|", pdg);//2212 - cut("CutsObjects", "G4StepNeutrons", " |pdg|", pdg);//2112 - - // Nuclear codes are given as 10-digit numbers +-10LZZZAAAI. - // For a nucleus consisting of np protons and nn neutrons - // A = np + nn +nlambda and Z = np and L = nlambda - // I gives the isomer level, with I = 0 corresponding to the ground state and I >0 to excitations - cut("CutsObjects", "G4StepNuclei", " |pdg|", pdg);//1000000000 - - } - - /** - * Prints out stuff when you select a step using the hand. - */ - public String getHitInfo(int index) { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if (simpleOutput > 0) { - return getNameScreenName() + " index: " + index + "\n"; - } - - String name = "none"; - try { - name = APDGTable.getName(pdg[index]); - - } catch(APDGTable.ParticleNotFoundError e) { - name = "unknown"; - } - - return getName() + " (index: " + index + ") : " - + " storegate key = " + storeGateKey + "\n" - + " total step # = " + nsteps[index] + " \n" - + " geant/parent id = " + gid[index]+"/"+ pid[index] + " \n" - + " first/last step? " + fs[index] +"/"+ ls[index] + " / step#="+stepn[index]+"\n" - + " process = " + pn[index] + " / # secondaries = " + nsec[index] + " \n" - + " energy/NI deposited = " + tedep[index]+" / "+tnedep[index]+" MeV\n" - + " length = " + length[index] + " cm / " +"eta1 = "+eta1[index]+"\n" - + " pdg = " + pdg[index] + " ("+name+")\n" - + " mass / charge = " + mass[index]+" MeV"+" / "+charge[index]+"\n" - + " x1 y1 z1 = " + String.format("%.3f", x1[index])+" "+String.format("%.3f", y1[index])+" "+String.format("%.3f", z1[index])+" cm\n" - + " t1 = " + String.format("%.3f", t1[index]) + " ns\n" - + " x2 y2 z2 = " + String.format("%.3f", x2[index])+" "+String.format("%.3f", y2[index])+" "+String.format("%.3f", z2[index])+" cm\n" - + " t2 = " + String.format("%.3f", t2[index]) + " ns\n" - + " px1 py1 pz1 = " + String.format("%.3f", px1[index])+" "+String.format("%.3f", py1[index])+" "+String.format("%.3f", pz1[index])+" MeV\n" - + " ke1 = " + String.format("%.3f", ke1[index]) + " MeV\n" - + " px2 py2 pz2 = " + String.format("%.3f", px2[index])+" "+String.format("%.3f", py2[index])+" "+String.format("%.3f", pz2[index])+" MeV\n" - + " ke2 = " + String.format("%.3f", ke2[index]) + " MeV\n" - + " p1 = " + String.format("%.3f", p1[index]) + " MeV\n" - ; - } - - /** - * Make some cuts for drawing in the YX view. - */ - @Override - protected ACoord getYXUser() { - //System.out.print("numData="+numData+", numDraw="+numDraw); - makeDrawList(); - //System.out.print(" "+numDraw); - - //cut on |eta1| - int num = 0; - double AbsEtaXYcut = parameterStore.get(PARAMETER_GROUP, "AbsEtaXYcut").getD(); - if (AbsEtaXYcut >= 0.0) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(eta1[listdl[i]]) < AbsEtaXYcut) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - //System.out.print(" "+numDraw); - - //cut on |z1| - num = 0; - double AbszXYcut = parameterStore.get(PARAMETER_GROUP, "AbszXYcut").getD(); - if (AbszXYcut >= 0.0) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(z1[listdl[i]]) < AbszXYcut) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - //System.out.println(" "+numDraw); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - //double length = parameterStore.get(PARAMETER_GROUP, "SegmentLength").getD(); - for (int i = 0; i < numDraw; i++) { - int j = listdl[i]; - hv[0][i] = new double[]{x1[j], x2[j]}; - hv[1][i] = new double[]{y1[j], y2[j]}; - index[i] = j; - } - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - } - - /** - * Make some cuts for drawing in the FR view. - */ - @Override - protected ACoord getFRUser() { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - /** - * Make some cuts for drawing in the RZ view. - */ - @Override - protected ACoord getRZUser() { - makeDrawList(); - - //cut on |eta1| - int num = 0; - double AbsEtaRZcut = parameterStore.get(PARAMETER_GROUP, "AbsEtaRZcut").getD(); - if (AbsEtaRZcut >= 0.0) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(eta1[listdl[i]]) < AbsEtaRZcut) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - //cut on |z1| - num = 0; - double AbszRZcut = parameterStore.get(PARAMETER_GROUP, "AbszRZcut").getD(); - if (AbszRZcut >= 0.0) { - for (int i = 0; i < numDraw; i++) { - if ( - Math.abs(z1[listdl[i]]) < AbszRZcut && - Math.sqrt(x1[listdl[i]]*x1[listdl[i]]+y1[listdl[i]]*y1[listdl[i]]) < 1200 - ) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - //double length = parameterStore.get(PARAMETER_GROUP, "SegmentLength").getD(); - for (int i = 0; i < numDraw; i++) { - int j = listdl[i]; - double s = AParameterUtilities.getRhoSign(x1[j], y1[j]);//use same for both points to avoid ugliness - double r1 = s * Math.sqrt(x1[j] * x1[j] + y1[j] * y1[j]); - double r2 = s * Math.sqrt(x2[j] * x2[j] + y2[j] * y2[j]); - hv[0][i] = new double[]{z1[j], z2[j]}; - hv[1][i] = new double[]{r1, r2}; - index[i] = j; - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - @Override - public String getName() { - return "G4Step"; - } - - @Override - public String getNameScreenName() { - return "G4Step"; - } - - @Override - public String getParameterGroup() { - return "G4Step"; - } - - /** - * Read in the corresponding G4Atlantis_run_event.txt(.zip) file. - * It needs to be in the same directory as the JiveXML_run_event.xml file - * that is currently being viewed. - */ - public static void ReadG4Steps(){ - AEvent ev = eventManager.getCurrentEvent(); - String source = eventManager.getEventSource().getSourceName(); - System.out.println("Source="+source); - String filename = source; - if (source.contains("\\")) filename+="\\G4Atlantis_"+ev.getRunNumber()+"_"+ev.getEventNumber()+".txt"; - else filename += "/G4Atlantis_" + ev.getRunNumber() + "_" + ev.getEventNumber() + ".txt"; - System.out.println("Reading G4 file: " + filename); - Scanner inFile = null; - int maxnstepsinthisevent = 4000000;//max allowed - int nstepsinfile = maxnstepsinthisevent;//will be set to actual number of steps in file, if lower than maximum - try { - inFile = new Scanner(new FileReader(filename)); - - //try to get the number of steps that are in the file - try { - FileInputStream in = new FileInputStream(filename); - BufferedReader br = new BufferedReader(new InputStreamReader(in)); - String strLine = null, tmp; - while ((tmp = br.readLine()) != null) { strLine = tmp; } - String lastLine = strLine; - System.out.println(lastLine); - in.close(); - - Scanner lastlinescanner = new Scanner(lastLine); - String llach = lastlinescanner.next(); - String _llach = "ACH_G4Step"; - if (!llach.equals(_llach)) { - System.out.println("??ach in lastline = " + llach); - } - nstepsinfile = lastlinescanner.nextInt()+1; - - } catch (IOException ex) { - Logger.getLogger(AG4StepData.class.getName()).log(Level.SEVERE, null, ex); - } - - } catch (FileNotFoundException ex) { - //Logger.getLogger(AEventQueue.class.getName()).log(Level.SEVERE, null, ex); - System.out.println("Could not open "+filename); - } - - if (inFile == null) { - ZipFile zipfile = null; - try { - System.out.println("Reading G4 file: " + filename+".zip"); - zipfile = new ZipFile(filename + ".zip"); - } catch (IOException ex) { - //Logger.getLogger(AEventQueue.class.getName()).log(Level.SEVERE, null, ex); - System.out.println("Could not open "+filename+".zip either"); - } - if (zipfile != null) { - BufferedInputStream is = null; - ZipEntry entry; - Enumeration e = zipfile.entries(); - while (e.hasMoreElements()) { - entry = (ZipEntry) e.nextElement(); - System.out.println("Extracting: " + entry); - try { - is = new BufferedInputStream(zipfile.getInputStream(entry)); - BufferedReader br = new BufferedReader(new InputStreamReader(is)); - String strLine = null, tmp; - while ((tmp = br.readLine()) != null) { - strLine = tmp; - } - String lastLine = strLine; - System.out.println(lastLine); - - Scanner lastlinescanner = new Scanner(lastLine); - String llach = lastlinescanner.next(); - String _llach = "ACH_G4Step"; - if (!llach.equals(_llach)) { - System.out.println("??ach in lastline = " + llach); - } - nstepsinfile = lastlinescanner.nextInt() + 1; - - is = new BufferedInputStream(zipfile.getInputStream(entry)); - inFile = new Scanner(is); - } catch (IOException ex) { - Logger.getLogger(AG4StepData.class.getName()).log(Level.SEVERE, null, ex); - } - - } - } - } - - if (inFile != null) { - - System.out.print("nsteps in file should be "+nstepsinfile+"... "); - if (nstepsinfile>maxnstepsinthisevent) nstepsinfile=maxnstepsinthisevent; - System.out.println(" and will read "+nstepsinfile+" steps."); - - try { - AHashMap para = new AHashMap(100); - float[] x1 = new float[nstepsinfile]; - float[] y1 = new float[nstepsinfile]; - float[] z1 = new float[nstepsinfile]; - float[] t1 = new float[nstepsinfile]; - float[] x2 = new float[nstepsinfile]; - float[] y2 = new float[nstepsinfile]; - float[] z2 = new float[nstepsinfile]; - float[] t2 = new float[nstepsinfile]; - float[] px1 = new float[nstepsinfile]; - float[] py1 = new float[nstepsinfile]; - float[] pz1 = new float[nstepsinfile]; - float[] ke1 = new float[nstepsinfile]; - float[] px2 = new float[nstepsinfile]; - float[] py2 = new float[nstepsinfile]; - float[] pz2 = new float[nstepsinfile]; - float[] ke2 = new float[nstepsinfile]; - int[] nsteps = new int[nstepsinfile]; - int[] id = new int[nstepsinfile]; - int[] pid = new int[nstepsinfile]; - int[] fs = new int[nstepsinfile]; - int[] ls = new int[nstepsinfile]; - int[] stepn = new int[nstepsinfile]; - String[] pn = new String[nstepsinfile]; - int[] nsec = new int[nstepsinfile]; - float[] tedep = new float[nstepsinfile]; - float[] tnedep = new float[nstepsinfile]; - float[] length = new float[nstepsinfile]; - int[] pdg = new int[nstepsinfile]; - float[] mass = new float[nstepsinfile]; - float[] charge = new float[nstepsinfile]; - - int n = 0; - String _ach = "ACH_G4Step"; - while (inFile.hasNext() && n<nstepsinfile){ - String ach = inFile.next(); - if (!ach.equals(_ach)) { - System.out.println("??ach = " + ach); - } - nsteps[n] = inFile.nextInt(); - id[n] = inFile.nextInt(); - pid[n] = inFile.nextInt(); - fs[n] = inFile.nextInt(); - ls[n] = inFile.nextInt(); - stepn[n] = inFile.nextInt(); - pn[n] = inFile.next(); - nsec[n] = inFile.nextInt(); - tedep[n] = inFile.nextFloat(); - tnedep[n] = inFile.nextFloat(); - length[n] = inFile.nextFloat()/10.0f; - pdg[n] = inFile.nextInt(); - //System.out.println("pdg="+pdg); - mass[n] = inFile.nextFloat(); - charge[n] = inFile.nextFloat(); - x1[n] = inFile.nextFloat()/10.0f; - y1[n] = inFile.nextFloat()/10.0f; - z1[n] = inFile.nextFloat()/10.0f; - t1[n] = inFile.nextFloat(); - px1[n] = inFile.nextFloat(); - py1[n] = inFile.nextFloat(); - pz1[n] = inFile.nextFloat(); - ke1[n] = inFile.nextFloat(); - x2[n] = inFile.nextFloat()/10.0f; - y2[n] = inFile.nextFloat()/10.0f; - z2[n] = inFile.nextFloat()/10.0f; - t2[n] = inFile.nextFloat(); - px2[n] = inFile.nextFloat(); - py2[n] = inFile.nextFloat(); - pz2[n] = inFile.nextFloat(); - ke2[n] = inFile.nextFloat(); - ++n; - if (n%100000==0) System.out.println("Read "+n+" steps"); - } - System.out.println("Read "+n+" steps"); - inFile.close(); - System.out.println("Closed file."); - - para.put("nsteps",nsteps); - para.put("id",id); - para.put("pid",pid); - para.put("fs",fs); - para.put("ls",ls); - para.put("stepn",stepn); - para.put("pn",pn); - para.put("nsec",nsec); - para.put("tedep",tedep); - para.put("tnedep",tnedep); - para.put("length",length); - para.put("pdg",pdg); - para.put("mass",mass); - para.put("charge",charge); - para.put("x1", x1); - para.put("y1", y1); - para.put("z1", z1); - para.put("t1", t1); - para.put("x2", x2); - para.put("y2", y2); - para.put("z2", z2); - para.put("t2", t2); - para.put("px1", px1); - para.put("py1", py1); - para.put("pz1", pz1); - para.put("ke1", ke1); - para.put("px2", px2); - para.put("py2", py2); - para.put("pz2", pz2); - para.put("ke2", ke2); - para.put("numData", n); - //para.put("storeGateKey", "G4"); - - ABufferedEventSource.maxNumberOfEvents=1;//otherwise we run out of heap - AG4StepData g4d = new AG4StepData(para, ev); - ev.add(g4d); - } catch (AAtlantisException ex) { - Logger.getLogger(AG4StepData.class.getName()).log(Level.SEVERE, null, ex); - } - catch (OutOfMemoryError oom) { - Logger.getLogger(AG4StepData.class.getName()).log(Level.SEVERE,"Ran out of memory while trying to read G4Step data"); - } - ACanvas.getCanvas().repaintAllFromScratch(); - }//inFile!=null - - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHECData.java b/graphics/AtlantisJava/src/atlantis/data/AHECData.java deleted file mode 100755 index 2b1efe56a62..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHECData.java +++ /dev/null @@ -1,574 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.utils.AUtilities; -import atlantis.utils.ALogger; -import java.io.IOException; -import com.Ostermiller.util.CSVParser; - -import java.io.InputStream; -import java.io.StringReader; -import java.io.FileNotFoundException; - - -/** - * The Hadronic End Cap calorimeter. - * - * @author Eric Jansen - */ -public class AHECData extends ACalorimeterData -{ - private static ALogger logger = ALogger.getLogger(AHECData.class); - - // data for real pulse shapes plots - private int numSamplings = 0; - private int[][] adcCounts = null; - private float[] cellTime = null; - private int[] cellGain = null; - private float[] cellPedestal = null; - private float[] adc2Mev = null; - private static boolean pulseShapesDataAvailable = false; - private static final String LOOKUP_TABLE_FILE = - AGlobals.instance().getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - "rpsplt_hec.csv"; - // number of lookup table values for real pulse shapes plots calculation - private static final short NUMBER_OF_LOOKUP_VALUES = 800; - - - - AHECData(AHashMap p, AEvent e) - { - super(p,e); - - for (int i = 0; i < numData; i++) - { - try - { - side[i] = (byte) AIdHelper.larBarrelEndcap(id[i]); - etaIndex[i] = (short) AIdHelper.larEta(id[i]); - phiIndex[i] = (short) AIdHelper.larPhi(id[i]); - sampling[i] = AIdHelper.larSampling(id[i]); - } - catch (AAtlantisException ex) - { - logger.error("Problem decoding ID " + id[i] + " in " + CALORIMETER_NAME + ": " + ex.getMessage()); - side[i] = 0; - etaIndex[i] = -1; - phiIndex[i] = -1; - sampling[i] = -1; - } - } - - makeHitToGeometryMapping(); - for (int i = 0; i < et.length; ++i) - { - et[i] = Math.abs(energy[i] / (float) Math.cosh(eta[i])); - } - - // Collect some constants we need for the histograms. - for (int i = 0; i < ACalorimeterDetector.count(); i++) - { - - if (ACalorimeterDetector.get(i).getName().indexOf(CALORIMETER_NAME) >= 0) - { - if (innerR == 0.0 || ACalorimeterDetector.get(i).getRMin() < innerR) - { - innerR = ACalorimeterDetector.get(i).getRMin(); - } - if (innerZ == 0.0 || ACalorimeterDetector.get(i).getZMin() < innerZ) - { - innerZ = ACalorimeterDetector.get(i).getZMin(); - } - if (phiGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaPhi() < phiGranularity) - { - phiGranularity = ACalorimeterDetector.get(i).getDeltaPhi(); - } - if (etaGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaEta() < etaGranularity) - { - etaGranularity = ACalorimeterDetector.get(i).getDeltaEta(); - } - if (outerEta == 0.0 || ACalorimeterDetector.get(i).getEtaMax() > outerEta) - { - outerEta = ACalorimeterDetector.get(i).getEtaMax(); - } - } - - if (outerR == 0.0 || ACalorimeterDetector.get(i).getRMax() > outerR) - { - outerR = ACalorimeterDetector.get(i).getRMax(); - } - if (outerZ == 0.0 || ACalorimeterDetector.get(i).getZMax() > outerZ) - { - outerZ = ACalorimeterDetector.get(i).getZMax(); - } - } - - // Add a little bit of extra margin to prevent binning errors due to - // rounding of numbers. - outerEta += etaGranularity; - - // read in HEC data from real pulse shapes plots - readPulseShapePlotData(p); - - } - - - - private void readPulseShapePlotData(AHashMap p) - { - // read ADCCounts and cell data for real pulse shapes plots - adcCounts = super.getADCCountsData(p); - - // read LAr digits (cell data) for real pulse shapes plots - cellTime = (p.get("cellTime") != null) ? p.getFloatArray("cellTime") : null; - cellGain = (p.get("cellGain") != null) ? p.getIntArray("cellGain") : null; - cellPedestal = (p.get("cellPedestal") != null) ? p.getFloatArray("cellPedestal") : null; - adc2Mev = (p.get("adc2Mev") != null) ? p.getFloatArray("adc2Mev") : null; - - pulseShapesDataAvailable = false; - if(adcCounts != null && cellTime != null && cellGain != null && - cellPedestal != null && adc2Mev != null) - { - pulseShapesDataAvailable = true; - numSamplings = adcCounts[0].length; - - logger.debug(CALORIMETER_NAME + - ": data for real pulse shape plots available"); - - if(ACalorimeterRPSPLT.areHECLookupTablesInitialized()) - { - logger.debug(CALORIMETER_NAME + - ": lookup tables have already been read in"); - } - else - { - logger.debug(CALORIMETER_NAME + - ": lookup table values have not been read in yet\n" + - " trying to read file: " + LOOKUP_TABLE_FILE); - - try - { - readLookupTableFile(); - logger.debug(CALORIMETER_NAME + - ": values from " + LOOKUP_TABLE_FILE + - " successfully read in"); - } - catch(AAtlantisException ex) - { - logger.debug(CALORIMETER_NAME + - ": reading " + LOOKUP_TABLE_FILE + - " failed, real pulse shapes plots will not " + - "be available, reason: " + ex.getMessage(), ex); - pulseShapesDataAvailable = false; - } - } - } - - } // readPulseShapePlotData() ------------------------------------------- - - - - /** - * Returns info about a selected hit (for picking) - * - * @param index int hit index - * @return String info - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",et[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",et[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",et[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",et[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String t = ""; - String cellInfo = ""; - - t = super.getHitInfo(index); - - cellInfo += "\n cell time = "; - cellInfo += (cellTime != null) ? Float.toString(cellTime[index]) + - " ns" : "n/a"; - cellInfo += "\n cell gain = "; - cellInfo += (cellGain != null) ? Integer.toString(cellGain[index]) : "n/a"; - cellInfo += "\n cell pedestal = "; - cellInfo += (cellPedestal != null) ? Float.toString(cellPedestal[index]) + - " ADC counts" : "n/a"; - - cellInfo += "\n ADC 2 MeV = "; - if(adc2Mev == null) - { - cellInfo += "n/a"; - } - else - { - // subtag adc2Mev was available in the event file - if(adc2Mev[index] != -1) - { - // other than -1: the factor was available in - // Athena (database) for this particular cell - cellInfo += Float.toString(adc2Mev[index]) + " (from database)"; - } - else - { - // -1 -> the factor wasn't available in Athena (database), - // use hardcoded constant for this particular cell - cellInfo += "-1 (n/a in database)"; - // see comment at the getADC2MevFactorPredefined() method - //, using predefined " + - // Float.toString(getADC2MevFactorPredefined()); - } - } - - cellInfo += pulseShapesDataAvailable ? "" : - "\n data for real pulse shapes plot n/a"; - - return t + cellInfo; - - } // getHitInfo() ------------------------------------------------------- - - @Override //ACalorimeterData - //Gives the hit time for this cell - protected double getTime(int hit) - { - if (cellTime == null) return 0.0; - else return cellTime[hit]; - } - -// /** -// * Determines adc2Mev factor value for a cell. The number either comes -// * with the event file (adc2Mev subtag), but sometimes is not available -// * in Athena (in the database) which is indicated by -1 in the event file -// * for a particular cell. In this case, use predefined constant in this -// * method. -// * -// * zdenek (2008-09-15): -// * These predefined values (which are used if adc2Mev factor is -1) should -// * no longer be used. if the factor is not present, do not plot the pulse -// * shape, just the ADC counts as these values are non-sense. The method -// * and references to it should be removed after some time (if calo people -// * don't change their mind to pre-define some other values and use those) -// -// * @param index int -// * @return String -// */ - /* - private float getADC2MevFactorPredefined() - { - - float r = 13.9f; - return r; - - } // getADC2MevFactorPredefined() --------------------------------------- - */ - - - - /** - * readLookupTableFile() reads in comma separated values (CSV) file - * with HEC real pulse shapes plots time and amplitude lookup values - * @param fileName String - * @throws AAtlantisException - */ - private void readLookupTableFile() throws AAtlantisException - { - try - { - InputStream is = AUtilities.getFileAsStream(LOOKUP_TABLE_FILE); - CSVParser parser = new CSVParser(is); - parser.setCommentStart("#"); - String arrayName = null; - - while((arrayName = parser.nextValue()) != null) - { - String valueArray = parser.nextValue(); // shall now contain all values - CSVParser parserArray = new CSVParser(new StringReader(valueArray)); - String[][] s = parserArray.getAllValues(); - if("HEC_AMPLITUDE".equals(arrayName)) - { - ACalorimeterRPSPLT.HEC_AMPLITUDE = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - else if("HEC_TIME".equals(arrayName)) - { - ACalorimeterRPSPLT.HEC_TIME = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(FileNotFoundException e) - { - throw new AAtlantisException("could not find file: " + - LOOKUP_TABLE_FILE); - } - catch(IOException e) - { - throw new AAtlantisException("exception while reading file: " + - LOOKUP_TABLE_FILE); - } - catch(AAtlantisException e) - { - throw e; - } - - } // readLookupTableFile() ---------------------------------------------- - - - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsCalo", "HECET", "HECET", et); - cut("CutsCalo", "HECEnergy", "HECEnergy", energy); - - int cutSub = parameterStore.get("CutsCalo", "HEC").getI(); - if(cutSub != -1) - { - cutArray(side, cutSub, "Endcap"); - } - - } - - /** - * Returns the name of the parameter group. - * - * @return String parameter group - */ - public String getParameterGroup() - { - return "HEC"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getName() - { - return "HEC"; - } - - /** - * Returns the displayed name of datatype - * - * @return String screen name - */ - public String getNameScreenName() - { - return "HEC"; - } - - /** - * Returns the type of calorimeter (ECAL/HCAL) for a hit. - * - * @param index int hit index - * @return String calorimeter type - */ - public String getCalorimeterType(int index) - { - return "HCAL"; - } - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - ACoord[] data = ACoord.NO_HISTOGRAMS; - int mode = parameterStore.get("YX", "Mode").getI(); - if (projection instanceof AProjectionRZ) - data = getRZHistograms(); - else if (projection instanceof AProjectionFZ) - data = getFZHistograms(); - else if ((projection instanceof AProjectionYX) && (mode == AProjectionYX.MODE_HEC_1 || - mode == AProjectionYX.MODE_HEC_2 || mode == AProjectionYX.MODE_HEC_3 || - mode == AProjectionYX.MODE_HEC_4 || mode == AProjectionYX.MODE_HEC_SUMMED)) - data = getYXHistograms(); - return projection.nonLinearTransform(data); - } - - - -// /** -// * Call util class which plots cell pulse shapes provided that -// * all real pulse shapes data is available -// * Functions calculates values of real pulse shape calculated in the method -// * getPhysicsPulseShape(). -// * This method is called from pick interaction. -// * -// * @param index int -// */ - /*public void plotPulseShapes(int index) - { - - if(pulseShapesDataAvailable) - { - String title = getPulseTitleString(index); - - int[][] adcCountsLocal = new int[][] { adcCounts[index] }; - - if(super.checkADCCountsAvailability(adcCountsLocal)) - { - // adc counts are available - logger.debug(CALORIMETER_NAME + " adc counts (digits) are " + - "available for pulse shapes plots for this cell."); - } - else - { - AOutput.append("\nADC counts are not available for this cell, " + - "can't plot pulse shapes.", ALogPane.WARNING); - return; - } - - - float[] time = ACalorimeterRPSPLT.HEC_TIME; // lookup tables - float[] amplitude = ACalorimeterRPSPLT.HEC_AMPLITUDE; // lookup tables - - // step - starting from 1, need to get step numbers within - // number of ADC samples (adcCounts[0].length) - double step = (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try - { - if(factor != -1) - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - realPulse[0][i] = super.getPhysicsPulseShape(d, cellTime[index], - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogPane.WARNING); - return; - } - - if(factor != -1) - { - logger.debug("adc2Mev factor available, plotting full plot."); - APulseShapePlot.plotRealPulseShapes(adcCountsLocal, realPulse, - step, null, title); - } - else - { - logger.debug("adc2Mev factor not available, plotting just adc counts."); - APulseShapePlot.plotADCCounts(adcCountsLocal, title, null); - } - - } // if(pulseShapesDataAvailable) - else - { - return; - } - - }*/ // plotPulseShapes() -------------------------------------------------- - - @Override - protected int[][] getADCCounts(int index) { - - if (pulseShapesDataAvailable) { - return new int[][]{adcCounts[index]}; - } else { - return null; - } - } - - /** - * Calculate local time for pulse shape plots - */ - protected double getLocalTime(double xTime, double cellTime, int numSamplings) { - int nominalPeakSample = (int)(numSamplings / 2.); - return ((xTime - nominalPeakSample + 3) * 25.0) - cellTime; - } - - @Override - protected double[][] getPulseShape(int index) { - - float[] time = ACalorimeterRPSPLT.HEC_TIME; // lookup tables - float[] amplitude = ACalorimeterRPSPLT.HEC_AMPLITUDE; // lookup tables - - // step - starting from 1, need to get step numbers within - // number of ADC samples (adcCounts[0].length) - double step = getPulseStep(index); - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try { - if (factor != -1) { - for (int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) { - d += step; - double localTime = getLocalTime(d, cellTime[index], this.numSamplings); - realPulse[0][i] = super.getPhysicsPulseShape(localTime, - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } catch (AAtlantisException aaex) { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - return null; - } - - if (factor != -1) { - logger.debug("adc2Mev factor available, plotting full plot."); - return realPulse; - } else { - logger.debug("adc2Mev factor not available, plotting just adc counts."); - return null; - } - } - - @Override - protected double getPulseStep(int index) { - return (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHelix.java b/graphics/AtlantisJava/src/atlantis/data/AHelix.java deleted file mode 100644 index 98e397b2275..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHelix.java +++ /dev/null @@ -1,854 +0,0 @@ -package atlantis.data; - -import atlantis.globals.AGlobals; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionVP; -import atlantis.utils.A3Vector; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -/** - * Base class for tracks with perigee parameters. Includes code for drawing - * helices as a function of the helix angle alpha. - * - * @author Eric Jansen - */ -public class AHelix { - - private final static ALogger logger = ALogger.getLogger(AHelix.class); - - // Constants - public static final double MIN_RADIUS_PHI = 2.; - public static final double TRACKER_RADIUS = 108.; - public static final double TRACKER_LENGTH = 270.; - public static final double SOLENOID_RADIUS = 125.; - public static final double SOLENOID_LENGTH = 280.; - protected static final int NUM_HELIX_POINTS = 30; - - // Parameters from the config/GUI we need - private static double curvature = -1; - - // Vertex w.r.t. which we define the perigee parameters - private float xVtx, yVtx, zVtx; - - // Perigee parameters for the track - private float d0, phi0, z0, cotanTheta, pt; - - // Additional space points outside the solenoid (muon tracks) - private float extraX[] = null; - private float extraY[] = null; - private float extraZ[] = null; - - // Covariance matrix - private double[][] cov = null; - - // Center point, radius and correction factors for the helix - private double xC, yC, R, dr1, dr2, dz1; - - // Sign of alpha, determines direction of curvature of the helix - private float S; - - // Alpha value where the helix crosses MIN_RADIUS_PHI. This is the starting - // value for all the phi-based projections, since phi is undefined at rho=0. - private double alphaMin = 0.; - - // Alpha value at which the helix meets its last space point or where it - // exits the tracker if no space points were defined. - private double alphaMax = Math.PI; - - // Alpha value at which the helix leaves the solenoidal field. When helices - // are drawn beyond this value, for example when extrapolating to the - // calorimeters, they switch from a helix to a straight line here. - private double alphaSolenoid = Math.PI; - - private static final APar parameterStore = APar.instance(); - - AHelix(AOldHelix helix) { - this((float)helix.d0, (float)helix.z0, (float)helix.phi0, (float)helix.tL, (float)helix.pT); - } - - AHelix(float rhoVertex, float phiVertex, float zVertex, - float pTTrack, float phiTrack, float etaTrack, int charge, float rhoEndVertex) { - - this(rhoVertex, phiVertex, zVertex, pTTrack, phiTrack, etaTrack, charge); - this.alphaMax = getAlphaExtrapolated(rhoEndVertex, TRACKER_LENGTH); - } - - AHelix(float rhoVertex, float phiVertex, float zVertex, - float pTTrack, float phiTrack, float eta, int charge) { - - this(0.f, 0.f, phiTrack, (float)AMath.tanLambda(eta), charge*Math.abs(pTTrack), - (float)(rhoVertex*Math.cos(phiVertex)), (float)(rhoVertex*Math.sin(phiVertex)), zVertex); - } - - AHelix(float d0, float z0, float phi0, float tL, float pT, float[][] cov) { - this(d0, z0, phi0, tL, pT); - this.setCovariance(cov); - } - - AHelix(float d0, float z0, float phi0, float cotanTheta, float pt) { - this(d0, z0, phi0, cotanTheta, pt, 0.f, 0.f, 0.f); - } - - /** - * Construct a new track from its perigee parameters. - * @param d0 transverse impact parameter - * @param z0 longitudinal impact parameter - * @param phi0 phi of the point of closest approach in degrees - * @param cotanTheta cotan(theta), angle of the track in the RZ-plane - * @param pt signed transverse momentum, sign encodes charge - * @param xVtx vertex x-coordinate - * @param yVtx vertex y-coordinate - * @param zVtx vertex z-coordinate - */ - AHelix(float d0, float z0, float phi0, float cotanTheta, float pt, - float xVtx, float yVtx, float zVtx) { - - this.xVtx = xVtx; - this.yVtx = yVtx; - this.zVtx = zVtx; - this.d0 = d0; - this.z0 = z0; - this.phi0 = (float)Math.toRadians(phi0); - this.cotanTheta = cotanTheta; // cotan(theta) = tan(lambda) - this.pt = Math.abs(pt); - this.S = -Math.signum(pt); - this.dr1 = 0; - this.dr2 = 0; - this.dz1 = 0; - - // Curvature/pT relation, magnetic field strength. - if (AHelix.curvature <= 0) { - AParameter curvatureParameter = parameterStore.get("Event", "Curvature"); - if (curvatureParameter != null) { - AHelix.curvature = curvatureParameter.getD(); - } else { - AHelix.curvature = 100/0.6; - logger.error("Curvature parameter not found," - + " defaulting to " + AHelix.curvature); - } - } - - // Radius and center point of the helix. The radius is limited to 1e6, - // which on the scale of our tracker corresponds to a straight line. - // This allows cosmics without B-field to be drawn with the same code. - this.R = Math.min(AHelix.curvature * this.pt, 1e6); - this.xC = xVtx - (this.S*this.R + this.d0) * Math.sin(this.phi0); - this.yC = yVtx + (this.S*this.R + this.d0) * Math.cos(this.phi0); - - // The alpha value from which the helix start. - this.alphaMin = 0.; - - // Calculate when this helix leaves the tracker. This is either (1) - // through the barrel or (2) through the endcap. The endcap expression - // is just the function getZ(alpha) reversed. Take the minumum of the - // two, so whatever happens first. - this.alphaMax = getAlphaCylinder(TRACKER_RADIUS, TRACKER_LENGTH); - - // Same as above, but now for the solenoid. - this.alphaSolenoid = getAlphaCylinder(SOLENOID_RADIUS, SOLENOID_LENGTH); - } - - /** - * Fit the radius of the helix to the given points. The radius is described - * by R + dr1 * alpha + dr2 * alpha^2. - * @param x array of x coordinates of points on the helix - * @param y array of y coordinates of points on the helix - * @param z array of z coordinates of points on the helix - */ - public double setPoints(float[] x, float[] y, float[] z, int numPoints) { - - this.dr1 = 0.; - this.dr2 = 0.; - this.dz1 = 0.; - - // Points outside the solenoid are taken as is and added to the end of the track - while (numPoints > 0 && (z[numPoints-1] > SOLENOID_LENGTH - || Math.hypot(x[numPoints-1], y[numPoints-1]) > SOLENOID_RADIUS)) { - - numPoints--; - } - - if (x.length > numPoints) { - extraX = new float[x.length - numPoints]; - extraY = new float[y.length - numPoints]; - extraZ = new float[z.length - numPoints]; - - for(int i=0; i<x.length - numPoints; i++) { - extraX[i] = x[numPoints+i]; - extraY[i] = y[numPoints+i]; - extraZ[i] = z[numPoints+i]; - } - } - - if (numPoints == 1) { - - // Just one point, only do a linear in/decrease of R and Z - double alpha = getAlpha(x[0], y[0]); - this.dr1 = (getRadius(x[0], y[0]) - this.R) / alpha; - this.dz1 = (z[0] - getZ(alpha)) / alpha; - - // Draw helix until this point - this.alphaMax = alpha; - - } else { - - // Several points, perform a least-squares fit using the functions - // R = R + dr1 * alpha + dr2 * alpha^2 and Z = Z + dz1 * alpha. - double a2 = 0., a3 = 0., a4 = 0.; - double dRa = 0., dRa2 = 0., dZa = 0.; - for (int i=0; i<numPoints; i++) { - double alpha = getAlpha(x[i], y[i]); - double rho = getRadius(x[i], y[i]); - - //a1 += alpha; - a2 += Math.pow(alpha, 2.); - a3 += Math.pow(alpha, 3.); - a4 += Math.pow(alpha, 4.); - dRa += (rho - this.R) * alpha; - dRa2 += (rho - this.R) * alpha * alpha; - - dZa += (z[i] - getZ(alpha)) * alpha; - - if (i == 0 || alpha > this.alphaMax) { - this.alphaMax = alpha; - } - } - - // Quadratic - this.dr1 = (dRa / a3 - dRa2 / a4) / (a2 / a3 - a3 / a4); - this.dr2 = (dRa / a2 - dRa2 / a3) / (a3 / a2 - a4 / a3); - - // Linear - this.dz1 = dZa / a2; - - } - - // Return relative correction; distance from the original position at - // the end point, divided by the length of the curve. - double change = Math.hypot(this.dr1 + this.alphaMax*this.dr2, this.dz1) / this.R; - logger.debug("Fitting changed R(maxAlpha) by " + change); - return change; - } - - /** - * Sets the covariance matrix of the track. - * @param cov new covariance matrix - */ - public final void setCovariance(float[][] cov) { - - // Covariance needs to be double[][] for the fitting classes - this.cov = new double[cov.length][cov[0].length]; - - for (int i=0; i<cov.length; i++) { - for (int j=0; j<cov[i].length; j++) { - this.cov[i][j] = cov[i][j]; - } - } - } - - /** - * Sets the covariance matrix of the track. - * @param cov new covariance matrix - */ - public final void setCovariance(double[][] cov) { - this.cov = cov; - } - - /** - * Returns the starting alpha value for the phi-based projections. - * @return alpha value - */ - public double getAlphaMin() { - return alphaMin; - } - - /** - * Returns the alpha value at the end of the helix - * @return alpha value - */ - public double getAlphaMax() { - return alphaMax; - } - - /** - * Returns the alpha value at which the track exits the solenoidal field - * @return alpha value - */ - public double getAlphaSolenoid() { - return alphaSolenoid; - } - - /** - * Calculates the alpha coordinate for a specific point. Alpha is the angle - * from the center point of the helix to the point. For the helix The angle - * should be positive and alpha=0 is the perigee. Returns negative values - * for points before the perigee point. - * @param x x coordinate of a point - * @param y y coordinate of a point - * @return alpha - */ - public double getAlpha(double x, double y) { - // Get the alpha parameter for this point, in the range 0-2*pi - double alpha = AMath.nearestPhiRadians(this.S * (Math.atan2((y - this.yC), (x - this.xC)) - this.phi0) + Math.PI/2.); - - // When dealing with a real space point, alpha can of course be slightly negative - if (alpha > 3./2. * Math.PI) alpha -= 2.*Math.PI; - - return alpha; - } - - /** - * Calculates the alpha coordinate where the helix has the given distance - * from the origin. Alpha is the angle from the center point of the helix to - * the point. The angle is always positive and alpha=0 is the perigee. - * @param rho radius with respect to the origin - * @return alpha - */ - public final double getAlphaCylinder(double rho, double z) { - - double alphaZ, alphaRho; - if (this.cotanTheta == 0) { - alphaZ = Math.PI; - } else { - alphaZ = zVtx + (Math.signum(this.cotanTheta)*z - this.z0) / (this.cotanTheta * this.R + this.dz1); - } - - // We take a circle centered around (0,0) with the requested radius - // (rho) and intersect it with the helix (circle around (xC,yC) with - // radius R. The distance between the centers of the two circles is D. - double D = Math.hypot(this.xC, this.yC); - - // By equating the intersection points in both circles we obtain the - // position of the intersection points as a distance d from (xC,yC) - // along the line from center to center. - double d = (this.R * this.R - rho * rho + D * D) / (2 * D); - - if (d >= this.R) { - // Helix is fully outside the requested radius, return 0. - alphaRho = 0; - } else if (d <= -this.R) { - // Helix is fully inside the requested radius, return pi. - alphaRho = Math.PI; - } else { - // Helix needs to be stopped when it reaches requested radius. - // Now the angle alpha is just the angle between the center-center - // line and the line from (xC,yC) to the intersection point. The - // helix is such that alpha is always taken positive, so it doesn't - // matter which of the two intersection points we take. The cosine - // of alpha is then simply the division of d by the radius of the - // circle R. This method should never return an alpha outside the - // solenoid, for the extrapolation there is getAlphaExtrapolated(). - alphaRho = Math.min(Math.acos(d / this.R), alphaSolenoid); - } - - return Math.min(alphaRho, alphaZ); - } - - /** - * Calculates the pseudo alpha coordinate and if necessary extrapolates - * beyond the curved part up to the given radius. Inside the solenoid this - * method falls back to getAlphaCylinder, so it can be used for any radius. - * The pseudo alpha coordinate is such that the distance along the curve is - * R*alpha also for the straight part. This parameterization allow the - * description of z to remain the same for any alpha. - * @param rho radius to extrapolate to - * @param z distance along the beam axis to extrapolate to - * @return alpha - */ - public final double getAlphaExtrapolated(double rho, double z) { - - // Check if the track actually makes it to the solenoid. - if (this.alphaSolenoid >= Math.PI) { - // If not, return the max alpha inside the tracker instead. - return getAlphaCylinder(rho, z); - } - - // Calculate the coordinates (xL,yL) of the last point inside the solenoid. - double xL = getX(this.alphaSolenoid); - double yL = getY(this.alphaSolenoid); - - // Check if we are actually outside the solenoid at this rho value - if (rho < Math.hypot(xL, yL)) { - // If not, return the normal alpha instead. For tracks that exit the - // solenoid through the endcap this is also fine, z(alpha) is the - // same inside and outside the field. So the max value returned is - // valid either way. - return getAlphaCylinder(rho, z); - } - - double alphaZ, alphaRho; - if (this.cotanTheta == 0) { - alphaZ = Math.PI; - } else { - alphaZ = zVtx + (Math.signum(this.cotanTheta)*z - this.z0) / (this.cotanTheta * this.R + this.dz1); - } - - // Calculate the direction of the track at the last point inside the solenoid, - // this is the direction in which it will be extrapolated through the calorimeters. - double dx = Math.cos(this.phi0 + this.S * this.alphaSolenoid); - double dy = Math.sin(this.phi0 + this.S * this.alphaSolenoid); - - // Now we have for a point on the extrapolated track - // x(alpha) = xL + dx * (alpha-this.alphaCurve) - // y(alpha) = yL + dy * (alpha-this.alphaCurve) - // Setting x^2+y^2 = rho^2 and solving for alpha then gives: - double D = rho*rho - (xL*dy - yL*dx)*(xL*dy - yL*dx); - if (D > 0) { - alphaRho = this.alphaSolenoid - (xL*dx + yL*dy)/this.R + Math.sqrt(D)/this.R; - } else { - return Math.PI; - } - - return Math.min(alphaRho, alphaZ); - } - - /** - * Calculate the distance between a point and the center of the helix. - * @param x x coordinate of the point - * @param y y coordinate of the point - * @return distance between (x,y) and the center of the helix - */ - private double getRadius(double x, double y) { - return Math.hypot(x - xC, y - yC); - } - - /** - * Returns the x coordinate for a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @return x coordinate - */ - public double getX(double alpha) { - // Correct the radius using the values obtained from the fit and calculate x - double localR = R + dr1 * alpha + dr2 * alpha * alpha; - if (alpha <= alphaSolenoid) { - return xC - S * localR * Math.cos(phi0 + S * alpha + Math.PI/2.); - } else { - double xL = xC - S * localR * Math.cos(phi0 + S * alphaSolenoid + Math.PI/2.); - return xL + R*Math.cos(phi0 + this.S * alphaSolenoid) * (alpha-alphaSolenoid); - } - } - - /** - * Returns the y coordinate for a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @return y coordinate - */ - public double getY(double alpha) { - // Correct the radius using the values obtained from the fit and calculate y - double localR = R + dr1 * alpha + dr2 * alpha * alpha; - if (alpha <= alphaSolenoid) { - return yC - S * localR * Math.sin(phi0 + S * alpha + Math.PI/2.); - } else { - double yL = yC - this.S * localR * Math.sin(phi0 + this.S * alphaSolenoid + Math.PI/2.); - return yL + R*Math.sin(phi0 + S * alphaSolenoid) * (alpha-alphaSolenoid); - } - } - - /** - * Returns the rho coordinate for a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @return rho coordinate - */ - public double getRho(double alpha) { - return Math.hypot(getX(alpha), getY(alpha)); - } - - public double getRhoVtx() { - return Math.hypot(xVtx, yVtx); - } - - /** - * Returns the z coordinate for a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @return z coordinate - */ - public double getZ(double alpha) { - // For z we don't use the corrected R, since it was calculated against - // the uncorrected one. - return z0 + cotanTheta * R * alpha + dz1 * alpha; - } - - public double getZVtx() { - return zVtx; - } - - /** - * Returns the phi coordinate of a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @param useVertex calculate phi w.r.t. the primary vertex - * @return phi coordinate - */ - public double getPhi(double alpha, boolean useVertex) { - if (useVertex) { - return AParameterUtilities.phi(getX(alpha), getY(alpha)); - } else { - return Math.toDegrees(Math.atan2(getY(alpha), getX(alpha))); - } - } - - /** - * Return eta coordinate for a point on the helix parameterized by alpha. - * @param alpha helix angular parameter - * @param vsign side (-1/+1) of the split track in the v-plot, 0 for true eta - * @return eta coordinate - */ - public double getEta(double alpha, int vsign) { - double rho = getRho(alpha); - double z = getZ(alpha); - double deta = Math.abs(AProjectionVP.getDeltaEta(rho, z)); - - return AParameterUtilities.eta(z, rho) + vsign*deta; - } - - /** - * Returns an array representing the x coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @return x coordinates - */ - public double[] getX(double alpha1, double alpha2) { - int numPoints = NUM_HELIX_POINTS; - if (alpha2 >= alphaMax && extraX != null) { - numPoints += extraX.length; - } - double[] x = new double[numPoints]; - - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - for (int i=0; i<NUM_HELIX_POINTS; i++) { - x[i] = getX(alpha1 + i*dalpha); - } - - for (int i=0; i<numPoints-NUM_HELIX_POINTS; i++) { - x[NUM_HELIX_POINTS+i] = extraX[i]; - } - - return x; - } - - /** - * Returns an array representing the y coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @return y coordinates - */ - public double[] getY(double alpha1, double alpha2) { - int numPoints = NUM_HELIX_POINTS; - if (alpha2 >= alphaMax && extraY != null) { - numPoints += extraY.length; - } - double[] y = new double[numPoints]; - - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - for (int i=0; i<NUM_HELIX_POINTS; i++) { - y[i] = getY(alpha1 + i*dalpha); - } - - for (int i=0; i<numPoints-NUM_HELIX_POINTS; i++) { - y[NUM_HELIX_POINTS+i] = extraY[i]; - } - - return y; - } - - /** - * Returns an array representing the z coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @return z coordinates - */ - public double[] getZ(double alpha1, double alpha2) { - int numPoints = NUM_HELIX_POINTS; - if (alpha2 >= alphaMax && extraZ != null) { - numPoints += extraZ.length; - } - double[] z = new double[numPoints]; - - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - for (int i=0; i<NUM_HELIX_POINTS; i++) { - z[i] = getZ(alpha1 + i*dalpha); - } - - for (int i=0; i<numPoints-NUM_HELIX_POINTS; i++) { - z[NUM_HELIX_POINTS+i] = extraZ[i]; - } - return z; - } - - /** - * Returns an array representing the rho coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @param signed return signed rho values for use in RZ - * @return rho coordinates - */ - public double[] getRho(double alpha1, double alpha2, boolean signed) { - int numPoints = NUM_HELIX_POINTS; - if (alpha2 >= alphaMax && extraX != null && extraY != null) { - numPoints += extraX.length; - } - double[] rho = new double[numPoints]; - - double sign = 1.; - if (signed) { - AParameter phiPar = parameterStore.get("RZ", "Phi"); - if (phiPar != null) { - double phi = getPhi((alpha1+alpha2)/2, false); - double diff = Math.toRadians(Math.abs(phi - phiPar.getD())); - if (diff > Math.PI / 2. && diff <= 3 * Math.PI / 2.) { - sign = -1.; - } - } else { - logger.error("Could not read RZ cutting plane parameter"); - } - } - - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - for (int i=0; i<NUM_HELIX_POINTS; i++) { - rho[i] = sign * getRho(alpha1 + i*dalpha); - } - - for (int i=0; i<numPoints-NUM_HELIX_POINTS; i++) { - rho[NUM_HELIX_POINTS+i] = sign * Math.hypot(extraX[i], extraY[i]); - } - - return rho; - } - - /** - * Returns an array representing the phi coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @param vplot return all points twice for use in the v-plot - * @return phi coordinates - */ - public double[] getPhi(double alpha1, double alpha2, boolean vplot) { - int numPoints = NUM_HELIX_POINTS; - if (vplot) { - numPoints += NUM_HELIX_POINTS-1; - } else if (alpha2 >= alphaMax && extraX != null && extraY != null) { - numPoints += extraX.length; - } - double[] phi = new double[numPoints]; - - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - for (int i=0; i<NUM_HELIX_POINTS; i++) { - phi[i] = getPhi(alpha1 + i*dalpha, true); - if (vplot) phi[numPoints-i-1] = phi[i]; - } - - if (!vplot) { - for (int i=0; i<numPoints-NUM_HELIX_POINTS; i++) { - phi[NUM_HELIX_POINTS+i] = AParameterUtilities.phi(extraX[i], extraY[i]); - } - } - - // Minimise distance from one point to the next to avoid phi wrapping - // around: use {25, 10, -5} and not {25, 10, 355}. - for (int i=1; i<phi.length; i++) { - phi[i] = AMath.nearestPhiDegrees(phi[i], phi[i-1]); - } - - return phi; - } - - /** - * Returns an array representing the eta coordinates of the helix between - * alpha1 and alpha2. - * @param alpha1 start alpha - * @param alpha2 end alpha - * @return eta coordinates - */ - public double[] getEta(double alpha1, double alpha2) { - double[] eta = new double[2*NUM_HELIX_POINTS - 1]; - double dalpha = (alpha2 - alpha1) / (NUM_HELIX_POINTS-1); - - for (int i=0; i<NUM_HELIX_POINTS; i++) { - double alpha = alpha1 + i*dalpha; - eta[i] = getEta(alpha, -1); - eta[2*NUM_HELIX_POINTS-2-i] = getEta(alpha, +1); - } - - return eta; - } - - /** - * Track momentum at perigee, x component - * @return px - */ - public double pX() { - return this.pt * Math.cos(this.phi0); - } - - /** - * Track momentum at perigee, y component - * @return py - */ - public double pY() { - return this.pt * Math.sin(this.phi0); - } - - /** - * Track momentum at perigee, z component - * @return pz - */ - public double pZ() { - return this.pt * this.cotanTheta; - } - - /** - * Signed transverse momentum at perigee - * @return pt - */ - public double pT() { - return -this.S * this.pt; - } - - public A3Vector p() { - return new A3Vector(pX(), pY(), pZ()); - } - - /** - * Pseudorapidity of track from perigee - * @return eta - */ - public double eta() { - return -Math.log(Math.hypot(cotanTheta, 1.) - cotanTheta); - } - - /** - * Phi of perigee - * @return phi0 - */ - public double phi0() { - return (float)Math.toDegrees(phi0); - } - - /** - * Returns the parameters of this helix in the "old" format. This is still - * used by the AFit class to fit secondary vertices in Atlantis. - * @return helix parameters - */ - public double[] getPar() { // Used by unit tests and AVertexFit - return new double[] { - d0, - z0, - phi0 < 0 ? phi0 + 2*Math.PI : phi0, - cotanTheta, - -S/pt - }; - } - - /** - * Returns the covariance matrix of this helix as a an array of double. - * @return covariance matrix - */ - public double[][] getCovariance() { - return cov; - } - - public double getRhoEndVertex() { - return getRho(alphaMax); - } - - public void setPhiStartByXYPoint(double Vx, double Vy) { - alphaMin = this.getAlpha(Vx, Vy); - } - - public float d0() { - return d0; - } - - public float z0() { - return z0; - } - - public float cotanTheta() { - return cotanTheta; - } - - public double getXc() { - return xC; - } - - public double getYc() { - return yC; - } - - /** - * Helper method for toString, formats a single line of information. - * @param name variable name - * @param value variable value - * @param uncertainty variable uncertainty - * @param units variable units - * @return formatted string - */ - private String formatInfo(String name, double value, double uncertainty, String units) { - return formatInfo(name, String.format("%.3f", value), - uncertainty > 0 ? String.format("%.3f", uncertainty) : null, units); - } - - /** - * Helper method for toString, formats a single line of information. - * @param name variable name - * @param value variable value - * @param uncertainty variable uncertainty - * @param units variable units - * @return formatted string - */ - private String formatInfo(String name, String value, String uncertainty, String units) { - String output = "\n "; - output += name + " = " + value; - if (uncertainty != null) - output += " " + AMath.PLUSMINUS + " " + uncertainty; - if (units != null) - output += " " + units; - - return output; - } - - @Override - public String toString() { - String output = ""; - - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if (simpleOutput > 0) { - if (simpleOutput == 1 || simpleOutput == 3) { - output += formatInfo("PT", pt, 0., "GeV"); - output += formatInfo(AMath.ETA, eta(), 0., null); - output += formatInfo(AMath.PHI, phi0(), 0., AMath.DEGREES); - } - if (simpleOutput == 2 || simpleOutput == 3) { - output += formatInfo("Px", pt*Math.cos(phi0), 0., "GeV"); - output += formatInfo("Py", pt*Math.sin(phi0), 0., "GeV"); - output += formatInfo("Pz", pt*Math.sinh(eta()), 0., "GeV"); - output += formatInfo("Charge", S < 0 ? "+1" : "-1", null, null); - } - - return output; - - } else { - - output += formatInfo("d0", d0, cov != null ? Math.sqrt(cov[0][0]) : 0., "cm"); - output += formatInfo("z0", z0, cov != null ? Math.sqrt(cov[1][1]) : 0., "cm"); - - double pv[] = AParameterUtilities.getPrimaryVertex(); - output += formatInfo("|z0-zVtx|", Math.abs(z0-pv[2]), 0., "cm"); - output += formatInfo("phi0", phi0(), cov != null ? Math.toDegrees(Math.sqrt(cov[2][2])) : 0., AMath.DEGREES); - output += formatInfo(" ", phi0, cov != null ? Math.sqrt(cov[2][2]) : 0., "rad"); - output += formatInfo("cotan(theta)", cotanTheta, cov != null ? Math.sqrt(cov[3][3]) : 0., null); - output += formatInfo(AMath.ETA, eta(), cov != null ? Math.sqrt(cov[3][3] / (cotanTheta * cotanTheta + 1.0)) : 0., null); - output += formatInfo("pT", pT(), 0., "GeV"); - output += formatInfo("p", AMath.getPFromPttL(pt, cotanTheta), 0., "GeV"); - - return output; - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHelixAODData.java b/graphics/AtlantisJava/src/atlantis/data/AHelixAODData.java deleted file mode 100755 index 0c3934033e9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHelixAODData.java +++ /dev/null @@ -1,178 +0,0 @@ -package atlantis.data; - -import atlantis.canvas.AWindow; -import atlantis.event.AEvent; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -public abstract class AHelixAODData extends AAODData -{ - protected AHelix[] h = null; - - AHelixAODData(AHashMap p, AEvent e) - { - super(p,e); - h = new AHelix[numData]; - float[] d0 = new float[numData]; - float[] z0 = new float[numData]; - float[] tl = new float[numData]; - for (int i = 0; i < numData; i++) - { - d0[i] = 0.0f; - z0[i] = 0.0f; - tl[i] = (float) AMath.tanLambda((double)eta[i]); - h[i] = new AHelix(d0[i], z0[i], (float) Math.toDegrees(phi[i]), tl[i], pT[i]); - } - } - - private void drawHelix(AWindow window, AGraphics ag, AProjection2D projection) - { - int drawnAs = parameterStore.get("InDetTrack", "DrawnAs").getI(); - if (drawnAs == ATrackData.DRAW_NEWHELIX) { - - boolean showS3D = parameterStore.get("Data", "S3D").getStatus(); - AParameter shortV = parameterStore.get("VP", "ShortV"); - - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - double alphaMin = h[j].getAlphaExtrapolated(projection.getMinRho(), AHelix.TRACKER_LENGTH); - double alphaMax = h[j].getAlphaExtrapolated(AProjectionVP.getRhoVPlot(), AHelix.TRACKER_LENGTH); - if (shortV.getStatus() && !showS3D) { - alphaMin = alphaMax - shortV.getD() * (alphaMax - alphaMin); - } - - hv[0][i] = h[j].getEta(alphaMin, alphaMax); - hv[1][i] = h[j].getPhi(alphaMin, alphaMax, true); - } - - ag.draw(window.calculateDisplay(new ACoord(hv, index, this, ACoord.POLYLINES))); - - } else { - // borrow the implementation in for tracks - // phi wrap around is done in user coordinates, so we convert to user coordinates, - // do the phi wrap around and convert back to display coordinates - ag.draw(window.calculateDisplay(window.calculateUser( - getVPDisplayHelices(window, projection)).includePhiWrapAround(projection.getName()) - )); - } - } - - // give back Drawable helices - private ADHelix[] getHelices() - { - makeDrawList(); - ADHelix[] tempList = new ADHelix[numDraw]; - - for (int i = 0; i < numDraw; i++) - if (h != null && h[listdl[i]] != null) - { - tempList[i] = new ADHelix(h[listdl[i]]); - if (tempList[i].getAStart() == tempList[i].getAEnd()) - { - tempList[i] = null; - } - } - else - tempList[i] = null; - return tempList; - } - - private ACoord getVPDisplayHelices(AWindow window, AProjection2D projection) - { - boolean drawApex = parameterStore.get("VP", "DrawApex").getStatus(); - ADHelix[] dhelix = getHelices(); - int size = 2 * dhelix.length; - if (drawApex) - size = 3 * dhelix.length; - double[][][] hv = new double[2][size][0]; - int[] index = new int[size]; - int[] indexIn = getDrawList(); - int num = 0; - - for (int j = 0; j < dhelix.length; ++j) - if (dhelix[j] != null) - { - double s1 = dhelix[j].getAStart(); - double s2 = 179.; - - s1 = dhelix[j].intersectWithRadialCylinder(projection.getMinRho(), s1, s2); - double sEnd = dhelix[j].intersectWithCylinder(true, AProjectionVP.getRhoVPlot(), true, AProjectionVP.getZVPlot()); - - s2 = Math.max(Math.min(s2, sEnd), s1); - // if the whole helix is to be drawn (which are unusual - // helices, shorten it a little to avoid wraparound problems - if (s1 == 0. && s2 == 180.) - s2 = 179.; - if (parameterStore.get("VP", "ShortV").getStatus() && !parameterStore.get("Data", "S3D").getStatus()) - s1 = s2 - parameterStore.get("VP", "ShortV").getD() * (s2 - s1); - if (s2 > s1) - { - int signMin = -1; - int signMax = 1; - double h = 0; - double v = 0; - for (int sign = signMin; sign <= signMax; sign += 2) - { - // ugly must change structure at some point - AProjectionVP.sign = sign; - ACoord pointsOnHelix = dhelix[j].drawHelix(window, projection, s1, s2); - hv[0][num] = pointsOnHelix.hv[0][0]; - hv[1][num] = pointsOnHelix.hv[1][0]; - index[num] = indexIn[j]; - h = hv[0][num][hv[0][num].length - 1]; - v = hv[1][num][hv[0][num].length - 1]; - num++; - } - if (drawApex) - { - int a = 3; - int b = 7; - hv[0][num] = new double[] { h - a, h + a, h, h, h - a, h + a }; - hv[1][num] = new double[] { v - b, v - b, v - b, v + b, v + b, v + b }; - index[num] = indexIn[j]; - num++; - } - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP) - { - // since no d0 and z0 data is provided for AOD Electron and Muon - // from event file, they are set to 0 manually, which is not - // compatible with the primary vertex calculated in Atlantis, and - // it will cause a wide and bizarre shape of 'v' drawn in V-Plot. - // So the temparary solution is to set primary vertex to (0,0,0) - // before drawing AOD Electron and Muon in V-Plot, and then restore - // their values after. - double[] primaryVtx=event.getPrimaryVertex(); - parameterStore.get("Event", "XVtx").setD(0.0); - parameterStore.get("Event", "YVtx").setD(0.0); - parameterStore.get("Event", "ZVtx").setD(0.0); - // super.draw(window, ag, projection); - drawHelix(window, ag, projection); - parameterStore.get("Event", "XVtx").setD(primaryVtx[0]); - parameterStore.get("Event", "YVtx").setD(primaryVtx[1]); - parameterStore.get("Event", "ZVtx").setD(primaryVtx[2]); - } - else - { - super.draw(window, ag, projection); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHistogram.java b/graphics/AtlantisJava/src/atlantis/data/AHistogram.java deleted file mode 100755 index 082b97de978..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHistogram.java +++ /dev/null @@ -1,422 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.graphics.ACoord; -import atlantis.utils.AHashMap; -import atlantis.utils.ALogger; -import atlantis.utils.AVector; - -/** - * Used to create, fill, and draw the calorimeter histograms. - */ -public class AHistogram extends AData -{ - private static ALogger logger = ALogger.getLogger(AHistogram.class); - - public static final int UP = 0; - public static final int DOWN = 1; - - public static final int HORIZONTAL = 0; - public static final int VERTICAL = 1; - - public final static int RIGHT = 0; - public final static int LEFT = 1; - - private float leftLimit; - private float rightLimit; - private float gran; - private float granSafety; - private float[] towers; - - private double eta0, z, r; - private double factor; - private AData detector; - - - AHistogram(double leftLimit, double rightLimit, double gran, double factor, AData detector) - { - super(new AHashMap(1).put("numData", 0),detector.getEvent()); - - this.leftLimit = (float) leftLimit; - this.rightLimit = (float) rightLimit; - this.gran = (float) gran; - this.factor = factor; - this.detector = detector; - granSafety = (float) (this.gran * 0.1); - towers = new float[(int) Math.abs(Math.round((rightLimit - leftLimit) / gran))]; - numData = towers.length; - } - - public float getGranularity() - { - return gran; - } - - public int getTowersCount() - { - return towers.length; - } - - public float[] getTowers() - { - return towers; - } - - public void fill(double v1, double v2, double q) - { - int t1 = (int) ((v1 + granSafety - leftLimit) / gran); - int t2 = (int) ((v2 - granSafety - leftLimit) / gran); - int i = -999; - - if (Math.min(t1, t2) < 0 || Math.max(t1, t2) >= towers.length) - { - logger.error("Histogram binning problem " + t1 + " " + t2 + " " + towers.length + " " + v1 + " " + v2); - return; - } - - if (t1 == t2) - towers[t1] += q; - else - for (i = t1; i <= t2; i++) - towers[i] += q / (t2 - t1 + 1); - } - - public void setGranularity(double newGran) - { - AHistogram newHist = new AHistogram(leftLimit, rightLimit, newGran, factor, detector); - - for (int i = 0; i < towers.length; i++) - newHist.fill(leftLimit + i * gran, leftLimit + (i + 1) * gran, towers[i]); - gran = (float) newGran; - towers = newHist.towers; - } - - public void add(AHistogram h) - { - float min = Math.min(leftLimit, h.leftLimit); - float max = Math.max(rightLimit, h.rightLimit); - - AHistogram sum = new AHistogram(min, max, gran, factor, detector); - - // first I add this histogram - for (int i = 0; i < towers.length; i++) - sum.fill(leftLimit + i * gran, leftLimit + (i + 1) * gran, towers[i]); - - // and the "h" histogram - for (int i = 0; i < h.towers.length; i++) - sum.fill(h.leftLimit + i * h.gran, h.leftLimit + (i + 1) * h.gran, h.towers[i]); - - // copy the sum histogram parameters into old ones - towers = sum.towers; - leftLimit = min; - rightLimit = max; - } - - public AHistogram getRegion(double v1, double v2) - { - AHistogram hRegion = new AHistogram(v1, v2, gran, factor, detector); - - int n1 = (int) Math.round((v1 - leftLimit) / gran); - int n2 = (int) Math.round((v2 - leftLimit) / gran); - - for (int i = n1; i < n2; i++) - hRegion.fill(v1 + (i - n1) * gran, v1 + (i - n1 + 1) * gran, towers[i]); - - return hRegion; - } - - private int getCode() - { - int c1, c2; - - if (leftLimit < -eta0) - c1 = 1; - else if (leftLimit > +eta0) - c1 = 3; - else - c1 = 2; - - if (rightLimit < -eta0) - c2 = 1; - else if (rightLimit > +eta0) - c2 = 3; - else - c2 = 2; - - return c1 * c2; - } - - public ACoord[] getRZUser(double z1, double r1, int upORdown) - { - this.z = z1; - this.r = r1; - double expEta0, k = z / r; - int N; - - eta0 = Math.abs(Math.log(k + Math.sqrt(k * k + 1))); - - switch (getCode()) - { - case 1: - return new ACoord[] { getRZVerticalUser(z, upORdown) }; - - case 4: - return new ACoord[] { getRZHorizontalUser(r, upORdown) }; - - case 9: - return new ACoord[] { getRZVerticalUser(z, upORdown) }; - - case 2: - N = (int) Math.abs(Math.round((eta0 - leftLimit) / gran)); - eta0 = leftLimit + N * gran; - expEta0 = Math.exp(eta0); - this.r = 2 * this.z / (expEta0 - 1 / expEta0); - - return new ACoord[] { getRegion(leftLimit, -eta0).getRZVerticalUser(z, upORdown), getRegion(-eta0, rightLimit).getRZHorizontalUser(r, upORdown) }; - - case 6: - N = (int) Math.abs(Math.round((eta0 - leftLimit) / gran)); - eta0 = leftLimit + N * gran; - expEta0 = Math.exp(eta0); - this.r = 2 * this.z / (expEta0 - 1 / expEta0); - - return new ACoord[] { getRegion(leftLimit, +eta0).getRZHorizontalUser(r, upORdown), getRegion(+eta0, rightLimit).getRZVerticalUser(z, upORdown) }; - - case 3: - // FIXME -- round() replaced by floor() here to make sure - // histograms do not end up inside the calorimeter outline. - // They should be right at the edge regardless of the binning - // though. This should be changed. -- EJ - N = (int) Math.abs(Math.floor((eta0 - leftLimit) / gran)); - eta0 = leftLimit + N * gran; - expEta0 = Math.exp(eta0); - this.r = 2 * this.z / (expEta0 - 1 / expEta0); - - return new ACoord[] { getRegion(leftLimit, -eta0).getRZVerticalUser(z, upORdown), getRegion(-eta0, +eta0).getRZHorizontalUser(r, upORdown), getRegion(+eta0, rightLimit).getRZVerticalUser(z, upORdown) }; - - default: - return null; - } - } - - public ACoord getRZHorizontalUser(double r, int place) - { - double[][][] hv = new double[2][towers.length][4]; - int[] index = new int[towers.length]; - double eta, exp1, exp2, zSign, rSign; - - for (int i = 0; i < towers.length; i++) - { - exp1 = Math.exp(leftLimit + i * gran); - exp2 = Math.exp(leftLimit + (i + 1) * gran); - rSign = (int) Math.pow(-1, place); - - eta = leftLimit + (i + 0.5) * gran; - if (eta != 0) - zSign = eta / Math.abs(eta); - else - zSign = 1; - - hv[0][i][0] = zSign * Math.abs(r * (exp1 - 1 / exp1) / 2); - hv[1][i][0] = rSign * r; - - hv[0][i][1] = zSign * Math.abs(r * (exp2 - 1 / exp2) / 2); - hv[1][i][1] = rSign * r; - - hv[0][i][2] = 0; - hv[1][i][2] = 0; - - index[i] = i; - } - - ACoord c = new ACoord(hv, index); - - c.source = this; - return c; - } - - public ACoord getRZVerticalUser(double z, int place) - { - double[][][] hv = new double[2][towers.length][4]; - int[] index = new int[towers.length]; - double exp1, exp2, zSign, rSign; - - for (int i = 0; i < towers.length; i++) - { - exp1 = Math.exp(leftLimit + i * gran); - exp2 = Math.exp(leftLimit + (i + 1) * gran); - rSign = (int) Math.pow(-1, place); - - if ((leftLimit > 0) && (rightLimit > 0)) - zSign = +1; - else - zSign = -1; - - hv[0][i][0] = zSign * z; - hv[1][i][0] = rSign * Math.abs(2 * z / (exp2 - 1 / exp2)); - - hv[0][i][1] = zSign * z; - hv[1][i][1] = rSign * Math.abs(2 * z / (exp1 - 1 / exp1)); - - hv[0][i][2] = 0; - hv[1][i][2] = 0; - - index[i] = i; - } - - ACoord c = new ACoord(hv, index); - - c.source = this; - return c; - } - - protected ACoord getYXUser(double r) - { - int n = towers.length; - double[][][] hv = new double[2][n][4]; - int[] index = new int[n]; - - for (int i = 0; i < n; i++) - { - double phi1 = leftLimit + i * gran; - double phi2 = leftLimit + (i + 1) * gran; - - // first point - hv[0][i][0] = r * Math.cos(phi1); - hv[1][i][0] = r * Math.sin(phi1); - - // second point - hv[1][i][1] = r * Math.sin(phi2); - hv[0][i][1] = r * Math.cos(phi2); - - // third point (the center) - hv[0][i][2] = 0; - hv[1][i][2] = 0; - - index[i] = i; - } - - ACoord c = new ACoord(hv, index); - - c.source = this; - return c; - } - - public ACoord completeTowers(ACoord c) - { - AVector u = new AVector(0, 0); - - for (int i = 0; i < c.hv[0].length; i++) - { - double x0 = (c.hv[0][i][0] + c.hv[0][i][1]) / 2; - double y0 = (c.hv[1][i][0] + c.hv[1][i][1]) / 2; - double f = factor * towers[c.index[i]]; - - u.set(x0 - c.hv[0][i][2], y0 - c.hv[1][i][2]).makeUnitary().scale(f); - - c.hv[0][i][2] = c.hv[0][i][1] + u.dx; - c.hv[1][i][2] = c.hv[1][i][1] + u.dy; - - c.hv[0][i][3] = c.hv[0][i][0] + u.dx; - c.hv[1][i][3] = c.hv[1][i][0] + u.dy; - } - - return c; - } - - protected ACoord getFRUser(double r) - { - int n = towers.length; - double[][][] hv = new double[2][n][4]; - int[] index = new int[n]; - - for (int i = 0; i < n; i++) - { - hv[0][i][0] = r; - hv[1][i][0] = Math.toDegrees(leftLimit + i * gran); - - hv[0][i][1] = r; - hv[1][i][1] = Math.toDegrees(leftLimit + (i + 1) * gran); - - hv[0][i][2] = 0; - hv[1][i][2] = Math.toDegrees(leftLimit + (i + 0.5) * gran); - - index[i] = i; - } - - ACoord c = new ACoord(hv, index); - - c.source = this; - return c; - } - - protected ACoord getFZUser(double z, int alignment) - { - int n = towers.length; - double[][][] hv = new double[2][n][4]; - int[] index = new int[n]; - - double zSign = Math.pow(-1, alignment); - - for (int i = 0; i < n; i++) - { - hv[0][i][0] = zSign * z; - hv[1][i][0] = Math.toDegrees(leftLimit + i * gran); - - hv[0][i][1] = zSign * z; - hv[1][i][1] = Math.toDegrees(leftLimit + (i + 1) * gran); - - hv[0][i][2] = 0; - hv[1][i][2] = Math.toDegrees(leftLimit + (i + 0.5) * gran); - - index[i] = i; - } - - ACoord c = new ACoord(hv, index); - - c.source = this; - return c; - } - - // implementation of AData - public String getParameterGroup() - { - return null; - } - - public String getName() - { - return null; - } - - public String getNameScreenName() - { - return detector.getParameterGroup() + " Histogram Tower"; - } - - protected int internalColor() - { - return 0; - } - - protected void applyCuts() - {} - - public String getHitInfo(int index) - { - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (index: " + index + ")"); - msg.append("\n ET = "); - msg.append(String.format("%.2f",towers[index])); - msg.append(" GeV"); - - return msg.toString(); - } - - public int getIdFromIndex(int index) - { - // Histograms have only an internal ID, override this method here to avoid problems - return index; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHistogramData.java b/graphics/AtlantisJava/src/atlantis/data/AHistogramData.java deleted file mode 100644 index c216d458266..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHistogramData.java +++ /dev/null @@ -1,15 +0,0 @@ -package atlantis.data; - - -import atlantis.graphics.ACoord; - - -public interface AHistogramData { - ACoord[] getYXHistograms(); - ACoord[] getRZHistograms(); - ACoord[] getFRHistograms(); - ACoord[] getFZHistograms(); - ACoord[] getXZHistograms(); - ACoord[] getYZHistograms(); - ACoord[] getVPHistograms(); -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AHitData.java b/graphics/AtlantisJava/src/atlantis/data/AHitData.java deleted file mode 100644 index b27c824660a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AHitData.java +++ /dev/null @@ -1,487 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.colormap.AColorMap; -import atlantis.list.AListManager; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.utils.AHashMap; -import java.util.Vector; -import atlantis.utils.ALogger; - -public abstract class AHitData extends AData -{ - private static ALogger logger = ALogger.getLogger(AHitData.class); - - protected byte[] type; - // sub should be removed at some point - protected int[] sub; - // linked list - protected int[] ll; - protected int[] llStart; - protected int[] llNum; - - // for "new Truth" (2006-08-08) implementation of barcode management - // (association to truth tracks) - protected int[] barcode = null; // old style barcode - protected int[] barcodes = null; // new style barcodes - protected int[] numBarcodes = null; // new style numBarcodes - - @Override - public final int getNumTypes(){ - return 2; - } - - private static final int NOISE = 0; - private static final int GOOD = 1; - - - - AHitData(AHashMap p, AEvent e) - { - super(p,e); - - sub = p.getUnknownIntArray("sub"); - type = new byte[numData]; - ll = new int[numData]; - llStart = new int[getNumTypes()]; - llNum = new int[getNumTypes()]; - - AAssociation assoc = null; - if (p.get("barcode") != null) - { - // old style truth (1-to-1 barcode association) - barcode = p.getUnknownIntArray("barcode"); - - assoc = new AAssociation(getFullName(), "STr", null, barcode, event); - event.getAssociationManager().add(assoc); - } - else if(p.get("barcodes") != null && p.get("numBarcodes") != null) - { - // new style truth (1-to-n barcodes, numBarcodes association) - barcodes = p.getUnknownIntArray("barcodes"); - numBarcodes = p.getUnknownIntArray("numBarcodes"); - - // getFullName() should return hit datatype name + storegate key - assoc = new AAssociation(getFullName(), "STr", numBarcodes, barcodes,event); - event.getAssociationManager().add(assoc); - } - - } // AHitData() --------------------------------------------------------- - - - - public String getHitInfo(int index) - { - StringBuilder r = new StringBuilder(); - if(this.barcode != null) - { - // old style truth association - 1 barcode associated with a hit - r.append("\n barcode = " + barcode[index]); - } - else if(this.barcodes != null && this.numBarcodes != null) - { - // new style truth association - N barcodes associated with a hit - - int[][] barcodes = event.getAssociationManager().get(getFullName(), "STr"); - if(barcodes[index] != null) - { - r.append("\n barcode(s) = "); - for(int i = 0; i < barcodes[index].length; i++) - { - r.append(barcodes[index][i] + " "); - } - } - else - { - r.append("\n no STr associated"); - } - } - - return r.toString(); - - } // getHitInfo() ------------------------------------------------------- - - - - /** - * Calculates actual association via - SiCluster for the datatype - * (SpacePoint (S3D) and TrigSpacePoint) to InDetTrack* (inner detector - * reconstructed track collection) - * @param to String - * @param via String - * @return int[][] - */ - private int[][] calculateAssociation(String to, String via) - { - String infoMsg = " association from: " + this.getName() + " to: " + - to + " via: " + via; - - logger.debug("AData.calculateAssociation()\n" + infoMsg); - - int[][] clusters = event.getAssociationManager().get(getFullName(), via); - int[][] recon = event.getAssociationManager().get(via, to); - AData source = event.get(via); - if(clusters == null || recon == null || source == null) - { - return null; - } - - int[][] ass = new int[numData][]; - - // iterate over all data items of this datatype - for(int i = 0; i < numData; ++i) - { - if(clusters[i] != null && clusters[i].length == 2) - { - // this is a SCT hit which has two clusters - int index1 = source.getIndexFromId(clusters[i][0]); - int index2 = source.getIndexFromId(clusters[i][1]); - if(index1 != -1 && index2 != -1 && - recon[index1] != null && recon[index2] != null) - { - int[] temp = new int[recon[index1].length]; - int matches = 0; - for(int k = 0; k < recon[index1].length; ++k) - { - for(int j = 0; j < recon[index2].length; ++j) - { - if(recon[index1][k] == recon[index2][j]) - { - // IndexOutOfBound protection - if(matches < recon[index1].length) - { - temp[matches] = recon[index1][k]; - matches++; - } - else - { - logger.warn("Association problem:\n" + infoMsg); - } - } - } - } - if(matches == 0) - { - ass[i] = null; - } - else if(matches == temp.length) - { - ass[i] = temp; - } - else - { - int[] dest = new int[matches]; - System.arraycopy(temp, 0, dest, 0, matches); - ass[i] = dest; - } - } - } - else if(clusters[i] != null && clusters[i].length == 1) - { - // this is pixel hit which has one cluster only (second number was - // -1 and was ignored in the datatypes (S3D, TrigS3D) constuctor - - // although this method calculates association via SiCluster - // there are no SiClusters for Pixel and this is a Pixel hit - // -> need to calculate the SpacePoint - Track association directly - // based on Track:hits (which has got id of non-existing SiCluster - // hits) and SpacePoint:cluster which also has Pixel cluster - // references (more see email on 2007-09-20 association problems ...) - // can't use above block as source (SiCluster) doesn't exists, there - // are no SiCluster in Pixel, thus source.getIndexFromId(clusters[i][0]) - // can't work ... - - // AAssociationManager.get(via, to); would return recalculated - // inverted association containing indices. - - // this returns the direct array saved in InDetTrackData() constructor - // AAssociationManager.add(new AAssociation(assocKey, "SiCluster", numHits, hits)); - int[][] directRecon = event.getAssociationManager().getAssociation(to, via).getData(); - - for(int x = 0; x < directRecon.length; x++) - { - if(directRecon[x] != null) - { - for(int y = 0; y < directRecon[x].length; y++) - { - // if the SpacePoint cluster ID is the same as id in - // Track:hits, then it's an associated hit - if(clusters[i][0] == directRecon[x][y]) - { - if(ass[i] == null) - { - // current association, x is associated track index - ass[i] = new int[] { x }; - } - else - { - // some tracks before were already associated - // copy the array and add current track index - int[] temp = new int[ass[i].length + 1]; - System.arraycopy(ass[i], 0, temp, 0, ass[i].length); - temp[ass[i].length] = x; // current association - ass[i] = new int[temp.length]; - System.arraycopy(temp, 0, ass[i], 0, temp.length); - } - - } - } // for(int y = 0; y < directRecon[x].length; y++) - } - } // loop over x (x is all track indices) - } // else - pixel cluster found - - } // for(int i = 0; i < numData; ++i) - loop over all current datatype items - - return ass; - - } // calculateAssociation() --------------------------------------------- - - - - /* - * This method uses clusters array (association with SiCluster) which - * is accessed in calculateAssociation() and creates - * TrigS3D - Track association and S3D - Track association (via SiCluster) - */ - protected void calculateAssociationViaClusters() - { - Vector<String> keys = event.getCollections().get("InDetTrack"); - int[][] recon = null; - int[][] recon2 = null; - AAssociation assoc = null; - String[] trackCollec = null; - - if(keys != null) - { - trackCollec = (String[]) keys.toArray(new String[keys.size()]); - for(int j = 0; j < trackCollec.length; j++) - { - String trackCollecFull = "InDetTrack" + trackCollec[j]; - recon = event.getAssociationManager().get(getFullName(), trackCollecFull); - recon2 = calculateAssociation(trackCollecFull, "SiCluster"); - if(recon != null && recon2 != null) - { - for(int i = 0; i< numData; i++) - { - if(recon2[i] != null) - { - // using array reference here - association array is corrected - recon[i] = recon2[i]; - } - } - assoc = event.getAssociationManager().getAssociation(getName(), trackCollecFull); - event.getAssociationManager().add(assoc.invert()); - } - } - } - - } // calculateAssociationViaClusters() --------------------------------- - - - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if (colorFunction == 0) - { - colorByConstant(); - } - else if (colorFunction == 1) - { - colorBy("STr"); - } - else if (colorFunction == 2) - { - colorBy(getReconstructedTracks()); - } - else if (colorFunction == 3) - { - colorBy(sub); - } - - return 3; - - } // internalColor() ---------------------------------------------------- - - - - protected String getSegments() - { - AEnumeratorParameter key = (AEnumeratorParameter) parameterStore.get("InDetSegment", "InDetSegmentCollections"); - - return "InDetSegment" + key.getCurrentText(); - } - - - - public void constructDefaultDrawlist() - { - // make seperate lists of noise and good hits - makeNoiseList(0, 0); - - if (!parameterStore.get("CutsATLAS", "ByList").getStatus()) - { - // put noise and/or good hits in drawlist according to HitType - // parameter - // if both are drawn noise is drawn first - makeDrawList(parameterStore.get("CutsInDet", "HitType").getI()); - - // if some hits are on a list they must be drawn last - int[][] temp = AListManager.getInstance().getColorMapping(this); - int[] index = temp[0]; - int[] ctemp = temp[1]; - if (index.length > 0) - { - int[] c = new int[numData]; - final int NONE = -999; - // color is not used at this time - for (int i = 0; i < c.length; ++i) - c[i] = NONE; - - for (int i = 0; i < index.length; ++i) - c[index[i]] = ctemp[i]; - - int[] newListdl = new int[numData]; - int num = 0; - for (int t = 0; t < getNumTypes(); t++) - { - for (int i = 0; i < numDraw; ++i) - if (t == type[listdl[i]] && c[listdl[i]] == NONE) - newListdl[num++] = listdl[i]; - for (int i = 0; i < numDraw; ++i) - if (t == type[listdl[i]] && c[listdl[i]] != NONE && c[listdl[i]] != AColorMap.INVISIBLE) - newListdl[num++] = listdl[i]; - } - listdl = newListdl; - numDraw = num; - } - } - else - { - boolean[] selected = AListManager.getInstance().getSelection(this); - numDraw = 0; - for (int t = 0; t < getNumTypes(); t++) - for (int i = 0; i < numData; ++i) - if (t == type[i] && selected[i]) - listdl[numDraw++] = i; - } - } - - - /** - * define noise and good hits type = 0 means noise - * noise hits - hits associated neither with Track not STr - * good hits - hits associated either with Track or with STr - */ - protected void setType() - { - int[][] assocSTr = event.getAssociationManager().get(getFullName(), "STr"); - int[][] assocRTr = event.getAssociationManager().get(getName(), getReconstructedTracks()); - - for (int i = 0; i < numData; i++) - { - if((assocSTr != null && assocSTr[i] != null) || - (assocRTr != null && assocRTr[i] != null)) - { - type[i] = 1; - } - else - { - type[i] = 0; - } - } - - } // setType() ---------------------------------------------------------- - - - - protected void makeNoiseList(int a, int b) - { - setType(); - - for (int i = 0; i < getNumTypes(); i++) - { - llStart[i] = -1; - llNum[i] = 0; - } - - for (int i = numData - 1; i >= 0; i--) - { - ll[i] = llStart[type[i]]; - llStart[type[i]] = i; - llNum[type[i]]++; - } - } - - private void makeDrawList(int hitType) - { - int start, end; - - numDraw = 0; - if (hitType == 0) - { - start = end = NOISE; - } - else if (hitType == 1) - { - start = end = GOOD; - } - else - { - start = NOISE; - end = GOOD; - } - - for (int i = start; i <= end; i++) - { - int n = llStart[i]; - - for (int j = 0; j < llNum[i]; j++) - { - listdl[numDraw++] = n; - n = ll[n]; - } - } - } - - - - public int[] getType(int[] dl) - { - int[] temp = new int[dl.length]; - - for (int i = 0; i < temp.length; i++) - temp[i] = type[dl[i]]; - return temp; - } - - - - /** - * cut hits if connected/unconnected to simulated tracks - */ - protected void cutSimulatedTracks() - { - int cutOption = parameterStore.get("CutsInDet", "HitsBySTr").getI(); - cutByAssociationTo("STr", getFullName(), cutOption); - } - - /** - * cut hits if connected/unconnected to reconstructed tracks - */ - protected void cutReconstructedTracks() - { - int cutOption = parameterStore.get("CutsInDet", "HitsByRTr").getI(); - cutByAssociationTo(getReconstructedTracks(), getName(), cutOption); - } - - /** - * cut hits if connected/unconnected to reconstructed segments - */ - protected void cutSegments() - { - int cutOption = parameterStore.get("CutsInDet", "HitsBySegment").getI(); - cutByAssociationTo(getSegments(), getName(), cutOption); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AInDetSegmentData.java b/graphics/AtlantisJava/src/atlantis/data/AInDetSegmentData.java deleted file mode 100755 index e7d97508d64..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AInDetSegmentData.java +++ /dev/null @@ -1,30 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.utils.AHashMap; - -/** - * - * @author Eric Jansen - */ -public class AInDetSegmentData extends ASegmentData { - - /** Creates a new instance of AInDetSegmentData */ - AInDetSegmentData(AHashMap p, AEvent e) { - super(p,e); - - event.getAssociationManager().add(new AAssociation(getFullName(), "TRT", numHits, hits,event)); - } - - public String getParameterGroup() { - return "InDetSegment"; - } - - public String getName() { - return "InDetSegment"; - } - - public String getNameScreenName() { - return "InDetSegment"; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AInDetTrackData.java b/graphics/AtlantisJava/src/atlantis/data/AInDetTrackData.java deleted file mode 100644 index 05e5bda343d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AInDetTrackData.java +++ /dev/null @@ -1,164 +0,0 @@ -package atlantis.data; - -import atlantis.event.AAssociation; -import atlantis.event.AEvent; -import atlantis.event.AData; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; - -/** - * - * @author Eric Jansen - */ - -public class AInDetTrackData extends ATrackData { - - private int[] author = null; - - protected int numBLayerHits[] = null; - protected int numPixelHits[] = null; - protected int numSCTHits[] = null; - protected int numTRTHits[] = null; - - private static ALogger logger = ALogger.getLogger(ATrackData.class); - - /** Creates a new instance of AInDetTrackData */ - AInDetTrackData(AHashMap p, AEvent e) throws AAtlantisException { - super(p,e); - - author = p.getUnsureIntArray("trackAuthor"); //Change added 17/02/2010 - - numBLayerHits = p.getUnsureIntArray("nBLayerHits"); - numPixelHits = p.getUnsureIntArray("nPixHits"); - numSCTHits = p.getUnsureIntArray("nSCTHits"); - numTRTHits = p.getUnsureIntArray("nTRTHits"); - - String assocKey = getFullName(); - if (p.get("numHits") != null) { - int[] numHits = p.getIntArray("numHits"); - int[] hits = p.getIntArray("hits"); - - // This was added into TrkJiveXML-00-01-24, July 2010. For backwards - // compatibilty, we can also fill these arrays from the association - if (numPixelHits == null && numSCTHits == null && numTRTHits == null) { - numPixelHits = new int[numData]; - numSCTHits = new int[numData]; - numTRTHits = new int[numData]; - for (int i=0, num=0; i<numData; i++) { - numPixelHits[i] = numSCTHits[i] = numTRTHits[i] = 0; - - for (int j=0; j<numHits[i]; j++, num++) { - try { - // Negative identifiers are pixels, the rest we can decode using AIdHelper - if (numHits[i] > 0 && (hits[num] < 0 || AIdHelper.subDetector(hits[num]) == 2)) { - switch(hits[num] < 0 ? 1 : AIdHelper.indetPart(hits[num])) { - case 1: - numPixelHits[i]++; - break; - case 2: - numSCTHits[i]++; - break; - case 3: - numTRTHits[i]++; - break; - } - } - } catch (AAtlantisException ex) { - logger.warn("Problem decoding hit identifier: " + ex.getMessage()); - } - } - } - } - - int[] driftSign = null; - int[] isOutlier = null; - if (p.get("driftSign") != null && p.get("isOutlier") != null) { - driftSign = p.getIntArray("driftSign"); - isOutlier = p.getIntArray("isOutlier"); - } - - event.getAssociationManager().add(new AAssociation(assocKey, "TRT", numHits, hits,event)); - if (driftSign != null) { - event.getAssociationManager().add(new AAssociation(assocKey + "Drift", "TRT", numHits, driftSign,event)); - } - if (isOutlier != null) { - event.getAssociationManager().add(new AAssociation(assocKey + "Outlier", "TRT", numHits, isOutlier,event)); - } - event.getAssociationManager().add(new AAssociation(assocKey, "SiCluster", numHits, hits,event)); - event.getAssociationManager().add(new AAssociation(assocKey, "PixelCluster", numHits, hits,event)); - - - // although these two following associations directly doesn't exist - // in the event file (e.g. Track:numHits,hits - S3D:id) because it - // is calculated over SiCluster, the association has to be - // established here and corrected later on in - // AS3D.finalizeConstruction() -> AHitData.calculateAssociationViaClusters() - event.getAssociationManager().add(new AAssociation(assocKey, "S3D", numHits, hits,event)); - event.getAssociationManager().add(new AAssociation(assocKey, "TrigS3D", numHits, hits,event)); - } - } - - public String getParameterGroup() { - return "InDetTrack"; - } - - public String getName() { - return "InDetTrack"; - } - - public String getNameScreenName() { - return "InDetTrack"; - } - - public String getHitInfo(int index) { - String msg = super.getHitInfo(index); - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) - return getNameScreenName()+" index: " + index + ((h!=null)?h[index].toString():""); // output for Minerva - if (numBLayerHits != null) { - msg += "\n numBLayerHits = " + numBLayerHits[index]; - } - if (numPixelHits != null) { - msg += "\n numPixelHits = " + numPixelHits[index]; - } - if (numSCTHits != null) { - msg += "\n numSCTHits = " + numSCTHits[index]; - } - if (numTRTHits != null) { - msg += "\n numTRTHits = " + numTRTHits[index]; - } - return msg; - } - - protected void applyCuts() { - cut("CutsInDet", "RTrIndex", " RTr id", id); - cut("CutsInDet", "trackAuthor", " Author", author); - - if (numBLayerHits != null) { - cut("CutsInDet", "NumBLayer", "Num BLayer", numBLayerHits); - } - if (numPixelHits != null) { - cut("CutsInDet", "NumPixel", "Num Pixel", numPixelHits); - } - if (numSCTHits != null) { - cut("CutsInDet", "NumSCT", "Num SCT", numSCTHits); - } - if (numTRTHits != null) { - cut("CutsInDet", "NumTRT", "Num TRT", numTRTHits); - } - - super.applyCuts(); - - if (polylinedTrack && parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_HELIX) { - // if reconstructed tracks are drawn as helices, check for tracks - // with rhoVertex beyond the diameter of InDet and don't draw those - // super.rhoVertex array was calculated only if Track provided - // polyline data, otherwise rhoVertex is null and this method would - // cause NullPointerException - super.cutRhoVertexAfterInDetRadius(); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AJetData.java b/graphics/AtlantisJava/src/atlantis/data/AJetData.java deleted file mode 100644 index d2e1743a92b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AJetData.java +++ /dev/null @@ -1,782 +0,0 @@ -package atlantis.data; - -import java.util.ArrayList; -import java.util.List; - -import atlantis.event.AAssociation; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.event.AObjectsAssociation; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import atlantis.utils.A3Vector; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.canvas.AWindow; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.graphics.AGraphics; - -/** - * Jet class - class handling multiple Jet datatypes - * (multiple collections) from various Jet alrogithms - * (JetRecJet, ParticleJet, etc) - */ -public class AJetData extends AData -{ - protected float[] eT; - protected float[] eta; - protected float[] phi; - protected float[] mass; - protected float[] pT; - protected float[] px; - protected float[] py; - protected float[] pz; - //Transition variable to ensure backwards compatability - protected boolean has4Vect = false; - //variables for jet quality information - protected float[] quality = null; - protected float[] qualityLAr = null; - protected float[] qualityTile = null; - protected float[] time = null; - protected float[] timeClusters = null; - protected int[] n90cells = null; - protected int[] n90const = null; - protected float[] hecf = null; - protected float[] emfrac = null; - protected float[] tileGap3f = null; - protected float[] fcorCell = null; - protected float[] fcorDotx = null; - protected float[] fcorJet = null; - protected float[] fcorJetForCell = null; - protected int[] nbadcells = null; - protected float[] fracSamplingMax = null; - protected float[] sMax = null; - protected float[] OutOfTimeEfrac = null; - protected float[] isGood = null; - protected float[] isBad = null; - protected float[] isUgly = null; - protected String[] bTagName = null; //new bTagname variable - protected float[] bTagValue = null; //new bTagValue variable - protected float[] weight = null; - protected float[] jvf = null; - //Transition variable to ensure backwards compatability - protected boolean hasJvf = true; - - String[] caloSample = { "EMB0", "EMB1", "EMB2", "EMB3", "EME0", "EME1", "EME2", "EME3", "HEC0", "HEC1", "HEC2", "HEC3", "TileBar0", "TileBar1", "TileBar2", "TileGap1", "TileGap2", "TileGap3", "TileExt0", "TileExt1", "TileExt2", "FCAL0", "FCAL1", "FCAL2", "Unknown" }; - - - AJetData(AHashMap p, AEvent e) - { - super(p,e); - if (p.get("et") != null) - { - eT = p.getFloatArray("et"); - } - else - { - eT = p.getFloatArray("pt"); - } - - - if(p.get("mass") != null) - { - mass = p.getFloatArray("mass"); - px = p.getFloatArray("px"); - py = p.getFloatArray("py"); - pz = p.getFloatArray("pz"); - has4Vect = true; - } - eta = p.getFloatArray("eta"); - phi = p.getFloatArray("phi"); - - if(p.get("emfrac") != null) - { - emfrac = p.getFloatArray("emfrac"); - } - - float forwardJVF = 10.0f; - float initJVF = 1.0f; - if(p.get("jvf") != null) - { - jvf = p.getFloatArray("jvf"); - for(int i=0; i<(jvf.length); i++) - { - if( jvf[i] == -1.0 ) - jvf[i] = forwardJVF; // forward-jets have jvf=-1 - } - } - else // dummy values for older xml-files - { - hasJvf = false; - jvf = new float[eta.length]; // for array size - for(int i=0; i<(jvf.length); i++) - { - jvf[i] = initJVF; // need to assign dummy value to allow cut - } - } - - //Getting BTagNames and BTagValues from xml - if(p.get("bTagValue") != null) - { - bTagValue = p.getFloatArray("bTagValue"); - bTagName = p.getUnsureStringArray("bTagName"); - weight = new float[eta.length]; - for(int i=0; i<(eta.length); i++) - weight[i] = bTagValue[i*(bTagValue.length/eta.length) + 0]; - // 0 is the first instance of JetFitterNNComb - // we take this as default for now... - } - - if(has4Vect) - { - float[] pTtemp = new float[mass.length]; - for(int i = 0; i < mass.length; i++){ - pTtemp[i] = (float) (new A4Vector(px[i],py[i],pz[i],mass[i]) ).getPt(); - } - pT = pTtemp; - } - - if(p.get("quality") != null) - quality = p.getFloatArray("quality"); - if(p.get("qualityLAr") != null){ - qualityLAr = p.getFloatArray("qualityLAr"); - qualityTile = p.getFloatArray("qualityTile"); - time = p.getFloatArray("time"); - timeClusters = p.getFloatArray("timeClusters"); - n90cells = p.getIntArray("n90cells"); - n90const = p.getIntArray("n90const"); - hecf = p.getFloatArray("hecf"); - tileGap3f = p.getFloatArray("tileGap3f"); - fcorCell = p.getFloatArray("fcorCell"); - fcorDotx = p.getFloatArray("fcorDotx"); - fcorJet = p.getFloatArray("fcorJet"); - fcorJetForCell = p.getFloatArray("fcorJetForCell"); - nbadcells = p.getIntArray("nbadcells"); - fracSamplingMax = p.getFloatArray("fracSamplingMax"); - sMax = p.getFloatArray("sMax"); - OutOfTimeEfrac = p.getFloatArray("OutOfTimeEfrac"); - isGood = p.getFloatArray("isGood"); - isBad = p.getFloatArray("isBad"); - isUgly = p.getFloatArray("isUgly"); - } - - String assocKey = getFullName(); - // create Jet - Calo associations if cells information is available - if(p.get("numCells") != null) - { - event.getAssociationManager().add(new AAssociation(assocKey, "LAr", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - event.getAssociationManager().add(new AAssociation(assocKey, "TILE", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - event.getAssociationManager().add(new AAssociation(assocKey, "HEC", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - event.getAssociationManager().add(new AAssociation(assocKey, "FCAL", p.getIntArray("numCells"), p.getIntArray("cells"),event)); - } - - if (p.get("clusterKey") != null) - { - int[] clusterLinkCount = p.getUnsureIntArray("clusterLinkCount"); - event.getAssociationManager().add(new AObjectsAssociation(assocKey, "Cluster", - p.getStringArray("clusterKey"), p.getIntArray("clusterIndex"), clusterLinkCount, event)); - } - if (p.get("trackKey") != null) - { - int[] trackLinkCount = p.getUnsureIntArray("trackLinkCount"); - event.getAssociationManager().add(new AObjectsAssociation(assocKey, "Track", - p.getStringArray("trackKey"), p.getIntArray("trackIndex"), trackLinkCount, event)); - } - } - - - public String getParameterGroup() - { - return "Jet"; - } - - - public String getName() - { - return "Jet"; - } - - - public String getNameScreenName() - { - return "Jet"; - } - - - public float getET(int index) - { - return eT[index]; - } - - - public float getEta(int index) - { - return eta[index]; - } - - - public float getPhi(int index) - { - return phi[index]; - } - - - public float[] getET() - { - return eT; - } - - - public float[] getEta() - { - return eta; - } - - - public float[] getPhi() - { - return phi; - } - - public float[] getPt() - { - if(has4Vect){ - return pT; - }else{ - return eT; - } - } - - @SuppressWarnings("unused") - // TODO: these cuts are from Nikolina - // using the wrong indices? - private float[] getfCorJetLevel() - { - // Tom - problem here with inconsistent indices? - // this code is not used yet, but the Jet people want it eventually - // i is the total data index, but we need to get that from the draw list, listdl[i]. - float[] temp = new float[numDraw]; - for (int i = 0; i < numDraw; i++) - temp[i] = (float) (fcorCell[i] - fcorJet[i]); - return temp; - } - - @SuppressWarnings("unused") - // TODO: these cuts are from Nikolina - // using the wrong indices? - private float[] getHECfQ() - { - float[] temp = new float[numDraw]; - for (int i = 0; i < numDraw; i++) - temp[i] = (float) (Math.abs(hecf[i]) + Math.abs(quality[i])); - return temp; - } - - /* - * Return an ordered list of the btaggers available in the event. - * If using an older XML file without btaggers available, an empty list is returned. - * Ordering is important to be consistent with the BTag Weights, which are ordered the same. - */ - public List<String> getBTaggers() { - - List<String> taggers = new ArrayList<String>(); - - if(bTagName == null) - return taggers; - - for(String tagger : bTagName) { - if(!taggers.contains(tagger)) { - taggers.add(tagger); - } - } - - return taggers; - } - - protected void applyCuts() - { - cutIndex(); - cut("CutsObjects", "JetET", " |ET|", eT); - cutPhi(phi); - cutEta(eta); - cut("CutsObjects", "JetEMfraction", " |EM fraction|", emfrac); - cut("CutsObjects", "JetVxFraction", " |Vx Fraction|", jvf); - - /* Placeholder for jet quality cuts (added by Nikolina Ilic) - cut("CutsObjects", "JetTime", " |dt(jet,coll)|", time); - cut("CutsObjects", "JetTileGap3F", " TileGap3F", tileGap3f); - cut("CutsObjects", "JetfCORRcell", " Already corrected cell level correction", fcorCell); - cut("CutsObjects", "JetfCORRjetLevel", " Correction by jet level estimation", getfCorJetLevel()); - cut("CutsObjects", "JetHECfQ", " HECf-Quality", getHECfQ()); - cut("CutsObjects", "JetOOTEf", " Out-Of-Time Energy frac", OutOfTimeEfrac); - */ - } - - public void colorbyBJets() { - //Initialy color all jets with constant color - for (int i = 0; i < numData; i++) { - int constantColor2 = parameterStore.get("Jet", "Constant").getI(); - color[i] = (byte) constantColor2; - } - - //Read necessary information to colour Jets - int bTagValue_user = parameterStore.get("CutsObjects", "JetBTagger").getI(); //getting user B-tagger preference - int constantColor = parameterStore.get("BJet", "Constant").getI(); - int constantColor2 = parameterStore.get("Jet", "Constant").getI(); - - //if b-tagging information is contained in xml file - if(bTagValue != null) { - int mod = bTagValue.length / eta.length; //Number of Btaggers - eta.length is the number of Jets - double s = parameterStore.get("CutsObjects", "JetBTagweight").getD(); - for (int i = 0; i < eta.length; i++) { - color[i] = (byte) constantColor2; - if(bTagValue[bTagValue_user + i*mod]>s){ - color[i] = (byte) constantColor; - } - } - } - } - - - - - protected int internalColor() - { - int colorFunction = APar.instance().get(PARAMETER_GROUP, "ColorFunction").getI(); - - if (colorFunction == 0) - { - colorByConstant(); - } - else if(colorFunction == 1) - { - colorByIndex(); - } - else if(colorFunction == 2) - { - colorByCollection(); - } - else if (colorFunction == 3) - { - colorbyBJets(); - } - return 3; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",eT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",eT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",eT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",eT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String msg; - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - String printPt = ""; - if(has4Vect){ - printPt = "\n PT = " + String.format("%.3f",pT[index]) + " GeV"; - } - msg = getNameScreenName() + " (id: " + id[index] + " index: " + index + ")\n" + - " storegate key: " + sgKey + printPt + "\n ET = " + - String.format("%.3f",eT[index]) + " GeV" + "\n E = " + - String.format("%.3f",Math.abs(eT[index] / Math.cos(AMath.lambda(eta[index])))) + - " GeV" + "\n " + AMath.ETA + " = " + String.format("%.3f",eta[index]) + "\n " + - AMath.PHI + " = " + String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)"; - - if(isGood != null) msg += "\n Selection: isGood =" + isGood[index] + "(isBad = " + isBad[index] + ", isUgly = " + isUgly[index] + ")"; - if(hecf != null) msg += "\n hecf = " + String.format("%.2f",hecf[index])+ ", n90cells = " + n90cells[index] + " (n90const = " + n90const[index] + ")"; - if (emfrac != null) msg += "\n emfrac = " + String.format("%.2f",emfrac[index]); - if (quality != null) msg += "\n quality = " + String.format("%.2f",quality[index]); - if (qualityLAr != null) msg += "(qLAr = " + String.format("%.2f",qualityLAr[index]) + ")"; - - if (hasJvf) - { - msg += "\n jvf = " + String.format("%.2f",jvf[index]); - } - else - { - msg += "\n jvf n/a "; - } - if (weight != null) msg += " b-weight = " + String.format("%.2f",weight[index]); - // Displaying bTagValues and bTagnames to the outputscreen - if(bTagValue != null) - { - //calculating "multiple" number - int Div = (bTagValue.length)/(eta.length); - msg += "\n b-Taggers: "; - for (int s=0;s<Div;s++) - { - msg += bTagName[index*Div + s] + "=" + String.format("%.2f",bTagValue[index*Div + s]) + ", "; - } - } - if (time != null) msg += "\n time = " + String.format("%.2f",time[index]) + " ns (clus time = " + String.format("%.2f",timeClusters[index]) + " ns)"; - if (OutOfTimeEfrac != null) msg += "\n Out-Of-Time Energy fraction = " + String.format("%.2f", OutOfTimeEfrac[index]); - if (fracSamplingMax != null) msg += "\n fracSamplingMax = " + String.format("%.2f",fracSamplingMax[index]) + " (sMax = " + caloSample[(int) sMax[index]] + ")"; - if (tileGap3f != null) msg += "\n tileGap3f = " + String.format("%.2f",tileGap3f[index]) + ", fcorCell=" + String.format("%.2f",fcorCell[index]) + ", fcorJet=" + String.format("%.2f",fcorJet[index]); - if (fcorDotx != null) msg += "\n fcorDotx=" + String.format("%.2f",fcorDotx[index]) + " (not implemented yet)"; - - return msg; - } - - // info on Jet collections contained in v-plot rubberband selection - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumE = 0.; - double sumEt = 0.; - - for (int i = 0; i < numDraw; ++i) - { - sumEt += Math.abs(eT[listdl[i]]); - sumE += Math.abs(eT[listdl[i]] / Math.cos(AMath.lambda(eta[listdl[i]]))); - } - - String key = getFullName(); - String msg = numDraw + " " + (key != null ? "" + key : getNameScreenName()); - msg += " sum(ET) = " + String.format("%.1f",sumEt) + " sum(E) = " + String.format("%.1f",sumE); - - return msg; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - if(has4Vect){ - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM(pT[k],eta[k],phi[k],mass[k]); - sum.add(start); - } - }else{ - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A3Vector start = A3Vector.fromRhoPhiZ(0., 0., 0.); - double tL = AMath.tanLambda(eta[k]); - A3Vector stop = A3Vector.fromRhoPhiZ(1., phi[k], tL); - A3Vector v = (stop.subtract(start)).normalize(); - double p = eT[k] / Math.sqrt(1. - v.z * v.z); - sum.add(new A4Vector(v.scale(p), 0.)); - } - } - return sum; - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if (projection instanceof AProjectionVP) - { - ACoord centers = window.calculateDisplay(getUser(projection)); - int[] drawlist = centers.index; - double eLimit = 0.05; - int numPoints = 25; - double[][][] hv = new double[2][drawlist.length][numPoints]; - - for (int i = 0; i < drawlist.length; ++i) - { - int list = drawlist[i]; - int jetMode = parameterStore.get("VP", "Jet").getI(); - double e; - if (jetMode == 0) - // showing jet in ET - e = Math.abs(eT[list]); - else - // showing jet in E - e = Math.abs(eT[list] / Math.cos(AMath.lambda(eta[list]))); - int d = (int) (Math.sqrt((e / eLimit) / Math.PI)); - if (d == 0) - d = 1; - for (int j = 0; j < numPoints; j++) - { - hv[0][i][j] = centers.hv[0][0][i] + d * Math.cos(Math.PI * 2 * j / (numPoints - 1)); - hv[1][i][j] = centers.hv[1][0][i] + d * Math.sin(Math.PI * 2 * j / (numPoints - 1)); - } - } - ag.draw(new ACoord(hv, drawlist, this, ACoord.POLYLINES)); - } - else - { - super.draw(window, ag, projection); - } - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - protected ACoord getVPUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = eta[list]; - v[i] = Math.toDegrees(phi[list]); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - @Override - protected ACoord getYXUser() - { - int coneSmooth = 20; - makeDrawList(); - double[][][] hv = new double[2][numDraw][(2*coneSmooth)]; - int[] index = new int[numDraw]; - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - - double dphi = 0.4; - - if(sgKey.contains("Kt6")) - dphi = 0.6; - if(sgKey.contains("Kt1")) - dphi = 1.0; - - double rhoMinus = parameterStore.get("Jet","Innerdrawradius").getD(); - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double s = parameterStore.get("Jet", "Scale").getD(); - double rhoMax = s*1000; - if (0==s) return ACoord.NO_POLYLINES; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - - //if no composite particles increase jet size - //Vector keys = (Vector) event.getCollections().get("CompositeParticle"); - //if (keys == null || !parameterStore.get("Data", "CompositeParticle").getStatus()) rhoMax=1000;//1800; - - double rhoPlus = rhoMax; - if(Math.abs(eT[list]) < maxEnergy) { - if(parameterStore.get("Jet", "ScaleType").getI() == 1) //sq root - rhoPlus = rhoMinus + rhoMax * (Math.sqrt (Math.abs(eT[list])/maxEnergy)); - if(parameterStore.get("Jet", "ScaleType").getI() == 0) // linear - rhoPlus = rhoMinus + rhoMax * (Math.abs(eT[list])/maxEnergy); - } - - double vx = parameterStore.get("Event", "XVtx").getD(); - double vy = parameterStore.get("Event", "YVtx").getD(); - - double h_shift = vx; - double v_shift = vy; - - // the loop interpolates between the inner and outer edge of the jet to draw the arc - - // draw the outer arc - for(int j=0; j<coneSmooth; j++){ - float f = ((float)j)/(coneSmooth-1); - hv[0][i][j] = h_shift + (rhoPlus) * Math.cos(((1-f)*phiPlus + (f)*phiMinus)); - hv[1][i][j] = v_shift + (rhoPlus) * Math.sin(((1-f)*phiPlus + (f)*phiMinus)); - } - - // draw the inner arc - for(int j=coneSmooth; j<(2*coneSmooth); j++){ - float f = ((float)j-coneSmooth)/(coneSmooth-1); - hv[0][i][j] = h_shift + (rhoMinus) * Math.cos(((1-f)*phiMinus + (f)*phiPlus)); - hv[1][i][j] = v_shift + (rhoMinus) * Math.sin(((1-f)*phiMinus + (f)*phiPlus)); - } - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.TRANSPARENT_POLYGONS); - } - - protected ACoord getFRUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - - double dphi = 0.4; - - if(sgKey.contains("Kt6")) - dphi = 0.6; - if(sgKey.contains("Kt1")) - dphi = 1.0; - - double s = parameterStore.get("Jet", "Scale").getD(); - double rhoMax = s*1500; - double rhoMinus = parameterStore.get("Jet","Innerdrawradius").getD(); - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - if (0==s) return ACoord.NO_POLYLINES; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - - //if no composite particles increase jet size - //Vector keys = (Vector) event.getCollections().get("CompositeParticle"); - //if (keys == null || !parameterStore.get("Data", "CompositeParticle").getStatus()) rhoMax=1000;//1800; - - double rhoPlus = rhoMinus + rhoMax; - if(Math.abs(eT[list]) < maxEnergy) { - if(parameterStore.get("Jet", "ScaleType").getI() == 1) //sq root - rhoPlus = rhoMinus + rhoMax * (Math.sqrt (Math.abs(eT[list])/maxEnergy)); - if(parameterStore.get("Jet", "ScaleType").getI() == 0) // linear - rhoPlus = rhoMinus + rhoMax * (Math.abs(eT[list])/maxEnergy); - } - - hv[0][i][0] = rhoMinus; - hv[1][i][0] = Math.toDegrees(phiMinus); - - hv[0][i][1] = rhoMinus; - hv[1][i][1] = Math.toDegrees(phiPlus); - - hv[0][i][2] = rhoPlus; - hv[1][i][2] = Math.toDegrees(phiPlus); - - hv[0][i][3] = rhoPlus; - hv[1][i][3] = Math.toDegrees(phiMinus); - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.TRANSPARENT_POLYGONS).includePhiWrapAround("FR"); - } - - protected double Theta (double eta, int rSign) - { - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta))) * 2.0; - if ((eta > 0.) && (rSign == -1)) - theta = 2 * Math.PI - theta; - else if ((eta < 0.) && (rSign == -1)) - theta += Math.PI; - else if ((eta < 0.) && (rSign == 1)) - theta = Math.PI - theta; - - return theta; - } - - protected ACoord getRZUser() - { - int coneSmooth = 20; - double s = parameterStore.get("Jet", "Scale").getD(); - if (0==s) return ACoord.NO_POLYLINES; - makeDrawList(); - double[][][] hv = new double[2][numDraw][(2*coneSmooth)]; - int[] index = new int[numDraw]; - - double innerRadius = parameterStore.get("Jet","Innerdrawradius").getD(); - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - - double deta = 0.4; - - if(sgKey.contains("Kt6")) - deta = 0.6; - if(sgKey.contains("Kt1")) - deta = 1.0; - - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list]-phiMid); - int rSign; - if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) - rSign = -1; - else - rSign = 1; - - double theta = Theta(eta[list],rSign); - double thetaPlus = Theta(eta[list] + deta, rSign); - double thetaMinus = Theta(eta[list] - deta, rSign); - - // decide the region based on the theta value - final byte TOP_BOTTOM = 0; - final byte LEFT_RIGHT = 1; - byte region = TOP_BOTTOM; - // hard-coded value is based on the values in Geometry - if(Math.abs(Math.tan(theta)) < 0.8) - region = LEFT_RIGHT; - - double radiusMinus = 0.; - - switch(region) - { - case TOP_BOTTOM: - radiusMinus = innerRadius / Math.abs(Math.sin(theta)); - break; - case LEFT_RIGHT: - radiusMinus = innerRadius / Math.abs(Math.cos(theta)); - break; - } - //compare to AAODData for rhoMax/Minus values - double radiusMax = s*2500.; - - //if no composite particles increase jet size - //Vector keys = (Vector) event.getCollections().get("CompositeParticle"); - //if (keys == null || !parameterStore.get("Data", "CompositeParticle").getStatus()) radiusMax+=200; - - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double radiusPlus = radiusMinus + radiusMax; - if(Math.abs(eT[list] / Math.cos(AMath.lambda(eta[list]))) < maxEnergy) - { - if(parameterStore.get("Jet", "ScaleType").getI() == 1) //sq root - radiusPlus = radiusMinus + radiusMax * (Math.sqrt (Math.abs(eT[list] / Math.cos(AMath.lambda(eta[list])))/maxEnergy)); - if(parameterStore.get("Jet", "ScaleType").getI() == 0) // linear - radiusPlus = radiusMinus + radiusMax *((Math.abs(eT[list] / Math.cos(AMath.lambda(eta[list]))))/maxEnergy); - } - - double vx = parameterStore.get("Event", "XVtx").getD(); - double vy = parameterStore.get("Event", "YVtx").getD(); - double vz = parameterStore.get("Event", "ZVtx").getD(); - - double h_shift = vz; - double v_shift = Math.sqrt(vx*vx + vy*vy); - - // the loop interpolates between the inner and outer edge of the jet to draw the arc - // draw the outer arc - for(int j=0; j<coneSmooth; j++){ - float f = ((float)j)/(coneSmooth-1); - hv[0][i][j] = h_shift + (radiusPlus) * Math.cos(((1-f)*thetaPlus + (f)*thetaMinus)); - hv[1][i][j] = v_shift + (radiusPlus) * Math.sin(((1-f)*thetaPlus + (f)*thetaMinus)); - } - - // draw the inner arc - for(int j=coneSmooth; j<(2*coneSmooth); j++){ - float f = ((float)j-coneSmooth)/(coneSmooth-1); - hv[0][i][j] = h_shift + (radiusMinus) * Math.cos(((1-f)*thetaMinus + (f)*thetaPlus)); - hv[1][i][j] = v_shift + (radiusMinus) * Math.sin(((1-f)*thetaMinus + (f)*thetaPlus)); - } - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.TRANSPARENT_POLYGONS); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AJetROIData.java b/graphics/AtlantisJava/src/atlantis/data/AJetROIData.java deleted file mode 100755 index c47c2ce9299..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AJetROIData.java +++ /dev/null @@ -1,38 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.utils.AHashMap; - -/** - * - * Jet Region Of Interest - * - * @author Zdenek Maxa, Qiang Lu - */ -public class AJetROIData extends AROIData -{ - - AJetROIData(AHashMap p, AEvent e) - { - super(p,e); - } // AJetROIData() ------------------------------------------------------ - - - public String getParameterGroup() - { - return "JetROI"; - } // getParameterGroup() ------------------------------------------------ - - - public String getName() - { - return "JetROI"; - } // getName() ---------------------------------------------------------- - - - public String getNameScreenName() - { - return "JetROI"; - } // getNameScreenName() ------------------------------------------------ - -} // class AJetROIData ====================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/ALArData.java b/graphics/AtlantisJava/src/atlantis/data/ALArData.java deleted file mode 100644 index 7b0efc9cd77..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ALArData.java +++ /dev/null @@ -1,1032 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import com.Ostermiller.util.CSVParser; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.io.FileNotFoundException; - -import atlantis.geometry.ABarrelCalorimeterDetector; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.utils.AUtilities; -import atlantis.parameters.AParameter; -import atlantis.utils.ALogger; - - -/** - * The Liquid Argon ElectroMagnetic Calorimeter - * - * @author Eric Jansen - */ -public class ALArData extends ACalorimeterData -{ - private static ALogger logger = ALogger.getLogger(ALArData.class); - - // data for real pulse shapes plots - private int numSamplings = 0; - private int[][] adcCounts = null; - private float[] cellTime = null; - private int[] cellGain = null; - private float[] cellPedestal = null; - private float[] adc2Mev = null; - private static boolean pulseShapesDataAvailable = false; - private static final String LOOKUP_TABLE_FILE = - AGlobals.instance().getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - "rpsplt_lar.csv"; - // number of lookup table values for real pulse shapes plots calculation - private static final short NUMBER_OF_LOOKUP_VALUES = 799; - - - - ALArData(AHashMap p, AEvent e) - { - super(p,e); - - for (int i = 0; i < numData; i++) - { - try - { - side[i] = (byte) AIdHelper.larBarrelEndcap(id[i]); - etaIndex[i] = (short) AIdHelper.larEta(id[i]); - phiIndex[i] = (short) AIdHelper.larPhi(id[i]); - sampling[i] = AIdHelper.larSampling(id[i]); - } - catch (AAtlantisException aex) - { - logger.warn("Problem decoding ID " + id[i] + " in " + - CALORIMETER_NAME + ": " + aex.getMessage(), aex); - side[i] = 0; - etaIndex[i] = -1; - phiIndex[i] = -1; - sampling[i] = -1; - } - } - - makeHitToGeometryMapping(); - for (int i = 0; i < et.length; ++i) - { - et[i] = Math.abs(energy[i] / (float) Math.cosh(eta[i])); - } - - // Collect some constants we need for the histograms. - for (int i = 0; i < ACalorimeterDetector.count(); i++) - { - - if (ACalorimeterDetector.get(i).getName().indexOf(CALORIMETER_NAME) >= 0) - { - if (ACalorimeterDetector.get(i) instanceof ABarrelCalorimeterDetector) - { - if (innerR == 0.0 || ACalorimeterDetector.get(i).getRMin() < innerR) - { - innerR = ACalorimeterDetector.get(i).getRMin(); - } - } - else - { - if (innerZ == 0.0 || ACalorimeterDetector.get(i).getZMin() < innerZ) - { - innerZ = ACalorimeterDetector.get(i).getZMin(); - } - } - if (outerR == 0.0 || ACalorimeterDetector.get(i).getRMax() > outerR) - { - outerR = ACalorimeterDetector.get(i).getRMax(); - } - if (outerZ == 0.0 || ACalorimeterDetector.get(i).getZMax() > outerZ) - { - outerZ = ACalorimeterDetector.get(i).getZMax(); - } - if (outerEta == 0.0 || ACalorimeterDetector.get(i).getEtaMax() > outerEta) - { - outerEta = ACalorimeterDetector.get(i).getEtaMax(); - } - if (phiGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaPhi() < phiGranularity) - { - phiGranularity = ACalorimeterDetector.get(i).getDeltaPhi(); - } - if (etaGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaEta() < etaGranularity) - { - etaGranularity = ACalorimeterDetector.get(i).getDeltaEta(); - } - } - } - - // Add a little bit of extra margin to prevent binning errors due to - // rounding of numbers. - outerEta += etaGranularity; - - readPulseShapePlotData(p); - - } // ALArData() --------------------------------------------------------- - - - - private void readPulseShapePlotData(AHashMap p) - { - // read ADCCounts and cell data for real pulse shapes plots - adcCounts = super.getADCCountsData(p); - - // read LAr digits (cell data) for real pulse shapes plots - cellTime = (p.get("cellTime") != null) ? p.getFloatArray("cellTime") : null; - cellGain = (p.get("cellGain") != null) ? p.getIntArray("cellGain") : null; - cellPedestal = (p.get("cellPedestal") != null) ? p.getFloatArray("cellPedestal") : null; - adc2Mev = (p.get("adc2Mev") != null) ? p.getFloatArray("adc2Mev") : null; - - pulseShapesDataAvailable = false; - if(adcCounts != null && cellTime != null && cellGain != null && - cellPedestal != null && adc2Mev != null) - { - pulseShapesDataAvailable = true; - numSamplings = adcCounts[0].length; - - logger.debug(CALORIMETER_NAME + - ": data for real pulse shape plots available"); - - if(ACalorimeterRPSPLT.areLarLookupTablesInitialized()) - { - logger.debug(CALORIMETER_NAME + - ": lookup tables have already been read in"); - } - else - { - logger.debug(CALORIMETER_NAME + - ": lookup table values have not been read in yet\n" + - " trying to read file: " + LOOKUP_TABLE_FILE); - - try - { - readLookupTableFile(); - - logger.debug(CALORIMETER_NAME + - ": values from " + LOOKUP_TABLE_FILE + - " successfully read in"); - } - catch(AAtlantisException ex) - { - logger.error(CALORIMETER_NAME + - ": reading " + LOOKUP_TABLE_FILE + - " failed, real pulse shapes plots will not " + - "be available, reason: " + ex.getMessage(), ex); - pulseShapesDataAvailable = false; - } - } - } - - } // readPulseShapePlotData() ------------------------------------------- - - - - /** - * readLookupTableFile() reads in comma separated values (CSV) file - * with LAr real pulse shapes plots time and amplitude lookup values - * @param fileName String - * @throws AAtlantisException - */ - private void readLookupTableFile() throws AAtlantisException - { - try - { - InputStream is = AUtilities.getFileAsStream(LOOKUP_TABLE_FILE); - CSVParser parser = new CSVParser(is); - parser.setCommentStart("#"); - String arrayName = null; - - while((arrayName = parser.nextValue()) != null) - { - String valueArray = parser.nextValue(); // shall now contain all values - CSVParser parserArray = new CSVParser(new StringReader(valueArray)); - String[][] s = parserArray.getAllValues(); - - float[] array = getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - ACalorimeterRPSPLT.setLarTable(arrayName, array); - } // while - } - catch(FileNotFoundException e) - { - throw new AAtlantisException("could not find file: " + - LOOKUP_TABLE_FILE); - } - catch(IOException e) - { - throw new AAtlantisException("exception while reading file: " + - LOOKUP_TABLE_FILE); - } - catch(AAtlantisException e) - { - throw e; - } - - } // readLookupTableFile() ---------------------------------------------- - - - - /** - * - * @param index int - * @param lookupTablesInfo String - * Debug info method in order to make sure that correct lookup table - * is used given barrel/endcap, sampling and region of LAr. - */ - private void pulseShapePlotsDebugInfo(int index, String lookupTableName) - { - String msg = null; - try { - msg = "\n barrel/endcap value: " + - AIdHelper.larBarrelEndcap(id[index]); - msg += " is "; - msg += AIdHelper.larIsBarrel(id[index]) ? "barrel" : "endcap"; - msg += "\n sampling/layer: " + sampling[index]; - msg += "\n region: " + AIdHelper.larRegion(id[index]); - msg += "\n lookup table used: " + lookupTableName; - logger.debug(msg + "\n"); - } catch (AAtlantisException aaex) { - logger.debug("\n exception: " + aaex.getMessage(), aaex); - } - } // pulseShapePlotsDebugInfo() ----------------------------------------- - - - - /** - * This method is used when calculating real pulse shapes plots. - * It is called from getLookupTableForPulseShapesPlots() - * It calculates index of the 0.1 eta bin the argument eta - * (eta of a cell) falls into. Thus it determines which eta - * range a cell belongs to (eta ranges are last level of cells - * division from barrel/endcap, layer, region. - * startIndex argument tells which eta range we start counting from - * (given the eta ranges division it may not necessarily be from 0). - * If eta doesn't fall into a specified interval, empty String - * is returned - then missing ETAx suffix will cause retrieving - * of the float[] will fail. - * - * @param etaFrom - * @param etaTo - * @return - */ - private static String getEtaBinIndex(float etaFrom, float etaTo, - float cellEta, int startIndex) - { - float step = 0.1f; // step, size of the eta bins - float absEta = Math.abs(cellEta); - int index = startIndex; - - for(float f = etaFrom; f < etaTo; f += step, index++) - { - if(absEta > f && absEta < f + step) - { - logger.debug("eta range calculation: cell eta = " + cellEta + " " + - "etaFrom = " + etaFrom + " etaTo = " + etaTo); - logger.debug("eta range index result: " + index + - " (index offset was: " + startIndex + ")"); - return "ETA" + index + "_" ; - } - } - - // calculating bin failed, retrieving the array will fail later - return ""; - - } // calculateEtaBinIndex() --------------------------------------------- - - - - /** - * Method returns correct float[] array for amplitude lookup table - * depending whether a cell (determined by index, resp. id[index]) is in - * barrel, endcap, which layer and which region or which eta range. - * This method accesses ACalorimeterRPSPLT - * Methods contains constant value defining parts of LAr detector - * (as used in AIdHelper) and also eta range constants provided by - * the LAr community. - * - * @param index int - * @return float[] - */ - private float[] getLookupTableForPulseShapesPlots(int index) throws AAtlantisException - { - float[] amplitude = null; // lookup table amplitude values - - // helper variable - absolute value of eta - for checking of the eta range - float absEta = Math.abs(eta[index]); - - // the key for ACalorimeterRPSPLT.getLarTable(key) will gradually be - // constructed depending on barrel/endcap, layer, region and eta range - String lookupTableKey = "LAR_"; // start of the name all LAR_ tables - - - if(AIdHelper.larIsBarrel(id[index])) - { - // it is barrel - lookupTableKey += "BARREL_"; - switch(sampling[index]) - { - case 0: // layer 0 - // plot ADC counts only for this layer - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - String title = "LAr cell: " + decodedId[0]; - int[][] data = { adcCounts[index] }; - APulseShapePlot.plotADCCounts(data, title, null); - throw new AAtlantisException("ADC counts plot only, pulse shape plot not " + - "implemented for LAr barrel, layer 0"); - case 1: - lookupTableKey += "LAYER1_"; // layer 1 - switch(AIdHelper.larRegion(id[index])) - { - case 0: - lookupTableKey += "REGION0_"; - break; - case 1: - lookupTableKey += "REGION1_"; - break; - default: - AOutput.append("\npulse shape plots - LAr barrel, " + - "layer 1, region > 1. Using layer 1, " + - "region 1 lookup table\n", ALogInterface.WARNING); - lookupTableKey += "REGION1_"; - } - break; - case 2: // layer 2 - lookupTableKey += "LAYER2_"; // layer 2 - switch(AIdHelper.larRegion(id[index])) - { - case 0: - lookupTableKey += "REGION0_"; - break; - case 1: - lookupTableKey += "REGION1_"; - break; - default: - AOutput.append("\npulse shape plots - LAr barrel, " + - "layer 2, region > 1. Using layer 2, " + - "region 1 lookup table\n", ALogInterface.WARNING); - lookupTableKey += "REGION1_"; - } - break; - case 3: // layer 3 - lookupTableKey += "LAYER3_REGION0_"; - break; - } - } // if(AIdHelper.larIsBarrel(id[index])) - else - { - // we are in the endcap - lookupTableKey += "ENDCAP_"; - switch(sampling[index]) - { - case 0: // layer 0 - // only one region and one eta range on this layer - lookupTableKey += "LAYER0_REGION0_ETA0_"; - break; - case 1: // layer 1 - lookupTableKey += "LAYER1_"; - switch(AIdHelper.larRegion(id[index])) - { - case 0: - lookupTableKey += "REGION0_"; - if(absEta > 1.375f && absEta < 1.425f) - { - lookupTableKey += "ETA0_"; // first eta range - } - else - { - // eta ranges with step 0.1 provided by Andre - // start index counting from 1, 0 range is used above - lookupTableKey += getEtaBinIndex(2.5f, 3.2f, eta[index], 1); - } - break; - case 1: - lookupTableKey += "REGION1_ETA0_"; // no eta subdivision - break; - case 2: - lookupTableKey += "REGION2_"; - // starting from first range, startIndex 0 - lookupTableKey += getEtaBinIndex(1.5f, 1.8f, eta[index], 0); - break; - case 3: - lookupTableKey += "REGION3_"; - lookupTableKey += getEtaBinIndex(1.8f, 2.0f, eta[index], 0); - break; - case 4: - lookupTableKey += "REGION4_"; - lookupTableKey += getEtaBinIndex(2.0f, 2.4f, eta[index], 0); - break; - case 5: - lookupTableKey += "REGION5_"; - if(absEta > 2.4f && absEta < 2.5f) - { - lookupTableKey += "ETA0_"; - } - break; - default: - AOutput.append("\npulse shape plots - LAr endcap, " + - "layer 1, region > 5. Using layer 1, " + - "region 5, eta range 0 lookup table\n", - ALogInterface.WARNING); - lookupTableKey += "REGION5_ETA0_"; - } - break; - case 2: // layer 2 - lookupTableKey += "LAYER2_"; - switch(AIdHelper.larRegion(id[index])) - { - case 0: - lookupTableKey += "REGION0_"; - if(absEta > 1.375f && absEta < 1.425f) - { - lookupTableKey += "ETA0_"; // first eta range - } - else - { - // eta ranges with step 0.1 provided by Andre - // start index counting from 1, 0 range is used above - lookupTableKey += getEtaBinIndex(2.5f, 3.2f, eta[index], 1); - } - break; - case 1: - lookupTableKey += "REGION1_"; - lookupTableKey += getEtaBinIndex(1.425f, 2.5f, eta[index], 0); - break; - } - break; - case 3: // layer 3 - lookupTableKey += "LAYER3_"; - lookupTableKey += "REGION0_"; - lookupTableKey += getEtaBinIndex(1.5f, 2.5f, eta[index], 0); - break; - } - } // else (endcap) - - lookupTableKey += "AMPLITUDE"; - pulseShapePlotsDebugInfo(index, lookupTableKey); - amplitude = ACalorimeterRPSPLT.getLarTable(lookupTableKey); - - return amplitude; - - } // getLookupTableForPulseShapesPlots() ------------------------------- - - - - /** - * This method plots only the ADC counts and no pulse shape plot for a - * given cell. This is useful when the pulse shape plot is not correct - * but ADC count plot is still needed. The method is called from pick - * interaction with D (digits only), see APickInteraction.pressed() - * It is supposedly a temporary solution until LAr real pulse shapes - * lookup tables are corrected / finalized and propagated to Atlantis. - * @param index - */ - public void plotADCCounts(int index) - { - if(pulseShapesDataAvailable) - { - String title = getPulseTitleString(index); - - int[][] adcCountsLocal = new int[][] { adcCounts[index] }; - - logger.debug("Plotting only ADC counts plot ... "); - APulseShapePlot.plotADCCounts(adcCountsLocal, title, null); - - } // if(pulseShapesDataAvailable) - else - { - return; - } - - } // plotADCCounts() ---------------------------------------------------- - - - -// /** -// * Call util class which plots cell pulse shapes provided that -// * all real pulse shapes data is available -// * Functions calculates values of real pulse shape calculated in the method -// * getPhysicsPulseShape(). -// * This method is called from pick interaction. -// * -// * @param index int -// */ - /*public void plotPulseShapes(int index) - { - if(pulseShapesDataAvailable) - { - String title = getPulseTitleString(index); - - int[][] adcCountsLocal = new int[][] { adcCounts[index] }; - - - if(super.checkADCCountsAvailability(adcCountsLocal)) - { - // adc counts are available - logger.debug(CALORIMETER_NAME + " adc counts (digits) are " + - "available for pulse shapes plots for this cell."); - } - else - { - String m = "ADC counts are not available for this cell, " + - "can't plot pulse shapes."; - AOutput.append("\n" + m, ALogPane.WARNING); - logger.warn(m); - return; - } - - - float[] amplitude = null; // amplitude lookup table - float[] time = null; // time lookup table - try - { - time = ACalorimeterRPSPLT.getLarTable("LAR_TIME"); - amplitude = getLookupTableForPulseShapesPlots(index); - } - catch(AAtlantisException ex) - { - AOutput.append("\n" + ex.getMessage(), ALogPane.WARNING); - logger.error(ex.getMessage()); - return; - } - - // 1 .. 32 range (32 values of ADC counts, i.e. 32 samples), need to - // get NUMBER_OF_LOOKUP_VALUES (769) within this range (starts from 1!). - // Real data will have (probably) only 5 samples per cell - double step = (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try - { - if(factor != -1) - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - realPulse[0][i] = super.getPhysicsPulseShape(d, cellTime[index], - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogPane.WARNING); - logger.error(aaex.getMessage()); - return; - } - - if(factor != -1) - { - logger.debug("adc2Mev factor available, plotting full plot."); - APulseShapePlot.plotRealPulseShapes(adcCountsLocal, realPulse, - step, null, title); - } - else - { - logger.debug("adc2Mev factor not available, plotting just adc counts."); - APulseShapePlot.plotADCCounts(adcCountsLocal, title, null); - } - - } // if(pulseShapesDataAvailable) - else - { - return; - } - - } */// plotPulseShapes() -------------------------------------------------- - - @Override - protected int[][] getADCCounts(int index) { - if (pulseShapesDataAvailable) { - for (int adc : adcCounts[index]) { - // Only return something if it is non-zero - if (adc != 0) return new int[][] { adcCounts[index] }; - } - } - return null; - } - - /** - * Calculate local time for pulse shape plots - */ - protected double getLocalTime(double xTime, double cellTime, int numSamplings) { - int nominalPeakSample = (int)(numSamplings / 2.); - return ((xTime - nominalPeakSample + 3) * 25.0) - cellTime; - } - - @Override - protected double[][] getPulseShape(int index) { - - float[] amplitude = null; // amplitude lookup table - float[] time = null; // time lookup table - try - { - time = ACalorimeterRPSPLT.getLarTable("LAR_TIME"); - amplitude = getLookupTableForPulseShapesPlots(index); - } - catch(AAtlantisException ex) - { - AOutput.append("\n" + ex.getMessage(), ALogInterface.WARNING); - logger.error(ex.getMessage()); - return null; - } - - // 1 .. 32 range (32 values of ADC counts, i.e. 32 samples), need to - // get NUMBER_OF_LOOKUP_VALUES (769) within this range (starts from 1!). - // Real data will have (probably) only 5 samples per cell - double step = getPulseStep(index); - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - // if adc2Mev != -1 -> use value from event file, otherwise predefined value - // see comment at the getADC2MevFactorPredefined() method - // factor variable is used as a flag whether or not to plot pulse shape, - // if is -1 (adc2Mev not available), then want to see only the adc counts - // and don't calculate the pulse shapes - // getADC2MevFactorPredefined(index) is no longer in use, see comment at it - float factor = adc2Mev[index]; - - double energyLocal = energy[index] * 1000.0 / factor; - try - { - if(factor != -1) - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - double localTime = getLocalTime(d, cellTime[index], this.numSamplings); - realPulse[0][i] = super.getPhysicsPulseShape(localTime, - cellPedestal[index], energyLocal, - amplitude, time, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - logger.error(aaex.getMessage()); - return null; - } - - if(factor != -1) - { - logger.debug("adc2Mev factor available, plotting full plot."); - return realPulse; - } - else - { - return null; - } - } - - @Override - protected double getPulseStep(int index) { - return (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - } - -// /** -// * Determines adc2Mev factor value for a cell. The number either comes -// * with the event file (adc2Mev subtag), but sometimes is not available -// * in Athena (in the database) which is indicated by -1 in the event file -// * for a particular cell. In this case, use predefined constant in this -// * method. -// * -// * zdenek (2008-09-15): -// * These predefined values (which are used if adc2Mev factor is -1) should -// * no longer be used. if the factor is not present, do not plot the pulse -// * shape, just the ADC counts as these values are non-sense. The method -// * and references to it should be removed after some time (if calo people -// * don't change their mind to pre-define some other values and use those) -// -// * @param index int -// * @return String -// */ - /* - private float getADC2MevFactorPredefined(int index) - { - boolean barrel = false; - int layer = sampling[index]; - - try - { - barrel = AIdHelper.larIsBarrel(id[index]); - } - catch (AAtlantisException e) - { - AOutput.append("Problem decoding ID " + id[index] + - " in " + CALORIMETER_NAME + ": " + e.getMessage(), - ALogPane.WARNING); - return Float.NEGATIVE_INFINITY; - } - - float r = Float.NEGATIVE_INFINITY; - if(barrel) - { - switch(layer) - { - case 0: r = 7.0f; - break; - case 1: r = 2.5f; - break; - case 2: r = Math.abs(this.eta[index]) < 0.8 ? 10.0f : 18.0f; - break; - case 3: r = 9.0f; - break; - } - } - else - { - r = 16.0f; - } - - return r; - - } // getADC2MevFactor() ------------------------------------------------- - */ - - - /** - * Returns calo hit info - * - * @param index int - * @return String - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",et[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",et[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",et[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",et[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String t = ""; - String cellInfo = ""; - - // if decoded ID is required and implemented for LAr ... - // String decodedId = AIdHelper.getDecodedTileIndentifier(id[index]); - // t = decodedId + " " + super.getHitInfo(index); - t = super.getHitInfo(index); - - cellInfo += "\n cell time = "; - cellInfo += (cellTime != null) ? Float.toString(cellTime[index]) + - " ns" : "n/a"; - cellInfo += "\n cell gain = "; - cellInfo += (cellGain != null) ? Integer.toString(cellGain[index]) : "n/a"; - cellInfo += "\n cell pedestal = "; - cellInfo += (cellPedestal != null) ? Float.toString(cellPedestal[index]) + - " ADC counts" : "n/a"; - - cellInfo += "\n ADC 2 MeV = "; - if(adc2Mev == null) - { - cellInfo += "n/a"; - } - else - { - // subtag adc2Mev was available in the event file - if(adc2Mev[index] != -1) - { - // other than -1: the factor was available in - // Athena (database) for this particular cell - cellInfo += Float.toString(adc2Mev[index]) + " (from database)"; - } - else - { - // -1 -> the factor wasn't available in Athena (database), - // use hardcoded constant for this particular cell - cellInfo += "-1 (n/a in database)"; - // see comment at getADC2MevFactorPredefined() method - // using predefined " + - // Float.toString(getADC2MevFactorPredefined(index)); - } - } - - cellInfo += pulseShapesDataAvailable ? "" : - "\n data for real pulse shapes plot n/a"; - - return t + cellInfo; - - } // getHitInfo() ------------------------------------------------------- - - @Override //ACalorimeterData - //Gives the hit time for this cell - protected double getTime(int hit) - { - if (cellTime == null) return 0.0; - else return cellTime[hit]; - } - - private void cutEnergyByLayer(String groupName, String parameterName, - String text, float[] array, int[] sampling, int currSampling) - { - AParameter par = parameterStore.get(groupName, parameterName); - - if(par.getStatus() && array != null) - { - double value = par.getD(); - String operator = par.getOperator(); - int num = 0; - - // this special cut shall have isMod="YES" attribute set, so - // par.isModulus() is true, thus only Math.abs() values are considered - if(operator.equals("<")) - { - for(int i = 0; i < numDraw; i++) - { - if(sampling[listdl[i]] == currSampling) - { - if(Math.abs(array[listdl[i]]) < value) - { - listdl[num++] = listdl[i]; - } - } - else - { - // don't check energy for other layers and don't cut - listdl[num++] = listdl[i]; - } - } - } - else if(operator.equals(">")) - { - // '>' really means '>=' for reals since they are real in - // from ascii file and don't have full precison - for(int i = 0; i < numDraw; i++) - { - if(sampling[listdl[i]] == currSampling) - { - if(Math.abs(array[listdl[i]]) >= value) - { - listdl[num++] = listdl[i]; - } - } - else - { - // don't check energy for other layers and don't cut - listdl[num++] = listdl[i]; - } - } - } - else - { - throw new Error(operator + " operator not sensible for floats"); - } - - numDraw = num; - } - - } // cutEnergyByLayer() ------------------------------------------------- - - - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsCalo", "LArET", "LArET", et); - cut("CutsCalo", "LArEnergy", "LArEnergy", energy); - - // energy cut (E) per layers - cutEnergyByLayer("CutsCalo", "LArEnergyLayer0", "LArEnergyLayer0", - energy, sampling, 0); - cutEnergyByLayer("CutsCalo", "LArEnergyLayer1", "LArEnergyLayer1", - energy, sampling, 1); - cutEnergyByLayer("CutsCalo", "LArEnergyLayer2", "LArEnergyLayer2", - energy, sampling, 2); - cutEnergyByLayer("CutsCalo", "LArEnergyLayer3", "LArEnergyLayer3", - energy, sampling, 3); - - // cut by LAr region (+- EndCap, All) - int cutSub = parameterStore.get("CutsCalo", "LAr").getI(); - if(cutSub != -1) - { - - int num = 0; - for(int i = 0; i < numDraw; i++) - { - - switch(cutSub){ - case 0: - if(side[listdl[i]] == -2 || side[listdl[i]] == -3){ - listdl[num++] = listdl[i]; - } - break; - case 1: - if(side[listdl[i]] == 2 || side[listdl[i]] == 3){ - listdl[num++] = listdl[i]; - } - break; - case 2: - if(Math.abs(side[listdl[i]]) != 1){ - listdl[num++] = listdl[i]; - } - break; - case 3: - if(Math.abs(side[listdl[i]]) == 1){ - listdl[num++] = listdl[i]; - } - break; - default: - break; - - - } - } - numDraw = num; - - } - } // applyCuts() -------------------------------------------------------- - - - /** - * Returns the name of the parameter group. - * - * @return String parameter group - */ - public String getParameterGroup() - { - return "LAr"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getName() - { - return "LAr"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getNameScreenName() - { - return "LAr"; - } - - /** - * Returns the type of calorimeter (ECAL/HCAL) for a hit. - * - * @param index int hit index - * @return String calorimeter type - */ - public String getCalorimeterType(int index) - { - return "ECAL"; - } - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - ACoord[] data = ACoord.NO_HISTOGRAMS; - int mode = parameterStore.get("YX", "Mode").getI(); - if ((projection instanceof AProjectionYX) && (mode == AProjectionYX.MODE_STANDARD || - mode == AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER || - mode == AProjectionYX.MODE_LAR_ENDCAP_1 || - mode == AProjectionYX.MODE_LAR_ENDCAP_2 || - mode == AProjectionYX.MODE_LAR_ENDCAP_3 || - mode == AProjectionYX.MODE_LAR_ENDCAP_SUMMED)) - data = getYXHistograms(); - else if (projection instanceof AProjectionFR) - data = getFRHistograms(); - else if (projection instanceof AProjectionRZ) - data = getRZHistograms(); - else if (projection instanceof AProjectionFZ) - data = getFZHistograms(); - return projection.nonLinearTransform(data); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ALVL1JetElementData.java b/graphics/AtlantisJava/src/atlantis/data/ALVL1JetElementData.java deleted file mode 100644 index a4aa50b1eaa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ALVL1JetElementData.java +++ /dev/null @@ -1,446 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import java.awt.Color; - -import atlantis.canvas.AWindow; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.APolygon; - -public class ALVL1JetElementData extends AData -{ - private float[] energy; - private float[] eta; - private float[] deta; - private float[] phi; - private float[] dphi; - - ALVL1JetElementData(AHashMap p, AEvent e) - { - super(p,e); - - phi = p.getFloatArray("phi"); - eta = p.getFloatArray("eta"); - // here energy is actually Et - energy = p.getFloatArray("energy"); - - deta = new float[numData]; - dphi = new float[numData]; - - fillGranularity(); - } - - private void fillGranularity() - { - for(int i = 0; i < numData; ++i) - { - float positiveEta = Math.abs(eta[i]); - if(positiveEta <= 2.4) - { - deta[i] = 0.1f; - dphi[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 2.7) - { - deta[i] = 0.15f; - dphi[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 2.9) - { - deta[i] = 0.1f; - dphi[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 3.2) - { - deta[i] = 0.15f; - dphi[i] = (float) (Math.PI / 32.); - } - else - { - deta[i] = 0.9f; - dphi[i] = (float) (Math.PI / 16.); - } - } - } - - public double getEta(int index) - { - return eta[index]; - } - - public double getdEta(int index) - { - return deta[index]; - } - - public double getPhi(int index) - { - return phi[index]; - } - - public double getdPhi(int index) - { - return dphi[index]; - } - - public double getET(int index) - { - return energy[index]; - } - - public String getNameScreenName() - { - return "LVL1JetElement"; - } - - public String getParameterGroup() - { - return "LVL1JetElement"; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - "\n E="+String.format("%.3f",energy[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n Energy = "); - msg.append(String.format("%.3f",energy[index])); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",phi[index])); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - return msg.toString(); - } - - protected void applyCuts() - { - cutIndex(); - cut("CutsCalo", "LVL1TriggerET", " ET", energy); - cutPhi(phi, dphi); - cutEtaDEta(eta, deta); - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == 0) - colorByConstant(); - - return 1; - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - protected ACoord getYXUser() - { - makeDrawList(); - - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi[list]; - double phiMinus = phi[list] - dphi[list]; - double cosPlus = Math.cos(phiPlus); - double sinPlus = Math.sin(phiPlus); - double cosMinus = Math.cos(phiMinus); - double sinMinus = Math.sin(phiMinus); - - // Rho range of Calo Detector is about between [148.175, 386] - double rhoMax = 380; - double rhoMinus = 155; - - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double rhoPlus = rhoMax; - if(Math.abs(energy[list]) < maxEnergy) - rhoPlus = rhoMinus + (rhoMax - rhoMinus) * Math.abs(energy[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = rhoMinus * cosPlus; - hv[1][i][0] = rhoMinus * sinPlus; - // x1, y1 - hv[0][i][1] = rhoPlus * cosPlus; - hv[1][i][1] = rhoPlus * sinPlus; - // x2, y2 - hv[0][i][2] = rhoPlus * cosMinus; - hv[1][i][2] = rhoPlus * sinMinus; - // x3, y3 - hv[0][i][3] = rhoMinus * cosMinus; - hv[1][i][3] = rhoMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getFRUser() - { - ACoord coordFR = getYXUser().convertYXToFR().includePhiWrapAround("FR"); - return coordFR; - } - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list]-phiMid); - double rSign; - if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) - rSign = -1; - else - rSign = 1; - - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta[list]))) * 2.0; - double thetaPlus = Math.atan(Math.exp(-(Math.abs(eta[list]) - deta[list]))) * 2.0; - double thetaMinus = Math.atan(Math.exp(-(Math.abs(eta[list]) + deta[list]))) * 2.0; - - if ((eta[list] > 0.) && (rSign == -1)) - { - theta = 2 * Math.PI - theta; - thetaPlus = 2 * Math.PI - thetaPlus; - thetaMinus = 2 * Math.PI - thetaMinus; - } - else if ((eta[list] < 0.) && (rSign == -1)) - { - theta += Math.PI; - thetaPlus += Math.PI; - thetaMinus += Math.PI; - } - else if ((eta[list] < 0.) && (rSign == 1)) - { - theta = Math.PI - theta; - thetaPlus = Math.PI - thetaPlus; - thetaMinus = Math.PI - thetaMinus; - } - - double cosPlus = Math.cos(thetaPlus); - double sinPlus = Math.sin(thetaPlus); - double cosMinus = Math.cos(thetaMinus); - double sinMinus = Math.sin(thetaMinus); - - // decide the region based on the theta value - final byte LAR = 0; - final byte LAR_ENDCAP = 1; - final byte FCAL_EM = 2; - byte region = LAR; - // hard-coded value is based on the values in AGeometry.xml - if(Math.abs(Math.tan(theta)) >= 0.0778 && Math.abs(Math.tan(theta)) < 0.4828) - region = LAR_ENDCAP; - else if(Math.abs(Math.tan(theta)) < 0.0778) - region = FCAL_EM; - - double radiusMinus = 0.; - switch(region) - { - // use fixed rho/z to determine the lower radius value - case LAR: - radiusMinus = 155 / Math.abs(Math.sin(theta)); - break; - case LAR_ENDCAP: - radiusMinus = 380 / Math.abs(Math.cos(theta)); - break; - case FCAL_EM: - radiusMinus = 470 / Math.abs(Math.cos(theta)); - break; - } - double radiusMax = radiusMinus + 200; - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double radiusPlus = radiusMax; - if(Math.abs(energy[list]) < maxEnergy) - radiusPlus = radiusMinus + (radiusMax - radiusMinus) * Math.abs(energy[list]) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = radiusMinus * cosPlus; - hv[1][i][0] = radiusMinus * sinPlus; - // x1, y1 - hv[0][i][1] = radiusPlus * cosPlus; - hv[1][i][1] = radiusPlus * sinPlus; - // x2, y2 - hv[0][i][2] = radiusPlus * cosMinus; - hv[1][i][2] = radiusPlus * sinMinus; - // x3, y3 - hv[0][i][3] = radiusMinus * cosMinus; - hv[1][i][3] = radiusMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getVPUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - h[i]=eta[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP) - { - ACoord centers=getUser(projection); - - int[] drawlist=centers.index; - double[] density = new double[drawlist.length]; - double maxDensity = 0.0; - double[][][] hv=new double[2][drawlist.length][4]; // cell - int[] index = new int[drawlist.length]; - ACoord geoCell; - - for(int i=0; i<drawlist.length; ++i) - { - int list=drawlist[i]; - // y coordinate of four cell corners - hv[1][i][0] = centers.hv[1][0][i] + Math.toDegrees(getdPhi(list)); - hv[1][i][1] = centers.hv[1][0][i] - Math.toDegrees(getdPhi(list)); - hv[1][i][2] = centers.hv[1][0][i] - Math.toDegrees(getdPhi(list)); - hv[1][i][3] = centers.hv[1][0][i] + Math.toDegrees(getdPhi(list)); - // x coordinate of four cell corners - hv[0][i][0] = centers.hv[0][0][i] - getdEta(list); - hv[0][i][1] = centers.hv[0][0][i] - getdEta(list); - hv[0][i][2] = centers.hv[0][0][i] + getdEta(list); - hv[0][i][3] = centers.hv[0][0][i] + getdEta(list); - - index[i] = list; - - // calculate density for all cells, and find min and max density - density[i] = Math.abs(energy[list]) / (getdPhi(list) * getdEta(list)); - if(i == 0) - maxDensity = density[i]; - else - { - if (density[i] > maxDensity) - maxDensity = density[i]; - } - } - - geoCell = window.calculateDisplay(new ACoord(hv, index, this, ACoord.POLYGONS)); - drawGeometry(geoCell, window, ag); - for (int i = 0; i < density.length; i++) - { - double factor = Math.sqrt(density[i] / maxDensity); - APolygon.scale(geoCell.hv[0][i], geoCell.hv[1][i], factor); - } - - drawHits(geoCell, window, ag); - } - else - { - super.draw(window, ag, projection); - } - } - - private void drawGeometry(ACoord display, AWindow window, AGraphics ag) - { - Color[] colorMap = AColorMap.getColors(); - boolean drawCellGeometry = parameterStore.get(getParameterGroup(), "CellGeometry").getStatus(); - boolean drawCellOutline = parameterStore.get(getParameterGroup(), "CellOutline").getStatus(); - int cellGeometryColor = parameterStore.get(getParameterGroup(), "CellGeometry").getI(); - int cellOutlineColor = parameterStore.get(getParameterGroup(), "CellOutline").getI(); - boolean drawFrame = parameterStore.get(getParameterGroup(), "Frame").getStatus(); - int frameColor = parameterStore.get(getParameterGroup(), "Frame").getI(); - int frameWidth = parameterStore.get(getParameterGroup(), "FrameWidth").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - drawFrame=true; - else - drawFrame=false; - - if(!drawCellGeometry && !drawCellOutline) - return; - - // Draw geometry - for(int i=0; i<display.hv[0].length; ++i) - { - if(drawCellGeometry) - { - if(drawFrame) - { - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 1, 0, frameWidth, 0)); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - ag.updateDrawParameters(new ADrawParameters(true, cellGeometryColor, 1, 0, 0, 0)); - ag.fillPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - if(drawCellOutline) - { - ag.setColor(colorMap[cellOutlineColor]); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - - private void drawHits(ACoord display, AWindow window, AGraphics ag) - { - int[] color = this.getColor(display.index); - - boolean drawCellGeometry = parameterStore.get(getParameterGroup(), "CellGeometry").getStatus(); - boolean drawFrame = parameterStore.get(getParameterGroup(), "Frame").getStatus(); - int frameColor = parameterStore.get(getParameterGroup(), "Frame").getI(); - int frameWidth = parameterStore.get(getParameterGroup(), "FrameWidth").getI(); - - // draw frame - if (drawFrame && !drawCellGeometry) - { - for (int i = 0; i < display.hv[0].length; i++) - { - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 1, 0, frameWidth, 0)); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - - // draw hits - for(int i=0; i<display.hv[0].length; ++i) - { - int lineWidth = parameterStore.get(getParameterGroup(), "LineWidth").getI(); - ag.updateDrawParameters(new ADrawParameters(true, color[i], 1, lineWidth, 0, 0)); - ag.fillPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ALVL1ResultData.java b/graphics/AtlantisJava/src/atlantis/data/ALVL1ResultData.java deleted file mode 100755 index db7dc97e2b1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ALVL1ResultData.java +++ /dev/null @@ -1,292 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.event.*; -import atlantis.utils.AHashMap; - -public class ALVL1ResultData extends AData -{ - private String[] ctpItemList; - private String[] itemListL2; - private String[] itemListEF; - private int[] ctpWord0; - private int[] ctpWord1; - private int[] ctpWord2; - private float[] energyEtMiss; - //private float[] energyEx; - //private float[] energyEy; - private float[] energySumEt; - private int[] passedL1; - private int[] passedL2; - private int[] passedEF; - private int[] passedTrigger; - private String[] prescaleListEF; - private String[] prescaleListL1; - private String[] prescaleListL2; - - ALVL1ResultData(AHashMap p, AEvent e) - { - super(p,e); - - ctpItemList = p.getStringArray("ctpItemList"); - itemListL2 = p.getStringArray("itemListL2"); - itemListEF = p.getStringArray("itemListEF"); - ctpWord0 = p.getUnknownIntArray("ctpWord0"); - ctpWord1 = p.getUnknownIntArray("ctpWord1"); - ctpWord2 = p.getUnknownIntArray("ctpWord2"); - energyEtMiss = p.getUnknownFloatArray("energyEtMiss"); - //energyEx = p.getUnknownFloatArray("energyEx"); - //energyEy = p.getUnknownFloatArray("energyEy"); - energySumEt = p.getUnknownFloatArray("energySumEt"); - passedL1 = p.getUnknownIntArray("passedL1"); - passedL2 = p.getUnknownIntArray("passedL2"); - passedEF = p.getUnknownIntArray("passedEF"); - passedTrigger = p.getUnknownIntArray("passedTrigger"); - //check for backward compatibility - prescaleListEF = (p.get("prescaleListEF") != null) ? p.getStringArray("prescaleListEF"): null; - prescaleListL1 = (p.get("prescaleListL1") != null) ? p.getStringArray("prescaleListL1"): null; - prescaleListL2 = (p.get("prescaleListL2") != null) ? p.getStringArray("prescaleListL2"): null; - } - - protected void applyCuts() - {} - - public String getHitInfo(int index) - { - return "LVL1Result"; - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == 0) - colorByConstant(); - - return 3; - } - - public String getParameterGroup() - { - return "LVL1Result"; - } - - public String getNameScreenName() - { - return "LVL1Result"; - } - - public String getCtpItemList(int index) - { - return ctpItemList[index]; - } - - /** - * Returns the individual parts of the list seperated by - - * By using cleanup removes L1 from the item - */ - public String[] getCtpItemListSplit(int index, boolean cleanUp) - { - if(ctpItemList!=null) - { - if(cleanUp) - return splitItems(ctpItemList[index], "L1"); - else - return splitItems(ctpItemList[index]); - } - else - return null; - } - - public String getitemListL2(int index) - { - return itemListL2[index]; - } - - /** - * Returns the individual parts of the list seperated by - - * By using cleanup removes L2 from the item - */ - public String[] getitemListL2Split(int index, boolean cleanUp) - { - if(itemListL2!=null) - { - if(cleanUp) - return splitItems(itemListL2[index], "L2"); - else - return splitItems(itemListL2[index]); - } - else - return null; - } - - public String getitemListEF(int index) - { - return itemListEF[index]; - } - - /** - * Returns the individual parts of the list seperated by - - * By using cleanup removes EF from the item - */ - public String[] getitemListEFSplit(int index, boolean cleanUp) - { - if(itemListEF!=null) - { - if(cleanUp) - return splitItems(itemListEF[index], "EF"); - else - return splitItems(itemListEF[index]); - } - else - return null; - } - - public int getCtpWord0(int index) - { - return ctpWord0[index]; - } - - public String getBinaryCtpWord0(int index) - { - return Integer.toBinaryString(ctpWord0[index]); - } - - public int getCtpWord1(int index) - { - return ctpWord1[index]; - } - - public int getCtpWord2(int index) - { - return ctpWord2[index]; - } - - /** - * This method is needed for backward compatibility - * New xml files store this in ATriggerInfoData - */ - public float getEnergyEtMiss(int index) - { - return energyEtMiss[index]; - } - - /*public float getEnergyEx(int index) - { - return energyEx[index]; - } - public float getEnergyEy(int index) - { - return energyEy[index]; - }*/ - - /** - * This method is needed for backward compatibility - * New xml files store this in ATriggerInfoData - */ - public float getEnergySumEt(int index) - { - return energySumEt[index]; - } - - public int getPassedL1(int index) - { - return passedL1[index]; - } - - public int getPassedL2(int index) - { - return passedL2[index]; - } - - public int getPassedEF(int index) - { - return passedEF[index]; - } - - public int getPassedTrigger(int index) - { - return passedTrigger[index]; - } - - public String getPrescaleListEF(int index) - { - return prescaleListEF[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getPrescaleListEFSplit(int index) - { - if(prescaleListEF!=null) - return splitItems(prescaleListEF[index]); - else - return null; - } - - public String getPrescaleListL1(int index) - { - return prescaleListL1[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getPrescaleListL1Split(int index) - { - if(prescaleListL1!=null) - return splitItems(prescaleListL1[index]); - else - return null; - } - - public String getPrescaleListL2(int index) - { - return prescaleListL2[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getPrescaleListL2Split(int index) - { - if(prescaleListL2!=null) - return splitItems(prescaleListL2[index]); - else - return null; - } - - /** - * Function that seperates an item list and carries out cleanup - */ - private String[] splitItems(String origItems, String level) - { - //string array to hold individual items - String[] newItems=splitItems(origItems); - //remove letters from start of item and duplicated names - char[] levelChar = level.toCharArray(); - for(int i=0; i<newItems.length; i++) - { - char[] newItemsChar = newItems[i].toCharArray(); - if(newItemsChar[0]==levelChar[0] && newItemsChar[1]==levelChar[1]) - { - if(newItemsChar[2]=='_') - newItems[i]=newItems[i].substring(3); - else - newItems[i]=newItems[i].substring(2); - //get rid of duplicated parts of name - char[] newItemsChar2 = newItems[i].toCharArray(); - for(int j=0; j<newItemsChar2.length-1; j++) - { - if(newItemsChar2[j]==levelChar[0] && newItemsChar2[j+1]==levelChar[1]) - { - newItems[i]=newItems[i].substring(0, j); - break; - } - } - } - } - return newItems; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ALVL1TriggerTowerData.java b/graphics/AtlantisJava/src/atlantis/data/ALVL1TriggerTowerData.java deleted file mode 100644 index 9cfef101342..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ALVL1TriggerTowerData.java +++ /dev/null @@ -1,800 +0,0 @@ -package atlantis.data; - -import java.util.Arrays; - -import atlantis.canvas.AWindow; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.list.AListManager; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.APolygon; - -public class ALVL1TriggerTowerData extends AData -{ - public static final boolean ELECTROMAGNETIC = true; - public static final boolean HADRONIC = false; - - // here energy is actually Et - private float[] emEnergy; - private float[] hadEnergy; - private float[] sumEnergy; - private float[] eta; - private float[] deta_em; - private float[] deta_had; - private float[] phi; - private float[] dphi_em; - private float[] dphi_had; - private int[] numADC; - private int[][] hadADC; - private int[][] emADC; - private int[] emBCID; - private int[] hadBCID; - private int[] isEMSaturated; - private int[] isHadSaturated; - - ALVL1TriggerTowerData(AHashMap p, AEvent e) - { - super(p,e); - - phi = p.getFloatArray("phi"); - eta = p.getFloatArray("eta"); - emEnergy = p.getFloatArray("emEnergy"); - hadEnergy = p.getFloatArray("hadEnergy"); - sumEnergy = p.getFloatArray("sumEnergy"); - - deta_em = new float[numData]; - deta_had = new float[numData]; - dphi_em = new float[numData]; - dphi_had = new float[numData]; - - fillGranularity(); - - numADC = p.getIntArray("numADC"); - emADC = fillADC(p.getIntArray("emADC")); - hadADC = fillADC(p.getIntArray("hadADC")); - emBCID = p.getIntArray("emBCID"); - hadBCID = p.getIntArray("hadBCID"); - isEMSaturated = p.getIntArray("isEMSaturated"); - isHadSaturated = p.getIntArray("isHadSaturated"); - } - - private void fillGranularity() - { - for(int i = 0; i < numData; ++i) - { - float positiveEta = Math.abs(eta[i]); - if(positiveEta <= 2.4) - { - deta_em[i] = 0.05f; - dphi_em[i] = (float) (Math.PI / 64.); - deta_had[i] = 0.05f; - dphi_had[i] = (float) (Math.PI / 64.); - } - else if(positiveEta <= 2.5) - { - deta_em[i] = 0.05f; - dphi_em[i] = (float) (Math.PI / 64.); - deta_had[i] = 0.1f; - dphi_had[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 3.0) - { - deta_em[i] = 0.1f; - dphi_em[i] = (float) (Math.PI / 32.); - deta_had[i] = 0.1f; - dphi_had[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 3.1) - { - deta_em[i] = 0.1f; - dphi_em[i] = (float) (Math.PI / 32.); - deta_had[i] = 0.05f; - dphi_had[i] = (float) (Math.PI / 32.); - } - else if(positiveEta <= 3.2) - { - deta_em[i] = 0.05f; - dphi_em[i] = (float) (Math.PI / 32.); - deta_had[i] = 0.2f; - dphi_had[i] = (float) (Math.PI / 16.); - } - else if(positiveEta <= 4.3) - { - deta_em[i] = 0.2f; - dphi_em[i] = (float) (Math.PI / 16.); - deta_had[i] = 0.2f; - dphi_had[i] = (float) (Math.PI / 16.); - } - else if(positiveEta <= 4.4) - { - deta_em[i] = 0.2f; - dphi_em[i] = (float) (Math.PI / 16.); - deta_had[i] = 0.35f; - dphi_had[i] = (float) (Math.PI / 16.); - } - else - { - deta_em[i] = 0.3f; - dphi_em[i] = (float) (Math.PI / 16.); - deta_had[i] = 0.35f; - dphi_had[i] = (float) (Math.PI / 16.); - } - } - } - - public int[][] fillADC(int[] tempADC) - { - int[][] ADC=null; - if(tempADC!=null) - { - ADC= new int[numADC.length][0]; - int num=0; - for(int i=0; i<numADC.length; i++) - { - // multiple numbers are associated with each cell - ADC[i]=new int[numADC[i]]; - for(int j=0; j<numADC[i]; j++) - { - ADC[i][j]=tempADC[num]; // fill in array for each cell - num++; - } - } - } // if(ADC != null) - return ADC; - } - - public void plotPulseShapes(int index) - { - if(emADC!=null && hadADC!=null) - { - //int[][] data={hadADC[index],emADC[index]}; - String[] labels={"EM trigger ADC counts","HAD trigger ADC counts","Sum trigger ADC counts"}; - int[] sumADC= new int[emADC[index].length]; - String[] axis= new String[3]; - String[] colors = new String[3]; - //EM plot - if(isEMSaturated[index]==0) - colors[0]="blue"; - else - colors[0]="red"; - axis[0]="index (BCID="+emBCID[index]+")"; - //HAD plot - if(isHadSaturated[index]==0) - colors[1]="blue"; - else - colors[0]="red"; - axis[1]="index (BCID="+hadBCID[index]+")"; - //Sum plot - colors[2]="blue"; - axis[2]="index"; - for(int i=0; i<emADC[index].length; i++) - { - sumADC[i]=emADC[index][i]+hadADC[index][i]; - } - int[][] data={emADC[index],hadADC[index],sumADC}; - String title="LVL1TriggerTower " + id[index] + " ADC counts"; - APulseShapePlot.plotADCCounts(data, title, axis, labels, colors); - } - else - { - if(emADC!=null) - { - int[][] data={emADC[index]}; - String[] axis={"index"}; - APulseShapePlot.plotADCCounts(data, "EM trigger ADC counts", axis); - } - if(hadADC!=null) - { - int[][] data={hadADC[index]}; - String[] axis={"index"}; - APulseShapePlot.plotADCCounts(data, "HAD trigger ADC counts", axis); - } - } - } - - public double getEta(int index) - { - return eta[index]; - } - - public double getdEta(int index, boolean emOrHad) - { - if(emOrHad == ELECTROMAGNETIC) - return deta_em[index]; - else - return deta_had[index]; - } - - public double getPhi(int index) - { - return phi[index]; - } - - public double getdPhi(int index, boolean emOrHad) - { - if(emOrHad == ELECTROMAGNETIC) - return dphi_em[index]; - else - return dphi_had[index]; - } - - public double getET(int index, boolean emOrHad) - { - if(emOrHad == ELECTROMAGNETIC) - return emEnergy[index]; - else - return hadEnergy[index]; - } - - public double getSumET(int index) - { - return sumEnergy[index]; - } - - public String getNameScreenName() - { - return "LVL1TriggerTower"; - } - - public String getParameterGroup() - { - return "LVL1TriggerTower"; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - "\n E="+String.format("%.3f",sumEnergy[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n EM Energy = "); - msg.append(String.format("%.3f",emEnergy[index])); - msg.append(" GeV\n Had Energy = "); - msg.append(String.format("%.3f",hadEnergy[index])); - msg.append(" GeV\n Sum Energy = "); - msg.append(String.format("%.3f",sumEnergy[index])); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - return msg.toString(); - } - - protected void applyCuts() - { - cutIndex(); - cut("CutsCalo", "LVL1TriggerET", " ET", sumEnergy); - } - - public void applyEMCuts() - { - cutPhi(phi, dphi_em); - cutEtaDEta(eta, deta_em); - } - - public void applyHadCuts() - { - cutPhi(phi, dphi_had); - cutEtaDEta(eta, deta_had); - } - - public byte[] getColor(boolean emOrHad) - { - internalColor(emOrHad); - coloring(); - byte[] temp = new byte[id.length]; - for(int i = 0; i < temp.length; i++) - temp[i] = color[getIndexFromId(id[i])]; - return temp; - } - - /* - * Returns the colours of the trigger tower cells - * If this method is used then internalColor(boolean emOrHad) - * must be called first elsewhere - */ - public int[] getColor(int[] dl) - { - coloring(); - int[] temp = new int[dl.length]; - - for(int i = 0; i < temp.length; i++) - temp[i] = color[dl[i]]; - return temp; - } - - /* - * Colour the cells if in lists or picked - * If this method is used then internalColor(boolean emOrHad) - * must be called first elsewhere - */ - public void coloring() - { - int[][] temp = AListManager.getInstance().getColorMapping(this); - int[] index = temp[0]; - int[] c = temp[1]; - // now add in colours specified in lists - - for(int i = 0; i < index.length; ++i) - if(c[i] >= 0) - color[index[i]] = (byte) c[i]; - int others = AListManager.getInstance().getColorOfOthers(); - // need to check if this data could have been picked - // so that colouring of hits by STr works even if STr - // is not in list because it wasn't on.... - if(others >= 0 && parameterStore.get("Data", getName()).getStatus()) - { - boolean[] inList = new boolean[numData]; - for(int i = 0; i < index.length; ++i) - inList[index[i]] = true; - - for(int i = 0; i < numData; ++i) - if(!inList[i]) - color[i] = (byte) others; - } - } - - protected int internalColor() - { - colorByConstant(); - return 1; - } - - protected int internalColor(boolean emOrHad) - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if(colorFunction == 0) - colorByConstant(); - else if(colorFunction ==1) - { - if(emOrHad == ELECTROMAGNETIC) - Arrays.fill(color, (byte) (parameterStore.get("Det", "ECALFill").getI() + 12)); - else - Arrays.fill(color, (byte) (parameterStore.get("Det", "HCALFill").getI() + 12)); - } - return 1; - } - - protected int getDrawOrFill() - { - return AGraphics.FILL; - } - - private void drawVP(AWindow window, AGraphics ag, boolean emOrHad) - { - ACoord centers = getVPUser(emOrHad); - - if(centers == null) - return; - - int[] drawlist = centers.index; - double[] density = new double[drawlist.length]; - double[] sumDensity = new double[drawlist.length]; - double maxDensity = 0.0; - double[][][] hv = new double[2][drawlist.length][4]; // cell - int[] index = new int[drawlist.length]; - ACoord geoCell; - - for(int i=0; i<drawlist.length; ++i) - { - int list = drawlist[i]; - // y coordinate of four cell corners - hv[1][i][0] = centers.hv[1][0][i] + Math.toDegrees(getdPhi(list, emOrHad)); - hv[1][i][1] = centers.hv[1][0][i] - Math.toDegrees(getdPhi(list, emOrHad)); - hv[1][i][2] = centers.hv[1][0][i] - Math.toDegrees(getdPhi(list, emOrHad)); - hv[1][i][3] = centers.hv[1][0][i] + Math.toDegrees(getdPhi(list, emOrHad)); - // x coordinate of four cell corners - hv[0][i][0] = centers.hv[0][0][i] - getdEta(list, emOrHad); - hv[0][i][1] = centers.hv[0][0][i] - getdEta(list, emOrHad); - hv[0][i][2] = centers.hv[0][0][i] + getdEta(list, emOrHad); - hv[0][i][3] = centers.hv[0][0][i] + getdEta(list, emOrHad); - - index[i] = list; - - // calculate density for all cells, and find min and max density - density[i] = Math.abs(getET(list, emOrHad)) / (getdPhi(list, emOrHad) * getdEta(list, emOrHad)); - sumDensity[i] = Math.abs(getSumET(list)) / (getdPhi(list, emOrHad) * getdEta(list, emOrHad)); - if(i == 0) - maxDensity = sumDensity[i]; - else - { - if (sumDensity[i] > maxDensity) - maxDensity = sumDensity[i]; - } - } - - geoCell = window.calculateDisplay(new ACoord(hv, index, this, ACoord.POLYGONS)); - drawGeometry(geoCell, window, ag, density); - for (int i = 0; i < density.length; i++) - { - double factor = Math.sqrt(density[i] / maxDensity); - APolygon.scale(geoCell.hv[0][i], geoCell.hv[1][i], factor); - } - - drawHits(geoCell, window, ag, density); - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - int energyType = parameterStore.get(PARAMETER_GROUP, "EnergyType").getI(); - if(projection instanceof AProjectionYX) - { - if(energyType == 0 || energyType == 2) - { - internalColor(ELECTROMAGNETIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getYXUser(ELECTROMAGNETIC)))); - } - if(energyType == 1 || energyType == 2) - { - internalColor(HADRONIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getYXUser(HADRONIC)))); - } - } - else if(projection instanceof AProjectionFR) - { - if(energyType == 0 || energyType == 2) - { - internalColor(ELECTROMAGNETIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getFRUser(ELECTROMAGNETIC)))); - } - if(energyType == 1 || energyType == 2) - { - internalColor(HADRONIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getFRUser(HADRONIC)))); - } - } - else if(projection instanceof AProjectionRZ) - { - if(energyType == 0 || energyType == 2) - { - internalColor(ELECTROMAGNETIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getRZUser(ELECTROMAGNETIC)))); - } - if(energyType == 1 || energyType == 2) - { - internalColor(HADRONIC); - ag.draw(window.calculateDisplay(projection.nonLinearTransform(getRZUser(HADRONIC)))); - } - } - else if(projection instanceof AProjectionVP) - { - if(energyType == 0 || energyType == 2) - { - internalColor(ELECTROMAGNETIC); - drawVP(window, ag, ELECTROMAGNETIC); - } - if(energyType == 1 || energyType == 2) - { - internalColor(HADRONIC); - drawVP(window, ag, HADRONIC); - } - } - else - { - super.draw(window, ag, projection); - } - } - - private ACoord getYXUser(boolean emOrHad) - { - makeDrawList(); - if(emOrHad == ELECTROMAGNETIC) - applyEMCuts(); - else - applyHadCuts(); - - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double et = getET(list, emOrHad); - if(et == 0.0) - continue; - double dphi = getdPhi(list, emOrHad); - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - double cosPlus = Math.cos(phiPlus); - double sinPlus = Math.sin(phiPlus); - double cosMinus = Math.cos(phiMinus); - double sinMinus = Math.sin(phiMinus); - - double rhoMax; - double rhoMinus; - - if(emOrHad == ELECTROMAGNETIC) - { - // Rho range of LAr Detector (EM) is about between [148.175, 198.47] - rhoMax = 195; - rhoMinus = 155; - } - else - { - // Rho range of TILE Detector (Had) is about between [229, 386] - rhoMax = 380; - rhoMinus = 235; - } - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double rhoPlus = rhoMax; - if(Math.abs(et) < maxEnergy) - rhoPlus = rhoMinus + (rhoMax - rhoMinus) * Math.abs(et) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = rhoMinus * cosPlus; - hv[1][i][0] = rhoMinus * sinPlus; - // x1, y1 - hv[0][i][1] = rhoPlus * cosPlus; - hv[1][i][1] = rhoPlus * sinPlus; - // x2, y2 - hv[0][i][2] = rhoPlus * cosMinus; - hv[1][i][2] = rhoPlus * sinMinus; - // x3, y3 - hv[0][i][3] = rhoMinus * cosMinus; - hv[1][i][3] = rhoMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getFRUser(boolean emOrHad) - { - ACoord coordFR = getYXUser(emOrHad).convertYXToFR().includePhiWrapAround("FR"); - return coordFR; - } - - protected ACoord getRZUser(boolean emOrHad) - { - makeDrawList(); - if(emOrHad == ELECTROMAGNETIC) - applyEMCuts(); - else - applyHadCuts(); - - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - double et = getET(list, emOrHad); - if(et == 0.0) - continue; - - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list]-phiMid); - double rSign; - if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) - rSign = -1; - else - rSign = 1; - - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta[list]))) * 2.0; - double deta = getdEta(list, emOrHad); - double thetaPlus = Math.atan(Math.exp(-(Math.abs(eta[list]) - deta))) * 2.0; - double thetaMinus = Math.atan(Math.exp(-(Math.abs(eta[list]) + deta))) * 2.0; - - if ((eta[list] > 0.) && (rSign == -1)) - { - theta = 2 * Math.PI - theta; - thetaPlus = 2 * Math.PI - thetaPlus; - thetaMinus = 2 * Math.PI - thetaMinus; - } - else if ((eta[list] < 0.) && (rSign == -1)) - { - theta += Math.PI; - thetaPlus += Math.PI; - thetaMinus += Math.PI; - } - else if ((eta[list] < 0.) && (rSign == 1)) - { - theta = Math.PI - theta; - thetaPlus = Math.PI - thetaPlus; - thetaMinus = Math.PI - thetaMinus; - } - - double cosPlus = Math.cos(thetaPlus); - double sinPlus = Math.sin(thetaPlus); - double cosMinus = Math.cos(thetaMinus); - double sinMinus = Math.sin(thetaMinus); - - // decide the region based on the theta value - final byte LAR = 0; - final byte LAR_ENDCAP = 1; - final byte FCAL_EM = 2; - byte region = LAR; - // hard-coded value is based on the values in AGeometry.xml - if(Math.abs(Math.tan(theta)) >= 0.0778 && Math.abs(Math.tan(theta)) < 0.4828) - region = LAR_ENDCAP; - else if(Math.abs(Math.tan(theta)) < 0.0778) - region = FCAL_EM; - - double radiusMinus = 0.; - double radiusMax = 0.; - switch(region) - { - // use fixed rho/z to determine the lower radius value - case LAR: - if(emOrHad == ELECTROMAGNETIC) - { - radiusMax = 195 / Math.abs(Math.sin(theta)); - radiusMinus = 155 / Math.abs(Math.sin(theta)); - } - else - { - radiusMax = 380 / Math.abs(Math.sin(theta)); - radiusMinus = 235 / Math.abs(Math.sin(theta)); - } - break; - case LAR_ENDCAP: - if(emOrHad == ELECTROMAGNETIC) - { - radiusMax = 420 / Math.abs(Math.cos(theta)); - radiusMinus = 380 / Math.abs(Math.cos(theta)); - } - else - { - radiusMax = 585 / Math.abs(Math.cos(theta)); - radiusMinus = 440 / Math.abs(Math.cos(theta)); - } - break; - case FCAL_EM: - if(emOrHad == ELECTROMAGNETIC) - { - radiusMax = 510 / Math.abs(Math.cos(theta)); - radiusMinus = 470 / Math.abs(Math.cos(theta)); - } - else - { - radiusMax = 600 / Math.abs(Math.cos(theta)); - radiusMinus = 520 / Math.abs(Math.cos(theta)); - } - break; - } - - double maxEnergy = parameterStore.get("Projection", "EnergyMax").getD(); - double radiusPlus = radiusMax; - if(Math.abs(et) < maxEnergy) - radiusPlus = radiusMinus + (radiusMax - radiusMinus) * Math.abs(et) / maxEnergy; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = radiusMinus * cosPlus; - hv[1][i][0] = radiusMinus * sinPlus; - // x1, y1 - hv[0][i][1] = radiusPlus * cosPlus; - hv[1][i][1] = radiusPlus * sinPlus; - // x2, y2 - hv[0][i][2] = radiusPlus * cosMinus; - hv[1][i][2] = radiusPlus * sinMinus; - // x3, y3 - hv[0][i][3] = radiusMinus * cosMinus; - hv[1][i][3] = radiusMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getVPUser(boolean emOrHad) - { - makeDrawList(); - if(emOrHad == ELECTROMAGNETIC) - applyEMCuts(); - else - applyHadCuts(); - - if(numDraw == 0) - return null; - - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index=new int[numDraw]; - - for(int i=0; i<numDraw; i++) - { - int list=listdl[i]; - h[i]=eta[list]; - v[i]=Math.toDegrees(phi[list]); - index[i]=list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - private void drawGeometry(ACoord display, AWindow window, AGraphics ag, double[] density) - { - boolean drawCellGeometry = parameterStore.get(getParameterGroup(), "CellGeometry").getStatus(); - boolean drawCellOutline = parameterStore.get(getParameterGroup(), "CellOutline").getStatus(); - int cellGeometryColor = parameterStore.get(getParameterGroup(), "CellGeometry").getI(); - int cellOutlineColor = parameterStore.get(getParameterGroup(), "CellOutline").getI(); - boolean drawFrame = parameterStore.get(getParameterGroup(), "Frame").getStatus(); - int frameColor = parameterStore.get(getParameterGroup(), "Frame").getI(); - int frameWidth = parameterStore.get(getParameterGroup(), "FrameWidth").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - drawFrame = true; - else - drawFrame = false; - - if(!drawCellGeometry && !drawCellOutline) - return; - - // Draw geometry - for(int i=0; i<display.hv[0].length; ++i) - { - if(density[i] == 0.0) - continue; - - if(drawCellGeometry) - { - if(drawFrame) - { - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 1, 0, frameWidth, 0)); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - ag.updateDrawParameters(new ADrawParameters(true, cellGeometryColor, 1, 0, 0, 0)); - ag.fillPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - if(drawCellOutline) - { - ag.updateDrawParameters(new ADrawParameters(true, cellOutlineColor, 0, 1, 0, 0, false, 1, 0)); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - } - } - - private void drawHits(ACoord display, AWindow window, AGraphics ag, double[] density) - { - int[] color = this.getColor(display.index); - - boolean drawCellGeometry = parameterStore.get(getParameterGroup(), "CellGeometry").getStatus(); - boolean drawFrame = parameterStore.get(getParameterGroup(), "Frame").getStatus(); - int frameColor = parameterStore.get(getParameterGroup(), "Frame").getI(); - int frameWidth = parameterStore.get(getParameterGroup(), "FrameWidth").getI(); - int lineWidth = parameterStore.get(getParameterGroup(), "LineWidth").getI(); - - for(int i=0; i<display.hv[0].length; ++i) - { - if(density[i] == 0.0) - continue; - - // draw frame - if (drawFrame && !drawCellGeometry) - { - ag.updateDrawParameters(new ADrawParameters(true, frameColor, 1, 0, frameWidth, 0)); - ag.drawPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - } - - // draw hits - ag.updateDrawParameters(new ADrawParameters(true, color[i], 1, lineWidth, 0, 0)); - ag.setCurrentDataAndIndex(this, display.index[i]); - ag.fillPolygon(display.hv[0][i], display.hv[1][i], display.hv[0][i].length); - ag.clearCurrentDataAndIndex(); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ALegoData.java b/graphics/AtlantisJava/src/atlantis/data/ALegoData.java deleted file mode 100755 index 9c2593e53ed..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ALegoData.java +++ /dev/null @@ -1,1042 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.event.*; -import java.awt.Color; -import java.awt.geom.Point2D; - -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - -import atlantis.canvas.AWindow; -import atlantis.graphics.AGraphics; -import atlantis.graphics.ALegoDraw; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -public class ALegoData -{ - private static ALogger logger = ALogger.getLogger(ALegoData.class); - - private static APar parameterStore = APar.instance(); - - /** - * This function loops over the cell data to find the maxEt. - * It also rescales the height of the cells if different scales are selected - * @param lego the tower heights - * @return maxEt the heighest tower height - */ - public static double findMaxEt(double[][][] lego) - { - double maxEt = 0.0; - double[][] legosum = new double[lego.length][lego[0].length]; - //find colors to loop over - int largestColourIndex=0; - int lowestColourIndex=AProjectionLegoPlot.nLayers; - Iterator colorIterator = AProjectionLegoPlot.colorset.iterator(); - while(colorIterator.hasNext()) - { - int currentColor = ((Integer) colorIterator.next()).intValue(); - if(currentColor>largestColourIndex) - largestColourIndex=currentColor; - if(currentColor<lowestColourIndex) - lowestColourIndex=currentColor; - } - for (int x = AProjectionLegoPlot.nPhiCells - 1; x >= 0; --x) - { - for (int y = 0; y < AProjectionLegoPlot.nEtaCells; ++y) - { - for(int z=largestColourIndex; z>=lowestColourIndex; z--) - { - legosum[x][y] += lego[x][y][z]; - } - if(legosum[x][y] > maxEt) - maxEt = legosum[x][y]; - } - } - if(maxEt>0) - { - if (AProjectionLegoPlot.defaultScale ==1 ) - { - for (int x = AProjectionLegoPlot.nPhiCells - 1; x >= 0; --x) - { - for (int y = 0; y < AProjectionLegoPlot.nEtaCells; ++y) - { - for(int z=largestColourIndex; z>=lowestColourIndex; z--) - { - if(Math.log10(legosum[x][y])>=AProjectionLegoPlot.minimumofLogScale) - { - //if multiple colors then each take linear amount of full log - double fraction=(lego[x][y][z]/legosum[x][y]); - lego[x][y][z]=fraction*(Math.log10(legosum[x][y])-AProjectionLegoPlot.minimumofLogScale); - } - else - { - //if not above minimum of log scale then don't draw - lego[x][y][z]=0.0; - } - } - } - } - } - else if (AProjectionLegoPlot.defaultScale ==2 ) - { - for (int x = AProjectionLegoPlot.nPhiCells - 1; x >= 0; --x) - { - for (int y = 0; y < AProjectionLegoPlot.nEtaCells; ++y) - { - for(int z=largestColourIndex; z>=lowestColourIndex; z--) - { - //if multiple colors then each take linear amount of full sqrt - double fraction=(lego[x][y][z]/legosum[x][y]); - lego[x][y][z]=fraction*Math.sqrt(legosum[x][y]); - } - } - } - } - } - return maxEt; - } - - public static double findAODMaxEt(AEvent event) - { - double AODmaxEt = 0.0; - //From the caloCluster - String[] colCluster=event.getActiveCollectionNames("Cluster"); - for(int i=0;i<colCluster.length;i++) - { - AClusterData cluster = (AClusterData) event.get(colCluster[i]); - if (!parameterStore.get("Data", "Cluster").getStatus()) - cluster = null; - if (cluster != null) - { - cluster.makeDrawList(); - for (int m = 0; m < cluster.getNumDraw(); ++m) - { - int list = cluster.getDrawIndex(m); - float et = Math.abs(cluster.getET(list)); - if (et > AODmaxEt) - AODmaxEt = et; - } - } - } - //From the Jets - Added code to make th e jet considered in the AOD scaling - String[] colJet=event.getActiveCollectionNames("Jet"); - for(int i=0;i<colJet.length;i++) - { - AJetData jets = (AJetData) event.get(colJet[i]); - if (!parameterStore.get("Data", "Jet").getStatus()) - jets = null; - if (jets != null) - { - jets.makeDrawList(); - for (int m = 0; m < jets.getNumDraw(); ++m) - { - int list = jets.getDrawIndex(m); - float pt = Math.abs(jets.getPt()[list]); - if (pt > AODmaxEt) - AODmaxEt = pt; - } - } - } - // From the muons - String[] colMuon=event.getActiveCollectionNames("Muon"); - for(int i=0;i<colMuon.length;i++) - { - AMuonData muons = (AMuonData) event.get(colMuon[i]); - if (!parameterStore.get("Data", "Muon").getStatus()) - muons = null; - if (muons != null) - { - muons.makeDrawList(); - for (int m = 0; m < muons.getNumDraw(); ++m) - { - int list = muons.getDrawIndex(m); - float pt = Math.abs(muons.getPT(list)); - if (pt > AODmaxEt) - AODmaxEt = pt; - } - } - } - // From the electrons - String[] colElectron=event.getActiveCollectionNames("Electron"); - for(int i=0;i<colElectron.length;i++) - { - AElectronData electrons = (AElectronData) event.get(colElectron[i]); - if (!parameterStore.get("Data", "Electron").getStatus()) - electrons = null; - if (electrons != null) - { - - electrons.makeDrawList(); - for (int e = 0; e < electrons.getNumDraw(); ++e) - { - int list = electrons.getDrawIndex(e); - float pt = Math.abs(electrons.getPT(list)); - if (pt > AODmaxEt) - AODmaxEt = pt; - } - } - } - // From the photons - String[] colPhoton=event.getActiveCollectionNames("Photon"); - for(int i=0;i<colPhoton.length;i++) - { - APhotonData photons = (APhotonData) event.get(colPhoton[i]); - if (!parameterStore.get("Data", "Photon").getStatus()) - photons = null; - if (photons != null) - { - photons.makeDrawList(); - for (int p = 0; p < photons.getNumDraw(); ++p) - { - int list = photons.getDrawIndex(p); - float pt = Math.abs(photons.getPT(list)); - if (pt > AODmaxEt) - AODmaxEt = pt; - } - } - } - //From the compositeParticles - String[] colCompPart=event.getActiveCollectionNames("CompositeParticle"); - for(int i=0;i<colCompPart.length;i++) - { - ACompositeParticleData compositeParticles = (ACompositeParticleData) event.get(colCompPart[i]); - if (!parameterStore.get("Data", "CompositeParticle").getStatus()) - compositeParticles = null; - if (compositeParticles != null) - { - compositeParticles.makeDrawList(); - for (int e = 0; e < compositeParticles.getNumDraw(); ++e) - { - int list = compositeParticles.getDrawIndex(e); - float pt = Math.abs(compositeParticles.getPT(list)); - if (pt > AODmaxEt) - AODmaxEt = pt; - } - } - } - - return AODmaxEt; - } - - public static double findMissingEt(AWindow window, double[][][] lego, AEvent event) - { - double met = 0.; - List hitsAndTracks = event.getHitsAndTracks(window.getProjection()); - for (int h = 0; h < hitsAndTracks.size(); h++) - { - AData datatype = ((AData) hitsAndTracks.get(h)); - if (datatype.getName().equals("ETMis")) - { - AETMisData mis = (AETMisData) datatype; - mis.makeDrawList(); - if (mis.getNumDraw() > 0) - { - double temp = Math.sqrt(mis.getETx() * mis.getETx() + mis.getETy() * mis.getETy()); - if(temp>met) - met=temp; - } - } - } - return met; - } - - public static void fillHistograms(AEvent event, double[][][] lego) - { - AProjectionLegoPlot.colorset.clear(); - if (AProjectionLegoPlot.mode == 0) - { - // Calorimeter Lego - fillCaloLego(event, lego); - } - else if (AProjectionLegoPlot.mode == 1) - { - // Trigger Tower Lego - fillTriggerTowerLego(event, lego); - } - else - { - // Jet Elements Lego - fillJetElementLego(event, lego); - } - } - - private static void fillCaloLego(AEvent event, double[][][] lego) - { - List detectors = event.getCalorimeters(); - for (int det = 0; det < detectors.size(); det++) - { - ACalorimeterData calorimeter = (ACalorimeterData) detectors.get(det); - String calname=calorimeter.getName(); - if (!calname.equals("TILE") && !calname.equals("FCAL") - && !calname.equals("HEC") && !calname.equals("LAr") - && !calname.equals("MBTS")) - { - logger.warn("Unknown calorimeter name for LegoPlot: " + calorimeter.getName()); - } - - calorimeter.makeDrawList(); - // for coloring - byte[] c = calorimeter.getColor(); - for (int i = 0; i < calorimeter.getNumDraw(); ++i) - { - int list = calorimeter.getDrawIndex(i); - double et = calorimeter.getET(list); - //MBTS energy is in MeV not GeV - if(calname.equals("MBTS")) et/=1000.; - double phi = calorimeter.getPhi(list); - double eta = calorimeter.getEta(list); - if (eta > 5 || eta < -5 || et == 0.0) - continue; - double dphi = calorimeter.getdPhi(list); - double deta = calorimeter.getdEta(list); - phietabinsLoop("calo", phi, dphi, eta, deta, c[list], et, lego); - }// loop over that calorimeter's cells - }// loop over the calorimeters - } - - private static void fillTriggerTowerLego(AEvent event, double[][][] lego) - { - //will draw even if data status is off - String[] colTT=event.getCollectionNames("LVL1TriggerTower"); - for(int k=0;k<colTT.length;k++) - { - ALVL1TriggerTowerData lvl1TriggerTower = (ALVL1TriggerTowerData) event.get(colTT[k]); - if (lvl1TriggerTower == null) - continue; - - byte[] ttColor; - for (int j = 0; j < 2; ++j) - { - int energyType = parameterStore.get(lvl1TriggerTower.getParameterGroup(), "EnergyType").getI(); - if((j == 0 && energyType == 1) || (j == 1 && energyType == 0)) - continue; - lvl1TriggerTower.makeDrawList(); - - boolean emOrHad; - if (j == 0) - { - emOrHad = ALVL1TriggerTowerData.ELECTROMAGNETIC; - lvl1TriggerTower.applyEMCuts(); - } - else - { - emOrHad = ALVL1TriggerTowerData.HADRONIC; - lvl1TriggerTower.applyHadCuts(); - } - ttColor = lvl1TriggerTower.getColor(emOrHad); - for (int i = 0; i < lvl1TriggerTower.getNumDraw(); ++i) - { - int list = lvl1TriggerTower.getDrawIndex(i); - double et = lvl1TriggerTower.getET(list, emOrHad); - double phi = lvl1TriggerTower.getPhi(list); - double eta = lvl1TriggerTower.getEta(list); - if (eta > 5 || eta < -5 || et == 0.0) - continue; - double dphi = lvl1TriggerTower.getdPhi(list, emOrHad); - double deta = lvl1TriggerTower.getdEta(list, emOrHad); - phietabinsLoop("trigger", phi, dphi, eta, deta, ttColor[list], et, lego); - }// loop over that triggerTower's cells - } - } - } - - private static void fillJetElementLego(AEvent event, double[][][] lego) - { - //will draw even if data status is off - String[] colJE=event.getCollectionNames("LVL1JetElement"); - for(int k=0;k<colJE.length;k++) - { - ALVL1JetElementData lvl1JetElement = (ALVL1JetElementData) event.get(colJE[k]); - if (lvl1JetElement == null) - continue; - byte[] jeColor = lvl1JetElement.getColor(); - lvl1JetElement.makeDrawList(); - for (int i = 0; i < lvl1JetElement.getNumDraw(); ++i) - { - int list = lvl1JetElement.getDrawIndex(i); - double et = lvl1JetElement.getET(list); - double phi = lvl1JetElement.getPhi(list); - double eta = lvl1JetElement.getEta(list); - if (eta > 5 || eta < -5 || et == 0.0) - continue; - double dphi = lvl1JetElement.getdPhi(list); - double deta = lvl1JetElement.getdEta(list); - phietabinsLoop("jetElement", phi, dphi, eta, deta, jeColor[list], et, lego); - }// loop over that jetElement's cells - } - } - - /** - * Is used to loop over the phi and eta bins to fill the lego "sender" - * histogram - * - * @param sender name of histogram that was sent for output message - * @param phi - * @param dphi - * @param eta - * @param deta - * @param color - * @param et - * @param lego - */ - private static void phietabinsLoop(String sender, double phi, double dphi, double eta, double deta, byte color, double et, double[][][] lego) - { - if (color >= AProjectionLegoPlot.nLayers) - color = (byte) (color % AProjectionLegoPlot.nLayers); - AProjectionLegoPlot.colorset.add(new Integer(color)); - - int highphibin = 0, lowphibin = 0; - - double phibinsize = (AMath.TWO_PI / AProjectionLegoPlot.nPhiCells); - highphibin = (int) ((phi + dphi) /phibinsize); - lowphibin = (int) ((phi - dphi) /phibinsize); - - int highetabin = 0, lowetabin = 0; - double etabinsize = 10.0 / AProjectionLegoPlot.nEtaCells; - highetabin = (int) ((eta + deta + 5.0) /etabinsize); - lowetabin = (int) ((eta - deta + 5.0) /etabinsize); - //check eta values - if (lowetabin < 0) - { - lowetabin=0; - if (highetabin < 0) - highetabin=0; - } - if (highetabin >= AProjectionLegoPlot.nEtaCells) - { - highetabin =AProjectionLegoPlot.nEtaCells-1; - if (lowetabin >= AProjectionLegoPlot.nEtaCells) - lowetabin =AProjectionLegoPlot.nEtaCells-1; - } - - for (int phibin = lowphibin; phibin <= highphibin; ++phibin) - { - double phiweight = 0; - if (lowphibin == highphibin) - phiweight = 1.0; - else if (phibin == lowphibin) - phiweight = (lowphibin + 1 - ((phi - dphi) / phibinsize)) * (phibinsize/(2 * dphi)); - else if (phibin == highphibin) - phiweight = (((phi + dphi) / phibinsize) - highphibin) * (phibinsize/(2 * dphi)); - else - phiweight = phibinsize/(2 * dphi); - if (phiweight > 1 || phiweight < 0) - { - logger.error("huh(" + sender + ")? how is phiweight...? " + phiweight); - } - - for (int etabin = lowetabin; etabin <= highetabin; ++etabin) - { - double etaweight = 0; - if (lowetabin == highetabin) - etaweight = 1.0; - else if (etabin == lowetabin) - etaweight = (lowetabin + 1 - ((eta - deta + 5.0) / etabinsize)) * (etabinsize/(2 * deta)); - else if (etabin == highetabin) - etaweight = (((eta + deta + 5.0) / etabinsize) - highetabin) * (etabinsize/(2 * deta)); - else - etaweight = etabinsize/(2 * deta); - if (etaweight > 1 || etaweight < 0) - { - logger.error("huh(" + sender + ")? how is etaweight...? " + etaweight); - } - - int wphibin = phibin;// for phi wrapping - while (wphibin >= AProjectionLegoPlot.nPhiCells) - wphibin -= AProjectionLegoPlot.nPhiCells; - while (wphibin < 0) - wphibin += AProjectionLegoPlot.nPhiCells; - int retabin = etabin; - if (AProjectionLegoPlot.reverse) - retabin = AProjectionLegoPlot.nEtaCells - etabin - 1; - - // add to the legoplot - lego[wphibin][retabin][color] += et * phiweight * etaweight; - }// loop over etabins - }// loop over phibins - }// end of phietabinsloop - - /** - * If the user has a different scale selected then this updates the value - */ - public static double scaleValue(double value) - { - if(value==0) - return 0; - if (AProjectionLegoPlot.defaultScale == 2) - { - value = Math.sqrt(value); - } - else if (AProjectionLegoPlot.defaultScale == 1) - { - value = Math.log10(value) - AProjectionLegoPlot.minimumofLogScale; - } - return value; - } - - public static void drawHistograms(AWindow window, AGraphics ag, AEvent event, double[][][] lego, double maxEt, double met, double AODmaxEt) - { - // Draw the other stuff in the event: jets, missing Et, etc. - double _jetcircleradius = parameterStore.get("LegoPlot", "JetCircleRadius").getD(); - double _legocut = parameterStore.get("LegoPlot", "LegoCut").getD(); - _legocut=scaleValue(_legocut); - boolean doAOD = false; - if (AODmaxEt!=0) - doAOD = true; - - //for ordering of ROIs - Stack jetROI = new Stack(), emTauROI = new Stack(), muonROI = new Stack(); - - List hitsAndTracks = event.getHitsAndTracks(window.getProjection()); - for (int h = 0; h < hitsAndTracks.size(); h++) - { - AData datatype = ((AData) hitsAndTracks.get(h)); - if (datatype.getName().equals("Jet")) - { - AJetData jet = (AJetData) datatype; - jet.makeDrawList(); - byte[] colors = jet.getColor(); - for (int j = 0; j < jet.getNumDraw(); ++j) - { - int list = jet.getDrawIndex(j); - double et = jet.getET(list); - Color _colorJet = AProjectionLegoPlot.defaultColorMap[colors[list]]; - ALegoDraw.drawJet(et, jet.getEta(list), jet.getPhi(list), _colorJet, window, ag, _jetcircleradius); - } - } - else if (datatype.getName().equals("ETMis")) - { - AETMisData mis = (AETMisData) datatype; - mis.makeDrawList(); - if (mis.getNumDraw() > 0) - { - byte[] colors = mis.getColor(); - int phib = (int) ((mis.getPhi()) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - if (phib < 0) - phib += AProjectionLegoPlot.nPhiCells; - if (phib >= AProjectionLegoPlot.nPhiCells) - phib -= AProjectionLegoPlot.nPhiCells; - Color _colorMis = AProjectionLegoPlot.defaultColorMap[colors[0]]; - ALegoDraw.drawMissEt(window, ag, phib, mis.getET(), _colorMis, maxEt); - } - } - //save the ROIs so they can be drawn jet-em-muon - else if (datatype.getName().equals("JetROI")) - { - jetROI.push(h); - } - else if (datatype.getName().equals("EmTauROI")) - { - emTauROI.push(h); - } - else if (datatype.getName().equals("MuonROI")) - { - muonROI.push(h); - } - }//end of loop over hitsandtracks - - //now draw the ROIs in the correct order - drawROIs(jetROI, window, ag, event); - drawROIs(emTauROI, window, ag, event); - drawROIs(muonROI, window, ag, event); - - - //for towers find colors to loop over - int largestColourIndex=0; - int lowestColourIndex=AProjectionLegoPlot.nLayers; - Iterator colorIterator = AProjectionLegoPlot.colorset.iterator(); - while(colorIterator.hasNext()) - { - int currentColor = ((Integer) colorIterator.next()).intValue(); - if(currentColor>largestColourIndex) - largestColourIndex=currentColor; - if(currentColor<lowestColourIndex) - lowestColourIndex=currentColor; - } - // Draw the EM and HAD towers - for (int y = 0; y < AProjectionLegoPlot.nEtaCells; ++y) - { - for (int x = AProjectionLegoPlot.nPhiCells - 1; x >= 0; --x) - { - double binheight = 0; - if(AProjectionLegoPlot.getDrawEMHAD() && AProjectionLegoPlot.colorset.size()==2) - { - //for Em/had option should only have 2 colors - int z=AProjectionLegoPlot.colorEM; - binheight=lego[x][y][z]; - if (binheight > _legocut) - { - ALegoDraw.drawBox(window, ag, x, y, z, 0.0, binheight, maxEt, 0.5); - if(lego[x][y][AProjectionLegoPlot.colorHad]> _legocut) - { - z=AProjectionLegoPlot.colorHad; - ALegoDraw.drawBox(window, ag, x, y, z, binheight, lego[x][y][z], maxEt, 0.5); - } - } - else if(lego[x][y][AProjectionLegoPlot.colorHad]> _legocut) - { - z=AProjectionLegoPlot.colorHad; - ALegoDraw.drawBox(window, ag, x, y, z, 0.0, lego[x][y][z], maxEt, 0.5); - } - } - else - { - //if not Em/Had then loop over colors - for(int z=largestColourIndex; z>=lowestColourIndex; z--) - { - if (lego[x][y][z] > _legocut) - { - ALegoDraw.drawBox(window, ag, x, y, z, binheight, lego[x][y][z], maxEt, 0.5); - binheight += lego[x][y][z]; - } - } - } - } - } - - //loop again and draw things that need to be on top of histogram - for (int h = 0; h < hitsAndTracks.size(); h++) - { - AData datatype = ((AData) hitsAndTracks.get(h)); - if (datatype.getName().equals("Jet")) - { - AJetData jet = (AJetData) datatype; - jet.makeDrawList(); - byte[] colors = jet.getColor(); - for (int j = 0; j < jet.getNumDraw(); ++j) - { - int list = jet.getDrawIndex(j); - double et = jet.getET(list); - Color _colorJet = AProjectionLegoPlot.defaultColorMap[colors[list]]; - if (parameterStore.get("LegoPlot", "JetText").getStatus()) - ALegoDraw.drawJetText(et, jet.getEta(list), jet.getPhi(list), _colorJet, window, ag, _jetcircleradius); - } - } - } - - if (doAOD) - { - //Draw the new jet Towers - String[] colJet=event.getActiveCollectionNames("Jet"); - for(int i=0;i<colJet.length;i++) - { - AJetData jets = (AJetData) event.get(colJet[i]); - - if (!parameterStore.get("Data", "Jet").getStatus()) - jets = null; - if (jets != null) - { - jets.makeDrawList(); - byte[] colors = jets.getColor(); - for (int j = 0; j < jets.getNumDraw(); ++j) - { - int list = jets.getDrawIndex(j); - Color _colorJet = AProjectionLegoPlot.defaultColorMap[colors[list]]; - int etabin = (int) ((jets.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((jets.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double pt = Math.abs(jets.getPt()[list]); - pt=scaleValue(pt); - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_JET,_colorJet, 0, pt, maxEt, 2.0); - } - } - } - - // Draw the caloClusters - String[] colCluster=event.getActiveCollectionNames("Cluster"); - for(int i=0;i<colCluster.length;i++) - { - AClusterData cluster = (AClusterData) event.get(colCluster[i]); - if (!parameterStore.get("Data", "Cluster").getStatus()) - cluster = null; - if (cluster != null) - { - cluster.makeDrawList(); - for (int m = 0; m < cluster.getNumDraw(); ++m) - { - int list = cluster.getDrawIndex(m); - int etabin = (int) ((cluster.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((cluster.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double et = Math.abs(cluster.getET(list)); - et=scaleValue(et); - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_CLUSTER, 0, et, maxEt, .5); - } - } - } - - // Draw the bjets - String[] colBjets=event.getActiveCollectionNames("BJet"); - for(int i=0;i<colBjets.length;i++) - { - ABJetData bjets = (ABJetData) event.get(colBjets[i]); - if (!parameterStore.get("Data", "BJet").getStatus()) - bjets = null; - if (bjets != null) - { - bjets.makeDrawList(); - for (int bj = 0; bj < bjets.getNumDraw(); ++bj) - { - int list = bjets.getDrawIndex(bj); - double et = bjets.getPT(list); - ALegoDraw.drawJet(et, bjets.getEta(list), bjets.getPhi(list), AProjectionLegoPlot.defaultColorMap[parameterStore.get("BJet", "Constant").getI()], window, ag, _jetcircleradius + _jetcircleradius / 5.0); - } - } - } - - // Draw the taujets - String[] colTau=event.getActiveCollectionNames("TauJet"); - for(int i=0;i<colTau.length;i++) - { - ATauJetData tjets = (ATauJetData) event.get(colTau[i]); - if (!parameterStore.get("Data", "TauJet").getStatus()) - tjets = null; - if (tjets != null) - { - tjets.makeDrawList(); - for (int tj = 0; tj < tjets.getNumDraw(); ++tj) - { - int list = tjets.getDrawIndex(tj); - double et = tjets.getPT(list); - ALegoDraw.drawJet(et, tjets.getEta(list), tjets.getPhi(list), AProjectionLegoPlot.defaultColorMap[parameterStore.get("TauJet", "Constant").getI()], window, ag, _jetcircleradius / 2.0); - } - } - } - - //Draw the muons - String[] colMuon=event.getActiveCollectionNames("Muon"); - for(int i=0;i<colMuon.length;i++) - { - AMuonData muons = (AMuonData) event.get(colMuon[i]); - if (!parameterStore.get("Data", "Muon").getStatus()) - muons = null; - if (muons != null) - { - muons.makeDrawList(); - for (int m = 0; m < muons.getNumDraw(); ++m) - { - int list = muons.getDrawIndex(m); - int etabin = (int) ((muons.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((muons.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double pt = Math.abs(muons.getPT(list)); - pt=scaleValue(pt); - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_MUON, 0, pt, maxEt, 0.5); - } - } - } - - //Draw the electrons - String[] colElectron=event.getActiveCollectionNames("Electron"); - for(int i=0;i<colElectron.length;i++) - { - AElectronData electrons = (AElectronData) event.get(colElectron[i]); - - if (!parameterStore.get("Data", "Electron").getStatus()) - electrons = null; - if (electrons != null) - { - electrons.makeDrawList(); - for (int e = 0; e < electrons.getNumDraw(); ++e) - { - int list = electrons.getDrawIndex(e); - int etabin = (int) ((electrons.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((electrons.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double pt = Math.abs(electrons.getPT(list)); - pt=scaleValue(pt); - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_ELECTRON, 0, pt, maxEt, 0.5); - } - } - } - - //Draw the photons - String[] colPhoton=event.getActiveCollectionNames("Photon"); - for(int i=0;i<colPhoton.length;i++) - { - APhotonData photons = (APhotonData) event.get(colPhoton[i]); - if (!parameterStore.get("Data", "Photon").getStatus()) - photons = null; - if (photons != null) - { - photons.makeDrawList(); - for (int p = 0; p < photons.getNumDraw(); ++p) - { - int list = photons.getDrawIndex(p); - int etabin = (int) ((photons.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((photons.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double pt = Math.abs(photons.getPT(list)); - pt=scaleValue(pt); - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_PHOTON, 0, pt, maxEt, 0.5); - } - } - } - - //Draw the compositeParticles - String[] colCompPart=event.getActiveCollectionNames("CompositeParticle"); - for(int i=0;i<colCompPart.length;i++) - { - ACompositeParticleData compositeParticles = (ACompositeParticleData) event.get(colCompPart[i]); - if (!parameterStore.get("Data", "CompositeParticle").getStatus()) - compositeParticles = null; - if (compositeParticles != null) - { - compositeParticles.makeDrawList(); - for (int e = 0; e < compositeParticles.getNumDraw(); ++e) - { - int list = compositeParticles.getDrawIndex(e); - int etabin = (int) ((compositeParticles.getEta(list) + 5.0) * AProjectionLegoPlot.nEtaCells / 10.0); - if (AProjectionLegoPlot.reverse) - etabin = AProjectionLegoPlot.nEtaCells - etabin; - int phibin = (int) ((compositeParticles.getPhi(list)) * AProjectionLegoPlot.nPhiCells / AMath.TWO_PI); - double pt = Math.abs(compositeParticles.getPT(list)); - pt=scaleValue(pt); - //change how drawn depending on type - if(Math.abs(compositeParticles.getPdgId(list))==13) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_MUON, 0, pt, maxEt, 0.5); - else if(Math.abs(compositeParticles.getPdgId(list))==11) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_ELECTRON, 0, pt, maxEt, 0.5); - else if(Math.abs(compositeParticles.getPdgId(list))==22) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_PHOTON, 0, pt, maxEt, 0.5); - else if(Math.abs(compositeParticles.getPdgId(list))==5) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_BJET, 0, pt, maxEt, 0.5); - else if(Math.abs(compositeParticles.getPdgId(list))==15) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_TAUJET, 0, pt, maxEt, 0.5); - else if(compositeParticles.getTypeEV(list).equals("EVParticleJet")) - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_JET, 0, pt, maxEt, 0.5); - else - ALegoDraw.drawBox(window, ag, phibin, etabin, AProjectionLegoPlot.DRAW_COMPOSITEPARTICLE, 0, pt, maxEt, 0.5); - } - } - } - }//if doAOD - }//drawHistograms - - public static void drawROIs(Stack ROIstack, AWindow window, AGraphics ag, AEvent event) - { - List hitsAndTracks = event.getHitsAndTracks(window.getProjection()); - //loop over ROIs - while(ROIstack.size()>0) - { - int h = (Integer) ROIstack.pop(); - AData datatype = ((AData) hitsAndTracks.get(h)); - - byte[] ROIColor; - double deltaPhi; - double deltaEta; - AROIData ROIData = (AROIData) datatype; - ROIData.makeDrawList(); - ROIColor = datatype.getColor(); - deltaEta = parameterStore.get(datatype.getName(), "deta").getD(); - deltaPhi = parameterStore.get(datatype.getName(), "dphi").getD(); - // deltaEta and deltaPhi should not be too large - for (int j = 0; j < ROIData.getNumDraw(); ++j) - { - int numPoints = 4; - int list = ROIData.getDrawIndex(j); - double ROIphi = ROIData.getPhi(list); - double ROIeta = ROIData.getEta(list); - if (AProjectionLegoPlot.reverse) - ROIeta = -ROIeta; - double leftPhi = ROIphi - deltaPhi; - double rightPhi = ROIphi + deltaPhi; - double topEta = ROIeta + deltaEta; - double bottomEta = ROIeta - deltaEta; - if ((ROIColor[list] < AProjectionLegoPlot.defaultColorMap.length) && (ROIColor[list] >= 0)) - ag.setColor(AProjectionLegoPlot.defaultColorMap[ROIColor[list]]); - ag.setLineWidth(3); - double ROIx = 0.0; - double ROIy = 0.0; - double[][] hv = new double[2][numPoints]; - if ((rightPhi <= AMath.TWO_PI) && (leftPhi >= 0.0)) - { - for (int p = 0; p < numPoints; p++) - { - switch (p) - { - case 0: - ROIx = rightPhi * 360.0 / AMath.TWO_PI; - ROIy = bottomEta; - break; - case 1: - ROIx = leftPhi * 360.0 / AMath.TWO_PI; - ROIy = bottomEta; - break; - case 2: - ROIx = leftPhi * 360.0 / AMath.TWO_PI; - ROIy = topEta; - break; - case 3: - ROIx = rightPhi * 360.0 / AMath.TWO_PI; - ROIy = topEta; - break; - } - if(ROIy <= -5.0) - ROIy = -5.0; - if(ROIy >= 5.0) - ROIy = 5.0; - //move phi value due to slant of eta axis - ROIx=AProjectionLegoPlot.adjustPhi(window,ROIx,ROIy); - hv[0][p] = ROIx; - hv[1][p] = ROIy; - } - } - else if ((rightPhi > AMath.TWO_PI) && (leftPhi < 0.0)) - { - for (int p = 0; p < numPoints; p++) - { - switch (p) - { - case 0: - ROIx = 360.0; - ROIy = bottomEta; - break; - case 1: - ROIx = 0.0; - ROIy = bottomEta; - break; - case 2: - ROIx = 0.0; - ROIy = topEta; - break; - case 3: - ROIx = 360.0; - ROIy = topEta; - break; - } - if(ROIy <= -5.0) - ROIy = -5.0; - if(ROIy >= 5.0) - ROIy = 5.0; - //move phi value due to slant of eta axis - ROIx=AProjectionLegoPlot.adjustPhi(window,ROIx,ROIy); - hv[0][p] = ROIx; - hv[1][p] = ROIy; - } - } - else if (rightPhi > AMath.TWO_PI) - { - double[][] hvWrap = new double[2][numPoints]; - double ROIxWrap = 0.0; - for (int p = 0; p < numPoints; p++) - { - switch (p) - { - case 0: - ROIx = 360.0; - ROIxWrap = (rightPhi - AMath.TWO_PI) * 360.0 / AMath.TWO_PI; - ROIy = bottomEta; - break; - case 1: - ROIx = leftPhi * 360.0 / AMath.TWO_PI; - ROIxWrap = 0.0; - ROIy = bottomEta; - break; - case 2: - ROIx = leftPhi * 360.0 / AMath.TWO_PI; - ROIxWrap = 0.0; - ROIy = topEta; - break; - case 3: - ROIx = 360.0; - ROIxWrap = (rightPhi - AMath.TWO_PI) * 360.0 / AMath.TWO_PI; - ROIy = topEta; - break; - } - if(ROIy <= -5.0) - ROIy = -5.0; - if(ROIy >= 5.0) - ROIy = 5.0; - //move phi value due to slant of eta axis - ROIx=AProjectionLegoPlot.adjustPhi(window,ROIx,ROIy); - hv[0][p] = ROIx; - hv[1][p] = ROIy; - //move phi value due to slant of eta axis - ROIxWrap=AProjectionLegoPlot.adjustPhi(window,ROIxWrap,ROIy); - hvWrap[0][p] = ROIxWrap; - hvWrap[1][p] = ROIy; - } - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<numPoints; i++) - { - p = window.calculateDisplay(hvWrap[0][i],hvWrap[1][i]); - hvWrap[0][i]=p.x; - hvWrap[1][i]=p.y; - } - ag.fillPolygon(hvWrap[0], hvWrap[1], numPoints); - } - else - { - double[][] hvWrap = new double[2][numPoints]; - double ROIxWrap = 0.0; - for (int p = 0; p < numPoints; p++) - { - switch (p) - { - case 0: - ROIx = rightPhi * 360.0 / AMath.TWO_PI; - ROIxWrap = 360.0; - ROIy = bottomEta; - break; - case 1: - ROIx = 0.0; - ROIxWrap = (leftPhi + AMath.TWO_PI) * 360.0 / AMath.TWO_PI; - ROIy = bottomEta; - break; - case 2: - ROIx = 0.0; - ROIxWrap = (leftPhi + AMath.TWO_PI) * 360.0 / AMath.TWO_PI; - ROIy = topEta; - break; - case 3: - ROIx = rightPhi * 360.0 / AMath.TWO_PI; - ROIxWrap = 360.0; - ROIy = topEta; - break; - } - if(ROIy <= -5.0) - ROIy = -5.0; - if(ROIy >= 5.0) - ROIy = 5.0; - //move phi value due to slant of eta axis - ROIx=AProjectionLegoPlot.adjustPhi(window,ROIx,ROIy); - hv[0][p] = ROIx; - hv[1][p] = ROIy; - //move phi value due to slant of eta axis - ROIxWrap=AProjectionLegoPlot.adjustPhi(window,ROIxWrap,ROIy); - hvWrap[0][p] = ROIxWrap; - hvWrap[1][p] = ROIy; - } - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<numPoints; i++) - { - p = window.calculateDisplay(hvWrap[0][i],hvWrap[1][i]); - hvWrap[0][i]=p.x; - hvWrap[1][i]=p.y; - } - ag.fillPolygon(hvWrap[0], hvWrap[1], numPoints); - } - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<numPoints; i++) - { - p = window.calculateDisplay(hv[0][i],hv[1][i]); - hv[0][i]=p.x; - hv[1][i]=p.y; - } - ag.fillPolygon(hv[0], hv[1], numPoints); - }//end of loop over ROI data - } - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMBTSData.java b/graphics/AtlantisJava/src/atlantis/data/AMBTSData.java deleted file mode 100644 index 931b749640d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMBTSData.java +++ /dev/null @@ -1,595 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.ALogger; - - -/** - * The Minimum Bias Trigger Scintillator implementation. - * - * @author Mark Stockton - */ -public class AMBTSData extends ACalorimeterData -{ - private static ALogger logger = ALogger.getLogger(AMBTSData.class); - - - /* - * For Rz histograms may/will need: - * - * private int[][] cellTable; - * - * phiIndex[i] - * etaIndex[i] - * outerEta -> use -> detector.getEtaMax() - * outerR -> use -> detector.getRMax() - * outerZ -> use -> detector.getZMax() - * etaGranularity - */ - - protected float[] quality; - protected float[] time; - //label not needed at present as is just a string made - // from type, module and channel - //protected String[] label; - - // data for real pulse shapes plots - private int[][] adcCounts = null; - private float[] cellPedestal = null; - private float[] cellRawTime = null; - private float[] cellRawAmplitude = null; - private static boolean pulseShapesDataAvailable = false; - private static final String LOOKUP_TABLE_FILE = - AGlobals.instance().getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - "rpsplt_tile.csv"; - // number of lookup table values for real pulse shapes plots calculation - private static final short NUMBER_OF_LOOKUP_VALUES = 401; - - - - - protected ACalorimeterDetector[] MBTSlayers = new ACalorimeterDetector[2]; - - AMBTSData(AHashMap p, AEvent e) - { - super(p,e); - - channel = p.getIntArray("channel"); - /* - * this energy is in MeV not GeV - */ - et = p.getFloatArray("energy"); - etSum = p.getFloatArray("energy"); - //label = p.getStringArray("label"); - quality = p.getFloatArray("quality"); - sampling = p.getIntArray("sampling"); - time = p.getFloatArray("time"); - - /* - * The phi and eta coordinates used here are actually not phi and eta - * - * Instead: - phi refers to the module number 0-8 - * - eta refers to which side of the detector - * - * The actual phi and eta are then calculated from the geometry object - */ - int[] inteta; - int[] intphi; - if( p.containsKey("module")) - { - //phi new version - intphi = p.getIntArray("module"); - } - else - { - //phi first version - float[] tempphi = p.getFloatArray("phi"); - intphi = new int[numData]; - for(int i=0; i<numData; i++) - { - intphi[i]=(int) (( (8*tempphi[i])/(2*Math.PI))-(1/2)); - } - } - - if( p.containsKey("type")) - { - //eta new version - inteta = p.getIntArray("type"); - } - else - { - //eta first version - float[] tempeta = p.getFloatArray("eta"); - inteta = new int[numData]; - for(int i=0; i<numData; i++) - { - if(tempeta[i]<0) - { - inteta[i] = -1; - } - else - { - inteta[i] = 1; - } - } - } - eta = new float[numData]; - phi = new float[numData]; - for(int i=0; i<numData; i++) - { - eta[i]=inteta[i]; - phi[i]=intphi[i]; - } - - //now define sub and side depending on eta value - for(int i=0; i<numData; i++) - { - if(eta[i]<0) - { - sub[i] = 0; - side[i] = -1; - } - else - { - sub[i] = 1; - side[i] = 1; - } - } - - //store the two sampling of the MBTS geometry - for (int i=0; i<ACalorimeterDetector.count(); i++) - { - ACalorimeterDetector detector = ACalorimeterDetector.get(i); - if(detector.getName().equals("Minimum Bias Trigger Scintillators")) - { - MBTSlayers[detector.getSampling()] = detector; - } - } - - // read in MBTS data for real pulse shapes plots - readPulseShapePlotData(p); - - } - - - - private void readPulseShapePlotData(AHashMap p) - { - // read ADCCounts and cell data for real pulse shapes plots - adcCounts = super.getADCCountsData(p); - - // read other MBTS data for real pulse shapes plots - cellPedestal = (p.get("cellPedestal") != null) ? p.getFloatArray("cellPedestal") : null; - cellRawTime = (p.get("cellRawTime") != null) ? p.getFloatArray("cellRawTime") : null; - cellRawAmplitude = (p.get("cellRawAmplitude") != null) ? p.getFloatArray("cellRawAmplitude") : null; - - pulseShapesDataAvailable = false; - if(adcCounts != null && cellPedestal != null && cellRawTime != null && - cellRawAmplitude != null) - { - pulseShapesDataAvailable = true; - - logger.debug(CALORIMETER_NAME + - ": data for real pulse shape plots available"); - - if(ACalorimeterRPSPLT.areTileLookupTablesInitialized()) - { - logger.debug(CALORIMETER_NAME + - ": lookup tables have already been read in"); - } - else - { - logger.debug(CALORIMETER_NAME + - ": lookup table values have not been read in yet\n" + - " trying to read file: " + LOOKUP_TABLE_FILE); - - try - { - ATILEData.readLookupTableFile(); - logger.debug(CALORIMETER_NAME + - ": values from " + LOOKUP_TABLE_FILE + - " successfully read in"); - } - catch(AAtlantisException ex) - { - logger.debug(CALORIMETER_NAME + - ": reading " + LOOKUP_TABLE_FILE + - " failed, real pulse shapes plots will not " + - "be available, reason: " + ex.getMessage(), ex); - pulseShapesDataAvailable = false; - } - } - } - - } // readPulseShapePlotData() ------------------------------------------- - - - - /** - * Returns the name of the parameter group. - * - * @return String parameter group - */ - public String getParameterGroup() - { - return "TILE"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getName() - { - return "MBTS"; - } - - /** - * Returns the name of the datatype. - * - * @return String datatype - */ - public String getNameScreenName() - { - return "MBTS"; - } - - /** - * Returns the type of calorimeter (ECAL/HCAL) for a hit. - * - * @param index int hit index - * @return String calorimeter type - */ - public String getCalorimeterType(int index) - { - return "HCAL"; - } - - /** - * Draws the MBTS data in the y-x projection. - * - * @return ACoord cell geometry polygons - */ - protected ACoord getYXUser() - { - makeDrawList(); - - int mode = parameterStore.get("YX", "Mode").getI(); - if (mode != AProjectionYX.MODE_MBTS) - { - return ACoord.NO_DATA; - } - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - double rMax = MBTSlayers[sampling[j]].getRMax(); - double rMin = MBTSlayers[sampling[j]].getRMin(); - int numPhi = MBTSlayers[sampling[j]].getNumPhi(); - double phiMin = Math.PI*2*phi[j]/numPhi; - double phiMax = Math.PI*2*(1+phi[j])/numPhi; - hv[0][i] = new double[] {rMax*Math.cos(phiMin), rMax*Math.cos(phiMax), - rMin*Math.cos(phiMax), rMin*Math.cos(phiMin)}; - hv[1][i] = new double[] {rMax*Math.sin(phiMin), rMax*Math.sin(phiMax), - rMin*Math.sin(phiMax), rMin*Math.sin(phiMin)}; - index[i] = j; - } - - return new ACoord(hv, index, this); - } - - /** - * Draws the MBTS data in the rho-z projection. See the description of - * filterDrawListRZ() for an explanation of the drawing method. - * - * @return ACoord cell geometry polygons - */ - protected ACoord getRZUser() - { - makeDrawList(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int j = listdl[i]; - int sign = MBTSlayers[sampling[j]].getRSign((int) phi[j]); - double zMax = MBTSlayers[sampling[j]].getZMax() * side[j]; - double zMin = MBTSlayers[sampling[j]].getZMin() * side[j]; - double rMax = MBTSlayers[sampling[j]].getRMax() * sign; - double rMin = MBTSlayers[sampling[j]].getRMin() * sign; - hv[0][i] = new double[] {zMax, zMin, zMin, zMax}; - hv[1][i] = new double[] {rMax, rMax, rMin, rMin}; - index[i] = j; - } - - return new ACoord(hv, index, this); - } - - /** - * Applies cuts to the data. - */ - protected void applyCuts() - { - super.applyCuts(); - - cut("CutsCalo", "MBTSEnergy", "MBTSEnergy", et); - int cutSub = parameterStore.get("CutsCalo", "MBTS").getI(); - if(cutSub != -1) - { - cutArray(sub, cutSub, "Endcap"); - } - } - - /** - * Returns the data in the phi-rho projection. - * - * @return ACoord polygons representing calorimeter cells - */ - public ACoord getFRUser() - { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - /** - * Returns info about a selected hit (for picking) - * - * @param index int hit index - * @return String info - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - "\n Energy="+correctEnergy(energy[index])+" GeV\n "; - - //find the cell energy on the opposite MBTS layer - String cellminus, cellplus; - double tempEnergy=0.0; - for(int i=0; i<energy.length; i++) - { - if(eta[i]==(-1.0*eta[index]) && phi[i]==phi[index] && sampling[i]==sampling[index]) - { - tempEnergy=energy[i]; - } - } - - if(eta[index]<0) - { - cellminus = correctEnergy(energy[index]); - cellplus = correctEnergy(tempEnergy); - } - else - { - cellplus = correctEnergy(energy[index]); - cellminus = correctEnergy(tempEnergy); - } - StringBuffer msg = new StringBuffer(CALORIMETER_NAME + " cell "); - - // calling AIdHelper.getFullIdentifier(id[index])[0] - does not work, - // id array is not present in the event data. it is arbitrarily created - // in Atlantis, however, but contains only indices, thus currently - // (2008-11-25) index and id[index] are the same values - msg.append(" (id: " + id[index] + " index: " + index + ")"); - - msg.append("\n Energy = " + correctEnergy(energy[index])); - msg.append("\n (MBTS + = " + cellplus + " MBTS - = " + cellminus + ")"); - msg.append("\n time = " + time[index]); - msg.append("\n quality = " + quality[index]); - msg.append("\n type = " + String.format("%.4f",eta[index])); - msg.append("\n module = " + String.format("%.1f",phi[index])); - msg.append("\n sampling = " + sampling[index]); - msg.append("\n channel = " + channel[index]); - - // real pulse shapes plots - msg.append("\n cell pedestal = "); - String m = (cellPedestal != null) ? Float.toString(cellPedestal[index]) + - " ADC counts" : "n/a"; - msg.append(m); - - m = pulseShapesDataAvailable ? "" : "\n data for real pulse shapes plot n/a"; - msg.append(m); - - return msg.toString(); - - } // getHitInfo() ------------------------------------------------------- - - private String correctEnergy(double energy) - { - String energyOutput; - if(energy>1.) - { - energyOutput = String.format("%.2f",energy) + " MeV"; - } - else if(energy>0.001) - { - energy*=1000.; - energyOutput = String.format("%.2f",energy) + " KeV"; - } - else - { - energy*=1000.*1000.; - energyOutput = String.format("%.2f",energy) + " eV"; - } - return energyOutput; - } - - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - ACoord[] data = ACoord.NO_HISTOGRAMS; - //TODO add MBTS RZ Histograms option turned off in gui - //if (projection instanceof AProjectionRZ) - // data = getRZHistograms(); - return projection.nonLinearTransform(data); - } - - - - // calculate real pulse shapes values based on the values in the lookup tables - // taken from ATILEData. This function can't be shared from ACalorimeterData - // (shared by LAr, FCAL, HEC) since the calculation is different and can't - // call it directly from TILE since there are two channels. - // Should likely be refactored (so that method is somewhat shared) - after - // discussion with someone from TILE/MBTS/LAr ... - private double getPhysicsPulseShape(double xTime, double pmtTime, - double pmtPedestal, double pmtEnergy, - float[] amplitude, float[] time) - throws AAtlantisException - { - double tdiv = 0.0; - int lookup = 0; - double localTime = 0.0; - double xpulse = 0.0; - - // need to get "multiple" parameter ( = number of values in adcCounts - // for each cell - adcCounts.length), shall be the same for all the - // cells - taking the length of the first array (for the first cell) - // no NullPointer or ArrayIndexBound checks are necessary here as this - // method shall only be called when the relevant data is available - double centerOfSamples = (adcCounts[0].length + 1.0) / 2.0; - - tdiv = time[1] - time[0]; - localTime = (xTime - centerOfSamples) * 25.0 - pmtTime; - lookup = (int) ((localTime - time[0]) / tdiv); - - if(lookup < 0) - { - lookup = 0; - } - if(lookup >= NUMBER_OF_LOOKUP_VALUES - 1) - { - lookup = NUMBER_OF_LOOKUP_VALUES - 2; // -1 was off by 1 - } - - try - { - if(lookup == 0 || lookup == NUMBER_OF_LOOKUP_VALUES - 2) - { - xpulse = amplitude[lookup]; - } - else - { - xpulse = amplitude[lookup] + ((amplitude[lookup + 1] - - amplitude[lookup]) / tdiv) * (localTime - time[lookup]); - } - } - catch(ArrayIndexOutOfBoundsException ex) - { - String m = "AMBTSData.getPhysicsPulseShape():\n" + - " lookup index out of bound: lookup = " + lookup; - throw new AAtlantisException(m); - } - return (xpulse * pmtEnergy) + pmtPedestal; - - } // getPhysicsPulseShape() --------------------------------------------- - - - - /** - * Utility method APulseShapePlot.plotRealPulseShapes() is called from - * here. - * Physics pulse is calculated here: getPhysicsPulseShape(). - * This method is called from APickInteraction via ACalorimeterData - * which defines abstract plotPulseShapes(). - * Method more or less copied & pasted from ATILEData, but here is - * for just one channel. - * - * @param index int - */ - public void plotPulseShapes(int index) - { - if(pulseShapesDataAvailable) - { - String title = CALORIMETER_NAME + " cell index: " + index; - - // one channel for MBTS - int[][] adcCountsLocal = new int[][] { adcCounts[index] }; - - if(super.checkADCCountsAvailability(adcCountsLocal)) - { - // adc counts are available - logger.debug(CALORIMETER_NAME + " adc counts (digits) are " + - "available for pulse shapes plots for this cell."); - } - else - { - AOutput.append("\nADC counts are not available for this cell, " + - "can't plot pulse shapes.", ALogInterface.WARNING); - return; - } - - - // step - starting from 1, need to get step numbers within - // number of ADC samples (adcCounts[0].length) - double step = (adcCounts[0].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - double[][] realPulse = new double[1][NUMBER_OF_LOOKUP_VALUES]; // 1 channel - double d = 1.0; - - // by zdenek 2008-12-02 - // DPD (slimed version of ESD) sometimes don't have cellPedestal - // for a cell (the tag exists, values are there, but are 0). check - // if pedestal is 0 and if so, take as pedestal value the first - // adc count digit - float cellPedestalLocal = cellPedestal[index]; - if(cellPedestalLocal == 0.0f) - { - logger.debug("MBTS cellPedestal is not available (i.e. " + - "are 0.0f), using first adcCount digit as pedestal."); - cellPedestalLocal = adcCounts[index][0]; - } - - try - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - realPulse[0][i] = - this.getPhysicsPulseShape(d, cellRawTime[index], - cellPedestalLocal, - cellRawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - return; - } - - APulseShapePlot.plotRealPulseShapes(adcCountsLocal, realPulse, - step, null, title); - } - else - { - logger.warn(CALORIMETER_NAME + " plotPulseShapes() method called, " + - "but data is not available."); - return; - } - - } // plotPulseShapes() -------------------------------------------------- - - - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMDTData.java b/graphics/AtlantisJava/src/atlantis/data/AMDTData.java deleted file mode 100755 index 0074b2c5a16..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMDTData.java +++ /dev/null @@ -1,338 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -public class AMDTData extends AMuonHitData -{ - protected float[] driftR; - protected float[] length; - private static final int BARREL = 1; - - private static ALogger logger = ALogger.getLogger(AMDTData.class); - - public String getParameterGroup() - { - return "MDT"; - } - - public String getName() - { - return "MDT"; - } - - public String getNameScreenName() - { - return "MDT"; - } - - AMDTData(AHashMap p, AEvent e) - { - super(p,e); - driftR = p.getFloatArray("driftR"); - length = p.getFloatArray("length"); - // removed the fudge (CT 27/7/2004), and replaced with another - // for(int i=0; i<numData; i++) - // driftR[i]*=500./700.; - for (int i = 0; i < numData; i++) - if (driftR[i] > 1.46) - driftR[i] = (float) 1.46; // don't go out of the drifttube ! - } - - protected int getStation(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(1) == 'I') { - return 0; - } else if (stationName.charAt(1) == 'E') { - return 1; - } else if (stationName.charAt(1) == 'M') { - return 2; - } else if (stationName.charAt(1) == 'O') { - return 3; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding MDT identifier", e); - } - - return 0; - } - - protected int getSub(int index) - { - try { - if (AIdHelper.stationName(id[index]).charAt(0) == 'B') { - return 1; - } else if (AIdHelper.stationEta(id[index]) < 0) { - return 0; - } else { - return 2; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding MDT identifier", e); - } - - return 1; - } - - public int getSector(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(2) == 'L') { - return 2 * (AIdHelper.stationPhi(id[index]) - 1); - } else { - return 2 * (AIdHelper.stationPhi(id[index]) - 1) + 1; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding MDT identifier", e); - } - - return 0; - } - - protected boolean getMeasuresPhi(int index) - { - return false; - } - - protected void applyCuts() - { - super.applyCuts(); - if (parameterStore.get("CutsATLAS", "CutPhi").getStatus()) - cutPhi(phi, getDPhi()); - cutEta(rho, z); - } - - // used to make phi cut - - private float[] getDPhi() - { - // only roughly correct for some special sectors - // must create all - float[] dphi = new float[numData]; - - // need only fill for those in draw list - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - dphi[list] = (float) Math.abs(Math.atan2(length[list] / 2., rho[list])); - } - return dphi; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.RHO+" = "+String.format("%.3f",rho[index])+"\n "+ - "z = " + String.format("%.3f",z[index]) + " cm\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - String temp = getNameScreenName() + " (id: " + identifier[index] + - " index: " + index + ")\n " + - AMath.RHO + " = " + String.format("%.3f",rho[index]) + " cm" + "\n " + - AMath.PHI + " = " + String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)\n " + - "z = " + String.format("%.3f",z[index]) + " cm\n " + - "driftR = " + String.format("%.3f",driftR[index]) + " cm"; - if (sector[index] != -1) - { - temp += "\n sector = " + sector[index]; - } - - return temp; - } - - private void makeDrawListYX() - { - int mode = parameterStore.get("YX", "Mode").getI(); - - if (mode > 0 && mode < 5) - { - numDraw = 0; - } - else - { - makeDrawList(); - if (mode == 0) - cut(" Barrel ", sub, "==", BARREL); - else - { - cut(" Endcaps", sub, "!=", BARREL); - cut(" Station", station, "==", mode - 5); - } - } - } - - private void makeDrawListFZ() - { - int mode = parameterStore.get("FZ", "Mode").getI(); - - if (mode > 0 && mode < 4) - { - numDraw = 0; - } - else - { - makeDrawList(); - if (mode == 0) - cut(" Endcaps", sub, "!=", BARREL); - else - { - cut(" Barrel ", sub, "==", BARREL); - if (mode == 4) - cut(" Station", station, "<=", mode - 3); - else - cut(" Station", station, "==", mode - 3); - } - } - } - - protected ACoord getYXUser() - { - return getYXUser(0); - } - - private ACoord getYXUser(int flag) - { - makeDrawListYX(); - int numPieces = 13; - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double r = rho[list]; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double phiM = Math.rint(phi[list] / AMath.PI_BY_8) * AMath.PI_BY_8; - double cosPhiM = Math.cos(phiM); - double sinPhiM = Math.sin(phiM); - double d = length[list] / 2.; - double x = r * cosPhi; - double y = r * sinPhi; - - hv[0][i] = AMath.splitLineIntoPieces(new double[] { x + d * sinPhiM, x - d * sinPhiM }, numPieces); - hv[1][i] = AMath.splitLineIntoPieces(new double[] { y - d * cosPhiM, y + d * cosPhiM }, numPieces); - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - protected ACoord getFRUser() - { - return getYXUser(1).convertYXToFR().includePhiWrapAround("FR"); - } - - protected ACoord getRZUser() - { - makeDrawList(); - int[] sign = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for (int i = 0; i < numDraw; i++) - { - double phiDiff = Math.abs(phi[listdl[i]] - phiMid); - - sign[i] = -1; - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign[i] = 1; - } - return getXZRZUser(sign); - } - - protected ACoord getXZUser() - { - makeDrawList(); - cutMuonSector(sector); - int[] sign = new int[numDraw]; - int sect=(int)Math.round(parameterStore.get("XZ", "Phi").getD() / 22.5); - - for (int i = 0; i < numDraw; i++) - { - sign[i] = 1; - if (sector[listdl[i]] != sect) - sign[i] = -1; - } - return getXZRZUser(sign); - } - - protected ACoord getXZRZUser(int[] sign) - { - // int muonMode=APar.get("Data.MDT").getI(); - int muonMode = parameterStore.get("MDT", "Mode").getI(); - int numPoints; - - if (muonMode == 0) // circles - numPoints = 48; - else - numPoints = 2; // lines - - double[][][] hv = new double[2][numDraw][numPoints]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double rC = sign[i] * getSectorRho(sector[list], rho[list], phi[list]); - double zC = z[list]; - double d = driftR[list]; - - if (muonMode == 0) - { // circles - for (int j = 0; j < numPoints; j++) - { - hv[0][i][j] = zC + d * Math.cos(Math.PI * 2 * j / (numPoints - 1)); - hv[1][i][j] = rC + d * Math.sin(Math.PI * 2 * j / (numPoints - 1)); - } - } - else - { // lines - double radius = Math.sqrt(rC * rC + zC * zC); - double sinTheta = rC / radius; - double cosTheta = zC / radius; - - hv[0][i][0] = zC + d * sinTheta; - hv[1][i][0] = rC - d * cosTheta; - hv[0][i][1] = zC - d * sinTheta; - hv[1][i][1] = rC + d * cosTheta; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - protected ACoord getFZUser() - { - makeDrawListFZ(); - double[][][] hv = new double[2][numDraw][2]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - index[i] = list; - hv[0][i][0] = z[list]; - hv[0][i][1] = z[list]; - double deltaPhi = Math.atan2(length[list] / 2., rho[list]); - - hv[1][i][0] = Math.toDegrees(phi[list] - deltaPhi); - hv[1][i][1] = Math.toDegrees(phi[list] + deltaPhi); - } - return new ACoord(hv, index, this, ACoord.POLYLINES).includePhiWrapAround("FZ"); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMuonData.java b/graphics/AtlantisJava/src/atlantis/data/AMuonData.java deleted file mode 100755 index 368a6a03988..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMuonData.java +++ /dev/null @@ -1,95 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.A4Vector; - -/** - * Reconstructed Muon - */ -public class AMuonData extends AHelixAODData -{ - private float[] chi2; - - AMuonData(AHashMap p, AEvent e) - { - super(p,e); - chi2=p.getFloatArray("chi2"); - } - - public String getParameterGroup() - { - return "Muon"; - } - - public float getchi2(int index) - { - return chi2[index]; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM(pT[k],eta[k],phi[k],0.1057); - sum.add(start); - } - - return sum; - } - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsObjects", "MuonPt", " |ET|", pT); - cut("CutsObjects", "Muonchi2", " |chi2|", chi2); - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - msg.append("\n chi2 = "); - msg.append(chi2[index]); - - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMuonHitData.java b/graphics/AtlantisJava/src/atlantis/data/AMuonHitData.java deleted file mode 100644 index 85717f5fa90..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMuonHitData.java +++ /dev/null @@ -1,192 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.*; -import atlantis.parameters.*; - -public abstract class AMuonHitData extends AHitData { - - protected float[] rho; - protected float[] phi; - protected float[] x; - protected float[] y; - protected float[] z; - protected int[] sector; - protected int[] station; - protected boolean[] measuresPhi; - - public static final int DOES_NOT_MEASURE_PHI=0; - public static final int MEASURES_PHI=1; - - // remove when go to compact id ( if compact id was in a sensible form) - String[] identifier; - - AMuonHitData(AHashMap p, AEvent e) { - super(p,e); - x=p.getFloatArray("x"); - y=p.getFloatArray("y"); - z=p.getFloatArray("z"); - rho=new float[numData]; - phi=new float[numData]; - for(int i=0; i<numData; ++i) { - rho[i]=(float)Math.sqrt(x[i]*x[i]+y[i]*y[i]); - phi[i]=(float)Math.atan2(y[i], x[i]); - if(phi[i]<0.) phi[i]+=AMath.TWO_PI; - } - identifier=p.getStringArray("identifier"); - station=new int[numData]; - sector=new int[numData]; - measuresPhi=new boolean[numData]; - for(int i=0; i<numData; ++i) { - // should be moved to AHitData - sub[i]=getSub(i); - sector[i]=getSector(i); - station[i]=getStation(i); - measuresPhi[i]=getMeasuresPhi(i); - } - } - - /** - * Get the name used for associating this datatype/collection. For the - * muon hits no storegate key is used. - * @return - */ - public String getFullName() { - return getName(); - } - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == numColorTypes + 1) // colour by Track Segment - { - colorBy(getSegments()); - } - return numColorTypes + 1; - - } // internalColor() ---------------------------------------------------- - - - abstract protected int getStation(int index); - - abstract public int getSector(int index); - - abstract protected int getSub(int index); - - abstract protected boolean getMeasuresPhi(int index); - - protected String getSegments() { - AEnumeratorParameter key = (AEnumeratorParameter) parameterStore.get("MuonSegment", "MuonSegmentCollections"); - - return "MuonSegment" + key.getCurrentText(); - } - - public int getRZSign(int index) { - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff=Math.abs(phi[index]-phiMid); - - int sign=-1; - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - sign=1; - return sign; - } - - protected String getReconstructedTracks() { - AData tracks = event.getTrackData("MuonTrack"); - if (tracks == null) { - return null; - } else { - return tracks.getName() + tracks.getStoreGateKey(); - } - } - - // get the distance of closest approach of the inifinite line representing the - // drift tube axis to Z axis - // Normal this is rho of the hit, but need not be for non standard modules - // (e.g. near feet) - static double getSectorRho(int sector, double rho, double phi) { - return rho*Math.abs(Math.cos(phi-sector*AMath.PI_BY_8)); - } - - protected void applyCuts() { - cutIndex(); - cutSimulatedTracks(); - cutReconstructedTracks(); - cutSegments(); - } - - // keep only muon hits in the input muon sectors - protected void cutMuonSector(int[] sector) { - AParameter p=parameterStore.get("XZ", "Phi"); - - // display muon data when phi is in the middle of a sector - if(p.getD() % 22.5 < 1e-2) { - int sect=(int)Math.round((p.getD() % 360.) / 22.5); - - int num=0; - - for(int i=0; i<numDraw; i++) { - int s=sector[listdl[i]]; - - if(s==sect||s==sect-8||s==sect+8) - listdl[num++]=listdl[i]; - } - numDraw=num; - } else { - numDraw=0; - } - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.RHO+" = "+String.format("%.3f",rho[index])+"\n "+ - "z = " + String.format("%.3f",z[index]) + "cm\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - String temp = getNameScreenName() + " (id: " + identifier[index] + " index: " + index + ")" + - "\n " + AMath.RHO + " = " + String.format("%.3f",rho[index]) + " cm" + - "\n " + AMath.PHI + " = " + String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)" + - "\n z = " + String.format("%.3f",z[index]) + " cm"; - - if(sector[index]!=-1) - { - temp += "\n sector = " + sector[index]; - } - - return temp; - } - - protected void setType() { //What is this doing?? - int[][] recon=event.getAssociationManager().get(getName(),getReconstructedTracks()); - for(int i=0; i<numData; i++) { - if( (recon!=null&&recon[i]!=null)) - type[i]=1; - else - type[i]=0; - } - } - - /** - * cut hits if connected/unconnected to reconstructed tracks - */ - protected void cutReconstructedTracks() - { - int cutOption = parameterStore.get("CutsMuon", "HitsByRTr").getI(); - cutByAssociationTo(getReconstructedTracks(), getName(), cutOption); - } - - /** - * cut hits if connected/unconnected to reconstructed segments - */ - protected void cutSegments() - { - int cutOption = parameterStore.get("CutsMuon", "HitsBySegment").getI(); - cutByAssociationTo(getSegments(), getName(), cutOption); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMuonROIData.java b/graphics/AtlantisJava/src/atlantis/data/AMuonROIData.java deleted file mode 100755 index 567f2f9cf5a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMuonROIData.java +++ /dev/null @@ -1,34 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.utils.AHashMap; - -/** - * - * Muon Region Of Interest - * - * @author Zdenek Maxa, Qiang Lu, Juergen Thomas - */ -public class AMuonROIData extends AROIData -{ - AMuonROIData(AHashMap p, AEvent e) - { - super(p,e); - } // AMuonROIData() ------------------------------------------------------ - - public String getParameterGroup() - { - return "MuonROI"; - } // getParameterGroup() ------------------------------------------------ - - public String getName() - { - return "MuonROI"; - } // getName() ---------------------------------------------------------- - - public String getNameScreenName() - { - return "MuonROI"; - } // getNameScreenName() ------------------------------------------------ - -} // class AMuonROIData ====================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/AMuonSegmentData.java b/graphics/AtlantisJava/src/atlantis/data/AMuonSegmentData.java deleted file mode 100755 index 96adc598bcf..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMuonSegmentData.java +++ /dev/null @@ -1,56 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AHashMap; - -/** - * - * @author Eric Jansen - */ -public class AMuonSegmentData extends ASegmentData { - - /** Creates a new instance of AMuonSegmentData */ - AMuonSegmentData(AHashMap p, AEvent e) { - super(p,e); - String assocKey = getName() + getStoreGateKey(); - event.getAssociationManager().add(new AAssociation(assocKey, "MDT", numHits, hits, event)); - event.getAssociationManager().add(new AAssociation(assocKey, "RPC", numHits, hits, event)); - event.getAssociationManager().add(new AAssociation(assocKey, "TGC", numHits, hits, event)); - event.getAssociationManager().add(new AAssociation(assocKey, "CSC", numHits, hits, event)); - } - - public void makeDrawList() { - super.makeDrawList(); - - if (currentProjection instanceof AProjectionYX) { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) { - numDraw = 0; - } else { - int num = 0; - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - - // Anything beyond z=13m or below r=6.5m is endcap - if (Math.sqrt(x[j]*x[j] + y[j]*y[j]) > 650. - && Math.abs(z[j]) < 1300.) { - listdl[num++] = j; - } - } - numDraw = num; - } - } - } - - public String getParameterGroup() { - return "MuonSegment"; - } - - public String getName() { - return "MuonSegment"; - } - - public String getNameScreenName() { - return "MuonSegment"; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AMuonTrackData.java b/graphics/AtlantisJava/src/atlantis/data/AMuonTrackData.java deleted file mode 100644 index cd768ea2a38..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AMuonTrackData.java +++ /dev/null @@ -1,200 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; - - -/** - * - * @author Eric Jansen - */ -public class AMuonTrackData extends ATrackData { - - private static ALogger logger = ALogger.getLogger(AMuonTrackData.class); - - protected float[] phi0; - protected float[] pT; - protected float[] cotTheta; - protected int[] author; - - /** Creates a new instance of AMuonTrackData */ - AMuonTrackData(AHashMap p, AEvent e) throws AAtlantisException { - super(p,e); - String assocKey = getName() + getStoreGateKey(); - if(p.get("numHits") != null) { - int[] numHits = p.getIntArray("numHits"); - int[] hits = p.getIntArray("hits"); - - event.getAssociationManager().add(new AAssociation(assocKey, "MDT", numHits, hits,event)); - event.getAssociationManager().add(new AAssociation(assocKey, "RPC", numHits, hits,event)); - event.getAssociationManager().add(new AAssociation(assocKey, "TGC", numHits, hits,event)); - event.getAssociationManager().add(new AAssociation(assocKey, "CSC", numHits, hits,event)); - } - - phi0 = p.getFloatArray("phi0"); - pT = p.getFloatArray("pt"); - cotTheta = p.getFloatArray("cotTheta"); - author = p.getUnsureIntArray("trackAuthor"); - } - - public String getParameterGroup() { - return "MuonTrack"; - } - - public String getName() { - return "MuonTrack"; - } - - public String getNameScreenName() { - return "MuonTrack"; - } - - protected void finalizeConstruction() { - super.finalizeConstruction(); -/* - // needs ZVTx - h = new AHelix[numData]; - for(int i = 0; i < numData; ++i) { - double p = AMath.getPFromPttL(pT[i], cotTheta[i]); - double xVtx = parameterStore.get("Event", "XVtx").getD(); - double yVtx = parameterStore.get("Event", "YVtx").getD(); - double phiVtx = Math.atan2(yVtx, xVtx); - double rho = Math.sqrt(xVtx * xVtx + yVtx * yVtx); - double d0 = -rho * Math.sin(phi0[i] - phiVtx); - // correct for average energy loss - double pTCorrected = pT[i] * (p + 3.7) / p; - - h[i] = new AHelix((float)d0, - (float)(parameterStore.get("Event", "ZVtx").getD()), - (float)Math.toDegrees(phi0[i]), cotTheta[i], (float)pTCorrected); - //calculatePhiCorrection(i); - } -*/ - } - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP - && parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() != DRAW_NEWHELIX) - { - ag.draw(window.calculateDisplay(getVPUser(window, projection))); - } - else - super.draw(window, ag, projection); - } - - protected ACoord getVPUser(AWindow window, AProjection projection) - { - makeDrawList(); - double[][][] hv = new double[2][2*numDraw][]; - int[] index = new int[2 * numDraw]; - int num = 0; - for (int j=0; j<numDraw; j++) { - int list = listdl[j]; - ADHelix dhelix = new ADHelix(h[list]); - double s1 = dhelix.getAStart(); - double s2 = 179.; - // hardwire projection.getMinRho() == 2. for now - s1 = dhelix.intersectWithRadialCylinder(((AProjection2D)projection).getMinRho(), s1, s2); - double sEnd = dhelix.intersectWithCylinder(true, AProjectionVP.getRhoVPlot(), - true, AProjectionVP.getZVPlot()); - s2 = Math.max(Math.min(s2, sEnd), s1); - // if the whole helix is to be drawn (which are unusual - // helices, shorten it a little to avoid wraparound problems - if (s1 == 0. && s2 == 180.) s2 = 179.; - - if (parameterStore.get("VP", "ShortV").getStatus() && !parameterStore.get("Data", "S3D").getStatus()) { - s1 = s2 - parameterStore.get("VP", "ShortV").getD() * (s2 - s1); - } - - // by Zdenek: - // if this condition is not entered, hv array containing coordinates - // remains empty and Atlantis will crash with NullPointerException - // in AWindow.calculateUser(ACoord user) - // magic constants here (e.g. s2) need to be understood and this - // method best reimplemented - for(int sign=-1; sign<=1; sign+=2) { - // ugly must change structure at some point - AProjectionVP.sign = sign; - ACoord pointsOnHelix; - if (s2 > s1) { - pointsOnHelix = dhelix.drawHelix(window, (AProjection2D) projection, s1, s2); - hv[0][num] = pointsOnHelix.hv[0][0]; - hv[1][num] = pointsOnHelix.hv[1][0]; - } else { - hv[0][num] = new double[0]; - hv[1][num] = new double[0]; - } - index[num] = list; - num++; - } - } - - // by Zdenek: - // condition to prevent NullPointerException in AWindow.calculateUser() - // see previous comment ... - // this condition should be removed completely 'bug in helix' - // problem is understood - ACoord coord = null; - if(hv[0].length > 0 && hv[0][0] == null) - { - logger.warn("AMuonTrackData.getVPUser(): \"" + this.getName() + - ":" + this.getStoreGateKey() + "\" can't be drawn in eta-phi"); - coord = ACoord.NO_DATA; - } - else - { - coord = new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - } - return window.calculateUser(coord).includePhiWrapAround(projection.getName()); - } - - - - private float[] getEta() - { - float[] eta = new float[numData]; - if(polylinedTrack) - { - for(int i = 0; i < numData; i++) - { - if(h!=null && h[i]!=null) eta[i] = (float) h[i].eta(); - else eta[i] = (float) AParameterUtilities.eta(z[i][0], rho[i][0]); - } - } - else - { - for(int i = 0; i < numData; i++) - { - eta[i] = (float) h[i].eta(); - } - - } - - return eta; - } - - - - protected void applyCuts() { - cutIndex(); - cut("CutsInDet", "Pt", " |Pt|", pT); - cut("CutsMuon", "Pt", " |Pt|", pT); - cut("CutsInDet", "trackAuthor", " Author", author); - cutPhi(phi0); - if(parameterStore.get("CutsATLAS", "CutEta").getStatus()) - { - cutEta(getEta()); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AOldHelix.java b/graphics/AtlantisJava/src/atlantis/data/AOldHelix.java deleted file mode 100755 index a3f490c5717..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AOldHelix.java +++ /dev/null @@ -1,338 +0,0 @@ -package atlantis.data; - -import atlantis.globals.AGlobals; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.utils.AMath; -import atlantis.utils.A3Vector; -import atlantis.utils.ALogger; - -import static java.lang.Math.PI; - -/** - * This is a convenience class to group together the six helix parameters. - */ -public class AOldHelix { - - private final static ALogger logger = ALogger.getLogger(AOldHelix.class); - - private static final int SIZE=5; - private static final boolean DEBUG = false; - private static final APar parameterStore = APar.instance(); - // C - constant depending on the magnetic field, constant proportional - // to curvature in the magnetic field - private static final double C; - static { - AParameter curvatureParameter = parameterStore.get("Event", "Curvature"); - if (curvatureParameter!=null) { - C = curvatureParameter.getD(); - } - else { - C = 100/0.6;; - logger.error("Curvature parameter not found, defaulting to "+C); - } - } - - // These fields are public but final so cannot be altered. - /** Distance between circle and (0,0) at point of closest approach (PCA). */ - public final double d0; - /** Z of circle at PCA. */ - public final double z0; - /** phi0 of track at PCA [degrees] */ - public final double phi0; - /** Dip of track = Pz/pTTrack =0.5 * ( E - 1/E ) : constant along the helix */ - public final double tL; - /** Transverse momentum * charge. */ - public final double pT; - /** ln( Pz/pTTrack + SQRT[(Pz/pTTrack)**2 +1 ] */ - public final double eta; - /** Angle between (0,0) and vertex as seen from the circle center [degrees]? - * For helices starting at PCA, startPhi=0. This is the case for reconstructed - * helices that are not yet associated to a secondary vertex or are - * drawn to PCA. - * Mutable because it is changed when tracks are used to fit a vertex. */ - double startPhi; - - // negative end vertex means none exits - double rhoVertex = 0.0; - private double rhoEndVertex = -1.0; - - private int numHits; - - double[][] cov=null; - - AOldHelix() { - this(0, 0, 0, 0, 0); - }; - - /** Standard Helix constructor without end vertex */ - AOldHelix(float rhoVertex, float phiVertex, float zVertex, - float pTTrack, float phiTrack, float etaTrack, int charge ) { - this(rhoVertex,phiVertex,zVertex,pTTrack,phiTrack,etaTrack,charge,-1); - } - - /** - * Standard Helix constructor with end vertex. - * - * Note: this method is not called when creating helix representation of - * reconstructed InDet tracks, but is called for simulated InDet tracks. - * - * @param rhoVertex rho of vertex from which track starts - * @param phiVertex phi of vertex from which track starts - * @param zVertex Z of vertex from which track starts - * @param pTTrack transverse track momentum > 0 - * @param phiTrack phi of track seen from vertex - * @param etaTrack eta = -ln(tg(theta/2)), theta = arctg(pTTrack/Pz) = 2*arctg( e**(-eta)) - * @param charge charge = +1 or -1 - * @param rhoEndVertex - */ - AOldHelix(float rhoVertex, float phiVertex, float zVertex, - float pTTrack, float phiTrack, float etaTrack, int charge, float rhoEndVertex ) { - /* - * Derived: - * rC = signed radius of circle (positive for positive particle, which - * loops in the clockwise direction in the standard xy projection, - * given that Bz is positive in the ATLAS solenoid) - * xC = x position of center of circle - * yC = y position of center of circle - * E = E**eta - * charge=1 if icode>=0 else charge=-1 - * - * Calculation: - * rC = C*pTTrack C = 100./0.6 - * xC = rhoVertex*cos(phiVertex) + rC*sin(phiTrack) - * yC = rhoVertex*sin(phiVertex) - rC*cos(phiTrack) - * tl = Pz/pTTrack = 0.5 * ( E - 1/E ) - * d0 = rC - sqrt(xC*xC + yC*yC) - * startPhi = pi/2 - phiTrack + atan2(yC,xC) modify startPhi to: -pi/2 < startPhi < pi/2 - * z0 = zVertex - rC*startPhi*tl - * phi0 = phiTrack + startPhi - * pCharge = charge*pTTrack - * Change startPhi and phi0 from radians to degrees. - * - */ - double rC=C*pTTrack*charge; - if (DEBUG) logger.debug("AOldHelix: charge, rC = "+charge+", "+rC); - double xC=rhoVertex*Math.cos(phiVertex)+rC*Math.sin(phiTrack); - double yC=rhoVertex*Math.sin(phiVertex)-rC*Math.cos(phiTrack); - if (DEBUG) logger.debug("AOldHelix: xCyC"+" "+xC+" "+yC); - double e=Math.exp(etaTrack); - tL=0.5*(e-1./e); - eta = etaTrack; - d0=rC-charge*Math.sqrt(xC*xC+yC*yC); - phiTrack = (float) AMath.nearestPhiRadians(phiTrack); - double temp=Math.atan2(yC, xC); - temp = AMath.nearestPhiRadians(temp); - double startPhiRad=charge*(PI/2)-phiTrack+temp; - startPhiRad = AMath.nearestPhiRadians(startPhiRad, 0); - z0=zVertex-rC*startPhiRad*tL; - phi0=Math.toDegrees(phiTrack+startPhiRad); - startPhi=charge*Math.toDegrees(startPhiRad); - pT=charge*pTTrack; - - // keep rhoEndVertex for simulated tracks with a daughter - this.rhoVertex=rhoVertex; - this.rhoEndVertex = rhoEndVertex; - } - - /** - * Construct AOldHelix object. - * @param d0 - * @param z0 - * @param phi0 [degrees] - * @param tL - * @param pT - */ - AOldHelix(float d0, float z0, float phi0, - float tL, float pT) { - this.d0=d0; - this.z0=z0; - this.phi0=AMath.nearestPhiDegrees(phi0); - this.tL=tL; - this.eta = calculateEta(this.tL); - this.pT=pT; - startPhi=0.; - } - - AOldHelix(float d0, float z0, float phi0, - float tL, float pT, int numHits) { - this(d0, z0, phi0, tL, pT); - this.numHits=numHits; - } - - AOldHelix(float d0, float z0, float phi0, - float tL, float pT, float[][] c) { - this.d0=d0; - this.z0=z0; - this.phi0=phi0; - this.tL=tL; - this.eta = calculateEta(this.tL); - this.pT=pT; - this.startPhi=0.; - - cov=new double[c.length][]; - if(c.length!=SIZE) - logger.error("Helix error "+c.length); - for(int i=0; i<c.length; ++i) { - if(c[i].length!=SIZE) - logger.error("Helix error "+c.length); - cov[i]=new double[c[i].length]; - } - for(int i=0; i<c.length; ++i) - for(int j=0; j<c[i].length; ++j) - cov[i][j]=c[i][j]; - } - - AOldHelix(float d0, float z0, float phi0, - float tL, float pT, int numHits, float[][] c) { - this(d0, z0, phi0, tL, pT, c); - this.numHits=numHits; - } - - public double[] getPar() { - return new double[] {d0, z0, Math.toRadians(phi0), tL, 1./pT}; - } - - public double[][] getCov() { - return cov; - } - - public double getRhoEndVertex(){ - return rhoEndVertex; - } - -/** - * Set Phi start so that the track will originate from the point on the - * reconstructed track in the YX plane which is closest to the point (Vx,Vy). - * Only used when drawing tracks originating from a reconstructed vertex. - */ - public void setPhiStartByXYPoint(double Vx, double Vy) { - //construct a local super object to get the xC and yC numbers - ADHelix Dh=new ADHelix(this); - // do the calculation to find the starting angle - double Xc=Dh.getxC(); - double Yc=Dh.getyC(); - - double a=-1.*(Vx-Xc); - double b=-1.*(Vy-Yc); - - double pTTrack=pT; - double phiTrack=Math.toRadians(phi0); - - double charge=1; - if(pTTrack<0.0) charge=-1.; - - double temp=Math.atan2(b, a); - temp = AMath.nearestPhiRadians(temp); - double sPhi=charge*(PI/2)-phiTrack+temp; - sPhi = AMath.nearestPhiRadians(sPhi, 0); - sPhi=charge*Math.toDegrees(sPhi); - startPhi=Math.abs(sPhi); - } - - public String toString() { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = ""; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",Math.abs(pT))+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta)+"\n "+ - AMath.PHI+" = "+String.format("%.3f",phi0)+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",Math.abs(pT)*Math.cos(Math.toRadians(phi0)))+" GeV "+ - "\n Py="+String.format("%.3f",Math.abs(pT)*Math.sin(Math.toRadians(phi0)))+" GeV "+ - "\n Pz="+String.format("%.3f",Math.abs(pT)*Math.sinh(eta))+" GeV "+ - "\n Charge = " + (int)(pT/Math.abs(pT)); - return output; - } - - String s=""; - double f=1.; - - if(numHits>0) - s+="\n numHits = "+numHits; - // if(Math.abs(d0)<0.1) f=10000.; - s+="\n d0 = "+String.format("%.3f",f*d0); - if(cov!=null) s+=" "+AMath.PLUSMINUS+" "+String.format("%.3f",f*Math.sqrt(cov[0][0])); - if(f>100) - s+=" um"; - else - s+=" cm"; - f=1.; - // if(Math.abs(z0)<0.1) f=10000.; - s+="\n z0 = "+String.format("%.3f",f*z0); - if(cov!=null) s+=" "+AMath.PLUSMINUS+" "+String.format("%.3f",Math.sqrt(f*cov[1][1])); - if(f>100) - s+=" um"; - else - s+=" cm"; - - double zVtx = parameterStore.get("Event", "ZVtx").getD(); - //if(Math.abs(z0-zVtx) < 0.1) f=10000.; - s+="\n |z0-zVtx| = "+String.format("%.3f",f*Math.abs(z0-zVtx)); - if(f>100) - s+=" um"; - else - s+=" cm"; - - s+="\n phi0 = "+String.format("%.3f",phi0); - if(cov!=null) - { - s += " " + AMath.PLUSMINUS + " " + - String.format("%.3f",Math.toDegrees(Math.sqrt(cov[2][2]))) + - AMath.DEGREES; - } - else - { - s += AMath.DEGREES; - - } - s+= " (" + String.format("%.3f",Math.toRadians(phi0)); - if(cov != null) - { - s += " " + AMath.PLUSMINUS + " " + - String.format("%.3f",Math.toRadians(Math.sqrt(cov[2][2]))) + " rad)"; - } - else - { - s += " rad)"; - } - - s+="\n "+AMath.ETA+" = "+String.format("%.3f",eta); - if(cov!=null) { - // based on the relation between eta and ctgTheta - double etaError = Math.sqrt(cov[3][3] / (tL * tL + 1.0)); - s+=" "+AMath.PLUSMINUS+" "+String.format("%.3f",etaError); - } - s+="\n tL = "+String.format("%.3f",tL); - if(cov!=null) s+=" "+AMath.PLUSMINUS+" "+String.format("%.3f",Math.sqrt(cov[3][3])); - s+="\n pT = "+String.format("%.2f",pT) + " GeV"; - if(cov!=null) { - double sigmaPt=Math.abs(1./(Math.abs(1./pT)+Math.sqrt(cov[4][4]))-Math.abs(pT)); - - s+=" "+AMath.PLUSMINUS+" "+String.format("%.3f",sigmaPt)+" GeV"; - } - if(pT<0.) - s+="\n p = "+String.format("%.2f",-AMath.getPFromPttL(pT,tL)); - else - s+="\n p = "+String.format("%.2f",AMath.getPFromPttL(pT,tL)); - s+= " GeV"; - - return s; - } - - public A3Vector getP() { - double pTrans=Math.abs(pT); - double phi=Math.toRadians(phi0); - return new A3Vector(pTrans*Math.cos(phi), pTrans*Math.sin(phi), pTrans*tL); - } - - /** eta = -ln(tg theta/2), so eta = -ln(sqrt(ctgtheta*ctgtheta+1)-ctgtheta) */ - private static double calculateEta(double ctgTheta) { - double eta; - eta = -Math.log(Math.sqrt(ctgTheta * ctgTheta + 1.0) - ctgTheta); - return eta; - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/data/APDGTable.java b/graphics/AtlantisJava/src/atlantis/data/APDGTable.java deleted file mode 100755 index 5fde73d3136..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/APDGTable.java +++ /dev/null @@ -1,107 +0,0 @@ -package atlantis.data; - -import atlantis.globals.AGlobals; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import atlantis.utils.xml.*; -import java.util.*; -import java.io.File; -import java.io.InputStream; -import org.w3c.dom.*; -import javax.xml.parsers.*; - -/** - * Read a PDG table from the file pdg.xml and provide - * basic accessor functions to its particles - */ -public final class APDGTable { - - //The logger - private final static ALogger logger = ALogger.getLogger(APDGTable.class); - - //Wether to validate the XML document - private final static boolean VALIDATION=true; - - //The particle table linked by PDG code - private final static Map<Integer, AParticle> particles = new HashMap<Integer, AParticle>(100); - - //Always read in the Hashmap - static { - readPDG(APDGTable.getFileInCurrentUserThenAtlantisHome("configuration","pdg.xml")); - } - - //Read in the PDG table from a file - private static void readPDG(String fileName) { - try { - DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); - - factory.setValidating(VALIDATION); - DocumentBuilder parser=factory.newDocumentBuilder(); - - parser.setErrorHandler(new AXMLErrorHandler()); - InputStream is = AUtilities.getFileAsStream(fileName); - Node pdg=parser.parse(is).getDocumentElement(); - NodeList particlesList=pdg.getChildNodes(); - int particlesCount=particlesList.getLength(); - - for(int i=0; i<particlesCount; i++) { - Node particle=particlesList.item(i); - - if(particle.getNodeType()==Node.ELEMENT_NODE) { - AParticle p=new AParticle(particle); - - particles.put(new Integer(p.getCode()), p); - } - } - } catch(Exception e) { - logger.error("Failed reading PDG table", e); - } - } - - public static int getCharge(int code) { - int sign=code/Math.abs(code); - AParticle p=particles.get(new Integer(Math.abs(code))); - - if(p!=null) - return p.getCharge()*sign; - else throw new ParticleNotFoundError(code); - } - - public static String getName(int code) { - AParticle p=particles.get(new Integer(Math.abs(code))); - int sign=1; - - if(code<0) sign=-1; - if(p!=null) - return p.getName(sign); - else throw new ParticleNotFoundError(code); - } - - public static int getParticleType(int code) { - AParticle p=particles.get(new Integer(Math.abs(code))); - - if(p!=null) - return p.getType(); - else throw new ParticleNotFoundError(code); - } - - //Declare our own error type here - no special implementation - public static class ParticleNotFoundError extends Error { - - //Only implement Error constructor with particle code - ParticleNotFoundError(int code){ - super("Particle with code "+code+" not found in PDG table"); - } - } - -public static String getFileInCurrentUserThenAtlantisHome(String directory, String name) -{ - File user = new File(name); - if (!user.canRead()) - { - return AGlobals.instance().getHomeDirectory() + directory + - System.getProperty("file.separator") + name; - } - return name; -}; -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AParticle.java b/graphics/AtlantisJava/src/atlantis/data/AParticle.java deleted file mode 100755 index 8007ae2c46f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AParticle.java +++ /dev/null @@ -1,57 +0,0 @@ -package atlantis.data; - - -import atlantis.output.AExceptionHandler; - -import org.w3c.dom.*; - - -/** - * This class is used to store the properties of a particle. Used by APDGTable. - */ -public class AParticle { - private String name; - private int charge; - private int type; - private int code; - - private String[] chargeRep=new String[] { "-", "0", "+"}; - - public AParticle(Node node) { - NamedNodeMap atts=node.getAttributes(); - - try { - charge=Integer.parseInt(atts.getNamedItem("charge").getNodeValue()); - type=Integer.parseInt(atts.getNamedItem("type").getNodeValue()); - code=Integer.parseInt(atts.getNamedItem("code").getNodeValue()); - name=atts.getNamedItem("name").getNodeValue(); - } catch(NumberFormatException e) { - AExceptionHandler.processException("PDG error in Particle Node: "+node, e); - } - } - - public int getCharge() { - return charge; - } - - public int getType() { - return type; - } - - public int getCode() { - return code; - } - - public String getName() { - return name; - } - - public String getName(int sign) { - if(charge!=0) { - if(name.equals("Proton")&&sign==1) return "Proton"; - if(name.equals("Proton")&&sign==-1) return "Antiproton"; - return name+chargeRep[charge*sign+1]; - } else - return name; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/APhotonData.java b/graphics/AtlantisJava/src/atlantis/data/APhotonData.java deleted file mode 100755 index 7f942031f09..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/APhotonData.java +++ /dev/null @@ -1,166 +0,0 @@ -package atlantis.data; - -import java.util.Vector; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.A4Vector; - -/** - * Reconstructed Photon - */ -public class APhotonData extends AAODData -{ - private enum isEMe { Tight, Loose, none } - - private int[] isEM; - - private Vector<Enum> isEMEnum = new Vector<Enum>(); - private String[] label; - - APhotonData(AHashMap p, AEvent e) - { - super(p,e); - String[] isEMString=p.getUnsureStringArray("isEMString"); - label=p.getUnsureStringArray("label"); - isEM=p.getUnsureIntArray("isEM"); - - if(isEMString!=null) - { - for(String s : isEMString) - { - try { - isEMEnum.add(isEMe.valueOf(s)); - } - catch(IllegalArgumentException q) { - isEMEnum.add(isEMe.none); - } - } - } - else - { - for(int i=0;i<numData;i++) - { - isEMEnum.add(isEMe.none); - } - } - } - - public String getParameterGroup() - { - return "Photon"; - } - - public String getName() - { - return "Photon"; - } - - public String getisEMEnum(int index) - { - return isEMEnum.get(index).toString(); - } - - public int getisEM(int index) - { - return isEM[index]; - } - - public String getlabel(int index) - { - return label[index]; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM(pT[k],eta[k],phi[k],0); - sum.add(start); - } - return sum; - } - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsObjects", "PhotonPt", " |ET|", pT); - - // because of the retriever bug, currently 2048 means 0 for isEM - // remove this for block when the bug is fixed - if(isEM != null) - { - for(int i=0; i<isEM.length; i++) - { - if(isEM[i]==2048) - isEM[i] = 0; - } - } - - cut("CutsObjects", "PhotonisEM", " isEM", isEM); - - if (parameterStore.get("CutsObjects", "PhotonisEMString").getStatus()) - { - int cutSub = parameterStore.get("CutsObjects", "PhotonisEMString").getI(); - cutArrayEnum(isEMEnum, cutSub, "Photon isEMString"); - } - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - - if (isEM != null) - { - msg.append("\n isEM = "); - msg.append(isEM[index]); - } - if (label != null) - { - msg.append("\n label = "); - msg.append(label[index]); - } - - return msg.toString(); - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/data/APixelClusterData.java b/graphics/AtlantisJava/src/atlantis/data/APixelClusterData.java deleted file mode 100644 index acbe38d5856..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/APixelClusterData.java +++ /dev/null @@ -1,403 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * PixelCluster - Pixel clusters, as SiCluster but for Pixels - * reads in PixelCluster datatype - */ -public class APixelClusterData extends AHitData -{ - // read in from event file - private float[] x; - private float[] y; - private float[] z; - private float[] widthx; - private float[] widthy; - private int[] etaModule; - private int[] phiModule; - private float[] eloss; - - // calculated - private float[][] rho; - private float[][] phi; - private int[] layer; - - public static final int U_CLUSTER = -1; - public static final int PHI_CLUSTER = 0; - public static final int V_CLUSTER = 1; - public static final int ENDCAP_MINUS = 0; - public static final int BARREL = 1; - public static final int ENDCAP_PLUS = 2; - - - public String getParameterGroup() - { - return "PixelCluster"; - } - - public String getName() - { - return "PixelCluster"; - } - - public String getNameScreenName() - { - return "PixelCluster"; - } - - public float[] getX() - { - return x; - } - - public float[] getY() - { - return y; - } - - public float[] getZ() - { - return z; - } - - APixelClusterData(AHashMap p, AEvent e) - { - super(p,e); - x = p.getFloatArray("x0"); - y = p.getFloatArray("y0"); - z = p.getFloatArray("z0"); - widthx = p.getFloatArray("widthx"); - widthy = p.getFloatArray("widthy"); - eloss = p.getFloatArray("eloss"); - - rho = new float[2][numData]; - phi = new float[2][numData]; - - layer = new int[numData]; - for (int i = 0; i < numData; ++i) - { - sub[i] = getSub(id[i]); - layer[i] = getLayer(id[i]); - } - - etaModule = (p.get("etaModule") != null) ? p.getIntArray("etaModule") : null; - phiModule = (p.get("phiModule") != null) ? p.getIntArray("phiModule") : null; - - } // APixelClusterData() --------------------------------------------------- - - - - protected void calculateRhoPhi() - { - calculateRhoPhi(x, y, rho[0], phi[0]); - // treat wraparound - for (int i = 0; i < numData; ++i) - { - if (Math.abs(0 - phi[0][i]) > Math.PI) - { - if (0 - phi[0][i] > 0) - { - phi[0][i] += AMath.TWO_PI; - } - } - } // for - } // calculateRhoPhi() -------------------------------------------------- - - private void cutSubdetector() - { - AParameter par = parameterStore.get("CutsInDet", "SCT"); - if (par.getI() != -1) - { - cutArray(sub, par.getI(), "Barrel/Endcap"); - } - } // cutSubdetector() --------------------------------------------------- - - - protected void applyCuts() - { - cutIndex(); - cutOrientation(); - cutSubdetector(); - cut("CutsInDet", "Layer", "Layer", layer); - cutSimulatedTracks(); - cutReconstructedTracks(); - cutPhi(phi[0]); - cutEta(); - } // applyCuts() -------------------------------------------------------- - - private void cutEta() - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - if (!par.getStatus()) - return; - double etaCut = par.getD(); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double eta1 = AParameterUtilities.eta(z[list], rho[0][list]); - if (eta1 > etaLowerCut && eta1 < etaUpperCut) - listdl[num++] = list; - } - numDraw = num; - } // cutEta() ----------------------------------------------------------- - - public int getLayer(int id) - { - int layer = (id >> 27) & 0x3; - int sub = getSub(id); - if (sub != BARREL) - { - layer += 7; - } - return layer; - } // getLayer() --------------------------------------------------------- - - public int getSub(int id) - { - // bitwise operation to determine cluster position from id (1,0,2 -> endcap-,barrel,endcap+) - return(id >> 29) & 0x3; - } // getSub() ----------------------------------------------------------- - - public int getOrientation(int id) - { - int side = (id & 0x400) >> 10; - int sub = getSub(id); - if ((side == 1 && sub == BARREL) || (side == 0 && sub != BARREL)) - { - return PHI_CLUSTER; - } - - int layer = getLayer(id); - if (layer % 2 == 1) - { - return U_CLUSTER; - } - - return V_CLUSTER; - } // getOrientation() --------------------------------------------------- - - protected void cutOrientation() - { - int num = 0; - AParameter stereoAnglePar = parameterStore.get("PixelCluster", "Stereo"); - if (!stereoAnglePar.getStatus()) - { - return; - } - int orientation = stereoAnglePar.getI(); - for (int i = 0; i < numDraw; i++) - { - if (orientation == getOrientation(id[listdl[i]])) - { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } // cutOrientation() --------------------------------------------------- - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if (colorFunction == numColorTypes + 1) - { - colorBy(layer); - } - else if (colorFunction == numColorTypes + 2) - { - colorByOrientation(); - } - else if (colorFunction == numColorTypes + 3) - { - colorByEloss(); - } - - return numColorTypes + 2; - } // internalColor() ---------------------------------------------------- - - protected void colorByOrientation() - { - int numColors = parameterStore.get("HitColors", "Number").getI(); - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) - { - color[i] = (byte) col[getOrientation(id[i]) + 1 % numColors]; - } - } // colorByOrientation() ----------------------------------------------- - - protected void colorByEloss() - { - // This method currently uses the uncorrected value for eloss as an approximation to dE/dx - // Need to either loop over one track collection for associated tracks in Atlantis, or do this in JiveXML.. - - int numColors = parameterStore.get("HitColors", "Number").getI(); - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) - { - if(eloss[i] < 0.5) - { - color[i] = (byte) col[1 + 1 % numColors]; // blue - } - else if(eloss[i] >=0.5 && eloss[i] < 2) - { - color[i] = (byte) col[5 + 1 % numColors]; // yellow - } - else if(eloss[i] >=2) - { - color[i] = (byte) col[2 + 1 % numColors]; // red/orange - } - } - } // colorByEloss() ----------------------------------------------------- - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index; - - String temp = getNameScreenName() + " (id: " + id[index] + " index: " + index +")\n" + - " orientation = " + getOrientation(id[index]); - temp += "\n x = " + x[index]; - temp += "\n y = " + y[index]; - temp += "\n z = " + z[index]; - temp += "\n " + AMath.RHO + " = " + rho[0][index] + " " + rho[1][index]; - temp += "\n " + AMath.ETA + " module = "; - temp += (etaModule != null) ? Integer.toString(etaModule[index]) : "n/a"; - temp += "\n " + AMath.PHI + " module = "; - temp += (phiModule != null) ? Integer.toString(phiModule[index]) : "n/a"; - temp += "\n widthx = "; - temp += (widthx != null) ? Float.toString(widthx[index]) : "n/a"; - temp += "\n widthy = "; - temp += (widthy != null) ? Float.toString(widthx[index]) : "n/a"; - temp += "\n eloss = "; - temp += (eloss != null) ? Float.toString(eloss[index]) : "n/a"; - - temp += super.getHitInfo(index); // finds barcode information - - return temp; - } // getHitInfo() ------------------------------------------------------- - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 1; j++) - { - hv[0][j][i] = x[list]; - hv[1][j][i] = y[list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.SYMBOLS); - } // getYXUser() -------------------------------------------------------- - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[0][list] - phiMid); - double sign; - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - { - sign = +1.; - } - else - { - sign = -1.; - } - - for (int j = 0; j < 1; j++) - { - hv[0][j][i] = z[list]; - hv[1][j][i] = sign * rho[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.SYMBOLS); - } // getRZUser() -------------------------------------------------------- - - protected ACoord getFRUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 1; j++) - { - hv[0][j][i] = rho[j][list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], z[list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.SYMBOLS).includePhiWrapAround("FR"); - } // getFRUser() -------------------------------------------------------- - - protected ACoord getFZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 1; j++) - { - hv[0][j][i] = z[list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], z[list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.SYMBOLS).includePhiWrapAround("FZ"); - } // getFZUser() -------------------------------------------------------- - - protected ACoord getVPUser() - { - makeDrawList(); - int numTotal = 2 * numDraw; - double[][][] hv = new double[2][numTotal][2]; - int[] index = new int[numTotal]; - double[] sign = new double[] { -1., 1. }; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - double deltaEta = AProjectionVP.getDeltaEta(rho[0][list], z[list]); - double eta = AParameterUtilities.eta(z[list], rho[0][list]); - for (int j = 0; j < 2; j++) - { - // pixels displayed halfway in phi and eta, for some reason - // quick fix = multiply by 2 - hv[0][2 * i + j][0] = 2*(eta + sign[j] * deltaEta); - hv[1][2 * i + j][0] = 2*Math.toDegrees(phi[0][list]); - index[2 * i + j] = list; - } - - } - return new ACoord(hv, index, this, ACoord.POLYLINES).includePhiWrapAround("VP"); - } // getVPUser() -------------------------------------------------------- - -} // class APixelClusterData =================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/APixelRDOData.java b/graphics/AtlantisJava/src/atlantis/data/APixelRDOData.java deleted file mode 100644 index f9c78bd7bf8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/APixelRDOData.java +++ /dev/null @@ -1,160 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - - -/* - * PixelRDO - Pixel Raw Data object (SpacePoint Raw Data Objects) - * The class is derived from AS3DData class (SpacePoint) - * Parameters expected in the event file for the PixelRDO datatype - * id x y z etaModule phiModule - */ -public class APixelRDOData extends AS3DData -{ - private int[] etaModule = null; - private int[] phiModule = null; - - - public String getParameterGroup() - { - return "PixelRDO"; - - } // getParameterGroup() ------------------------------------------------ - - - - public String getName() - { - return "PixelRDO"; - - } // getName() ---------------------------------------------------------- - - - - public String getNameScreenName() - { - return "PixelRDO"; - - } // getNameScreenName() ------------------------------------------------ - - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.RHO+" = "+String.format("%.3f",rho[index])+"\n "+ - "z = "+String.format("%.3f",z[index])+" cm\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - String temp = getNameScreenName() + " (id: " + id[index] + " index: " + index + ")" + - "\n " + AMath.RHO + " = " + String.format("%.3f",rho[index]) + " cm" + - "\n " + AMath.PHI + " = " + - String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)" + - "\n z = " + String.format("%.3f",z[index]) + " cm"; - - temp += "\n " + AMath.ETA + " module = "; - temp += (etaModule != null) ? Integer.toString(etaModule[index]) : "n/a"; - temp += "\n " + AMath.PHI + " module = "; - temp += (phiModule != null) ? Integer.toString(phiModule[index]) : "n/a"; - - return temp; - - } // getHitInfo() ------------------------------------------------------- - - - - APixelRDOData(AHashMap p, AEvent e) - { - super(p,e); - id = p.getIntArray("id"); - etaModule = (p.get("etaModule") != null) ? p.getIntArray("etaModule") : null; - phiModule = (p.get("phiModule") != null) ? p.getIntArray("phiModule") : null; - - } // APixelRDOData() ---------------------------------------------------- - - - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - // int colorFunction=APar.get(PARAMETER_GROUP, "ColorFunction").getI(); - // color by error will go here - // if(colorFunction==numColorTypes+1) - // colorByError() - to implement - - return numColorTypes + 1; - - } // internalColor() ---------------------------------------------------- - - - - protected void applyCuts() - { - cutIndex(); - cutPhi(phi); - cutEta(rho, z); - if(etaModule != null) - { - cut("CutsInDet", "EtaModule", " EtaModule", etaModule); - } - if(phiModule != null) - { - cut("CutsInDet", "PhiModule", " PhiModule", phiModule); - } - - cutSubdetector(); - } // applyCuts() -------------------------------------------------------- - - private void cutSubdetector() - { - AParameter subPar = parameterStore.get("CutsInDet", "SCT"); - if(subPar.getI() != -1) - cutArray(sub, subPar.getI(), "Barrel/Endcap"); - } - - protected ACoord getFRUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = rho[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FR"); - - } // getFRUser() -------------------------------------------------------- - - - - protected ACoord getFZUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = z[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FZ"); - - } // getFZUser() -------------------------------------------------------- - -} // class APixelRDOData ==================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/APulseShapePlot.java b/graphics/AtlantisJava/src/atlantis/data/APulseShapePlot.java deleted file mode 100644 index 8f1279d0fd0..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/APulseShapePlot.java +++ /dev/null @@ -1,513 +0,0 @@ -package atlantis.data; - -import java.util.Vector; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.event.WindowEvent; -import java.awt.event.WindowAdapter; - -import javax.swing.JFrame; -import javax.swing.JPanel; - -// JAS libraries used by Plot class below -import hep.aida.IAnalysisFactory; -import hep.aida.ITree; -import hep.aida.IPlotter; -import hep.aida.IDataPoint; -import hep.aida.IDataPointSet; -import hep.aida.IDataPointSetFactory; -import hep.aida.IPlotterStyle; -import hep.aida.ref.plotter.PlotterUtilities; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; - - -/** - * Plotting pulse shapes and ADC counts for calorimeters - * - * @author Zdenek Maxa - - */ -public class APulseShapePlot -{ - protected static Component guiComponent = AGlobals.instance().getGuiFrame(); - private static Vector<JFrame> frameVector = new Vector<JFrame>(); - - private APulseShapePlot() {} - - - /** - * Plot real pulse shapes plots - ADC counts and calculated values of the - * real pulse shape plot over it. Works for multiple channels (TILE) as - * well as for a single channel e.g. LAr - * - * @param adcCounts int[][] - * @param realPulse double[][] - * @param step double - * @param subTitle String[] - * @param title String - */ - public static void plotRealPulseShapes(int[][] adcCounts, double[][] realPulse, - double step, String[] subTitle, String title) - { - JFrame frame = new JFrame(title); - frame.setTitle(title); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - AIcon.setIconImage(frame); - frame.setLocation(guiComponent.getLocation()); - Plot p = new Plot(); - frame.setContentPane(p); - p.plotRealPulseShapes(adcCounts, realPulse, step, subTitle); - frame.pack(); - int windowWidth = 330 + ((adcCounts.length - 1) * 110); - int windowHeight = 300; - frame.setSize(windowWidth, windowHeight); - frame.setVisible(true); - - frame.addWindowListener(new AllWindowsDisposer()); - frameVector.add(frame); - - } // plotRealPulseShapes() ---------------------------------------------- - - public static void plotRawCellPulseShapes(int[][] adcCounts, double[][] rawPulse, - double[][] cellPulse, double step, - String[] subTitle, String title) - { - JFrame frame = new JFrame(title); - frame.setTitle(title); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - AIcon.setIconImage(frame); - frame.setLocation(guiComponent.getLocation()); - Plot p = new Plot(); - frame.setContentPane(p); - p.plotRawCellPulseShapes(adcCounts, rawPulse, cellPulse, step, subTitle); - frame.pack(); - int windowWidth = 440 + ((adcCounts.length - 1) * 140); - int windowHeight = 400; - frame.setSize(windowWidth, windowHeight); - frame.setVisible(true); - - frame.addWindowListener(new AllWindowsDisposer()); - frameVector.add(frame); - - } // plotRealPulseShapes() ---------------------------------------------- - - /** - * Plots only ADC counts, used as follows: - * APulseShapePlot.plotADCCounts(adcCounts[index], title) - * still used for instance when real pulse shapes plot data is not - * available, e.g. LAr presampler (layer 0) - - * @param data int[][] - * @param title String title of window - * @param axis String[] title for the horizontal axis on each plot (if null uses "bunch crossing") - */ - public static void plotADCCounts(int[][] data, String title, String[] axis) - { - String[] labels = new String[data.length]; - String[] colors = new String[data.length]; - for(int i=0; i<data.length; i++) - { - labels[i]="ADC counts"; - colors[i]="blue"; - } - String[] newAxis; - if(axis!=null) - { - newAxis=axis; - } - else - { - newAxis= new String[data.length]; - for(int i=0; i<data.length; i++) - { - newAxis[i] = "bunch crossing"; - } - } - plotADCCounts(data, title, newAxis, labels, colors); - } - - - - /** - * Plots only ADC counts, used as follows: - * APulseShapePlot.plotADCCounts(adcCounts[index], title) - * still used for instance when real pulse shapes plot data is not - * available, e.g. LAr presampler (layer 0) - - * @param data int[][] - * @param title String title of window - * @param axis String[] titles for the horizontal axis on each plot - * @param labels String[] titles for each plot - * @param colors String[] color of datapoints for each plot - */ - public static void plotADCCounts(int[][] data, String title, String[] axis, String[] labels, String[] colors) - { - JFrame frame = new JFrame(title); - AIcon.setIconImage(frame); - frame.setLocation(guiComponent.getLocation()); - Plot p = new Plot(); - frame.setContentPane(p); - p.plotADCCounts(data, axis, labels, colors); - frame.pack(); - int windowWidth = 330+ ((data.length - 1) * 110); - int windowHeight = 300; - frame.setSize(windowWidth, windowHeight); - frame.setVisible(true); - - frame.addWindowListener(new AllWindowsDisposer()); - frameVector.add(frame); - - } // plotADCCounts() -------------------------------------------------- - - - - static class AllWindowsDisposer extends WindowAdapter - { - public void windowClosing(WindowEvent e) - { - for(int i = 0; i < frameVector.size(); i++) - { - JFrame cf = frameVector.get(i); - cf.dispose(); - } - frameVector.removeAllElements(); - } - - } // class AllWindowsDisposer =========================================== - - -} // class ACaloPulseShapePlot ============================================== - - - -/** - * - * <p>Title: Plot</p> - * - * <p>Description: Plotting class using JAS library </p> - * - */ -class Plot extends JPanel -{ - - public Plot() - { - super(new BorderLayout()); - - } // Plot() ------------------------------------------------------------- - - - - protected void plotRealPulseShapes(int[][] adcCounts, double[][] realPulse, - double step, String[] subTitle) - { - - IAnalysisFactory af = IAnalysisFactory.create(); - ITree tree = af.createTreeFactory().create(); - IDataPointSetFactory dpsf = af.createDataPointSetFactory(tree); - - // Create a two dimensional IDataPointSet - IDataPointSet[] dataPointSet = new IDataPointSet[adcCounts.length]; - for(int i = 0; i < adcCounts.length; i++) - { - String myTitle = (subTitle != null) ? subTitle[i] : "Real pulse shape"; - - double[] x = new double[adcCounts[i].length]; - double[] y = new double[adcCounts[i].length]; - double[] e = new double[adcCounts[i].length]; - - for(int ii = 0; ii < adcCounts[i].length; ii++) - { - x[ii] = ii + 1.0; // counting from 1 (to 9 for TILE) - y[ii] = (double) adcCounts[i][ii]; - e[ii] = 0.0; // arrays with errors - } - - // first parameter must be path - what for here? - dataPointSet[i] = dpsf.createXY(myTitle, x, y, e, e); - dataPointSet[i].setTitle(myTitle); - } // over number of channels - - // Create a two dimensional IDataPointSet - IDataPointSet[] dataPointSetReal = new IDataPointSet[realPulse.length]; - for(int i = 0; i < realPulse.length; i++) - { - String myTitle = (subTitle != null) ? subTitle[i] : "Real pulse shape"; - - double[] x = new double[realPulse[i].length]; - double[] y = new double[realPulse[i].length]; - double[] e = new double[realPulse[i].length]; - - double d = 1.0; - for(int ii = 0; ii < realPulse[i].length; ii++) - { - x[ii] = d; - y[ii] = realPulse[i][ii]; - e[ii] = 0.0; // arrays with errors - d += step; - } - - // first parameter must be path - what for here? - dataPointSetReal[i] = dpsf.createXY(myTitle, x, y, e, e); - dataPointSetReal[i].setTitle(myTitle); - - } // over number of channels - - - IPlotter plotter = af.createPlotterFactory().create(""); - - plotter.createRegions(adcCounts.length, 1); // regions 1x1, 1x2, ... - - // set common style parameters for both regions - IPlotterStyle style = af.createPlotterFactory().createPlotterStyle(); - style.xAxisStyle().setLabel("bunch crossing"); - style.yAxisStyle().setLabel("ADC counts"); - style.titleStyle().textStyle().setColor("black"); - style.titleStyle().textStyle().setBold(true); - style.xAxisStyle().labelStyle().setColor("black"); - style.yAxisStyle().labelStyle().setColor("black"); - - // set no legend at plots - style.statisticsBoxStyle().setVisible(false); // statistical legend - style.legendBoxStyle().setVisible(false); // legend for function fit - - for(int i = 0; i < adcCounts.length; i++) - { - // set style parameters different for regions - style.dataStyle().markerStyle().setParameter("size", "2"); - style.dataStyle().markerStyle().setShape("box"); // "square" - plotter.region(i).style().dataStyle().markerStyle().setColor("red"); - plotter.region(i).plot(dataPointSetReal[i], style); - - style.dataStyle().markerStyle().setParameter("size", "7"); - style.dataStyle().markerStyle().setShape("dot"); // "circle" - plotter.region(i).style().dataStyle().markerStyle().setColor("blue"); - plotter.region(i).plot(dataPointSet[i], style); - } - - // now embed the plotter - add(PlotterUtilities.componentForPlotter(plotter), BorderLayout.CENTER); - - } // plotRealPulseShapes() ---------------------------------------------- - - - - - /** - * Method creates multiple plots of ADC counts only. - * multiple channels, no fit, no pulse shapes. - * or plots of ADC Counts pulse shapes. - * - * @param data int[][] - * @param labels String[] titles for each plot - */ - public void plotADCCounts(int[][] data, String[] axis, String[] labels, String[] colors) - { - IAnalysisFactory af = IAnalysisFactory.create(); - ITree tree = af.createTreeFactory().create(); - IDataPointSetFactory dpsf = af.createDataPointSetFactory(tree); - - // Create a IDataPointSet (one dimension) - IDataPointSet[] dataPointSet = new IDataPointSet[data.length]; - for(int j = 0; j < data.length; j++) - { - - dataPointSet[j] = dpsf.create("plot", labels[j], 2); - - for(int i = 0; i < data[j].length; i++) - { - dataPointSet[j].addPoint(); - IDataPoint dp = dataPointSet[j].point(i); - - dp.coordinate(0).setValue(i); - dp.coordinate(1).setValue(data[j][i]); - } - } - - - IPlotter plotter = af.createPlotterFactory().create(""); - - plotter.createRegions(data.length, 1); // regions 1x1, 1x2, ... - - IPlotterStyle style = af.createPlotterFactory().createPlotterStyle(); - style.yAxisStyle().setLabel("ADC counts"); - style.dataStyle().markerStyle().setParameter("size", "7"); - style.dataStyle().markerStyle().setShape("dot"); - style.titleStyle().textStyle().setColor("black"); - style.titleStyle().textStyle().setBold(true); - style.xAxisStyle().labelStyle().setColor("black"); - style.yAxisStyle().labelStyle().setColor("black"); - - // set no legend at plots - style.statisticsBoxStyle().setVisible(false); // statistical legend - style.legendBoxStyle().setVisible(false); // legend for function fit - - for(int j = 0; j < data.length; j++) - { - plotter.region(j).style().xAxisStyle().setLabel(axis[j]); - plotter.region(j).style().dataStyle().markerStyle().setColor(colors[j]); - plotter.region(j).style().dataStyle().outlineStyle().setColor(colors[j]); - - // plot the data - points ('style' parameter is optional for plotter) - plotter.region(j).plot(dataPointSet[j], style); - } - // now embed the plotter - add(PlotterUtilities.componentForPlotter(plotter), BorderLayout.CENTER); - - } // plotADCCounts() ------------ --------------------------------------- - - - protected void plotRawCellPulseShapes(int[][] adcCounts, double[][] rawPulse, - double[][] cellPulse, - double step, String[] subTitle) - { - - IAnalysisFactory af = IAnalysisFactory.create(); - ITree tree = af.createTreeFactory().create(); - IDataPointSetFactory dpsf = af.createDataPointSetFactory(tree); - - // Create a two dimensional IDataPointSet - IDataPointSet[] dataPointSet = new IDataPointSet[adcCounts.length]; - for(int i = 0; i < adcCounts.length; i++) - { - String myTitle = "ADC counts"; - - double[] x = new double[adcCounts[i].length]; - double[] y = new double[adcCounts[i].length]; - double[] e = new double[adcCounts[i].length]; - - for(int ii = 0; ii < adcCounts[i].length; ii++) - { - x[ii] = ii + 1.0; // counting from 1 (to 9 for TILE) - y[ii] = (double) adcCounts[i][ii]; - e[ii] = 0.0; // arrays with errors - } - - // first parameter must be path - what for here? - dataPointSet[i] = dpsf.createXY(myTitle, x, y, e, e); - dataPointSet[i].setTitle(myTitle); - } // over number of channels - - // Create a two dimensional IDataPointSet - IDataPointSet[] dataPointSetCell = new IDataPointSet[cellPulse.length]; - for(int i = 0; i < cellPulse.length; i++) - { - String myTitle = "Cell time"; - - double[] x = new double[cellPulse[i].length]; - double[] y = new double[cellPulse[i].length]; - double[] e = new double[cellPulse[i].length]; - - double d = 1.0; - for(int ii = 0; ii < cellPulse[i].length; ii++) - { - x[ii] = d; - y[ii] = cellPulse[i][ii]; - e[ii] = 0.0; // arrays with errors - d += step; - } - - // first parameter must be path - what for here? - dataPointSetCell[i] = dpsf.createXY(myTitle, x, y, e, e); - dataPointSetCell[i].setTitle(myTitle); - - } // over number of channels - - - // Create a two dimensional IDataPointSet - IDataPointSet[] dataPointSetRaw = new IDataPointSet[rawPulse.length]; - for(int i = 0; i < rawPulse.length; i++) - { - String myTitle = "Raw time"; - - double[] x = new double[rawPulse[i].length]; - double[] y = new double[rawPulse[i].length]; - double[] e = new double[rawPulse[i].length]; - - double d = 1.0; - for(int ii = 0; ii < rawPulse[i].length; ii++) - { - x[ii] = d; - y[ii] = rawPulse[i][ii]; - e[ii] = 0.0; // arrays with errors - d += step; - } - - // first parameter must be path - what for here? - dataPointSetRaw[i] = dpsf.createXY(myTitle, x, y, e, e); - dataPointSetRaw[i].setTitle(myTitle); - - } // over number of channels - - - IPlotter plotter = af.createPlotterFactory().create(""); - - plotter.createRegions(adcCounts.length, 1); // regions 1x1, 1x2, ... - - // set common style parameters for both regions - IPlotterStyle style = af.createPlotterFactory().createPlotterStyle(); - style.xAxisStyle().setLabel("bunch crossing"); - style.yAxisStyle().setLabel("ADC counts"); - style.titleStyle().textStyle().setColor("black"); - style.titleStyle().textStyle().setBold(true); - style.xAxisStyle().labelStyle().setColor("black"); - style.yAxisStyle().labelStyle().setColor("black"); - - style.statisticsBoxStyle().setVisible(false); // statistical legend - style.legendBoxStyle().setVisible(true); // legend for function fit - - for(int i = 0; i < adcCounts.length; i++) - { - // set style parameters different for regions - style.dataStyle().markerStyle().setParameter("size", "4"); - style.dataStyle().markerStyle().setShape("box"); // "square" - style.dataStyle().showInLegendBox(true); - plotter.region(i).style().dataStyle().markerStyle().setColor("red"); - plotter.region(i).plot(dataPointSetRaw[i], style); - - style.dataStyle().markerStyle().setParameter("size", "2"); - style.dataStyle().markerStyle().setShape("box"); // "square" - style.dataStyle().showInLegendBox(true); - plotter.region(i).style().dataStyle().markerStyle().setColor("green"); - plotter.region(i).plot(dataPointSetCell[i], style); - - style.dataStyle().markerStyle().setParameter("size", "7"); - style.dataStyle().markerStyle().setShape("dot"); // "circle" - style.dataStyle().showInLegendBox(false); - plotter.region(i).style().dataStyle().markerStyle().setColor("blue"); - plotter.region(i).plot(dataPointSet[i], style); - - //plotter.region(i).style().legendBoxStyle().boxStyle().borderStyle().setVisible(false); - - plotter.region(i).setTitle((subTitle != null) ? subTitle[i] : "Real pulse shape"); - } - - // now embed the plotter - add(PlotterUtilities.componentForPlotter(plotter), BorderLayout.CENTER); - - } // plotRealPulseShapes() ---------------------------------------------- - - - -} // class Plot ============================================================= - - - -/* following lines for hints only (futher JAS plotting styles settings) - - IPlotterStyle style = plotterFactory.createPlotterStyle(); - style.xAxisStyle().tickLabelStyle().setFontSize(14); - style.xAxisStyle().tickLabelStyle().setBold(true); - style.xAxisStyle().tickLabelStyle().setColor("blue"); - style.xAxisStyle().labelStyle().setFontSize(24); - style.xAxisStyle().labelStyle().setItalic(true); - style.titleStyle().textStyle().setFontSize(30); - style.dataStyle().markerStyle().setParameter("size","12"); - style.dataStyle().markerStyle().setParameter("shape","3"); - style.dataStyle().markerStyle().setParameter("color","blue"); - plotter.region(0).plot(h1); - plotter.region(0).plot(h2, style); - plotter.show(); -*/ diff --git a/graphics/AtlantisJava/src/atlantis/data/AROIData.java b/graphics/AtlantisJava/src/atlantis/data/AROIData.java deleted file mode 100644 index 0b3a539e250..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AROIData.java +++ /dev/null @@ -1,334 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Base class for EmTauROI, JetROI and MuonROI - * - * @author Gary Taylor, Zdenek Maxa, Qiang Lu - */ - -abstract public class AROIData extends AData -{ - protected float[] eta; - protected float[] phi; - protected float[] energy; - // energy variables for EmTauROIs - protected float[] energyEM; - protected float[] energyTAU; - - private int drawOrFill = AGraphics.FILL; - - AROIData(AHashMap p, AEvent e) - { - super(p,e); - eta = p.getFloatArray("eta"); - phi = p.getFloatArray("phi"); - energy = p.getFloatArray("energy"); - if(this instanceof AEmTauROIData) - { - energyEM = p.getFloatArray("energyEM"); - energyTAU = p.getFloatArray("energyTAU"); - } - } - - public float getEnergy(int index) - { - return energy[index]; - } - public float getEnergyEM(int index) - { - return energyEM[index]; - } - public float getEnergyTAU(int index) - { - return energyTAU[index]; - } - - public float getEta(int index) - { - return eta[index]; - } - - public float getPhi(int index) - { - return phi[index]; - } - - public float[] getEnergy() - { - return energy; - } - - public float[] getEnergyEM() - { - return energyEM; - } - - public float[] getEnergyTAU() - { - return energyTAU; - } - - public float[] getEta() - { - return eta; - } - - public float[] getPhi() - { - return phi; - } - - protected int getDrawOrFill() - { - return drawOrFill; - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - "\n Energy="+String.format("%.3f",energy[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - double deta = parameterStore.get(PARAMETER_GROUP, "deta").getD(); - double dphi = parameterStore.get(PARAMETER_GROUP, "dphi").getD(); - - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n energy = "); - msg.append(String.format("%.3f",energy[index])); - msg.append(" GeV\n "); - if(this instanceof AEmTauROIData) - { - if(energyEM != null) - { - msg.append("energyEM = "); - msg.append(String.format("%.3f",energyEM[index])); - msg.append(" GeV\n "); - } - if(energyTAU != null) - { - msg.append("energyTAU = "); - msg.append(String.format("%.3f",energyTAU[index])); - msg.append(" GeV\n "); - } - } - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - msg.append("\n deta = "); - msg.append(String.format("%.3f",deta)); - msg.append("\n dphi = "); - msg.append(String.format("%.3f",Math.toDegrees(dphi))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",dphi) + " rad)"); - - return msg.toString(); - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if (colorFunction == 0) - { - colorByConstant(); - } - else if (colorFunction == 1) - { - colorByIndex(); - } - - return 1; - } - - protected void applyCuts() - { - cutIndex(); - cutPhi(phi); - cutEta(eta); - } - - protected ACoord getVPUser() - { - drawOrFill = AGraphics.DRAW; - - double deta = parameterStore.get(PARAMETER_GROUP, "deta").getD() / 2; - double dphiDeg = Math.toDegrees(parameterStore.get(PARAMETER_GROUP, "dphi").getD()) / 2; - double phiDeg = 0; - - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - phiDeg = Math.toDegrees(phi[list]); - - // without the cross in the middle - // hv[0][i] = AMath.xBox(eta[list], deta); // x-dx,x-dx,x+dx,x+dx - // hv[1][i] = AMath.yBox(phiDeg, dphiDeg); // y-dy,y+dy,y+dy,y-dy - - hv[0][i] = new double[] { eta[list] - deta, eta[list] - deta, - eta[list] + deta, eta[list] - deta, eta[list] + deta, - eta[list] - deta, eta[list] + deta, eta[list] + deta }; - hv[1][i] = new double[] { phiDeg - dphiDeg, phiDeg + dphiDeg, - phiDeg - dphiDeg, phiDeg - dphiDeg, phiDeg + dphiDeg, - phiDeg + dphiDeg, phiDeg - dphiDeg, phiDeg + dphiDeg }; - index[i] = list; - } - - return new ACoord(hv, index, this).includePhiWrapAround("VP"); - } - - protected ACoord getYXUser() - { - drawOrFill = AGraphics.FILL; - double dphi = parameterStore.get(PARAMETER_GROUP, "dphi").getD() / 2; - - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiPlus = phi[list] + dphi; - double phiMinus = phi[list] - dphi; - double cosPlus = Math.cos(phiPlus); - double sinPlus = Math.sin(phiPlus); - double cosMinus = Math.cos(phiMinus); - double sinMinus = Math.sin(phiMinus); - - double rhoPlus = 1150; - double rhoMinus = 1130; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = rhoMinus * cosPlus; - hv[1][i][0] = rhoMinus * sinPlus; - // x1, y1 - hv[0][i][1] = rhoPlus * cosPlus; - hv[1][i][1] = rhoPlus * sinPlus; - // x2, y2 - hv[0][i][2] = rhoPlus * cosMinus; - hv[1][i][2] = rhoPlus * sinMinus; - // x3, y3 - hv[0][i][3] = rhoMinus * cosMinus; - hv[1][i][3] = rhoMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - - protected ACoord getFRUser() - { - ACoord coordFR = getYXUser().convertYXToFR().includePhiWrapAround("FR"); - return coordFR; - } - - protected ACoord getRZUser() - { - drawOrFill = AGraphics.FILL; - double deta = parameterStore.get(PARAMETER_GROUP, "deta").getD() / 2; - - makeDrawList(); - double[][][] hv = new double[2][numDraw][4]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi[list] - phiMid); - double rSign; - if (phiDiff > Math.PI / 2. && phiDiff <= 3 * Math.PI / 2.) - rSign = -1; - else - rSign = 1; - - // calculate theta based on the eta value - double theta = Math.atan(Math.exp(-Math.abs(eta[list]))) * 2.0; - double thetaPlus = Math.atan(Math.exp(-(Math.abs(eta[list]) - deta))) * 2.0; - double thetaMinus = Math.atan(Math.exp(-(Math.abs(eta[list]) + deta))) * 2.0; - - if ((eta[list] > 0.) && (rSign == -1)) - { - theta = 2 * Math.PI - theta; - thetaPlus = 2 * Math.PI - thetaPlus; - thetaMinus = 2 * Math.PI - thetaMinus; - } - else if ((eta[list] < 0.) && (rSign == -1)) - { - theta += Math.PI; - thetaPlus += Math.PI; - thetaMinus += Math.PI; - } - else if ((eta[list] < 0.) && (rSign == 1)) - { - theta = Math.PI - theta; - thetaPlus = Math.PI - thetaPlus; - thetaMinus = Math.PI - thetaMinus; - } - - double cosPlus = Math.cos(thetaPlus); - double sinPlus = Math.sin(thetaPlus); - double cosMinus = Math.cos(thetaMinus); - double sinMinus = Math.sin(thetaMinus); - - // decide the region based on the theta value - final byte TOP_BOTTOM = 0; - final byte LEFT_RIGHT = 1; - byte region = TOP_BOTTOM; - // hard-coded value is based on the values in Geometry - if (Math.abs(Math.tan(theta)) < 0.8) - region = LEFT_RIGHT; - - double radiusMinus = 0.; - switch (region) - { - case TOP_BOTTOM: - radiusMinus = 1330 / Math.abs(Math.sin(theta)); - break; - case LEFT_RIGHT: - radiusMinus = 1630 / Math.abs(Math.cos(theta)); - break; - } - double radiusPlus = radiusMinus + 20; - - // 4 corners of the cell area - // x0, y0 - hv[0][i][0] = radiusMinus * cosPlus; - hv[1][i][0] = radiusMinus * sinPlus; - // x1, y1 - hv[0][i][1] = radiusPlus * cosPlus; - hv[1][i][1] = radiusPlus * sinPlus; - // x2, y2 - hv[0][i][2] = radiusPlus * cosMinus; - hv[1][i][2] = radiusPlus * sinMinus; - // x3, y3 - hv[0][i][3] = radiusMinus * cosMinus; - hv[1][i][3] = radiusMinus * sinMinus; - - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.POLYGONS); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ARPCData.java b/graphics/AtlantisJava/src/atlantis/data/ARPCData.java deleted file mode 100755 index de50662cfd6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ARPCData.java +++ /dev/null @@ -1,311 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -/** - * for comments see AMDTData - */ - -public class ARPCData extends AMuonHitData -{ - protected float[] width; - protected float[] length; - protected int[] gasGap; - - private static ALogger logger = ALogger.getLogger(ARPCData.class); - - public String getParameterGroup() - { - return "RPC"; - } - - public String getName() - { - return "RPC"; - } - - public String getNameScreenName() - { - return "RPC"; - } - - ARPCData(AHashMap p, AEvent e) - { - super(p,e); - length = p.getFloatArray("length"); - width = p.getFloatArray("width"); - gasGap = new int[numData]; - for (int i = 0; i < numData; ++i) - gasGap[i] = getGasGap(i); - } - - protected int getStation(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(1) == 'M') { - return AIdHelper.rpcDoubletR(id[index]) - 1; - } else { - return AIdHelper.rpcDoubletR(id[index]) + 1; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding RPC identifier", e); - } - - return 0; - } - - protected int getSub(int index) - { - return 0; - } - - public int getSector(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - - if (stationName.charAt(2) == 'L') { - return 2 * (AIdHelper.stationPhi(id[index]) - 1); - } else { - return 2 * (AIdHelper.stationPhi(id[index]) - 1) + 1; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding RPC identifier", e); - } - - return 0; - } - - protected int getGasGap(int index) - { - try { - return AIdHelper.rpcGasGap(id[index]); - } catch (AAtlantisException e) { - logger.error("Problem decoding RPC identifier", e); - } - - return 0; - } - - protected boolean getMeasuresPhi(int index) - { - try { - if (AIdHelper.rpcMeasuresPhi(id[index]) == 1) { - return true; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding RPC identifier", e); - } - - return false; - } - - protected void applyCuts() - { - super.applyCuts(); - if (parameterStore.get("CutsATLAS", "CutPhi").getStatus()) - cutPhi(phi, getDPhi()); - if (parameterStore.get("CutsATLAS", "CutEta").getStatus()) - cutEtaDZ(rho, z, getDZ()); - } - - private float[] getDPhi() - { - // only roughly correct - // must create all - float[] dphi = new float[numData]; - - // need only fill for those in draw list - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - if (measuresPhi[list]) - dphi[list] = (float) Math.abs(Math.atan2(width[list] / 2., rho[list])); - else - dphi[list] = (float) Math.abs(Math.atan2(length[list] / 2., rho[list])); - } - return dphi; - } - - private float[] getDZ() - { - // must create all - float[] dz = new float[numData]; - - // need only fill for those in draw list - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - if (measuresPhi[list]) - dz[list] = (float) (length[list] / 2.); - else - dz[list] = (float) (width[list] / 2.); - } - return dz; - } - - protected ACoord getYXUser() - { - makeDrawList(); - cutArray(measuresPhi, true, " Strip"); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double r = rho[list]; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double phiSector = sector[list] * AMath.PI_BY_8; - double cosPhiSector = Math.cos(phiSector); - double sinPhiSector = Math.sin(phiSector); - double d = width[list] / 2.; - if (!measuresPhi[list]) - d = length[list] / 2.; - double x = r * cosPhi; - double y = r * sinPhi; - double dx = d * sinPhiSector; - double dy = d * cosPhiSector; - - hv[0][0][i] = x + dx; - hv[1][0][i] = y - dy; - hv[0][1][i] = x - dx; - hv[1][1][i] = y + dy; - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getRZUser() - { - makeDrawList(); - cutArray(measuresPhi, false, " Strip"); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[list] - phiMid); - int sign = -1; - - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign = 1; - double rC = sign * AMDTData.getSectorRho(sector[list], rho[list], phi[list]); - double zC = z[list]; - double w = width[list] / 2.; - - hv[0][0][i] = zC - w; - hv[1][0][i] = rC; - hv[0][1][i] = zC + w; - hv[1][1][i] = rC; - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getXZUser() - { - makeDrawList(); - cutMuonSector(sector); - cutArray(measuresPhi, false, " Strip"); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - int sect=(int)Math.round(parameterStore.get("XZ", "Phi").getD() / 22.5); - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int sign = 1; - - if (sector[list] != sect) - sign = -1; - double rC = sign * AMDTData.getSectorRho(sector[list], rho[list], phi[list]); - double zC = z[list]; - double w = width[list] / 2.; - - hv[0][0][i] = zC - w; - hv[1][0][i] = rC; - hv[0][1][i] = zC + w; - hv[1][1][i] = rC; - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getFRUser() - { - makeDrawList(); - cutArray(measuresPhi, true, " Strip"); - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - private void makeDrawListFZ() - { - int mode = parameterStore.get("FZ", "Mode").getI(); - - if (mode == 0 || mode >= 4) - { - numDraw = 0; - } - else - { - makeDrawList(); - cut(" Station", station, "==", mode - 1); - } - cut("FZ", "RPCGasGap", " RPC Gas Gap", gasGap); - } - - protected ACoord getFZUser() - { - makeDrawListFZ(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - index[i] = list; - if (measuresPhi[list]) - { - hv[0][i] = AMath.xBox(z[list], length[list] / 2.); - hv[1][i] = AMath.yBox(Math.toDegrees(phi[list]), Math.toDegrees((width[list] / 2.) / rho[list])); - } - else - { - double zC = z[list]; - double r = rho[list]; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double phiSector = sector[list] * AMath.PI_BY_8; - double cosPhiSector = Math.cos(phiSector); - double sinPhiSector = Math.sin(phiSector); - double d = length[list] / 2.; - double w = width[list] / 2.; - double x = r * cosPhi; - double y = r * sinPhi; - double dx = d * sinPhiSector; - double dy = d * cosPhiSector; - double phi1 = Math.toDegrees(Math.atan2(y - dy, x + dx)); - double phi2 = Math.toDegrees(Math.atan2(y + dy, x - dx)); - hv[0][i] = AMath.xBox(zC, w); - hv[1][i] = AMath.yBox((phi1 + phi2) / 2., (phi1 - phi2) / 2.); - - } - } - return new ACoord(hv, index, this).includePhiWrapAround("FZ"); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ARVxData.java b/graphics/AtlantisJava/src/atlantis/data/ARVxData.java deleted file mode 100644 index 6d27099259a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ARVxData.java +++ /dev/null @@ -1,1043 +0,0 @@ -/* - * CAUTION: When working on this class, remember that the number of vertices - * is not a fixed number for an event. If the user fits additional - * vertices in Atlantis, they will be appended to the list. For this - * reason everything is using ArrayList and not simple arrays. - */ - -package atlantis.data; - -import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.Vector; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.tree.DefaultMutableTreeNode; - -import atlantis.canvas.ACanvas; -import atlantis.event.AEvent; -import atlantis.event.AData; -import atlantis.event.AAssociation; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.list.AList; -import atlantis.list.AListManager; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection3D; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.ALogger; - -import static atlantis.data.AVertex.Type.*; - -/** - * Stores Reconstructed vertices formed for fitting groups - * of tracks. There may not be any reconstructed vertices when a new event - * is read in. However, empty datatype ARVxData is always created within - * the AEvent instance. RVx instances may be added at run time by the user - * when the vertex fitter algorithm is run inside Atlantis. - * - * @author Gary Taylor - */ -public class ARVxData extends AData -{ - private static ALogger logger = ALogger.getLogger(ARVxData.class); - - // size of the arrays with coordinates of the RVx ellipse, - // size of martices - private static final int SIZE = 3; - - // vertices - saved reconstructed vertices, instances of AVertex - private ArrayList<AVertex> vertices = new ArrayList<AVertex>(); - // tracksIndex - indices of tracks (starting from 0) - private ArrayList<int[]> tracksIndex = new ArrayList<int[]>(); - // tracksId - IDs of tracks (as read from event file) - private ArrayList<int[]> tracksId = new ArrayList<int[]>(); - private ArrayList<String> tracksCollection = new ArrayList<String>(); - private ArrayList<Boolean> drawFlag = new ArrayList<Boolean>(); - // false - RVx calculated in Atlantis, true - RVx calculated in Athena - private ArrayList<Boolean> athenaOrigin = new ArrayList<Boolean>(); - - // array of flags 1 - is primary vertex candidate, this - // attribute should be accessed only during event finalise phase - private int[] primVxCand = null; - - /** Vertex type from Athena: for types see - * http://alxr.usatlas.bnl.gov/lxr/source/atlas/Tracking/TrkEvent/TrkEventPrimitives/TrkEventPrimitives/VertexType.h */ - private int[] vertexType = null; - - /** Array containing number of tracks associated with each vertex. */ - private int[] numTracks = null; - - /** Flag whether track numbers are consistent: see Trac bug #551 */ - private boolean hasConsistentTrackNumbers; - - // numData (as at all other datatypes) is used instead of numVertices - // numData variable is referenced from ADrawnGraphics2D (by .getNumData - // method) and since it wasn't set properly in case of RVx it was crashing - // in ADrawnGraphics2D.drawLine() [when rubberbanding over RVx object] - - public String getParameterGroup() - { - return "RVx"; - } - - @Override - public String getName() - { - return "RVx"; - } - - public String getNameScreenName() - { - return "RecVertex"; - } - - /** - * This constructor is called when RVx datatype is found in the event file. - * This RVx data was produced in Athena. - * @param p elements within RVx element in JiveXML input: map of names to values - * @param e parent event - * @throws AAtlantisException if failing to create data - */ - ARVxData(AHashMap p, AEvent e) throws AAtlantisException - { - super(p,e); - - int[] tracks = p.getIntArray("tracks"); - numTracks = p.getUnsureIntArray("numTracks"); - if (numTracks == null) numTracks = new int[numData]; - float[] z = p.getFloatArray("z"); - float[] y = p.getFloatArray("y"); - float[] x = p.getFloatArray("x"); - float[] covMatrix = p.getFloatArray("covMatrix"); - float[] chi2 = p.getFloatArray("chi2"); - String[] storegateKeys = null; - - // Check whether numbers of tracks agree. - hasConsistentTrackNumbers = false; - if (tracks!=null) { - int numTrackIds = tracks.length; - int numTracksFromVertices = 0; - for (int numTracksFromVertex : numTracks) { - numTracksFromVertices += numTracksFromVertex; - } - if (numTracksFromVertices == numTrackIds) { - hasConsistentTrackNumbers = true; - } - } - if (!hasConsistentTrackNumbers) { - logger.error("RVx: numbers of tracks are inconsistent."); - } - - if(p.getStringArray("sgkey") != null) - { - storegateKeys = p.getStringArray("sgkey"); - } - else - { - storegateKeys = new String[numData]; - for (int i = 0; i < numData; i++) - { - storegateKeys[i] = "n/a"; - } - } - - // Allowed to be null if element not in JiveXML. - vertexType = p.getUnsureIntArray("vertexType"); - - primVxCand = p.getUnsureIntArray("primVxCand"); - if (primVxCand == null) primVxCand = new int[numData]; - - if (hasConsistentTrackNumbers) createVertexTrackAssociations(tracks, storegateKeys); - - double[] pos = new double[SIZE]; - double[][] cov = new double[SIZE][SIZE]; - int[] tracksIdArray = null; - int[] tracksIndexArray = null; - - int n = 0; - int m = 0; - for (int i = 0; i < numData; i++) - { - // x, y, z coordinates of the RVx ellipse - pos[0] = x[i]; - pos[1] = y[i]; - pos[2] = z[i]; - - // covMatrix, resp. 3x3 cov array - // numbers are too small, so JiveXML multiplies by 10k, here inverse - // [the same happens with covMatrix for tracks - AHelixData class] - for (int j = 0; j < SIZE; j++) - { - for (int k = 0; k < j + 1; k++) - { - cov[j][k] = covMatrix[n] / 10000; - cov[k][j] = cov[j][k]; - n++; - } - } - - AVertex vertex = new AVertex(chi2[i], pos, cov); - vertices.add(vertex); // new vertex - - // Only save track details if data are consistent. - if (hasConsistentTrackNumbers) { - tracksIdArray = new int[numTracks[i]]; - tracksIndexArray = new int[numTracks[i]]; - for (int j = 0; j < numTracks[i]; j++) - { - tracksIdArray[j] = tracks[m]; - // should be removed - problem that IDs run from 1 and indices - // from 0 - will be fixed - tracksIndexArray[j] = tracks[m] - 1; - m++; - } - tracksIndex.add(tracksIndexArray.clone()); // save indices of tracks - tracksId.add(tracksIdArray.clone()); // save IDs of tracks - } - - // save storeGateKey of the Tracks which form this vertex - tracksCollection.add(storegateKeys[i]); - drawFlag.add(new Boolean(true)); - athenaOrigin.add(new Boolean(true)); - } // for(int i = 0; i < numData; i++) - } // ARVxData() --------------------------------------------------------- - - - /** - * Create vertex-track associations. and adds them to the event's association manager. - * @param tracks array of track ID numbers - * @param storegateKeys array of storegate keys, one per vertex - * Also uses numTracks: number of tracks associated with each vertex. - */ - private void createVertexTrackAssociations(int[] tracks, String[] storegateKeys) { - // Create a list of unique storegate keys. - Vector<String> uniqueStoregateKeys = new Vector<String>(); - if(!storegateKeys[0].equals("n/a")){ - uniqueStoregateKeys.add(storegateKeys[0]); - } - for(int i = 0; i < storegateKeys.length; i++){ - if(storegateKeys[i].equals("n/a")){ - continue; - } - // Check if track particle type already added to list of storegate keys - boolean inVector = false; - for (String sgKey : uniqueStoregateKeys) { - if (sgKey.equals(storegateKeys[i])) { - inVector = true; - break; - } - } - // If storegate key is not in the list, it is added. - if(!inVector){ - uniqueStoregateKeys.add(storegateKeys[i]); - } - } - // Create new association int array for each unique storegate key. - for(int i = 0; i < uniqueStoregateKeys.size(); i++){ - int trackCount = 0; - Vector<Integer> TrkNum = new Vector<Integer>(); - Vector<Integer> Track = new Vector<Integer>(); - // Creating vectors of the 'number of tracks associated to each list' and 'track Ids' - for(int j = 0; j < storegateKeys.length; j++){ - if(uniqueStoregateKeys.get(i).equals(storegateKeys[j])){ - TrkNum.add(numTracks[j]); - for(int k = trackCount; k < trackCount + numTracks[j]; k++){ - Track.add(tracks[k]); - } - } - trackCount += numTracks[j]; - } - //Converting vectors to int[] - int[] assocTracks = new int[Track.size()]; - for(int j = 0; j < Track.size(); j++){ - assocTracks[j] = Track.get(j); - } - int[] numTrks = new int[TrkNum.size()]; - for(int j = 0; j < TrkNum.size(); j++){ - numTrks[j] = TrkNum.get(j); - } - //Creating associations - AAssociation assoc = new AAssociation("RVx" + getStoreGateKey(), - "InDetTrack" + uniqueStoregateKeys.get(i), numTrks, - assocTracks, event); - event.getAssociationManager().add(assoc); - } - } - - /** - * Redefined inherited method AData.getIdFromIndex() - * the array int[] id is not used in this class (unlike other types) so - * AData.getIdFromIndex() was crashing at RVx since this array was empty - * listdl[] array (also inherited from AData) should be properly handled - * in this class (used to crash when rubberbanding over displayed RVx) - * @param index int - * @return int - */ - @Override - public int getIdFromIndex(int index) - { - return listdl[index]; - } // getIdFromIndex() ----------------------------------------------------- - - /** - * - * @param listOfTracksToVertex int[] - list of track indices (internal - * Atlantis indices starting from 0) - * @param key - Track collection storeGateKey - */ - private void createVertexFromTracks(int[] listOfTracksToVertex, String key) - { - - //Retrieving/checking for pre-existing assocation - int[][] assoc = event.getAssociationManager().get("RVx","InDetTrack" + key); - if(assoc == null){ - //Create new association for the between selected tracks and the new vertex - int[] numTracks2 = new int[1]; - numTracks2[0] = listOfTracksToVertex.length; - event.getAssociationManager().add(new AAssociation("RVx","InDetTrack" + key, numTracks2, listOfTracksToVertex, event)); - }else{//if assocation already exists add new one to it - //Remove old assocation - event.getAssociationManager().remove("InDetTrack" + key + "RVx"); - //Create new assocation by copying old one and adding extra line at the end. - int[][] newAssoc = new int[assoc.length + 1][]; - for(int i = 0; i < newAssoc.length; i++){ - if(i == assoc.length){ - newAssoc[i] = listOfTracksToVertex; - }else{ - newAssoc[i] = assoc[i]; - } - } - //recreating assocation - event.getAssociationManager().add(new AAssociation("RVx","InDetTrack" + key, newAssoc, event)); - } - - - - ATrackData aRTr = null; - aRTr = event.getTrackData("InDetTrack", key); - if (aRTr == null) - { - return; - } - // get helices of the appropriate tracks, helices are access by indices - // save the IDs of tracks into trackIdLocal which will be copied to tracksId - int[] trackIdLocal = new int[listOfTracksToVertex.length]; - AHelix[] thisHelGoToFitter = new AHelix[listOfTracksToVertex.length]; - for (int j = 0; j < listOfTracksToVertex.length; j++) - { - AHelix helix = aRTr.getModifiableHelix(listOfTracksToVertex[j]); - if (helix == null) { - AOutput.alwaysAppend("\nOne or more of the selected tracks do not have perigee parameters, " - + "the vertex cannot be created\n", ALogInterface.BAD_COMMAND); - return; - } - thisHelGoToFitter[j] = helix; - trackIdLocal[j] = aRTr.getIdFromIndex(listOfTracksToVertex[j]); - } - - - double xVtx = parameterStore.get("Event", "XVtx").getD(); - double yVtx = parameterStore.get("Event", "YVtx").getD(); - double zVtx = parameterStore.get("Event", "ZVtx").getD(); - AVertex startingPoint = new AVertex(new double[] { xVtx, yVtx, zVtx }); - try - { - // RuntimeException is thrown - no vertex found or goes on (new vertex) - AVertex vertex = AVertexFit.fitVertex(startingPoint, thisHelGoToFitter); - vertices.add(vertex); // new vertex - tracksIndex.add(listOfTracksToVertex.clone()); // save indices of tracks - tracksId.add(trackIdLocal.clone()); // save IDs of tracks - tracksCollection.add(key); - drawFlag.add(new Boolean(true)); - athenaOrigin.add(new Boolean(false)); - - int[] newNumTracks = new int[numData+1]; - int[] newPrimVxCand = new int[numData+1]; - for (int i=0; i<numData; i++) { - newNumTracks[i] = numTracks[i]; - newPrimVxCand[i] = primVxCand[i]; - } - numTracks = newNumTracks; - primVxCand = newPrimVxCand; - numTracks[numData] = listOfTracksToVertex.length; - primVxCand[numData] = 2; - - if (vertexType != null) { - int[] newVertexType = new int[numData+1]; - for (int i=0; i<numData; i++) { - newVertexType[i] = vertexType[i]; - } - vertexType = newVertexType; - vertexType[numData] = 2; - } - - double[] par = vertex.getPosition(); - double Vx = par[0]; - double Vy = par[1]; - // temp set axis and orientation of 3D rotation wrt last vertex - // adjust the starting point of the tracks according to the vertex - double Vz = par[2]; - for (int j = 0; j < thisHelGoToFitter.length; j++) - { - double a = Vx - xVtx; - double b = Vy - yVtx; - double c = Vz - zVtx; - double size = Math.sqrt(a * a + b * b + c * c); - parameterStore.get("3D", "xAxis").setD(a / size); - parameterStore.get("3D", "yAxis").setD(b / size); - parameterStore.get("3D", "zAxis").setD(c / size); - thisHelGoToFitter[j].setPhiStartByXYPoint(Vx, Vy); - } - AOutput.alwaysAppend("\n" + getHitInfo(numData) + "\n", ALogInterface.NORMAL); - numData++; - makeDrawList(); - } - catch (RuntimeException e) - { - StringBuilder temp = new StringBuilder("\nRVx: tracks ("); - for (int i = 0; i < listOfTracksToVertex.length; i++) - { - if (i > 0) - { - temp.append(", "); - } - // the tracks were accessed by indices but user wants to see - // IDs like pick prints (listOfTracksToVertex[] - indices) - temp.append(aRTr.getIdFromIndex(listOfTracksToVertex[i])); - } - AOutput.alwaysAppend(temp + ")\n not originating from a common vertex\n", ALogInterface.NORMAL); - throw e; - } - } // createVertexFromTracks() ------------------------------------------- - - /** - * 'Colour by vertex type' option, that allows to colour the vertices depending on whether they are primary, - * secondary or other vertices. - */ - protected void colorbyVertexType() { - - int pri = parameterStore.get("RVx", "PriVxColor").getI(); - int sec = parameterStore.get("RVx", "SecVxColor").getI(); - int res = parameterStore.get("RVx", "RestVxColor").getI(); - - if (vertexType!=null) { - for (int i=0; i<numData; ++i) { - int typeId = vertexType[i]; - AVertex.Type type = AVertex.Type.typeFromId(typeId); - switch (type) { - case PRIMARY: - case DUMMY: - color[i] = (byte) pri; - break; - case SECONDARY: - color[i] = (byte) sec; - break; - case TEMPV0LAMBDA: - color[i] = (byte) sec; - break; - case TEMPV0LAMBDABAR: - color[i] = (byte) sec; - break; - case TEMPKSHORT: - color[i] = (byte) sec; - break; - case PILEUP: - case CONVERSION: - case V0: - case KINK: - color[i] = (byte) res; - break; - default: - color[i] = (byte) res; - - } - } - } - else if (primVxCand!=null) { // use primary vertex candidate flag as fall-back if vertex type not available - for (int i=0; i<numData; ++i) { - if (primVxCand[i]==1) { - color[i] = (byte) pri; - } - else { - color[i] = (byte) res; - } - } - } - else { // if no vertex type information, use constant colour - colorByConstant(); - } - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - // The number of vertices can increase when the user fits a vertex in - // Atlantis, make sure the color array also increases in size then - if (numData > color.length) - color = new byte[numData]; - - if (colorFunction == 0) - { - colorByConstant(); - } - else if(colorFunction == 1) - { - colorByIndex(); - } - else if (colorFunction == 2) - { - colorbyVertexType(); - } - return 0; - } // internalColor() ---------------------------------------------------- - - @Override - public void makeDrawList() - { - numDraw = 0; - listdl = new int[numData]; - for (int i = 0; i < numData; i++) { - if (drawFlag.get(i).booleanValue()) { - listdl[numDraw] = i; - numDraw++; - } - } - this.cutTracksByVertexType(); - this.applyCuts(); - } - - private void cutTracksByVertexType() { - numDraw = 0; - listdl = new int[numData]; - for (int i = 0; i < numData; i++) { - if (drawFlag.get(i).booleanValue()) { - // All=0, Primary=1, Secondary=2, Rest=3 - int vertexTypeSelected = parameterStore.get("CutsObjects", "vertextype").getI(); - if (vertexTypeSelected==0) { - listdl[numDraw] = i; - numDraw++; - } - if (vertexTypeSelected==1) { // primary - if (vertexType!=null) { - int typeId = vertexType[i]; - AVertex.Type type = AVertex.Type.typeFromId(typeId); - if (type == PRIMARY || type == DUMMY){ - listdl[numDraw] = i; - numDraw++; - } - } - } - if (vertexTypeSelected==2){ - if (vertexType!=null) { - int typeId = vertexType[i]; - AVertex.Type type = AVertex.Type.typeFromId(typeId); - if (type == SECONDARY || type == TEMPV0LAMBDA || type == TEMPV0LAMBDABAR || type == TEMPKSHORT){ - listdl[numDraw] = i; - numDraw++; - } - } - } - if (vertexTypeSelected==3){ - if (vertexType!=null) { - int typeId = vertexType[i]; - AVertex.Type type = AVertex.Type.typeFromId(typeId); - if (type == PILEUP || type == CONVERSION || type == V0 || type == KINK){ - listdl[numDraw] = i; - numDraw++; - } - } - } - } - } - } - - public String getHitInfo(int index) - { - boolean athenaOriginBoolean = athenaOrigin.get(index).booleanValue(); - String origin = (athenaOriginBoolean == true) ? "Athena" : "Atlantis"; - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - "\n calculated in "+origin; - - StringBuilder temp = new StringBuilder(); - temp.append("\n" + getNameScreenName() + " (index: " + index + ") (calculated in " + origin + ")\n" + " type of Track: " + tracksCollection.get(index) + "\n"); - temp.append(" tracks IDs = "); - boolean tracksIDsKnown = false; - if (tracksId.size() > 0) { - int[] tracksIdInVertex = (tracksId.get(index)); - for (int i = 0; i < tracksIdInVertex.length; i++) - { - int id2 = tracksIdInVertex[i]; - // if the JiveXML knows that vertex creates X number of - // tracks but doesn't know the ID, -1 is put as tracks ID - // list of -1 doesn't need to be printed - if (id2 > -1) - { - tracksIDsKnown = true; - if (i > 0) - { - temp.append(","); - } - temp.append(tracksIdInVertex[i]); - } - } - } - if (!tracksIDsKnown) temp.append("n/a"); - //To display in the output screen the vertex type number and description when this is selected - if (vertexType!=null) { - int typeId = vertexType[index]; - AVertex.Type type = AVertex.Type.typeFromId(typeId); - String vertexInfo = String.format("%nVertex type = %d (%s)", typeId, type.description); - temp.append(vertexInfo); - } - temp.append("\nPrimary candidate status = " + primVxCand[index]); - temp.append("\nnumTracks = " + numTracks[index]); - temp.append("\n" + vertices.get(index)); - return temp.toString(); - } // getHitInfo() ------------------------------------------------------- - - @Override - public ACoord getYXUser() - { - makeDrawList(); - double hv[][][] = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double[][] p = vertex.getYXEllipse(); - hv[0][i] = p[0]; - hv[1][i] = p[1]; - - index[i] = listdl[i]; - } - return new ACoord(hv, index, this); - } // getYXUser() -------------------------------------------------------- - - @Override - public ACoord getXZUser() - { - makeDrawList(); - double hv[][][] = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double[][] p = vertex.getXZEllipse(); - hv[0][i] = p[0]; - hv[1][i] = p[1]; - index[i] = listdl[i]; - } - return new ACoord(hv, index, this); - } // getXZUser() -------------------------------------------------------- - - @Override - public ACoord getYZUser() - { - makeDrawList(); - double hv[][][] = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double[][] p = vertex.getYZEllipse(); - hv[0][i] = p[0]; - hv[1][i] = p[1]; - index[i] = listdl[i]; - } - return new ACoord(hv, index, this); - } // getYZUser() -------------------------------------------------------- - - @Override - public ACoord getRZUser() - { - makeDrawList(); - double hv[][][] = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - //TODO: make "RZ ellipse" - double[][] p = vertex.getRZEllipse(); - hv[0][i] = p[0]; - hv[1][i] = p[1]; - index[i] = listdl[i]; - } - return new ACoord(hv, index, this); - } // getRZUser() -------------------------------------------------------- - - @Override - protected ACoord get3DUser() - { - makeDrawList(); - double h[] = new double[numDraw]; - double v[] = new double[numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - double[] hvo = AProjection3D.getRotated(vertices.get(listdl[i]).getPosition()); - h[i] = hvo[0]; - v[i] = hvo[1]; - index[i] = listdl[i]; - } - return new ACoord(h, v, index, this); - } // get3DUser() -------------------------------------------------------- - - @Override - public ACoord getFZUser() - { - makeDrawList(); - double h[] = new double[numDraw]; - double v[] = new double[numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double[] xyz = vertex.getPosition(); - double phi = vertex.getPhi(); - double z = xyz[2]; - h[i] = z; - v[i] = Math.toDegrees(phi); - index[i] = listdl[i]; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FZ"); - } // getFZUser() -------------------------------------------------------- - - @Override - public ACoord getFRUser() - { - makeDrawList(); - double h[] = new double[numDraw]; - double v[] = new double[numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double rho = vertex.getRho(); - double phi = vertex.getPhi(); - h[i] = rho; - v[i] = Math.toDegrees(phi); - index[i] = listdl[i]; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FR"); - } // getFRUser() -------------------------------------------------------- - - @Override - public ACoord getVPUser() - { - makeDrawList(); - double h[] = new double[numDraw * 2]; - double v[] = new double[numDraw * 2]; - int[] index = new int[numDraw * 2]; - double[] sign = new double[] { -1., 1. }; - int num = 0; - - for (int i = 0; i < numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - double[] xyz = vertex.getPosition(); - // if rho is 0, AMath.eta() divides by 0, since it's real type, - // Infinity is returned, program doesn't crash, vertex is not drawn - // proper would be to test all rho > 0.01cm values in advance - double rho = vertex.getRho(); - double phi = vertex.getPhi(); - double z = xyz[2]; - double eta = AParameterUtilities.eta(z, rho); - double delEta = AProjectionVP.getDeltaEta(rho, z); - for (int j = 0; j < 2; j++) - { - h[num] = eta + sign[j] * delEta; - v[num] = Math.toDegrees(phi); - index[num] = listdl[i]; - num++; - } - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } // getVPUser() -------------------------------------------------------- - - protected void applyCuts() - { - cutIndex(); - - float[] phi = new float[numDraw]; - float[] eta = new float[numDraw]; - for(int i=0; i<numDraw; i++) - { - AVertex vertex = vertices.get(listdl[i]); - phi[i] = (float) vertex.getPhi(); - double z = vertex.getPosition()[2]; - eta[i] = (float) AParameterUtilities.eta(z, vertex.getRho()); - } - cutPhi(phi); - cutEta(eta); - - cut("CutsInDet", "NumRVxTracks", " Ntrack", numTracks); - cut("CutsInDet", "PrimaryRVx", " Primary", primVxCand); - - } // applyCuts() -------------------------------------------------------- - - /** - * @param nodes Collection - * @return Action[] - * Method returns either empty list of Actions or Vertex item after the - * right mouse click on the list (in the list dialog) - * Vertex only appear if there is one type of reconstructed tracks in the - * list and no other datatype - */ - @Override - public Action[] getActions(Collection nodes) - { - if (nodes.size() != 1) - { - return new Action[0]; - } - final DefaultMutableTreeNode node = (DefaultMutableTreeNode) (nodes.iterator().next()); - if (!node.getAllowsChildren()) - { - return new Action[0]; - } - AList[] list = AListManager.getInstance().getChildren(node); - if (list == null) - { - return new Action[0]; - } - Set<Integer> tracks = new HashSet<Integer>(); - Set<Integer> tracksID = new HashSet<Integer>(); - // iterate over the items in the list (set of whichever datatypes) - // condition in this loop assures that 'Vertex *' action appears only - // if there is/are set(s) of one type of reconstructed tracks and no - // other types. the condition used to be - // list[i].getSource() == ... .event.getRTrData() which was - // a method depending on the current selected Hits-to-RTr association - for (int i = 0; i < list.length; i++) - { - // tests that there is either type of reconstructed tracks in the list - if (list[i].getSource() instanceof ATrackData) - { - // test that there is just one type of reconstructed tracks if - // there are more than one item in list - if (i > 0) - { - String key1 = list[i - 1].getSource().getStoreGateKey(); - String key2 = list[i].getSource().getStoreGateKey(); - if (!(key1 == null && key2 == null) && !key1.equals(key2)) - { - String msg = "info: Vertexing is available if only one " + - "Track collection is chosen in the list. " + - " (select: InDet->Track->Track Collections)\n"; - AOutput.alwaysAppend(msg, ALogInterface.NORMAL); - return new Action[0]; - } - } - // tests passed - save indices of the tracks from the hashtable - for (int j = 0; j < list[i].getItems().length; j++) - { - int index = list[i].getItems()[j]; - int id2 = list[i].getSource().getIdFromIndex(index); - tracks.add(new Integer(index)); - tracksID.add(new Integer(id2)); - } - } - else - { - return new Action[0]; - } - } // for - int numTracks2 = tracks.size(); - if (numTracks2 < 2) - { - return new Action[0]; - } - final String trackName = list[0].getSource().getNameScreenName(); - final String trackStoreGateKey = list[0].getSource().getStoreGateKey(); - final int[] trackNumbers = new int[numTracks2]; // indices of tracks - final int[] trackIDs = new int[numTracks2]; // IDs of tracks - Iterator<Integer> i = tracks.iterator(); - int n = 0; - while (i.hasNext()) - { - trackNumbers[n++] = (i.next()).intValue(); - } - i = tracksID.iterator(); - n = 0; - while (i.hasNext()) - { - trackIDs[n++] = (i.next()).intValue(); - } - Action[] action = new Action[1]; // only one action will be displayed - // after removing interactive Athena - action[0] = new AbstractAction("Vertex " + trackName + " " + trackStoreGateKey + " in Atlantis") - { - public void actionPerformed(ActionEvent e) - { - try - { - createVertexFromTracks(trackNumbers, trackStoreGateKey); - // maybe should be all windows - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - node.setUserObject(new AList(ARVxData.this, numData - 1)); - } - catch (Exception ee) - { - // this exception was initially completely ignored (empty - // block) - can't actually see the reason why it is thrown - // at the end of createVertexFromTracks since it should be - // ignored. whether or not the exception occures tells - // whether the tracks are coming from the common vertex - - logger.debug("ARVxData.getActions() exception: " + ee.getMessage(), ee); - } - } - }; - - return action; - } // getActions() ------------------------------------------------------- - - - /** - * The method is called when Remove action is selected after right-click - * on the list item. There may be vertices coming from different types of - * tracks, trackType variable assures that the current reconstructed track - * instance is retrieved and the helix paremeters set on corrent tracks - * @param index int[] - */ - @Override - public void remove(int[] index) - { - String key = null; - ATrackData aRTr = null; - for (int i = 0; i < index.length; ++i) - { - drawFlag.set(index[i], new Boolean(false)); - key = tracksCollection.get(index[i]); - aRTr = event.getTrackData("InDetTrack", key); - if (aRTr != null) - { - int[] tracksInVertex = (tracksIndex.get(index[i])); - for (int j = 0; j < tracksInVertex.length; ++j) - { - aRTr.getModifiableHelix(tracksInVertex[j]).setPhiStartByXYPoint(0., 0.); - } - } // if - } // for - } // remove() ----------------------------------------------------------- - - /** - * if RVx (with numData > 0) is present in this event, cut Tracks - * forming vertices when tracks are drawn as polylines - */ - public void cutTracksToRVx(AEvent event) - { - if (!hasConsistentTrackNumbers) return; - for (int i = 0; i < numData; i++) - { - boolean origin = athenaOrigin.get(i).booleanValue(); - if (origin) - { - // true - RVx coming from Athena -> cut the track if its - // storeGateKey is known (was saved into tracksCollection) - String trackKey = tracksCollection.get(i); - ATrackData tracks = event.getTrackData("InDetTrack", trackKey); - if (tracks != null) - { - int[] tracksIdInVertex = (tracksId.get(i)); - if (tracksIdInVertex.length < 2) //ACH - put some more cuts on this? - continue; - AHelix[] thisHelGoToFitter = new AHelix[tracksIdInVertex.length]; - AVertex vertex = vertices.get(i); - double[] par = vertex.getPosition(); - double Vx = par[0]; - double Vy = par[1]; - for (int j = 0; j < tracksIdInVertex.length; j++) - { - int id2 = tracksIdInVertex[j]; - // if the JiveXML knows that vertex creates X number of - // tracks but doesn't know the ID, -1 is put as tracks ID - // skip cutting tracks - ID is actually unknown - if (id2 > -1) - { - thisHelGoToFitter[j] = tracks.getModifiableHelix(id2); - thisHelGoToFitter[j].setPhiStartByXYPoint(Vx, Vy); - } - } - } // if(tracks != null) - } - } - } // cutTracksToRVx() ---------------------------------------------------- - - - - /** - * Returns the values of primary vertex for the current event using the - * first vertex in this RVx data if it exists. - * @return double[3] or null - */ - public double[] getPrimaryVertex() - { - double[] vtx = null; // vertex position (x, y, z order) - - if (!(numData > 0)) - { - // Check this? If we have no vertices, want to get a primary vertex - // from somewhere else - return vtx; // null - } - - // if datatype contains primVxCand subtag, then take first item - // flagged 1 (primary vertex candidate) otherwise first item of - // the whole datatype - if(primVxCand != null) - { - for(int i = 0; i < numData; i++) - { - if(primVxCand[i] == 1) - { - vtx = vertices.get(i).getPosition(); - break; - } - } - if(vtx == null) - { - // none of the vetices had flag 1, take the first one anyway - vtx = vertices.get(0).getPosition(); - } - } - else - { - // primVxCand is not available, take the first item - vtx = vertices.get(0).getPosition(); - } - - return vtx; - - } // getPrimaryVertex() ------------------------------------------------- - - - - /** - * - * @param index int - * @return double[] - * Returns double array with x, y, z positions of the vertex - */ - public double[] getVertex(int index) - { - double[] vtx = null; - vtx = vertices.get(index).getPosition(); - return vtx; - - } // getVertex() -------------------------------------------------------- - - -} // class ARVxData ========================================================= diff --git a/graphics/AtlantisJava/src/atlantis/data/AS3DData.java b/graphics/AtlantisJava/src/atlantis/data/AS3DData.java deleted file mode 100644 index 62929b6f6b8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AS3DData.java +++ /dev/null @@ -1,486 +0,0 @@ -package atlantis.data; - -import atlantis.event.AAssociation; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - - -/* - * The input array clusters is being used to contain two types of information - * for pixel clusters - * clusters[i][0] = identifier - * clusters[i][1] = -1 - * for space points from 2 strip clusters it contains the identifiers of the - * individual strips - * clusters[i][0] = identifier of first strip - * clusters[i][1] = identifier of second strip - */ -public class AS3DData extends A3DPointData -{ - private int[][] clusters = null; - // read from the event file - protected int[] layer = null; - private int[] etaModule = null; - private int[] phiModule = null; - - // for use by the filter loop, group[] is filled in by hit filter, other - // classes contain group functionality as well but currently (2006/08) - // hit filter takes into account only S3D (SiSpacePoint) data - protected int[] group = null; - private double[] eta = null; - - private boolean[] pixel = null; - public static final int PIXEL = -1; - public static final int CUT_INDET_SCT_ALL = -1; - public static final int CUT_INDET_SCT_EC_NEG = 0; - public static final int CUT_INDET_SCT_BARREL = 1; - public static final int CUT_INDET_SCT_EC_POS = 2; - - - - public String getParameterGroup() - { - return "S3D"; - } - - - public String getName() - { - return "S3D"; - } - - - public String getNameScreenName() - { - return "SpacePoint"; - } - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - String clId = clusters[index][0] + ", " + clusters[index][1]; - String type = pixel[index] ? " (Pixel hit)" : " (SCT hit)"; - - String temp = getNameScreenName() + " (id: " + id[index] + " index: " + index + ")" + - type + - "\n cluster identifiers: " + clId + - "\n x = " + String.format("%.3f",x[index]) + " cm" + - "\n y = " + String.format("%.3f",y[index]) + " cm" + - "\n z = " + String.format("%.3f",z[index]) + " cm" + - "\n " + AMath.RHO + " = " + String.format("%.3f",rho[index]) + - " cm" + - "\n " + AMath.PHI + " = " + - String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)" + - "\n z = " + String.format("%.3f",z[index]) + " cm" + - "\n group = " + group[index]; - temp += "\n " + AMath.ETA + " module = "; - temp += (etaModule != null) ? Integer.toString(etaModule[index]) : "n/a"; - temp += "\n " + AMath.PHI + " module = "; - temp += (phiModule != null) ? Integer.toString(phiModule[index]) : "n/a"; - temp += super.getHitInfo(index); // finds barcode information - - return temp; - - } // getHitInfo() --------------------------------------------------------- - - - - AS3DData(AHashMap p, AEvent e) - { - super(p,e); - - etaModule = (p.get("etaModule") != null) ? p.getIntArray("etaModule") : null; - phiModule = (p.get("phiModule") != null) ? p.getIntArray("phiModule") : null; - - // use this for now as pixel id have bug i.e. sometimes > 0 - layer = p.getUnknownIntArray("layer"); - if(p.get("layer") == null || p.get("sub") == null) - { - calculateLayerSubdetector(); - } - group = new int[numData]; - eta = new double[numData]; - - if(p.get("clusters") != null) - { - // can only distinguish between SCT and Pixel hits if clusters - // subtag is available - pixel = new boolean[numData]; - // save IDs from event file to be available with pick info - clusters = new int[numData][]; - int[][] assocClusters = new int[numData][]; - int[] temp = p.getIntArray("clusters"); - for(int i = 0; i < numData; i++) - { - // save all clusters IDs - clusters[i] = new int[] { temp[2 * i], temp[2 * i + 1] }; - - // check if the second number, PIXEL (-1) designates pixel hit - if(temp[2 * i + 1] != PIXEL) - { - // this is SCT spacepoint - has got two clusters - assocClusters[i] = new int[] { temp[2 * i], temp[2 * i + 1] }; - } - else - { - // this is a pixel spacepoint (second cluster number is -1) - pixel[i] = true; - - // to ignore associtiation between pixel clusters and spacepoints: - // assocClusters[i] = null; - - // taking pixel cluster into account (pixel spacepoint has got - // only one cluster) (where as SCT spacepoint has got two clusters) - assocClusters[i] = new int[] { temp[2 * i] }; - } - } - event.getAssociationManager().add(new AAssociation(getFullName(), "SiCluster", assocClusters, event)); - event.getAssociationManager().add(new AAssociation(getFullName(), "PixelCluster", assocClusters, event)); - } - } - - - - protected void finalizeConstruction() - { - super.finalizeConstruction(); - super.calculateAssociationViaClusters(); - - } // finalizeConstruction() ---------------------------------------------- - - - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if(colorFunction == numColorTypes + 1) - { - colorByGroup(); - } - else if(colorFunction == numColorTypes + 2) - { - colorBy(layer); - } - return numColorTypes + 2; - - } // internalColor() ---------------------------------------------------- - - - protected void colorByGroup() - { - byte ungroupedColor; - if(parameterStore.get(PARAMETER_GROUP, "Ungrouped").getStatus()) - ungroupedColor = (byte) parameterStore.get(PARAMETER_GROUP, "Ungrouped").getI(); - else - ungroupedColor = (byte) parameterStore.get(PARAMETER_GROUP, "Unconnected"). - getI(); - int numColors = (byte) parameterStore.get("HitColors", "Number").getI(); - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for(int i = 0; i < numData; i++) - { - if(group[i] == 0) - color[i] = ungroupedColor; - else - color[i] = (byte) col[(group[i] - 1) % numColors]; - } - } - - - - /** - * define noise and good hits type = 0 means noise - * noise hits - hits associated neither with Track not STr - * good hits - hits associated either with Track or with STr plus - * group information - set by the AFilter (hit filter) - */ - protected void setType() - { - int[][] assocSTr = event.getAssociationManager().get(getFullName(), "STr"); - int[][] assocRTr = event.getAssociationManager().get(getFullName(), getReconstructedTracks()); - for(int i = 0; i < numData; i++) - { - if((assocSTr != null && assocSTr[i] != null) || - (assocRTr != null && assocRTr[i] != null) || group[i] > 0) - { - type[i] = 1; - } - else - { - type[i] = 0; - } - } - - } // setType() ---------------------------------------------------------- - - - - protected void applyCuts() - { - cutIndex(); - cutSubdetector(); - cut("CutsInDet", "Layer", " Layer", layer); - cutPhi(phi); - cutEta(rho, z); - cutSimulatedTracks(); - cutReconstructedTracks(); - cut("CutsInDet", "Group", " Group", group); - if(etaModule != null) - { - cut("CutsInDet", "EtaModule", " EtaModule", etaModule); - } - if(phiModule != null) - { - cut("CutsInDet", "PhiModule", " PhiModule", phiModule); - } - } - - private void cutSubdetector() - { - AParameter subPar = parameterStore.get("CutsInDet", "SCT"); - if(subPar.getI() != -1) - cutArray(sub, subPar.getI(), "Barrel/Endcap"); - } - - - public int getLayer(int id) - { - int layer; - if(id > -1) - layer = (id >> 21) & 0xF; - else - layer = (id >> 27) & 0x3; - int sub = getSub(id); - if(id > -1) - { - // strips - if(sub == ASiClusterData.BARREL) - layer += 3; - else - layer += 11; - } - else - { - // pixels - if(sub != ASiClusterData.BARREL) - layer += 7; - } - return layer; - } - - - public int getSub(int id) - { - if(id > -1) - return(id >> 25) & 0x3; - else - return(id >> 29) & 0x3; - } - - - private void calculateLayerSubdetector() - { - final double rhoPixelMax = 24.; - final double zBarrelPixelMax = 41.; - final double zBarrelStripsMax = 78.; - final double[] zEndcapPixel = - {51., 64., 90.}; - final double[] zEndcapStrips = - {88., 98., 116., 134., 156., 190., 233., - 263.}; - final double[] rhoBarrel = - {6.74, 11.5, 23., 34., 40., 48.}; - for(int i = 0; i < numData; i++) - { - double z = Math.abs(this.z[i]); - double r = rho[i]; - if(r < rhoPixelMax) - { - // .............................................. pixels - if(z < zBarrelPixelMax) - { - // ............................................ barrel - sub[i] = 1; - for(int l = 0; l < rhoBarrel.length; l++) - if(r < rhoBarrel[l]) - { - layer[i] = l; - break; - } - } - else - { - // ............................................ end cap - layer[i] = 10; - for(int l = 0; l < zEndcapPixel.length; l++) - { - if(z < zEndcapPixel[l]) - { - layer[i] = 7 + l; - break; - } - } - if(this.z[i] < 0) - sub[i] = 0; - else - sub[i] = 2; - } - } - else - { - // .............................................. strips - - if(z < zBarrelStripsMax) - { - // ............................................ BARREL - sub[i] = 1; - layer[i] = 6; - for(int l = 0; l < rhoBarrel.length; l++) - if(r < rhoBarrel[l]) - { - layer[i] = l; - break; - } - } - else - { - // ............................................ end cap - layer[i] = 19; - for(int l = 0; l < zEndcapStrips.length; l++) - { - if(z < zEndcapStrips[l]) - { - layer[i] = 11 + l; - break; - } - } - if(this.z[i] < 0) - sub[i] = 0; - else - sub[i] = 2; - } - } - } - } - - - // drawlist to be used as input to the filter - public int makeFilterDrawList(double etaRange) - { - calculateRhoPhi(); - - // overwrite the input array to improve speed - numDraw = 0; - for(int i = 0; i < numData; i++) - { - double eta = AParameterUtilities.eta(z[i], rho[i]); - this.eta[i] = eta; - if(eta > -etaRange && eta < etaRange) - { - listdl[numDraw++] = i; - } - } - - return numDraw; - } - - - public int[] getIntegerEta(int numBins, double etaRange, int[] integerEta) - { - // overwrite the input array to improve speed - double binWidth = 2 * etaRange / numBins; - double etaRangeOptimised = etaRange + binWidth; - for(int i = 0; i < numDraw; i++) - // implicit (int) conversion only does correct thing if positive - integerEta[i] = (int) ((eta[listdl[i]] + etaRangeOptimised) / - binWidth); - return integerEta; - } - - - public int[] getIntegerPhi(int numBins, double skew, int[] integerPhi) - { - calculateRhoPhi(); - // overwrite the input array to improve speed - double binWidth = 2 * Math.PI / numBins; - for(int i = 0; i < numDraw; i++) - { - // can only be positive - // add one to treat wraparound efficiently - double p = phi[listdl[i]] - skew * rho[listdl[i]]; - if(p < 0.) - p += 2 * Math.PI; - else if(p > 2 * Math.PI) - p -= 2 * Math.PI; - integerPhi[i] = (int) (p / binWidth) + 1; - } - return integerPhi; - } - - - public int[] getLayer(int[] layer) - { - for(int i = 0; i < numDraw; i++) - layer[i] = this.layer[listdl[i]]; - return layer; - } - - - public void setGroup(int[] group) - { - for(int i = 0; i < numData; i++) - this.group[i] = 0; - for(int i = 0; i < numDraw; i++) - this.group[listdl[i]] = group[i]; - } - - - protected ACoord getFRUser() - { - if(!parameterStore.get("SiCluster", "Stereo").getStatus())return super.getFRUser(); - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = rho[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FR"); - } - - - protected ACoord getFZUser() - { - if(!parameterStore.get("SiCluster", "Stereo").getStatus())return super.getFZUser(); - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = z[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FZ"); - } - -} // class AS3DData ========================================================= diff --git a/graphics/AtlantisJava/src/atlantis/data/ASMTrData.java b/graphics/AtlantisJava/src/atlantis/data/ASMTrData.java deleted file mode 100644 index dfd4eb8c63d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASMTrData.java +++ /dev/null @@ -1,626 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.utils.A3Vector; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Simulated particle in the muon system - */ - -public class ASMTrData extends AData -{ - private static final double START_RADIUS = 2.; - protected int[] code; - protected int[] particleType; - protected int[] originVertex; - protected float[] pT; - protected float[][] rho; - protected float[][] phi; - protected float[][] z; - protected float[][] x; - protected float[][] y; - AHelix[] innerTrack; - protected int[] type; - private int[] index; - - - public String getParameterGroup() - { - return "SMTr"; - } - - - public String getName() - { - return "SMTr"; - } - - - public String getNameScreenName() - { - return "SimMuonTrack"; - } - - - ASMTrData(AHashMap p, AEvent e) - { - super(p,e); - rho = new float[2][]; - phi = new float[2][]; - z = new float[2][]; - x = new float[2][]; - y = new float[2][]; - x[0] = new float[numData]; - y[0] = new float[numData]; - rho[0] = p.getFloatArray("rhoVertex"); - phi[0] = p.getFloatArray("phiVertex"); - z[0] = p.getFloatArray("zVertex"); - for(int i = 0; i < numData; ++i) - { - x[0][i] = (float) (rho[0][i] * Math.cos(phi[0][i])); - y[0][i] = (float) (rho[0][i] * Math.sin(phi[0][i])); - } - x[1] = (float[]) x[0].clone(); - y[1] = (float[]) y[0].clone(); - z[1] = (float[]) z[0].clone(); - phi[1] = (float[]) phi[0].clone(); - rho[1] = (float[]) rho[0].clone(); - pT = p.getFloatArray("pt"); - code = p.getIntArray("code"); - type = new int[numData]; - particleType = new int[numData]; - originVertex = p.getIntArray("simulatedVertex"); - for(int i = 0; i < numData; i++) - { - if(Math.abs(code[i]) > 10) - // code is being used to store particle code - particleType[i] = APDGTable.getParticleType(code[i]); - } - calculateReasonableEndpoints(p.getFloatArray("phi"), - p.getFloatArray("eta")); - double[] phiD = new double[numData]; - float[] phiF = p.getFloatArray("phi"); - for(int i = 0; i < numData; i++) - phiD[i] = phiF[i]; - index = indexBy(phiD); - } - - - protected void calculateRhoPhi() - { - calculateRhoPhi(x[0], y[0], rho[0], phi[0]); - calculateRhoPhi(x[1], y[1], rho[1], phi[1]); - } - - private void calculateReasonableEndpoints(float[] phiDir, float[] eta) - { - double rhoTo = 1500.; - double zTo = 2500.; - int maxPoints = 5; - double[] d = new double[maxPoints]; - for(int i = 0; i < numData; i++) - { - int numPoints = 0; - //initial point inside volume - if(rho[0][i] < rhoTo && Math.abs(z[0][i]) < zTo) - { - d[numPoints++] = 0.; - } - double lambda = AMath.lambda(eta[i]); - double x0 = x[0][i]; - double y0 = y[0][i]; - double z0 = z[0][i]; - x[1][i] = (float) x0; - y[1][i] = (float) y0; - z[1][i] = (float) z0; - double u = Math.cos(lambda) * Math.cos(phiDir[i]); - double v = Math.cos(lambda) * Math.sin(phiDir[i]); - double w = Math.sin(lambda); - //intersections with cylinder walls - if(w != 0.) - { - d[numPoints++] = (zTo - z0) / w; - d[numPoints++] = ( -zTo - z0) / w; - } - double a = u * u + v * v; - double c = x0 * x0 + y0 * y0 - rhoTo * rhoTo; - double b = 2 * (u * x0 + v * y0); - double squared = b * b - 4 * a * c; - if(squared >= 0.) - { - d[numPoints++] = ( -b + Math.sqrt(squared)) / (2 * a); - d[numPoints++] = ( -b - Math.sqrt(squared)) / (2 * a); - } - //bubble sort points by increasing path length - for(int j = 0; j < numPoints - 1; ++j) - for(int k = j + 1; k < numPoints; ++k) - if(d[k] < d[j]) - { - double temp = d[k]; - d[k] = d[j]; - d[j] = temp; - } - for(int j = 0; j < numPoints; ++j) - if(d[j] >= 0. && j < numPoints - 1) - { - x[0][i] = (float) (x0 + d[j] * u); - y[0][i] = (float) (y0 + d[j] * v); - z[0][i] = (float) (z0 + d[j] * w); - x[1][i] = (float) (x0 + d[j + 1] * u); - y[1][i] = (float) (y0 + d[j + 1] * v); - z[1][i] = (float) (z0 + d[j + 1] * w); - break; - } - } - } - - - protected void finalizeConstruction() - { - super.finalizeConstruction(); - // needs ZVTx - innerTrack = new AHelix[numData]; - for(int i = 0; i < numData; ++i) - { - double p = AMath.getPFromPttL(pT[i], - AMath.tanLambda(AParameterUtilities.eta(z[0][i], - rho[0][i]))); - // correct for average energy loss - double pTCorrected = pT[i] * (p + 3.7) / p; - innerTrack[i] = new AHelix((float) 0., - (float) (parameterStore.get("Event", "ZVtx").getD()), ( - float) (Math.toDegrees(phi[0][i])), - (float) AMath.tanLambda(AParameterUtilities.eta(z[0][i], - rho[0][i])), (float) pTCorrected); - // calculatePhiCorrection(i); - } - } - - - protected void applyCuts() - { - cutIndex(); - cut("CutsInDet", "STrType", " STr Type", particleType); - cut("CutsInDet", "STr", " STr id", id); - cut("CutsInDet", "Pt", " |Pt|", pT); - cut("CutsInDet", "SVx", " Vertex", originVertex); - cutPhi(phi[1]); - float[] phiStart = new float[numData]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - if(rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - phiStart[list] = (float) phi[iMin][list]; - } - cutPhi(phiStart); - cutEta(rho[1], z[1]); - } - - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if(colorFunction == 0) - colorByConstant(); - else if(colorFunction == 1) - colorByIndex(index); - else if(colorFunction == 2) - colorBy("ParticleColors", particleType); - return 2; - } - - - public String getHitInfo(int index) - { - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n Type = "); - msg.append(APDGTable.getName(code[index])); - if (innerTrack != null) - msg.append(innerTrack[index].toString()); - msg.append("\n pT (muon spectrometer) = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV"); - - return msg.toString(); - } - - - protected void cutStartRadius() - { - int num = 0; - for(int i = 0; i < numDraw; i++) - if(Math.min(Math.abs(z[0][listdl[i]] / rho[0][listdl[i]]), - Math.abs(z[1][listdl[i]] / rho[1][listdl[i]])) - < 12.3 / 9.2) - listdl[num++] = listdl[i]; - numDraw = num; - } - - - protected void cutStartRadius2() - { - int num = 0; - for(int i = 0; i < numDraw; i++) - if(Math.max(Math.abs(z[0][listdl[i]] / rho[0][listdl[i]]), - Math.abs(z[1][listdl[i]] / rho[1][listdl[i]])) - > 12.3 / 9.2) - listdl[num++] = listdl[i]; - numDraw = num; - } - - - protected ACoord getYXUser() - { - makeDrawList(); - cutStartRadius(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = x[j][list]; - hv[1][j][i] = y[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - - protected ACoord getRZUser() - { - makeDrawList(); - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - int numSplit = 0; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[0][list] - phiMid); - double sign0 = -1.; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign0 = +1.; - phiDiff = Math.abs(phi[1][list] - phiMid); - double sign1 = -1.; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign1 = +1.; - if(sign0 != sign1) numSplit++; - } - int numPoints = 100; - double[][][] hv = new double[2][numDraw + numSplit][]; - int[] index = new int[numDraw + numSplit]; - int num = 0; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[0][list] - phiMid); - double sign0 = -1.; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign0 = +1.; - phiDiff = Math.abs(phi[1][list] - phiMid); - double sign1 = -1.; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign1 = +1.; - if(sign0 == sign1) - { - hv[0][num] = AMath.splitLineIntoPieces(new double[] - {z[1][list], z[0][list]}, numPoints); - double[] xx = AMath.splitLineIntoPieces(new double[] - {x[1][list], x[0][list]}, numPoints); - double[] yy = AMath.splitLineIntoPieces(new double[] - {y[1][list], y[0][list]}, numPoints); - hv[1][num] = new double[xx.length]; - for(int j = 0; j < xx.length; ++j) - hv[1][num][j] = sign0 * - Math.sqrt(xx[j] * xx[j] + yy[j] * yy[j]); - index[num++] = list; - } - else - { - //just for now.... - double a = Math.cos(phiMid); - double b = Math.sin(phiMid); - double x0 = x[0][list]; - double y0 = y[0][list]; - double z0 = z[0][list]; - double dx = x[1][list] - x0; - double dy = y[1][list] - y0; - double dz = z[1][list] - z0; - double mag = Math.sqrt(dx * dx + dy * dy + dz * dz); - dx /= mag; - dy /= mag; - dz /= mag; - double d = -(a * x0 + b * y0) / (a * dx + b * dy); - double xMid = x0 + d * dx; - double yMid = y0 + d * dy; - double zMid = z0 + d * dz; - hv[0][num] = AMath.splitLineIntoPieces(new double[] - {zMid, z[0][list]}, numPoints); - double[] xx = AMath.splitLineIntoPieces(new double[] - {xMid, x[0][list]}, numPoints); - double[] yy = AMath.splitLineIntoPieces(new double[] - {yMid, y[0][list]}, numPoints); - hv[1][num] = new double[xx.length]; - for(int j = 0; j < xx.length; ++j) - hv[1][num][j] = sign0 * - Math.sqrt(xx[j] * xx[j] + yy[j] * yy[j]); - index[num++] = list; - hv[0][num] = AMath.splitLineIntoPieces(new double[] - {z[1][list], zMid}, numPoints); - xx = AMath.splitLineIntoPieces(new double[] - {x[1][list], xMid}, numPoints); - yy = AMath.splitLineIntoPieces(new double[] - {y[1][list], yMid}, numPoints); - hv[1][num] = new double[xx.length]; - for(int j = 0; j < xx.length; ++j) - hv[1][num][j] = sign1 * - Math.sqrt(xx[j] * xx[j] + yy[j] * yy[j]); - index[num++] = list; - } - } - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - } - - - protected ACoord getFRUser() - { - makeDrawList(); - cutStartRadius(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - if(rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - double rho1 = rho[iMin][list]; - double rho2 = rho[iMax][list]; - if(rho1 > START_RADIUS) - { - hv[0][0][i] = rho1; - hv[1][0][i] = Math.toDegrees(phi[iMin][list]); - } - else - { - double[] rpz = calculateRhoPhiZAtStart(list); - hv[0][0][i] = rpz[0]; - hv[1][0][i] = Math.toDegrees(rpz[1]); - } - hv[0][1][i] = rho2; - hv[1][1][i] = Math.toDegrees(phi[iMax][list]); - index[i] = list; - } - return new ACoord(hv, index, this, - ACoord.LINES).includePhiWrapAround("FR"); - } - - - protected ACoord getXZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0 = Math.cos(phi0); - double sinPhi0 = Math.sin(phi0); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = x[j][list] * cosPhi0 + y[j][list] * sinPhi0; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - - protected ACoord getYZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0 = Math.cos(phi0); - double sinPhi0 = Math.sin(phi0); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = y[j][list] * cosPhi0 - x[j][list] * sinPhi0; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - - protected ACoord getFZUser() - { - makeDrawList(); - cutStartRadius2(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - if(rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - double rho1 = rho[iMin][list]; - if(rho1 > START_RADIUS) - { - hv[0][0][i] = z[iMin][list]; - hv[1][0][i] = Math.toDegrees(phi[iMin][list]); - } - else - { - double[] rpz = calculateRhoPhiZAtStart(list); - hv[0][0][i] = rpz[2]; - hv[1][0][i] = Math.toDegrees(rpz[1]); - } - hv[0][1][i] = z[iMax][list]; - hv[1][1][i] = Math.toDegrees(phi[iMax][list]); - index[i] = list; - } - return new ACoord(hv, index, this, - ACoord.LINES).includePhiWrapAround("FZ"); - } - - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(projection instanceof AProjectionVP) - { - ag.draw(window.calculateDisplay(getVPUser(window, projection))); - } - else - super.draw(window, ag, projection); - } - - - // a track has two arms in the VPlot - - protected ACoord getVPUser(AWindow window, AProjection projection) - { - makeDrawList(); - - // make a copy of the points to draw: both arms * ??? - double[][][] hv = new double[2][2 * numDraw][]; - int[] index = new int[2 * numDraw]; - int num = 0; - - //loop over drawn objects? - for(int j = 0; j < numDraw; ++j) - { - // get list item from draw index list? - int list = listdl[j]; - // get the helix that should be drawn - ADHelix dhelix = new ADHelix(innerTrack[list]); - // get the helix start and end - double s1 = dhelix.getAStart(); - double s2 = 179.; - // hardwire projection.getMinRho() == 2. for now - s1 = dhelix.intersectWithRadialCylinder(((AProjection2D) projection). - getMinRho(), s1, s2); - double sEnd = dhelix.intersectWithCylinder(true, - AProjectionVP.getRhoVPlot(), true, - AProjectionVP.getZVPlot()); - s2 = Math.max(Math.min(s2, sEnd), s1); - // if the whole helix is to be drawn (which are unusual - // helices, shorten it a little to avoid wraparound problems - if(s1 == 0. && s2 == 180.) s2 = 179.; - if(parameterStore.get("VP", "ShortV").getStatus() && - !parameterStore.get("Data", "S3D").getStatus()) - s1 = s2 - parameterStore.get("VP", "ShortV").getD() * (s2 - s1); - if(s2 > s1) - { - int signMin = -1; - int signMax = 1; - for(int sign = signMin; sign <= signMax; sign += 2) - { - // ugly must change structure at some point - AProjectionVP.sign = sign; - ACoord pointsOnHelix = dhelix.drawHelix(window, - (AProjection2D) projection, s1, s2); - hv[0][num] = pointsOnHelix.hv[0][0]; - hv[1][num] = pointsOnHelix.hv[1][0]; - index[num] = list; - num++; - } - } - } - return window.calculateUser(new ACoord(hv, index, this, - ACoord.SMOOTH_POLYLINES)). - includePhiWrapAround(projection.getName()); - } - - - private double[] calculateRhoPhiZAtStart(int index) - { - double[] rpz = new double[3]; - double rho1 = rho[0][index]; - double phi1 = phi[0][index]; - double z1 = z[0][index]; - double rho2 = rho[1][index]; - double phi2 = phi[1][index]; - double z2 = z[1][index]; - double x1 = rho1 * Math.cos(phi1); - double y1 = rho1 * Math.sin(phi1); - double x2 = rho2 * Math.cos(phi2); - double y2 = rho2 * Math.sin(phi2); - double fract = (START_RADIUS - rho1) / (rho2 - rho1); - double x = x1 + fract * (x2 - x1); - double y = y1 + fract * (y2 - y1); - double z = z1 + fract * (z2 - z1); - double phi = Math.atan2(y, x); - if(phi < 0.) phi += 2 * Math.PI; - rpz[0] = START_RADIUS; - rpz[1] = phi; - rpz[2] = z; - return rpz; - } - - - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumP = 0.; - double sumPt = 0.; - for(int i = 0; i < numDraw; ++i) - { - sumPt += Math.abs(pT[listdl[i]]); - double invLambda = (rho[1][listdl[i]] - rho[0][listdl[i]]) / - (z[1][listdl[i]] - z[0][listdl[i]]); - sumP += Math.abs(pT[listdl[i]] / Math.cos(Math.atan(1. / invLambda))); - } - - String msg = numDraw + " " + getNameScreenName(); - msg += " sum(PT) = " + String.format("%.1f",sumPt) + " sum(P) = " + String.format("%.1f",sumP); - - return msg; - } - - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for(int i = 0; i < num; ++i) - { - int k = list[i]; - A3Vector start = A3Vector.fromRhoPhiZ(rho[0][k], phi[0][k], - z[0][k]); - A3Vector stop = A3Vector.fromRhoPhiZ(rho[1][k], phi[1][k], - z[1][k]); - A3Vector v = (stop.subtract(start)).normalize(); - double p = pT[k] / Math.sqrt(1. - v.z * v.z); - sum.add(new A4Vector(v.scale(p), 0.)); - } - return sum; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ASNPData.java b/graphics/AtlantisJava/src/atlantis/data/ASNPData.java deleted file mode 100644 index 4c660247995..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASNPData.java +++ /dev/null @@ -1,659 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionXZ; -import atlantis.utils.A3Vector; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -/** - * Simulated Neutral Particle - */ - -public class ASNPData extends AData -{ - private static ALogger logger = ALogger.getLogger(ASNPData.class); - - private static final double START_RADIUS = 2.; - - protected int[] code; - protected int[] particleType; - protected int[] originVertex; - protected float[] pT; - protected float[][] rho; - protected float[][] phi; - protected float[][] z; - protected float[][] x; - protected float[][] y; - protected int[] type; - private float[] temp; - private int[] index; - - public float[] getPt() - { - return pT; - } - - public String getParameterGroup() - { - return "SNP"; - } - - public String getName() - { - return "SNP"; - } - - public String getNameScreenName() - { - return "SimNeutralTrack"; - } - - ASNPData(AHashMap p, AEvent e) - { - super(p,e); - rho = new float[2][]; - phi = new float[2][]; - z = new float[2][]; - x = new float[2][numData]; - y = new float[2][numData]; - rho[0] = p.getFloatArray("rhoVertex"); - phi[0] = p.getFloatArray("phiVertex"); - z[0] = p.getFloatArray("zVertex"); - - pT = p.getFloatArray("pt"); - code = p.getIntArray("code"); - type = new int[numData]; - particleType = new int[numData]; - originVertex = p.getIntArray("simulatedVertex"); - temp = new float[numData]; - for (int i = 0; i < numData; i++) - { - if (Math.abs(code[i]) > 10) - { - // code is being used to store particle code - particleType[i] = APDGTable.getParticleType(code[i]); - } - } - calculateReasonableEndpoints(p.getFloatArray("phi"), p.getFloatArray("eta")); - - double[] phiD = new double[numData]; - float[] phiF = p.getFloatArray("phi"); - - for (int i = 0; i < numData; i++) - phiD[i] = phiF[i]; - index = indexBy(phiD); - calculateXY(rho[0], phi[0], x[0], y[0]); - calculateXY(rho[1], phi[1], x[1], y[1]); - } - - protected void calculateRhoPhi() - { - calculateRhoPhi(x[0], y[0], rho[0], phi[0]); - calculateRhoPhi(x[1], y[1], rho[1], phi[1]); - } - - public static AHashMap createSNP(AHashMap p) - { - float[] pt = p.getFloatArray("pt"); - float[] phi = p.getFloatArray("phi"); - float[] eta = p.getFloatArray("eta"); - float[] rhoVertex = p.getFloatArray("rhoVertex"); - float[] phiVertex = p.getFloatArray("phiVertex"); - float[] zVertex = p.getFloatArray("zVertex"); - int[] id = p.getIntArray("id"); - - int[] code = p.getIntArray("code"); - - int numNeutral = 0; - - for (int i = 0; i < code.length; ++i) - { - int charge = code[i]; - - try - { - if (Math.abs(code[i]) >= 10) - - // code is being used to store particle code - charge = APDGTable.getCharge(code[i]); - if (charge == 0) - numNeutral++; - } - catch (APDGTable.ParticleNotFoundError pnf){ - logger.debug(pnf.getMessage()); - } - } - - int[] simulatedVertex = ASVxData.assignVertexNumbers(phiVertex, rhoVertex, zVertex); - - int[] idN = new int[numNeutral]; - float[] rhoVertexN = new float[numNeutral]; - float[] phiVertexN = new float[numNeutral]; - float[] zVertexN = new float[numNeutral]; - float[] ptN = new float[numNeutral]; - float[] phiN = new float[numNeutral]; - float[] etaN = new float[numNeutral]; - int[] codeN = new int[numNeutral]; - int[] simulatedVertexN = new int[numNeutral]; - - numNeutral = 0; - for (int i = 0; i < code.length; ++i) - { - double charge = code[i]; - - try - { - if (Math.abs(code[i]) >= 10) - { - // code is being used to store particle code - charge = APDGTable.getCharge(code[i]); - } - if (charge == 0) - { - idN[numNeutral] = id[i]; - rhoVertexN[numNeutral] = (float) Math.sqrt(rhoVertex[i]*rhoVertex[i]-zVertex[i]*zVertex[i]); - phiVertexN[numNeutral] = phiVertex[i]; - zVertexN[numNeutral] = zVertex[i]; - ptN[numNeutral] = pt[i]; - phiN[numNeutral] = phi[i]; - etaN[numNeutral] = eta[i]; - codeN[numNeutral] = code[i]; - simulatedVertexN[numNeutral] = simulatedVertex[i]; - numNeutral++; - } - } - catch (APDGTable.ParticleNotFoundError pnf){ - logger.debug(pnf.getMessage()); - } - } - - AHashMap newP = new AHashMap(10); - - newP.put("numData", new Integer(numNeutral)); - newP.put("id", idN); - newP.put("rhoVertex", rhoVertexN); - newP.put("phiVertex", phiVertexN); - newP.put("zVertex", zVertexN); - newP.put("pt", ptN); - newP.put("phi", phiN); - newP.put("eta", etaN); - newP.put("code", codeN); - newP.put("simulatedVertex", simulatedVertexN); - return newP; - } - - private void calculateReasonableEndpoints(float[] dirPhi, float[] dirEta) - { - double rhoTo = parameterStore.get("RTr", "RadiusTr").getD(); - double zTo = parameterStore.get("RTr", "ZTr").getD(); - - rho[1] = (float[]) rho[0].clone(); - phi[1] = (float[]) phi[0].clone(); - z[1] = (float[]) z[0].clone(); - for (int i = 0; i < numData; i++) - { - if (particleType[i] == 5) - { - // photon -> ecal entrance - rhoTo = 150.; - zTo = 370.; - } - else - { - // neutral hadron -> hcal entrance - rhoTo = 228.; - zTo = 426.2; - } - if (rho[0][i] > rhoTo || Math.abs(z[0][i]) > zTo) - continue; - double rho2 = rhoTo; - double tanLambda = AMath.tanLambda(dirEta[i]); - double zz = z[0][i] + (rho2 - rho[0][i]) * tanLambda; - - if (zz > zTo) - rho2 = (zTo - z[0][i]) / tanLambda + rho[0][i]; - if (zz < -zTo) - rho2 = (-zTo - z[0][i]) / tanLambda + rho[0][i]; - double x = rho[0][i] * Math.cos(phi[0][i]); - double y = rho[0][i] * Math.sin(phi[0][i]); - // y=mx+c, x*x+y*y=rho2*rho2 - double m = Math.tan(dirPhi[i]); - double c = y - m * x; - // ax^2+bx+cc=0 - double a = m * m + 1.; - double b = 2. * m * c; - double cc = c * c - rho2 * rho2; - double d = Math.sqrt(b * b - 4 * a * cc); - double x1 = (-b + d) / (a * 2); - double x2 = (-b - d) / (a * 2); - double y1 = m * x1 + c; - double y2 = m * x2 + c; - double xx = x1; - double yy = y1; - - if ((x2 - x) * Math.cos(dirPhi[i]) + (y2 - y) * Math.sin(dirPhi[i]) > 0.) - { - xx = x2; - yy = y2; - } - zz = z[0][i] + (rho2 - rho[0][i]) * tanLambda; - rho[1][i] = (float) Math.sqrt(xx * xx + yy * yy); - phi[1][i] = (float) Math.atan2(yy, xx); - if (phi[1][i] < 0.) - phi[1][i] += 2 * Math.PI; - z[1][i] = (float) zz; - } - } - - protected void applyCuts() - { - cutIndex(); - cut("CutsInDet", "STrType", " STr Type", particleType); - cut("CutsInDet", "STr", " STr id", id); - cut("CutsInDet", "Pt", " |Pt|", pT); - cut("CutsInDet", "SVx", " Vertex", originVertex); - cut("CutsInDet", "d0", " |d0|", getD0()); - cut("CutsInDet", "d0Loose", " |d0Loose|", getD0()); - cut("CutsInDet", "z0-zVtx", " |z0-zVtx|", getZ0Primary()); - cut("CutsInDet", "z0", " |z0|", getZ0()); - cutPhi(phi[1]); - float[] phiStart = new float[numData]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - - if (rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - - if (rho[iMin][list] > START_RADIUS) - phiStart[list] = phi[iMin][list]; - else - { - double[] rpz = calculateRhoPhiZAtStart(list); - - phiStart[list] = (float) rpz[1]; - } - } - cutPhi(phiStart); - cutEta(rho[1], z[1]); - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if (colorFunction == 0) - colorByConstant(); - else if (colorFunction == 1) - colorByIndex(index); - else if (colorFunction == 2) - colorBy(getPt()); - else if (colorFunction == 3) - colorBy("ParticleColors", particleType); - else if (colorFunction == 4) - colorBy(originVertex); - return 3; - } - - public String getHitInfo(int index) - { - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n Type = "); - msg.append(APDGTable.getName(code[index])); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV"); - - return msg.toString(); - } - - protected void cutStartRadius() - { - int num = 0; - - for (int i = 0; i < numDraw; i++) - if (Math.max(rho[0][listdl[i]], rho[1][listdl[i]]) > START_RADIUS) - listdl[num++] = listdl[i]; - numDraw = num; - } - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = x[j][list]; - hv[1][j][i] = y[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[1][list] - phiMid); - double sign; - - // this is not quite correct need to split some tracks - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign = +1.; - else - sign = -1.; - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = sign * rho[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getFRUser() - { - makeDrawList(); - cutStartRadius(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - - if (rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - double rho1 = rho[iMin][list]; - double rho2 = rho[iMax][list]; - - if (rho1 > START_RADIUS) - { - hv[0][0][i] = rho1; - hv[1][0][i] = Math.toDegrees(phi[iMin][list]); - } - else - { - double[] rpz = calculateRhoPhiZAtStart(list); - - hv[0][0][i] = rpz[0]; - hv[1][0][i] = Math.toDegrees(rpz[1]); - } - hv[0][1][i] = rho2; - hv[1][1][i] = Math.toDegrees(phi[iMax][list]); - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FR"); - } - - protected ACoord getXZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0 = Math.cos(phi0); - double sinPhi0 = Math.sin(phi0); - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = x[j][list] * cosPhi0 + y[j][list] * sinPhi0; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getYZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - double cosPhi0 = Math.cos(phi0); - double sinPhi0 = Math.sin(phi0); - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = y[j][list] * cosPhi0 - x[j][list] * sinPhi0; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - protected ACoord getFZUser() - { - makeDrawList(); - cutStartRadius(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int iMax = 0; - - if (rho[1][list] > rho[0][list]) - iMax = 1; - int iMin = 1 - iMax; - double rho1 = rho[iMin][list]; - - if (rho1 > START_RADIUS) - { - hv[0][0][i] = z[iMin][list]; - hv[1][0][i] = Math.toDegrees(phi[iMin][list]); - } - else - { - double[] rpz = calculateRhoPhiZAtStart(list); - - hv[0][0][i] = rpz[2]; - hv[1][0][i] = Math.toDegrees(rpz[1]); - } - hv[0][1][i] = z[iMax][list]; - hv[1][1][i] = Math.toDegrees(phi[iMax][list]); - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FZ"); - } - - protected ACoord getVPUser() - { - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - h[i] = AParameterUtilities.eta(z[1][list], rho[1][list]); - v[i] = Math.toDegrees(phi[1][list]); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("VP"); - } - - private double[] calculateRhoPhiZAtStart(int index) - { - double[] rpz = new double[3]; - double rho1 = rho[0][index]; - double phi1 = phi[0][index]; - double z1 = z[0][index]; - double rho2 = rho[1][index]; - double phi2 = phi[1][index]; - double z2 = z[1][index]; - double x1 = rho1 * Math.cos(phi1); - double y1 = rho1 * Math.sin(phi1); - double x2 = rho2 * Math.cos(phi2); - double y2 = rho2 * Math.sin(phi2); - double fract = (START_RADIUS - rho1) / (rho2 - rho1); - double x = x1 + fract * (x2 - x1); - double y = y1 + fract * (y2 - y1); - double z = z1 + fract * (z2 - z1); - double phi = Math.atan2(y, x); - - if (phi < 0.) - phi += 2 * Math.PI; - rpz[0] = START_RADIUS; - rpz[1] = phi; - rpz[2] = z; - return rpz; - } - - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumP = 0.; - double sumPt = 0.; - - for (int i = 0; i < numDraw; ++i) - { - sumPt += Math.abs(pT[listdl[i]]); - double invLambda = (rho[1][listdl[i]] - rho[0][listdl[i]]) / (z[1][listdl[i]] - z[0][listdl[i]]); - sumP += Math.abs(pT[listdl[i]] / Math.cos(Math.atan(1. / invLambda))); - } - - String msg = numDraw + " " + getNameScreenName(); - msg += " sum(PT) = " + String.format("%.1f",sumPt) + " sum(P) = " + String.format("%.1f",sumP); - - return msg; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A3Vector start = A3Vector.fromRhoPhiZ(rho[0][k], phi[0][k], z[0][k]); - A3Vector stop = A3Vector.fromRhoPhiZ(rho[1][k], phi[1][k], z[1][k]); - A3Vector v = (stop.subtract(start)).normalize(); - double p = pT[k] / Math.sqrt(1. - v.z * v.z); - sum.add(new A4Vector(v.scale(p), 0.)); - } - - return sum; - } - - private float[] getZ0() - { - for (int i = 0; i < numDraw; ++i) - { - int list = listdl[i]; - double[] poca = getPoca(list); - temp[list] = (float) poca[2]; - } - return temp; - } - - private float[] getZ0Primary() - { - double[] primary = event.getPrimaryVertex(); - double c = primary[2]; - for (int i = 0; i < numDraw; ++i) - { - int list = listdl[i]; - double[] poca = getPoca(list); - temp[list] = (float) (poca[2] - c); - } - return temp; - } - - private float[] getD0() - { - double[] primary = event.getPrimaryVertex(); - double a = primary[0]; - double b = primary[1]; - for (int i = 0; i < numDraw; ++i) - { - int list = listdl[i]; - double[] poca = getPoca(list); - temp[list] = (float) Math.hypot(a-poca[0], b-poca[1]); - } - return temp; - } - - private double[] getPoca(int i) - { - double[] primary = event.getPrimaryVertex(); - double a = primary[0]; - double b = primary[1]; - double xMin; - double yMin; - double zMin; - double dx = x[1][i] - x[0][i]; - if (dx == 0.) - { - xMin = x[0][i]; - yMin = b; - } - else - { - double m = (y[1][i] - y[0][i]) / dx; - double c = y[0][i] - m * x[0][i]; - xMin = (a + (b - c) * m) / (m * m + 1); - yMin = m * xMin + c; - } - double dz = z[1][i] - z[0][i]; - if (dz == 0.) - { - zMin = z[0][i]; - } - else - { - double mx = (x[1][i] - x[0][i]) / dz; - if (mx != 0.) - zMin = z[0][i] + (xMin - x[0][i]) / mx; - else - { - double my = (y[1][i] - y[0][i]) / dz; - if (my != 0.) - zMin = z[0][i] + (yMin - y[0][i]) / my; - else - zMin = z[0][i]; - } - } - return new double[] { xMin, yMin, zMin }; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ASTrData.java b/graphics/AtlantisJava/src/atlantis/data/ASTrData.java deleted file mode 100644 index aa8f6caa5d7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASTrData.java +++ /dev/null @@ -1,254 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.utils.AHashMap; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; - -public class ASTrData extends ATrackData -{ - private static ALogger logger = ALogger.getLogger(ASTrData.class); - - public static final int UNDERLYING_EVENT = 0; - public static final int NORMAL = 1; - - protected int[] code; - protected int[] type; - protected int[] particleType; - protected int[] originVertex; - - public String getParameterGroup() - { - return "STr"; - } - - public String getName() - { - return "STr"; - } - - public String getNameScreenName() - { - return "SimChargedTrack"; - } - - ASTrData(AHashMap p, AEvent e) throws AAtlantisException - { - super(p,e); - code = p.getIntArray("code"); - originVertex = p.getIntArray("originVertex"); - type = p.getIntArray("type"); - particleType = new int[numData]; - for(int i = 0; i < numData; i++) - particleType[i] = APDGTable.getParticleType(code[i]); - } - - - public static AHashMap createSTr(AHashMap p) - { - float[] pt = p.getFloatArray("pt"); - float[] phi = p.getFloatArray("phi"); - float[] eta = p.getFloatArray("eta"); - float[] rhoVertex = p.getFloatArray("rhoVertex"); - float[] phiVertex = p.getFloatArray("phiVertex"); - float[] zVertex = p.getFloatArray("zVertex"); - int[] id = p.getIntArray("id"); - int[] code = p.getIntArray("code"); - //rhoEndVertex not available in older xml files - check that it exists first. - float[] rhoEndVertex = (p.get("rhoEndVertex") != null) ? p.getFloatArray("rhoEndVertex") : null; - //float[] phiEndVertex = (p.get("phiEndVertex") != null) ? p.getFloatArray("phiEndVertex") : null; - float[] zEndVertex = (p.get("zEndVertex") != null) ? p.getFloatArray("zEndVertex") : null; - - int numCharged = 0; - for(int i = 0; i < code.length; ++i) - { - int charge = code[i]; - - try - { - if(Math.abs(code[i]) >= 10 || Math.abs(code[i]) == 1) - // code is being used to store particle code - charge = APDGTable.getCharge(code[i]); - if(charge == 1 || charge == -1) - numCharged++; - } - catch(APDGTable.ParticleNotFoundError pnf){ - logger.debug(pnf.getMessage()); - } - } - - //Assign the vertices to the particle tracks - int[] simulatedVertex = ASVxData.assignVertexNumbers(phiVertex, rhoVertex, zVertex); - - //Now build subsets of the charged tracks only - int[] idC = new int[numCharged]; - int[] typeC = new int[numCharged]; - float[] rhoVertexC = new float[numCharged]; - float[] rhoEndVertexC = new float[numCharged]; - float[] phiVertexC = new float[numCharged]; - float[] zVertexC = new float[numCharged]; - float[] ptC = new float[numCharged]; - float[] phiC = new float[numCharged]; - float[] etaC = new float[numCharged]; - int[] chargeC = new int[numCharged]; - int[] codeC = new int[numCharged]; - int[] simulatedVertexC = new int[numCharged]; - - numCharged = 0; - for(int i = 0; i < code.length; ++i) - { - int charge = code[i]; - try - { - if(Math.abs(code[i]) >= 10 || Math.abs(code[i]) == 1) - // code is being used to store particle code - charge = APDGTable.getCharge(code[i]); - if(charge == 1 || charge == -1) - { - if(id[i] > 0) - { - idC[numCharged] = id[i]; - typeC[numCharged] = NORMAL; - } - else - { - // negative id is used to flag tracks belong to a second - // track bank which correspond to the underlyingEvent - // set id to zero as it is not a kine number - idC[numCharged] = 0; - typeC[numCharged] = UNDERLYING_EVENT; - } - //copy all the information - rhoVertexC[numCharged] = (float)(Math.sqrt(rhoVertex[i]*rhoVertex[i]-zVertex[i]*zVertex[i])); - //if there is no end vertex, fill with 0.0 as in XML file - rhoEndVertexC[numCharged] = (rhoEndVertex != null) ? (float)(Math.sqrt(rhoEndVertex[i]*rhoEndVertex[i]-zEndVertex[i]*zEndVertex[i])) : 0 ; - phiVertexC[numCharged] = phiVertex[i]; - zVertexC[numCharged] = zVertex[i]; - ptC[numCharged] = pt[i]; - //if (pt[i]>5) System.out.println(zVertex[i]); - phiC[numCharged] = phi[i]; - etaC[numCharged] = eta[i]; - codeC[numCharged] = code[i]; - chargeC[numCharged] = charge; - simulatedVertexC[numCharged] = simulatedVertex[i]; - numCharged++; - } - } - catch(APDGTable.ParticleNotFoundError pnf) - { - logger.debug(pnf.getMessage()); - } - } - - //Build a new hash map with the information for the - //charged tracks only - AHashMap newP = new AHashMap(12); - newP.put("numData", new Integer(numCharged)); - newP.put("id", idC); - newP.put("type", typeC); - newP.put("rhoVertex", rhoVertexC); - newP.put("rhoEndVertex", rhoEndVertexC); - newP.put("phiVertex", phiVertexC); - newP.put("zVertex", zVertexC); - newP.put("pt", ptC); - newP.put("phi", phiC); - newP.put("eta", etaC); - newP.put("code", codeC); - newP.put("charge", chargeC); - newP.put("originVertex", simulatedVertexC); - //return the new hasp map - return newP; - } - - - /** - * Get the vertex for which sum|Pt| is maximum - * @return the index of that vertex - */ - public int getMaxSumPtVertex() - { - /*** - * Triple loop can be avoided, e.g using hashmap, - * to tired to fix all this - S.B. - */ - - //get the highest vertex number - int maxVertex = 0; - - //by looping over all tracks and looking at the vertex number - for(int i = 0; i < numData; i++) - if(type[i] == NORMAL) - if(originVertex[i] > maxVertex) - maxVertex = originVertex[i]; - - //Now make an array to hold the sumPT for all vertices - double[] sumPt = new double[maxVertex + 1]; - - //Now loop again to add up all the pT - for(int i = 0; i < numData; i++) - if(type[i] == NORMAL && Math.abs(h[i].d0()) < 2.0) - sumPt[originVertex[i]] += Math.abs(h[i].pT()); - - //Yippee - lets loop once more to find the highest pT one - int VtxIndex = 0; - for(int i = 0; i < sumPt.length; i++) - if(sumPt[i] > sumPt[VtxIndex]) - VtxIndex = i; - - return VtxIndex; - } - - - - protected void applyCuts() - { - super.applyCuts(); - - // STr are always drawn as helices, check for tracks with rhoVertex - // beyond the diameter of InDet and don't draw those - super.cutRhoVertexAfterInDetRadius(); - - cut("CutsInDet", "STr", " STr id", id); - cut("CutsInDet", "STrCode", " STr code", code); - cut("CutsInDet", "STrType", " STr Type", particleType); - cut("CutsInDet", "SVx", " Vertex", originVertex); - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - switch (colorFunction) - { - case 0: - colorByConstant(); - break; - case 1: - colorByIndex(index); - break; - case 2: - colorBy(getPt()); - break; - case 3: - colorBy("ParticleColors", particleType); - break; - case 4: - colorBy(originVertex); - break; - } - - return 4; - } - - public String getHitInfo(int index) - { - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (barcode/id: " + id[index] + " index: " + index + ")"); - msg.append("\n Type = "+APDGTable.getName(code[index])); - msg.append(" (type code "); msg.append(code[index]); - msg.append(")"); msg.append(h[index].toString()); - - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ASVxData.java b/graphics/AtlantisJava/src/atlantis/data/ASVxData.java deleted file mode 100644 index 87481919d2a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASVxData.java +++ /dev/null @@ -1,167 +0,0 @@ -package atlantis.data; - - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.*; -import java.util.*; - - -/** - * Simulated vertices - */ -public class ASVxData extends A3DPointData { - - // protected final String PARAMETER_GROUP = getParameterGroup(); - - - public String getParameterGroup() - { - return "SVx"; - } - - - public String getName() - { - return "SVx"; - } - - - public String getNameScreenName() - { - return "SimVertex"; - - } - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.RHO+" = "+String.format("%.3f",rho[index])+"\n "+ - "z = "+String.format("%.3f",z[index])+" cm\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - return getNameScreenName() + " (id: " + id[index] + " index: " + index + ")" + - "\n x = " + String.format("%.5f",x[index]) + " cm" + - "\n y = " + String.format("%.5f",y[index]) + " cm" + - "\n z = " + String.format("%.5f",z[index]) + " cm" + - "\n " + AMath.RHO + " = " + String.format("%.5f",rho[index]) + " cm" + - "\n " + AMath.PHI + " = " + - String.format("%.5f",Math.toDegrees(phi[index])) + AMath.DEGREES + - " (" + String.format("%.5f",phi[index]) + " rad)"; - - } // getHitInfo() -------------------------------------------------------- - - - - ASVxData(AHashMap p, AEvent e) { - super(p,e); - } - - // SVx do not come correctly in input xml file - // must create them from STr data in xml file - public static AHashMap createSVx(AHashMap p) { - float[] rhoVertex=p.getFloatArray("rhoVertex"); - float[] phiVertex=p.getFloatArray("phiVertex"); - float[] zVertex=p.getFloatArray("zVertex"); - int[] sv=ASVxData.assignVertexNumbers(phiVertex, rhoVertex, zVertex); - int numVertex=0; - - for(int i=0; i<sv.length; i++) - if(sv[i]>=numVertex) numVertex=sv[i]+1; - - float[] rho=new float[numVertex]; - float[] phi=new float[numVertex]; - float[] z=new float[numVertex]; - - for(int i=0; i<sv.length; i++) { - rho[sv[i]]=(float)(Math.sqrt(rhoVertex[i]*rhoVertex[i]-zVertex[i]*zVertex[i])); - phi[sv[i]]=phiVertex[i]; - z[sv[i]]=zVertex[i]; - } - - AHashMap newP=new AHashMap(4); - - newP.put("numData", new Integer(numVertex)); - newP.put("rho", rho); - newP.put("phi", phi); - newP.put("z", z); - return newP; - } - - public static int[] assignVertexNumbers(float[] phi, float[] rho, float[] z) { - int[] sv=new int[phi.length]; - Vertex[] key=new Vertex[phi.length]; - - HashMap vertices=new HashMap(); - -// this is ugly, related to the fact that id[i]=i+1 by default; - int num=1; - for(int i=0; i<sv.length; i++) { - key[i]=new Vertex(rho[i], phi[i], z[i]); - Object value=vertices.get(key[i]); - if(value==null) { - sv[i]=num; - vertices.put(key[i], new Integer(num++)); - } else { - sv[i]=((Integer)value).intValue(); - } - } - return sv; - } - - protected int internalColor() { - colorByConstant(); - return 1; - } - - protected void applyCuts() { - cutIndex(); - cutPhi(phi); - cutEta(rho, z); - cut("CutsInDet", "SVx", " Vertex", id); - } - - - public double[] getVertex(int index) { - - double[] vertex=new double[3]; - - if(index>-1&&index<numData) { - vertex[0]=x[index]; - vertex[1]=y[index]; - vertex[2]=z[index]; - } - return vertex; - } - -} - - -class Vertex { - float x; - float y; - float z; - int hashcode; - - Vertex(float x, float y, float z) { - this.x=x; - this.y=y; - this.z=z; - hashcode=Float.floatToIntBits(z); - } - - @Override - public int hashCode() { - return hashcode; - } - - @Override - public boolean equals(Object a) { - if(!(a instanceof Vertex)) return false; - Vertex b=(Vertex)a; - return x==b.x&&y==b.y&&z==b.z; - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/data/ASegmentData.java b/graphics/AtlantisJava/src/atlantis/data/ASegmentData.java deleted file mode 100755 index d999effdb0b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASegmentData.java +++ /dev/null @@ -1,164 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionXZ; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * Generic track segment class. - * - * @author Eric Jansen - */ -public abstract class ASegmentData extends AData { - - protected float[] x; - protected float[] y; - protected float[] z; - protected float[] theta; - protected float[] phi; - protected int[] hits; - protected int[] numHits; - - ASegmentData(AHashMap p, AEvent e) { - super(p,e); - - x = p.getFloatArray("x"); - y = p.getFloatArray("y"); - z = p.getFloatArray("z"); - phi = p.getFloatArray("phi"); - theta = p.getFloatArray("theta"); - numHits = p.getIntArray("numHits"); - - hits = p.getIntArray("hits"); - } - - protected int internalColor() { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - switch(colorFunction) { - case 0: - colorByConstant(); - break; - case 1: - colorByIndex(); - break; - } - - return 1; - } - - - protected void applyCuts() - { - cutIndex(); - - } - - - public String getHitInfo(int index) { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - - return getName() + " (index: " + index + ")\n" - + " storegate key = " + storeGateKey + "\n" - + " " + AMath.PHI + " = " + String.format("%.3f",Math.toDegrees(phi[index])) - + " (" + String.format("%.3f",phi[index]) + " rad)" + "\n" - + " tL = " + String.format("%.3f",Math.toDegrees(1./Math.tan(theta[index]))) + "\n" - + " x = " + String.format("%.3f",x[index]) + " cm\n" - + " y = " + String.format("%.3f",y[index]) + " cm\n" - + " z = " + String.format("%.3f",z[index]) + " cm\n" - + " hits = " + numHits[index] + "\n"; - } - - protected ACoord getYXUser() { - makeDrawList(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - double length = parameterStore.get(PARAMETER_GROUP, "SegmentLength").getD(); - - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - - double dx = length * Math.sin(theta[j]) * Math.cos(phi[j]); - double dy = length * Math.sin(theta[j]) * Math.sin(phi[j]); - - hv[0][i] = new double [] {x[j]-dx, x[j]-dx/2., x[j], x[j]+dx/2., x[j]+dx}; - hv[1][i] = new double [] {y[j]-dy, y[j]-dy/2., y[j], y[j]+dy/2., y[j]+dy}; - - index[i] = j; - } - - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - } - - protected ACoord getFRUser() { - return getYXUser().convertYXToFR().includePhiWrapAround("FR"); - } - - protected ACoord getRZUser() { - makeDrawList(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - double length = parameterStore.get(PARAMETER_GROUP, "SegmentLength").getD(); - - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - - double dx = length * Math.sin(theta[j]) * Math.cos(phi[j]); - double dy = length * Math.sin(theta[j]) * Math.sin(phi[j]); - double dz = length * Math.cos(theta[j]); - - int sign = AParameterUtilities.getRhoSign(x[j], y[j]); - - hv[0][i] = new double [] {z[j]-dz, z[j]+dz}; - hv[1][i] = new double [] { - sign * Math.hypot(x[i]-dx, y[i]-dy), - sign * Math.hypot(x[i]+dx, y[i]+dy) - }; - - index[i] = j; - } - - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - protected ACoord getXZUser() { - makeDrawList(); - - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - double length = parameterStore.get(PARAMETER_GROUP, "SegmentLength").getD(); - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - - double dx = length * Math.sin(theta[j]) * Math.cos(phi[j]); - double dy = length * Math.sin(theta[j]) * Math.sin(phi[j]); - double dz = length * Math.cos(theta[j]); - - double s = x[j] * Math.cos(phi0) + y[j] * Math.sin(phi0); - double ds = dx * Math.cos(phi0) + dy * Math.sin(phi0); - - if (z[j] < 0) { - hv[0][i] = new double [] {z[j]+dz, z[j]-dz}; - hv[1][i] = new double [] {s-ds, s+ds}; - } else { - hv[0][i] = new double [] {z[j]-dz, z[j]+dz}; - hv[1][i] = new double [] {s-ds, s+ds}; - } - - index[i] = j; - } - - return new ACoord(hv, index, this, ACoord.POLYLINES); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ASiClusterData.java b/graphics/AtlantisJava/src/atlantis/data/ASiClusterData.java deleted file mode 100644 index 83cc0f98026..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASiClusterData.java +++ /dev/null @@ -1,385 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - -/** - * SiCluster - Silicon clusters, reads in STC datatype from event file - */ -public class ASiClusterData extends AHitData -{ - // read in from event file - private float[][] x; - private float[][] y; - private float[][] z; - private float[] width; - private int[] etaModule; - private int[] phiModule; - private int[] side; - - // calculated - private float[][] rho; - private float[][] phi; - private int[] layer; - - public static final int U_CLUSTER = -1; - public static final int PHI_CLUSTER = 0; - public static final int V_CLUSTER = 1; - public static final int ENDCAP_MINUS = 0; - public static final int BARREL = 1; - public static final int ENDCAP_PLUS = 2; - - - public String getParameterGroup() - { - return "SiCluster"; - } - - public String getName() - { - return "SiCluster"; - } - - public String getNameScreenName() - { - return "SCT_Cluster"; - } - - public float[][] getX() - { - return x; - } - - public float[][] getY() - { - return y; - } - - public float[][] getZ() - { - return z; - } - - - - ASiClusterData(AHashMap p, AEvent e) - { - super(p,e); - x = new float[][] { p.getFloatArray("x0"), p.getFloatArray("x1") }; - y = new float[][] { p.getFloatArray("y0"), p.getFloatArray("y1") }; - z = new float[][] { p.getFloatArray("z0"), p.getFloatArray("z1") }; - width = p.getFloatArray("width"); - - rho = new float[2][numData]; - phi = new float[2][numData]; - - layer = new int[numData]; - for (int i = 0; i < numData; ++i) - { - sub[i] = getSub(id[i]); - layer[i] = getLayer(id[i]); - } - - etaModule = (p.get("etaModule") != null) ? p.getIntArray("etaModule") : null; - phiModule = (p.get("phiModule") != null) ? p.getIntArray("phiModule") : null; - side = (p.get("side") != null) ? p.getIntArray("side") : null; - - } // ASiClusterData() --------------------------------------------------- - - - - protected void calculateRhoPhi() - { - - calculateRhoPhi(x[0], y[0], rho[0], phi[0]); - calculateRhoPhi(x[1], y[1], rho[1], phi[1]); - // treat wraparound - for (int i = 0; i < numData; ++i) - { - if (Math.abs(phi[1][i] - phi[0][i]) > Math.PI) - { - if (phi[1][i] - phi[0][i] > 0) - { - phi[0][i] += AMath.TWO_PI; - } - else - { - phi[1][i] += AMath.TWO_PI; - } - } - } // for - } // calculateRhoPhi() -------------------------------------------------- - - private void cutSubdetector() - { - AParameter par = parameterStore.get("CutsInDet", "SCT"); - if (par.getI() != -1) - { - cutArray(sub, par.getI(), "Barrel/Endcap"); - } - } // cutSubdetector() --------------------------------------------------- - - - protected void applyCuts() - { - cutIndex(); - cutOrientation(); - cutSubdetector(); - cut("CutsInDet", "Layer", "Layer", layer); - cutSimulatedTracks(); - cutReconstructedTracks(); - cutPhi(phi[0]); - cutEta(); - } // applyCuts() -------------------------------------------------------- - - private void cutEta() - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - if (!par.getStatus()) - return; - double etaCut = par.getD(); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double eta1 = AParameterUtilities.eta(z[0][list], rho[0][list]); - double eta2 = AParameterUtilities.eta(z[1][list], rho[1][list]); - double etaLower = Math.min(eta1, eta2); - double etaUpper = Math.max(eta1, eta2); - if (etaUpper > etaLowerCut && etaLower < etaUpperCut) - listdl[num++] = list; - } - numDraw = num; - } // cutEta() ----------------------------------------------------------- - - public int getLayer(int id) - { - int layer = (id & 0x01e00000) >> 21; - int sub = getSub(id); - if (sub == BARREL) - { - layer += 3; - } - else - { - layer += 11; - } - return layer; - } // getLayer() --------------------------------------------------------- - - public int getSub(int id) - { - return (id & 0x06000000) >> 25; - } // getSub() ----------------------------------------------------------- - - public int getOrientation(int id) - { - int side = (id & 0x400) >> 10; - int sub = getSub(id); - if ((side == 1 && sub == BARREL) || (side == 0 && sub != BARREL)) - { - return PHI_CLUSTER; - } - - int layer = getLayer(id); - if (layer % 2 == 1) - { - return U_CLUSTER; - } - - return V_CLUSTER; - } // getOrientation() --------------------------------------------------- - - protected void cutOrientation() - { - int num = 0; - AParameter stereoAnglePar = parameterStore.get("SiCluster", "Stereo"); - if (!stereoAnglePar.getStatus()) - { - return; - } - int orientation = stereoAnglePar.getI(); - for (int i = 0; i < numDraw; i++) - { - // only works for barrel for now !!!! - // if( getSub(id[listdl[i]])==BARREL && - // orientation==getOrientation(id[listdl[i]])) - if (orientation == getOrientation(id[listdl[i]])) - { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } // cutOrientation() --------------------------------------------------- - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if (colorFunction == numColorTypes + 1) - { - colorBy(layer); - } - else if (colorFunction == numColorTypes + 2) - { - colorByOrientation(); - } - - return numColorTypes + 2; - } // internalColor() ---------------------------------------------------- - - protected void colorByOrientation() - { - int numColors = parameterStore.get("HitColors", "Number").getI(); - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) - { - color[i] = (byte) col[getOrientation(id[i]) + 1 % numColors]; - } - } // colorByOrientation() ----------------------------------------------- - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index; - - String temp = getNameScreenName() + " (id: " + id[index] + " index: " + index +")\n" + - " orientation = " + getOrientation(id[index]); - temp += "\n x = " + x[0][index] + " " + x[1][index]; - temp += "\n y = " + y[0][index] + " " + y[1][index]; - temp += "\n z = " + z[0][index] + " " + z[1][index]; - temp += "\n " + AMath.RHO + " = " + rho[0][index] + " " + rho[1][index]; - temp += "\n " + AMath.ETA + " module = "; - temp += (etaModule != null) ? Integer.toString(etaModule[index]) : "n/a"; - temp += "\n " + AMath.PHI + " module = "; - temp += (phiModule != null) ? Integer.toString(phiModule[index]) : "n/a"; - temp += "\n side = "; - temp += (side != null) ? Integer.toString(side[index]) : "n/a"; - temp += "\n width = "; - temp += (width != null) ? Float.toString(width[index]) : "n/a"; - - temp += super.getHitInfo(index); // finds barcode information - - return temp; - } // getHitInfo() ------------------------------------------------------- - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = x[j][list]; - hv[1][j][i] = y[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } // getYXUser() -------------------------------------------------------- - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[1][list] - phiMid); - double sign; - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - { - sign = +1.; - } - else - { - sign = -1.; - } - - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = sign * rho[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } // getRZUser() -------------------------------------------------------- - - protected ACoord getFRUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = rho[j][list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], z[j][list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FR"); - } // getFRUser() -------------------------------------------------------- - - protected ACoord getFZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], z[j][list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FZ"); - } // getFZUser() -------------------------------------------------------- - - protected ACoord getVPUser() - { - makeDrawList(); - int numTotal = 2 * numDraw; - double[][][] hv = new double[2][numTotal][2]; - int[] index = new int[numTotal]; - double[] sign = new double[] { -1., 1. }; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for (int k = 0; k < 2; k++) - { - double deltaEta = AProjectionVP.getDeltaEta(rho[k][list], z[k][list]); - double eta = AParameterUtilities.eta(z[k][list], rho[k][list]); - for (int j = 0; j < 2; j++) - { - hv[0][2 * i + j][k] = eta + sign[j] * deltaEta; - hv[1][2 * i + j][k] = Math.toDegrees(phi[k][list]); - index[2 * i + j] = list; - } - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES).includePhiWrapAround("VP"); - } // getVPUser() -------------------------------------------------------- - -} // class ASiClusterData =================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/ASiClusterRDOData.java b/graphics/AtlantisJava/src/atlantis/data/ASiClusterRDOData.java deleted file mode 100644 index ac1806b4cb1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ASiClusterRDOData.java +++ /dev/null @@ -1,481 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionVP; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - - -/** - * Silicon clusters RDO Raw Data Objects (class derived from ASiClusterData) - * Parameters expected in the event file for SCTRDO datatype: - * x0|x1|y0|y1|z0|z1|phiModule|etaModule|id|BCIDError|firstHitError| - * formatterError|lvl1Error|preambleError|secondHitError|syncError|timeBin - * - */ -public class ASiClusterRDOData extends AHitData -{ - private float[][] x = null; - private float[][] y = null; - private float[][] z = null; - private int[] etaModule = null; - private int[] phiModule = null; - private int[] BCIDError = null; - private int[] firstHitError = null; - private int[] formatterError = null; - private int[] lvl1Error = null; - private int[] preambleError = null; - private int[] secondHitError = null; - private int[] syncError = null; - private int[] timeBin = null; - // calculated here - private int[] layer; - private float[][] rho; - private float[][] phi; - - public static final int U_CLUSTER = -1; - public static final int PHI_CLUSTER = 0; - public static final int V_CLUSTER = 1; - public static final int ENDCAP_MINUS = 0; - public static final int BARREL = 1; - public static final int ENDCAP_PLUS = 2; - - - - public String getParameterGroup() - { - return "SiClusterRDO"; - - } // getParameterGroup() ------------------------------------------------ - - - - public String getName() - { - return "SiClusterRDO"; - - } // getName() ---------------------------------------------------------- - - - - public String getNameScreenName() - { - return "SiClusterRDO"; - - } // getNameScreenName() ------------------------------------------------ - - - - ASiClusterRDOData(AHashMap p, AEvent e) - { - super(p,e); - x = new float[][] - { p.getFloatArray("x0"), p.getFloatArray("x1") }; - y = new float[][] - { p.getFloatArray("y0"), p.getFloatArray("y1") }; - z = new float[][] - { p.getFloatArray("z0"), p.getFloatArray("z1") }; - etaModule = p.getIntArray("etaModule"); - phiModule = p.getIntArray("phiModule"); - BCIDError = p.getIntArray("BCIDError"); - firstHitError = p.getIntArray("firstHitError"); - formatterError = p.getIntArray("formatterError"); - lvl1Error = p.getIntArray("lvl1Error"); - preambleError = p.getIntArray("preambleError"); - secondHitError = p.getIntArray("secondHitError"); - syncError = p.getIntArray("syncError"); - timeBin = p.getIntArray("timeBin"); - rho = new float[2][numData]; - phi = new float[2][numData]; - layer = new int[numData]; - - for(int i = 0; i < numData; ++i) - { - sub[i] = getSub(id[i]); - layer[i] = getLayer(id[i]); - } - - } // ASiClusterRDOData() ------------------------------------------------ - - - protected void calculateRhoPhi() - { - calculateRhoPhi(x[0], y[0], rho[0], phi[0]); - calculateRhoPhi(x[1], y[1], rho[1], phi[1]); - // treat wraparound - for(int i = 0; i < numData; ++i) - { - if(Math.abs(phi[1][i] - phi[0][i]) > Math.PI) - { - if(phi[1][i] - phi[0][i] > 0) - { - phi[0][i] += AMath.TWO_PI; - } - else - { - phi[1][i] += AMath.TWO_PI; - } - } - } - - } // calculateRhoPhi() -------------------------------------------------- - - - - private void cutSubdetector() - { - AParameter par = parameterStore.get("CutsInDet", "SCT"); - if(par.getI() != -1) - { - cutArray(sub, par.getI(), "Barrel/Endcap"); - } - - } // cutSubdetector() --------------------------------------------------- - - - protected void applyCuts() - { - cutIndex(); - cutOrientation(); - cutSubdetector(); - cut("CutsInDet", "Layer", "Layer", layer); - cutPhi(phi[0]); - cutEta(); - - } // applyCuts() -------------------------------------------------------- - - - - private void cutEta() - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - if(!par.getStatus())return; - double etaCut = par.getD(); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double eta1 = AParameterUtilities.eta(z[0][list], rho[0][list]); - double eta2 = AParameterUtilities.eta(z[1][list], rho[1][list]); - double etaLower = Math.min(eta1, eta2); - double etaUpper = Math.max(eta1, eta2); - if(etaUpper > etaLowerCut && etaLower < etaUpperCut) - listdl[num++] = list; - } - numDraw = num; - - } // cutEta() ----------------------------------------------------------- - - - - public int getLayer(int id) - { - int layer = (id & 0x01e00000) >> 21; - int sub = getSub(id); - if(sub == BARREL) - layer += 3; - else - layer += 11; - return layer; - - } // getLayer() --------------------------------------------------------- - - - - public int getSub(int id) - { - return(id & 0x06000000) >> 25; - - } // getSub() ----------------------------------------------------------- - - - - public int getOrientation(int id) - { - int side = (id & 0x400) >> 10; - int sub = getSub(id); - if((side == 1 && sub == BARREL) || (side == 0 && sub != BARREL)) - { - return PHI_CLUSTER; - } - int layer = getLayer(id); - if(layer % 2 == 1)return U_CLUSTER; - return V_CLUSTER; - - } // getOrientation() --------------------------------------------------- - - - - protected void cutOrientation() - { - int num = 0; - AParameter stereoAnglePar = parameterStore.get("SiCluster", "Stereo"); - if(!stereoAnglePar.getStatus()) - { - return; - } - int orientation = stereoAnglePar.getI(); - for(int i = 0; i < numDraw; i++) - // only works for barrel for now !!!! - // if( getSub(id[listdl[i]])==BARREL && orientation==getOrientation(id[listdl[i]])) - if(orientation == getOrientation(id[listdl[i]])) - { - listdl[num++] = listdl[i]; - } - numDraw = num; - - } // cutOrientation() --------------------------------------------------- - - - - /** - * parameter InDet -> SiClusterRDO -> Color Function: - * pv="Constant = 0, Error = 1, Orientation = 2" - */ - protected int internalColor() - { - // it's usual to call this method from mother class, but in this case - // it uses it's own colour types co we don't care about AHitData - // int numColorTypes = super.internalColor(); - - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == 0) - { - colorByConstant(); - } - else if(colorFunction == 1) - { - colorByError(); - } - else if(colorFunction == 2) - { - colorByOrientation(); - } - - // 3 colour schemes exist here - return 3; - - } // internalColor() ---------------------------------------------------- - - - - /** - * colour elements by error (error subtags from the event file): - * BCIDError, firstHitError, formatterError, lvl1Error, preambleError, - * secondHitError, syncError ] - * if any of these flags is set to true, the element is considered erroneous - * (next iteration may be to colour by error type, if they want it ...) - */ - protected void colorByError() - { - int constantColor = parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - int errorColor = parameterStore.get(PARAMETER_GROUP, "Error").getI(); - - for(int i = 0; i < numData; i++) - { - if(BCIDError[i] != 0 || firstHitError[i] != 0 || - formatterError[i] != 0 || lvl1Error[i] != 0 || - preambleError[i] != 0 || secondHitError[i] != 0 || - syncError[i] != 0) - { - // element is erroneous - color[i] = (byte) errorColor; - } - else - { - color[i] = (byte) constantColor; - } - } - - } // colorByError() ----------------------------------------------------- - - - - protected void colorByOrientation() - { - int numColors = parameterStore.get("HitColors", "Number").getI(); - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for(int i = 0; i < numData; i++) - { - color[i] = (byte) col[getOrientation(id[i]) + 1 % numColors]; - } - - } // colorByOrientation() ----------------------------------------------- - - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index; - - String temp = getNameScreenName() + " (id: " + id[index] + " index: " + index + ")\n" + - " orientation = " + getOrientation(id[index]) + "\n" + - " x = " + x[0][index] + " " + x[1][index] + "\n" + - " y = " + y[0][index] + " " + y[1][index] + "\n" + - " z = " + z[0][index] + " " + z[1][index] + "\n" + - " " + AMath.RHO + " = " + rho[0][index] + " " + - rho[1][index] + "\n" + - " " + AMath.ETA + " module = " + etaModule[index] + "\n" + - " " + AMath.PHI + " module = " + phiModule[index] + "\n" + - " BCID error = " + BCIDError[index] + "\n" + - " first hit error = " + firstHitError[index] + "\n" + - " formatter error = " + formatterError[index] + "\n" + - " lvl1 error = " + lvl1Error[index] + "\n" + - " preamble error = " + preambleError[index] + "\n" + - " second hit error = " + secondHitError[index] + "\n" + - " sync error = " + syncError[index] + "\n" + - " time bin = " + timeBin[index]; - return temp; - - } // getHitInfo() ------------------------------------------------------- - - - - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = x[j][list]; - hv[1][j][i] = y[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - - } // getYXUser() -------------------------------------------------------- - - - - protected ACoord getRZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double phiDiff = Math.abs(phi[1][list] - phiMid); - double sign; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - { - sign = +1.; - } - else - { - sign = -1.; - } - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = sign * rho[j][list]; - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - - } // getRZUser() -------------------------------------------------------- - - - - protected ACoord getFRUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = rho[j][list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], - z[j][list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FR"); - - } // getFRUser() -------------------------------------------------------- - - - - protected ACoord getFZUser() - { - makeDrawList(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - for(int j = 0; j < 2; j++) - { - hv[0][j][i] = z[j][list]; - hv[1][j][i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[j][list], phi[j][list], - z[j][list])); - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FZ"); - - } // getFZUser() -------------------------------------------------------- - - - - protected ACoord getVPUser() - { - makeDrawList(); - int numTotal = 2 * numDraw; - int numPoints = 10; - double[][][] hv = new double[2][numTotal][numPoints]; - int[] index = new int[numTotal]; - double[] sign = new double[] - { -1., 1.}; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double xx = x[0][list]; - double delx = (x[1][list] - x[0][list]) / (numPoints - 1); - double yy = y[0][list]; - double dely = (y[1][list] - y[0][list]) / (numPoints - 1); - double zz = z[0][list]; - double delz = (z[1][list] - z[0][list]) / (numPoints - 1); - for(int k = 0; k < numPoints; k++) - { - double xxx = xx + k * delx; - double yyy = yy + k * dely; - double zzz = zz + k * delz; - double rrr = Math.sqrt(xxx * xxx + yyy * yyy); - double ppp = Math.atan2(yyy, xxx); - double deltaEta = AProjectionVP.getDeltaEta(rrr, zzz); - double eta = AParameterUtilities.eta(zzz, rrr); - for(int j = 0; j < 2; j++) - { - hv[0][2 * i + j][k] = eta + sign[j] * deltaEta; - hv[1][2 * i + j][k] = Math.toDegrees(ppp); - index[2 * i + j] = list; - } - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES). includePhiWrapAround("VP"); - - } // getVPUser() -------------------------------------------------------- - - -} // class ASiClusterRDOData ================================================ diff --git a/graphics/AtlantisJava/src/atlantis/data/ATGCData.java b/graphics/AtlantisJava/src/atlantis/data/ATGCData.java deleted file mode 100755 index e0005dce948..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATGCData.java +++ /dev/null @@ -1,340 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameterUtilities; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - -public class ATGCData extends AMuonHitData -{ - float[] swidth; - float[] lwidth; - float[] length; - int[] gasGap; - - private static ALogger logger = ALogger.getLogger(ATGCData.class); - - public String getParameterGroup() - { - return "TGC"; - } - - public String getName() - { - return "TGC"; - } - - public String getNameScreenName() - { - return "TGC"; - } - - ATGCData(AHashMap p, AEvent e) - { - super(p,e); - swidth = p.getFloatArray("swidth"); - length = p.getFloatArray("length"); - lwidth = p.getFloatArray("lwidth"); - gasGap = new int[numData]; - for (int i = 0; i < numData; i++) - gasGap[i] = getGasGap(i); - } - - protected int getStation(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - return (stationName.charAt(1) - '0') % 4; - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - } - - protected int getSub(int index) - { - try { - if (AIdHelper.stationEta(id[index]) < 0) { - return 0; - } else { - return 1; - } - - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - } - - public int getSector(int index) - { - try { - String stationName = AIdHelper.stationName(id[index]); - int stationPhi = AIdHelper.stationPhi(id[index]); - - int retval; - if (stationName.equals("T4E")) { - int temp = stationPhi % 24; - retval = 2 * (temp / 3); - } else if (stationName.charAt(2) == 'F') { - int temp = stationPhi % 24; - retval = 2 * (temp / 3); - if (temp % 3 > 1) retval += 1; - } else { - int temp = (stationPhi + 1) % 48; - retval = 2 * (temp / 6); - if (temp % 6 > 3) retval += 1; - } - return retval; - - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - - } - - protected int getGasGap(int index) - { - try { - return AIdHelper.tgcGasGap(id[index]); - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return 0; - } - - protected boolean getMeasuresPhi(int index) - { - try { - if (AIdHelper.tgcIsStrip(id[index]) == 1) { - return true; - } - } catch (AAtlantisException e) { - logger.error("Problem decoding TGC identifier", e); - } - - return false; - } - - public void applyCuts() - { - super.applyCuts(); - if (parameterStore.get("CutsATLAS", "CutPhi").getStatus()) - cutPhi(phi, getDPhi()); - if (parameterStore.get("CutsATLAS", "CutEta").getStatus()) - cutEtaDRho(rho, z, getDRho()); - } - - // used for cuts - - private float[] getDPhi() - { - // only roughly correct - // must create all - float[] dphi = new float[numData]; - - // need only fill for those in draw list - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - dphi[list] = (float) Math.abs(Math.atan2((swidth[list] + lwidth[list]) / 4., rho[list])); - } - return dphi; - } - - // used for cuts - - private float[] getDRho() - { - // only roughly correct - // must create all - float[] drho = new float[numData]; - - // need only fill for those in draw list - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - drho[list] = (float) (length[list] / 2.); - } - return drho; - } - - protected ACoord getFZUser() - { - makeDrawList(); - cutArray(measuresPhi, true, " Strip"); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - index[i] = list; - double deltaPhi = ((swidth[list] + lwidth[list]) / 4.) / rho[list]; - - hv[0][0][i] = z[list]; - hv[1][0][i] = Math.toDegrees(phi[list] - deltaPhi); - hv[0][1][i] = z[list]; - hv[1][1][i] = Math.toDegrees(phi[list] + deltaPhi); - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FZ"); - } - - private void makeDrawListYX() - { - int mode = parameterStore.get("YX", "Mode").getI(); - - if (mode == 0 || mode >= 5) - { - numDraw = 0; - } - else - { - makeDrawList(); - int num = 0; - - for (int i = 0; i < numDraw; ++i) - if (mode == station[listdl[i]] + 1) - listdl[num++] = listdl[i]; - numDraw = num; - } - cut("YX", "TGCGasGap", " TGC Gas Gap", gasGap); - } - - protected ACoord getYXUser() - { - return getYXUser(0); - } - - protected ACoord getYXUser(int flag) - { - makeDrawListYX(); - int[] split = { 6, 1, 6, 1 }; - int numPoints = 4; - boolean splitIt = parameterStore.get("YX", "FishEye").getStatus() || flag == 1; - - if (splitIt) - numPoints = 14; - double[] temp = new double[4]; - double[][][] hv = new double[2][numDraw][numPoints]; - int[] index = new int[numDraw]; - - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - - index[i] = list; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double rMid = rho[list]; - double dR = length[list] / 2.; - double r = rMid - dR; - double d = swidth[list] / 2.; - double x = r * cosPhi; - double y = r * sinPhi; - double dx = d * sinPhi; - double dy = d * cosPhi; - - hv[0][i][0] = x + dx; - hv[1][i][0] = y - dy; - hv[0][i][1] = x - dx; - hv[1][i][1] = y + dy; - r = rMid + dR; - x = r * cosPhi; - y = r * sinPhi; - d = lwidth[list] / 2.; - dx = d * sinPhi; - dy = d * cosPhi; - hv[0][i][2] = x - dx; - hv[1][i][2] = y + dy; - hv[0][i][3] = x + dx; - hv[1][i][3] = y - dy; - if (splitIt) - for (int j = 0; j < 2; ++j) - { - for (int k = 0; k < 4; ++k) - temp[k] = hv[j][i][k]; - AMath.splitArrayIntoPieces(temp, hv[j][i], split); - } - } - return new ACoord(hv, index, this); - } - - protected ACoord getFRUser() - { - return getYXUser(1).convertYXToFR().includePhiWrapAround("FR"); - } - - protected ACoord getXZRZUser(int sign[]) - { - double[][][] hv = new double[2][numDraw][]; - int index[] = new int[numDraw]; - - try { - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - double rho = Math.sqrt(x[j]*x[j] + y[j]*y[j]); - - if (AIdHelper.tgcIsStrip(id[j]) == 1) { - double drho = length[j]/2.; - hv[0][i] = new double[] { z[j], z[j] }; - hv[1][i] = new double[] { sign[i] * (rho - drho), - sign[i] * (rho + drho) }; - } else { - hv[0][i] = new double[] { z[j] }; - hv[1][i] = new double[] { sign[i] * rho }; - } - } - - return new ACoord(hv, index, this); - } catch (AAtlantisException e) { - AOutput.append("Error decoding TGC identifier: " + e.getMessage(), ALogInterface.BAD_COMMAND); - return ACoord.NO_DATA; - } - } - - protected ACoord getXZUser() { - makeDrawList(); - cutMuonSector(sector); - - int[] sign = new int[numDraw]; - int sect = (int) Math.round(parameterStore.get("XZ", "Phi").getD() / 22.5); - - for(int i=0; i<numDraw; i++) { - if (sector[listdl[i]] == sect) - sign[i] = 1; - else - sign[i] = -1; - } - - return getXZRZUser(sign); - } - - protected ACoord getRZUser() { - makeDrawList(); - - int[] sign = new int[numDraw]; - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - sign[i] = AParameterUtilities.getRhoSign(x[j], y[j]); - } - - return getXZRZUser(sign); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ATILEData.java b/graphics/AtlantisJava/src/atlantis/data/ATILEData.java deleted file mode 100755 index 99bc22c7daa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATILEData.java +++ /dev/null @@ -1,843 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.io.FileNotFoundException; - -import com.Ostermiller.util.CSVParser; - -import atlantis.geometry.ACalorimeterDetector; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.utils.AUtilities; -import atlantis.utils.ALogger; - - -/** - * The TILE hadronic calorimeter. - * - * @author Eric Jansen - */ -public class ATILEData extends ACalorimeterData -{ - private static ALogger logger = ALogger.getLogger(ATILEData.class); - - // data for real pulse shapes plots - private float[] pmt1Energy = null; - private float[] pmt2Energy = null; - private float[] pmt1Chi2 = null; - private float[] pmt2Chi2 = null; - private float[] pmt1Time = null; - private float[] pmt2Time = null; - private float[] pmt1RawTime = null; - private float[] pmt2RawTime = null; - private float[] pmt1RawAmplitude = null; - private float[] pmt2RawAmplitude = null; - private int[][] adcCounts1 = null; - private int[][] adcCounts2 = null; - private int[] pmt1Gain = null; - private int[] pmt2Gain = null; - private float[] pmt1Pedestal = null; - private float[] pmt2Pedestal = null; - private int[] pmt1Number = null; - private int[] pmt2Number = null; - private int[] pmt1ADCStatus = null; - private int[] pmt2ADCStatus = null; - private static boolean pulseShapesDataAvailable = false; - private static final String LOOKUP_TABLE_FILE = - AGlobals.instance().getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - "rpsplt_tile.csv"; - // number of lookup table values for real pulse shapes plots calculation - private static final short NUMBER_OF_LOOKUP_VALUES = 401; - - - ATILEData(AHashMap p, AEvent e) - { - super(p,e); - - - for (int i = 0; i < numData; i++) - { - try - { - side[i] = (byte) AIdHelper.tileSide(id[i]); - etaIndex[i] = (short) AIdHelper.tileTower(id[i]); - phiIndex[i] = (short) AIdHelper.tileModule(id[i]); - sampling[i] = AIdHelper.tileSampling(id[i]); - } - catch (AAtlantisException ex) - { - System.out.println("Problem decoding ID " + id[i] + " in " + - CALORIMETER_NAME + ": " + ex.getMessage()); - side[i] = 0; - etaIndex[i] = -1; - phiIndex[i] = -1; - sampling[i] = -1; - } - } - - makeHitToGeometryMapping(); - for (int i = 0; i < et.length; ++i) - { - et[i] = Math.abs(energy[i] / (float) Math.cosh(eta[i])); - } - - // Collect some constants needed for the histograms. - for (int i = 0; i < ACalorimeterDetector.count(); i++) - { - if (ACalorimeterDetector.get(i).getName().indexOf(CALORIMETER_NAME) >= 0) - { - if (innerR == 0.0 || ACalorimeterDetector.get(i).getRMin() < innerR) - { - innerR = ACalorimeterDetector.get(i).getRMin(); - } - if (phiGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaPhi() < phiGranularity) - { - phiGranularity = ACalorimeterDetector.get(i).getDeltaPhi(); - } - if (etaGranularity == 0.0 || ACalorimeterDetector.get(i).getDeltaEta() < etaGranularity) - { - etaGranularity = ACalorimeterDetector.get(i).getDeltaEta(); - } - if (outerEta == 0.0 || ACalorimeterDetector.get(i).getEtaMax() > outerEta) - { - outerEta = ACalorimeterDetector.get(i).getEtaMax(); - } - } - - if (outerR == 0.0 || ACalorimeterDetector.get(i).getRMax() > outerR) - { - outerR = ACalorimeterDetector.get(i).getRMax(); - } - if (outerZ == 0.0 || ACalorimeterDetector.get(i).getZMax() > outerZ) - { - outerZ = ACalorimeterDetector.get(i).getZMax(); - } - } - - // Add a little bit of extra margin to prevent binning errors due to - // rounding of numbers. - outerEta += etaGranularity; - - readPulseShapePlotData(p); - - pmt1ADCStatus = (p.get("pmt1ADCStatus") != null) ? p.getIntArray("pmt1ADCStatus") : null; - pmt2ADCStatus = (p.get("pmt2ADCStatus") != null) ? p.getIntArray("pmt2ADCStatus") : null; - - - } // ATILEData() -------------------------------------------------------- - - - - /** - * readLookupTableFile() reads in comma separated values (CSV) file - * with TILE real pulse shapes plots time and amplitude lookup values - * @throws AAtlantisException - */ - protected static void readLookupTableFile() throws AAtlantisException - { - try - { - InputStream is = AUtilities.getFileAsStream(LOOKUP_TABLE_FILE); - CSVParser parser = new CSVParser(is); - parser.setCommentStart("#"); - String arrayName = null; - - while((arrayName = parser.nextValue()) != null) - { - String valueArray = parser.nextValue(); // shall now contain all values - CSVParser parserArray = new CSVParser(new StringReader(valueArray)); - String[][] s = parserArray.getAllValues(); - if("TILE_AMPLITUDE".equals(arrayName)) - { - ACalorimeterRPSPLT.TILE_AMPLITUDE = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - else if("TILE_TIME".equals(arrayName)) - { - ACalorimeterRPSPLT.TILE_TIME = - getLookupTableArray(s, NUMBER_OF_LOOKUP_VALUES); - } - } - } - catch(FileNotFoundException e) - { - throw new AAtlantisException("could not find file: " + - LOOKUP_TABLE_FILE); - } - catch(IOException e) - { - throw new AAtlantisException("exception while reading file: " + - LOOKUP_TABLE_FILE); - } - catch(AAtlantisException e) - { - throw e; - } - - } // readLookupTableFile() ---------------------------------------------- - - - - private void readPulseShapePlotData(AHashMap p) - { - pmt1Energy = (p.get("pmt1Energy") != null) ? p.getFloatArray("pmt1Energy") : null; - pmt2Energy = (p.get("pmt2Energy") != null) ? p.getFloatArray("pmt2Energy") : null; - pmt1Chi2 = (p.get("pmt1Chi2") != null) ? p.getFloatArray("pmt1Chi2") : null; - pmt2Chi2 = (p.get("pmt2Chi2") != null) ? p.getFloatArray("pmt2Chi2") : null; - pmt1Time = (p.get("pmt1Time") != null) ? p.getFloatArray("pmt1Time") : null; - pmt2Time = (p.get("pmt2Time") != null) ? p.getFloatArray("pmt2Time") : null; - - pmt1Gain = (p.get("pmt1Gain") != null) ? p.getIntArray("pmt1Gain") : null; - pmt2Gain = (p.get("pmt2Gain") != null) ? p.getIntArray("pmt2Gain") : null; - - pmt1Pedestal = (p.get("pmt1Pedestal") != null) ? p.getFloatArray("pmt1Pedestal") : null; - pmt2Pedestal = (p.get("pmt2Pedestal") != null) ? p.getFloatArray("pmt2Pedestal") : null; - - pmt1Number = (p.get("pmt1Number") != null) ? p.getIntArray("pmt1Number") : null; - pmt2Number = (p.get("pmt2Number") != null) ? p.getIntArray("pmt2Number") : null; - - int[] adc1 = (p.get("adcCounts1") != null) ? p.getIntArray("adcCounts1") : null; - int[] adc2 = (p.get("adcCounts2") != null) ? p.getIntArray("adcCounts2") : null; - - // by zdenek (2008-09-15): - // raw time: later additions to tilecal pulse shapes, doens't necessarily - // have to be in the event files, will not be in the old ones - pmt1RawTime = (p.get("pmt1RawTime") != null) ? p.getFloatArray("pmt1RawTime") : null; - pmt2RawTime = (p.get("pmt2RawTime") != null) ? p.getFloatArray("pmt2RawTime") : null; - - // by zdenek (2008-11-24): - // pmt1RawAmplitude, pmt2RawAmplitude now used to calculate pulse shape - // this is made now obligatory, without this data, the pulse shapes will - // not be available - pmt1RawAmplitude = (p.get("pmt1RawAmplitude") != null) ? p.getFloatArray("pmt1RawAmplitude") : null; - pmt2RawAmplitude = (p.get("pmt2RawAmplitude") != null) ? p.getFloatArray("pmt2RawAmplitude") : null; - - // read in ADCCounts - if(adc1 != null && adc2 != null) - { - adcCounts1 = new int[numData][0]; - adcCounts2 = new int[numData][0]; - // amount of numbers associated with each cells (i.e. with each data item) - int multiple = adc1.length / numData; - int num = 0; - for (int i = 0; i < numData; i++) - { - adcCounts1[i] = new int[multiple]; - adcCounts2[i] = new int[multiple]; - for (int j = 0; j < multiple; j++) - { - adcCounts1[i][j] = adc1[num]; // fill in array for each cell - adcCounts2[i][j] = adc2[num]; // fill in array for each cell - num++; - } - } - } - - pulseShapesDataAvailable = false; - if(adcCounts1 != null && adcCounts2 != null && adcCounts1.length != 0 && - adcCounts2.length != 0 && adcCounts1[0].length != 0 && - adcCounts2[0].length != 0 && pmt1Number != null && - pmt2Number != null && pmt1Energy != null && pmt2Energy != null && - pmt1Time != null && pmt2Time != null && pmt1Pedestal != null && - pmt2Pedestal != null && pmt1Gain != null && pmt2Gain != null && - pmt1RawAmplitude != null && pmt2RawAmplitude != null) - { - pulseShapesDataAvailable = true; - - logger.debug(CALORIMETER_NAME + - ": data for real pulse shape plots available"); - - if(ACalorimeterRPSPLT.areTileLookupTablesInitialized()) - { - logger.debug(CALORIMETER_NAME + - ": lookup tables have already been read in"); - } - else - { - - logger.debug(CALORIMETER_NAME + - ": lookup table values have not been read in yet\n" + - " trying to read file: " + LOOKUP_TABLE_FILE); - - try - { - readLookupTableFile(); - logger.debug(CALORIMETER_NAME + - ": values from " + LOOKUP_TABLE_FILE + - " successfully read in"); - } - catch(AAtlantisException ex) - { - logger.error(CALORIMETER_NAME + - ": reading " + LOOKUP_TABLE_FILE + - " failed, real pulse shapes plots will not " + - "be available, reason: " + ex.getMessage(), ex); - pulseShapesDataAvailable = false; - } - } - } - - } // readPulseShapePlotData() ------------------------------------------- - - - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsCalo", "TileET", "TileET", et); - cut("CutsCalo", "TileEnergyBottom", "TileEnergyBottom", energy); - cut("CutsCalo", "TileEnergyUp", "TileEnergyUp", energy); - - // following cut is based on pmt1ADCStatus, resp. pmt2ADCStatus - if(pmt1ADCStatus != null && pmt2ADCStatus != null) - { - cut("CutsCalo", "TilePMTADC", "TilePMTADC", pmt1ADCStatus); - cut("CutsCalo", "TilePMTADC", "TilePMTADC", pmt2ADCStatus); - } - } - - - - /** - * Returns the name of the parameter group. - * @return String parameter group - */ - public String getParameterGroup() - { - return "TILE"; - } - - /** - * Returns the name of the datatype. - * @return String datatype - */ - public String getName() - { - return "TILE"; - } - - /** - * Returns the displayed name of datatype - * @return String screen name - */ - public String getNameScreenName() - { - return "TILE"; - } - - /** - * Returns the type of calorimeter (ECAL/HCAL) for a hit. - * @param index int hit index - * @return String calorimeter type - */ - public String getCalorimeterType(int index) - { - return "HCAL"; - } - - @Override //ACalorimeterData - //Gives the hit time for this Tile cell based on the PMT times - protected double getTime(int hit) - { - if (pmt1Time == null) return 0.0; - else if (pmt2Time == null) return 0.0; - else { - if (pmt1Time[hit]!=0.0 && pmt2Time[hit]!=0.0){ - return (pmt1Time[hit]+pmt2Time[hit])/2.; - } - if (pmt1Time[hit]==0.0 && pmt2Time[hit]!=0.0){ - return pmt2Time[hit]; - } - if (pmt1Time[hit]!=0.0 && pmt2Time[hit]==0.0){ - return pmt1Time[hit]; - } - } - return 0.0; - } - - /** - * Returns calo hit info, most of the parameters are taken from from - * (mother) ACalorimeterData class. - * @param index int - * @return String - */ - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n ET="+String.format("%.3f",et[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Ex="+String.format("%.3f",et[index]*Math.cos(phi[index]))+" GeV "+ - "\n Ey="+String.format("%.3f",et[index]*Math.sin(phi[index]))+" GeV "+ - "\n Ez="+String.format("%.3f",et[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String t = ""; - String pmt1Info = ""; - String pmt2Info = ""; - - String decodedId = AIdHelper.getDecodedTileIndentifier(id[index]); - t = decodedId + " " + super.getHitInfoNoDecode(index); - - - pmt1Info += "\n PMT1 ADC status = "; - pmt1Info += (pmt1ADCStatus != null) ? Integer.toString(pmt1ADCStatus[index]) : "n/a"; - - pmt1Info += "\n PMT1 energy = "; - pmt1Info += (pmt1Energy != null) ? Float.toString(pmt1Energy[index]) + - " GeV" : "n/a"; - pmt1Info += "\n PMT1 chi2 = "; - pmt1Info += (pmt1Chi2 != null) ? Float.toString(pmt1Chi2[index]) : "n/a"; - pmt1Info += "\n PMT1 time = "; - pmt1Info += (pmt1Time != null) ? Float.toString(pmt1Time[index]) + - " ns" : "n/a"; - pmt1Info += "\n PMT1 gain = "; - pmt1Info += (pmt1Gain != null) ? Integer.toString(pmt1Gain[index]) : "n/a"; - pmt1Info += "\n PMT1 pedestal = "; - pmt1Info += (pmt1Pedestal != null) ? Float.toString(pmt1Pedestal[index]) + - " ADC counts" : "n/a"; - - - pmt2Info += "\n PMT2 ADC status = "; - pmt2Info += (pmt2ADCStatus != null) ? Integer.toString(pmt2ADCStatus[index]) : "n/a"; - - pmt2Info += "\n PMT2 energy = "; - pmt2Info += (pmt2Energy != null) ? Float.toString(pmt2Energy[index]) + - " GeV" : "n/a"; - pmt2Info += "\n PMT2 chi2 = "; - pmt2Info += (pmt2Chi2 != null) ? Float.toString(pmt2Chi2[index]) : "n/a"; - pmt2Info += "\n PMT2 time = "; - pmt2Info += (pmt2Time != null) ? Float.toString(pmt2Time[index]) + - " ns" : "n/a"; - pmt2Info += "\n PMT2 gain = "; - pmt2Info += (pmt2Gain != null) ? Integer.toString(pmt2Gain[index]) : "n/a"; - pmt2Info += "\n PMT2 pedestal = "; - pmt2Info += (pmt2Pedestal != null) ? Float.toString(pmt2Pedestal[index]) + - " ADC counts" : "n/a"; - - pmt2Info += pulseShapesDataAvailable ? "" : - "\n data for real pulse shapes plot n/a"; - - pmt2Info += "\n calc time = "+getTime(index); - - return t + pmt1Info + pmt2Info; - - } // getHitInfo() ------------------------------------------------------- - - - - // calculate real pulse shapes values based on the values in the lookup tables - private double getPhysicsPulseShape(double xTime, double pmtTime, - double pmtPedestal, double pmtEnergy, - float[] amplitude, float[] time) - throws AAtlantisException - { - double tdiv = 0.0; - int lookup = 0; - double localTime = 0.0; - double xpulse = 0.0; - - // need to get "multiple" parameter ( = number of values in adcCounts - // for each cell - adcCounts1[0].length), shall be the same for all the - // cells - taking the length of the first array (for the first cell) - // [currently (2007-05-23) is this multiple 9 but to change in real data] - // no NullPointer or ArrayIndexBound checks are necessary here as this - // method shall only be called when the relevant data is available - double centerOfSamples = (adcCounts1[0].length + 1.0) / 2.0; - - tdiv = time[1] - time[0]; - localTime = (xTime - centerOfSamples) * 25.0 - pmtTime; - lookup = (int) ((localTime - time[0]) / tdiv); - - if(lookup < 0) - { - lookup = 0; - } - if(lookup >= NUMBER_OF_LOOKUP_VALUES - 1) - { - lookup = NUMBER_OF_LOOKUP_VALUES - 2; // -1 was off by 1 - } - - try - { - if(lookup == 0 || lookup == NUMBER_OF_LOOKUP_VALUES - 2) - { - xpulse = amplitude[lookup]; - } - else - { - xpulse = amplitude[lookup] + ((amplitude[lookup + 1] - - amplitude[lookup]) / tdiv) * (localTime - time[lookup]); - } - } - catch(ArrayIndexOutOfBoundsException ex) - { - String m = "ATILEData.getPhysicsPulseShape():\n" + - " lookup index out of bound: lookup = " + lookup; - throw new AAtlantisException(m); - } - return (xpulse * pmtEnergy) + pmtPedestal; - - } // getPhysicsPulseShape() --------------------------------------------- - - - -// /** -// * Call util class which plots cell pulse shapes provided that -// * all real pulse shapes data is available -// * Functions calculates values of real pulse shape calculated in the method -// * getPhysicsPulseShape(). -// * This method is called from pick interaction. -// * -// * @param index int -// */ - /*public void plotPulseShapes(int index) - { - - if(pulseShapesDataAvailable) - { - String title = getPulseTitleString(index); - - // two channels for a TILE cell (two arrays of ADC counts) - int[][] adcCounts = new int[][] { adcCounts1[index], adcCounts2[index] }; - - if(super.checkADCCountsAvailability(adcCounts)) - { - // adc counts are available - logger.debug(CALORIMETER_NAME + " adc counts (digits) are " + - "available for pulse shapes plots for this cell."); - } - else - { - AOutput.append("\nADC counts are not available for this cell, " + - "can't plot pulse shapes.", ALogPane.WARNING); - return; - } - - - String cap1 = "Real pulse shape " + "PMT " + pmt1Number[index] + - " gain " + pmt1Gain[index]; - String cap2 = "Real pulse shape " + "PMT " + pmt2Number[index] + - " gain " + pmt2Gain[index]; - String[] subTitle = new String[] { cap1, cap2 }; - - // by zdenek (2008-11-24): - // energy calculations (lowGainFactor, highGainFactor) and related - // magic constants removed - now using pmt1RawAmplitude, pmt2RawAmplitude - // instead of pmt[1,2]Energy, resp. former local variables - // energy1, energy2 when calling getPhysicsPulseShape() further down - - // 1 .. 9 range (9 values of ADC counts, 9 samples (starts from 1!)), - // need to get 401 values within this range. number of samples will - // likely decrease in real data from 9 to 7 - double step = (adcCounts1[index].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - double[][] realPulse = new double[2][NUMBER_OF_LOOKUP_VALUES]; // 2 channels - double[][] realPulseForRawTime = null; - double d = 1.0; - - // if pmt1RawTime and pmt2RawTime are present, use those for - // calculating data for real pulse shape plot based on these time values - boolean showPlotForRawTime = false; - if(pmt1RawTime != null && pmt2RawTime != null) - { - logger.debug("TILE pmt[1,2]RawTime are present, showing another plot."); - showPlotForRawTime = true; - realPulseForRawTime = new double[2][NUMBER_OF_LOOKUP_VALUES]; // 2 channels - } - - - // by zdenek 2008-11-25 - // DPD (slimed version of ESD) sometimes don't have pmt[1,2]Pedestal - // for a cell (the tag exists, values are there, but are 0). check - // if pedestal is 0 and if so, take as pedestal value the first - // adc count digit - float pmt1PedestalLocal = pmt1Pedestal[index]; - float pmt2PedestalLocal = pmt2Pedestal[index]; - if(pmt1PedestalLocal == 0.0f && pmt2PedestalLocal == 0.0f) - { - logger.debug("TILE pmt[1,2]Pedestal are not available (i.e. " + - "are 0.0f), using minimum of first and last " + - "adcCount digit as pedestal."); - float last1 = adcCounts1[index][adcCounts1[index].length - 1]; - float last2 = adcCounts2[index][adcCounts2[index].length - 1]; - pmt1PedestalLocal = Math.min(adcCounts1[index][0], last1); - pmt2PedestalLocal = Math.min(adcCounts2[index][0], last2); - } - - - try - { - for(int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) - { - d += step; - realPulse[0][i] = - getPhysicsPulseShape(d, pmt1Time[index], pmt1PedestalLocal, - pmt1RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - realPulse[1][i] = - getPhysicsPulseShape(d, pmt2Time[index], pmt2PedestalLocal, - pmt2RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - if(showPlotForRawTime) - { - realPulseForRawTime[0][i] = - getPhysicsPulseShape(d, pmt1RawTime[index], pmt1PedestalLocal, - pmt1RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - realPulseForRawTime[1][i] = - getPhysicsPulseShape(d, pmt2RawTime[index], pmt2PedestalLocal, - pmt2RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - } - } - } - catch(AAtlantisException aaex) - { - AOutput.append(aaex.getMessage(), ALogPane.WARNING); - return; - } - - if(realPulseForRawTime != null) - { - APulseShapePlot.plotRealPulseShapes(adcCounts, realPulse, - step, subTitle, title + " (cell time)"); - APulseShapePlot.plotRealPulseShapes(adcCounts, realPulseForRawTime, - step, subTitle, title + " (raw time)"); - } - else - { - // if RawTime stuff is to be removed, there will remain only - // one such call to plot real pulse shapes - this one - APulseShapePlot.plotRealPulseShapes(adcCounts, realPulse, - step, subTitle, title); - } - } - else - { - logger.warn(CALORIMETER_NAME + " plotPulseShapes() method called, " + - "but data is not available."); - return; - } - - } */// plotPulseShapes() -------------------------------------------------- - - - - /** - * Returns the histograms for this projection. - * - * @param projection AProjection2D current projection - * @return ACoord[] polygons representing histograms - */ - protected ACoord[] getUserHistograms(AProjection2D projection) - { - ACoord[] data = ACoord.NO_HISTOGRAMS; - if (projection instanceof AProjectionYX && parameterStore.get("YX", "Mode").getI() == AProjectionYX.MODE_STANDARD) - data = getYXHistograms(); - else if (projection instanceof AProjectionFR) - data = getFRHistograms(); - else if (projection instanceof AProjectionRZ) - data = getRZHistograms(); - return projection.nonLinearTransform(data); - } - - @Override - protected String getPulseTitleString(int index) { - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - - String title = CALORIMETER_NAME + " cell: " + decodedId[0]; - - return title; - } - - @Override - protected int[][] getADCCounts(int index) { - - if (pulseShapesDataAvailable) { - // two channels for a TILE cell (two arrays of ADC counts) - return new int[][]{adcCounts1[index], adcCounts2[index]}; - } else { - return null; - } - } - - @Override - protected double[][] getPulseShape(int index) { - - if (!pulseShapesDataAvailable) return null; - - // by zdenek (2008-11-24): - // energy calculations (lowGainFactor, highGainFactor) and related - // magic constants removed - now using pmt1RawAmplitude, pmt2RawAmplitude - // instead of pmt[1,2]Energy, resp. former local variables - // energy1, energy2 when calling getPhysicsPulseShape() further down - - // 1 .. 9 range (9 values of ADC counts, 9 samples (starts from 1!)), - // need to get 401 values within this range. number of samples will - // likely decrease in real data from 9 to 7 - double step = getPulseStep(index); - double[][] realPulseRaw = new double[2][NUMBER_OF_LOOKUP_VALUES]; // 2 channels - double d = 1.0; - - // if pmt1RawTime and pmt2RawTime are present, use those for - // calculating data for real pulse shape plot based on these time values - if (pmt1RawTime == null || pmt2RawTime == null) { - logger.warn("No raw time values available"); - return null; - } - - - // by zdenek 2008-11-25 - // DPD (slimed version of ESD) sometimes don't have pmt[1,2]Pedestal - // for a cell (the tag exists, values are there, but are 0). check - // if pedestal is 0 and if so, take as pedestal value the first - // adc count digit - float pmt1PedestalLocal = pmt1Pedestal[index]; - float pmt2PedestalLocal = pmt2Pedestal[index]; - if (pmt1PedestalLocal == 0.0f && pmt2PedestalLocal == 0.0f) { - logger.debug("TILE pmt[1,2]Pedestal are not available (i.e. " + - "are 0.0f), using minimum of first and last " + - "adcCount digit as pedestal."); - float last1 = adcCounts1[index][adcCounts1[index].length - 1]; - float last2 = adcCounts2[index][adcCounts2[index].length - 1]; - pmt1PedestalLocal = Math.min(adcCounts1[index][0], last1); - pmt2PedestalLocal = Math.min(adcCounts2[index][0], last2); - } - - try { - for (int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) { - d += step; - realPulseRaw[0][i] = - getPhysicsPulseShape(d, pmt1RawTime[index], pmt1PedestalLocal, - pmt1RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - realPulseRaw[1][i] = - getPhysicsPulseShape(d, pmt2RawTime[index], pmt2PedestalLocal, - pmt2RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - } - } catch (AAtlantisException aaex) { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - return null; - } - - return realPulseRaw; - } - - protected double[][] getPulseShapeCellTime(int index) { - - if (!pulseShapesDataAvailable) return null; - - double step = getPulseStep(index); - double[][] realPulse = new double[2][NUMBER_OF_LOOKUP_VALUES]; // 2 channels - double d = 1.0; - - // by zdenek 2008-11-25 - // DPD (slimed version of ESD) sometimes don't have pmt[1,2]Pedestal - // for a cell (the tag exists, values are there, but are 0). check - // if pedestal is 0 and if so, take as pedestal value the first - // adc count digit - float pmt1PedestalLocal = pmt1Pedestal[index]; - float pmt2PedestalLocal = pmt2Pedestal[index]; - if (pmt1PedestalLocal == 0.0f && pmt2PedestalLocal == 0.0f) { - logger.debug("TILE pmt[1,2]Pedestal are not available (i.e. " + - "are 0.0f), using minimum of first and last " + - "adcCount digit as pedestal."); - float last1 = adcCounts1[index][adcCounts1[index].length - 1]; - float last2 = adcCounts2[index][adcCounts2[index].length - 1]; - pmt1PedestalLocal = Math.min(adcCounts1[index][0], last1); - pmt2PedestalLocal = Math.min(adcCounts2[index][0], last2); - } - - try { - for (int i = 0; i < NUMBER_OF_LOOKUP_VALUES; i++) { - d += step; - realPulse[0][i] = - getPhysicsPulseShape(d, pmt1Time[index], pmt1PedestalLocal, - pmt1RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - realPulse[1][i] = - getPhysicsPulseShape(d, pmt2Time[index], pmt2PedestalLocal, - pmt2RawAmplitude[index], - ACalorimeterRPSPLT.TILE_AMPLITUDE, - ACalorimeterRPSPLT.TILE_TIME); - } - } catch (AAtlantisException aaex) { - AOutput.append(aaex.getMessage(), ALogInterface.WARNING); - return null; - } - - return realPulse; - } - - - @Override - protected double getPulseStep(int index) { - return (adcCounts1[index].length - 1) / (float) NUMBER_OF_LOOKUP_VALUES; - } - - @Override - protected String[] getPulseSubtitle(int index) { - String cap1 = "Real pulse shape " + "PMT " + pmt1Number[index] + - " gain " + pmt1Gain[index]; - String cap2 = "Real pulse shape " + "PMT " + pmt2Number[index] + - " gain " + pmt2Gain[index]; - return new String[]{cap1, cap2}; - } - - public void plotPulseShapesWithTiming(int index) { - - int[][] adc = getADCCounts(index); - double[][] raw = getPulseShape(index); - double[][] cell = getPulseShapeCellTime(index); - - if (adc == null || raw == null || cell == null) { - logger.warn("Pulse shapes with raw/cell times requested but no " + - "data available, falling back to regular pulse shapes"); - plotPulseShapes(index, true); - } else { - APulseShapePlot.plotRawCellPulseShapes(adc, raw, cell, - getPulseStep(index), getPulseSubtitle(index), - getPulseTitleString(index)); - } - - /*if (!withcurve) { - APulseShapePlot.plotADCCounts(adc, getPulseTitleString(index), null); - } else { - double[][] ps = getPulseShape(index); - if (ps == null) { - logger.warn("No pulse shape information available, just plotting adc instead"); - APulseShapePlot.plotADCCounts(adc, getPulseTitleString(index), null); - } else { - APulseShapePlot.plotRealPulseShapes(adc, ps, - getPulseStep(index), getPulseSubtitle(index), getPulseTitleString(index)); - } - }*/ - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ATRTData.java b/graphics/AtlantisJava/src/atlantis/data/ATRTData.java deleted file mode 100644 index c77849df8a9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATRTData.java +++ /dev/null @@ -1,752 +0,0 @@ -package atlantis.data; - -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.Vector; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.tree.DefaultMutableTreeNode; - -import atlantis.canvas.ACanvas; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.colormap.AColorMap; -import atlantis.list.AList; -import atlantis.list.AListManager; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AHashMap; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; - - -/** - * - * Transition Radiation Tracker data - * - * data from the event file - * id - processed by AData - * barcode (old) / barcodes and numBarcodes (new) - processed by AHitData - * phi - * rhoz - rho (for barrel) or z (for endcap) - * driftR - drift radius - * threshold - * sub - subdetector - * - * still need to have correct phi calculated from pVtx for cuts - * still need to have correct rho calculated from pVtx for cuts - * - */ -public class ATRTData extends AHitData -{ - protected float[] phi = null; - protected float[] rhoz = null; - protected float[] driftR = null; - protected int[] threshold = null; - protected int[] noise = null; - // bitPattern subtag information implemented in the retriever but - // currently (2009-01-21) not used or necessary but - // said to may become useful later - protected int[] bitPattern = null; - protected float[] timeOverThreshold = null; - protected HashMap<String, int[]> driftSign = new HashMap<String, int[]>(); - protected HashMap<String, int[]> isOutlier = new HashMap<String, int[]>(); - //error code for when driftSign/isOutlier is not present - private static final int NO_DATA =-99; - - - - public String getParameterGroup() - { - return "TRT"; - } - - - public String getName() - { - return "TRT"; - } - - - public String getNameScreenName() - { - return "TRT_DriftCircle"; - } - - - public int getDriftSign(int index) - { - //find current selection of track - AEnumeratorParameter listBox = (AEnumeratorParameter) parameterStore.get("InDetTrack", "InDetTrackCollections"); - String currentSelection = listBox.getCurrentText(); - if(driftSign!=null && !currentSelection.equals("All")) - { - //find data from current track - int[] data = (int[]) driftSign.get(currentSelection); - if(data!=null) - return data[index]; - } - //no present so return error code - return NO_DATA; - } - - - public int getIsOutlier(int index) - { - //find current selection of track - AEnumeratorParameter listBox = (AEnumeratorParameter) parameterStore.get("InDetTrack", "InDetTrackCollections"); - String currentSelection = listBox.getCurrentText(); - if(isOutlier!=null && !currentSelection.equals("All")) - { - //find data from current track - int[] data = (int[]) isOutlier.get(currentSelection); - if(data!=null) - return data[index]; - } - //no present so return error code - return NO_DATA; - } - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - StringBuilder s = new StringBuilder(); - String[] decodedId = AIdHelper.getFullIdentifier(id[index]); - s.append(getNameScreenName() + " (id: " + decodedId[0] + - " index: " + index + ")"); - // iterate over decodedId to get further details (if available), - // first item [0] was already printed out above - for(int i = 1; i < decodedId.length; i++) - { - s.append("\n " + decodedId[i]); - } - if(sub[index] == 1 || sub[index] == 2) - { - s.append("\n " + AMath.RHO + " = " + String.format("%.1f",rhoz[index]) + " cm"); - } - else - { - s.append("\n z = " + String.format("%.1f",rhoz[index]) + " cm"); - } - s.append("\n " + AMath.PHI + " = " + - String.format("%.1f",Math.toDegrees(phi[index])) + AMath.DEGREES + - " (" + String.format("%.3f",phi[index]) + " rad)" + - "\n drift radius = " + String.format("%.3f",driftR[index]) + " cm" + - "\n threshold = " + threshold[index] + - "\n sub = " + sub[index]); - - s.append(super.getHitInfo(index)); // finds barcode information - - int d = getDriftSign(index); - s.append((d!=NO_DATA) ? ("\n driftSign = " + d) : "\n driftSign = n/a"); - int o = getIsOutlier(index); - s.append((o!=NO_DATA) ? ("\n isOutlier = " + o) : "\n isOutlier = n/a"); - s.append("\n noise = " + (noise != null ? noise[index] : "n/a")); - s.append("\n time over threshold = " + - (timeOverThreshold != null ? timeOverThreshold[index] : "n/a")); - - return s.toString(); - - } // getHitInfo() ------------------------------------------------------- - - - public ATRTData(AHashMap p, AEvent e) - { - super(p,e); - phi = p.getFloatArray("phi"); - rhoz = p.getFloatArray("rhoz"); - driftR = p.getFloatArray("driftR"); - threshold = p.getUnknownIntArray("threshold"); - noise = p.getUnsureIntArray("noise"); - if(p.getIntArray("sub") == null) - { - for(int i=0; i<numData; i++) - { - sub[i] = getSub(id[i]); - } - } - // the way to retrieve bitPattern subtag information - // currently (2009-01-21) not used or necessary but - // said to may become useful later - // bitPattern = p.getIntArray("bitPattern"); - timeOverThreshold = p.getFloatArray("timeOverThreshold"); - - } // ATRTData() --------------------------------------------------------- - - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == numColorTypes + 1) // colour by Track Segment - { - colorBy(getSegments()); - } - else if(colorFunction == numColorTypes + 2) // colour by isOutlier - { - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - int iO = getIsOutlier(list); - if(iO==0) - color[list]= AColorMap.GN;//green - else if(iO==1) - color[list]= AColorMap.RD;//red - else - color[list]= (byte) parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - } - } - else if(colorFunction == numColorTypes + 3) // colour by driftSign - { - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - int ds = getDriftSign(list); - if(ds==-1) - color[list]= AColorMap.GN;//green - else if(ds==1) - color[list]= AColorMap.RD;//red - else - color[list]= (byte) parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - } - } - else if(colorFunction == numColorTypes + 4) // colour by threshold - { - for(int i=0; i<numDraw; i++) - { - int list = listdl[i]; - if(threshold[list]==1) - color[list]= AColorMap.RD; // red is preferable then previous green - else - color[list]= (byte) parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - } - } - return numColorTypes + 1; - - } // internalColor() ---------------------------------------------------- - - - - public int getLayer(int id) - { - try { - return AIdHelper.trtLayerWheel(id); - } catch (AAtlantisException e) { - return 0; - } - //return(id & 0x01F00000) >> 20; before using IDHelper - } - - - - public int getSub(int id) - { - try { - return AIdHelper.trtBarrelEndcap(id); - } catch (AAtlantisException e) { - return 0; - } - //return(id & 0x06000000) >> 25; before using IDHelper - } - - - - protected void applyCuts() - { - cutIndex(); - cut("CutsInDet", "Threshold", " Threshold", threshold); - cutSimulatedTracks(); - cutReconstructedTracks(); - cutSegments(); - cutPhi(phi); - cutEta(); - - // cut noise - if(noise != null && parameterStore.get("CutsInDet", "Noise").getStatus()) - { - cutArray(noise, 0, "TRT Noise Cut"); - } - - // cut TimeOverThreshold - // method takes care that the cut is actually turned on - // or if the timeOverThreshold array is null (n/a in the event file) - cut("CutsInDet", "TRTTimeOverThreshold", - "TRTTimeOverThreshold", timeOverThreshold); - } - - - - private void keepBarrel() - { - int num = 0; - int cutSub = parameterStore.get("CutsInDet", "TRT").getI(); - for(int i = 0; i < numDraw; i++) - { - // sub values 1 and 2 - barrel - if(sub[listdl[i]] == 1 || sub[listdl[i]] == 2) - { - if(cutSub == -1 || sub[listdl[i]] == cutSub) - { - listdl[num++] = listdl[i]; - } - } - } - numDraw = num; - } - - - - private void keepEndcap() - { - int num = 0; - for(int i = 0; i < numDraw; i++) - { - // sub values 0 and 3 - endcaps - if(sub[listdl[i]] == 0 || sub[listdl[i]] == 3) - { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - - - private void cutEta() - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - if(!par.getStatus())return; - double etaCut = par.getD(); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double z1, z2, r1, r2; - if(sub[list] == 0 || sub[list] == 3) - { - // endcap - z1 = rhoz[list]; - z2 = rhoz[list]; - r1 = 64.; - if(Math.abs(rhoz[list]) > 280.) r1 = 48.; - r2 = 103.; - } - else - { - // barrel - z1 = 0.35; - if(rhoz[list] < 62) z1 = 40.; - z2 = 74.2; - if(sub[list] == 1) - { - z1 *= -1.; - z2 *= -1.; - } - r1 = rhoz[list]; - r2 = rhoz[list]; - } - double eta1 = AParameterUtilities.eta(z1, r1); - double eta2 = AParameterUtilities.eta(z2, r2); - double etaLower = Math.min(eta1, eta2); - double etaUpper = Math.max(eta1, eta2); - if(etaUpper > etaLowerCut && etaLower < etaUpperCut) - listdl[num++] = list; - } - numDraw = num; - } - - - // in XY only TRT barrel data are displayed - protected ACoord getYXUser() - { - makeDrawList(); - keepBarrel(); - double zoomScaling=0; - //check if zoomed in enough to display circles/drift sign arrows - Point2D.Double[] corners = ACanvas.getCanvas().getPaintingWindow().getUserCorners(); - double widthx=corners[1].x-corners[0].x; - double widthy=corners[0].y-corners[2].y; - //average width of window - double width=Math.sqrt(widthx*widthx+widthy*widthy); - //calculate scaling (100 is arbitrary constant) - zoomScaling=100/width; - //now return relevant user coords depending on the zoom - //(0.25 is arbitrary constant increase to turn on drawing - // circles and arrows at a more zoomed in state) - if(zoomScaling>0.25) - return getYXUserCircle(); - else - return getYXUserNormal(); - } - - - /** - * Will give coords for a line along the TRT drift - */ - private ACoord getYXUserNormal() - { - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double r = rhoz[list]; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double d = driftR[list]; - double x = r * cosPhi; - double y = r * sinPhi; - hv[0][0][i] = x + d * sinPhi; - hv[1][0][i] = y - d * cosPhi; - hv[0][1][i] = x - d * sinPhi; - hv[1][1][i] = y + d * cosPhi; - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - - /** - * Will give coords for the drift circle and arrow showing the drift - */ - private ACoord getYXUserCircle() - { - int numPoints = 48; - int[] index = new int[numDraw]; - double[][][] hv = new double[2][numDraw][]; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int ds = getDriftSign(list); - //adjust ds if z<0 - if(sub[list] == 1) - { - ds *= -1; - } - if(ds==1 || ds==-1) - { - //has drift sign so has extra points for arrow - hv[0][i] = new double[numPoints+3]; - hv[1][i] = new double[numPoints+3]; - } - else - { - hv[0][i] = new double[numPoints]; - hv[1][i] = new double[numPoints]; - ds=0; - } - double r = rhoz[list]; - double cosPhi = Math.cos(phi[list]); - double sinPhi = Math.sin(phi[list]); - double d = driftR[list]; - double x = r * cosPhi; - double y = r * sinPhi; - int jstart=0; - //calculate starting point of circle - if(ds==1 || ds ==-1) - { - jstart = (int) (phi[list]/(Math.PI * 2 / (numPoints - 1))); - d*=ds; - } - //store points of circle - int count=0; - for (int j = jstart; j < numPoints; j++) - { - hv[0][i][count] = x + d * Math.sin(Math.PI * 2 * j / (numPoints - 1)); - hv[1][i][count] = y - d * Math.cos(Math.PI * 2 * j / (numPoints - 1)); - count++; - } - for (int j = 0; j < jstart; j++) - { - hv[0][i][count] = x + d * Math.sin(Math.PI * 2 * (j+1) / (numPoints - 1)); - hv[1][i][count] = y - d * Math.cos(Math.PI * 2 * (j+1) / (numPoints - 1)); - count++; - } - index[i] = list; - //if has drift show arrow - if(ds==1 || ds==-1) - { - //first line - hv[0][i][numPoints] = hv[0][i][2*(numPoints-1)/5]; - hv[1][i][numPoints] = hv[1][i][2*(numPoints-1)/5]; - //back to end point of circle - hv[0][i][numPoints+1] = hv[0][i][numPoints-1]; - hv[1][i][numPoints+1] = hv[1][i][numPoints-1]; - //second line - hv[0][i][numPoints+2] = hv[0][i][3*(numPoints-1)/5]; - hv[1][i][numPoints+2] = hv[1][i][3*(numPoints-1)/5]; - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } - - - protected ACoord getRZUser() - { - // correction for primary vertex - if(!parameterStore.get("RZ", "TRT").getStatus())return ACoord.NO_DATA; - makeDrawList(); - // line size was found using findRZActiveArea(){ - // may need to be found again if geometry changes... - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - if(sub[list] == 0 || sub[list] == 3) - { - // endcap - hv[0][0][i] = rhoz[list]; - hv[0][1][i] = rhoz[list]; - double phiDiff = Math.abs(phi[list] - phiMid); - double r1 = 64.; - if(Math.abs(rhoz[list]) > 280.) r1 = 48.; - double r2 = 103.; - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - { - hv[1][0][i] = r1; - hv[1][1][i] = r2; - } - else - { - hv[1][0][i] = -r1; - hv[1][1][i] = -r2; - } - } - else - { - // barrel - double z1 = 0.35; - if(rhoz[list] < 62) z1 = 40.; - double z2 = 74.2; - if(sub[list] == 1) - { - z1 *= -1.; - z2 *= -1.; - } - hv[0][0][i] = z1; - hv[0][1][i] = z2; - double phiDiff = Math.abs(phi[list] - phiMid); - if(phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - { - hv[1][0][i] = rhoz[list]; - hv[1][1][i] = rhoz[list]; - } - else - { - hv[1][0][i] = -rhoz[list]; - hv[1][1][i] = -rhoz[list]; - } - } - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES); - } - - - protected ACoord getFRUser() - { - makeDrawList(); - keepBarrel(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - double[] pVtx = event.getPrimaryVertex(); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double r = rhoz[list]; - double p = phi[list]; - double x = r * Math.cos(p); - double y = r * Math.sin(p); - double dx = x - pVtx[0]; - double dy = y - pVtx[1]; - r = Math.sqrt(dx * dx + dy * dy); - p = Math.atan2(dy, dx); - if(p < 0.) p += AMath.TWO_PI; - double delPhi = driftR[list] / r; - hv[0][0][i] = r; - hv[1][0][i] = Math.toDegrees(p - delPhi); - hv[0][1][i] = r; - hv[1][1][i] = Math.toDegrees(p + delPhi); - index[i] = list; - } - return new ACoord(hv, index, this, ACoord.LINES).includePhiWrapAround("FR"); - } - - - - protected ACoord getFZUser() - { - makeDrawList(); - keepEndcap(); - double[][][] hv = new double[2][2][numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double z = rhoz[list]; - // average rho from findRZActiveArea() - double averageRho = 81.; - if(Math.abs(z) > 280.) - averageRho = 70.; - double p = phi[list]; - double delPhi = driftR[list] / averageRho; - hv[0][0][i] = z; - hv[1][0][i] = Math.toDegrees(p - delPhi); - hv[0][1][i] = z; - hv[1][1][i] = Math.toDegrees(p + delPhi); - index[i] = list; - } - return new ACoord(hv, index, this, - ACoord.LINES).includePhiWrapAround("FZ"); - } - - - public Action[] getActions(Collection nodes) - { - if(nodes.size() != 1) - return new Action[0]; - final DefaultMutableTreeNode node = (DefaultMutableTreeNode) (nodes. - iterator().next()); - AList[] list = AListManager.getInstance().getChildren(node); - if(list == null)return new Action[0]; - Set hits = new HashSet(); - for(int i = 0; i < list.length; ++i) - { - if(list[i].getSource() == this) - { - for(int j = 0; j < list[i].getItems().length; j++) - { - hits.add(new Integer(list[i].getItems()[j])); - } - } - else - { - return new Action[0]; - } - } - int numHits = hits.size(); - if(numHits < 2) - return new Action[0]; - final int[] h = new int[numHits]; - Iterator i = hits.iterator(); - int n = 0; - while(i.hasNext()) - { - h[n++] = ((Integer) (i.next())).intValue(); - } - Action[] action = new Action[1]; - action[0] = new AbstractAction("Find Eta") - { - public void actionPerformed(ActionEvent e) - { - final double MIN = 9999.; - final double MAX = -9999.; - double minRho = MIN; - double maxRho = MAX; - double minZ = MIN; - double maxZ = MAX; - for(int i = 0; i < h.length; ++i) - { - if(sub[h[i]] == 1 || sub[h[i]] == 2) - { - minRho = Math.min(minRho, rhoz[h[i]]); - maxRho = Math.max(maxRho, rhoz[h[i]]); - } - else - { - minZ = Math.min(minZ, rhoz[h[i]]); - maxZ = Math.max(maxZ, rhoz[h[i]]); - } - } - AOutput.append("Eta results:\n minRho = " + - String.format("%.3f",minRho) + - " maxRho = " + String.format("%.3f",maxRho) + "\n" + - " minZ = " + String.format("%.3f",minZ) + - " maxZ = " + String.format("%.3f",maxZ) + "\n", - ALogInterface.NORMAL); - } - }; - return action; - } - - - @Override - protected void finalizeConstruction() { - super.finalizeConstruction(); - Vector keys = (Vector) event.getCollections().get("InDetTrack"); - if(keys != null) - { - Iterator keysIterator = keys.iterator(); - //loop over collections - while(keysIterator.hasNext()) - { - String trackCollec = (String) keysIterator.next(); - AInDetTrackData data = (AInDetTrackData) (event.get("InDetTrack" + trackCollec)); - int[][] hits = event.getAssociationManager().get("InDetTrack" + trackCollec, getName()); - int[][] drifts = event.getAssociationManager().get("InDetTrack" + trackCollec + "Drift", getName()); - int[][] outliers = event.getAssociationManager().get("InDetTrack" + trackCollec + "Outlier", getName()); - - if(drifts!=null || outliers!=null) - { - int[] driftSignData = new int[numData]; - int[] isOutlierData = new int[numData]; - //set to noData to distinguish from a 0 returned if the data is present - for(int i=0; i<this.numData; i++) - { - driftSignData[i]=NO_DATA; - isOutlierData[i]=NO_DATA; - } - //loop over alll hits in track collection - for(int i=0; i<data.getNumData(); i++) - { - for(int j=0; j<hits[i].length; j++) - { - //check if current hit matches a TRT index - int list=getIndexFromId(hits[i][j]); - if(list!=-1) - { - //found match so save value if not null - if(drifts!=null) - driftSignData[list] = drifts[i][j]; - if(outliers!=null) - isOutlierData[list] = outliers[i][j]; - } - } - } - //if has data in file then save array of values - if(drifts!=null) - driftSign.put(trackCollec, driftSignData); - if(outliers!=null) - isOutlier.put(trackCollec, isOutlierData); - } - //no data for this collection in file so save null to vector - if(drifts==null) - driftSign.put(trackCollec, null); - if(outliers==null) - isOutlier.put(trackCollec, null); - } - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ATauJetData.java b/graphics/AtlantisJava/src/atlantis/data/ATauJetData.java deleted file mode 100755 index 91ebb9af775..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATauJetData.java +++ /dev/null @@ -1,198 +0,0 @@ -package atlantis.data; - -import java.util.Vector; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; -import atlantis.utils.A4Vector; - -/** - * Reconstructed Tau Jet - */ -public class ATauJetData extends AAODData -{ - // Note: This is a hierarchy list ! I.e. TauCutTight is assumed to have passed - // all other criteria as well. This is strictly not completely correct but - // good enough for Atlantis purposes. - private enum isTau { TauCutTight, TauCutMedium, TauCutLoose, TauLlhTight, TauLlhMedium, TauLlhLoose, none } - - private float[] charge; - private int[] integerCharge; - private int[] numTracks; - private float[] isolFrac; - private float[] logLhRatio; - private String[] label; - private Vector<Enum> isTauEnum = new Vector<Enum>(); - - ATauJetData(AHashMap p, AEvent e) - { - super(p,e); - charge=p.getFloatArray("charge"); - integerCharge = new int[charge.length]; - - // The recommended default cut for Tau charge is to equal to 1/-1, - // but the cut for float value has no "=" operator in the - // implementation, so change float[] to int[] to make it possible - // to use "=". - for(int i=0; i<charge.length; ++i) - { - integerCharge[i] = (int) charge[i]; - } - numTracks=p.getUnknownIntArray("numTracks"); - isolFrac=p.getUnsureFloatArray("isolFrac"); - logLhRatio=p.getUnsureFloatArray("logLhRatio"); - label=p.getUnsureStringArray("label"); - String[] isTauString=p.getUnsureStringArray("isTauString"); - - if(isTauString!=null){ - for(String s : isTauString) - { - try { - isTauEnum.add(isTau.valueOf(s)); - } - catch(IllegalArgumentException q) { - isTauEnum.add(isTau.none); - } - } - } - else - { - for(int i=0;i<numData;i++) - { - isTauEnum.add(isTau.none); - } - } - } - - public String getParameterGroup() - { - return "TauJet"; - } - - public String getName() - { - return "TauJet"; - } - - public float getCharge(int index) - { - return charge[index]; - } - - public int getNumTracks(int index) - { - return numTracks[index]; - } - - public float getIsolFrac(int index) - { - if(isolFrac != null) return isolFrac[index]; - else return -100; - } - - public float getLogLhRatio(int index) - { - if(logLhRatio != null) return logLhRatio[index]; - else return -100; - } - - public String getisTau(int index) - { - return isTauEnum.get(index).toString(); - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) - { - int k = list[i]; - A4Vector start = new A4Vector(); - start.setPtEtaPhiM(pT[k],eta[k],phi[k],1.77682); - sum.add(start); - } - - return sum; - } - - protected void applyCuts() - { - super.applyCuts(); - cut("CutsObjects", "TauJetPt", " |ET|", pT); - cut("CutsObjects", "TauJetCharge", " |Charge|", integerCharge); - cut("CutsObjects", "TauJetNumTracks", " |NumTracks|", numTracks); - if(isolFrac != null) - cut("CutsObjects", "TauJetisolFrac", " isolFrac", isolFrac); - if(logLhRatio != null) - cut("CutsObjects", "TauJetlogLhRatio", " logLhRatio", logLhRatio); - - if (parameterStore.get("CutsObjects", "TauJetisTauString").getStatus()) - { - int cutSub = parameterStore.get("CutsObjects", "TauJetisTauString").getI(); - cutArrayEnum(isTauEnum, cutSub, "TauJet isTauString"); - } - } - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0){ - String output = getNameScreenName()+" index: " + index; - if(simpleOutput==1 || simpleOutput==3) - output+= "\n PT="+String.format("%.3f",pT[index])+" GeV\n "+ - AMath.ETA+" = "+String.format("%.3f",eta[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - if(simpleOutput==2 || simpleOutput==3) - output+= "\n Px="+String.format("%.3f",pT[index]*Math.cos(phi[index]))+" GeV "+ - "\n Py="+String.format("%.3f",pT[index]*Math.sin(phi[index]))+" GeV "+ - "\n Pz="+String.format("%.3f",pT[index]*Math.sinh(eta[index]))+" GeV "; - return output; - } - - String k = this.getStoreGateKey(); - String sgKey = k != null ? k : "n/a"; - StringBuffer msg = new StringBuffer(getNameScreenName()); - msg.append(" (id: " + id[index] + " index: " + index + ")"); - msg.append("\n storegate key: "); - msg.append(sgKey); - msg.append("\n PT = "); - msg.append(String.format("%.3f",pT[index])); - msg.append(" GeV\n P = "); - msg.append(String.format("%.3f",Math.abs(pT[index]/Math.cos(AMath.lambda(eta[index]))))); - msg.append(" GeV\n Charge = "); - msg.append(integerCharge[index]); - msg.append("\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.3f",eta[index])); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.3f",Math.toDegrees(phi[index]))); - msg.append(AMath.DEGREES); - msg.append(" (" + String.format("%.3f",phi[index]) + " rad)"); - msg.append("\n numTracks = "); - msg.append(numTracks[index]); - - if (label != null) - { - msg.append("\n label = "); - msg.append(label[index]); - } - if (isolFrac != null) - { - msg.append("\n isolFrac = "); - msg.append(isolFrac[index]); - } - if (logLhRatio != null) - { - msg.append("\n logLhRatio = "); - msg.append(logLhRatio[index]); - } - - return msg.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ATrackData.java b/graphics/AtlantisJava/src/atlantis/data/ATrackData.java deleted file mode 100644 index bc680fdd7b1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATrackData.java +++ /dev/null @@ -1,1389 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.canvas.ACanvas; -import atlantis.utils.AMath; -import atlantis.utils.AHashMap; -import atlantis.utils.AAtlantisException; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameterUtilities; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.projection.AProjectionXZ; -import atlantis.graphics.AGraphics; -import atlantis.canvas.AWindow; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjection3D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjectionPhi; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.A4Vector; -import atlantis.utils.ALogger; - -/** - * - * base class for ASTrData - Simulated Track - * AInDetTrackData - Reconstructed Inner Detector Track - * AMuonTrackData - Reconstructed Muon Detector Track - * - */ -public abstract class ATrackData extends AData -{ - private static final ALogger logger = ALogger.getLogger(ATrackData.class); - - public static final int DRAW_HELIX = 0; - public static final int DRAW_POLYLINE = 1; - public static final int DRAW_SMOOTH = 2; - public static final int DRAW_NEWHELIX = 3; - public static final int ADD_HELIX_POINTS = 0; - - /** True if track residual is available */ - private boolean hasResidual = false; - - protected ATrackResidualData[] residuals = null; - - /** True if reconstructed track event data contains polyline information */ - protected boolean polylinedTrack = false; - - // these attributes are used to store polyline coordinates of tracks - protected float x[][] = null; - protected float y[][] = null; - protected float z[][] = null; - protected float rho[][] = null; - protected float phi[][] = null; - - protected int numHelix[] = null; - protected boolean cosmic[] = null; - - protected AHelix[] h = null; - - /** - * rhoVertex value - for STr provided in the event file, for reconstructed - * track (Track) it is calculated from first polyline coordinates. - * This value is tested in cutRhoVertexAfterInDetRadius() method. - */ - protected float[] rhoVertex = null; - - protected int[] index = null; - - protected float chi2[] = null; - protected int numDoF[] = null; - private int[] vertexType = null; - - // methods -------------------------------------------------------------- - - ATrackData(AHashMap p, AEvent e) throws AAtlantisException - { - super(p,e); - - String assocKey = getName() + getStoreGateKey(); - if (p.get("barcode") != null) - { - int[] barcode = p.getUnknownIntArray("barcode"); - AAssociation assoc = new AAssociation(assocKey, "STr", null, barcode, event); - event.getAssociationManager().add(assoc); - } - //Get vertex type numbers - vertexType = p.getUnsureIntArray("vertexType"); - // if residual information is provided, second check is a workaround for a JiveXML bug -- EJ - if(p.get("numTsos")!=null && p.get("tsosPullLoc1")!=null) - { - hasResidual = true; - residuals = new ATrackResidualData[numData]; - int[] numTsos = p.getIntArray("numTsos"); - float[] tsosPullLoc1 = p.getFloatArray("tsosPullLoc1"); - float[] tsosResLoc1 = p.getFloatArray("tsosResLoc1"); - float[] tsosPullLoc2 = p.getFloatArray("tsosPullLoc2"); - float[] tsosResLoc2 = p.getFloatArray("tsosResLoc2"); - String[] tsosDetType = p.getUnsureStringArray("tsosDetType"); - - int num = 0; - for(int i=0; i<numData; i++) - { - int numPoints = numTsos[i]; - float[] pullLoc1 = new float[numPoints]; - float[] resLoc1 = new float[numPoints]; - float[] pullLoc2 = new float[numPoints]; - float[] resLoc2 = new float[numPoints]; - String[] detType = null; - if(tsosDetType != null) - detType = new String[numPoints]; - - for(int j=0; j<numPoints; j++) - { - pullLoc1[j] = tsosPullLoc1[num]; - resLoc1[j] = tsosResLoc1[num]; - pullLoc2[j] = tsosPullLoc2[num]; - resLoc2[j] = tsosResLoc2[num]; - if(tsosDetType != null) - detType[j] = tsosDetType[num]; - num++; - } - residuals[i] = new ATrackResidualData(this, i, numPoints, pullLoc1, - resLoc1, pullLoc2, resLoc2, detType); - } - } - - // helix may come in different formats: - // * helix track from reconstructed track ? - if (p.get("d0") != null) - { - h = new AHelix[numData]; - - float[] d0 = p.getFloatArray("d0"); - float[] phi0 = p.getFloatArray("phi0"); - float[] tl = p.getFloatArray("cotTheta"); - float[] pt = p.getFloatArray("pt"); - float[] z0 = p.getFloatArray("z0"); - - // this patch is useful when reading old event files generated by - // some older version of JiveXML, in which cotTheta is set to inf by - // error when eta equals to 0 for IDScan Tracks - if ("TrigInDetTrack".equals((String) p.get("storeGateKey"))) - { - for(int i = 0; i < tl.length; i++) - { - if(Float.isInfinite(tl[i])) - tl[i] = 0.0f; - } - } // end of the patch - - // 2005-11-16 - numbers in event file in covMatrix too small, a lot - // of them were 0.00000 hence multiplied by 10000 in JiveXML and - // divided here by 10000. only Vertex fitter affected, didn't work - // before anyway, so numbers are divided for all events - if (p.get("covMatrix") != null) - { - float[][][] cov = new float[numData][5][5]; - float[] covMatrix = p.getFloatArray("covMatrix"); - // dividing numbers - for (int i = 0; i < covMatrix.length; i++) - { - covMatrix[i] = covMatrix[i] / 10000; - } - - int n = 0; - for (int i = 0; i < numData; i++) - { - for (int j = 0; j < 5; j++) - { - for (int k = 0; k < j + 1; k++) - { - cov[i][j][k] = covMatrix[n++]; - cov[i][k][j] = cov[i][j][k]; - } - } - - h[i] = new AHelix(d0[i], z0[i], (float) Math.toDegrees(phi0[i]), tl[i], pt[i], cov[i]); - } - } - else - { - for (int i = 0; i < numData; i++) { - h[i] = new AHelix(d0[i], z0[i], (float) Math.toDegrees(phi0[i]), tl[i], pt[i]); - } - } - } - // * helix track from simulated charged tracks ? - else if (p.get("rhoVertex") != null) - { - h = new AHelix[numData]; - - // STr - save rhoVertex value for tests - rhoVertex = p.getFloatArray("rhoVertex"); - float[] rhoEndVertex = p.getFloatArray("rhoEndVertex"); - float[] pt = p.getFloatArray("pt"); - float[] phi = p.getFloatArray("phi"); - float[] eta = p.getFloatArray("eta"); - float[] phiVertex = p.getFloatArray("phiVertex"); - float[] zVertex = p.getFloatArray("zVertex"); - // charge is calculated in ASTrData, based on code subtag - // information and pdg.xml data - int[] charge = p.getIntArray("charge"); - for (int i = 0; i < numData; i++) - { - //Create helix w/ end vertex information if rhoEndVertex is set - if ( rhoEndVertex[i] != 0.0 ) - h[i] = new AHelix(rhoVertex[i], phiVertex[i], zVertex[i], pt[i], - (float)Math.toDegrees(phi[i]), eta[i], charge[i], rhoEndVertex[i]); - //Otherwise create helix w/o end vertex information - else - h[i] = new AHelix(rhoVertex[i], phiVertex[i], zVertex[i], pt[i], - (float)Math.toDegrees(phi[i]), eta[i], charge[i] ); - } - } - - // if polyline information is provided for tracks - if(p.get("numPolyline") != null) - { - int[] numPolyline = p.getIntArray("numPolyline"); - - boolean hasPolyline = false; - for (int i=0; i<numData; i++) { - if (numPolyline[i] > 0) { - hasPolyline = true; - break; - } - } - - if (hasPolyline) { - polylinedTrack = true; - x = new float[numData][]; - y = new float[numData][]; - z = new float[numData][]; - rho = new float[numData][]; - phi = new float[numData][]; - rhoVertex = new float[numData]; - numHelix = new int[numData]; - cosmic = new boolean[numData]; - - float[] polyX = p.getFloatArray("polylineX"); - float[] polyY = p.getFloatArray("polylineY"); - float[] polyZ = p.getFloatArray("polylineZ"); - int num = 0; - - for(int i = 0; i < numData; ++i) - { - numHelix[i] = 0; - cosmic[i] = false; - - // Do some checks on the track, decide what drawing we enable/disable for it. - if (numPolyline[i] >= 2) { - int first = num; - int next = num+1; - - // Find the next different point on the track. - while (next < numPolyline[i]-1 && polyX[next]==polyX[first] && polyY[next]==polyY[first]) next++; - - // Determine what direction the track has in rho and z. - float rStart = (float)Math.sqrt(polyX[first]*polyX[first] + polyY[first]*polyY[first]); - float rDir = (float)Math.sqrt(polyX[next]*polyX[next] + polyY[next]*polyY[next]) - rStart; - float zDir = Math.abs(polyZ[next]) - Math.abs(polyZ[first]); - - // Now in order to extrapolate to the IP we the track to: - // - go radially outwards - // - go away from the IP in z - // - have perigee parameters - // - have its first polyline point some distance from the perigee - // - be an InDetTrack - if (rDir > 0 && zDir > 0 && h != null && h[i] != null && rStart-Math.abs(h[i].d0()) > 1 - && this instanceof AInDetTrackData) { - numHelix[i] = ADD_HELIX_POINTS; - } - - // Check if this is perhaps a cosmic. Cosmics are allowed - // to be drawn on both sides in the rho-z projection - if (rDir < 0) { - cosmic[i] = true; - } - } else if (h != null && h[i] != null && this instanceof AInDetTrackData) { - - // In case of a track with only perigee parameters, draw it also as a helix. - numHelix[i] = ADD_HELIX_POINTS; - } - - x[i] = new float[numPolyline[i]+numHelix[i]]; - y[i] = new float[numPolyline[i]+numHelix[i]]; - z[i] = new float[numPolyline[i]+numHelix[i]]; - rho[i] = new float[numPolyline[i]+numHelix[i]]; - phi[i] = new float[numPolyline[i]+numHelix[i]]; - - for(int j = 0; j < numPolyline[i]; ++j) - { - x[i][j+numHelix[i]] = polyX[num]; - y[i][j+numHelix[i]] = polyY[num]; - z[i][j+numHelix[i]] = polyZ[num]; - rho[i][j+numHelix[i]] = (float)Math.sqrt(polyX[num]*polyX[num]+polyY[num]*polyY[num]); - num++; - - if(j == 0) - { - // first coordinate of a track - calculate rhoVertex - rhoVertex[i] = (float) Math.sqrt( x[i][numHelix[i]] * x[i][numHelix[i]] + - y[i][numHelix[i]] * y[i][numHelix[i]] ); - } - } - - if (h != null && h[i] != null) { - h[i].setPoints(x[i], y[i], z[i], numPolyline[i]); - } - - // When perigee parameters are available we extend the track all the way down to the IP - if (numHelix[i] > 0) { - // Radius of curvature of this track in the magnetic field - double R = parameterStore.get("Event", "Curvature").getD() * Math.abs(h[i].pT()); - - // +1/-1 for a clockwise/anti-clockwise helix - double S = AMath.getSign(h[i].pT()); - - // Coordinates of the center point for the helix - double xC = (S * h[i].d0() - R) * Math.cos(Math.toRadians(h[i].phi0()) + S * Math.PI / 2.); - double yC = (S * h[i].d0() - R) * Math.sin(Math.toRadians(h[i].phi0()) + S * Math.PI / 2.); - - // Determine to what radius we have to draw this track based on its - // perigee parameters. When space points are available for the track - // we stop before the first space point and make a smooth connection. - // If no space points are available we draw all the way through the - // inner detector. Not any further though, because the track will stop - // curving when it leaves the magnetic field. - double Rmax; - if (numPolyline[i] > 0) { - Rmax = Math.min(parameterStore.get("RTr", "RadiusTr").getD(), - Math.abs(Math.sqrt(x[i][numHelix[i]]*x[i][numHelix[i]] - + y[i][numHelix[i]]*y[i][numHelix[i]]) - 1)); - } else { - Rmax = parameterStore.get("RTr", "RadiusTr").getD(); - } - - // Calculate the phi value at which our helix intersects the maximum - // radius determined above. We have one circle (detector) centered at - // the origin with radius Rmax. The other circle (helix) we imagine to - // be at x=d with a radius R. Now we can easily calculate the coordinates - // (xI,+/-yI) of the intersection points. The curving direction of the - // helix determines which value of yI we have to use. Finally, the phiMax - // we're interested in is the polar angle with respect to the center of the - // helix at x=d. Calculation is straightforward. By adding phi0+S*PI/2 - // (as we do below) this solution is also valid for helices centered - // around y!=0. - double d = Math.sqrt(xC * xC + yC * yC); - double xI = (Rmax * Rmax - R * R + d * d) / (2 * d); - double yI = Math.sqrt(Rmax * Rmax - xI * xI); - double phiMax = Math.atan2(S * yI, d - xI); - - // This spreads the number of helix points evenly across the part of the - // helix we're going to draw - double dphi = phiMax / numHelix[i]; - - for (int j=0; j<numHelix[i]; j++) { - // Points on the helix in user coordinates - x[i][j] = (float) (xC + R * Math.cos(Math.toRadians(h[i].phi0()) + S * Math.PI/2. - j * dphi)); - y[i][j] = (float) (yC + R * Math.sin(Math.toRadians(h[i].phi0()) + S * Math.PI/2. - j * dphi)); - - // In R-Z the track is just a straight line - rho[i][j] = (float) Math.sqrt(x[i][j]*x[i][j] + y[i][j]*y[i][j]); - z[i][j] = (float) (h[i].z0() + h[i].cotanTheta() * (rho[i][j] - h[i].d0())); - } - } - - for (int j=0; j<numPolyline[i]+numHelix[i]; j++) { - phi[i][j] = (float)Math.atan2(y[i][j], x[i][j]); - - if (j>0 && Math.abs(phi[i][j-1]-phi[i][j]) > Math.PI) { - - // Don't let phi wrap around - if (phi[i][j] > phi[i][j-1]) { - phi[i][j] -= 2*Math.PI; - } else { - phi[i][j] += 2*Math.PI; - } - } - } - } - } - } // if(p.get("numPolyline") - - if (h != null) - { - double[] phi = new double[numData]; - for (int i = 0; i < numData; i++) - phi[i] = h[i].phi0(); - index = indexBy(phi); - } - else if(x != null && y != null) - { - double[] phi = new double[numData]; - for(int i = 0; i < numData; i++) - { - // if number of polylines for a track is 0 - Atlantis used - // to crash here with IndexOutOfBoundException - // check to avoid crashes with old events, from some point - // JiveXML doesn't output tracks with number of polylines - // coordinates less then 2 - if(x[i].length > 0 && y[i].length > 0) - { - phi[i] = Math.toDegrees(Math.atan2(y[i][0], x[i][0])); - } - else - { - String m = getName() + ":" + getStoreGateKey() + - " datatype rejected\n" + - "(no polyline coordinates)."; - throw new AAtlantisException(m, false); // non fatal - } - } - index = indexBy(phi); - } - - if (p.get("chi2") != null) chi2 = p.getFloatArray("chi2"); - if (p.get("numDoF") != null) numDoF = p.getIntArray("numDoF"); - } // ATrackData() ------------------------------------------------------- - - - public float[][] getX() - { - return x; - } - - public float[][] getY() - { - return y; - } - - public float[][] getZ() - { - return z; - } - - public float[][] getRho() - { - return rho; - } - - public float[][] getPhi() - { - return phi; - } - - public boolean getResidualStatus() - { - return hasResidual; - } - - public ATrackResidualData getTrackResidual(int index) - { - return residuals[index]; - } - - // moved from the former iPatData class where it was without the condition - protected void calculateRhoPhi() - { - if(!polylinedTrack) { - super.calculateRhoPhi(); - } - } // calculateRhoPhi() -------------------------------------------------- - - - - protected void applyCuts() - { - cutIndex(); - if (h != null) - { - cut("CutsInDet", "z0-zVtx", " |z0-zVtx|", getZ0Primary()); - cut("CutsInDet", "z0", " |z0|", getZ0()); - cut("CutsInDet", "Pt", " |Pt|", getPt()); - cut("CutsInDet", "d0", " |d0|", getD0()); - cut("CutsInDet", "d0Loose", " |d0Loose|", getD0()); - } - cutPhi(); - cutEta(); - cutNextInDrawList(); - cutReconstructedVertex(); - } // applyCuts() -------------------------------------------------------- - - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+ - ((h!=null)?h[index].toString():""); - - - String msg = getNameScreenName() + " (id: " + id[index] + " index: " + index + ")"; - msg += "\n storegate key: "; - msg += (storeGateKey == null ? "n/a" : storeGateKey); - if (h != null) - msg += h[index].toString(); - if (chi2 != null && numDoF != null) - msg += "\n chi2/numDoF = " + chi2[index]/numDoF[index]; - return msg; - - } // getHitInfo() ------------------------------------------------------- - - - // all get**User() methods which are only called when tracks are drawn - // as polylines - protected ACoord getYXUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = x[list].length; - hv[0][i] = new double[numPoints]; - hv[1][i] = new double[numPoints]; - for(int j = 0; j < numPoints; j++) - { - hv[0][i][j] = x[list][j]; - hv[1][i][j] = y[list][j]; - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - else - return new ACoord(hv, index, this, ACoord.POLYLINES); - - } // getYXUser() -------------------------------------------------------- - - - - protected ACoord getFRUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = x[list].length; - int skip = 0; - - // Skip points with very small R, phi changes rapidly here - for (skip=0; skip<numPoints; skip++) - if (rho[list][skip] > 2.) break; - - hv[0][i] = new double[numPoints-skip]; - hv[1][i] = new double[numPoints-skip]; - - double phiStart = 0.; - if(numPoints > 0) phiStart = phi[list][0]; - for(int j = skip; j < numPoints; j++) - { - double phiTemp = phi[list][j]; - if(phiTemp - phiStart > Math.PI) phiTemp -= AMath.TWO_PI; - if(phiTemp - phiStart < -Math.PI) phiTemp += AMath.TWO_PI; - - hv[0][i][j-skip] = rho[list][j]; - hv[1][i][j-skip] = Math.toDegrees(phiTemp); - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES).includePhiWrapAround("FR"); - else - return new ACoord(hv, index, this, ACoord.POLYLINES).includePhiWrapAround("FR"); - - } // getFRUser() -------------------------------------------------------- - - - - protected ACoord getFZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = x[list].length; - int skip = 0; - - // Skip points with very small R, phi changes rapidly here - for (skip=0; skip<numPoints; skip++) - if (rho[list][skip] > 2.) break; - - hv[0][i] = new double[numPoints-skip]; - hv[1][i] = new double[numPoints-skip]; - // treat phi wraparound - double phiStart = 0.; - if(numPoints > 0) phiStart = phi[list][0]; - for(int j = skip; j < numPoints; j++) - { - hv[0][i][j-skip] = z[list][j]; - double phiTemp = phi[list][j]; - if(phiTemp - phiStart > Math.PI) phiTemp -= AMath.TWO_PI; - if(phiTemp - phiStart < -Math.PI) phiTemp += AMath.TWO_PI; - hv[1][i][j-skip] = Math.toDegrees(phiTemp); - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES).includePhiWrapAround("FZ"); - else - return new ACoord(hv, index, this, ACoord.POLYLINES).includePhiWrapAround("FZ"); - - } // getFZUser() -------------------------------------------------------- - - - - protected ACoord getRZUser() - { - // not quite correct need to split tracks crossing phi boundary - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = rho[list].length; - hv[0][i] = new double[numPoints]; - hv[1][i] = new double[numPoints]; - - if (numPoints > 0) { - int sign = AParameterUtilities.getRhoSign(x[list][numPoints-1], y[list][numPoints-1]); - for(int j = 0; j < numPoints; j++) - { - if (cosmic != null && cosmic[i]) { - sign = AParameterUtilities.getRhoSign(x[list][j], y[list][j]); - } - hv[0][i][j] = z[list][j]; - hv[1][i][j] = rho[list][j] * sign; - } - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - else - return new ACoord(hv, index, this, ACoord.POLYLINES); - - } // getRZUser() -------------------------------------------------------- - - - - protected ACoord getXZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = rho[list].length; - hv[0][i] = new double[numPoints]; - hv[1][i] = new double[numPoints]; - for(int j = 0; j < numPoints; j++) - { - hv[0][i][j] = z[list][j]; - hv[1][i][j] = rho[list][j] * Math.cos(phi[list][j] - phi0); - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - else - return new ACoord(hv, index, this, ACoord.POLYLINES); - - } // getXZUser() -------------------------------------------------------- - - protected ACoord getYZUser() - { - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - double phi0 = Math.toRadians(AProjectionXZ.getPhi()); - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - int numPoints = rho[list].length; - hv[0][i] = new double[numPoints]; - hv[1][i] = new double[numPoints]; - for(int j = 0; j < numPoints; j++) - { - hv[0][i][j] = z[list][j]; - hv[1][i][j] = rho[list][j] * Math.sin(phi[list][j] - phi0); - } - index[i] = list; - } - - if (parameterStore.get(PARAMETER_GROUP, "DrawnAs").getI() == DRAW_SMOOTH) - return new ACoord(hv, index, this, ACoord.SMOOTH_POLYLINES); - else - return new ACoord(hv, index, this, ACoord.POLYLINES); - - } // getYZUser() -------------------------------------------------------- - - - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(h != null && (projection instanceof AProjectionVP || projection instanceof AProjection3D)) - { - // in VPlot only helices are drawn, so try to draw tracks as helices - // in VPlot by default ignoring Track->DrawAs option for VPlot - drawHelix(window, ag, projection); - } - else - { - AParameter drawPar = parameterStore.get(PARAMETER_GROUP, "DrawnAs"); - int drawnAs = drawPar != null ? drawPar.getI() : DRAW_HELIX; - if (polylinedTrack && (h == null || drawnAs == DRAW_POLYLINE || drawnAs == DRAW_SMOOTH)) - { - // draw as polyline - ag.draw(window.calculateDisplay(getUser(projection))); - } - else if (h != null) - { - // draw as helix - drawHelix(window, ag, projection); - } - } - - } // draw() ------------------------------------------------------------- - - protected void cutRhoVertexAfterInDetRadius() - { - int num = 0; - int wrong = 0; - int list = 0; - double rho = 108; // 1.08m - double parRhoTr = parameterStore.get("RTr", "RadiusTr").getD(); - for(int i = 0; i < numDraw; i++) - { - list = listdl[i]; - if(this.rhoVertex[list] > Math.min(rho, parRhoTr)) - { - wrong++; - } - else - { - // include into drawlist - listdl[num++] = list; - } - } - - if(wrong > 0) - { - logger.debug("AHelix.cutRhoVertexAfterInDetRadius()"); - String key = this.getStoreGateKey(); - key = key != null ? ":" + key : ""; - logger.debug(" " + numDraw + " " + this.getName() + key + - " before test, " + wrong + " removed\n"); - } - numDraw = num; - } // cutRhoVertexAfterInDetRadius() ------------------------------------- - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - switch (colorFunction) - { - case 0: - colorByConstant(); - break; - case 1: - colorByIndex(index); - break; - case 2: - colorBy(getPt()); - break; - case 3: - colorByCollection(); - break; - case 4: - colorBy("STr"); - break; - case 5: - colorBy(getRVx()); - break; - case 6: - colorBy(getJets()); - break; - case 7: // by objects - colorByObjects(); - break; - } - - return 7; - } - - public int[] getDrawList() - { - int[] temp = new int[numDraw]; - System.arraycopy(listdl, 0, temp, 0, numDraw); - return temp; - } - - protected void cutNextInDrawList() - { - AParameter nextTrkPar = parameterStore.get(PARAMETER_GROUP, "NextTrack"); - if(!nextTrkPar.getStatus()) - { - return; - } - if(numDraw == 0) - { - return; - } - - int nextTrk = nextTrkPar.getI() % numData; - int nextTrkIndex = nextTrk; - boolean hasFound = false; - while (!hasFound) - { - for (int i=0; i<numDraw; ++i) - { - if(listdl[i] == nextTrk) - { - nextTrkIndex = nextTrk; - hasFound = true; - } - } - if(!hasFound) - nextTrk = (nextTrk + 1) % numData; - } - nextTrkPar.setI(nextTrkIndex); - numDraw = 1; - listdl[0] = nextTrkIndex; - } - - protected void cutPhi() - { - AParameter par = parameterStore.get("CutsATLAS", "CutPhi"); - boolean usePhiCut = par.getStatus(); - - if (usePhiCut) - { - // use degrees for tracks - double phiCut = par.getD(); - double phiMid = AMath.nearestPhiDegrees(parameterStore.get("CutsATLAS", "PhiMiddle").getD()); - // use vplot as projection - AProjection2D projection = (AProjection2D) AProjectionsManager.getProjection("VP"); - - int num = 0; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - ADHelix dH = new ADHelix(h[list]); - double s1 = dH.getAStart(); - double s2 = dH.getAEnd(); - s1 = dH.intersectWithRadialCylinder(projection.getMinRho(), s1, s2); - double sEnd = dH.intersectWithCylinder(true, AProjectionVP.getRhoVPlot(), true, AProjectionVP.getZVPlot()); - s2 = Math.max(Math.min(s2, sEnd), s1); - - double phiDiffStart = Math.abs(AMath.nearestPhiDegrees(dH.getPhi(s1), phiMid) - phiMid); - double phiDiffEnd = Math.abs(AMath.nearestPhiDegrees(dH.getPhi(s2), phiMid) - phiMid); - double phiDiffMiddle = Math.abs(AMath.nearestPhiDegrees(dH.getPhi((s1 + s2) / 2), phiMid) - phiMid); - // treats wrap around - int numPointsInside = 0; - - if (phiDiffStart < phiCut) - numPointsInside++; - if (phiDiffMiddle < phiCut) - numPointsInside++; - if (phiDiffEnd < phiCut) - numPointsInside++; - if (numPointsInside > 1) - listdl[num++] = list; - } - numDraw = num; - } - } - - /** - * Cut tracks if connected/unconnected to reconstructed vertices. - */ - protected void cutReconstructedVertex() - { - int cutOption = parameterStore.get("CutsObjects", "RTrsByRVtx").getI(); - cutByAssociationTo( "RVx", getReconstructedTracks(), cutOption); - } - - - protected void cutEta() - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - - if (par.getStatus()) - { - // use vplot as projection - AProjection2D projection = (AProjection2D) AProjectionsManager.getProjection("VP"); - - double etaCut = par.getD(); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaC1 = etaMid - etaCut; - double etaC2 = etaMid + etaCut; - int num = 0; - for (int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - ADHelix dH = new ADHelix(h[list]); - double s1 = dH.getAStart(); - double s2 = dH.getAEnd(); - s1 = dH.intersectWithRadialCylinder(projection.getMinRho(), s1, s2); - double sEnd = dH.intersectWithCylinder(true, AProjectionVP.getRhoVPlot(), true, AProjectionVP.getZVPlot()); - s2 = Math.max(Math.min(s2, sEnd), s1); - double[] etaPoints = new double[] { dH.getEta(s1), dH.getEta((s1 + s2) / 2), dH.getEta(s2) }; - - int numPointsInside = 0; - for (int j = 0; j < etaPoints.length; ++j) - if (etaC1 < etaPoints[j] && etaPoints[j] < etaC2) - numPointsInside++; - if (numPointsInside > 1) - listdl[num++] = list; - } - numDraw = num; - } - } - - // does not work correctly if primary vertex is displaced in YX plane - private float[] getZ0Primary() - { - double[] pVtx = event.getPrimaryVertex(); - float[] temp = new float[numData]; - double zVertex = pVtx[2]; - for (int i = 0; i < numDraw; i++) - temp[listdl[i]] = (float) (h[listdl[i]].z0() - zVertex); - return temp; - } - - private float[] getZ0() - { - float[] temp = new float[numData]; - for (int i = 0; i < numDraw; i++) - temp[listdl[i]] = (float) h[listdl[i]].z0(); - return temp; - } - - protected float[] getPt() - { - float[] temp = new float[numData]; - for (int i = 0; i < numDraw; i++) - temp[listdl[i]] = (float) h[listdl[i]].pT(); - return temp; - } - - - // d0 is calculated w.r.t. to XY position of the primary vertex - private float[] getD0() - { - double[] pVtx = event.getPrimaryVertex(); - float[] temp = new float[numData]; - for (int i = 0; i < numDraw; i++) - { - double phi0 = Math.toRadians(h[listdl[i]].phi0()); - - temp[listdl[i]] = (float) (-h[listdl[i]].d0() + pVtx[1] * Math.cos(phi0) - pVtx[0] * Math.sin(phi0)); - - } - return temp; - } - - - // give back Drawable helices - public ADHelix[] getHelices() - { - makeDrawList(); - ADHelix[] tempList = new ADHelix[numDraw]; - - for (int i = 0; i < numDraw; i++) - if (h != null && h[listdl[i]] != null) - { - tempList[i] = new ADHelix(h[listdl[i]]); - if (tempList[i].getAStart() == tempList[i].getAEnd()) - { - tempList[i] = null; - } - } - else - tempList[i] = null; - return tempList; - } - - // used by vertex package when changing the position on the helix from which - // to start drawing - public AHelix getModifiableHelix(int i) - { - if (h != null) - return h[i]; - else - return null; - } - - // info on tracks contained in vplot rubberband - public String getVPHitInfo() - { - makeDrawList(); - if (numDraw == 0) - return ""; - double sumP = 0.; - double sumPt = 0.; - - for (int i = 0; i < numDraw; ++i) - { - sumPt += Math.abs(h[listdl[i]].pT()); - sumP += AMath.getPFromPttL(h[listdl[i]].pT(), h[listdl[i]].cotanTheta()); - } - - String msg = numDraw + " " + getFullName(); - msg += " sum(PT) = " + String.format("%.1f",sumPt) + " sum(P) = " + String.format("%.1f",sumP); - return msg; - } - - public A4Vector get4Vector(int num, int[] list) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) { - if (h == null || h[list[i]] == null) continue; - // Use the pion mass (~140 MeV) here - sum.add(new A4Vector(h[list[i]].p(), 0.14)); - } - return sum; - } - - public A4Vector get4Vector(int num, int[] list, double mass) - { - A4Vector sum = new A4Vector(); - for (int i = 0; i < num; ++i) { - if (h == null || h[list[i]] == null) continue; - sum.add(new A4Vector(h[list[i]].p(), mass)); - - - } - return sum; - } - - public void zoomAroundTracks() - { - AWindow window = ACanvas.getCanvas().getCurrentWindow(); - AProjection projection = window.getProjection(); - if (projection instanceof AProjectionLegoPlot) - { - AOutput.append("Zoom Next Track unavailable for LegoPlot\n", ALogInterface.NORMAL); - } - else if (projection instanceof AProjection2D) - { - ACoord user; - if (projection instanceof AProjectionVP) - user = window.calculateUser(getVPDisplayHelices(window, (AProjection2D) projection)); - else if (polylinedTrack) - user = getUser((AProjection2D) projection); - else - user = window.calculateUser(getDisplayHelices(window, (AProjection2D) projection)); - double[] min = new double[2]; - double[] max = new double[2]; - min[0] = min[1] = 100000.; - max[0] = max[1] = -100000.; - for (int i = 0; i < 2; ++i) - for (int j = 0; j < user.hv[i].length; ++j) - for (int k = 0; k < user.hv[i][j].length; ++k) - { - if (user.hv[i][j][k] < min[i]) - min[i] = user.hv[i][j][k]; - if (user.hv[i][j][k] > max[i]) - max[i] = user.hv[i][j][k]; - } - // increase by 10% to improve appearence - for (int i = 0; i < 2; ++i) - { - double diff = (max[i] - min[i]) / 2.; - double middle = (max[i] + min[i]) / 2.; - if (diff > 0.) - { - max[i] = middle + 1.1 * diff; - min[i] = middle - 1.1 * diff; - } - } - // ensure entire trt hits included - if (projection instanceof AProjectionPhi) - { - min[1] -= 0.5; - max[1] += 0.5; - } - - if (max[0] - min[0] > 0 && max[1] - min[1] > 0) - { - window.setUserCorners(min[0], max[0], min[1], max[1]); - } - } - } - - public void drawHelix(AWindow window, AGraphics ag, AProjection2D projection) - { - if (projection instanceof AProjectionVP) - { - // phi wrap around is done in user coordinates, so we convert to user coordinates, - // do the phi wrap around and convert back to display coordinates - ag.draw(window.calculateDisplay(window.calculateUser( - getVPDisplayHelices(window, projection)).includePhiWrapAround(projection.getName()) - )); - } - else if (projection instanceof AProjectionRZ) - { - ag.draw(getRZDisplayHelices(window, projection)); - } - else if (projection instanceof AProjectionPhi) - { - // phi wrap around in user coordinates, see above - ag.draw(window.calculateDisplay(window.calculateUser( - getDisplayHelices(window, projection)).includePhiWrapAround(projection.getName()) - )); - - } - else - { - ag.draw(getDisplayHelices(window, projection)); - } - } - - // treat discontinuity when RZ sign changes crossing the phi boundary - private ACoord getRZDisplayHelices(AWindow window, AProjection2D projection) - { - ACoord display = getDisplayHelices(window, projection); - ACoord user = projection.inverseNonLinearTransform(window.calculateUser(display)); - - double[][] rho = user.hv[1]; - - int extraTrackSegments = 0; - - for (int i = 0; i < rho.length; i++) - for (int j = 1; j < rho[i].length - 2; j++) - if (rho[i][j] * rho[i][j + 1] < 0. && Math.abs(rho[i][j]) > 2.) - extraTrackSegments++; - - double hv[][][] = new double[2][rho.length + extraTrackSegments][]; - int index[] = new int[rho.length + extraTrackSegments]; - - extraTrackSegments = 0; - for (int i = 0; i < rho.length; i++) - { - int startOfSegment = 0; - int endOfLastSegment = rho[i].length - 1; - - for (int j = 0; j < rho[i].length - 1; j++) - if (rho[i][j] * rho[i][j + 1] < 0. && Math.abs(rho[i][j]) > 2.) - { - if (j == 0) - { - if (Math.abs(rho[i][0]) > 1.) - startOfSegment = 1; - } - else if (j == rho[i].length - 2) - endOfLastSegment = rho[i].length - 2; - else - { - for (int k = 0; k < hv.length; ++k) - { - hv[k][i + extraTrackSegments] = new double[j + 1 - startOfSegment]; - System.arraycopy(user.hv[k][i], startOfSegment, hv[k][i + extraTrackSegments], 0, j + 1 - startOfSegment); - } - index[i + extraTrackSegments] = user.index[i]; - startOfSegment = j + 1; - extraTrackSegments++; - } - } - if (startOfSegment == 0 && endOfLastSegment == rho[i].length - 1) - { - for (int k = 0; k < hv.length; ++k) - hv[k][i + extraTrackSegments] = user.hv[k][i]; - index[i + extraTrackSegments] = user.index[i]; - } - else - { - for (int k = 0; k < hv.length; ++k) - { - hv[k][i + extraTrackSegments] = new double[endOfLastSegment - startOfSegment + 1]; - System.arraycopy(user.hv[k][i], startOfSegment, hv[k][i + extraTrackSegments], 0, endOfLastSegment - startOfSegment + 1); - } - index[i + extraTrackSegments] = user.index[i]; - } - } - - rho = hv[1]; - for (int i = 0; i < rho.length; i++) - { - int j = 0; - - while (j < rho[i].length && Math.abs(rho[i][j]) < 2.) - j++; - if (j < rho[i].length) - if (rho[i][j] > 0.) - for (int k = 0; k < j; k++) - rho[i][k] = Math.abs(rho[i][k]); - else - for (int k = 0; k < j; k++) - rho[i][k] = -Math.abs(rho[i][k]); - } - - return window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv, index, this, ACoord.POLYLINES))); - } - - protected ACoord getDisplayHelices(AWindow window, AProjection2D projection) - { - AParameter drawPar = parameterStore.get(PARAMETER_GROUP, "DrawnAs"); - int drawnAs = drawPar != null ? drawPar.getI() : DRAW_HELIX; - - if (drawnAs == DRAW_HELIX) { - ADHelix[] dhelix = getHelices(); - double[][][] hv = new double[2][dhelix.length][0]; - int[] index = getDrawList(); - - for (int j = 0; j < dhelix.length; ++j) { - if (dhelix[j] != null) { - double s1 = dhelix[j].getAStart(); // Get start phi-angle - double s2 = dhelix[j].getAEnd(); // Get end phi-angle - - // s1 becomes phi at the intersection of the minimal radius - s1 = dhelix[j].intersectWithRadialCylinder(projection.getMinRho(), s1, s2); // minrho = 0 - // avoid drawing discontinuous in phi - dhelix[j].setPhiStart(s1, s2); - // returning a set of points to be drawn for this helix - ACoord pointsOnHelix = dhelix[j].drawHelix(window, projection, s1, s2); - - hv[0][j] = pointsOnHelix.hv[0][0]; - hv[1][j] = pointsOnHelix.hv[1][0]; - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } else { // DRAW_NEW_HELIX - - // V-plot needs some additional settings - boolean showS3D = parameterStore.get("Data", "S3D").getStatus(); - AParameter shortV = parameterStore.get("VP", "ShortV"); - - makeDrawList(); - double[][][] hv = new double[2][numDraw][]; - int[] index = new int[numDraw]; - - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - index[i] = j; - - if (projection instanceof AProjectionYX) { - - hv[0][i] = h[j].getX(h[j].getAlphaMin(), h[j].getAlphaMax()); - hv[1][i] = h[j].getY(h[j].getAlphaMin(), h[j].getAlphaMax()); - - } else if (projection instanceof AProjectionRZ - || projection instanceof AProjectionXZ - || projection instanceof AProjectionYZ) { - - double alphaMin = h[j].getAlphaCylinder(projection.getMinRho(), AHelix.TRACKER_LENGTH); - hv[0][i] = h[j].getZ(alphaMin, h[j].getAlphaMax()); - hv[1][i] = h[j].getRho(alphaMin, h[j].getAlphaMax(), true); - - if (projection instanceof AProjectionXZ || projection instanceof AProjectionYZ) { - double phiC = AProjectionXZ.getPhi(); - if (projection instanceof AProjectionYZ) phiC += 90; - - double phi[] = h[j].getPhi(alphaMin, h[j].getAlphaMax(), false); - for (int k=0; k<hv[1][i].length; k++) { - hv[1][i][k] = Math.abs(hv[1][i][k]) * Math.cos(Math.toRadians(phi[k] - phiC)); - } - } - } else if (projection instanceof AProjectionFR) { - - double alphaMin = h[j].getAlphaCylinder(projection.getMinRho(), AHelix.TRACKER_LENGTH); - hv[0][i] = h[j].getRho(alphaMin, h[j].getAlphaMax(), false); - hv[1][i] = h[j].getPhi(alphaMin, h[j].getAlphaMax(), false); - - } else if (projection instanceof AProjectionFZ) { - - double alphaMin = h[j].getAlphaCylinder(projection.getMinRho(), AHelix.TRACKER_LENGTH); - hv[0][i] = h[j].getZ(alphaMin, h[j].getAlphaMax()); - hv[1][i] = h[j].getPhi(alphaMin, h[j].getAlphaMax(), false); - - } else if (projection instanceof AProjectionVP) { - - double alphaMin = h[j].getAlphaCylinder(projection.getMinRho(), AHelix.TRACKER_LENGTH); - double alphaMax = h[j].getAlphaExtrapolated(AProjectionVP.getRhoVPlot(), AHelix.TRACKER_LENGTH); - if (shortV.getStatus() && !showS3D) { - alphaMin = alphaMax - shortV.getD() * (alphaMax - alphaMin); - } - - hv[0][i] = h[j].getEta(alphaMin, alphaMax); - hv[1][i] = h[j].getPhi(alphaMin, alphaMax, true); - - } - } - - return window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv, index, this, ACoord.POLYLINES))); - } - } - - // a track has two arms in the VPlot - protected ACoord getVPDisplayHelices(AWindow window, AProjection2D projection) - { - boolean drawApex = parameterStore.get("VP", "DrawApex").getStatus(); - AParameter drawPar = parameterStore.get(PARAMETER_GROUP, "DrawnAs"); - int drawnAs = drawPar != null ? drawPar.getI() : DRAW_HELIX; - - if (drawnAs == DRAW_HELIX) { - ADHelix[] dhelix = getHelices(); - int size = 2 * dhelix.length; - if (drawApex) - size = 3 * dhelix.length; - double[][][] hv = new double[2][size][0]; - int[] index = new int[size]; - int[] indexIn = getDrawList(); - int num = 0; - - for (int j = 0; j < dhelix.length; ++j) - if (dhelix[j] != null) - { - double s1 = dhelix[j].getAStart(); - double s2 = dhelix[j].getAEnd(); - - int mode = parameterStore.get("VP", "Mode").getI(); - if(mode <= AProjectionVP.MODE_HCAL_LAYER_3 - && mode >= AProjectionVP.MODE_ECAL_LAYER_0) { - s2 = 179; - } - - s1 = dhelix[j].intersectWithRadialCylinder(projection.getMinRho(), s1, s2); - double sEnd = dhelix[j].intersectWithCylinder(true, AProjectionVP.getRhoVPlot(), true, AProjectionVP.getZVPlot()); - - s2 = Math.max(Math.min(s2, sEnd), s1); - // if the whole helix is to be drawn (which are unusual - // helices, shorten it a little to avoid wraparound problems - if (s1 == 0. && s2 == 180.) - s2 = 179.; - if (parameterStore.get("VP", "ShortV").getStatus() && !parameterStore.get("Data", "S3D").getStatus()) - s1 = s2 - parameterStore.get("VP", "ShortV").getD() * (s2 - s1); - if (s2 > s1) - { - int signMin = -1; - int signMax = 1; - double h = 0; - double v = 0; - for (int sign = signMin; sign <= signMax; sign += 2) - { - // ugly must change structure at some point - AProjectionVP.sign = sign; - ACoord pointsOnHelix = dhelix[j].drawHelix(window, projection, s1, s2); - hv[0][num] = pointsOnHelix.hv[0][0]; - hv[1][num] = pointsOnHelix.hv[1][0]; - index[num] = indexIn[j]; - h = hv[0][num][hv[0][num].length - 1]; - v = hv[1][num][hv[0][num].length - 1]; - num++; - } - if (drawApex) - { - int a = 3; - int b = 7; - hv[0][num] = new double[] { h - a, h + a, h, h, h - a, h + a }; - hv[1][num] = new double[] { v - b, v - b, v - b, v + b, v + b, v + b }; - index[num] = indexIn[j]; - num++; - } - } - } - return new ACoord(hv, index, this, ACoord.POLYLINES); - } else { // DRAW_NEW_HELIX is handled by the normal method - return getDisplayHelices(window, projection); - } - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/data/ATrackResidualData.java b/graphics/AtlantisJava/src/atlantis/data/ATrackResidualData.java deleted file mode 100644 index 6f630c06636..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATrackResidualData.java +++ /dev/null @@ -1,323 +0,0 @@ -package atlantis.data; - -import java.awt.Color; -import java.awt.Point; -import java.awt.geom.Point2D; - -import atlantis.canvas.AWindow; -import atlantis.globals.AGlobals; -import atlantis.graphics.AGraphics; -import atlantis.graphics.APickingGraphics2D; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjectionTrackResidual; - -/** - * Contains residual data for a single track - * - * @author Qiang Lu - */ -public class ATrackResidualData -{ - public static String PULL_X = "P_X"; - public static String RESIDUAL_X = "R_X"; - - private ATrackData track; - private int trackIndex; - private String showType = RESIDUAL_X; - private int numPoints; - private float[] pullLoc1; - private float[] resLoc1; - private float[] pullLoc2; - private float[] resLoc2; - private String[] detType; - - private double logMagnitudeMin; - private int pickedIndex; - private byte pickedGroup; // 1 for loc1/pull1, 2 for loc2/pull2 - private double minDiff; - - private static APar parameterStore = APar.instance(); - - /** - * @param theTrack track collection to which this residual belongs to - * @param trackIndex index of the associated track - * @param points number of residuals points - * @param pullLoc1 residuals pull data 1 - * @param resLoc1 residuals data 1 - * @param pullLoc2 residuals pull data 2 (only for Pixel) - * @param resLoc2 residuals data 2 (only for Pixel) - * @param detType detector type of each residual - */ - ATrackResidualData(ATrackData track, int trackIndex, int points, - float[] pullLoc1, float[] resLoc1, float[] pullLoc2, float[] resLoc2, - String[] detType) - { - this.track = track; - this.trackIndex = trackIndex; - numPoints = points; - this.pullLoc1 = pullLoc1; - this.resLoc1 = resLoc1; - this.pullLoc2 = pullLoc2; - this.resLoc2 = resLoc2; - this.detType = detType; - } - - /** - * @return Returns the number of residual points. - */ - public int getNumPoints() - { - return numPoints; - } - - public float[] getPullLoc1() - { - return pullLoc1; - } - - public float[] getResLoc1() - { - return resLoc1; - } - - public float[] getPullLoc2() - { - return pullLoc2; - } - - public float[] getResLoc2() - { - return resLoc2; - } - - public void setLogMagnitudeMin(double logMagnitudeMin) - { - this.logMagnitudeMin = logMagnitudeMin; - } - - public double getLogMagnitudeMin() - { - return logMagnitudeMin; - } - - public void draw(AWindow window, AGraphics ag, AProjectionTrackResidual projection) - { - Color[] colorMap=AColorMap.getColors(); - - // draw horizontal axis through 0 - double x1 = 0., y1 = 0., x2 = projection.getXLength(), y2 = 0.0; - Point2D.Double from = window.calculateDisplay(x1, y1); - Point2D.Double to = window.calculateDisplay(x2, y2); - ag.setColor(colorMap[AColorMap.BL]); - ag.drawLine(from.x, from.y, to.x, to.y); - - float[] temp1; - AParameter showExtraPar = parameterStore.get("TrackResidual", "ShowExtra"); - if(projection.getResidualType().equals(RESIDUAL_X)) - { - showType = RESIDUAL_X; - temp1 = this.resLoc1; - float[] temp2 = this.pullLoc1; // needed when drawing error bar - drawResidual(window, ag, temp1, temp2, colorMap, false); - if(showExtraPar.getStatus()) - { - temp1 = this.resLoc2; - temp2 = this.pullLoc2; - drawResidual(window, ag, temp1, temp2, colorMap, true); - } - } - else - { - showType = PULL_X; - temp1 = this.pullLoc1; - drawResidual(window, ag, temp1, null, colorMap, false); - if(showExtraPar.getStatus()) - { - temp1 = this.pullLoc2; - drawResidual(window, ag, temp1, null, colorMap, true); - } - } - - if(ag.getGraphics2D() instanceof APickingGraphics2D - && parameterStore.get("Event", "PickingMode").getI() == APickingGraphics2D.PICK_HITS_AND_TRACKS) // pick residula - { - APickingGraphics2D.mode = APickingGraphics2D.PICK_RESIDUAL; - APickingGraphics2D.setPicked(this); - } - } - - public void drawResidual(AWindow window, AGraphics ag, float[] res, - float[] pull, Color[] colorMap, boolean drawExtra) - { - // every residual is drawn as a small square with 2 pixels * 2 pixels - // N.B. when showType=PULL_X, res actually represents pull, and pull=null - double[] h = new double[4]; - double[] v = new double[4]; - int pixelOffset = 1; - - Point clickedPoint = null; - if(ag.getGraphics2D() instanceof APickingGraphics2D - && parameterStore.get("Event", "PickingMode").getI() == APickingGraphics2D.PICK_HITS_AND_TRACKS) // pick residual - { - clickedPoint = ((APickingGraphics2D)ag.getGraphics2D()).pickedPoint; - } - - Color colValid = colorMap[AColorMap.RD]; //for backward compatibility - Color colInvalid = colorMap[AColorMap.BK]; - for(int i=0; i<numPoints; i++) - { - double y; - if(res[i] == -99.0f) // unavailable - { - ag.setColor(colInvalid); - y = 0.0; - } - else - { - if(detType != null) - { - String det = detType[i]; - if("unident".equals(det)) - ag.setColor(colorMap[AColorMap.GY]); - else - { - AParameter detColor = parameterStore.get("Det", det+"Fill"); - if(detColor != null) - ag.setColor(colorMap[detColor.getI()]); - else - ag.setColor(colValid); - } - } - else // for old files that don't have <tsosDetType> - ag.setColor(colValid); - - if(parameterStore.get("TrackResidual", "Scale").getI() == 0) // linear - y = res[i]; - else // logarithmic scale - { - if(res[i] != 0.0f) - y = Math.log10(Math.abs(res[i])) - logMagnitudeMin; - else - y = res[i]; - if(res[i] < 0.0f) - y = -y; - } - } - - double tempX, tempY; - if(!drawExtra) - tempX = window.calculateDisplay(i, y).x; - else - tempX = window.calculateDisplay(i+0.25, y).x; - tempY = window.calculateDisplay(i, y).y; - - // when shape is a square, calculate the corners - // x0, y0 - h[0] = tempX - pixelOffset; - v[0] = tempY + pixelOffset; - // x1, y1 - h[1] = tempX - pixelOffset; - v[1] = tempY - pixelOffset; - // x2, y2 - h[2] = tempX + pixelOffset; - v[2] = tempY - pixelOffset; - // x3, y3 - h[3] = tempX + pixelOffset; - v[3] = tempY + pixelOffset; - - ag.fillPolygon(h, v, h.length); - - // draw error bar only for residual - AParameter showErrorBarPar = parameterStore.get("TrackResidual", "ErrorBar"); - if(showType.equals(RESIDUAL_X) && showErrorBarPar.getStatus() && - pull != null) - { - double error = 0.0; - if(pull[i] != 0.0f && pull[i] != -99.0f && y != 0.0) - error = res[i] / pull[i]; - - if(error != 0.0) // draw the error bar by linear scale always - { - double[][] vLine = new double[2][2]; - vLine[0][0] = tempX; - vLine[0][1] = tempX; - vLine[1][0] = window.calculateDisplay(i, y+error).y; - vLine[1][1] = window.calculateDisplay(i, y-error).y; - ag.drawPolyline(vLine[0], vLine[1], vLine[0].length); // verticle line - - double xMinus = tempX - 2 * pixelOffset; - double xPlus = tempX + 2 * pixelOffset; - double yTop = vLine[1][0]; - double yBottom = vLine[1][1]; - ag.drawLine(xMinus, yTop, xPlus, yTop); - ag.drawLine(xMinus, yBottom, xPlus, yBottom); - } - } - - // find the picked residual - if(ag.getGraphics2D() instanceof APickingGraphics2D - && parameterStore.get("Event", "PickingMode").getI() == APickingGraphics2D.PICK_HITS_AND_TRACKS) // pick residula - { - if(i==0 && !drawExtra) - { - pickedIndex = i; - pickedGroup = 1; - minDiff = Math.abs(clickedPoint.x - tempX); - APickingGraphics2D.pickedH = tempX; - APickingGraphics2D.pickedV = tempY; - } - else - { - double diff = Math.abs(clickedPoint.x - tempX); - if(minDiff > diff) - { - pickedIndex = i; - if(drawExtra) - pickedGroup = 2; - else - pickedGroup = 1; - minDiff = diff; - APickingGraphics2D.pickedH = tempX; - APickingGraphics2D.pickedV = tempY; - } - } - } - } - } - - public String getHitInfo() - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return track.getNameScreenName()+ - " index: "+trackIndex+"\n storegate key: "+ - (track.getStoreGateKey() == null ? "n/a" : track.getStoreGateKey()); - - StringBuffer msg = new StringBuffer(track.getNameScreenName() + " (index: "); - msg.append(trackIndex); - msg.append(")"); - msg.append("\n storegate key: "); - msg.append(track.getStoreGateKey() == null ? "n/a" : track.getStoreGateKey()); - if(showType.equals(RESIDUAL_X)) - { - msg.append("\n Residual" + pickedGroup + "(" + "index: " + pickedIndex + ") = "); - if (pickedGroup == 1) - msg.append((this.resLoc1[pickedIndex]==-99.0f)?"unavailable":this.resLoc1[pickedIndex] + "(mm)"); - else - msg.append((this.resLoc2[pickedIndex]==-99.0f)?"unavailable":this.resLoc2[pickedIndex] + "(mm)"); - } - else - { - msg.append("\n Pull" + pickedGroup + "(" + "index: " + pickedIndex + ") = "); - if (pickedGroup == 1) - msg.append((this.pullLoc1[pickedIndex]==-99.0f)?"unavailable":this.pullLoc1[pickedIndex] + "(mm)"); - else - msg.append((this.pullLoc2[pickedIndex]==-99.0f)?"unavailable":this.pullLoc2[pickedIndex] + "(mm)"); - } - - return msg.toString(); - - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/data/ATrigS3DData.java b/graphics/AtlantisJava/src/atlantis/data/ATrigS3DData.java deleted file mode 100644 index 2a20340f4ea..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATrigS3DData.java +++ /dev/null @@ -1,252 +0,0 @@ -package atlantis.data; - -import atlantis.event.*; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.utils.AHashMap; -import atlantis.utils.AMath; - - -/** - * - * Trigger SpacePoints - * - * barcodes + numBarcodes - associations with Truth (STr) - * clusters - associations with SiClusters and over it with reconstructed - * tracks (Track) - * - * cleanup notes: - * methods makeFilterDrawList(), getIntegerEta(), getIntegerPhi() were removed - * as these were only used by AFilter in S3D (this class was obviously the - * origin for the others) but AFilter doesn't work with TrigS3D - * other also unused methods are getLayer() and getSub() - what are these - * used for? - * - */ -public class ATrigS3DData extends A3DPointData -{ - private int[][] clusters = null; - - // data from the event file - protected int[] layer = null; - - private boolean[] pixel = null; - public static final int PIXEL = -1; - - - - public String getParameterGroup() - { - return "TrigS3D"; - } - - - - public String getName() - { - return "TrigS3D"; - } - - - - public String getNameScreenName() - { - return "TrigSiSpacePoint"; - } - - - - public String getHitInfo(int index) - { - int simpleOutput = AGlobals.instance().getSimpleOutput(); - if(simpleOutput>0) return getNameScreenName()+" index: " + index+"\n"+ - AMath.RHO+" = "+String.format("%.3f",rho[index])+"\n "+ - AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phi[index]))+AMath.DEGREES; - - String clId = " (" + clusters[index][0] + ", " + - clusters[index][1] + ")"; - String type = pixel[index] ? " (Pixel)" : " (SCT)"; - - String r = ""; - r += getNameScreenName() + " (id: " + id[index] + " index: " + index + ")" + - clId + type + "\n " + - "x = " + String.format("%.3f",x[index]) + " cm\n " + - "y = " + String.format("%.3f",y[index]) + " cm\n " + - "z = " + String.format("%.3f",z[index]) + " cm\n " + - AMath.RHO + " = " + String.format("%.3f",rho[index]) + " cm\n " + - AMath.PHI + " = " + - String.format("%.3f",Math.toDegrees(phi[index])) + - AMath.DEGREES + " (" + String.format("%.3f",phi[index]) + " rad)\n " + - " layer = " + layer[index]; - r += super.getHitInfo(index); // finds barcode information - - return r; - - } // getHitInfo() ------------------------------------------------------- - - - - ATrigS3DData(AHashMap p, AEvent e) - { - super(p,e); - layer = p.getUnknownIntArray("layer"); - - if(p.get("clusters") != null) - { - // can only distinguish between SCT and Pixel hits if clusters - // subtag is available - pixel = new boolean[numData]; - // save IDs from event file to be availeble with pick info - clusters = new int[numData][]; - - int[][] assocClusters = new int[numData][]; - int[] temp = p.getIntArray("clusters"); - for(int i = 0; i < numData; ++i) - { - // save all clusters IDs - clusters[i] = new int[] { temp[2 * i], temp[2 * i + 1] }; - - // check if the second number, PIXEL (-1) designates pixel hit - if(temp[2 * i + 1] != PIXEL) - { - // this is SCT spacepoint - has got two clusters - assocClusters[i] = new int[] { temp[2 * i], temp[2 * i + 1] }; - } - else - { - // this is a pixel spacepoint (second cluster number is -1) - pixel[i] = true; - - // to ignore associtiation between pixel clusters and spacepoints: - // assocClusters[i] = null; - - // taking pixel cluster into account (pixel spacepoint has got - // only one cluster) (where as SCT spacepoint has got two clusters) - assocClusters[i] = new int[] { temp[2 * i] }; - } - } - AAssociation assoc = new AAssociation(getName(), "SiCluster", - assocClusters,event); - event.getAssociationManager().add(assoc); - } - - } // ATrigS3DData() ----------------------------------------------------- - - - - protected void finalizeConstruction() - { - super.finalizeConstruction(); - super.calculateAssociationViaClusters(); - - } // finalizeConstruction() --------------------------------------------- - - - - protected int internalColor() - { - int numColorTypes = super.internalColor(); - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - if(colorFunction == numColorTypes + 1) - { - colorBy(layer); - } - - return numColorTypes + 1; - - } // internalColor() ---------------------------------------------------- - - - protected void applyCuts() - { - cutIndex(); - cutSubdetector(); - cut("CutsInDet", "Layer", "Layer", layer); - cutPhi(phi); - cutEta(rho, z); - cutSimulatedTracks(); - cutReconstructedTracks(); - - } // applyCuts() -------------------------------------------------------- - - - private void cutSubdetector() - { - AParameter subPar = parameterStore.get("CutsInDet", "SCT"); - if(subPar.getI() != -1) - { - cutArray(sub, subPar.getI(), "Barrel/Endcap"); - } - - } // cutSubdetector() --------------------------------------------------- - - - - public int[] getLayer(int[] layer) - { - for(int i = 0; i < numDraw; i++) - { - layer[i] = this.layer[listdl[i]]; - } - return layer; - - } // getLayer() --------------------------------------------------------- - - - - public int getSub(int id) - { - if(id > -1) - { - return(id >> 25) & 0x3; - } - else - { - return(id >> 29) & 0x3; - } - - } // getSub() ----------------------------------------------------------- - - - - protected ACoord getFRUser() - { - if(!parameterStore.get("SiCluster", "Stereo").getStatus())return super.getFRUser(); - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = rho[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FR"); - - } // getFRUser() -------------------------------------------------------- - - - - protected ACoord getFZUser() - { - if(!parameterStore.get("SiCluster", "Stereo").getStatus())return super.getFZUser(); - makeDrawList(); - double[] h = new double[numDraw]; - double[] v = new double[numDraw]; - int[] index = new int[numDraw]; - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - h[i] = z[list]; - v[i] = Math.toDegrees(AParameterUtilities.getPhiStereo(rho[list], phi[list], z[list])); - index[i] = list; - } - return new ACoord(h, v, index, this).includePhiWrapAround("FZ"); - - } // getFZUser() -------------------------------------------------------- - -} // class ATrigS3DData ===================================================== diff --git a/graphics/AtlantisJava/src/atlantis/data/ATriggerInfoData.java b/graphics/AtlantisJava/src/atlantis/data/ATriggerInfoData.java deleted file mode 100644 index 4e9b000c650..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/ATriggerInfoData.java +++ /dev/null @@ -1,213 +0,0 @@ -package atlantis.data; - -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.utils.AHashMap; - -public class ATriggerInfoData extends AData -{ - private float[] energyEtMiss; - //private float[] energyEx; - //private float[] energyEy; - private float[] energySumEt; - private String[] trigInfoEF; - private String[] trigInfoExtL1ID; - private String[] trigInfoL1; - private String[] trigInfoL2; - private String[] trigInfoLvl1Type; - private String[] trigInfoStatus; - private String[] trigInfoStreamTag; - - ATriggerInfoData(AHashMap p, AEvent e) - { - super(p,e); - energyEtMiss = p.getUnknownFloatArray("energyEtMiss"); - //energyEx = p.getUnknownFloatArray("energyEx"); - //energyEy = p.getUnknownFloatArray("energyEy"); - energySumEt = p.getUnknownFloatArray("energySumEt"); - trigInfoEF = p.getStringArray("trigInfoEF"); - trigInfoExtL1ID = p.getStringArray("trigInfoExtL1ID"); - trigInfoL1 = p.getStringArray("trigInfoL1"); - trigInfoL2 = p.getStringArray("trigInfoL2"); - trigInfoLvl1Type = p.getStringArray("trigInfoLvl1Type"); - trigInfoStatus = p.getStringArray("trigInfoStatus"); - trigInfoStreamTag = p.getStringArray("trigInfoStreamTag"); - } - - protected void applyCuts() - {} - - public String getHitInfo(int index) - { - return "TriggerInfo"; - } - - protected int internalColor() - { - int colorFunction = parameterStore.get(PARAMETER_GROUP, "ColorFunction").getI(); - - if(colorFunction == 0) - colorByConstant(); - - return 3; - } - - public String getParameterGroup() - { - return "TriggerInfo"; - } - - public String getNameScreenName() - { - return "TriggerInfo"; - } - - /** - * For backward compatibility if this is null or -1 - * also check the value returned from ALVL1ResultData - */ - public float getEnergyEtMiss(int index) - { - return energyEtMiss[index]; - } - - /*public float getEnergyEx(int index) - { - return energyEx[index]; - } - public float getEnergyEy(int index) - { - return energyEy[index]; - }*/ - - /** - * For backward compatibility if this is null or -1 - * also check the value returned from ALVL1ResultData - */ - public float getEnergySumEt(int index) - { - return energySumEt[index]; - } - - public String getTrigInfoEF(int index) - { - return trigInfoEF[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getTrigInfoEFSplit(int index) - { - if(trigInfoEF!=null) - return splitItems(trigInfoEF[index]); - else - return null; - } - - /** - * Returns the hex values of the - * individual parts of the list seperated by - - */ - public String[] getTrigInfoEFSplitHex(int index) - { - return hexValues(splitItems(trigInfoEF[index])); - } - - public String getTrigInfoExtL1ID(int index) - { - return trigInfoExtL1ID[index]; - } - - public String getTrigInfoL1(int index) - { - return trigInfoL1[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getTrigInfoL1Split(int index) - { - if(trigInfoL1!=null) - return splitItems(trigInfoL1[index]); - else - return null; - } - - /** - * Returns the hex values of the - * individual parts of the list seperated by - - */ - public String[] getTrigInfoL1SplitHex(int index) - { - return hexValues(splitItems(trigInfoL1[index])); - } - - public String getTrigInfoL2(int index) - { - return trigInfoL2[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getTrigInfoL2Split(int index) - { - if(trigInfoL2!=null) - return splitItems(trigInfoL2[index]); - else - return null; - } - - /** - * Returns the hex values of the - * individual parts of the list seperated by - - */ - public String[] getTrigInfoL2SplitHex(int index) - { - return hexValues(splitItems(trigInfoL2[index])); - } - - public String getTrigInfoLvl1Type(int index) - { - return trigInfoLvl1Type[index]; - } - - public String getTrigInfoStatus(int index) - { - return trigInfoStatus[index]; - } - - - public String getTrigInfoStreamTag(int index) - { - return trigInfoStreamTag[index]; - } - - /** - * Returns the individual parts of the list seperated by - - */ - public String[] getTrigInfoStreamTagSplit(int index) - { - if(trigInfoStreamTag!=null) - return splitItems(trigInfoStreamTag[index]); - else - return null; - } - - - /** - * Returns the hex values of each element in the string - * string[] items represents a long[] - */ - private String[] hexValues(String[] items) - { - for(int i=0; i<items.length; i++) - { - long longvalue= Long.valueOf(items[i]).longValue(); - items[i] = "0x"+Long.toString(longvalue, 16).toUpperCase(); - } - return items; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/data/AVertex.java b/graphics/AtlantisJava/src/atlantis/data/AVertex.java deleted file mode 100755 index ed4ea9643d7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AVertex.java +++ /dev/null @@ -1,328 +0,0 @@ -package atlantis.data; - -import Jama.Matrix; - -import java.util.HashMap; -import java.util.Map; -import atlantis.parameters.APar; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjectionXZ; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.utils.AMath; -import atlantis.utils.AAtlantisException; - -/** - * - * Reconstructed vertex instance. Either calculated in - * Atlantis (atlantis.utils.AVertexFit class) or read in from the event data as - * RVx datatype. RVx class keeps track of all the reconstructed vertices - * and contains instances of this class Avertex. - * (2005-08-08 refactoring and clean-ups) - * (2006-01-10 covMatrix, errMatrix variables were messed up (covMatrix - * numbers were huge - was actually the inverse - the weight matrix. AVertexFit - * code didn't give any ideas, very unclear code - covFittedMatrix there - * was used to initialize errMatrix here ...)) - * - * - * variables names renaming: - * covMatrix -> weightMatrix - * errMatrix -> covErrorMatrix - * - * @author Gary Taylor - */ -public class AVertex -{ - // size of the arrays with coordinates of the RVx ellipse and matrices - private static final int SIZE = 3; - - // basic RVx data - private double[] position = null; // x, y, z centre of the ellipse - private double chi2 = 1.e+10; - private Matrix covErrMatrix = null; // covariance error matrix - private Matrix weightMatrix = null; // inverse matrix of covErrMatrix - private double phi; // phi of the ellipse - private double rho; // rho of the ellipse - - private static APar parameterStore = APar.instance(); - - public AVertex(double[] p) - { - position = new double[SIZE]; - - if (p.length != SIZE) - { - throw new IllegalArgumentException("p.length=" + p.length); - } - for (int i = 0; i < SIZE; ++i) - { - position[i] = p[i]; - } - } // AVertex() ---------------------------------------------------------- - - /** - * @param p double[] - x, y, z positions of the centre of the ellipse - * @param c double[][] - input for covErrMatrix - * @param chiSquared double - */ - public AVertex(double[] p, double[][] c, double chiSquared) - { - testInputArrays(p, c); - - position = new double[SIZE]; - double[][] covErr = new double[SIZE][SIZE]; - - for (int i = 0; i < SIZE; ++i) - { - position[i] = p[i]; - } - phi = Math.atan2(p[1], p[0]); - if (phi < 0.) - phi += AMath.TWO_PI; - rho = Math.sqrt(p[0] * p[0] + p[1] * p[1]); - for (int i = 0; i < SIZE; ++i) - { - for (int j = 0; j < SIZE; ++j) - { - covErr[i][j] = c[i][j]; - } - } - - covErrMatrix = new Matrix(covErr); - weightMatrix = covErrMatrix.inverse(); - this.chi2 = chiSquared; - } // AVertex() ---------------------------------------------------------- - - /** - * - * @param chiSquared double - * @param p double[] - x, y, z positions of the centre of the ellipse - * @param c double[][] - input for covErrMatrix - */ - public AVertex(double chiSquared, double[] p, double[][] c) throws AAtlantisException - { - testInputArrays(p, c); - - chi2 = chiSquared; - - position = new double[SIZE]; - - for (int i = 0; i < SIZE; ++i) - { - position[i] = p[i]; - } - - phi = Math.atan2(p[1], p[0]); - if (phi < 0.) - phi += AMath.TWO_PI; - rho = Math.sqrt(p[0] * p[0] + p[1] * p[1]); - - double[][] covErr = new double[SIZE][SIZE]; - for (int x = 0; x < SIZE; x++) - { - covErr[x] = (double[]) c[x].clone(); - } - - try - { - covErrMatrix = new Matrix(covErr); - weightMatrix = covErrMatrix.inverse(); - } - catch (Exception ex) - { - String msg = "Error when creating covariance and/or weight\n" + "matrix in AVertex class.\nReason: " + ex.getMessage(); - throw new AAtlantisException(msg); - } - } // AVertex() ---------------------------------------------------------- - - private void testInputArrays(double[] p, double[][] c) throws IllegalArgumentException - { - if (p.length != SIZE) - { - throw new IllegalArgumentException("p.length = " + p.length); - } - - if (c.length != SIZE) - { - throw new IllegalArgumentException("c.length = " + c.length); - } - - for (int i = 0; i < SIZE; ++i) - { - if (c[i].length != SIZE) - { - throw new IllegalArgumentException("c[" + i + "].length = " + c[i].length); - } - } - } // testInputArrays() -------------------------------------------------- - - public double[] getPosition() - { - return (double[]) position.clone(); - } // getPosition() ------------------------------------------------------ - - public Matrix getCovErrMatrix() - { - return covErrMatrix; - } // getCovErrMatrix() -------------------------------------------------- - - public double getRho() - { - return rho; - } - - public double getPhi() - { - return phi; - } - - public String toString() - { - StringBuffer msg = new StringBuffer(" x = "); - msg.append(String.format("%.5f",position[0])); - msg.append(" "); - msg.append(AMath.PLUSMINUS); - msg.append(" "); - msg.append(String.format("%.3f",Math.sqrt(covErrMatrix.get(0, 0)))); - msg.append(" cm\n y = "); - msg.append(String.format("%.5f",position[1])); - msg.append(" "); - msg.append(AMath.PLUSMINUS); - msg.append(" "); - msg.append(String.format("%.3f",Math.sqrt(covErrMatrix.get(1, 1)))); - msg.append(" cm\n z = "); - msg.append(String.format("%.5f",position[2])); - msg.append(" "); - msg.append(AMath.PLUSMINUS); - msg.append(" "); - msg.append(String.format("%.3f",Math.sqrt(covErrMatrix.get(2, 2)))); - msg.append(" cm\n "); - msg.append(AMath.ETA); - msg.append(" = "); - msg.append(String.format("%.4f",AParameterUtilities.eta(position[2], rho))); - msg.append("\n "); - msg.append(AMath.PHI); - msg.append(" = "); - msg.append(String.format("%.1f",Math.toDegrees(phi))); - msg.append(AMath.DEGREES); - msg.append("\n chi2 = "); - msg.append(String.format("%.1f",chi2)); - - return msg.toString(); - } // toString() --------------------------------------------------------- - - // Ask Alan Litke to explain this calculation - private double[][] getEllipse(Matrix rM, int[] axisMapping) - { - Matrix parPrime = rM.times(new Matrix(position, position.length)); - - double a1 = weightMatrix.get(axisMapping[0], axisMapping[0]); - double a2 = weightMatrix.get(axisMapping[1], axisMapping[1]); - double a3 = weightMatrix.get(axisMapping[2], axisMapping[2]); - double a4 = 2. * weightMatrix.get(axisMapping[0], axisMapping[1]); - double a5 = 2. * weightMatrix.get(axisMapping[0], axisMapping[2]); - double a6 = 2. * weightMatrix.get(axisMapping[1], axisMapping[2]); - double b1 = a1 - a5 * a5 / (4. * a3); - double b2 = a2 - a6 * a6 / (4. * a3); - double b3 = a4 - 2 * a5 * a6 / (4. * a3); - double[][] hv = new double[2][360]; - double sigma = parameterStore.get("RVx", "NumSigma").getD(); - for (int i = 0; i < 360; ++i) - { - double thetat = Math.toRadians(i); - double tt = Math.tan(thetat); - double x = Math.sqrt(sigma * sigma / (b1 + b2 * tt * tt + b3 * tt)); - if (i > 90 && i <= 270) - x *= -1.; - hv[0][i] = x + parPrime.get(axisMapping[0], 0); - hv[1][i] = x * tt + parPrime.get(axisMapping[1], 0); - } - return hv; - } // getEllipse() ------------------------------------------------------- - - public double[][] getYXEllipse() - { - Matrix rM = new Matrix(AProjectionYX.getRotationMatrix()); - int[] axisMapping = AProjectionYX.getAxisMapping(); - - return getEllipse(rM, axisMapping); - } // getYXEllipse() ----------------------------------------------------- - - public double[][] getYZEllipse() - { - Matrix rM = new Matrix(AProjectionYZ.getRotationMatrix()); - int[] axisMapping = AProjectionYZ.getAxisMapping(); - - return getEllipse(rM, axisMapping); - } // getYZEllipse() ----------------------------------------------------- - - public double[][] getXZEllipse() - { - Matrix rM = new Matrix(AProjectionXZ.getRotationMatrix()); - int[] axisMapping = AProjectionXZ.getAxisMapping(); - - return getEllipse(rM, axisMapping); - } // getXZEllipse() ----------------------------------------------------- - - public double[][] getRZEllipse() - { - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi-phiMid); - int rSign; if (phiDiff > Math.PI/2. && phiDiff <= 3*Math.PI/2.) rSign = -1; else rSign = 1; - - double[][] hv = new double[2][360]; - double sigma = parameterStore.get("RVx", "NumSigma").getD(); - for (int i = 0; i < 360; ++i) - { - double thetat = Math.toRadians(i); - double ey = Math.sqrt(Math.sqrt(covErrMatrix.get(0,0)*covErrMatrix.get(0,0)+covErrMatrix.get(1,1)*covErrMatrix.get(1,1))); - double ex = Math.sqrt(covErrMatrix.get(2,2)); - hv[1][i] = rSign * Math.sqrt(position[0]*position[0]+position[1]*position[1]) + sigma*ey*Math.sin(thetat); - hv[0][i] = position[2] + sigma*ex*Math.cos(thetat); - //System.out.println(i+" "+thetat+" "+hv[0][i]+" "+hv[1][i]); - } - return hv; - } // getXZEllipse() ----------------------------------------------------- - - // Vertex type - enum same as in Athena - - enum Type { - DUMMY (0, "Dummy. Track particle was not used in vertex fit."), - PRIMARY (1, "Primary"), - SECONDARY (2, "Secondary"), - PILEUP (3, "Pile-up"), - CONVERSION (4, "Conversion"), - V0 (5, "V0 decay"), - KINK (6, "Kink"), - TEMPV0LAMBDA (7, "Temporary Addition for V0 Lambda"), - TEMPV0LAMBDABAR (8, "Temporary Addition for V0 LambdaBar"), - TEMPKSHORT (9, "Temporary Addition for KShort"), - DEFAULT (99, "Not specified"); - - public final int id; - public final String description; - - private static Map<Integer,Type> typeMap = new HashMap<Integer,Type>(); - static { - for (Type type : Type.values()) { - typeMap.put(type.id, type); - } - } - - /** - * Get vertex type corresponding to given integer type identifier. - * @param id type identifier - * @return vertex type - */ - public static Type typeFromId(int id) { - return typeMap.get(id); - } - - private Type (int id, String description) { - this.id = id; - this.description = description; - } - } - -} - \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/data/AVertexFit.java b/graphics/AtlantisJava/src/atlantis/data/AVertexFit.java deleted file mode 100755 index 09fba478e39..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/AVertexFit.java +++ /dev/null @@ -1,289 +0,0 @@ -package atlantis.data; - -import atlantis.parameters.APar; -import atlantis.utils.ALogger; - -import Jama.*; - - -/** - * This class provide a java implementation of the ALEPH vertex fitting - * routine YTOPOL. At the moment the only functionality is the fitting - * of ATLAS helices to a common vertex. A reasonable starting vertex for the - * fit must be given. For B decays the primary vertex should be good enough. - * Future improvements in functionality could include estimation of a - * starting vertex and including in the fitting also already calculated - * vertices and charged and neutral particles - */ - -public class AVertexFit { - private static ALogger logger = ALogger.getLogger(AVertexFit.class); - private static APar parameterStore = APar.instance(); - - private static final int MXITR=8; - private static final double CHISC=1.E-2; - private static final double CHISR=0.01; - private static final double PARCR=0.01; - private static final boolean DEBUG=false; - - private AVertexFit() {} - - public static AVertex fitVertex(AVertex estimatedVertex, AHelix[] helix) { - Matrix[] measuredHelix=new Matrix[helix.length]; - Matrix[] covHelix=new Matrix[helix.length]; - Matrix[] errHelix=new Matrix[helix.length]; - - for(int k=0; k<helix.length; ++k) { - double[] par=helix[k].getPar(); - double[][] cov=helix[k].getCovariance(); - double signD0=-1.; - double signPt=1.; - - par[0]*=signD0; - par[4]*=signPt; - - for(int i=0; i<5; ++i) { - cov[0][i]*=signD0; - cov[i][0]*=signD0; - cov[4][i]*=signPt; - cov[i][4]*=signPt; - } - - measuredHelix[k]=new Matrix(par, par.length); - covHelix[k]=new Matrix(cov); - errHelix[k]=covHelix[k].inverse(); - - // AOutput.logln( "measuredHelix "+k+" "+measuredHelix[k]); - // AOutput.logln( measuredHelix[k].toString()); - // AOutput.logln( covHelix[k].toString()); - - } - - int numFreeParam=3+3*helix.length; - Matrix fitted=new Matrix(numFreeParam, 1); - double[] estVertex=estimatedVertex.getPosition(); - int ipar; - - for(ipar=0; ipar<3; ++ipar) - fitted.set(ipar, 0, estVertex[ipar]); - ipar=3; - for(int k=0; k<helix.length; ++k) { - fitted.set(ipar++, 0, parameterStore.get("Event", "Curvature").getD()/measuredHelix[k].get(4, 0)-measuredHelix[k].get(0, 0)); - - fitted.set(ipar++, 0, measuredHelix[k].get(3, 0)); - fitted.set(ipar++, 0, measuredHelix[k].get(2, 0)); - } - - logger.debug("fittedHelix "+0+" "+new Transformation(fitted, 0).helixFromFitted()); - logger.debug("fittedHelix "+1+" "+new Transformation(fitted, 1).helixFromFitted()); - - // AOutput.logln( fitted.toString()); - - Matrix g=new Matrix(numFreeParam, 1); - Matrix gg=new Matrix(numFreeParam, numFreeParam); - int iteration=0; - double chiso=0.; - double chisq=0.; - boolean converged; - - FITTINGLOOP: - do { - g.timesEquals(0.); - gg.timesEquals(0.); - for(int k=0; k<helix.length; ++k) { - Transformation t=new Transformation(fitted, k); - - Matrix fittedHelix=t.helixFromFitted(); - - logger.debug("fittedHelix "+k+" "+fittedHelix); - Matrix dMdF=t.getHelixdMdF(); - Matrix delFM=fittedHelix.minus(measuredHelix[k]); - // helices are independent of each other so can - // use temporary matrices to avoid large matrix multiplications - Matrix gtemp=(errHelix[k].times(dMdF)).transpose().times(delFM); - Matrix ggtemp=dMdF.transpose().times(errHelix[k].times(dMdF)); - - // now put these into the large matrices - for(int i=0; i<3; ++i) { - int ix=3+3*k; - - g.set(i, 0, g.get(i, 0)+gtemp.get(i, 0)); - g.set(ix+i, 0, g.get(ix+i, 0)+gtemp.get(3+i, 0)); - for(int j=0; j<3; ++j) { - gg.set(i, j, gg.get(i, j)+ggtemp.get(i, j)); - gg.set(ix+i, j, gg.get(ix+i, j)+ggtemp.get(3+i, j)); - gg.set(i, ix+j, gg.get(i, ix+j)+ggtemp.get(i, 3+j)); - gg.set(ix+i, ix+j, gg.get(ix+i, ix+j)+ggtemp.get(3+i, 3+j)); - } - } - if(iteration==0) { - double chih=delFM.transpose().times(errHelix[k].times(delFM)).get(0, 0); - - chiso+=Math.min(chih, 1.0e+10); - // AOutput.logln( "initial chi2"+chih); - } - } - - // AOutput.logln( gg.toString()); - - gg=gg.inverse(); - Matrix delFitted=gg.times(g); - - logger.debug("DELFITTED "+iteration+" "+delFitted.toString()); - - fitted.minusEquals(delFitted); - - int jter=0; - int kter=0; - - while(true) { - if(kter>10) break FITTINGLOOP; - if(jter>100) break FITTINGLOOP; - - double chish=0.; - - chisq=0.; - for(int k=0; k<helix.length; ++k) { - Transformation t=new Transformation(fitted, k); - Matrix fittedHelix=t.helixFromFitted(); - Matrix delFM=fittedHelix.minus(measuredHelix[k]); - double chih=delFM.transpose().times(errHelix[k].times(delFM)).get(0, 0); - - chish+=Math.min(chih, 1.0e+10); - } - chisq+=chish; - - double chis1=0.; - - if((chisq>chiso+0.0001&&jter==0)||chisq>1.1*chiso) { - delFitted.timesEquals(0.5); - fitted.plusEquals(delFitted); - jter++; - chis1=chisq; - continue; - } else { - if(jter>0) { - // estimate best parameters - double chtrm=chis1+chiso-2.*chisq; - double fx; - - if(chtrm>0.) { - // concave chisq dependance - fx=(chis1-chiso)/(2.*(chis1+chiso-2.*chisq)); - fx=Math.max(fx, -2.); - fx=Math.min(fx, 2.); - } else { - // convex chisq dependance - fx=-2.; - } - delFitted.timesEquals(fx); - - jter=0; - kter++; - continue; - } - } - break; - } - - double dchi2=chiso-chisq; - - chiso=chisq; - converged=true; - // check for change in chisq - if(dchi2>CHISC&&dchi2>CHISR*chisq) converged=false; - // check for change in parameters - for(int i=0; i<numFreeParam; i++) - if(delFitted.get(i, 0)*delFitted.get(i, 0)>PARCR*gg.get(i, i)) - converged=false; - } while((!converged)&&iteration++<MXITR); - - double[] fittedVertex=new double[3]; - double[][] fittedVertexCov=new double[3][]; - - for(int i=0; i<3; i++) { - fittedVertex[i]=fitted.get(i, 0); - fittedVertexCov[i]=new double[3]; - for(int j=0; j<3; j++) - fittedVertexCov[i][j]=gg.get(i, j); - } - - return new AVertex(fittedVertex, fittedVertexCov, chisq); - } - - private static class Transformation { - double rho, tau, phi0, d0, z0, sinPhi, cosPhi, sinDPhi, cosDPhi, eta, s, r, dPhi; - - Transformation(Matrix fitted, int iHelix) { - int index=3+3*iHelix; - - eta=fitted.get(index++, 0); - tau=fitted.get(index++, 0); - phi0=fitted.get(index++, 0); - double sinPhi0=Math.sin(phi0); - double cosPhi0=Math.cos(phi0); - double xC=-eta*sinPhi0; - double yC=eta*cosPhi0; - - // if(DEBUG) AOutput.logln(" Afit xCyC"+iHelix+" "+xC+" "+yC+" "+eta); - - double xVxC=fitted.get(0, 0)-xC; - double yVyC=fitted.get(1, 0)-yC; - - r=0.; - if(eta>0.) - r=Math.sqrt(xVxC*xVxC+yVyC*yVyC); - else - r=-Math.sqrt(xVxC*xVxC+yVyC*yVyC); - - d0=r-eta; - sinPhi=xVxC/r; - cosPhi=-yVyC/r; - double phi=Math.atan2(sinPhi, cosPhi); - - if(phi-phi0<-Math.PI) phi+=2.*Math.PI; - dPhi=phi-phi0; - s=dPhi*r; - z0=fitted.get(2, 0)-s*tau; - sinDPhi=Math.sin(dPhi); - cosDPhi=Math.cos(dPhi); - rho=1./r; - } - - Matrix getHelixdMdF() { - Matrix dMdF=new Matrix(5, 6); - - double curvature = parameterStore.get("Event", "Curvature").getD(); - dMdF.set(4, 0, -curvature*rho*rho*sinPhi); - dMdF.set(4, 1, curvature*rho*rho*cosPhi); - dMdF.set(4, 3, -curvature*rho*rho*cosDPhi); - dMdF.set(4, 5, -curvature*rho*rho*eta*sinDPhi); - dMdF.set(3, 4, 1.); - dMdF.set(2, 5, 1.); - dMdF.set(0, 0, sinPhi); - dMdF.set(0, 1, -cosPhi); - dMdF.set(0, 3, cosDPhi-1.); - dMdF.set(0, 5, eta*sinDPhi); - dMdF.set(1, 0, -tau*(sinPhi*dPhi+cosPhi)); - dMdF.set(1, 1, tau*(cosPhi*dPhi-sinPhi)); - dMdF.set(1, 2, 1.); - dMdF.set(1, 3, -tau*(dPhi*cosDPhi-sinDPhi)); - dMdF.set(1, 4, -s); - dMdF.set(1, 5, -tau*(eta*(dPhi*sinDPhi+cosDPhi)-r)); - return dMdF; - } - - Matrix helixFromFitted() { - Matrix helix=new Matrix(5, 1); - - helix.set(4, 0, rho*parameterStore.get("Event", "Curvature").getD()); - helix.set(3, 0, tau); - helix.set(2, 0, phi0); - helix.set(0, 0, d0); - helix.set(1, 0, z0); - return helix; - } - - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/data/package.html b/graphics/AtlantisJava/src/atlantis/data/package.html deleted file mode 100644 index 15056059d09..00000000000 --- a/graphics/AtlantisJava/src/atlantis/data/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head></head> -<body> -<p>All classes handling particular datatypes are part of this package. -They all implement AData from the atlantis.event package.</p> -</body> -</html> - diff --git a/graphics/AtlantisJava/src/atlantis/event/AAssociation.java b/graphics/AtlantisJava/src/atlantis/event/AAssociation.java deleted file mode 100755 index b2338def707..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AAssociation.java +++ /dev/null @@ -1,298 +0,0 @@ -package atlantis.event; - -import atlantis.utils.ALogger; - -/** - * Representation of the association between two data types. The association is - * stored using the string name+storeGateKey for both data types. - * - * The actual association is a an array of arrays of integers. The first index - * of this array is the index of an element in the first datatype. The array - * then contains the Athena IDs of the element in the second datatype that are - * associated to it. This is necessary because the second datatype might not - * have been read from the XML file yet, so the indices are unknown. - * - * @todo Modify this class to perform a translation of Athena ID to Atlantis ID - * for the identifiers of "b". This can be done together with purgeIDNotInData() - * and avoids the need for continuously looking up Athena IDs when drawing. - */ -public class AAssociation { - - /** Logger */ - private static final ALogger logger = ALogger.getLogger(AAssociation.class); - - /** Event this association belongs to */ - private final AEvent event; - - /** Identifying the datatype this association if from */ - private final String a; - - /** Identifying the datatype this association is to */ - private final String b; - - /** - * Association, the first index is the index of an element of "a", the - * second index then loops over the Athena IDs in "b" to which the element - * of "a" is associated. - */ - private final int[][] assoc; - - /** - * Constructor, taking as input a flat array (btoa) and an array that - * specifies how many entries correspond to each object in "a". - * - * For example: - * - * from = "Jet"; - * to = "Track"; - * numbtoa = {2, 0, 3}; - * btoa = {1, 5, 3, 4, 6}; - * - * This means that the first jet in the event (index=0) is associated - * to 2 tracks, namely index 1 and 5. The second jet has no associated - * tracks and the third jet (index=2) is associated to 3 tracks, indices - * 3, 4 and 6. - * - * Alternatively, numbtoa can be null. In that case the length of btoa has - * to be equal to the number of entries in "a". Every object in "a" will be - * associated to exactly one object in "b". - * - * @param from name+key this association is from, "a" - * @param to name+key this association is to, "b" - * @param numbtoa number of elements in "b" that each element in "a" is associated to - * @param btoa contents of the association in flat array - * @param e event object this association belongs to - */ - public AAssociation(String from, String to, int[] numbtoa, int[] btoa, AEvent e) { - - // Association to STr is done using barcodes, this is the only exception - // here: for barcodes ID=0 means no association. So we skip those entries. - boolean skipZero = to.startsWith("STr") && numbtoa == null; - - event = e; - a = from; - b = to; - - if (btoa == null) { - - assoc = null; - - } else { - - if (numbtoa != null) { - - // Multiple "b" entries associated to an "a" entry - assoc = new int[numbtoa.length][]; - - int num = 0; - for (int i = 0; i < numbtoa.length; ++i) { - if (numbtoa[i] <= 0) { - assoc[i] = new int[0]; - } else { - assoc[i] = new int[numbtoa[i]]; - } - - for (int j=0; j<numbtoa[i]; ++j) { - assoc[i][j] = btoa[num++]; - } - } - - } else { - - // Simple 1-on-1 association - assoc = new int[btoa.length][]; - - for (int i=0; i<btoa.length; i++) { - if (skipZero && btoa[i] <= 0) { - assoc[i] = new int[0]; - } else { - assoc[i] = new int[] { btoa[i] }; - } - } - } - - } - } - - /** - * Copy constructor - * - * @param from source datatype - * @param to target datatype - * @param associations association index arrays - * @param e event the association belongs to - */ - public AAssociation(String from, String to, int[][] associations, AEvent e) { - event = e; - a = from; - b = to; - assoc = associations; - } - - /** - * Get the name of association - * @return association name, concatenation of the two data types it associates - */ - public String getName() { - return a + b; - } - - /** - * Get source data type of association - * @return name of source data type - */ - public String getFrom() { - return a; - } - - /** - * Get target data type of association - * @return name of target data type - */ - public String getTo() { - return b; - } - - /** - * Get association array - * @return association array - */ - public int[][] getData() { - return assoc; - } - - /** - * Method that constructs the association b->a when only an association a->b - * currently exists. The complication here is due to the fact that "a" uses - * Atlantis indices (0, 1, ...), while "b" uses Athena IDs (1611690048, - * 1635282976, etc.). - * - * @return inverted association - */ - public AAssociation invert() { - - AData aData = event.get(a); - AData bData = event.get(b); - - if (aData == null || bData == null) { - logger.debug(getClass().getName() - + ": No association found between " + a + " and " + b); - return null; - - } else { - - try { - // New assoc will have the same number of entries as "b" - int[][] inv = new int[bData.getNumData()][]; - - // Athena IDs of object "a" - int[] ida = aData.getID(); - - // Loop over all entries in "a", the current association array - for (int i=0; i<assoc.length; ++i) { - if (assoc[i] != null) { - for (int j=0; j<assoc[i].length; ++j) { - - // For each associated entry in "b", we need to find - // the index from the Athena ID - int index = bData.getIndexFromId(assoc[i][j]); - - if (index != AData.NO_INVERSE) { - - if (inv[index] == null) { - - // The object in "a" is the first object that - // this object in "b" is associated to. Create - // a new array and add this entry. - inv[index] = new int[] { ida[i] }; - - } else { - - // The object in "b" is already associated to - // other objects in "a". Retrieve the other - // objects, increment the size and add the - // current object in "a". - int[] temp = new int[inv[index].length + 1]; - for (int k=0; k<inv[index].length; ++k) { - temp[k] = inv[index][k]; - } - temp[inv[index].length] = ida[i]; - inv[index] = temp; - } - } - } - } - } - return new AAssociation(b, a, inv, event); - - } catch (Exception e) { - logger.error("Unable to invert association.", e); - return null; - } - } - } // invert() --------------------------------------------------------------- - - /** - * Remove associations between items that are not present in the event data - */ - void purgeIDNotInData() { - // remove inconsistencies - // TRT hits from RTr<->SiCluster - // Association to an STr which does not exist in STr - - AData source = event.get(b); - if (assoc == null || source == null) { - return; - } - int INVALID_ID = -1; // (i hope!) - for (int i = 0; i < assoc.length; i++) { - if (assoc[i] != null) { - int num = 0; - for (int j = 0; j < assoc[i].length; j++) { - if (source.getIndexFromId(assoc[i][j]) == AData.NO_INVERSE) { - assoc[i][j] = INVALID_ID; - num++; - } - } - if (num > 0) { - if (num == assoc[i].length) { - assoc[i] = null; - } else { - int[] temp = new int[assoc[i].length - num]; - num = 0; - for (int j = 0; j < assoc[i].length; j++) { - if (assoc[i][j] != INVALID_ID) { - temp[num++] = assoc[i][j]; - } - } - assoc[i] = temp; - } - } - } - } - } - - /** - * Convert association into an informational message for the user - */ - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - s.append(a).append(" to ").append(this.b); - if (assoc == null) { - s.append(" is empty\n"); - return s.toString(); - } else { - s.append("\n"); - for (int i = 0; i < assoc.length; i++) { - if (assoc[i] != null) { - for (int j = 0; j < assoc[i].length; j++) { - s.append(assoc[i][j]).append(" "); - } - s.append("\n"); - } - } - } - return s.toString(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AAssociationManager.java b/graphics/AtlantisJava/src/atlantis/event/AAssociationManager.java deleted file mode 100755 index cc1cbedaf47..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AAssociationManager.java +++ /dev/null @@ -1,118 +0,0 @@ -package atlantis.event; - - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import atlantis.utils.ALogger; - -public class AAssociationManager -{ - private static ALogger logger = ALogger.getLogger(AAssociationManager.class); - - private Map<String, AAssociation> associations = new HashMap<String, AAssociation>(); - - public AAssociationManager() {} - - public void clear() - { - associations = new HashMap<String, AAssociation>(); - } - - public void add(AAssociation a) - { - associations.put(a.getName(), a); - } - - public void remove(String key) - { - associations.remove(key); - } - - public int[][] get(String a, String b) - { - Object o = associations.get(a + b); - if(o != null) - { - return((AAssociation) o).getData(); - } - else - { - o = associations.get(b + a); - if(o != null) - { - //AOutput.logln("AAssociationManager.get()\n" + - // "querying non-existing association from-" + a + "-to-" + b + - // "\ncalculating inverse association ...") ; - AAssociation ass = ((AAssociation) o).invert(); - // following test prevents Atlantis from crashing if there - // is something wrong with the association between clusters - // and cells - if(ass != null) - { - add(ass); - return ass.getData(); - } - else - { - String name = "AAssociationManager.get(): "; - logger.debug(name + "No association " + - "found between " + a + " and " + b); - return null; - } - } - } - return null; - } // get() -------------------------------------------------------------- - - - public AAssociation getAssociation(String a, String b) - { - return (AAssociation) associations.get(a + b); - } - - public void correct() - { - Collection<AAssociation> c = associations.values(); - for (AAssociation a : c) { - a.purgeIDNotInData(); - } - } - - - public String[] getKnownAssociations(String a) - { - Collection<AAssociation> c = associations.values(); - Set<String> list = new TreeSet<String>(); - for (AAssociation ass : c) { - if(ass.getFrom().equals(a)) - { - list.add(ass.getTo()); - } - else if(ass.getTo().equals(a)) - { - list.add(ass.getFrom()); - } - } - return (String[]) list.toArray(new String[list.size()]); - } - - - public String getAllKnownAssociations() - { - Collection<AAssociation> col = associations.values(); - StringBuilder r = new StringBuilder(); - int c = 0; - - for (AAssociation ass : col) { - c++; - r.append(c + " association from " + ass.getFrom() + " to " + - ass.getTo() + " (name: " + ass.getName() + ")\n"); - } - - return r.toString(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/ABufferedEventSource.java b/graphics/AtlantisJava/src/atlantis/event/ABufferedEventSource.java deleted file mode 100644 index 7d089cf7ce8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/ABufferedEventSource.java +++ /dev/null @@ -1,263 +0,0 @@ -package atlantis.event; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.ALogger; -import java.util.Vector; - -/** - * Extension class to AEventSource providing buffering for a fixed number of events. - * @author sboeser - */ -public abstract class ABufferedEventSource implements AEventSource { - - //Logging interface - private final static ALogger logger = ALogger.getLogger(ABufferedEventSource.class); - - //The index of the currently selected event in the list - private static int currentEvent = -1; - //The maximum number of events to save - public static int maxNumberOfEvents = 1; - //A vector of available events - private static Vector<AEvent> eventContainer = new Vector<AEvent>(); - // the current event navigation mode - private NavigationMode eventNavigationMode = NavigationMode.SEQUENTIAL; - - /** - * Abstract read next event method to be implemented by all subclasses - * @return the next event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - protected abstract AEvent readNext(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException; - /** - * Abstract read previous event method to be implemented by all subclasses - * @return the previous event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - protected abstract AEvent readPrevious(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException; - - /** - * Get the next event, either from the buildin buffer or by reading it in - * @return the next event - * @throws atlantis.event.AEventSource.NoMoreEventsException - * @throws atlantis.event.AEventSource.InvalidEventSourceException - * @throws atlantis.event.AEventSource.ReadEventException - */ - public AEvent nextEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException - { - //Check if we are already at the last event - if (currentEvent == eventContainer.size()-1){ - - //if so, try to get another event - AEvent event = null; - try{ - event = readNext(getCurrentEventInfo()); - } catch ( OutOfMemoryError oom ) { - - //throw an error message - logger.error("Ran out of memory while reading event data"); - - //See if we can clear memory by removing events - if ( getNumberOfEvents() > 0) { - //be verbose - logger.info("Clearing event cache and retry..."); - //remove events - clearEventContainer(); - //Call garbage collector to free resources - System.gc(); - //Now retry (no current event) - event = readNext(null); - } - } - - //Add it to the eventContainer as last one - addEvent(event,false); - - } else { - // simply increase event counter - setCurrentEvent(currentEvent+1); - } - - //Now return the new current event - return eventContainer.get(currentEvent); - } - - public AEvent previousEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException { - - //Check if we are already at the first event - if (currentEvent <= 0 ){ - - //if so, try to get another event - AEvent event = null; - try{ - event = readPrevious(getCurrentEventInfo()); - } catch ( OutOfMemoryError oom ) { - - //throw an error message - logger.error("Ran out of memory while reading event data"); - - //See if we can clear memory by removing events - if ( getNumberOfEvents() > 0) { - //be verbose - logger.info("Clearing event cache and retry..."); - //remove events - clearEventContainer(); - //Call garbage collector to free resources - System.gc(); - //Now retry (no current event) - event = readPrevious(null); - } - } - - //Add it to the eventContainer as first one - addEvent(event,true); - - } else { - // simply decrease event counter - setCurrentEvent(currentEvent-1); - } - - //Now return the new current event - return eventContainer.get(currentEvent); - - } - - /** - * Get the event navigation mode for the current source. - * @return current event navigation mode - */ - public NavigationMode getNavigationMode() { - return eventNavigationMode; - } - - /** - * Set the event navigation mode for the current source, - * clears the buffer and reads the first event. - * Throws InvalidEventSourceException if the current - * source does not support the requested mode - * @param mode requested event navigation mode - */ - public void setNavigationMode(NavigationMode mode) throws InvalidEventSourceException - { - if(supportsNavigationMode(mode)) { - NavigationMode oldMode = getNavigationMode(); - eventNavigationMode = mode; - - // empty the buffer - clearEventContainer(); - } else - throw new InvalidEventSourceException("Mode '"+mode.name()+"' not supported by current source"); - } - - /** - * Checks whether the current event source supports - * a particular display mode. - * @return true if the mode is supported - * @param mode requested event navigation mode - */ - public abstract boolean supportsNavigationMode(NavigationMode mode); - - /** - * Returns number of events saved in the eventContainer - * @return int - */ - public int getNumberOfEvents() - { - return eventContainer != null ? eventContainer.size() : 0; - - } - - /** - * Add the given even to the event container. By default, events are added - * to the end of the container. If skipping backward, it may be necessary to - * add to the beginning of the container, as indicated by the asFirst flag - * The new event will also be set as default event - * - * @param event the event to add - * @param asFirst whether to add the event at the beginning (default is end) - */ - private synchronized void addEvent(AEvent event, boolean asFirst) - { - //create event container if it does not exist - if(eventContainer == null) eventContainer = new Vector<AEvent>(); - - //Make sure container does not get too large - while (eventContainer.size() >= maxNumberOfEvents){ - // remove at the side at which we are not adding event - if (asFirst) eventContainer.remove(eventContainer.lastElement()); - else eventContainer.remove(0); - } - - //At the end or at the beginning - int index = (asFirst) ? 0 : eventContainer.size(); - - //add the event - eventContainer.add(index,event); - - //be verbose - logger.debug(eventContainer.size() + " event(s) in memory"); - - //set as current event - setCurrentEvent(index); - } - - - /** - * Clear the event container, reset the current event - */ - protected synchronized void clearEventContainer() - { - //Make sure the event container exits before clearing it - if(eventContainer != null){ - // let the user know - String msg = "Clearing event container with "+getNumberOfEvents()+" events."; - logger.warn(msg); - AOutput.append(msg, ALogInterface.WARNING); - - //Clear the container - eventContainer.clear(); - } - - //Alse reset current event - currentEvent = -1; - - //Run the garbage collector to free space immediately - System.gc(); - - } - - private void setCurrentEvent(int index) { - //Check for out-of-bounds - if ((index < 0) || ( index >= eventContainer.size())) - throw new ArrayIndexOutOfBoundsException("Cannot set index "+index+" in event container of size "+eventContainer.size()); - currentEvent = index; - } - - /** - * @return the curent event or null if there is none - */ - private AEventInfo getCurrentEventInfo(){ - - //Check if the current event is there - try { - //get the current events name - return eventContainer.get(currentEvent); - } catch (ArrayIndexOutOfBoundsException ex){ - //return an empty string if there is no current event - return null; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AData.java b/graphics/AtlantisJava/src/atlantis/event/AData.java deleted file mode 100644 index 6bf4541ac22..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AData.java +++ /dev/null @@ -1,1661 +0,0 @@ -package atlantis.event; - -import java.awt.Component; -import java.util.Vector; -import java.util.Collection; -import javax.swing.Action; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.canvas.AWindow; -import atlantis.data.ACompositeParticleData; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.ADrawable; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.list.AListManager; -import atlantis.output.AExceptionHandler; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjection3D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.utils.A4Vector; -import atlantis.utils.AHashMap; -import atlantis.utils.AIntHashtable; -import atlantis.utils.AMath; -import atlantis.list.AListProcessor; -import atlantis.utils.ALogger; - -/** - * Base class which holds the data from a subdetector (e.g. TRT) This - * representation is appropriate for data with a static number of entries but - * not for example for reconstructed vertices the number of which may be changed - * interactively by the user. AData should perhaps become an interface. - */ -abstract public class AData implements ADrawable, AListProcessor { - private static final ALogger logger = ALogger.getLogger(AData.class); //the event that this data belongs to - protected static AEventManager eventManager = AEventManager.instance(); - protected static APar parameterStore = APar.instance(); - protected static Component guiComponent = AGlobals.instance().getGuiFrame(); - protected final AEvent event; - protected static final int NO_INVERSE = -1; - protected int numData; - protected int numDraw; - protected int[] listdl; - protected byte[] color; - protected int[] id; - protected AIntHashtable indexFromId; - protected String storeGateKey = null; - protected final String PARAMETER_GROUP = getParameterGroup(); - - abstract protected int internalColor(); - - abstract protected void applyCuts(); - - abstract public String getNameScreenName(); - - abstract public String getHitInfo(int index); // pick info - - abstract public String getParameterGroup(); - // Holds the projection object that we are currently drawing on. This is *NOT* the same - // as ACanvas.getCanvas().getCurrentWindow().getProjection(), since this function gives - // the projection in the active window. Particularly at startup windows will be redrawn - // without being the active window. Hence this variable. - // - // By the way: this is also inherently bad design. Why does the data need - // to know about the projection? The main flaw is that the data draws itself, - // rather then the graphics context drawing the data - S.B. - protected AProjection2D currentProjection; - - // dummy version, only applies to dynamic data sources (e.g. RecVertex (RVx)) - public void remove(int[] index) {} - - // used to finalize the state of this object - // after all other AData objects are essentially built - // e.g. calculate the number of S3D hits on a track after both are read - protected void finalizeConstruction() {} - - // x y and z are now stored - // rho and phi arrays are only correct after a call to this function - protected void calculateRhoPhi() {} - - // used by rubberband in V-Plot - public String getVPHitInfo() { - return ""; - } - - public AData(AHashMap p, AEvent e) { - //save reference to the event this data belongs to - event = e; - - numData = p.getInt("numData"); - numDraw = numData; - listdl = new int[numData]; - color = new byte[numData]; - - storeGateKey = (String) p.get("storeGateKey"); - if ("".equals(storeGateKey) || storeGateKey == null) { - storeGateKey = null; - } - - if (p.get("id") != null) { - id = p.getIntArray("id"); - } else { - id = new int[numData]; - for (int i = 0; i < numData; i++) { - // start IDs calculated in Atlantis from 0, should be the same - // as in JiveXML - id[i] = i; - } - } - - indexFromId = new AIntHashtable(id); - } // AData() - - AData(Node node, AEvent e) { - //save reference to the event this data belongs to - event = e; - numData = 0; - NodeList children = node.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { - numData++; - } - } - numDraw = numData; - listdl = new int[numData]; - color = new byte[numData]; - id = new int[numData]; - for (int i = 0; i < numData; i++) { - id[i] = i; - } - indexFromId = new AIntHashtable(id); - } - - public AEvent getEvent(){ - return event; - } - - public int getIndexFromId(int id) { - return indexFromId.get(id); - } - - public final A4Vector get4Vector() { - makeDrawList(); - return get4Vector(numDraw, listdl); - } - - // only applies to data which can provide 4 vectors - public A4Vector get4Vector(int num, int[] list) { - return null; - } - - // only applies to data which can provide 4 vectors - public A4Vector get4Vector(int num, int[] list, double mass) { - return null; - } - - public int getNumData() { - return numData; - } - - public int getNumDraw() { - return numDraw; - } - - public int getDrawIndex(int index) { - return this.listdl[index]; - } - - public int[] getID() { - return id; - } - - protected int getNum(String name, int index) { - int[][] ass = event.getAssociationManager().get(getFullName(), name); - if (ass != null && ass[index] != null) { - return ass[index].length; - } else { - return 0; - } - } - - protected int[] getNum(String name) { - int[][] ass = event.getAssociationManager().get(getFullName(), name); - int[] num = new int[numData]; - if (ass != null) { - for (int i = 0; i < ass.length; ++i) { - if (ass[i] != null) { - num[i] = ass[i].length; - } - } - } - return num; - } - - public byte[] getColor() { - color(); - byte[] temp = new byte[id.length]; - - for (int i = 0; i < temp.length; i++) { - temp[i] = color[getIndexFromId(id[i])]; - } - return temp; - } - - public int[] getColor(int[] dl) { - color(); - int[] temp = new int[dl.length]; - - for (int i = 0; i < temp.length; i++) { - temp[i] = color[dl[i]]; - } - return temp; - } - - public int getColor(int index){ - return color[index]; - } - - public void makeDrawList() { - calculateRhoPhi(); - constructDefaultDrawlist(); - applyCuts(); - } - - public void constructDefaultDrawlist() { - if (!parameterStore.get("CutsATLAS", "ByList").getStatus()) { - // if some hits are on a list they must be drawn last - int[][] temp = AListManager.getInstance().getColorMapping(this); - int[] index = temp[0]; - int[] ctemp = temp[1]; - if (index.length > 0) { - // AOutput.logln("AData.constructDefaultDrawlist() numData = " + - // numData); - int[] c = new int[numData]; - final int NONE = -999; - for (int i = 0; i < numData; ++i) { - c[i] = NONE; - } - for (int i = 0; i < index.length; ++i) { - c[index[i]] = ctemp[i]; - } - numDraw = 0; - for (int i = 0; i < numData; ++i) { - if (c[i] == NONE) { - listdl[numDraw++] = i; - } - } - for (int i = 0; i < numData; ++i) { - if (c[i] != NONE && c[i] != AColorMap.INVISIBLE) { - listdl[numDraw++] = i; - // nb invisible are not in the drawlist - } - } - } else { - // this is the standard case - numDraw = numData; - for (int i = 0; i < numDraw; ++i) { - listdl[i] = i; - } - } - } else { - // drawlist set by cuts..... - boolean[] selected = AListManager.getInstance().getSelection(this); - numDraw = 0; - for (int i = 0; i < selected.length; ++i) { - if (selected[i]) { - listdl[numDraw++] = i; - } - } - } - } - - // provides the draw list as a boolean array parallel to the data array - protected boolean[] isDrawn() { - boolean[] drawn = new boolean[numData]; - - for (int i = 0; i < numDraw; i++) { - drawn[listdl[i]] = true; - } - return drawn; - } - - public void cut(String groupName, String parameterName, String text, float[] array) { - AParameter par = parameterStore.get(groupName, parameterName); - - if (par != null && par.getStatus() && array != null) { - double value = par.getD(); - String operator = par.getOperator(); - int num = 0; - - if (par.isModulus()) { - if (operator.equals("<")) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) < value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">")) { - // '>' really means '>=' for reals since they are real in - // from ascii file and don't have full precison - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) >= value) { - listdl[num++] = listdl[i]; - } - } - } else { - throw new Error(operator + " operator not sensible for floats"); - } - } else { - if (operator.equals("<")) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] < value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">")) { - // '>' really means '>=' for reals since they are real in - // from ascii file - // and don't have full precison - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] >= value) { - listdl[num++] = listdl[i]; - } - } - } else { - throw new Error(operator + " operator not sensible for floats"); - } - } - numDraw = num; - } - } - - protected void cut(String groupName, String parameterName, String text, int[] array) { - AParameter par = parameterStore.get(groupName, parameterName); - - if (par != null && par.getStatus() && array != null) { - int value = par.getI(); - - // consider two special cases: Electron/isEM and Photon/isEM - if (parameterName.endsWith("isEM")) { - if (!isEMValidate(value)) { - return; - } - String binaryString = Integer.toBinaryString(value); - Vector<String> possibleValues = getPossibleValues(binaryString); - cutIsEM(text, array, possibleValues); - } else { - String operator = par.getOperator(); - boolean modulus = par.isModulus(); - - cut(text, modulus, array, operator, value); - } - } - } - - protected void cut(String text, int[] array, String operator, int value) { - cut(text, false, array, operator, value); - } - - protected void cut(String text, boolean modulus, int[] array, String operator, int value) { - int num = 0; - - if (modulus) { - if (operator.equals("<")) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) < value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">")) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) > value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("=") || operator.equals("==")) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) == value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("!=") || operator.equals(AMath.NOTEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) != value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("<=") || operator.equals(AMath.LESSEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) <= value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">=") || operator.equals(AMath.GREATEREQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (Math.abs(array[listdl[i]]) >= value) { - listdl[num++] = listdl[i]; - } - } - } else { - throw new Error(operator + " operator not sensible for integers"); - } - } else { - if (operator.equals("<")) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] < value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">")) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] > value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("=") || operator.equals("==")) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] == value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("!=") || operator.equals(AMath.NOTEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] != value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("<=") || operator.equals(AMath.LESSEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] <= value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">=") || operator.equals(AMath.GREATEREQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (array[listdl[i]] >= value) { - listdl[num++] = listdl[i]; - } - } - } else { - throw new Error(operator + " operator not sensible for integers"); - } - } - numDraw = num; - } - - // cut based on the i'th item in the data array - public void cutIndex() { - AParameter par = parameterStore.get("CutsATLAS", "Index"); - - if (par.getStatus()) { - int value = par.getI(); - String operator = par.getOperator(); - int num = 0; - - if (operator.equals("<")) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] < value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">")) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] > value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("=") || operator.equals("==")) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] == value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("!=") || operator.equals(AMath.NOTEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] != value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals("<=") || operator.equals(AMath.LESSEQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] <= value) { - listdl[num++] = listdl[i]; - } - } - } else if (operator.equals(">=") || operator.equals(AMath.GREATEREQUAL)) { - for (int i = 0; i < numDraw; i++) { - if (listdl[i] >= value) { - listdl[num++] = listdl[i]; - } - } - } else { - throw new Error(operator + " operator not sensible for integers"); - } - numDraw = num; - } - } - - protected void cutArray(int[] value, int cutValue, String description) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - - if (value[listdl[i]] == cutValue) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - protected void cutArray(byte[] value, int cutValue, String description) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - - if (value[listdl[i]] == cutValue) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - //isEMString cut declaration - // - // Clone of above cut, but to allow values less than or equal to the cut value - // At the moment, Specific to isEMString for Electrons and Photons, and isTauString. - // - protected void cutArrayEnum(Vector<Enum> value, int cutValue, String description) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - if ((value.get(listdl[i]).ordinal()) <= cutValue) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - // End isEMString cut declaration - - protected void cutArray(boolean[] value, boolean cutValue, String description) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - if (value[listdl[i]] == cutValue) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - protected void cutArrayOR(int[] value, int cutValue1, int cutValue2, - String description) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - if (value[listdl[i]] == cutValue1 || value[listdl[i]] == cutValue2) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - // apply phi+-deltaphi cut to lines (e.g. TRT) - protected void cutPhi(float[] phi, float[] dphi) { - AParameter par = parameterStore.get("CutsATLAS", "CutPhi"); - - if (!par.getStatus()) { - return; - } - double phiCut = Math.toRadians(par.getD()); - double phiMid = Math.toRadians(AMath.nearestPhiDegrees(parameterStore.get("CutsATLAS", "PhiMiddle").getD())); - double phiLowerCut = phiMid - phiCut; - double phiUpperCut = phiMid + phiCut; - int num = 0; - - for (int i = 0; i < numDraw; i++) { - int list = listdl[i]; - double phiHit = AMath.nearestPhiRadians(phi[list], phiMid); - double phiLower = phiHit - dphi[list]; - double phiUpper = phiHit + dphi[list]; - - if (phiUpper - phiLowerCut > 1.0e-6 && phiUpperCut - phiLower > 1.0e-6) { - listdl[num++] = list; - } - } - numDraw = num; - } - - /** Apply phi+-deltaphi cut to points (e.g. S3D) */ - public void cutPhi(float[] phi) { - AParameter par = parameterStore.get("CutsATLAS", "CutPhi"); - boolean usePhiCut = par.getStatus(); - - if (usePhiCut) { - double phiCut = Math.toRadians(Math.abs(par.getD())); - double phiMid = Math.toRadians(AMath.nearestPhiDegrees(parameterStore.get("CutsATLAS", "PhiMiddle").getD())); - int num = 0; - - for (int i = 0; i < numDraw; i++) { - double phiDiff = Math.abs(AMath.nearestPhiRadians(phi[listdl[i]], phiMid) - phiMid); - - if (phiCut - phiDiff > 1.0e-6) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - } - - /** apply eta+-deltaeta cut to points (e.g. S3D) */ - public void cutEta(float[] eta) { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - boolean useEtaCut = par.getStatus(); - - if (useEtaCut) { - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - int num = 0; - - for (int i = 0; i < numDraw; i++) { - double etaDiff = Math.abs(eta[listdl[i]] - etaMid); - - if (etaCut - etaDiff > 1.0e-6) { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - } - - protected void colorByConstant() { - if (!PARAMETER_GROUP.equals("CompositeParticle")) { - int constantColor = parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - - for (int i = 0; i < numData; i++) { - color[i] = (byte) constantColor; - } - } else { - ACompositeParticleData compositeParticles = (ACompositeParticleData) this; - compositeParticles.makeDrawList(); - for (int e = 0; e < compositeParticles.getNumDraw(); ++e) { - int list = compositeParticles.getDrawIndex(e); - switch (Math.abs(compositeParticles.getPdgId(list))) { - case 13: - color[list] = (byte) parameterStore.get("Muon", "Constant").getI(); - break; - case 11: - color[list] = (byte) parameterStore.get("Electron", "Constant").getI(); - break; - case 22: - color[list] = (byte) parameterStore.get("Photon", "Constant").getI(); - break; - case 5: - color[list] = (byte) parameterStore.get("BJet", "Constant").getI(); - break; - case 15: - color[list] = (byte) parameterStore.get("TauJet", "Constant").getI(); - break; - case 24: - color[list] = (byte) parameterStore.get("CompositeParticle", "ConstantW").getI(); - break; - case 6: - color[list] = (byte) parameterStore.get("CompositeParticle", "ConstantTop").getI(); - break; - case 25: - color[list] = (byte) parameterStore.get("CompositeParticle", "ConstantH").getI(); - break; - - default: - if (compositeParticles.getTypeEV(list).equals("EVParticleJet")) { - color[list] = (byte) parameterStore.get("Jet", "Constant").getI(); - } else { - color[list] = (byte) parameterStore.get("CompositeParticle", "Constant").getI(); - } - } - } - } - } - - - /** Colour by index. - * e.g. colorByIndex(indexBy(phi)); - * will allow nearby phi tracks to be coloured differently. - * @param index - */ - protected void colorByIndex(int[] index) { - int numColors = parameterStore.get("HitColors", "Number").getI(); - - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) { - color[index[i]] = (byte) col[i % numColors]; - } - } - - protected void colorByIndex() { - int numColors = parameterStore.get("HitColors", "Number").getI(); - - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) { - color[i] = (byte) col[i % numColors]; - } - } - - protected void colorByCollection() { - int constantColor = parameterStore.get(PARAMETER_GROUP, "Constant").getI(); - int numColors = parameterStore.get("HitColors", "Number").getI(); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - AEvent ev = eventManager.getCurrentEvent(); - // vector with store gate keys for a particular datatype name: this.getName() - Vector<String> v = ev.getCollections().get(this.getName()); - int keyIndex = 0; - if (v != null && (keyIndex = v.indexOf(this.getStoreGateKey())) != -1) { - // v is null - requested datatype name doesn't exists in the current - // event - - // if keyIndex is -1 it means the current - // store gate key doesn't exists in the current event (for a datatype - // which exists in the current event) - // previous event(s) are being drawn and this colouring function - // won't work for them but only for the current event - - // constant colour index is used purely as modifier so as all datatypes - // coloured by colletictions don't start at the same colour ... - keyIndex += constantColor; - for (int i = 0; i < numData; i++) { - color[i] = (byte) col[keyIndex % numColors]; - } - } else { - logger.debug("colorByCollection(): can't colour by collection"); - } - - } // colorByCollection() ------------------------------------------------ - - /** - * Colour another class by association. This class is providing the colour, - * we assign colours from the local class to the target using col[] and id[][]. - * - * @param col target class colour array - * @param id association array from this class to the target class - * @param unconnectedColor colour for unconnected hits - * @param sharedColor colour for shared hits - */ - protected void colorByAssociation(AData target, int[][] id, - byte unconnectedColor, byte sharedColor) { - - // All hits are unconnected by default - for (int i=0; i<target.color.length; i++) { - target.color[i] = unconnectedColor; - } - - if (id == null) return; - - // Loop over drawn objects in this class, then colour the other elements - // that are associated. i iterates over the drawn items, j is the true - // index and k refers to an associated item in the target class, with true - // index l. - for (int i=0; i<numDraw; i++) { - int j = listdl[i]; - - if (id[j] != null) { - for (int k = 0; k < id[j].length; k++) { - int l = target.getIndexFromId(id[j][k]); - - if (l < 0) continue; - - if (target.color[l] != unconnectedColor) { - // If item l was already connected, that means it is shared - target.color[l] = sharedColor; - } else { - // Assign associated item l the colour of item j in the local class - target.color[l] = this.color[j]; - } - } - } - } - } // colorByAssociation() ----------------------------------------------- - - protected void setColor(int index, byte color) { - if (index >= 0 && index < this.color.length) { - this.color[index] = color; - } else { - logger.debug(getClass().getName() + ": Set color for data with index = " + index); - } - } - - protected void setColor(byte color) { - for (int i = 0; i < this.color.length; i++) { - this.color[i] = color; - } - } - - protected void colorBy(int[] coloringVariable) { - int numColors = parameterStore.get("HitColors", "Number").getI(); - - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - - for (int i = 0; i < numData; i++) { - color[i] = (byte) col[coloringVariable[i] % numColors]; - } - } - - protected void colorBy(String colorGroup, int[] coloringVariable) { - int numColors = parameterStore.get(colorGroup, "Number").getI(); - - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray(colorGroup, "C1", numColors); - - for (int i = 0; i < numData; i++) { - color[i] = (byte) col[coloringVariable[i] % numColors]; - } - } - - protected void colorBy(float[] Pt) { - int numColors = parameterStore.get("HitColors", "Number").getI(); - - numColors = Math.min(7, numColors); - int[] col = parameterStore.getArray("HitColors", "C1", numColors); - for (int i = 0; i < numData; i++) { - int icol = 0; - if (Math.abs(Pt[i]) < 2) { - icol = 4; //lichtblauw - } else if (Math.abs(Pt[i]) < 4) { - icol = 2; //blauw - } else if (Math.abs(Pt[i]) < 10) { - icol = 5; //paars - } else if (Math.abs(Pt[i]) < 40) { - icol = 3; //oranje - } else { - icol = 0; //rood - } - color[i] = (byte) col[icol]; - } - } - - public String getName() { - return getParameterGroup(); - } - - public String getStoreGateKey() { - return storeGateKey; - } - - // x y from rho phi - protected void calculateXY(float[] rho, float[] phi, float[] x, float[] y) { - for (int i = 0; i < x.length; ++i) { - x[i] = (float) (rho[i] * Math.cos(phi[i])); - y[i] = (float) (rho[i] * Math.sin(phi[i])); - } - } - - /** Calculate rho phi from x y */ - protected void calculateRhoPhi(float[] x, float[] y, float[] rho, float[] phi) { - // [2007-07-20] method is again always called from AData.makeDrawList() - // but reference to primary vertex is removed, it's not taken into account now - // double[] pVtx = Atlantis.getEventManager().getCurrentEvent().getPrimaryVertex(); - // double dx = x[i] - pVtx[0]; - // double dy = y[i] - pVtx[1]; - - for (int i = 0; i < rho.length; i++) { - double dx = x[i]; - double dy = y[i]; - - rho[i] = (float) (Math.sqrt(dx * dx + dy * dy)); - phi[i] = (float) (Math.atan2(dy, dx)); - if (phi[i] < 0.) { - phi[i] += AMath.TWO_PI; - } - } - } - - /** Draw the data form this detector on this window and projection */ - public void draw(AWindow window, AGraphics ag, AProjection2D projection) { - ag.draw(window.calculateDisplay(getUser(projection))); - } - - /** Get the data from a projection without non linear transform applied. - * @param projection - * @return - */ - protected ACoord getUserNoTransform(AProjection projection) { - ACoord data = ACoord.NO_DATA; - // don't use reflection as debugging is then harder - if (projection instanceof AProjectionYX) { - data = getYXUser(); - } else if (projection instanceof AProjectionFR) { - data = getFRUser(); - } else if (projection instanceof AProjectionRZ) { - data = getRZUser(); - } else if (projection instanceof AProjectionXZ) { - data = getXZUser(); - } else if (projection instanceof AProjectionYZ) { - data = getYZUser(); - } else if (projection instanceof AProjectionFZ) { - data = getFZUser(); - } else if (projection instanceof AProjectionVP) { - data = getVPUser(); - } else if (projection instanceof AProjection3D) { - data = get3DUser(); - } - - return data; - } - - /** Get the data form a projection with non linear transform applied. */ - protected ACoord getUser(AProjection2D projection) { - currentProjection = projection; - return projection.nonLinearTransform(getUserNoTransform(projection)); - } - - /** Should the polygon from this detector be drawn or filled? */ - protected int getDrawOrFill() { - return AGraphics.DRAW; - } - - /** - * Prints info about association in which AData:index participates - * (pick + n (navigate) - * @param index int - * @return String - */ - public String navigate(int index) { - StringBuilder temp = new StringBuilder(); - String assocKey = getFullName(); - String[] knownAssoc = event.getAssociationManager().getKnownAssociations(assocKey); - temp.append(" associated to:\n"); - for (int i = 0; i < knownAssoc.length; i++) { - AData source = eventManager.getCurrentEvent().get(knownAssoc[i]); - if (source == null) continue; - int[][] ass = event.getAssociationManager().get(assocKey, knownAssoc[i]); - if (ass != null && ass[index] != null) { - for (int x = 0; x < ass[index].length; x++) { - temp.append(" " + knownAssoc[i] + " id: " + ass[index][x] + - " index: " + source.getIndexFromId(ass[index][x]) + "\n"); - } - } - } - return temp.toString(); - - } // navigate() --------------------------------------------------------- - - private boolean isEMValidate(int inputValue) { - if (inputValue > 65535) { - String displayMessage = "isEM is a 16-bit binary data, maximum is 65535"; - AExceptionHandler.processException("warning", displayMessage.toString()); - return false; - } - return true; - } - - // "1" means a wildcard, can be "0" or "1" - private Vector<String> getPossibleValues(String bStr) { - Vector<String> possibleValues = new Vector<String>(); - if (bStr.length() == 1) { - possibleValues.add("0"); - if (bStr.charAt(0) == '1') { - possibleValues.add("1"); - } - } else { - Vector<String> possibleValuesWithoutFirstChar = getPossibleValues(bStr.substring(1)); - for (int i = 0; i < possibleValuesWithoutFirstChar.size(); i++) { - String str = possibleValuesWithoutFirstChar.get(i); - possibleValues.add("0" + str); - if (bStr.charAt(0) == '1') { - possibleValues.add("1" + str); - } - } - - } - return possibleValues; - } - - private void cutIsEM(String text, int[] array, Vector<String> possibleValues) { - int num = 0; - - for (int i = 0; i < numDraw; i++) { - for (int j = 0; j < possibleValues.size(); j++) { - String str = possibleValues.get(j); - int value = Integer.parseInt(str, 2); - if (array[listdl[i]] == value) { - listdl[num++] = listdl[i]; - break; - } - } - } - - numDraw = num; - } - - /** - * Track name + Track storeGateKey is returned according to selected - * Track collection in InDet -> Track -> TrackCollection listbox - * @return String - */ - protected String getReconstructedTracks() { - AData tracks = eventManager.getCurrentEvent().getTrackData("InDetTrack"); - String r = null; - if (tracks != null) { - r = tracks.getName() + tracks.getStoreGateKey(); - } - - return r; - - } // getReconstructedTracks() --------------------------------------------- - - /** - * Jet + Jet storeGateKey is returned according to selected - * Jet collection in ATLAS -> Jet -> JetCollection listbox - * @return String - */ - protected String getJets() { - AData jets = eventManager.getCurrentEvent().getJetData(); - String r = null; - if (jets != null) { - r = jets.getName() + jets.getStoreGateKey(); - } - - return r; - - } // getJets() ---------------------------------------------------------- - - /** - * RVx + RVx storeGateKey is returned according to selected - * vertex collection in InDet -> RecVertex -> VerteCollection listbox - * @return String - */ - protected String getRVx() { - AData rvx = eventManager.getCurrentEvent().getRVxData(); - String r = null; - if (rvx != null) { - r = rvx.getName() + rvx.getStoreGateKey(); - } - - return r; - - } // getRVx() ---------------------------------------------------------- - - protected AData getObjectCollection(String type) { - return eventManager.getCurrentEvent().getData(type); - } - - /** - * Cluster + Cluster storeGateKey is returned according to selected - * Cluster collection in Calo -> Cluster -> Cluster listbox - * @return String - */ - protected String getClusters() { - AData clusters = eventManager.getCurrentEvent().getClusterData(); - String r = null; - if (clusters != null) { - r = clusters.getName() + clusters.getStoreGateKey(); - } - - return r; - - } // getClusters() ------------------------------------------------------ - - public int[] getDrawList() { - return listdl; - - } // getDrawList() ------------------------------------------------------ - - /** Apply eta+-deltaEta cut to points (e.g. S3D) */ - protected void cutEta(float[] rho, float[] z) - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - boolean useEtaCut = par.getStatus(); - - if(useEtaCut) - { - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLower = etaMid - etaCut; - double etaUpper = etaMid + etaCut; - int num = 0; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double eta = AParameterUtilities.eta(z[list], rho[list]); - - if(eta - etaLower > 1.0e-6 && etaUpper - eta > 1.0e-6) - listdl[num++] = list; - } - numDraw = num; - } - } - - - /** Apply eta+-deltaEta cut to lines perpendicular to beam axis */ - protected void cutEtaDRho(float[] rho, float[] z, float[] drho) - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - boolean useEtaCut = par.getStatus(); - - if(useEtaCut) - { - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double eta1 = AParameterUtilities.eta(z[list], rho[list] + drho[list]); - double eta2 = AParameterUtilities.eta(z[list], rho[list] - drho[list]); - double etaLower = Math.min(eta1, eta2); - double etaUpper = Math.max(eta1, eta2); - - if(etaUpper - etaLowerCut > 1.0e-6 - && etaUpperCut - etaLower > 1.0e-6) - listdl[num++] = list; - } - numDraw = num; - } - } - - /** Apply eta+- deltaEta cut to lines parallel to beam axis */ - protected void cutEtaDZ(float[] rho, float[] z, float[] dz) - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - boolean useEtaCut = par.getStatus(); - - if(useEtaCut) - { - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double etaLower = AParameterUtilities.eta(z[list] - dz[list], rho[list]); - double etaUpper = AParameterUtilities.eta(z[list] + dz[list], rho[list]); - - if(etaUpper - etaLowerCut > 1.0e-6 - && etaUpperCut - etaLower > 1.0e-6) - listdl[num++] = list; - } - numDraw = num; - } - } - - /** apply eta+-deltaeta cut to lines (e.g. TRT) */ - protected void cutEtaDEta(float[] eta, float[] deta) - { - AParameter par = parameterStore.get("CutsATLAS", "CutEta"); - - if(!par.getStatus()) - return; - double etaCut = Math.abs(par.getD()); - double etaMid = parameterStore.get("CutsATLAS", "EtaMiddle").getD(); - double etaLowerCut = etaMid - etaCut; - double etaUpperCut = etaMid + etaCut; - int num = 0; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - double etaLower = eta[list] - deta[list]; - double etaUpper = eta[list] + deta[list]; - - if(etaUpper - etaLowerCut > 1.0e-6 - && etaUpperCut - etaLower > 1.0e-6) - listdl[num++] = list; - } - numDraw = num; - - } - - - - /** - * - * @param sourceDatatype name of the datatype according to - * which the cut is being done - * @param beingCutDatatype name of the datatype which is - * being cut - * @param cutOption integer value of the cut option in GUI - */ - protected void cutByAssociationTo(String sourceDatatype, - String beingCutDatatype, int cutOption) - { - if(cutOption == 0) - { - // SA select all - // do nothing, draw everything - return; - } - - AEvent ev = eventManager.getCurrentEvent(); - AData source = ev.get(sourceDatatype); - int[][] assoc = event.getAssociationManager().get(beingCutDatatype, sourceDatatype); - if (assoc == null || source == null) { - AData being = ev.get(beingCutDatatype); - String screenName; - if(being!=null)screenName= being.getNameScreenName(); - else screenName="null"; - logger.warn(screenName + " - null (" + beingCutDatatype + " - " - + sourceDatatype +") association, nothing to draw"); - // if 'connected' or 'unconnected' is selected and association - // or datatype to associate with doesn't exist, draw nothing - // (numDraw = 0) - numDraw = 0; - return; - } - - if(cutOption == 1) - { - // SC select connected - int num = 0; - // first remove those not connected to anything - for(int i = 0; i < numDraw; i++) - { - if(assoc[listdl[i]] != null) - { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - // if tracks exist apply cuts to them - numDraw = source.cutByAssociation(numDraw, listdl, assoc); - } - else if(cutOption == 2) - { - // SU select unconnected - int num = 0; - for(int i = 0; i < numDraw; i++) - { - if(assoc[listdl[i]] == null) - { - listdl[num++] = listdl[i]; - } - } - numDraw = num; - } - - } // cutByAssociationTo() ----------------------------------------------- - - - - private int cutByAssociation(int numDraw, int[] listdl, int[][] id) - { - // aaargh danger modifies input listdl - makeDrawList(); - boolean[] drawn = isDrawn(); - int num = 0; - - for(int i = 0; i < numDraw; i++) - { - int list = listdl[i]; - if(id[list] != null) - { - for(int j = 0; j < id[list].length; ++j) - { - int inverse = indexFromId.get(id[list][j]); - if(inverse != NO_INVERSE && drawn[inverse]) - listdl[num++] = list; - break; - } - } - } - numDraw = num; - return numDraw; - } - - /** - * return graphics attributes corresponding to layer =0 frame layer =1 hits - * or tracks type=0 noise type=1 non-noise - */ - public ADrawParameters getDrawParameters(int layer, int type) - { - boolean draw = true; - int singleColor = -1; - int size = 10; - int lineWidth = 1; - int symbol = 0; - int frameWidth = 0; - boolean forceSymbols = false; - int minSize = 0; - - AParameter forceSymbolsPar = parameterStore.getUnknown(PARAMETER_GROUP, "ForceSymbols"); - AParameter symbolSize = parameterStore.getUnknown(PARAMETER_GROUP, "SymbolSize"); - AParameter symbolType = parameterStore.getUnknown(PARAMETER_GROUP, "Symbol"); - AParameter lineWidthPar = parameterStore.getUnknown(PARAMETER_GROUP, "LineWidth"); - - if(forceSymbolsPar != null) - { - forceSymbols = forceSymbolsPar.getStatus(); - if(forceSymbols && symbolSize != null) - minSize = Math.max(symbolSize.getI(), 1); - } - - if(symbolSize != null) - size = symbolSize.getI(); - if(symbolType != null) - symbol = symbolType.getI(); - if(lineWidthPar != null) - lineWidth = lineWidthPar.getI(); - //for etmiss, line width scaled by energy by using the stroke setting - if(lineWidth<=0) - lineWidth = 1; - - if(type == 0) - { - AParameter noiseSymbolType = parameterStore.getUnknown(PARAMETER_GROUP, "Noise"); - - if(noiseSymbolType != null && noiseSymbolType.getStatus()) - { - AParameter noiseSymbolSize = parameterStore.getUnknown(PARAMETER_GROUP, "NoiseSize"); - AParameter noiseWidth = parameterStore.getUnknown(PARAMETER_GROUP, "NoiseWidth"); - - if(noiseSymbolSize != null) - size = noiseSymbolSize.getI(); - if(noiseWidth != null) - lineWidth = noiseWidth.getI(); - symbol = noiseSymbolType.getI(); - } - else - { - AParameter noiseWidth = parameterStore.getUnknown(PARAMETER_GROUP, "NoiseWidth"); - - if(noiseWidth != null && noiseWidth.getStatus()) - lineWidth = noiseWidth.getI(); - } - } - - if(layer == 0) - { - AParameter frameWidthPar = parameterStore.getUnknown(PARAMETER_GROUP, "FrameWidth"); - if(parameterStore.get(PARAMETER_GROUP, "Frame")!=null) - { - boolean drawFrame = parameterStore.get(PARAMETER_GROUP, "Frame").getStatus(); - singleColor = parameterStore.get(PARAMETER_GROUP, "Frame").getI(); - //only draw frames for Grey/BW color maps if is selected to draw frames - if(drawFrame && AColorMap.drawFrames()) - { - if(frameWidthPar != null) - frameWidth = frameWidthPar.getI(); - } - } - } - return new ADrawParameters(draw, singleColor, size, lineWidth, - frameWidth, symbol, forceSymbols, minSize, getDrawOrFill()); - } - - /** Provide an array of indices with increasing a, - * used e.g. by coloring. - * @param a - * @return - */ - protected int[] indexBy(double[] a) - { - int[] index = new int[a.length]; - - for(int i = 0; i < a.length; i++) - index[i] = i; - // this is only cosmetic improvement in appearance so if input data too - // large simply return null - if(a.length > 1000) - return index; - - for(int i = 0; i < a.length - 1; i++) - for(int j = i + 1; j < a.length; j++) - if(a[index[i]] > a[index[j]]) - { - int temp = index[i]; - index[i] = index[j]; - index[j] = temp; - } - return index; - } - - /** - * Colour items in this class by the associated class that is given by - * association. The difference with the method colorByAssociation is that - * colorBy is called on the target class, while colorByAssociation is called - * on the source class of the colour. (i.e. colour hits by tracks invokes - * AHitData.colorBy("Tracks"), calling ATrackData.colourByAssociation(...) - * internally. - * - * @param otherClass source class for the colours - */ - protected void colorBy(String otherClass) - { - AData source = eventManager.getCurrentEvent().get(otherClass); - byte unconnected = (byte) parameterStore.get(PARAMETER_GROUP, "Unconnected").getI(); - if(source != null) - { - byte shared = (byte) parameterStore.get(PARAMETER_GROUP, "Shared").getI(); - String assocKey = getFullName(); - int[][] assoc = event.getAssociationManager().get(otherClass, assocKey); - source.makeDrawList(); - source.color(); - source.colorByAssociation(this, assoc, unconnected, shared); - - } - else - { - /* - * given association doesn't exist. for instance, there are only - * hits in the event file and nothing to associate them with. - * if some 'association colouring' (e.g. colour by reconstructed - * track) is selected in that case, the items appear all in - * 'unconnected' colour. another option is to colour them in - * constant colour, simply by calling only colorByConstant(); - */ - for(int i = 0; i < numData; i++) - { - color[i] = (byte) unconnected; - } - } - - } // colorBy() ---------------------------------------------------------- - - protected void colorByObjects() - { - // initially set all with unconnected color, connected will be changed later - byte unconnectedColor = (byte) parameterStore.get(PARAMETER_GROUP, "Unconnected").getI(); - setColor(unconnectedColor); - String[] objectList = new String[] {"Jet", "BJet", "TauJet", "Photon", "Electron", "Muon"}; - for(int i=0; i<objectList.length; ++i) - { - if (parameterStore.get("Data", objectList[i]).getStatus()) - colorByObject(getObjectCollection(objectList[i])); - } - } - - private void colorByObject(AData objectData) - { - if(objectData == null) - { - return; - } - - AEnumeratorParameter listBox = (AEnumeratorParameter) parameterStore.get(getName(), getName() + "Collections"); - String selectedCollection = listBox.getCurrentText(); - if(!("All".equals(selectedCollection) || "None".equals(selectedCollection))) - { - String assName = getName(); - if(getName().indexOf("Track") >= 0) - assName = "Track"; - AAssociation assoc = event.getAssociationManager().getAssociation(objectData.getName()+objectData.getStoreGateKey(), assName); - if(assoc != null) - { - if(!(assoc instanceof AObjectsAssociation)) - { - logger.warn(getClass().getName() + ": no objects association is found!"); - return; - } - int[][] associatedIndex = ((AObjectsAssociation) assoc).getData(); - String[] associatedKey = ((AObjectsAssociation) assoc).getKey(); - - // if currently selected collection is included in associatedKey, show associations - // otherwise using the color set for unconnected cluster/track - int objectIndex = 0; - for(int i=0; i<associatedKey.length;) - { - // objectIndex is the index of the associated object (e.g. Electron) - // associatedIndex[objectIndex][] contain the index of the associated Cluster/Track - if ("none".equals(associatedKey[i])) - { - i++; - objectIndex++; - } - else - { - if (associatedKey[i].equals(selectedCollection)) - for(int j=0; j<associatedIndex[objectIndex].length; ++j) - setColor(associatedIndex[objectIndex][j], objectData.getColor()[objectIndex]); - i+=associatedIndex[objectIndex++].length; - } - } - } - } - } - - /** - * The same as name, but if it's multiple collection datatype, the full - * name is getName() + getStoreGateKey() - * @return String - */ - public String getFullName() - { - String k = this.getStoreGateKey(); - String full = this.getName() + (k != null ? k : ""); - return full; - } - - public int getIdFromIndex(int index) - { - return id[index]; - } - - // sets the color of each hit - protected final void color() - { - // standard scheme - internalColor(); - int[][] temp = AListManager.getInstance().getColorMapping(this); - int[] index = temp[0]; - int[] c = temp[1]; - // now add in colors specified in lists - - for(int i = 0; i < index.length; ++i) - if(c[i] >= 0) - color[index[i]] = (byte) c[i]; - int others = AListManager.getInstance().getColorOfOthers(); - // need to check if this data could have been picked - // so that coloring of hits by STr works even if STr - // is not in list because it wasn't on.... - if(others >= 0 && parameterStore.get("Data", getName()).getStatus()) - { - boolean[] inList = new boolean[numData]; - for(int i = 0; i < index.length; ++i) - inList[index[i]] = true; - - for(int i = 0; i < numData; ++i) - if(!inList[i]) - color[i] = (byte) others; - } - - - - } - - - /** Type = e.g. noise/good */ - public int[] getType(int[] dl) - { - return new int[dl.length]; - } - - // get data representation in user space in different projections - // empty by default - protected ACoord getYXUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getRZUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getYZUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getXZUser() - { - return ACoord.NO_DATA; - } - - protected ACoord get3DUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getUserUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getUserUser2() - { - return ACoord.NO_DATA; - } - - protected ACoord getFRUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getFZUser() - { - return ACoord.NO_DATA; - } - - protected ACoord getVPUser() - { - return ACoord.NO_DATA; - } - - public int getNumTypes() - { - return 1; - } - - - /** The only method from AListProcessor interface. */ - @Override - public Action[] getActions(Collection nodes) - { - return new Action[0]; - } // getActions() ------------------------------------------------------- - - /** - * Function to split a list of items seperated by - - */ - public String[] splitItems(String origItems) - { - char[] origItemsChar = origItems.toCharArray(); - int origItemsLength = origItems.length(); - int spacePosition=0, noOfItems=0, count=0; - //calculate the number of items - for(int i=0;i<origItemsLength;i++) - if((i!=0 && origItemsChar[i]=='-') || (i==origItemsLength-1 && origItemsChar[i]!='-')) - noOfItems++; - //split up the array into newItems - if(noOfItems>0) - { - //string array to hold individual items - String[] newItems=new String[noOfItems]; - for(int i=0;i<origItemsLength;i++) - { - if(i==0 && origItemsChar[i]=='-') - spacePosition=i+1;//ignore first'-' - else if(i==origItemsLength-1 && origItemsChar[i]!='-') - { - //store the text from previous '-' upto end if doesn't end with '-' - newItems[count]=origItems.substring(spacePosition,i+1); - spacePosition=i+1; - count++; - } - else if(origItemsChar[i]=='-' && i!=0) - { - //store the text from previous '-' upto current '-' - newItems[count]=origItems.substring(spacePosition,i); - spacePosition=i+1; - count++; - } - } - return newItems; - } - else - return null; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AEpsImageProducer.java b/graphics/AtlantisJava/src/atlantis/event/AEpsImageProducer.java deleted file mode 100644 index eef4e9615f1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEpsImageProducer.java +++ /dev/null @@ -1,117 +0,0 @@ -package atlantis.event; - -import java.io.File; -import java.io.IOException; - -import atlantis.utils.*; -import atlantis.canvas.ACanvas; -import atlantis.graphics.encoders.AImageEncoder; -import java.awt.Dimension; - - -/** - * Implements ANewEventListener and creates EPS files - * upon each newEvent call. A scale factor allows to e.g. produce thumbnails by - * scaling down image. The image producer works in two modes: - * a) If no file name is given, a file name will be generated from run and event - * number. In case the output file exists, no file is created but a warning is written out. - * b) If a file name is given, a temporary file is generated first, and then - * renamed to the given file name. If renaming fails, a warning is written out - * and the temporary file is deleted. - * - * @author Sebastian Boeser - */ - -public class AEpsImageProducer extends AImageProducer -{ - // the logger - private static final ALogger logger = ALogger.getLogger(AEpsImageProducer.class); - - // Our image encode - private final AImageEncoder imageEncoder = new AImageEncoder(); - - /** - * Fully qualified constructor, - * intializing all the attributes and check the parameters validity - * @param dir the directory in which to save all the files - * @param size the dimensions of the images - * @param scale the factor by which to scale the images - * @param fileName if not null, that file will be overwritten for each event - * @throws InstantiationException if we fail to create the object - */ - public AEpsImageProducer(String dir, Dimension size, double scale, String fileName) throws InstantiationException - { - super(dir, size, scale, fileName); - } - - /** - * Called whenever a new event appears. Store an EPS in the directory, - * either with a generated file name (no overwrite) or with a fixed file name (overwrite) - * @param event the event from which to generate the EPS - */ - public void newEvent(AEvent event) - { - - //If auto had been set for size (height is negative), get height from Canvas - if (imageSize.height < 0) imageSize.setSize(imageSize.width, ACanvas.getCanvas().getRespectiveHeight(imageSize.width)); - - //Create the file to write the data into - File outFile; - //If we don't have a fixed file name, - //generate a unique one based on run- and event number - if (fixedFileName==null){ - - //Now construct all the full path for the file we want to save - String outFileName = String.format("%s%s%s.eps",directory, - System.getProperty("file.separator"), - getEventFileName(event)); - - // Create file handles to the file and check if it exists - outFile = new File(outFileName); - //Do not overwrite any existing files - if (outFile.exists()) { - logger.warn("File "+ outFileName +" already exists - will not overwrite"); - return; - } - //otherwise generate a temporary file first, - //then move it in place later - } else { - //make a temporary file in the final directory - try { - outFile = File.createTempFile(filePrefix+"_", ".eps",directory); - } catch (IOException ex) { - logger.warn("Failed to create temporary file in "+directory.getAbsolutePath()); - return; - } - } - - //Now try saving the acquired data, - //and if it shall go to a fixed file, move it there - try { - imageEncoder.saveEPS(imageSize.width, imageSize.height, outFile); - - //move to fixed file name if requested - if (fixedFileName != null){ - - //Get a handle to the final destination - File fixedFile = new File(directory,fixedFileName); - - //delete target if exits - if (fixedFile.exists() && (!fixedFile.delete())) - throw new IOException("Failed to delete existing file "+fixedFile.getAbsolutePath()); - - //And move the new file in place - if (!outFile.renameTo(fixedFile)) - throw new IOException("Failed to rename temporary file to "+fixedFile.getAbsolutePath()); - } - } catch (IOException ioe) { - //If we fail, throw a warning - logger.warn("Could not save EPS files for history\n"+ioe.toString()); - } finally { - //In any case, delete the pngFile, if it was just temporary - if (fixedFileName != null) outFile.delete(); - } - - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AEvent.java b/graphics/AtlantisJava/src/atlantis/event/AEvent.java deleted file mode 100755 index beeae482f16..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEvent.java +++ /dev/null @@ -1,1051 +0,0 @@ -package atlantis.event; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Vector; -import java.util.TreeMap; -import java.util.LinkedHashMap; -import java.util.Set; - -import atlantis.list.AListManager; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.parameters.APar; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; -import atlantis.data.*; -import atlantis.globals.AGlobals; - -/** - * AEvent is the Container for an ATLAS physics event. - * It is identified by deriving from AEventInfo and holds a map of all the - * data that is available in the event. - * - */ -public class AEvent extends AEventInfo -{ - private static ALogger logger = ALogger.getLogger(AEvent.class); - - // container with all datatypes within the event - private Map<String,AData> data = new HashMap<String,AData>(); - // storegate keys for collections-aware datatypes - // Use parameterized type but keep Hashtable and Vector instead of HashMap - // and ArrayList until I work out if thread safety is an issue. - Ben 31/1/11 - private Hashtable<String,Vector<String>> collections = new Hashtable<String,Vector<String>>(); - - private AAssociationManager assocmgr = new AAssociationManager(); - - private static APar parameterStore = APar.instance(); - - /** - * @param eventNumber the event number - * @param runNumber the run number - * @param dateTime the date and time of the event - * @param sourceName the name of the event source - * @param lumiBlock the lumiBlock number - */ - public AEvent(String eventNumber, String runNumber, String dateTime, String sourceName, String lumiBlock, String eventProperties) { - - //Initialize event information - super(Integer.parseInt(eventNumber), Integer.parseInt(runNumber), dateTime, sourceName, lumiBlock, eventProperties); - - } // AEvent() ----------------------------------------------------------- - - /** - * @return the hashtable of available collections - */ - public Hashtable<String,Vector<String>> getCollections(){ - return collections; - } // getCollections() --------------------------------------------------- - - - public void add(AData dataSet) throws AAtlantisException - { - String name = dataSet.getClass().getName(); - - int index = name.lastIndexOf('.'); - if(index >= 0 && index < name.length() - 1) - { - name = name.substring(index + 1); - } - - // remove the "A" and "Data" - name = name.substring(1, name.length() - 4); - String newKey = dataSet.getStoreGateKey(); - - if(newKey == null) - { - // no storegatekey comes with this dataset (datatype) - // hash data shouldn't contain entry under sourceName key, if it does - // the old one is replaced - data.put(name, dataSet); - } - else - { - // just checking for the same key at the datatypes in the event - if(data.containsKey(name + newKey)) - { - String msg = "Error - datatype " + name + " with storeGateKey\n" + - newKey + " already exists in this event."; - AAtlantisException aaex = new AAtlantisException(msg); - // Stuck the trace in the logging for good measure - AD - logger.error("\n" + msg, aaex); - throw aaex; - } - else - { - data.put(name + newKey, dataSet); - // saving key of a particular sourceName (datatype) - Vector<String> keys = new Vector<String>(); - if(collections.containsKey(name)) - { - keys = collections.get(name); - if(keys.contains(newKey)) - { - String msg = "Previously read datatype " + name + "\n" + - "(different collection) contained " + - "storeGateKey " + newKey + ". Error."; - AAtlantisException aaex = new AAtlantisException(msg); - logger.error(msg, aaex); - throw aaex; - } - else - { - keys.add(newKey); - collections.put(name, keys); - } - } - else - { - keys.add(newKey); - collections.put(name, keys); - } - } - } - - } // add() --------------------------------------------------------------- - - - - - - // < get<DATA_TYPE> methods > ------------------------------------------- - - - public AData get(String name) - { - return data.get(name); - } - - public AData[] getData() - { - AData[] aData = new AData[data.size()]; - Collection<AData> collection = data.values(); - return collection.toArray(aData); - } - - - /** - * AJetData getJetData() - * returns collection of Jet datatype according to selected - * collection (Jet storeGateKey) in ATLAS -> Jet -> Jet Collection - * if 'all' (or 'none') is selected - returns null (no association will - * be taken into account) - * @return AJetData - */ - public AJetData getJetData() - { - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("Jet", "JetCollections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) -{ - logger.debug("AEvent.getJetData(): " + selectedKey + - " is selected in Jet->JetCollection, no association " + - " to Jet is taken into account, null is returned"); - return null; - } - else - { - AJetData jet = (AJetData) data.get("Jet" + selectedKey); - return jet; - } - } - - - // can combine with the other methods (e.g. getClusterData) - public AData getData(String type) - { - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get(type, type+"Collections"); - String selectedKey = (listBox == null) ? "" : listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) { - - logger.debug("AEvent.getData(String type): " + selectedKey + - " is selected in " + type + "->" + type + " Collections, " + - "no association to " + type + " is taken into account."); - - return null; - } - else - { - return data.get(type + selectedKey); - } - } - - /** - * AClusterData getClusterData() - * returns collection of Cluster datatype according to selected - * collection (Cluster storeGateKey) in ATLAS -> Cluster -> Cluster Collection - * if 'all' (or 'none') is selected - returns null (no association will - * be taken into account) - * @return AClusterData - */ - public AClusterData getClusterData() - { - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("Cluster", "ClusterCollections"); - String selectedKey = listBox.getCurrentText(); - if ("All".equals(selectedKey) || "None".equals(selectedKey)) { - - logger.debug("AEvent.getClusterData(): " + selectedKey + - " is selected in Cluster->ClusterCollection, no association " + - " to Cluster is taken into account, null is returned"); - - return null; - } - else - { - AClusterData cluster = (AClusterData) data.get("Cluster" + selectedKey); - return cluster; - } - } - - - /** - * ATrackData getTrackData(String type) - * type is InDetTrack, MuonTrack - the internal datatype sourceName for Track - * returns collection of Track datatype according to selected - * collection (Track storeGateKey) in InDet -> Track -> TrackCollection - * if 'all' (or 'none') is selected - returns null (no association will - * be taken into account) - * @param type String - * @return ATrackData - */ - public ATrackData getTrackData(String type) - { - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get(type, type + "Collections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) - { - logger.debug("AEvent.getTrackData(" + type + "): " + selectedKey + - " is selected in Track->TrackCollection, no association " + - " to Track is taken into account, null is returned"); - return null; - } - else - { - ATrackData track = (ATrackData) data.get(type + selectedKey); - return track; - } - } - - - /** - * ATrackData getTrackData(String type, String key) - * returns specified collection of Track datatype if it exists - * @param type String - * @param key String - * @return ATrackData - */ - public ATrackData getTrackData(String type, String key) - { - Vector<String> keys = collections.get(type); - if(keys == null) { - logger.warn("AEvent: " + type + " datatype doesn't exist " + - "in current event"); - return null; - } - else - { - if(keys.contains(key)) - { - return (ATrackData) data.get(type + key); - } - else { - - logger.warn("AEvent: " + type + " datatype: storeGateKey " + - key + " doesn't exist in current event"); - return null; - } - } - } - - - - - public ASTrData getSTrData() - { - return (ASTrData) data.get("STr"); - } - - public ASNPData getSNPData() - { - return (ASNPData) data.get("SNP"); - } - - public APixelClusterData getPixelClusterData() - { - return (APixelClusterData) data.get("PixelCluster"); - } - - public ASiClusterData getSiClusterData() - { - return (ASiClusterData) data.get("SiCluster"); - } - - public AS3DData getS3DData() - { - return (AS3DData) data.get("S3D"); - } - - public ATRTData getTRTData() - { - return (ATRTData) data.get("TRT"); - } - - public ALArData getLArData() - { - return (ALArData) data.get("LAr"); - } - - public ATILEData getTILEData() - { - return (ATILEData) data.get("TILE"); - } - - public AHECData getHECData() - { - return (AHECData) data.get("HEC"); - } - - public AFCALData getFCALData() - { - return (AFCALData) data.get("FCAL"); - } - - public AMBTSData getMBTSData() - { - return (AMBTSData) data.get("MBTS"); - } - - //Because some things need to access the data before the parameters are filled, another method - //for accessing the data has been added. This method first checks the list of available storegate keys - //and see's if there is one starting with MDT. As the dataType + storegatekey is hard coded into how - //the hash map keys are created this should be a stable way of doing it. If there are multiple - //results for the search, it then checks which one is currently selected by the user. - - public AMDTData getMDTData() - { - Vector<String> storeGateKeys = new Vector<String>(); - Set<String> keys = data.keySet(); - for(String entry : keys){ - if(entry.startsWith("MDT")){ - storeGateKeys.add(entry); - } - } - if(storeGateKeys.size() == 1){ - return (AMDTData) data.get(storeGateKeys.get(0)); - }else{ - - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("MDT", "MDTCollections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) - { - logger.debug("AEvent.getMDTata(): " + selectedKey + - " is selected in MDT->MDTCollection, no association " + - " to MDT is taken into account, null is returned"); - return null; - - } - else{ - AMDTData mdt = (AMDTData) data.get("MDT" + selectedKey); - return mdt; - } - - - } - - } - - //See description for getMDTData - - public ARPCData getRPCData() - { - - Vector<String> storeGateKeys = new Vector<String>(); - Set<String> keys = data.keySet(); - for(String entry : keys){ - if(entry.startsWith("RPC")){ - storeGateKeys.add(entry); - } - } - if(storeGateKeys.size() == 1){ - return (ARPCData) data.get(storeGateKeys.get(0)); - }else{ - - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("RPC", "RPCCollections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) - { - logger.debug("AEvent.getRPCData(): " + selectedKey + - " is selected in RPC->RPCCollection, no association " + - " to RPC is taken into account, null is returned"); - return null; - - } - else{ - ARPCData rpc = (ARPCData) data.get("RPC" + selectedKey); - return rpc; - } - - - } - } - //See description for getMDTData - - public ATGCData getTGCData() - { - Vector<String> storeGateKeys = new Vector<String>(); - Set<String> keys = data.keySet(); - for(String entry : keys){ - if(entry.startsWith("TGC")){ - storeGateKeys.add(entry); - } - } - if(storeGateKeys.size() == 1){ - return (ATGCData) data.get(storeGateKeys.get(0)); - }else{ - - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("TGC", "TGCCollections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) - { - logger.debug("AEvent.getTGCData(): " + selectedKey + - " is selected in TGC->TGCCollection, no association " + - " to TGC is taken into account, null is returned"); - return null; - - } - else{ - ATGCData tgc = (ATGCData) data.get("TGC" + selectedKey); - return tgc; - } - - - } - } - //See description for getMDTData - - public ACSCDData getCSCDData() - { - Vector<String> storeGateKeys = new Vector<String>(); - Set<String> keys = data.keySet(); - for(String entry : keys){ - if(entry.startsWith("CSC")){ - storeGateKeys.add(entry); - } - } - if(storeGateKeys.size() == 1){ - return (ACSCDData) data.get(storeGateKeys.get(0)); - }else{ - - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("CSC", "CSCCollections"); - String selectedKey = listBox.getCurrentText(); - if("All".equals(selectedKey) || "None".equals(selectedKey)) - { - logger.debug("AEvent.getCSCData(): " + selectedKey + - " is selected in CSC->CSCCollection, no association " + - " to CSC is taken into account, null is returned"); - return null; - - } - else{ - ACSCDData csc = (ACSCDData) data.get("CSC" + selectedKey); - return csc; - } - - - } - } - - public ASVxData getSVxData() - { - return (ASVxData) data.get("SVx"); - } - - public ARVxData getRVxData() - { - AEnumeratorParameter listBox = - (AEnumeratorParameter) parameterStore.get("RVx", "RVxCollections"); - String selectedKey = listBox.getCurrentText(); - if ("All".equals(selectedKey)) { - - logger.debug("AEvent.getRVxData(): " + selectedKey + - " is selected in InDet->RecVertex, no association " + - " to vertex is taken into account, null is returned"); - - return null; - } else if ("None".equals(selectedKey)) { - // Return collection without for backwards compatibility - return (ARVxData) data.get("RVx"); - } else - { - ARVxData rvx = (ARVxData) data.get("RVx" + selectedKey); - return rvx; - } - } - - public ATrigS3DData getTrigS3DData() - { - return (ATrigS3DData) data.get("TrigS3D"); - } - - public ALVL1TriggerTowerData getLvl1TriggerTowerData() - { - return (ALVL1TriggerTowerData) data.get("LVL1TriggerTower"); - } - - public ALVL1ResultData getLvl1ResultData() - { - return (ALVL1ResultData) data.get("LVL1Result"); - } - - public ALVL1JetElementData getLvl1JetElementData() - { - return (ALVL1JetElementData) data.get("LVL1JetElement"); - } - - public ATriggerInfoData getTriggerInfoData() - { - return (ATriggerInfoData) data.get("TriggerInfo"); - } - - /** - * This function returns the names currently selected for a certain collection - * which has its data draw status set to true - * @param collectionType String sourceName of the collection - * @return string of collection names length 0 if none in event - */ - public String[] getActiveCollectionNames(String collectionType) - { - //LVL1Result is not on the Data list as it is always on hence check this first - boolean collectionStatus = collectionType.equals("LVL1Result"); - if(!collectionStatus) - collectionStatus=parameterStore.get("Data", collectionType).getStatus(); - if (collectionStatus) - { - return getCollectionNames(collectionType); - } - else - return new String[0]; - } - - /** - * This function returns the names currently selected for a certain collection - * @param collectionType String sourceName of the collection - * @return string of collection names length 0 if none in event - */ - public String[] getCollectionNames(String collectionType) - { - String[] col; - Vector<String> keys = collections.get(collectionType); - if (keys != null) - { - String[] collec = keys.toArray(new String[keys.size()]); - AEnumeratorParameter listBox = (AEnumeratorParameter) parameterStore.get(collectionType, collectionType + "Collections"); - String currentSelection = listBox.getCurrentText(); - int count=0; - //count how many items in list - for (int i = 0; i < collec.length; i++) - { - if ("All".equals(currentSelection) || collec[i].equals(currentSelection)) - count++; - } - col=new String[count]; - count=0; - //now save items into string array - for (int i = 0; i < collec.length; i++) - { - if ("All".equals(currentSelection) || collec[i].equals(currentSelection)) - { - col[count] = collectionType + collec[i]; - count++; - } - } - return col; - } - else - return new String[0]; - } - - // </ get<DATA_TYPE> methods > -------------------------------------------- - - public List<ACalorimeterData> getCalorimeters() - { - List<ACalorimeterData> v = new ArrayList<ACalorimeterData>(); - Iterator<AData> i = data.values().iterator(); - while(i.hasNext()) - { - AData data = i.next(); - if(data instanceof ACalorimeterData) - { - ACalorimeterData calorimeter = (ACalorimeterData) data; - if(parameterStore.get("Data", calorimeter.getCalorimeterName()).getStatus() && - (parameterStore.getUnknown("Det", calorimeter.getCalorimeterName() + "Fill") == null - || parameterStore.get("Det", calorimeter.getCalorimeterName() + "Fill").getStatus())) - { - v.add(calorimeter); - } - } - } - return v; - - } // getCalorimeters() --------------------------------------------------- - - - - public List<AData> getHitsAndTracks(AProjection projection) - { - int mode = parameterStore.get(projection.getName(), "Mode").getI(); - String[][] det = new String[0][0]; - String[] simTr = new String[0]; - String[] recTr = new String[0]; - String[] hits = new String[0]; - String[] aod = new String[0]; - - if(mode == 0 || projection instanceof AProjectionVP - || projection instanceof AProjectionLegoPlot) - { - simTr = new String[] { "STr", "SNP", "SMTr" }; - recTr = new String[] { "InDetSegment", "MuonSegment", "G4Step", - "InDetTrack", "MuonTrack" }; - - aod = new String[] {"CompositeParticle", "BJet", "TauJet", "Photon", "Electron", "Muon" }; - - if(parameterStore.get("InDetDrawingOrder", "SpacePoints").getI() == 0) - { - hits = new String[] {"UserHit", "RVx", "TRT", "SiCluster", - "SiClusterRDO", "S3D", "PixelCluster", "PixelRDO", "TrigS3D", - "MDT", "CSCD", "CSC", "RPC", "R3D", "TGC", "T3D", "SVx", - "Jet", "EmTauROI", "Particle", "Cluster", "ETMis", - "JetROI", "MuonROI", "LVL1TriggerTower", "LVL1JetElement"}; - } - else - { - hits = new String[] {"UserHit", "RVx", "TRT", "SiCluster", - "SiClusterRDO", "TrigS3D", "S3D", "PixelCluster", "PixelRDO", - "MDT", "CSCD", "CSC", "RPC", "R3D", "TGC", "T3D", "SVx", - "Jet", "EmTauROI", "Particle", "Cluster", "ETMis", - "JetROI", "MuonROI", "LVL1TriggerTower", "LVL1JetElement"}; - } - } - else if(projection instanceof AProjectionYX - || projection instanceof AProjectionFR) - { - if(mode >= AProjectionYX.MODE_MDT_INNER && mode <= AProjectionYX.MODE_MDT_OUTER) - { - simTr = new String[] { "SMTr", "SMTr" }; - recTr = new String[] { "MuonTrack", "MuonSegment" }; - if(mode == AProjectionYX.MODE_MDT_INNER) - { - hits = new String[] { "MDT", "CSCD", "CSC" }; - } - else - { - hits = new String[] { "MDT" }; - } - } - else if(mode < AProjectionYX.MODE_MDT_INNER) - { - simTr = new String[] { "SMTr", "SMTr" }; - recTr = new String[] { "MuonTrack", "MuonSegment" }; - hits = new String[] { "TGC", "T3D" }; - } - } - else if(projection instanceof AProjectionFZ) - { - if(mode >= 4) - { - simTr = new String[] { "SMTr", "SMTr" }; - recTr = new String[] { "MuonTrack", "MuonSegment" }; - hits = new String[] { "MDT" }; - } - else - { - simTr = new String[] { "SMTr", "SMTr" }; - recTr = new String[] { "MuonTrack", "MuonSegment" }; - hits = new String[] { "RPC", "R3D" }; - } - } - - if(parameterStore.get("InDetDrawingOrder", "SpacePointsTracks").getI() == 0) - { - // Simulated tracks, reconstructed tracks, hits - det = new String[][] { simTr, recTr, hits, aod }; - } - else if(parameterStore.get("InDetDrawingOrder", "SpacePointsTracks").getI() == 1) - { - // Simulated tracks, hits, reconstructed tracks - det = new String[][] { simTr, hits, recTr, aod }; - } - else - { - // Reconstructed tracks, hits, simulated tracks - det = new String[][] { recTr, hits, simTr, aod }; - } - - AEnumeratorParameter listBox = null; - List<AData> v = new ArrayList<AData>(); - for(int i = 0; i < det.length; ++i) - { - for(int j = 0; j < det[i].length; ++j) - { - if(collections.containsKey(det[i][j])) - { - Vector<String> keys = collections.get(det[i][j]); - String[] array; - array = keys.toArray(new String[keys.size()]); - // GUI listbox sourceName datatype + "Collections" - listBox = (AEnumeratorParameter) parameterStore.get(det[i][j], - det[i][j] + "Collections"); - String currentSelection = listBox.getCurrentText(); - for(int c = 0; c < array.length; c++) - { - if("All".equals(currentSelection) || - array[c].equals(currentSelection)) - { - AData a = data.get(det[i][j] + array[c]); - processDataSet(v, a); - } - } - } - else - { - AData a = data.get(det[i][j]); - processDataSet(v, a); - } - } - } - return v; - - } // getHitsAndTracks() ------------------------------------------------- - - - private static void processDataSet(List<AData> v, AData a) - { - if(a != null) - { - if(parameterStore.getUnknown("Data", a.getName()) != null && - parameterStore.get("Data", a.getName()).getStatus() && - (parameterStore.getUnknown("Det", a.getName() + "Fill") == null || - parameterStore.get("Det", a.getName() + "Fill").getStatus())) - { - v.add(a); - } - } - - } // processDataSet() --------------------------------------------------- - - - - public List<ACalorimeterData> getElectromagneticCalorimeters() - { - List<ACalorimeterData> v = new ArrayList<ACalorimeterData>(); - Iterator<AData> i = data.values().iterator(); - while(i.hasNext()) - { - AData a = i.next(); - if(a instanceof ALArData || a instanceof AFCALData) - { - v.add((ACalorimeterData)a); - } - } - return v; - - } // getElectromagneticCalorimeters() ------------------------------------ - - - - public List<ACalorimeterData> getHadronicCalorimeters() - { - List<ACalorimeterData> v = new ArrayList<ACalorimeterData>(); - Iterator<AData> i = data.values().iterator(); - while(i.hasNext()) - { - AData a = i.next(); - if(a instanceof ATILEData || a instanceof AHECData - || a instanceof AFCALData || a instanceof AMBTSData) - { - v.add((ACalorimeterData)a); - } - } - return v; - - } // getHadronicCalorimeters() ------------------------------------------- - - - - /** - * setPrimaryVertex() called during event finalisation - * sets Event: XVtx, YVtx, ZVtx in the internal parameter store - * (in GUI: Projection -> eta-phi -> XVtx, YVtx, ZVtx) - - * 1) gets values from RecVertex (RVx) - see conditions in ARVxData class - * 2) gets values from simulated vertices with highest pt sum (STr) - * 3) if above fail, sets 0.0, 0.0, 0.0 - * - * (taking primary vertex from reconstructed tracks was removed) - * - */ - public void setPrimaryVertex() - { - double[] vtx = null; - - // (1) - if(getRVxData() != null) - { - // RVx data exists, try to retrieve primary vertex information - vtx = getRVxData().getPrimaryVertex(); - } - // (2) - if(vtx == null && getSTrData() != null) - { - // STr data exists, try to get primary vertex information - int vtxIndex = getSTrData().getMaxSumPtVertex(); - - //retrieve that vertex - vtx = getSVxData().getVertex(vtxIndex); - - //Completely unclear to me... why 4? - if(vtx[0] * vtx[0] + vtx[1] * vtx[1] > 4.) - { - logger.info("replacing primary with first"); - logger.info(" was " + vtx[0] + " " + vtx[1] + " " + vtx[2]); - vtx = getSVxData().getVertex(0); - if(vtx[0] * vtx[0] + vtx[1] * vtx[1] > 4.) - { - vtx[0] = 0.; - vtx[1] = 0.; - vtx[2] = 0.; - } - logger.info(" now is " + vtx[0] + " " + vtx[1] + " " + vtx[2]); - } - } - - if(vtx == null) - { - vtx = new double[] { 0.0, 0.0, 0.0 }; - } - - parameterStore.get("Event", "XVtx").setD(vtx[0]); - parameterStore.get("Event", "YVtx").setD(vtx[1]); - parameterStore.get("Event", "ZVtx").setD(vtx[2]); - - AOutput.append("\n\nPrimary vertex set for projection " + - AMath.PHI + AMath.ETA + ":\n" + - " XVtx = " + String.format("%.5f",vtx[0]) + " cm\n" + - " YVtx = " + String.format("%.5f",vtx[1]) + " cm\n" + - " ZVtx = " + String.format("%.5f",vtx[2]) + " cm\n", ALogInterface.NORMAL); - - } // setPrimaryVertex() ------------------------------------------------- - - - - /** - * Finalize event construction: - * - finalize all data objects - * - set primary vertex - * - calculate the number of hits on a track - * - create associations - * - update collections - * @return the event - */ - public AEvent finalizeEvent() - { - - // setting primary vertex must be done before finalizeConstruction() - // happens on datatypes! - setPrimaryVertex(); - - Iterator<AData> iter = data.values().iterator(); - while(iter.hasNext()) - { - AData data = iter.next(); - if(data instanceof AData) - { - try { - ((AData) data).finalizeConstruction(); - } catch ( Exception e ){ - //Get sourceName of the object where the error occured - String ObjName = ((AData)data).getFullName(); - logger.error("Exception while finalizing construction of "+ObjName,e); - AOutput.append("\n\nError while constructing " + ObjName +"\n", ALogInterface.WARNING); - AOutput.append(" - object will not be shown!\n",ALogInterface.WARNING); - iter.remove(); - - } - } - } - - if (!AGlobals.isAtlantisHeadless()) { - AListManager.getInstance().resetAndPreserveInvisible(); - } - - // are there any RVx read in from the event file? if so, cut the tracks - // which form vertices (when drawn as helices) to the reconstructed - // vertices. - ARVxData rvxData = this.getRVxData(); - if(rvxData != null) - { - rvxData.cutTracksToRVx(this); - } - - assocmgr.correct(); - - return this; - - } // AEvent finalizeEvent() --------------------------------------------- - - - /** - * Returns information about datatypes and number of items datatypes in - * the current event - * First item of the result array is the datatype sourceName followed - * by ":<storeGateKey>" if that exists for a datatype and second item is - * integer number (numData). - * The array is alphabetically sorted. - * - * @return String[][] - */ - public String[][] getInfo() - { - AData[] sources = getData(); - Map<String,String> m = new LinkedHashMap<String,String>(); - m.clear(); - for(int i = 0; i < sources.length; i++) - { - String sg = sources[i].getStoreGateKey(); - String a = sources[i].getNameScreenName(); - a += sg != null ? ":" + sg : ""; - m.put(a, String.valueOf(sources[i].getNumData())); - } - - TreeMap<String,String> tm = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER); - tm.clear(); - tm.putAll(m); - - String[][] s = new String[tm.size()][2]; - int i = 0; - for(Iterator<String> iter = tm.keySet().iterator() ; iter.hasNext() ; i++) - { - String key = iter.next(); - s[i][0] = key; - s[i][1] = tm.get(key); - } - - return s; - - } // getInfo() ----------------------------------------------------------- - - - /** - * Returns information about datatypes and number of items datatypes in - * the current event drawn for all event data, and data passing cuts - * First item of the result array is the datatype sourceName followed - * by ":<storeGateKey>" if that exists for a datatype and second/third items are - * integer number (numData, numDraw). - * The array is alphabetically sorted. - * - * @return String[][] - */ - public String[][] getInfoDraw() - { - AData[] sources = getData(); - Map<String,String> m = new LinkedHashMap<String,String>(); - m.clear(); - Map<String,String> mDraw = new LinkedHashMap<String,String>(); - mDraw.clear(); - - for(int i = 0; i < sources.length; i++) - { - String sg = sources[i].getStoreGateKey(); - String a = sources[i].getNameScreenName(); - a += sg != null ? ":" + sg : ""; - m.put(a, String.valueOf(sources[i].getNumData())); - mDraw.put(a, String.valueOf(sources[i].getNumDraw())); - } - - TreeMap<String,String> tm = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER); - tm.clear(); - tm.putAll(m); - TreeMap<String,String> tmDraw = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER); - tmDraw.clear(); - tmDraw.putAll(mDraw); - - - String[][] s = new String[tm.size()][3]; - int i = 0; - for(Iterator<String> iter = tm.keySet().iterator() ; iter.hasNext() ; i++) - { - String key = iter.next(); - - s[i][0] = key; - s[i][1] = tm.get(key); - s[i][2] = tmDraw.get(key); - } - - return s; - - } // getInfoDraw() ----------------------------------------------------------- - - - /** - * Get coordinates of event vertex. - * - * The coordinates are obtained from the parameter store rather than - * from the event itself, since the vertex position can be changed by the - * user through the GUI. - * - * @return (x,y,z) of vertex - */ - public double[] getPrimaryVertex() - { - return AParameterUtilities.getPrimaryVertex(); - } - - public AAssociationManager getAssociationManager() { - return assocmgr; - } - - -} // class AEvent ------------------------------------------------------------ diff --git a/graphics/AtlantisJava/src/atlantis/event/AEventInfo.java b/graphics/AtlantisJava/src/atlantis/event/AEventInfo.java deleted file mode 100644 index 0fe0aca7a01..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEventInfo.java +++ /dev/null @@ -1,212 +0,0 @@ -package atlantis.event; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Comparator; -import java.util.Date; - -/** - * The AEventInfo class summarizes the information that uniquely identifies a event. - * It also provides an "equals" function allowing to compare if two events are identical. - * @author sboeser - */ -public class AEventInfo { - - // number of the run of the event - private final long runNumber; - // event number in a run - private final long eventNumber; - // Athena time when XML event file was made in JiveXML - private final String dateTime; - // the name of the source this event was coming from (filename, servername, ...) - private final String sourceName; - // the lumiBlock number - private final String lumiBlock; - // Any additional eventProperties that may be important - private final String eventProperties; - // any additional info that is needed - - //the date format to use with the event info - public final static SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); - - /** - * Fully qualified constructor - * @param run the run number - * @param event the event number - * @param time the date and time of the event - */ - AEventInfo(long event, long run, String time, String source, String lumiBlock, String eventProperties){ - this.runNumber = run; - this.eventNumber = event; - this.dateTime = time != null ? time : "n/a"; - this.sourceName = source != null ? source : "n/a"; - this.lumiBlock = checkString(lumiBlock); - this.eventProperties = checkString(eventProperties); - } - - /** - * Copy constructor - * @param the evenInfo object to copy - */ - AEventInfo(AEventInfo event){ - this(event.getEventNumber(),event.getRunNumber(), - event.getDateTime(),event.getSourceName(), - event.getLumiBlock(),event.getEventProperties()); - } - - /** - * @return the run number - */ - public long getRunNumber() { - return runNumber; - } // getRunNumber() ----------------------------------------------------- - - /** - * @return the event number - */ - public long getEventNumber(){ - return eventNumber; - } // getEventNumber() --------------------------------------------------- - - - /** - * @return the date and time of the event - */ - public String getDateTime() { - return dateTime; - } // getEventNumber() --------------------------------------------------- - - /** - * @return the name of the event source - */ - public String getSourceName() { - return sourceName; - } // getSourceName() ---------------------------------------------------------- - - /** - * @return the lumiBlock - */ - public String getLumiBlock() { - return lumiBlock; - } // getSourceName() ---------------------------------------------------------- - - /** - * @return the eventProperties - */ - public String getEventProperties() { - return eventProperties; - } // getSourceName() ---------------------------------------------------------- - - - - /** - * Performs test to see if there is a valid value for send string - */ - private String checkString(String receivedString){ - String temp; - if(receivedString == null || receivedString.endsWith("-1")){ - temp = "default"; - }else{ - temp = receivedString; - } - return temp; - } - - - - - /** - * Check whether this event is identical to the event described by info - * @param info the event information for the event to compare to - * @return true if identical - */ - // FIXME: Should take Object as argument. Need to consider how to deal with - // subclasses like AEvent. - public boolean equals(AEventInfo info){ - //check if info is valid - if (info == null) return false; - //Only compare run- and event number and time, source may be different - return ((info.getRunNumber() == runNumber)&& - (info.getEventNumber() == eventNumber)); - } - -// Need to override hashCode() to guarantee correct behaviour of equals() -@Override -public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (eventNumber ^ (eventNumber >>> 32)); - result = prime * result + (int) (runNumber ^ (runNumber >>> 32)); - return result; -} - - -/** - * Implementation of Comparable interface - sort events by run- and event number - */ - public static class RunEventNumberComparator implements Comparator { - - /** - * @param o1 , o2 the two eventInfo objects to compare - * @return negative/zero/positive int if o1 is less/equal/larger than o2 - */ - public int compare(Object o1, Object o2) { - - /** - * Cast to an event info object - if this fails, someone has mixed this with - * another class in a collection and we better crash with ClassCastException than catch - */ - AEventInfo info1 = (AEventInfo)o1; - AEventInfo info2 = (AEventInfo)o2; - - //compare by run number first - Long run = info1.getRunNumber(); - if (run.compareTo(info2.getRunNumber()) != 0) - return run.compareTo(info2.getRunNumber()); - - //otherwise return by event number - Long event = info2.getEventNumber(); - return event.compareTo(info2.getEventNumber()); - } - } - - /** - * Implementation of Comparable interface - sort events by date and time - */ - public static class DateTimeComparator implements Comparator { - - /** - * @param o1 , o2 the two eventInfo objects to compare - * @return negative/zero/positive int if o1 is less/equal/larger than o2 - */ - public int compare(Object o1, Object o2) { - - /** - * Cast to an event info object - if this fails, someone has mixed this with - * another class in a collection and we better crash with ClassCastException than catch - */ - AEventInfo info1 = (AEventInfo)o1; - AEventInfo info2 = (AEventInfo)o2; - - //return zero for events that are equal - if (info1.equals(info2)) return 0; - - //Now get date and time objects - Date date1 = null; Date date2=null; - try { - date1 = dateTimeFormat.parse(info1.getDateTime()); - date2 = dateTimeFormat.parse(info2.getDateTime()); - } catch (ParseException pex) { - throw new ClassCastException("Parse exception when comparing dates"); - } - - //If there is not date assoicated with any of these, throw an exception - if ((date1==null)||(date2==null)) - throw new ClassCastException("Could not parse valid date comparing " - +info1.getDateTime()+" to "+info2.getDateTime()); - - //Finally, compare the two dates - return date1.compareTo(date2); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AEventInfoPrinter.java b/graphics/AtlantisJava/src/atlantis/event/AEventInfoPrinter.java deleted file mode 100644 index 174eed015a7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEventInfoPrinter.java +++ /dev/null @@ -1,60 +0,0 @@ -package atlantis.event; - -import atlantis.globals.AGlobals; -import atlantis.output.ALogInterface; - -/** - * Print event information for each new event to the log pane - * @author sboeser - */ -public class AEventInfoPrinter implements ANewEventListener { - - private ALogInterface logPane = null; - - /** - * Constructor with the log pane where the information shall be printed - * @param output the output pane to which to write - */ - public AEventInfoPrinter(ALogInterface output){ - logPane = output; - } - - private void printEventInfo(AEvent event, ALogInterface dest) - { - //For Minerva just output name and coded event and run numbers - //Not on canvas title, but teachers may want to see the number to help - //with recognising difficult events - if(AGlobals.instance().getSimpleOutput()>0) - { - String r = "\n" + event.getSourceName() + - " (" + event.getRunNumber() + "00"+ event.getEventNumber() + ")\n"; - dest.append(r + "\n", ALogInterface.NORMAL); - return; - } - - int lineLen = 39; - String r = "\n" + event.getSourceName() + "\n" + - "run number: " + event.getRunNumber() + - " event number: " + event.getEventNumber() + "\n" + - "--------------------------------------\n"; - - String[][] s = event.getInfo(); - - for(int i = 0; i < s.length; i++) - { - r += String.format("%-"+lineLen+"s", s[i][0]) + ": " + s[i][1] + "\n"; - } - dest.append(r + "\n", ALogInterface.NORMAL); - - } // printEventInfo() ---------------------------------------------------*/ - - /** - * For each new event print log information to the log pane - * @param event the change event - */ - public void newEvent(AEvent event) { - //simply print it - printEventInfo(event,logPane); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AEventManager.java b/graphics/AtlantisJava/src/atlantis/event/AEventManager.java deleted file mode 100755 index ba5b27b035b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEventManager.java +++ /dev/null @@ -1,319 +0,0 @@ -package atlantis.event; - -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.event.AEventSource.NavigationMode; -import atlantis.event.oncrpc.AONCRPCEventSource; -import atlantis.event.xmlrpc.AXMLRPCEventSource; -import java.util.Vector; - -import atlantis.utils.ALogger; - -/** - * All new physics events come into Atlantis via the AEventManager - * The AEventManager may hold a list of event, has the index of the - * current event int the list and informs its listeners about new events. - * Only one event can be active at one time. - * - * @author sboeser - */ -public class AEventManager -{ - private final static ALogger logger = ALogger.getLogger(AEventManager.class); - private static AEventManager instance; - - /** Private constructor for singleton. */ - private AEventManager() {} - - /** Get the singleton instance. */ - public synchronized static AEventManager instance() { - if (instance==null) instance = new AEventManager(); - return instance; - } - - //The current event source - private AEventSource eventSource = null; - - //The current event - i.e. the last delivered by any event source - private AEvent currentEvent = null; - - //A list of listeners for new events - private Vector<ANewEventListener> NewEventListeners = new Vector<ANewEventListener>(); - - //A list of listeners for new events sources - private Vector<ANewEventSourceListener> NewEventSourceListeners = new Vector<ANewEventSourceListener>(); - - /** - * Return the currently active event - * @return AEvent - */ - public synchronized AEvent getCurrentEvent() - { - //simply return the current event - return currentEvent; - } - - - /** - * Set the event with the given index as the current event - * @param index the index of the new event - */ - private synchronized void setCurrentEvent(AEvent event) - { - //Now simply set the current event - currentEvent = event; - //Inform all listeners - fireNewEvent(getCurrentEvent()); - } - - - /** - * @return the current active event source - */ - public synchronized AEventSource getEventSource(){ - return eventSource; - } - - /** - * Set a new already constructed event source. Note that this constructor - * does not throw InvalidEventSource exception as the AEventSource object - * is already constructed. - * @param source the AEventSource object - */ - public synchronized void setEventSource( AEventSource source ) - { - //Simply set the source and we are done - eventSource = source; - fireNewEventSource(getEventSource()); - } - - - /** - * Set the source given by name as new event source. If the event source is - * not valid (e.g invalid file name) we rely on the constructor to fail, throwing - * an InvalidEventSourceException. Thus, the old source is retained if the new one - * can not be created. - * @param sourceName the name of the source (e.g. file name, url, server name,...) - * @throws InvalidEventSourceException - */ - public synchronized void setEventSource(String sourceName) throws InvalidEventSourceException - { - //Make a nice string out of it - String theSourceName = sourceName.toLowerCase().trim(); - - // XMLRPC Server source given as "xmlrpc://server:port" - if(theSourceName.startsWith("xmlrpc://")) { - eventSource = new AXMLRPCEventSource(sourceName); - // ONCRPC Server source given as "oncrpc://server[:port]" - } else if(theSourceName.startsWith("oncrpc://")) { - eventSource = new AONCRPCEventSource(sourceName); - // Metwork sources possibilities - // .xml, .zip or web directory containing event files - } else if(theSourceName.startsWith("http://")) { - // normal xml file - if(theSourceName.endsWith(".xml")){ - eventSource = new AURLEventSource(sourceName); - // zip file on the web - } else if(theSourceName.endsWith(".zip")) { - eventSource = new AZipEventSource(sourceName); - //Anything else should be a web directory - } else { - eventSource = new AURLEventSource(sourceName); - } - - // local disk access possibilities (.xml, .zip, .gz, .gzip) - // event source starts with file:// - } else if(theSourceName.startsWith("file://")) { - // normal xml file - if (theSourceName.endsWith(".xml")) { - eventSource = new AFileEventSource(sourceName); - // normal zip file - } else if (theSourceName.endsWith(".zip")) { - eventSource = new AZipEventSource(sourceName); - // compressed single xml file - } else if (theSourceName.endsWith(".gz") || theSourceName.endsWith(".gzip")) { - eventSource = new AFileEventSource(sourceName); - } else { - String msg = "Could not identify event source: "+sourceName; - logger.error(msg); - throw new InvalidEventSourceException(msg); - } - } else { - String msg = "Could not identify event source: "+sourceName; - logger.error(msg); - throw new InvalidEventSourceException(msg); - } - fireNewEventSource(getEventSource()); - } - - /** - * Sets event navigation mode: random, push, loop or sequential. - * Throws InvalidEventSourceException if there is no source - * or if it doesn't support the requested mode. - * @throws InvalidEventSourceException - */ - public synchronized void setNavigationMode(NavigationMode mode) throws InvalidEventSourceException - { - if(eventSource == null) throw new InvalidEventSourceException("Current event source is NULL"); - - NavigationMode oldMode = eventSource.getNavigationMode(); - - // check if we're really setting a new mode, or if - // the user just clicked on the same button twice - if(oldMode != mode) { - if(eventSource.supportsNavigationMode(mode)) { - eventSource.setNavigationMode(mode); - fireNewEventSource(getEventSource()); - // go to the next event - try { - nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "No more events from current source"; - logger.error(msg); - } catch (ReadEventException re) { - String msg = "Error while reading the event"; - logger.error(msg); - } - } else throw new InvalidEventSourceException("Current event source does not support the selected display mode"); - } - } - - /** - * Gets the current event navigation mode. - * @return event navigation mode - */ - public synchronized NavigationMode getNavigationMode() throws InvalidEventSourceException - { - if(eventSource == null) throw new InvalidEventSourceException("Current event source is NULL"); - return eventSource.getNavigationMode(); - } - - /** - * Check if the current source supports a specific event navigation mode. - * @param mode the requested event navigation mode - * @return true if the event navigation mode is supported - */ - public boolean supportseventNavigationMode(NavigationMode mode) throws InvalidEventSourceException - { - if(eventSource == null) throw new InvalidEventSourceException("Current event source is NULL"); - return eventSource.supportsNavigationMode(mode); - } - - /** - * Read the next event from the current event source. - * Throws NoMoreEvents if there is none. - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - public void nextEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException - { - - // Check for valid event source. - if (eventSource==null) - throw new InvalidEventSourceException("Current event source is NULL"); - - // Simply read next event from it. - AEvent event = eventSource.nextEvent(); - setCurrentEvent(event); - - } - - - /** - * Read previous event from current event source. - * Throws NoMoreEvents if there is none. - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - public void previousEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException - { - - // Check for valid event source. - if (eventSource==null) - throw new InvalidEventSourceException("Current event source is NULL"); - - // Simply read previous event from it. - setCurrentEvent(eventSource.previousEvent()); - - } - - /** - * Add a new listener for newEvent incidents - * @param listener to be added to list - */ - public void addNewEventListener(ANewEventListener listener) - { - //Add this listener - NewEventListeners.addElement(listener); - //If there are already some events - if (getCurrentEvent() == null) return; - //Make the new listener aware of the current event - listener.newEvent(getCurrentEvent()); - } - - /** - * Remove a listener from the list. - * @param listener to be removed from list - */ - public void removeNewEventListener(ANewEventListener listener) - { - //Remove this listener - NewEventListeners.removeElement(listener); - } - - /** - * Call stateChanges of all newEvent listeners - * @param event the new event passed on to all listeners - */ - private synchronized void fireNewEvent(AEvent event) - { - - // Loop over all listeners - for ( ANewEventListener listener : NewEventListeners ) - // give them the new event - listener.newEvent(event); - } - - /** - * Add a new listener for newEventSource incidents - * @param listener to be added to list - */ - public void addNewEventSourceListener(ANewEventSourceListener listener) - { - //Add this listener - NewEventSourceListeners.addElement(listener); - //If there are already some events - if (getEventSource() == null) return; - //Make the new listener aware of the current event - listener.newEventSource(getEventSource()); - } - - /** - * Remove a listener from the list - * @param listener to be removed from list - */ - public void removeNewEventSourceListener(ANewEventSourceListener listener) - { - NewEventSourceListeners.removeElement(listener); - } - - /** - * Call eventSourceChanged of all event source changes listeners - * @param eventSource the new event source - */ - private synchronized void fireNewEventSource(AEventSource eventSource) - { - // Loop over all listeners - for ( ANewEventSourceListener listener : NewEventSourceListeners ) - // give them the new event - listener.newEventSource(eventSource); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AEventSource.java b/graphics/AtlantisJava/src/atlantis/event/AEventSource.java deleted file mode 100755 index 01fef1e727d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEventSource.java +++ /dev/null @@ -1,114 +0,0 @@ -package atlantis.event; - -/** - * Basic interface class to be implemented by all event sources - * @author sboeser - */ - -public interface AEventSource -{ - - /*** - * Exception that is thrown if an event can not be read from this source - */ - public class ReadEventException extends AEventSourceException - { - //Default constructor - public ReadEventException() { super(); } - //Constructor with a string - public ReadEventException( String message ){ super( message ); } - //Constructor with a description and cause - public ReadEventException( String message, Throwable cause ){ super( message, cause ); } - } - - /*** - * Exception that is thrown if there are no more events from this source - */ - public class NoMoreEventsException extends AEventSourceException - { - //Default constructor - public NoMoreEventsException() { super(); } - //Constructor with a string - public NoMoreEventsException( String message ){ super( message ); } - //Constructor with a description and cause - public NoMoreEventsException( String message, Throwable cause ){ super( message, cause ); } - } - - /** - * Exception that is thrown if the event source is invalid - */ - public class InvalidEventSourceException extends AEventSourceException - { - //Default constructor - public InvalidEventSourceException() { super(); } - //Constructor with a string - public InvalidEventSourceException( String message ){ super( message ); } - //Constructor with a description and cause - public InvalidEventSourceException( String message, Throwable cause ){ super( message, cause ); } - } - - /** - * Read the next event from the source, throws NoMoreEvents - * if no next event is available - * @return the next event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - AEvent nextEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException; - - /** - * Read the previous event from the source, throws NoMoreEvents - * if no previous event is available - * @return the previous event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - AEvent previousEvent() throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException; - /** - * Get a string uniquly identifying the event source, e.g the URL, the zip - * archive name or the server:port string - * @return a unique name describing the source - */ - String getSourceName(); - - /*** - * Enum that stores the possible event navigation modes - */ - public enum NavigationMode { - SEQUENTIAL, //go through events in their natural order - LOOP, //start from beginning when reaching the end - RANDOM, //take a random event - PUSH //event loop is driven from outside (see AServerXMLRPC) - } - - /** - * Get the event navigation mode for the current source. - * @return current navigation mode - */ - NavigationMode getNavigationMode(); - - /** - * Set the event navigation mode for the current source. - * Throws InvalidEventSourceException if the current - * source does not support the requested mode - * @param mode requested event navigation mode - * @throws InvalidEventSourceException if the mode is not supported - */ - void setNavigationMode(NavigationMode mode) throws InvalidEventSourceException; - - /** - * Checks whether the current event source supports - * a particular display mode. - * @return true if the mode is supported - * @param mode requested event navigation mode - */ - boolean supportsNavigationMode(NavigationMode mode); - -} - diff --git a/graphics/AtlantisJava/src/atlantis/event/AEventSourceException.java b/graphics/AtlantisJava/src/atlantis/event/AEventSourceException.java deleted file mode 100644 index 94061279df3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AEventSourceException.java +++ /dev/null @@ -1,65 +0,0 @@ - -package atlantis.event; - -/** - * All exceptions occuring while attempting to read events shall be chaught - * and converted into one of the three generic event source exceptions: - * - * -NoMoreEventsException: there is no next/previous event - * -InvalidEventSourceException: the specified event source is invalid - * -ReadEventException: there was an error reading in the event - * - * All three of them derive from AEventSourceException which provides printing methods. - * - * These three exceptions are then handed up to the GUI level, where they are treated - * differently, depending on the current reading mode (e.g. NoMoreEvents can be ignored - * when waiting for events to appear on a server, web-dir, etc..) - * - * @author sboeser - */ -public class AEventSourceException extends Exception{ - - //Default constructor - public AEventSourceException() { super(); } - //Constructor with a string - public AEventSourceException( String message ){ super( message ); } - //Constructor with a description and cause - public AEventSourceException( String message, Throwable cause ){ super( message, cause ); } - - /** - * Generates a string with the cause of this message and all causing ones - * @return the generated string - */ - public String getCauseMessages(){ - - //Create the string buffer - StringBuffer msg = new StringBuffer(); - - //Add all cause messages starting from this exception - addCauseMessage(this,msg); - - //return string - return msg.toString(); - } - - /** - * Recursively add cause messages to string buffer - * @param t the exception - * @param msg the string buffer - */ - private void addCauseMessage(Throwable t, StringBuffer msg){ - - //Add the name of the exception class - msg.append(t.getClass().getName()); - //Add the description of the exception - msg.append(": "); - msg.append(t.getMessage()); - - //Check if there has been a cause given - if (t.getCause() != null){ - //Add cause messages in next line - msg.append("\n caused by "); - addCauseMessage(t.getCause(),msg); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AFileEventSource.java b/graphics/AtlantisJava/src/atlantis/event/AFileEventSource.java deleted file mode 100644 index 51625ac86d3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AFileEventSource.java +++ /dev/null @@ -1,309 +0,0 @@ -package atlantis.event; - -import atlantis.data.AEventFromXML; -import java.io.File; -import java.io.FilenameFilter; -import java.io.InputStream; - -import java.util.Arrays; -import java.util.zip.GZIPInputStream; -import java.util.Random; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; - - -/** - * Read a single event from an XML file in a directory - * @author sboeser - */ -public class AFileEventSource extends ABufferedEventSource -{ - - //The current directory - private File directory = null; - - //A filter for valid files in the current directory - private final XMLFilenameFilter filter = new XMLFilenameFilter(); - - // needed for random mode - private Random randomGenerator = new Random(); - - /** - * Constructor with file name given - * @param sourceName - * @throws AEventSource.InvalidEventSourceException - */ - public AFileEventSource(String sourceName) throws AEventSource.InvalidEventSourceException - { - // check if it's a well-formed event path - if(sourceName.startsWith("file://")) { - // strip file:// from the sourceName - sourceName = sourceName.substring(7); - //Check if the current file name is valid - directory = new File(sourceName); - - //Check that we can read that file or directory - if (!directory.canRead()) - throw new InvalidEventSourceException("Can not read from "+sourceName); - } else throw new InvalidEventSourceException(sourceName+" is not in the form file://path"); - } - - /** - * @return the full name of the file or directory - */ - public String getSourceName() { - return directory.getAbsolutePath(); - } - - /** - * @param mode event navigation mode - * @return true if the requested mode is supported by this source - */ - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.SEQUENTIAL || - mode == NavigationMode.RANDOM || - mode == NavigationMode.LOOP) - return true; - return false; - } - - /** - * Read an event from the current file and directory - * @return the event - * @throws ReadEventException - * @throws InvalidEventSourceException - */ - protected AEvent readEventFromFile(File file) throws ReadEventException, - InvalidEventSourceException - { - //Reassemble full file name - String FullFileName = file.getAbsolutePath(); - - try{ - - //Use full path and name to specify the file - InputStream is = new FileInputStream(FullFileName); - - //Check if this might be a gzip stream - if ((file.getName().toLowerCase().endsWith(".gz"))|| - (file.getName().toLowerCase().endsWith(".gzip"))){ - - //Run through GZIPInput for decoding - is = new GZIPInputStream(is); - } - //Read file from stream - return AEventFromXML.read(is, file.getName()); - - } catch( OutOfMemoryError oom ) { - - //Check if we can clear the event container - if( getNumberOfEvents() > 0) clearEventContainer(); - - //Run garbage collector - System.gc(); - - //Retry reading the event - return readEventFromFile(file); - - } catch(FileNotFoundException fnfe){ - //rethrow - throw new InvalidEventSourceException("File not found: "+FullFileName,fnfe); - } catch(IOException ioe){ - //rethrow - throw new ReadEventException("I/O error readding file: "+FullFileName,ioe); - } - } - - /** - *Get a sorted list of files in the directory of the current file - */ - private String[] getListOfFiles(){ - - //get a list of files in the same directory using the filter - String[] FileList = directory.list(filter); - - //Sort the list - Arrays.sort(FileList); - - return FileList; - - } - - protected AEvent readRandom() throws ReadEventException, InvalidEventSourceException { - - //The file we want to pass on to the reading routine - File file = null; - //On the first encounter "directory" might be a file - if (directory.isFile()){ - //set this as the file we want to read - file = directory.getAbsoluteFile(); - //store its parent directory - directory = file.getParentFile(); - } else { - //Get a list of files - String[] FileList = getListOfFiles(); - //Check there are more files - if (FileList.length == 0) - throw new InvalidEventSourceException("No valid files in directory " - +directory.getAbsolutePath()); - //Loop over file list - int iName = randomGenerator.nextInt(FileList.length); - - //Now get the new file - file = new File(directory,FileList[iName]); - } - - //Should now have a file in any case, try to read from it - return readEventFromFile(file); - - } - - - /** - * Read the next event from the next XML file in the same directory - * @return the next event - * @throws NoMoreEventsException - * @throws ReadEventException - * @throws InvalidEventSourceException - */ - public AEvent readNext(AEventInfo currentEvent) throws NoMoreEventsException, - ReadEventException, - InvalidEventSourceException - { - // if random mode is set, return a random event - if(getNavigationMode() == NavigationMode.RANDOM) return readRandom(); - - //The file we want to pass on to the reading routine - File file = null; - //On the first encounter "directory" might be a file - if (directory.isFile()){ - //set this as the file we want to read - file = directory.getAbsoluteFile(); - //store its parent directory - directory = file.getParentFile(); - } else { - //Get a list of files - String[] FileList = getListOfFiles(); - //Check there are more files - if (FileList.length == 0) - throw new NoMoreEventsException("No valid files in directory " - +directory.getAbsolutePath()); - //Loop over file list - int iName = 0; - //search for next entry that is lexicographically larger - //taking first one if there is no current event to compare to - while ((currentEvent != null ) && - (currentEvent.getSourceName().compareTo(FileList[iName]) >= 0)){ - //Go to next file - ++iName; - // if we have reached the end of the list - if (iName == FileList.length) { - // if in loop mode, go back to the first file - if(getNavigationMode() == NavigationMode.LOOP) { - iName = 0; - break; - } - // if not in loop mode, abort - else throw new NoMoreEventsException("No more files after" - + currentEvent.getSourceName() + " in directory "+directory.getAbsolutePath()); - } - } - - //Now get the new file - file = new File(directory,FileList[iName]); - } - - //Should now have a file in any case, try to read from it - return readEventFromFile(file); - - } - - /** - * Read the next event from the previous XML file in the same directory - * @return the previous event - * @throws NoMoreEventsException - * @throws ReadEventException - * @throws InvalidEventSourceException - */ - public AEvent readPrevious(AEventInfo currentEvent) throws NoMoreEventsException, - ReadEventException, - InvalidEventSourceException - { - // in random mode there's no looking back - if(getNavigationMode() == NavigationMode.RANDOM) throw new NoMoreEventsException("No more random events left in the buffer"); - //The file we want to pass on to the reading routine - File file = null; - //On the first encounter "directory" might be a file - if (directory.isFile()){ - //set this as the file we want to read - file = directory.getAbsoluteFile(); - //store its parent directory - directory = file.getParentFile(); - } else { - //Get a list fo files - String[] FileList = getListOfFiles(); - //Check there are more files - if (FileList.length == 0) - throw new NoMoreEventsException("No valid files in directory " - +directory.getAbsolutePath()); - //Loop over file list - int iName = FileList.length-1; - //search for next entry that is lexicographically smaller - //taking last one if there is no current one to compare to - while ((currentEvent != null) && - (currentEvent.getSourceName().compareTo(FileList[iName]) <= 0)){ - //Go to next file - --iName; - // if we have reached the end of the list - if (iName < 0) { - // if in loop mode, go to the last event - if(getNavigationMode() == NavigationMode.LOOP) { - iName = FileList.length - 1; - break; - } - // if not in loop mode, abort - else throw new NoMoreEventsException("No more files before" - + currentEvent.getSourceName() + " in directory "+directory.getName()); - } - } - - //Now get the new file - file = new File(directory,FileList[iName]); - } - - //Should now have a file in any case, try to read from it - return readEventFromFile(file); - } -} -/** - * Filter helper class only accepting file names ending in .xml, .gz or .gzip - * @author sboeser - */ -class XMLFilenameFilter implements FilenameFilter -{ - - // accept all readable .xml .gz and .gzip files, no directories - public boolean accept(File dir, String name) - { - //First check the name - if ( ! name.toLowerCase().endsWith(".xml")) - if ( ! name.toLowerCase().endsWith(".gzip")) - if ( ! name.toLowerCase().endsWith(".gz")) - //invalid ending - return false; - - //Check file properties - File f = new File(dir, name); - - //Reject directories - if(! f.isFile()) return false; - //Reject unreadable files - if(! f.canRead()) return false; - - //Finally accept - return true; - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AFilter.java b/graphics/AtlantisJava/src/atlantis/event/AFilter.java deleted file mode 100755 index e6293cba5df..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AFilter.java +++ /dev/null @@ -1,275 +0,0 @@ -package atlantis.event; - - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.data.AS3DData; - - -/** - * Filter of S3D hits ask Hans Drevermann - */ - -public class AFilter { - - final static int FILTER_GROUP=76; - - static int[] h=null; - static int[] eta=null; - static int[] phi=null; - static int[] layer=null; - static int[] group=null; - static int[] skewGroup=null; - static int[] groupMapping=null; - - static int[] bin=null; - static int[] ll=null; - static int[] hitLayers=null; - static int[] id=null; - static boolean[] good=null; - static int numEtaBins=0; - - private static APar parameterStore = APar.instance(); - - final static int[] layerAsBits=new int[32]; - static { - layerAsBits[0]=1; - for(int i=1; i<32; i++) - layerAsBits[i]=2*layerAsBits[i-1]; - } - - - public static void filter(AS3DData aS3DData) { - if(aS3DData==null) { - AOutput.append("AS3DData not found can't filter\n", ALogInterface.BAD_COMMAND); - return; - } - - int numUsefulPhiBins=parameterStore.get("Fil", "NumPhi").getI(); - int numUsefulEtaBins=parameterStore.get("Fil", "NumEta").getI(); - // +2 for wrap around and edge effect - int numPhiBins=numUsefulPhiBins+2; - - // +2 for edge effects - numEtaBins=numUsefulEtaBins+2; - - double etaRange=parameterStore.get("Fil", "EtaRange").getD(); - int requiredHitsInBin=parameterStore.get("Fil", "NumHits").getI(); - int numSkewSteps=parameterStore.get("Fil", "NumSkew").getI(); - double skewStepSize=parameterStore.get("Fil", "SkewStep").getD(); - - int numHits=aS3DData.makeFilterDrawList(etaRange); - int maxBins=numHits+1; - - if(h==null||h.length<numPhiBins*numEtaBins) h=new int[numPhiBins*numEtaBins]; - if(layer==null||layer.length<numHits) layer=new int[numHits]; - if(eta==null||eta.length<numHits) eta=new int[numHits]; - if(phi==null||phi.length<numHits) phi=new int[numHits]; - if(group==null||group.length<numHits) group=new int[numHits]; - if(skewGroup==null||skewGroup.length<numHits) skewGroup=new int[numHits]; - if(groupMapping==null||groupMapping.length<numHits) groupMapping=new int[numHits]; - // - if(bin==null||bin.length<maxBins) bin=new int[maxBins]; - if(hitLayers==null||hitLayers.length<maxBins) hitLayers=new int[maxBins]; - if(id==null||id.length<maxBins) id=new int[maxBins]; - if(ll==null||ll.length<maxBins) ll=new int[maxBins]; - if(good==null||good.length<maxBins) good=new boolean[maxBins]; - - layer=aS3DData.getLayer(layer); - eta=aS3DData.getIntegerEta(numUsefulEtaBins, etaRange, eta); - - // initialise - for(int i=0; i<numHits; ++i) - group[i]=0; - - if(!parameterStore.get("Fil", "Loop").getStatus()) numSkewSteps=0; - - int numGroups=0; - - for(int step=-numSkewSteps; step<=numSkewSteps; step++) { - double skew=0.; - - // TODO: Check if 166.666 should be the curvature parameter from the parameter store - if(numSkewSteps!=0) - skew=(1./skewStepSize)*step/(numSkewSteps*2*166.666); - - for(int i=0; i<maxBins; ++i) { - hitLayers[i]=0; - good[i]=false; - } - - phi=aS3DData.getIntegerPhi(numUsefulPhiBins, skew, phi); - - int numBins=1; - - for(int i=0; i<numHits; ++i) { - int b=phi[i]*numEtaBins+eta[i]; - - if(h[b]==0) { - h[b]=numBins; - bin[numBins]=b; - numBins++; - } - hitLayers[h[b]]|=layerAsBits[layer[i]]; - } - - // must treat the phi wraparound here...... - - for(int e=0; e<numEtaBins; e++) { - h[(0)*numEtaBins+e]=h[(numUsefulPhiBins)*numEtaBins+e]; - h[(numUsefulPhiBins+1)*numEtaBins+e]=h[(1)*numEtaBins+e]; - } - - int ngood=0; - - for(int i=1; i<numBins; i++) { - int b=bin[i]; - int hitLayersSummed=0; - - // add hits from 3x3 region around this bin - for(int p=b-numEtaBins; p<b+2*numEtaBins; p+=numEtaBins) - for(int e=p-1; e<p+2; ++e) { - int ibin=h[e]; - - if(ibin>0) - hitLayersSummed|=hitLayers[ibin]; - } - if(countBits(hitLayersSummed)>=requiredHitsInBin) { - good[i]=true; - ll[ngood++]=i; - } - } - - for(int i=0; i<ngood; ++i) - id[ll[i]]=0; - - int firstGroup=numGroups+1; - - for(int i=0; i<ngood; ++i) - if(id[ll[i]]==0) - add(ll[i], ++numGroups); - - for(int j=firstGroup; j<=numGroups; ++j) { - int hls=0; - - for(int i=0; i<ngood; i++) - if(id[ll[i]]==j) { - hls|=hitLayers[ll[i]]; - } - if(countBits(hls)<requiredHitsInBin) - for(int i=0; i<ngood; i++) - if(id[ll[i]]==j) - good[ll[i]]=false; - } - - for(int i=0; i<numHits; ++i) { - int b=h[phi[i]*numEtaBins+eta[i]]; - - if(good[b]) - skewGroup[i]=id[b]; - else - skewGroup[i]=0; - } - - // now zero the histogram for next call - for(int i=1; i<numBins; i++) - h[bin[i]]=0; - // wrap around - for(int e=0; e<numEtaBins; e++) { - h[(0)*numEtaBins+e]=0; - h[(numPhiBins-1)*numEtaBins+e]=0; - } - - group=mergeGroups(numHits, numGroups, group, skewGroup); - - } - - group=renumberGroups(numHits, group); - - int num=0; - - for(int i=0; i<numHits; ++i) - if(group[i]>0) num++; - - AOutput.alwaysAppend("\nFiltering:\n Input hits = "+numHits+"\n Num grouped = "+num+"\n",ALogInterface.NORMAL_BOLD); - - aS3DData.setGroup(group); - } - - public static void add(int i, int numGroup) { - id[i]=numGroup; - int b=bin[i]; - - // add hits from 3x3 region around this bin - for(int p=b-numEtaBins; p<b+2*numEtaBins; p+=numEtaBins) - for(int e=p-1; e<p+2; ++e) { - int ibin=h[e]; - - if(good[ibin]&&id[ibin]==0) - add(ibin, numGroup); - } - } - - public static int[] mergeGroups(int numHits, int numGroups, int[] group, int[] skewgroup) { - - for(int i=1; i<=numGroups; ++i) - groupMapping[i]=i; - - for(int i=0; i<numHits; ++i) - if(skewGroup[i]>0&&group[i]>0) { - int g1=groupMapping[group[i]]; - int g2=groupMapping[skewGroup[i]]; - - if(g1!=g2) - for(int g=1; g<=numGroups; ++g) - if(groupMapping[g]==g1||groupMapping[g]==g2) groupMapping[g]=g1; - } - - for(int i=0; i<numHits; ++i) - if(skewGroup[i]>0||group[i]>0) { - int g=skewGroup[i]; - - if(g==0) - g=group[i]; - group[i]=groupMapping[g]; - } - return group; - } - - public static int[] renumberGroups(int numHits, int[] group) { - int numGroups=0; - - for(int i=0; i<numHits; ++i) - if(group[i]>0) { - int g=group[i]; - - numGroups++; - for(int j=i; j<numHits; ++j) - if(group[j]==g) - group[j]=-numGroups; - } - for(int i=0; i<numHits; ++i) - group[i]=-group[i]; - return group; - } - - // Return the number of bits currently set. This is done via a lookup table - - final static int[] countLUT= {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, - 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, - 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, - 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, - 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, - 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, - 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, - 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, - 7, 5, 6, 6, 7, 6, 7, 7, 8}; - - final static int maskByte=255; - - public static int countBits(int bits) { - return countLUT[bits&maskByte]+countLUT[(bits>>>8)&maskByte]+countLUT[(bits>>>16)&maskByte]; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AImageProducer.java b/graphics/AtlantisJava/src/atlantis/event/AImageProducer.java deleted file mode 100644 index 74615cbd896..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AImageProducer.java +++ /dev/null @@ -1,129 +0,0 @@ -package atlantis.event; - -import atlantis.utils.*; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import atlantis.Atlantis; -import atlantis.canvas.ACanvas; -import atlantis.graphics.encoders.AImageEncoder; -import java.awt.Dimension; - - -/** - * Implements ANewEventListener and creates image files - * upon each newEvent call. A scale factor allows to e.g. produce thumbnails by - * scaling down image. The image producer works in two modes: - * a) If no file name is given, a file name will be generated from run and event - * number. In case the output file exists, no file is created but a warning is written out. - * b) If a file name is given, a temporary file is generated first, and then - * renamed to the given file name. If renaming fails, a warning is written out - * and the temporary file is deleted. - * - * @author Sebastian Boeser - */ - -public abstract class AImageProducer implements ANewEventListener -{ - /** File name prefix */ - protected static final String filePrefix = "atlantis"; - /** Minimum number of digits for event- and run-number when writing files */ - protected static final int encodeNumberDigits = 6; - - /** directory to store files in */ - protected final File directory ; - /** Default image dimensions */ - protected final Dimension imageSize; - /** The thumbnail scale */ - protected final double scaleFactor; - /** A fixed filename if given on the command line */ - protected final String fixedFileName; - - /** - * Inner exception class - */ - public static class InstantiationException extends Exception { - //only declare constructor - InstantiationException(String what){ - super(what); - } - }; - - /** - * Fully qualified constructor, - * intializing all the attributes and check the parameters validity - * @param dir the directory in which to save all the files - * @param size the dimensions of the images - * @param scale the factor by which to scale the images - * @param fileName if not null, that file will be overwritten for each event - * @throws InstantiationException if we fail to create the object - */ - protected AImageProducer(String dir, Dimension size, double scale, String fileName) throws InstantiationException - { - // First check the directory parameter - directory = new File(dir); - - //That it exists - if(! directory.exists()) throw new InstantiationException("Directory "+dir+" doesn't exist"); - - //That it is a directory - if(! directory.isDirectory()) throw new InstantiationException(dir + " is not a directory"); - - //And that we can write in it - if(! directory.canWrite()) throw new InstantiationException("Cannot write to directory "+dir); - - //Check frequency and history length arguments - if (scale <= 0) throw new InstantiationException("Negative or zero scale factor"); - - // store all parameters - imageSize = size; - scaleFactor = scale; - fixedFileName = fileName; - - } - - - /** - * Return the string build from this events file name - * @param evt the event info from which to build the filename - * @param minDigit minimum number of digits for run- and event-number - * @return the file name - */ - protected String getEventFileName(AEventInfo evt){ - String nameFormat = String.format("%%s_%%0%dd_%%0%dd",encodeNumberDigits,encodeNumberDigits); - return String.format(nameFormat, - filePrefix,evt.getRunNumber(),evt.getEventNumber()); - } - - - /** - * Safes a byteArray of data into a file given by a fileName - * @param data the data - * @param file the file to write into - * @throws Exception in case of saving fails - */ - protected void saveDataIntoFile(byte[] data, File file) throws IOException - { - - //Sanity check - if ((data == null) ||(file == null)) return; - - //Open output stream and write to output stream - FileOutputStream fos = new FileOutputStream(file); - OutputStream os = new BufferedOutputStream(fos); - os.write(data); - os.flush(); - os.close(); - - } - - /** - * Called whenever a new event appears. Store an image in the directory, - * either with a generated file name (no overwrite) or with a fixed file name (overwrite) - * @param event the event from which to generate the image - */ - public abstract void newEvent(AEvent event); -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/event/ANewEventListener.java b/graphics/AtlantisJava/src/atlantis/event/ANewEventListener.java deleted file mode 100644 index 7657cbe4839..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/ANewEventListener.java +++ /dev/null @@ -1,18 +0,0 @@ - -package atlantis.event; - -/** - * Interface for all NewEventListener classes. Each time a new event is - * brought to the event manager, the NewEvent:isteners newEvent method is - * called with the new event as an argument - * @author sboeser - */ -public interface ANewEventListener { - - /** - * This method gets called each time a new new is available. - * @param event the new event - */ - abstract public void newEvent(AEvent event); - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/event/ANewEventSourceListener.java b/graphics/AtlantisJava/src/atlantis/event/ANewEventSourceListener.java deleted file mode 100644 index 6101f3a4f1b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/ANewEventSourceListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package atlantis.event; - -/** - * Interface for all NewEventSourceListener classes. Each time the event source - * is changed, the newEventSourcemethod is called. - * @author maillard - */ -public interface ANewEventSourceListener { - - /** - * This method gets called each time the layout is changed. - * @param eventSource the new event source - */ - abstract public void newEventSource(AEventSource eventSource); - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AObjectsAssociation.java b/graphics/AtlantisJava/src/atlantis/event/AObjectsAssociation.java deleted file mode 100644 index 6f4b148b436..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AObjectsAssociation.java +++ /dev/null @@ -1,26 +0,0 @@ -package atlantis.event; - -/** - * @author Qiang Lu - * - */ -public class AObjectsAssociation extends AAssociation -{ - private String[] key; - - public AObjectsAssociation(String a, String b, String[] associatedKey, - int[] associatedIndex, int[] associatedLinkCount, AEvent e) - { - super(a, b, associatedLinkCount, associatedIndex,e); - this.key = new String[associatedKey.length]; - for (int i=0; i<associatedKey.length; i++) - { - this.key[i] = associatedKey[i]; - } - } - - public String[] getKey() - { - return key; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/APngImageProducer.java b/graphics/AtlantisJava/src/atlantis/event/APngImageProducer.java deleted file mode 100644 index 21cd4d7199b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/APngImageProducer.java +++ /dev/null @@ -1,119 +0,0 @@ -package atlantis.event; - -import atlantis.utils.*; -import java.io.File; -import java.io.IOException; - -import atlantis.canvas.ACanvas; -import atlantis.graphics.encoders.AImageEncoder; -import java.awt.Dimension; - - -/** - * Implements ANewEventListener and creates PNG files - * upon each newEvent call. A scale factor allows to e.g. produce thumbnails by - * scaling down image. The image producer works in two modes: - * a) If no file name is given, a file name will be generated from run and event - * number. In case the PNG file exists, no file is created but a warning is written out. - * b) If a file name is given, a temporary file is generated first, and then - * renamed to the given file name. If renaming fails, a warning is written out - * and the temporary file is deleted. - * - * @author Sebastian Boeser - */ - -public class APngImageProducer extends AImageProducer -{ - // the logger - private static final ALogger logger = ALogger.getLogger(APngImageProducer.class); - - // Our image encode - private final AImageEncoder imageEncoder = new AImageEncoder(); - - /** - * Fully qualified constructor, - * intializing all the attributes and check the parameters validity - * @param dir the directory in which to save all the files - * @param size the dimensions of the images - * @param scale the factor by which to scale the images - * @param fileName if not null, that file will be overwritten for each event - * @throws InstantiationException if we fail to create the object - */ - public APngImageProducer(String dir, Dimension size, double scale, String fileName) throws InstantiationException - { - super(dir, size, scale, fileName); - } - - /** - * Called whenever a new event appears. Store a PNG in the directory, - * either with a generated file name (no overwrite) or with a fixed file name (overwrite) - * @param event the event from which to generate the PNG - */ - public void newEvent(AEvent event) - { - - //If auto had been set for size (height is negative), get height from Canvas - if (imageSize.height < 0) imageSize.setSize(imageSize.width, ACanvas.getCanvas().getRespectiveHeight(imageSize.width)); - - //Create the file to write the data into - File pngFile; - //If we don't have a fixed file name, - //generate a unique one based on run- and event number - if (fixedFileName==null){ - - //Now construct all the full path for the file we want to save - String pngName = String.format("%s%s%s.png",directory, - System.getProperty("file.separator"), - getEventFileName(event)); - - // Create file handles to the file and check if it exists - pngFile = new File(pngName); - //Do not overwrite any existing files - if (pngFile.exists()) { - logger.warn("File "+ pngName +" already exists - will not overwrite"); - return; - } - //otherwise generate a temporary file first, - //then move it in place later - } else { - //make a temporary file in the final directory - try { - pngFile = File.createTempFile(filePrefix+"_", ".png",directory); - } catch (IOException ex) { - logger.warn("Failed to create temporary file in "+directory.getAbsolutePath()); - return; - } - } - - //Now create the image. If the scaleFactor equals 1, no scaling will happen. - byte[] pngData = imageEncoder.getScaledPNGData(imageSize.width,imageSize.height,scaleFactor); - - //Now try saving the acquired data, - //and if it shall go to a fixed file, move it there - try { - //Save the PNG - saveDataIntoFile(pngData, pngFile); - //move to fixed file name if requested - if (fixedFileName != null){ - - //Get a handle to the final destination - File fixedFile = new File(directory,fixedFileName); - - //delete target if exits - if (fixedFile.exists() && (!fixedFile.delete())) - throw new IOException("Failed to delete existing file "+fixedFile.getAbsolutePath()); - - //And move the new file in place - if (!pngFile.renameTo(fixedFile)) - throw new IOException("Failed to rename temporary file to "+fixedFile.getAbsolutePath()); - } - } catch (IOException ioe) { - //If we fail, throw a warning - logger.warn("Could not save PNG files for history\n"+ioe.toString()); - } finally { - //In any case, delete the pngFile, if it was just temporary - if (fixedFileName != null) pngFile.delete(); - } - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AStreamedEventSource.java b/graphics/AtlantisJava/src/atlantis/event/AStreamedEventSource.java deleted file mode 100644 index b41e007072f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AStreamedEventSource.java +++ /dev/null @@ -1,52 +0,0 @@ -package atlantis.event; - -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import java.util.Vector; - -/** - * This interface shall be implemented by all event sources that support event - * streams. Only provides simple get and set methods. - * @author sboeser - */ -public interface AStreamedEventSource extends AEventSource { - - /** - * Exception that is thrown if the stream is invalid - */ - public class InvalidStreamException extends AEventSourceException - { - //Default constructor - public InvalidStreamException() { super(); } - //Constructor with a string - public InvalidStreamException( String message ){ super( message ); } - //Constructor with a description and cause - public InvalidStreamException( String message, Throwable cause ){ super( message, cause ); } - } - - /** - * Get an array of names of all available streams - * @return the array of stream names - * @throws InvalidEventSourceException if the list of streams can not be obtained - */ - Vector<String> getAvailableStreams() throws InvalidEventSourceException; - - /** - * Set the stream from which to provide events - * @param streamName the stream from which to get events - * @throws InvalidStreamException if the given name does not specify a valid stream - * @throws InvalidEventSourceException if the server cannot be contacted to get the stream names - */ - void setStream(String streamName) throws InvalidStreamException, - InvalidEventSourceException; - - /** - * Get the currently selected stream, or the default stream if none is selected - * @return the name of the currently selected stream - * @throws InvalidEventSourceException if the list of streams can not be obtained - * @throws NoMoreEventsException if no stream is available - * - */ - String getStream() throws InvalidEventSourceException, - NoMoreEventsException; -} diff --git a/graphics/AtlantisJava/src/atlantis/event/ASvgImageProducer.java b/graphics/AtlantisJava/src/atlantis/event/ASvgImageProducer.java deleted file mode 100644 index a27830547d9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/ASvgImageProducer.java +++ /dev/null @@ -1,117 +0,0 @@ -package atlantis.event; - -import java.io.File; -import java.io.IOException; - -import atlantis.utils.*; -import atlantis.canvas.ACanvas; -import atlantis.graphics.encoders.AImageEncoder; -import java.awt.Dimension; - - -/** - * Implements ANewEventListener and creates SVG files - * upon each newEvent call. A scale factor allows to e.g. produce thumbnails by - * scaling down image. The image producer works in two modes: - * a) If no file name is given, a file name will be generated from run and event - * number. In case the output file exists, no file is created but a warning is written out. - * b) If a file name is given, a temporary file is generated first, and then - * renamed to the given file name. If renaming fails, a warning is written out - * and the temporary file is deleted. - * - * @author Tom McLaughlan - */ - -public class ASvgImageProducer extends AImageProducer -{ - // the logger - private static final ALogger logger = ALogger.getLogger(ASvgImageProducer.class); - - // Our image encode - private final AImageEncoder imageEncoder = new AImageEncoder(); - - /** - * Fully qualified constructor, - * intializing all the attributes and check the parameters validity - * @param dir the directory in which to save all the files - * @param size the dimensions of the images - * @param scale the factor by which to scale the images - * @param fileName if not null, that file will be overwritten for each event - * @throws InstantiationException if we fail to create the object - */ - public ASvgImageProducer(String dir, Dimension size, double scale, String fileName) throws InstantiationException - { - super(dir, size, scale, fileName); - } - - /** - * Called whenever a new event appears. Store an SVG in the directory, - * either with a generated file name (no overwrite) or with a fixed file name (overwrite) - * @param event the event from which to generate the SVG - */ - public void newEvent(AEvent event) - { - - //If auto had been set for size (height is negative), get height from Canvas - if (imageSize.height < 0) imageSize.setSize(imageSize.width, ACanvas.getCanvas().getRespectiveHeight(imageSize.width)); - - //Create the file to write the data into - File outFile; - //If we don't have a fixed file name, - //generate a unique one based on run- and event number - if (fixedFileName==null){ - - //Now construct all the full path for the file we want to save - String outFileName = String.format("%s%s%s.svg",directory, - System.getProperty("file.separator"), - getEventFileName(event)); - - // Create file handles to the file and check if it exists - outFile = new File(outFileName); - //Do not overwrite any existing files - if (outFile.exists()) { - logger.warn("File "+ outFileName +" already exists - will not overwrite"); - return; - } - //otherwise generate a temporary file first, - //then move it in place later - } else { - //make a temporary file in the final directory - try { - outFile = File.createTempFile(filePrefix+"_", ".svg",directory); - } catch (IOException ex) { - logger.warn("Failed to create temporary file in "+directory.getAbsolutePath()); - return; - } - } - - //Now try saving the acquired data, - //and if it shall go to a fixed file, move it there - try { - imageEncoder.saveSVG(imageSize.width, imageSize.height, outFile); - - //move to fixed file name if requested - if (fixedFileName != null){ - - //Get a handle to the final destination - File fixedFile = new File(directory,fixedFileName); - - //delete target if exits - if (fixedFile.exists() && (!fixedFile.delete())) - throw new IOException("Failed to delete existing file "+fixedFile.getAbsolutePath()); - - //And move the new file in place - if (!outFile.renameTo(fixedFile)) - throw new IOException("Failed to rename temporary file to "+fixedFile.getAbsolutePath()); - } - } catch (IOException ioe) { - //If we fail, throw a warning - logger.warn("Could not save SVG files for history\n"+ioe.toString()); - } finally { - //In any case, delete the pngFile, if it was just temporary - if (fixedFileName != null) outFile.delete(); - } - - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/AURLEventSource.java b/graphics/AtlantisJava/src/atlantis/event/AURLEventSource.java deleted file mode 100644 index 530a3793cd8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AURLEventSource.java +++ /dev/null @@ -1,385 +0,0 @@ -package atlantis.event; - -import atlantis.data.AEventFromXML; - -import java.util.ArrayList; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.net.URL; -import java.net.MalformedURLException; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.util.Random; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.ALogger; - -import java.util.Collections; - - -/** - * This class obtains an event from an XML file which is read from - * URL address (from a remote source). - * - * Once the file is read the classes tries to create an internal - * list of XML event files from this remote source which is utilised - * when the user accesses next, resp. previous event from this address. - * - * It is dependent on the fact that the web server supports directory - * listings - i.e. it returns an HTML page which this class parses - * and gets all files conforming ".*\.xml" regular expression. - * - * It is possible to specify only URL with a directory where the event - * files are. - * - * @author sboeser - */ -public class AURLEventSource extends ABufferedEventSource -{ - // get the logger - private static final ALogger logger = ALogger.getLogger(AURLEventSource.class); - // the name of the event source - private String directoryURL = null; - - // needed for random mode - private Random randomGenerator = new Random(); - - /** - * @param mode event navigation mode - * @return true if the requested mode is supported by this source - */ - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.SEQUENTIAL || - mode == NavigationMode.RANDOM || - mode == NavigationMode.LOOP) - return true; - return false; - } - - /** - * Constructor with the URL of the directory - * @param sourceName - * @throws atlantis.event.AEventSource.InvalidEventSourceException - */ - public AURLEventSource(String sourceName) throws InvalidEventSourceException - { - - //Make sure the event source starts with http:// - if( ! sourceName.toLowerCase().startsWith("http://")) - throw new InvalidEventSourceException("URL event source name does"+ - "not start with \"http://\""); - - //Store event source - directoryURL = sourceName; - } - - /** - * @return the directory URL string - */ - public String getSourceName() { - return directoryURL; - } - - /** - * Get a list of files in a directory given by a URL - * @param url the url of the directory - * @return a list of urls to the individual files - * @throws atlantis.event.AEventSource.InvalidEventSourceException - */ - private ArrayList<String> getEventListForURL(String url) throws InvalidEventSourceException { - - //the url of the directory we are searching - String baseUrl = url; - //trim any file endings from url - if (url.endsWith(".xml")) - baseUrl = url.substring(0, url.lastIndexOf('/')); - - - //The input stream - need to be closed in the end - InputStreamReader urlStream = null; - BufferedReader br = null; - - //be a bit verbose - logger.info("Trying to get directory listing from " + baseUrl); - - //Create an array to return - ArrayList<String> eventList = new ArrayList<String>(); - - //Now try reading stuff from the web - try { - //Get an input stream reader - urlStream = new InputStreamReader(new URL(baseUrl).openStream()); - //get a buffered reader for that stream - br = new BufferedReader(urlStream); - - // input is the whole line from HTML directory listing - // example to match: <a href="atlantis_event_70417_93.xml"> - // We use regular expressions patterns to catch the lines of interest - // ( ) defines group, group 0 is the whole match and group 1 is - // just the desired file name within the parentheses - Pattern pattern = Pattern.compile("<a href=\"(.*\\.xml)\">"); - - //Loop over all lines - String line = null; - while ((line = br.readLine()) != null) { - //try to match the patter - Matcher matcher = pattern.matcher(line); - if (matcher.find()) // not .match() (!) - { - //Get the first group from the pattern - //i.e the file name and add to our event list - eventList.add(matcher.group(1)); - } - } - - //be a bit verbose - logger.debug("List of " + eventList.size() + " events loaded from " + baseUrl); - - - } catch (MalformedURLException mue) { - String msg = "Incorrect URL address: " + baseUrl; - logger.error(msg); - AOutput.alwaysAppend("\n" + msg + "\n", ALogInterface.WARNING); - throw new InvalidEventSourceException(msg, mue); - } catch (IOException ioe) { - String msg = "IO error while reading URL: " + baseUrl; - logger.error(msg); - AOutput.alwaysAppend("\n" + msg + "\n", ALogInterface.WARNING); - throw new InvalidEventSourceException(msg, ioe); - } finally { - //In any case close everything - try { - br.close(); - urlStream.close(); - } catch (Throwable t) { - //do nothing here - } - } - - //check if there were at least some events - if (eventList.size()==0) - throw new InvalidEventSourceException("No events found at "+baseUrl); - - //In the end sort the event list - Collections.sort(eventList); - - //and return it - return eventList; - - } - - /** - * Read in an event from a fully specified path - * @param fileName the URL to the file - * @param directoryURL the name of the event source - * @return the event - */ - private AEvent readEventFromURL(String fileName, String directoryURL) - throws ReadEventException { - //Things we need to close in the end - InputStream urlStream = null; - BufferedInputStream buffStream = null; - AEvent event = null; - - try { - //Open the url as stream - String fullURL = directoryURL + "/" + fileName; - URL eventURL = new URL(fullURL); - urlStream = eventURL.openStream(); - buffStream = new BufferedInputStream(urlStream); - //then read the event from there - logger.debug("Reading event data stream from " + eventURL.toString() + "..."); - event = AEventFromXML.read(buffStream, fileName); - - } catch (FileNotFoundException fnfe) { - //Show as a warning and rethrow - String msg = "File not found at " + directoryURL+"/"+fileName; - logger.error(msg); - AOutput.alwaysAppend("\n" + msg + "\n", ALogInterface.WARNING); - throw new ReadEventException(msg, fnfe); - } catch (IOException ioe) { - //Show as an error and rethrow - String msg = "IO error when reading " + directoryURL; - logger.error(msg); - AOutput.alwaysAppend("\n" + msg + "\n", ALogInterface.WARNING); - throw new ReadEventException(msg, ioe); - } finally { - try { - if (urlStream != null) { - urlStream.close(); - } - if (buffStream != null) { - buffStream.close(); - } - } catch (Throwable t) { - //Ignore all errors - } - } - return event; - } - - /** - * Read a random event - * @return the random event - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - protected AEvent readRandom() throws InvalidEventSourceException, ReadEventException - { - - String fileName = null; - - //Check if we have been given a fully specified file url - if(directoryURL.endsWith(".xml")){ - //Store the file name from the url - fileName = directoryURL.substring(directoryURL.lastIndexOf('/')+1,directoryURL.length()); - //trim file endings from url - directoryURL = directoryURL.substring(0, directoryURL.lastIndexOf('/')); - - } else { - - //Update event list every time, so we get new files - ArrayList<String> eventList=getEventListForURL(directoryURL); - - //Check there are more files - if (eventList.size() == 0) - throw new InvalidEventSourceException("No valid files at "+directoryURL); - - //Pick a random event - int iName = randomGenerator.nextInt(eventList.size()); - - //Now get the new file - fileName = eventList.get(iName); - } - - //Now read exactly that event and return it - return readEventFromURL(fileName,directoryURL); - } - - - /** - * Read the previous event from the URL directory - * @return the previous event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - public AEvent readNext(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException - { - // if random mode is set, return a random event - if(getNavigationMode() == NavigationMode.RANDOM) return readRandom(); - - String fileName = null; - - //Check if we have been given a fully specified file url - if(directoryURL.endsWith(".xml")){ - //Store the file name from the url - fileName = directoryURL.substring(directoryURL.lastIndexOf('/')+1,directoryURL.length()); - //trim file endings from url - directoryURL = directoryURL.substring(0, directoryURL.lastIndexOf('/')); - - } else { - - //Update event list every time, so we get new files - ArrayList<String> eventList=getEventListForURL(directoryURL); - - //Check there are more files - if (eventList.size() == 0) - throw new NoMoreEventsException("No valid files at "+directoryURL); - //Loop over file list - int iName = 0; - //search for next entry that is lexicographically larger - //taking first one if there is no current one to compare to - while ((currentEvent != null) && - (currentEvent.getSourceName().compareTo(eventList.get(iName)) >= 0)){ - //Go to next file - ++iName; - // if we have reached the end of the list... - if (iName == eventList.size()) - // if in loop mode go to the first event - if(getNavigationMode() == NavigationMode.LOOP) { - iName = 0; - break; - } - // if not in loop mode, abort - else throw new NoMoreEventsException("No more files after " - + currentEvent.getSourceName() + " in directory "+directoryURL); - } - - //Now get the new file - fileName = eventList.get(iName); - } - - //Now read exactly that event and return it - return readEventFromURL(fileName,directoryURL); - } - - /** - * Read the previous event from the current URL directory - * @return the previous event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - public AEvent readPrevious(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException - { - // in random mode there's no looking back - if(getNavigationMode() == NavigationMode.RANDOM) throw new NoMoreEventsException("No more random events left in the buffer"); - - String fileName = null; - - //Check if we have been given a fully specified file url - if(directoryURL.endsWith(".xml")){ - //Store the file name from the url - fileName = directoryURL.substring(directoryURL.lastIndexOf('/')+1,directoryURL.length()); - //trim file endings from url - directoryURL = directoryURL.substring(0, directoryURL.lastIndexOf('/')); - - } else { - - //Update event list every time, so we get new files - ArrayList<String> eventList=getEventListForURL(directoryURL); - - //Check there are more files - if (eventList.size() == 0) - throw new NoMoreEventsException("No valid files at "+directoryURL); - //Loop over file list - int iName = eventList.size()-1; - //search from the end for the first entry that is lexicographically smaller - //taking last one if there is no previous one to compare to - while ((currentEvent != null) && - (currentEvent.getSourceName().compareTo(eventList.get(iName)) <= 0)){ - //Go to next file - --iName; - // if we have reached the end of the list... - if (iName < 0) - // if in loop mode, go to the last file - if(getNavigationMode() == NavigationMode.LOOP) { - iName = eventList.size()-1; - break; - } - // if not in loop mode, abort - else throw new NoMoreEventsException("No more files before " - + currentEvent.getSourceName() + " in directory "+directoryURL); - } - - //Now get the new file - fileName = eventList.get(iName); - } - - //Now read exactly that event and return it - return readEventFromURL(fileName,directoryURL); - } - -} // class AURLEventSource diff --git a/graphics/AtlantisJava/src/atlantis/event/AZipEventSource.java b/graphics/AtlantisJava/src/atlantis/event/AZipEventSource.java deleted file mode 100644 index 16aeb4d0f5e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/AZipEventSource.java +++ /dev/null @@ -1,478 +0,0 @@ -package atlantis.event; - -import atlantis.data.AEventFromXML; - -import java.io.IOException; -import java.io.File; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.ArrayList; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipInputStream; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AUtilities; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.zip.ZipException; -import java.util.Random; - -/** - * Reading zip archives from local or network files or from zip files stored within .jar file - */ -public class AZipEventSource implements AEventSource -{ - - //define the source type - private enum SourceType { - JAR_FILE, - ZIP_FILE, - ZIP_NETWORK_FILE - }; - - // current event navigation mode - private NavigationMode eventNavigationMode = NavigationMode.SEQUENTIAL; - - // needed for random mode - private Random randomGenerator = new Random(); - - // A list of entries in the zip file - ArrayList<ZipEntry> ZipEntries = new ArrayList<ZipEntry>(); - // pointer to the current zip entry - int eventIndex = -1; - // flag if zip file is read from jar file (as stream) - SourceType sourceType = null; - // event file name (or event archive name) - String eventSource = null; - - /** - * @return current event navigation mode - */ - public NavigationMode getNavigationMode() { - return eventNavigationMode; - } - - /** - * @param mode sets the event navigation mode - */ - public void setNavigationMode(NavigationMode mode) throws InvalidEventSourceException { - if(supportsNavigationMode(mode)) { - eventNavigationMode = mode; - // go to the first event - eventIndex = -1; - } - else - throw new InvalidEventSourceException("Mode '"+mode+"' not supported by current source"); - } - - /** - * @param mode event navigation mode - * @return true if the requested mode is supported by this source - */ - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.SEQUENTIAL || - mode == NavigationMode.RANDOM || - mode == NavigationMode.LOOP) - return true; - return false; - } - - /** - * Constructor with event source - * @param sourceName the name of the source - * @throws InvalidEventSourceException - */ - public AZipEventSource(String sourceName) throws InvalidEventSourceException - { - //Locally opened things - ZipFile zipfile = null; - ZipInputStream stream = null; - - try { - // first check if it is an network file - if (sourceName.startsWith("http://")) { - - //open network zip file input stream - stream = openNetworkStream(sourceName); - //try to read entries from network file - readEntriesFromStream(stream); - //set the source type - sourceType = SourceType.ZIP_NETWORK_FILE; - - } else if (sourceName.startsWith("file://")) { - - // strip the file:// from the source name - sourceName = sourceName.substring(7); - - // Check if this is a regular file - File file = new File(sourceName); - - //Read entries from regular file - if( (file.exists() && file.canRead())){ - - //Now try to open as a zipfile - zipfile = new ZipFile(sourceName); - //Try to read the entries from that file - readEntriesFromFile(zipfile); - //set the source type - sourceType = SourceType.ZIP_FILE; - - - } else { - //might still be a zip file in a jar archive - stream = openJarStream(sourceName); - //try to read entries from jar file - readEntriesFromStream(stream); - //set the source type - sourceType = SourceType.JAR_FILE; - } - } - } catch(AAtlantisException ae) { - //Rethrow - throw new InvalidEventSourceException("Atlantis exception reading from: "+eventSource,ae); - } catch(MalformedURLException mue) { - //Rethrow - throw new InvalidEventSourceException("An unknown protocol is specified: "+eventSource,mue); - } catch(ZipException zfe) { - //Rethrow - throw new InvalidEventSourceException("ZIP format error has occurred: "+eventSource,zfe); - } catch(IOException ioe) { - //Rethrow - throw new InvalidEventSourceException("I/O error has occurred reading: "+eventSource,ioe); - } finally { - //Try to close everthing that has been opened - try { - if (zipfile != null) zipfile.close(); - if (stream != null) stream.close(); - } catch (Throwable t){ - //Do nothing if closing fails - } - } - - //If we have not got a valid source type, throw an error - if (sourceType == null) - throw new InvalidEventSourceException("Could not identify source type of "+sourceName); - - //Make sure there are valid events in the file - if (ZipEntries.size() == 0) - throw new InvalidEventSourceException("No entries in ZIP archive: "+sourceName); - - //Store source name - eventSource=sourceName; - //Otherwise set counter to first event - eventIndex = -1; - } - - /** - * @return the name of the event file or archive - */ - public String getSourceName() { - return eventSource; - } - - /** - * Try to open a zip file in a jar file as input stream - * @param sourceName the name of the zip file - * @return the zip stream - */ - private ZipInputStream openJarStream(String sourceName) throws AAtlantisException - { - //Open as zip input stream - return new ZipInputStream(AUtilities.getFileAsStream(sourceName)); - } - - /** - * Try to open a zip file on the net as input stream - * @param sourceName the URL of the zip file - * @return the zip stream - */ - private ZipInputStream openNetworkStream(String sourceName) throws ZipException, - MalformedURLException, - IOException - { - //Open a network zip file as input stream - return new ZipInputStream(new URL(sourceName).openStream()); - } - - - /** - * Check if this is a valid name of an entry in a zip file or stream - * @param entryName the name of the entry - * @return true if valid - */ - private boolean checkZipEntry(ZipEntry entry){ - //Make sure it is not a directory - if(entry.isDirectory()) return false; - //Make sure it ends with .xml - if (! entry.getName().toLowerCase().endsWith(".xml")) return false; - //everthing fine - return true; - } - - /** - * Get a list of all valid entries from a zip stream - * @param zis the input stream - */ - private void readEntriesFromStream(ZipInputStream zis) throws InvalidEventSourceException - { - try { - //Loop over zip entries - ZipEntry next = null; - while((next = zis.getNextEntry()) != null){ - //If it is valid add it to our list fo entries - if (checkZipEntry(next)) ZipEntries.add(next); - } - } catch(ZipException ze) { - //Rethrow - throw new InvalidEventSourceException("ZIP exception reading entry from zip stream",ze); - } catch(IOException ioe){ - //rethrow - throw new InvalidEventSourceException("I/O exception reading entry from zip stream",ioe); - } - } - - /** - * Get a list of all valid XML file entries from a zip file - * @param file the zip input file - * @throws InvalidEventSourceException - */ - private void readEntriesFromFile(ZipFile file) throws InvalidEventSourceException{ - - //Seems to be a regular file - try{ - //Get the zip file entries - Enumeration<? extends ZipEntry> myenum = file.entries(); - //Loop over zip entries - while(myenum.hasMoreElements()){ - //get the entry - ZipEntry next = (ZipEntry) myenum.nextElement(); - //If it is valid add it to our list fo entries - if (checkZipEntry(next)) ZipEntries.add(next); - } - } catch(IllegalStateException ise){ - //rethrow - throw new InvalidEventSourceException("Zip file was cleased while trying to read entries: "+file.getName()); - } - } - /** - * Read a particular event from a stream. - * Since the file is read as stream, it's not possible to reference a - * particular zip entry. However, we know the number of a zip entry - * we want to get (eventIndex), so we seek (getNextEntry()) to the - * zip entry of interest and then read it. - * @return the event - */ - private AEvent readEventFromStream() throws ReadEventException - { - //Things we need to close in the end - ZipInputStream zis = null; - AEvent event = null; - - try{ - //Check which kind of stream we have and open it - if (sourceType == SourceType.JAR_FILE) - zis = openJarStream(eventSource); - else if (sourceType == SourceType.ZIP_NETWORK_FILE) - zis = openNetworkStream(eventSource); - else - throw new ReadEventException("Trying to read stream from neither jar file nor network file:" +eventSource); - - //Now seek through file to current entry - ZipEntry entry = null; - for(int i = 0; i <= eventIndex; i++) - entry = zis.getNextEntry(); - - //Check if we have reached EOF while skipping - if (entry == null) - throw new ReadEventException("Reached EOF while skippeng to entry #"+eventIndex - +" with name "+ZipEntries.get(eventIndex).getName()+ " in "+eventSource); - - //Next check if this is the entry we wanted to have - if (! entry.getName().equals(ZipEntries.get(eventIndex).getName())) - throw new ReadEventException("Content of zip stream changed since opening it:"+eventSource); - - //Finally read-in this entry - event = AEventFromXML.read(zis, entry.getName()); - } catch (AAtlantisException ae) { - throw new ReadEventException("Atlantis exception reading from: " + eventSource, ae); - } catch (ZipException ze) { - throw new ReadEventException("A ZIP format error has occurred reading entry " + - ZipEntries.get(eventIndex).getName() + " from " + eventSource, ze); - } catch (IllegalStateException ise) { - throw new ReadEventException("The zip file has been closed while reading entry" + - ZipEntries.get(eventIndex).getName() + " from " + eventSource, ise); - } catch (IOException ioe) { - throw new ReadEventException("I/O exception reading from: " + eventSource, ioe); - - } finally { - try { - //Always close the files in the end; - if (zis != null) { - zis.close(); - } - } catch (Throwable t) { - //Do nothing if closing the stream fails - } - } - - //Evertthing is fine, return the event - return event; - } - - /** - * Read a particular event from a zip file - * @param file the zip file - * @return the event - * @throws ReadEventException - */ - private AEvent readEventFromFile() throws ReadEventException - { - ZipFile file = null; - AEvent event = null; - try { - //Open the zip file - file = new ZipFile(eventSource); - //Get the input stream for the requested entry - InputStream stream = file.getInputStream(ZipEntries.get(eventIndex)); - //Get the entry name - String eventName = ZipEntries.get(eventIndex).getName(); - //Read the event - event = AEventFromXML.read(stream,eventName); - } catch (ZipException ze){ - throw new ReadEventException("A ZIP format error has occurred reading entry "+ - ZipEntries.get(eventIndex).getName() + " from "+ eventSource, ze); - } catch (IllegalStateException ise){ - throw new ReadEventException("The zip file has been closed while reading entry"+ - ZipEntries.get(eventIndex).getName() + " from "+ eventSource, ise); - } catch(IOException ioe){ - throw new ReadEventException("I/O error reading entry "+ - ZipEntries.get(eventIndex).getName() + " from "+ eventSource, ioe); - } finally { - //Always close the input stream - try { - if(file != null) file.close(); - } catch (Throwable t) { - //Ignore all errors here - } - } - - //Everything fine so we can return the event - return event; - } - - /** - * Reads a random event from a zipped source - * @return the event - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - protected AEvent randomEvent() throws InvalidEventSourceException, - ReadEventException - { - //Check if we have a valid source - if(( sourceType == null ) || ( eventSource==null )) - throw new InvalidEventSourceException("No valid input source"); - - //Now go to next event - eventIndex = randomGenerator.nextInt(ZipEntries.size()); - - //Now get this stream from its proper source - switch (sourceType){ - case JAR_FILE: return readEventFromStream(); - case ZIP_NETWORK_FILE: return readEventFromStream(); - case ZIP_FILE: return readEventFromFile(); - default: throw new ReadEventException("Unknown event source type"); - } - } - - /** - * Read the next event from a zipped source - * @return the event - * @throws InvalidEventSourceException - * @throws NoMoreEventsException - * @throws ReadEventException - */ - public AEvent nextEvent() throws InvalidEventSourceException, - NoMoreEventsException, - ReadEventException - { - // if random mode is selected, return a random event - if(getNavigationMode() == NavigationMode.RANDOM) return randomEvent(); - - //Check if we have a valid source - if(( sourceType == null ) || ( eventSource==null )) - throw new InvalidEventSourceException("No valid input source"); - - // if we're in loop mode and at the last event, go to the first one - if(getNavigationMode() == NavigationMode.LOOP && eventIndex >= ZipEntries.size() - 1) - eventIndex = 0; - // if we're not in loop mode and at the last event... - else { - // check that there are still some events - if(eventIndex >= ZipEntries.size() - 1){ - String msg="Already at last event in archive"; - // inform user - AOutput.alwaysAppend("\n" + msg+"\n", ALogInterface.WARNING); - throw new NoMoreEventsException(msg); - } - // go to next event. - eventIndex++; - } - - //Now get this stream from its proper source - switch (sourceType){ - case JAR_FILE: return readEventFromStream(); - case ZIP_NETWORK_FILE: return readEventFromStream(); - case ZIP_FILE: return readEventFromFile(); - default: throw new ReadEventException("Unknown event source type"); - } - } - - - /** - * Read the previous event from a zipped source - * @return the event - * @throws InvalidEventSourceException - * @throws NoMoreEventsException - * @throws ReadEventException - */ - public AEvent previousEvent() throws InvalidEventSourceException, - NoMoreEventsException, - ReadEventException - { - - // in random mode there's no looking back - if(getNavigationMode() == NavigationMode.RANDOM) throw new NoMoreEventsException("Cannot go back in random mode"); - - //Check if we have a valid source - if(( sourceType == null ) || ( eventSource==null )) - throw new InvalidEventSourceException("No valid input source"); - - // if we're in loop mode and we're at the first event, go to the last one - if(getNavigationMode() == NavigationMode.LOOP && eventIndex == 0) - eventIndex = ZipEntries.size() -1; - // if we're not il loop mode and at the first event... - else { - // check that there are still some events - if(eventIndex == 0){ - String msg="Already at first event in archive"; - // inform user - AOutput.alwaysAppend("\n" + msg+"\n", ALogInterface.WARNING); - throw new NoMoreEventsException(msg); - } - // go to previous event. - eventIndex--; - } - - //Now get this stream from its proper source - switch (sourceType){ - case JAR_FILE: return readEventFromStream(); - case ZIP_NETWORK_FILE: return readEventFromStream(); - case ZIP_FILE: return readEventFromFile(); - default: throw new ReadEventException("Unknown event source type"); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/oncrpc/AONCRPCEventSource.java b/graphics/AtlantisJava/src/atlantis/event/oncrpc/AONCRPCEventSource.java deleted file mode 100644 index 42410d71941..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/oncrpc/AONCRPCEventSource.java +++ /dev/null @@ -1,304 +0,0 @@ - -package atlantis.event.oncrpc; - -import atlantis.data.AEventFromXML; -import atlantis.utils.ALogger; - -import atlantis.event.ABufferedEventSource; -import atlantis.event.AEvent; -import atlantis.event.AEventInfo; -import atlantis.event.AStreamedEventSource; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; - -import org.acplt.oncrpc.XdrVoid; -import org.acplt.oncrpc.OncRpcTcpClient; -import org.acplt.oncrpc.OncRpcException; -import org.acplt.oncrpc.OncRpcProgramNotRegisteredException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetAddress; -import java.util.Arrays; -import java.util.Vector; - -/** - * Implements an event source retrieving events from an ONC/RPC server. - * By implementing a ABufferedEventSource, a number of previous events will be - * available to the user. Care is taken to clear the buffer in case we run into - * memory problems. This event source also provides event streams by implementing - * AStreamedEventSource. - * - * @author sboeser - */ - -public class AONCRPCEventSource extends ABufferedEventSource implements AStreamedEventSource { - - //The logger - private static final ALogger logger = ALogger.getLogger(AONCRPCEventSource.class); - - //The ONC/RPC client - private OncRpcTcpClient client = null; - - //The default timeout value in milliseconds for calling the server - private static final int DEFAULT_TIMEOUT = 2000; - //The name of the stream to read events from - private String currentStream = null; - - /** - * Constructor with the server name and port as a string value - * @param sourceName - * @throws InvalidEventSourceException - */ - public AONCRPCEventSource(String sourceName) throws InvalidEventSourceException { - - //Remove any leading "oncrpc://" indicator - sourceName = sourceName.replaceFirst("oncrpc://", ""); - - //Check if we can split the sourceName in hostName:port pair - String[] sourceParams = sourceName.split(":"); - //Do some sanity check - if (sourceParams.length > 3) - throw new InvalidEventSourceException("Invalid <server[:port][:stream]> specification: "+sourceName); - - //Now try to get the port number if it was given, - //Otherwise get port from portmapper by using 0; - int port = 0; - if ((sourceParams.length > 1)&&(sourceParams[1].length() > 0)){ - try { - port = Integer.decode(sourceParams[1]); - } catch (NumberFormatException nfe){ - throw new InvalidEventSourceException("Invalid port number: "+sourceParams[1]); - } - } - - //More sanity checks - if (port < 0) - throw new InvalidEventSourceException("Invalid port number: "+port); - - //If a stream name was given, set it now - if (sourceParams.length > 2) currentStream = sourceParams[2]; - - - //Now call the fully qualified constructor with the defaul timeout value - createClient(sourceParams[0],port,DEFAULT_TIMEOUT); - - } - - /** - * Constructor with server name, port number and timeout - * @param hostName the name or IP-address of the remote server - * @param port the port number to which the request is send - can be 0 - * @param timeout a timeout value in milliseconds - * @throws InvalidEventSourceException - */ - public AONCRPCEventSource(String hostName, int port, int timeout) throws InvalidEventSourceException { - //Call common constructor entry - createClient(hostName,port,timeout); - } - - /** - * @return a string of the form oncrpc://hostName:port:stream - */ - public String getSourceName() { - return "oncrpc://"+client.getHost().getHostName()+":"+ client.getPort()+ - ((currentStream != null) ? ":"+currentStream : ""); - } - - /** - * This source only supports sequential mode. - * @param mode event navigation mode to test - * @return true if the requested mode is supported by this source - */ - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.SEQUENTIAL) - return true; - return false; - } - - /** - * Common entry point for all constructors - * @param hostName the name or IP-address of the remote server - * @param port the port number to which the request is send - * @param timeout a timeout value in milliseconds - * @throws InvalidEventSourceException - */ - private void createClient(String hostName, int port, int timeout) throws InvalidEventSourceException { - - //Now try to create the client - try { - client = new OncRpcTcpClient(InetAddress.getByName(hostName), - Server.ONCRPCSERVERPROG,Server.ONCRPCSERVERVERS,port); - } catch ( ConnectException e ) { - throw new InvalidEventSourceException("Could not connect to "+hostName,e); - } catch ( OncRpcProgramNotRegisteredException e ) { - throw new InvalidEventSourceException("Server not (yet) registered on "+hostName,e); - } catch ( OncRpcException e ) { - throw new InvalidEventSourceException("ONC/RPC exception while connecting to "+hostName,e); - } catch ( IOException e ) { - throw new InvalidEventSourceException("I/O Exception while connecting to "+hostName,e); - } - - //Set the requested timeout - client.setTimeout(timeout); - } - - /** - * Read the next event from the server - * @param currentEvent the current event - * @return the next event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - @Override - protected synchronized AEvent readNext(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException { - - //Be verbose - logger.info("Call to remote server "+getSourceName()); - - //Ping the server to make sure it is alive, otherwise try to recreate client - try { - client.call(Server.ONCRPC_NULL_PROC,XdrVoid.XDR_VOID, XdrVoid.XDR_VOID); - } catch (OncRpcException e) { - //Server does not respond to ping, try to recreate client - logger.info("Failed to ping server "+getSourceName()+", trying to recreate client"); - //Use setting from old client to create new client, but allow new port number - createClient(client.getHost().getHostName(),0,client.getTimeout()); - } - - //Create an event request - this may als set the default stream - EventRequest eventReq = new EventRequest(-1,-1,getStream()); - - - //use information from existing event if there is - if (currentEvent != null){ - eventReq.EventNumber = currentEvent.getEventNumber(); - eventReq.RunNumber = currentEvent.getRunNumber(); - } - - //Also prepare the return structure - Event event = new Event(); - - //record calling time - long startTime = System.currentTimeMillis(); - - - // perform the remote call - try { - client.call(Server.ONCRPC_GETEVENT_PROC, eventReq, event); - } catch (OncRpcException e) { - throw new InvalidEventSourceException("Failed to get new event from server",e); - } - - //do some statistics - long callDuration = System.currentTimeMillis() - startTime; - logger.debug("Received " + event.EventData.length + " bytes in " + callDuration + " ms"); - - //Now analyze the event we got - //Check if we already have the event - if (event.isIdentical) - //already have this event - throw new NoMoreEventsException("Already have event "+event.EventNumber + - " from run "+event.RunNumber); - //Check if the stream was available - if (!event.isAvailable) - //make event source invalid - throw new InvalidEventSourceException("No event available for stream "+eventReq.StreamName); - - //Check if the event is compressed - if (event.isCompressed) - //not supported yet - throw new UnsupportedOperationException("Support for compressed events not yet implemented"); - - //It seems we got something worth processing - //Strip the trailing null character - event.EventData=(new String(event.EventData)).trim().getBytes(); - //Wrap the data as an inputstream - ByteArrayInputStream bais = new ByteArrayInputStream(event.EventData); - - //Finally construct a new event and return it - return AEventFromXML.read(bais, currentStream); - } - -/** - * Requesting to read the previouse event from the server only appears - * if we have already reached the beginning of the event buffer. - * Only one current events are provided by the server at any time, thus we - * will always throw a NoMoreEventsException. Handling of the exception is left - * to the GUI interface. - * @param currentEvent will be ignored - * @return nothing as it will always raise an exception - * @throws NoMoreEventsException - */ - @Override - protected AEvent readPrevious(AEventInfo currentEvent) throws NoMoreEventsException - { - throw new NoMoreEventsException("ONC/RPC server does not provide a previous event"); - } - - /** - * Get a list of available streams from the server - * @return the list of stream names - * @throws InvalidEventSourceException if the server cannot be contacted - */ - public synchronized Vector<String> getAvailableStreams() throws InvalidEventSourceException { - - //Prepare response structure - Streams streams = new Streams(); - - - //Call the server - try { - client.call(Server.ONCRPC_GETSTREAMS_PROC, XdrVoid.XDR_VOID, streams); - } catch (OncRpcException e) { - throw new InvalidEventSourceException("Failed to get new stream list from server",e); - } - //We got stream names, so just return them - return new Vector(Arrays.asList(streams.StreamNames)); - } - - /** - * Set a new stream as current stream - * @param streamName the name of the stream - * @throws InvalidStreamException if the stream does not exist at the server - */ - public synchronized void setStream(String streamName) throws InvalidStreamException, - InvalidEventSourceException{ - //Check if the requested stream is available - if (! getAvailableStreams().contains(streamName)) - throw new InvalidStreamException("Stream \""+streamName+"\" not available at server"); - - //Store this as the new current stream - currentStream = streamName; - } - - /** - * Get the currently selected stream - * @return the name of the currently selected stream - * @throws NoMoreEventsException if no streams are available - * @throws InvalidEventSourceException if the list of streams can not be obtained - */ - public synchronized String getStream() throws InvalidEventSourceException, - NoMoreEventsException - { - - //If stream name is not set, set it to first available by default - if (currentStream==null){ - //Get list of streams - Vector<String> streams = getAvailableStreams(); - //If there are none throw a "NoMoreEventsException" - if (streams.size()<1) throw new NoMoreEventsException("No streams available"); - //Now set current stream as first one in list - currentStream=streams.firstElement(); - //be verbose - logger.info("Stream not set, using '"+currentStream+"'"); - } - - return currentStream; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Event.java b/graphics/AtlantisJava/src/atlantis/event/oncrpc/Event.java deleted file mode 100644 index cf34cf74cb0..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Event.java +++ /dev/null @@ -1,86 +0,0 @@ -package atlantis.event.oncrpc; -import org.acplt.oncrpc.*; -import java.io.IOException; - -/** - * This structure declares the event as returned from a call - * to the ONCRPC_GETEVENT_PROC. - * @author Sebastian Boeser - */ -public class Event implements XdrAble { - - - /** False if no event exists for the requested stream at the server*/ - public boolean isAvailable; - /** True if no new event exists at the server */ - public boolean isIdentical; - /** True if the event data is compressed */ - public boolean isCompressed; - /** The name fo the stream this event belongs to */ - public String StreamName; - /** The number of the event */ - public long EventNumber; - /** The number of the run */ - public long RunNumber; - /** The event data as byte array */ - public byte [] EventData; - - /** - * Constructor - */ - public Event() { - //Initialize variables - isAvailable = false ; - isIdentical = false ; - isCompressed = false ; - StreamName = ""; - EventNumber = -1; - RunNumber = -1; - EventData = null; - } - - /** - * Constructor that can be used with RPC client call - * @param xdr the stream that holds the encoded event - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public Event(XdrDecodingStream xdr) throws OncRpcException, IOException { - xdrDecode(xdr); - } - - /** - * Encode the information in XDR representation - * @param xdr the stream to encode into - * @throws OncRpcException if encoding fails - * @throws IOException - */ - public void xdrEncode(XdrEncodingStream xdr) throws OncRpcException, IOException { - //Encode all fields in proper order into the stream - xdr.xdrEncodeBoolean(isAvailable); - xdr.xdrEncodeBoolean(isIdentical); - xdr.xdrEncodeBoolean(isCompressed); - xdr.xdrEncodeString(StreamName); - xdr.xdrEncodeLong(EventNumber); - xdr.xdrEncodeLong(RunNumber); - xdr.xdrEncodeByteVector(EventData); - } - - /** - * Decode the information from XDR representation - * @param xdr the stream to decode from - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public void xdrDecode(XdrDecodingStream xdr) throws OncRpcException, IOException { - //Decode all fields in proper order from stream - isAvailable = xdr.xdrDecodeBoolean(); - isIdentical = xdr.xdrDecodeBoolean(); - isCompressed = xdr.xdrDecodeBoolean(); - StreamName = xdr.xdrDecodeString(); - EventNumber = xdr.xdrDecodeLong(); - RunNumber = xdr.xdrDecodeLong(); - EventData = xdr.xdrDecodeDynamicOpaque(); - } - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/event/oncrpc/EventRequest.java b/graphics/AtlantisJava/src/atlantis/event/oncrpc/EventRequest.java deleted file mode 100644 index fa60d782857..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/oncrpc/EventRequest.java +++ /dev/null @@ -1,79 +0,0 @@ -package atlantis.event.oncrpc; -import org.acplt.oncrpc.*; -import java.io.IOException; - -/** - * Data structure as passed to the ONCRPC_GETEVENT_PROC - * When sending an event request to the server, we have to specify the stream name, - * along with informatian about events we already have. Negative event and run number - * indicates we don't have any events yet. - * @author Sebastian Boeser - */ -public class EventRequest implements XdrAble { - - /** The event number of the event we already have */ - public long EventNumber; - /** The run number of the event we already have */ - public long RunNumber; - /** The name of the stream we are asking events from */ - public String StreamName; - - /** - * Constructor - */ - public EventRequest() { - //Initialize values - EventNumber = -1; - RunNumber = -1; - StreamName = ""; - } - - /** - * Fully qualified constructor - * @param eventNumber the event number of the event we already have - * @param runNumber the run number of the event we already have - * @param streamName the stream we are asking events from - */ - public EventRequest(long eventNumber, long runNumber, String streamName){ - EventNumber = eventNumber; - RunNumber = runNumber; - StreamName = streamName; - } - - /** - * Construct an event request returned from an rpc call - * @param xdr the stream to construct the request from - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public EventRequest(XdrDecodingStream xdr) throws OncRpcException, IOException { - xdrDecode(xdr); - } - - /** - * Encode the information in XDR representation - * @param xdr the stream to encode into - * @throws OncRpcException if encoding fails - * @throws IOException - */ - public void xdrEncode(XdrEncodingStream xdr) throws OncRpcException, IOException { - //Encode into stream in proper order - xdr.xdrEncodeLong(EventNumber); - xdr.xdrEncodeLong(RunNumber); - xdr.xdrEncodeString(StreamName); - } - - /** - * Decode the information in XDR representation - * @param xdr the stream to decode from - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public void xdrDecode(XdrDecodingStream xdr) throws OncRpcException, IOException { - //Decode from stream in proper order - EventNumber = xdr.xdrDecodeLong(); - RunNumber = xdr.xdrDecodeLong(); - StreamName = xdr.xdrDecodeString(); - } - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Server.java b/graphics/AtlantisJava/src/atlantis/event/oncrpc/Server.java deleted file mode 100644 index be83e8e71c9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Server.java +++ /dev/null @@ -1,47 +0,0 @@ -package atlantis.event.oncrpc; - -/** - * A collection of constants used by the "ONCRPCServer" ONC/RPC program. - * These constants need to match the respective definitons on the C++ server - * side, where they are defined in JiveXML/JiveXML/ONCRPCServer.h - * @author Sebastian Boeser - */ -public interface Server { - - /** - * The ID by which the server is identified - */ - public static final int ONCRPCSERVERPROG = 200048965; - - /** - * The version of the current server interface - */ - public static final int ONCRPCSERVERVERS = 2; - - /** - * The ID of the void procdure - */ - public static final int ONCRPC_NULL_PROC = 0; - - /** - * The ID of the getStatus procedure - */ - public static final int ONCRPC_GETSTATUS_PROC = 1; - - /** - * The ID of the getStreams procedure - */ - public static final int ONCRPC_GETSTREAMS_PROC = 2; - - - /** - * The ID of the getEvent procedure - */ - public static final int ONCRPC_GETEVENT_PROC = 3; - - /** - * The ID of the SetNewEvent procedure - is not implemented in this client - */ - //public static final int ONCRPC_SETEVENT_PROC = 4; -} - diff --git a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Streams.java b/graphics/AtlantisJava/src/atlantis/event/oncrpc/Streams.java deleted file mode 100644 index b61d84cb973..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/oncrpc/Streams.java +++ /dev/null @@ -1,53 +0,0 @@ -package atlantis.event.oncrpc; -import org.acplt.oncrpc.*; -import java.io.IOException; - -/** - * Data structure as returned from ONCRPC_GETSTREAMS_PROC is a list of stream names - * available at the server. - * @author Sebastian Boeser - */ -public class Streams implements XdrAble { - - /** The array of stream names */ - public String [] StreamNames; - - /** - * Constructor - */ - public Streams() { - //Array is empty by default, nothing to initialize - } - - /** - * Constructure that can be passed to an RPC client call - * @param xdr the stream to decode from - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public Streams(XdrDecodingStream xdr) throws OncRpcException, IOException { - xdrDecode(xdr); - } - - /** - * Encode the information in XDR representation - * @param xdr the XDR stream to encode into - * @throws OncRpcException if encoding fails - * @throws IOException - */ - public void xdrEncode(XdrEncodingStream xdr) throws OncRpcException, IOException { - //Encode the stream name - xdr.xdrEncodeStringVector(StreamNames); - } - - /** - * Decode the information from XDR representation - * @param xdr the XDR stream to decode from - * @throws OncRpcException if decoding fails - * @throws IOException - */ - public void xdrDecode(XdrDecodingStream xdr) throws OncRpcException, IOException { - //Encode stream names - StreamNames = xdr.xdrDecodeStringVector(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/event/package.html b/graphics/AtlantisJava/src/atlantis/event/package.html deleted file mode 100644 index b6788c40f43..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/package.html +++ /dev/null @@ -1,9 +0,0 @@ -<html> -<head></head> -<body> -<p>This package holds all the main event base classes, such as - the data type base AData or the event class AEvent. It also hold the event - sourc managers and interfaces, as well as their concrete implementations. -</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AClientXMLRPC.java b/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AClientXMLRPC.java deleted file mode 100755 index 2e795e433c1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AClientXMLRPC.java +++ /dev/null @@ -1,244 +0,0 @@ -package atlantis.event.xmlrpc; - -import atlantis.utils.*; -import java.net.URL; -import java.net.MalformedURLException; -import java.util.Vector; - -import org.apache.xmlrpc.client.XmlRpcClient; -import org.apache.xmlrpc.client.AsyncCallback; -import org.apache.xmlrpc.XmlRpcException; -import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; -import org.apache.xmlrpc.client.TimingOutCallback; - - -/** - * Implementation of XMLRPC client communicating to the - * server side running within the Athena framework - JiveXML C++ ulxmlrpcpp server, - * Python Interactive server. - * - * @author Zdenek Maxa - */ -public class AClientXMLRPC -{ - private final static ALogger logger = ALogger.getLogger(AClientXMLRPC.class); - - private String methodName = ""; - private AsyncCallback caller = null; - - // timeout - default timeout delay for synchronous calls [ms] - private int timeout = 6000; - - - - - /** - * Constructor for synchronous XMLRPC calls - * @param method - */ - public AClientXMLRPC(String method) - { - this.methodName = method; - this.caller = null; // synchronous calls will be demanded - - } // AClientXMLRPC() ---------------------------------------------------- - - - - /** - * Constructor for asynchronous XMLRPC calls - * @param method - * @param caller - */ - public AClientXMLRPC(String method, AsyncCallback caller) - { - this.methodName = method; - this.caller = caller; // asynchronous calls - - } // AClientXMLRPC() ---------------------------------------------------- - - - - public void setTimeout(int value) - { - this.timeout = value; - - } // setTimeout() ------------------------------------------------------- - - - - /** - * Asynchronous XMLRPC call, returns immediately and callback - * caller is later invoked when result is available. - * @param client - * @param params - * @throws ARemoteCallerException - */ - private void asynchronousCallXMLRPCServer(XmlRpcClient client, Vector params) - throws ARemoteCallerException - { - String msg = ""; - - logger.debug("Asynchronous XMLRPC call ..."); - try - { - client.executeAsync(methodName, params, caller); - - } - catch(Throwable t) - { - if(t instanceof XmlRpcException) - { - msg = "XMLRPC exception occured, performing the remote call failed."; - } - else - { - msg = "Unspecified exception occured, reason: " + t.getMessage(); - } - logger.debug(msg, t); - throw new ARemoteCallerException(msg); - } - - } // asynchronousCallXMLRPCServer() ------------------------------------- - - - - /** - * Synchronous XMLRPC call. Implemented as asynchronous but timing-out - * call so that we wait until the result is available. This way it prevents - * Atlantis from hanging if remote server (Athena) crashes. - * @param client - * @param params - * @return - * @throws ARemoteCallerException - */ - private String synchronousCallXMLRPCServer(XmlRpcClient client, Vector params) - throws ARemoteCallerException - { - String msg = ""; - String result = null; - - logger.debug("Synchronous timing-out XMLRPC call (timeout " + - timeout / 1000 + "s) ..."); - - TimingOutCallback callback = new TimingOutCallback(timeout); - try - { - client.executeAsync(methodName, params, callback); - } - catch(XmlRpcException xmle) - { - msg = "XMLRPC exception occured, performing the remote call failed."; - logger.debug(msg, xmle); - throw new ARemoteCallerException(msg); - } - - - try - { - result = (String) callback.waitForResponse(); - - // no error, result should be event data - all well - logger.debug("Performing timing out XMLRPC call successful."); - } - catch(Throwable t) - { - if(t instanceof InterruptedException) - { - msg = "The request was interrupted, timed out after " + - timeout / 1000 + "s, try increasing the timer."; - } - else if(t instanceof TimingOutCallback.TimeoutException) - { - msg = "No response was received after waiting " + - timeout / 1000 + "s, try increasing the timer."; - } - else - { - msg = "An error was returned by the server, reason: " + t.getMessage(); - } - logger.debug(msg, t); - throw new ARemoteCallerException(msg); - } - - return result; - - } // synchronousCallXMLRPCServer() -------------------------------------- - - - - /** - * Main method calling remote server methods via XMLRPC - * - * @param serverName - name of the XMLRPC server to call method on - * @param port - where XMLRPC runs - * @param params - Vector containing either command to execute, - * name of a remote variable to get its value or expression to - * process (to change some variables's value) - * @return String - result - * @throws ARemoteCallerException - */ - public String callXMLRPCServer(String serverName, int port, Vector params) - throws ARemoteCallerException - { - - XmlRpcClient client = null; - String result = null; - String msg = null; // logging temporary variable - - msg = "Calling " + serverName + ":" + port; - logger.info(msg); - - - // create instance of XMLRPC client - try - { - // Vector type is only acceptable for XmlRpcClient.execute() / - // .executeAsync() - // String is expected on the remote side by C++ ulxmlrpcpp server - // String, among others, is accepted by Python server as well - - // throws MalformedURLException - XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); - config.setServerURL(new URL(serverName + ":" + port)); - client = new XmlRpcClient(); - client.setConfig(config); - logger.debug("XMLRPC client instantiated successfully."); - } - catch(Throwable t) - { - if(t instanceof MalformedURLException) - { - msg = "Could not create XMLRPC client, bad address " + - serverName + ":" + port + "\n" + - "reason: " + t.getMessage(); - } - else - { - msg = "Unspecified exception occured\n" + - "reason: " + t.getMessage(); - } - - logger.debug(msg, t); - throw new ARemoteCallerException(msg); - } - - - if(caller != null) - { - // perform asynchronous XMLRPC call, returns immediately - asynchronousCallXMLRPCServer(client, params); - } - else - { - // synchronous call, timing out synchronous call - result = synchronousCallXMLRPCServer(client, params); - } - - client = null; - return result; - - } // callXMLRPCServer() ------------------------------------------------- - - -} // class AClientXMLRPC ==================================================== \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/ARemoteCallerException.java b/graphics/AtlantisJava/src/atlantis/event/xmlrpc/ARemoteCallerException.java deleted file mode 100755 index b6958f4d1ea..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/ARemoteCallerException.java +++ /dev/null @@ -1,22 +0,0 @@ -package atlantis.event.xmlrpc; - -import atlantis.utils.*; - - -/** - * - * Exception thrown after errors occured during calls - * to remote server methods (within Athena) via XMLRPC - * - * @author Zdenek Maxa - */ -public class ARemoteCallerException extends AAtlantisException -{ - public ARemoteCallerException(String msg) - { - super("Exception while calling remote procedure.\n" + msg); - - } // ARemoteCallerException() ------------------------------------------- - - -} // class ARemoteCallerException =========================================== diff --git a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPC.java b/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPC.java deleted file mode 100644 index 8d481b260b6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPC.java +++ /dev/null @@ -1,43 +0,0 @@ -package atlantis.event.xmlrpc; - -import atlantis.utils.*; -import java.io.IOException; -import org.apache.xmlrpc.XmlRpcException; -import org.apache.xmlrpc.webserver.WebServer; -import org.apache.xmlrpc.server.XmlRpcServer; -import org.apache.xmlrpc.server.PropertyHandlerMapping; - -/** - * - * @author Adam Davison - */ -public class AServerXMLRPC { - - private static ALogger logger = ALogger.getLogger(AServerXMLRPC.class); - - private WebServer m_ws; - - public AServerXMLRPC(int port, Class handler) throws XmlRpcException { - - logger.debug("Attempting to create XMLRPC server on port " + port); - logger.debug("Serving requests to handler of type " + handler.getName()); - - m_ws = new WebServer(port); - XmlRpcServer xmlRpcServer = m_ws.getXmlRpcServer(); - PropertyHandlerMapping phm = new PropertyHandlerMapping(); - phm.addHandler(handler.getName(), handler); - xmlRpcServer.setHandlerMapping(phm); - - logger.debug("XMLRPC server created successfully"); - - } - - public void start() throws IOException { - - logger.debug("Attempting to start XMLRPC server"); - m_ws.start(); - logger.info("XMLRPC server started"); - - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPCEventSource.java b/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPCEventSource.java deleted file mode 100644 index f3bf0fe2c68..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AServerXMLRPCEventSource.java +++ /dev/null @@ -1,146 +0,0 @@ -package atlantis.event.xmlrpc; - -import atlantis.utils.*; -import atlantis.canvas.ACanvas; -import atlantis.data.AEventFromXML; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource; -import atlantis.globals.AGlobals; -import atlantis.graphics.encoders.AImageEncoder; -import java.io.ByteArrayInputStream; - -/** - * - * @author Adam Davison - */ -public class AServerXMLRPCEventSource implements AEventSource{ - - private static ALogger logger = ALogger.getLogger(AServerXMLRPCEventSource.class); - - private AEventManager m_aem; - private ACanvas m_canv; - private AImageEncoder m_ie; - - private AEvent m_event = null; // Current event - private String m_sourcename = ""; // Source name - - private NavigationMode eventNavigationMode = NavigationMode.PUSH; - - public AServerXMLRPCEventSource() { - m_aem = AEventManager.instance(); - m_canv = ACanvas.getCanvas(); - m_ie = new AImageEncoder(); - } - - public String getVersion() { - return AGlobals.instance().getVersion(); - } - - public boolean isReady() { - return true; - } - - public boolean shutdown() { - logger.info("Exiting atlantis..."); - System.exit(0); - return true; - } - - public NavigationMode getNavigationMode() { - return eventNavigationMode; - } - - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.PUSH) - return true; - return false; - } - - public void setNavigationMode(NavigationMode mode) throws InvalidEventSourceException { - if(mode != NavigationMode.PUSH) - throw new InvalidEventSourceException("Mode '"+mode.name()+"' not supported by current source"); - eventNavigationMode = mode; - } - - private void setEventFromBytes(byte[] eventdata, String sourcename) throws Exception { - AEvent e = AEventFromXML.read(new ByteArrayInputStream(eventdata), sourcename); - - m_event = e; - m_sourcename = sourcename; - - // Force update from event manager - m_aem.setEventSource(this); - m_aem.nextEvent(); - } - - private byte[] getSingleImage(int w, int h, String type, double s) throws Exception { - if (type.equalsIgnoreCase("png")) { - return m_ie.getPNGData(w, h); - } else if (type.equalsIgnoreCase("scaledpng")) { - return m_ie.getScaledPNGData(w, h, s); - } - - throw new Exception("Unknown image format: " + type); - } - - private byte[] getSingleImageAspect(int w, String type, double s) throws Exception { - int h = m_canv.getRespectiveHeight(w); - return getSingleImage(w, h, type, s); - } - - public byte[][] generateDefaultImages(byte[] eventdata, String sourcename, - int width, double thumb_scale) { - - byte ret[][] = new byte[2][]; - - try { - setEventFromBytes(eventdata, sourcename); - ret[0] = getSingleImageAspect(width, "png", 0.0); - ret[1] = getSingleImageAspect(width, "scaledpng", thumb_scale); - } catch (Exception e) { - logger.error("Error while handling request to generateDefaultImages()", e); - return null; - } - - return ret; - } - - public AEvent nextEvent() throws NoMoreEventsException, InvalidEventSourceException, ReadEventException { - if (m_event == null) { - throw new InvalidEventSourceException(); - } - return m_event; - } - - public AEvent previousEvent() throws NoMoreEventsException, InvalidEventSourceException, ReadEventException { - throw new NoMoreEventsException(); - } - - public String getSourceName() { - return m_sourcename; - } - - /*public byte[][] generateImages(byte[] eventdata, String sourcename, - Integer nimgs, Object[] w, Object[] h, Object[] type, Object[] s) { - - byte ret[][] = new byte[nimgs][]; - - try { - setEventFromBytes(eventdata, sourcename); - - for (int i = 0; i < nimgs; i++) { - // Handle cast of s better here - ret[i] = getSingleImage((Integer) (w[i]), (Integer) (h[i]), - (String) (type[i]), (Double) (s[i])); - } - - } catch (Exception e) { - logger.error("Error while handling request to generateImages()", e); - return null; - } - - return ret; - }*/ - -} diff --git a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AXMLRPCEventSource.java b/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AXMLRPCEventSource.java deleted file mode 100644 index 29967b6e310..00000000000 --- a/graphics/AtlantisJava/src/atlantis/event/xmlrpc/AXMLRPCEventSource.java +++ /dev/null @@ -1,238 +0,0 @@ - -package atlantis.event.xmlrpc; - -import atlantis.event.*; -import atlantis.data.AEventFromXML; -import atlantis.Atlantis; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; - -import atlantis.utils.ALogger; - -import java.io.ByteArrayInputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Vector; - - -/** - * Implements an event source retrieving events from an XMLRCP server. - * By implementing a ABufferedEventSource, a number of previous events will be - * available to the user. Care is taken to clear the buffer in case we run into - * memory problems. - * - * @author sboeser - */ - -public class AXMLRPCEventSource extends ABufferedEventSource { - - //The logger - private static final ALogger logger = ALogger.getLogger(AXMLRPCEventSource.class); - - //The XMLRPC client - private AClientXMLRPC XMLRPCClient = null; - //The Method to call on the server side - private static final String GETEVENTDATA = "getEventData"; - //The default timeout value in milliseconds for calling the server - private static final int DEFAULT_TIMEOUT = 2000; - //The name of the local machine (send along with event request) - private String localMachineName = "<unknown>"; - //The name and port number of the remote host - private String remoteMachineName = null; - //The port number to which we should connect - private Integer portNumber = null; - //The timeout for a request - private Integer timeOut = null; - - /** - * Constructor with the server name and port as a string value - * @param sourceName - * @throws InvalidEventSourceException - */ - public AXMLRPCEventSource(String sourceName) throws InvalidEventSourceException { - - //Remove any leading "xmlrpc://" indicator - sourceName = sourceName.replaceFirst("xmlrpc://", ""); - //try to split sourceName in serverName:port pair - String[] sourceParams = sourceName.split(":"); - //Do some checks - if (sourceParams.length != 2) - throw new InvalidEventSourceException("Invalid <server:port> specification: "+sourceName); - - //Try to get the port number - int port = -1; - try { - port = Integer.decode(sourceParams[1]); - } catch (NumberFormatException nfe){ - throw new InvalidEventSourceException("Invalid port number: "+sourceParams[1]); - } - - if (port < 0) - throw new InvalidEventSourceException("Invalid port number: "+port); - - //Now call the fully qualified constructor with the defaul timeout value - CreateXMLRPCEventSource(sourceParams[0],port,DEFAULT_TIMEOUT); - - } - - /** - * Constructor with server name, port number and timeout - * @param serverName the name or IP-address of the remote server - * @param port the port number to which the request is send - * @param timeout a timeout value in milliseconds - * @throws InvalidEventSourceException - */ - public AXMLRPCEventSource(String serverName, int port, int timeout) - throws InvalidEventSourceException { - //Call common constructor entry - CreateXMLRPCEventSource(serverName,port,timeout); - } - - /** - * @return a string of the form xmlrpc://servername:port - */ - public String getSourceName() { - return "xmlrpc://"+remoteMachineName+":"+portNumber; - } - - /** - * @param mode event navigation mode - * @return true if the requested mode is supported by this source - */ - public boolean supportsNavigationMode(NavigationMode mode) { - if(mode == NavigationMode.SEQUENTIAL) - return true; - return false; - } - - /** - * Common entry point for all constructors - * @param serverName the name or IP-address of the remote server - * @param port the port number to which the request is send - * @param timeout a timeout value in milliseconds - * @throws InvalidEventSourceException - */ - private void CreateXMLRPCEventSource(String serverName, int port, int timeout) - throws InvalidEventSourceException { - - //Store the input values - remoteMachineName = serverName; - portNumber = port; - timeOut = timeout; - - //try to obtain the name of the local machine - try { - localMachineName = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException ex) { - //Can't get name of local host - String msg = "Unable to obtain local machine name, using \"" - + localMachineName +"\" instead"; - logger.error(msg); - } catch(Exception ex) { - //Rethrow everything else as invalid source exception - throw new InvalidEventSourceException("Exception trying to obtain local machine name",ex); - } - - //Finally create a new AClientXMLRPC object - XMLRPCClient = new AClientXMLRPC(GETEVENTDATA); - - } - - /** - * Read the next event from the server - * @param currentEvent the current event - * @return the next event - * @throws NoMoreEventsException - * @throws InvalidEventSourceException - * @throws ReadEventException - */ - @Override - protected AEvent readNext(AEventInfo currentEvent) throws NoMoreEventsException, - InvalidEventSourceException, - ReadEventException { - //Be verbose - logger.info("Call to remote server xmlrpc://" + remoteMachineName + ":" + portNumber.toString()); - - //send the name of the local machine to the JiveXML server - Vector<String> parameters = new Vector(); - parameters.add(localMachineName); - - //record calling time - long startTime = System.currentTimeMillis(); - - //The XMLRPC client will return data as a string - String eventXMLData = null; - - // perform the remote call - try { - eventXMLData = XMLRPCClient.callXMLRPCServer("http://"+remoteMachineName, portNumber, parameters); - } catch (ARemoteCallerException ex) { - //An error occured - String msg = "readNext(): Exception while calling remote server"; - logger.error(msg,ex); - //rethrow - throw new InvalidEventSourceException(msg, ex); - } - - //do some statistics - long callDuration = System.currentTimeMillis() - startTime; - logger.debug("Received " + eventXMLData.length() + " bytes in " + callDuration + " ms"); - - - //If there is just no new event, we should get back an empty string - if (eventXMLData.length() == 0) { - throw new NoMoreEventsException("No event available from the server (yet)"); // something was received, going to process the result - } - if (!(eventXMLData.startsWith("<?xml"))) { - String msg = "Invalid event data received from JiveXML server"; - logger.error(msg); - throw new ReadEventException(msg); - } - - - - //So it seems we got something worth processing - logger.info("Received data from remote server, going to process it ..."); - - // Wrap the string as an inputstream - ByteArrayInputStream bais = new ByteArrayInputStream(eventXMLData.getBytes()); - - //Construct a new event - AEvent event = AEventFromXML.read(bais, remoteMachineName+":"+portNumber); - - /** - * The XMLRPC server is not clever enough to return no event if there is no - * new one. In order to avoid filling the buffer with identical events, we - * therefore check here if we don't already have that event, and throw a - * NoMoreEventsException in case we do. - */ - if (event.equals(currentEvent)){ - String msg = "Already have event "+event.getEventNumber()+" in run " - + event.getRunNumber() + " - ignored!"; - throw new NoMoreEventsException(msg); - } - - - //Now we are sure we have a next event, return it - return event; - - } - -/** - * Requesting to read the previous event from the server only appears - * if we have already reached the beginning of the event buffer. - * Only one current events are provided by the server at any time, thus we - * will always throw a NoMoreEventsException. Handling of the exception is left - * to the GUI interface, and may e.g be ignored in loop mode. - * @param currentEvent will be ignored - * @return nothing as it will always raise an exception - * @throws NoMoreEventsException - */ - @Override - protected AEvent readPrevious(AEventInfo currentEvent) throws NoMoreEventsException - { - throw new NoMoreEventsException("XMLRPC server does not provide a previous event"); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AAtlasDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AAtlasDetector.java deleted file mode 100755 index bf8b9a267fb..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AAtlasDetector.java +++ /dev/null @@ -1,119 +0,0 @@ -package atlantis.geometry; - -import java.util.regex.Pattern; - -import atlantis.config.ADefaultValues; -import atlantis.utils.ALogger; - - -/** - * AAtlasDetector - * contains one instance of - * ABoxDetectors (which contains all instances of ABoxDetector) (MDT,RPC in barrel) - * ATrapezoidDetectors (which contains all instances of ATrapezoidDetector) (MDT,TGC endcap) - * AGeneralDetectors (which contains all instances of AGeneralPathDetector, - * ADiscDetector, ARectangleDetector) (all others) - */ -public class AAtlasDetector extends ADetectorSystem -{ - private static ALogger logger = ALogger.getLogger(AAtlasDetector.class); - private static ADetectorSystem theDetector; - - public AAtlasDetector(String geomIdCalo) - { - super(new ADetectors[] - { - new AGeneralDetectors( - new AGeometryFromXMLReader().readDetectorGeometryFromXML(geomIdCalo)) - }); - - logger.info("Using geometry file: " + geomIdCalo); - - setGeometryName(geomIdCalo); - - } // AAtlasDetector(String fileName) ------------------------------------ - - - - public AAtlasDetector(String geomIdCalo, String geomMuon) - { - super(new ADetectors[] - { - new ABoxDetectors( - new AGeometryFromXMLReader().readDetectorGeometryFromXML(geomMuon)), - new ATrapezoidDetectors( - new AGeometryFromXMLReader().readDetectorGeometryFromXML(geomMuon)), - new AGeneralDetectors( - new AGeometryFromXMLReader().readDetectorGeometryFromXML(geomMuon)), - new AGeneralDetectors( - new AGeometryFromXMLReader().readDetectorGeometryFromXML(geomIdCalo)) - }); - - logger.info("Using geometry file: " + geomIdCalo); - logger.info("Using geometry file: " + geomMuon); - - setGeometryName(geomIdCalo); - - } // AAtlasDetector(String fileName, String muFileName) ----------------- - - - - private static void setGeometryName(String absFileName) - { - // default geometry file, shall always be AGeometry.xml - // arbitrary, named geometry file, geometry name after '_' character - // (but there is also AGeometryTB.xml) - String name = "AGeometry"; - String ext = ".xml"; - String pattern = ".*" + name + "_?.*" + ext; - - if(Pattern.compile(pattern).matcher(absFileName).matches()) - { - int s = absFileName.lastIndexOf(name); - int e = absFileName.lastIndexOf(ext); - String r = absFileName.substring(s + name.length(), e); - if(r.startsWith("_")) - { - // arbitrary, named geometry - geometryName = r.substring(1); // without leading _ - ADefaultValues.set("GeometryName", geometryName); - } - else if("".equals(r)) - { - // default geometry (no name given: "") - geometryName = "<default>"; - ADefaultValues.set("GeometryName", ""); - } - else - { - geometryName = r; - ADefaultValues.set("GeometryName", geometryName); - } - } - else - { - logger.warn("Geometry name not matching regular expression: " + - pattern + "\n geometry name will be: n/a"); - geometryName = "n/a"; - } - - } // setGeometryName() -------------------------------------------------- - - - /** - * @return the detector - */ - public static ADetectorSystem getDetector() { - return theDetector; - } - - - /** - * @param theDetector the ATLAS detector geometry to be used - */ - public static void setDetector(ADetectorSystem theDetector) { - AAtlasDetector.theDetector = theDetector; - } - - -} // class class AAtlasDetector ============================================= diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelCalorimeterDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ABarrelCalorimeterDetector.java deleted file mode 100755 index 870a7d46f7e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelCalorimeterDetector.java +++ /dev/null @@ -1,284 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.graphics.AClipper; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AMath; - -/** - * Class representing a calorimeter part in the barrel section of ATLAS. - * - * @author Eric Jansen - */ -public class ABarrelCalorimeterDetector extends ACalorimeterDetector { - - /** - * Constructs a new barrel calorimeter object. - * @param name String name of the object - * @param color String name of the color used to draw this object - * @param sampling int sampling of this calorimeter part - * @param region int region of this calorimeter part - * @param rMin double inner radius - * @param rMax double outer radius - * @param zMin double inner z - * @param zMax double outer z - * @param eta0 double start of the first cell in eta - * @param deta double size of a cell in eta - * @param neta int number of cells in eta - * @param meta int eta index of the first cell - * @param phi0 double start of the first cell in phi - * @param nphi int number of cells in phi - */ - public ABarrelCalorimeterDetector(String name, String color, int sampling, int region, - double rMin, double rMax, double zMin, double zMax, - double eta0, double deta, int neta, int meta, - double phi0, int nphi) { - super(name, color); - - // Just to be sure we take absolute values here. - this.sampling = Math.abs(sampling); - this.region = Math.abs(region); - - this.rMin = rMin; - this.rMax = rMax; - this.zMin = zMin; - this.zMax = zMax; - this.eta0 = eta0; - this.deltaEta = deta; - this.numEta = neta; - this.minEta = meta; - this.phi0 = Math.toRadians(phi0); - this.numPhi = nphi; - this.deltaPhi = 2.*Math.PI/numPhi; - - this.detEtaMin = AMath.etaAbs(this.zMax, this.rMax); - this.detEtaMax = AMath.etaAbs(this.zMin, this.rMin); - - if (this.eta0 <= 0.0) { - this.zMin = -this.zMax; - this.detEtaMin = -this.detEtaMax; - } - - // This one is used for clipping the cell geometry in rho-z. - this.clipper = new AClipper(this.zMin, this.zMax, this.rMin, this.rMax); - - // These arrays are used by the getDetectorIndex() method in ACalorimeterData. - // They provide fast mapping of hits to detectors. - if (this.name.indexOf("LAr") >= 0 && this.sampling < lar[1].length - && this.region < lar[1][this.sampling].length) { - - lar[1][this.sampling][this.region] = detectors.indexOf(this); - } else if (this.name.equals("TILE Barrel") && this.sampling < tile.length) { - tile[this.sampling] = detectors.indexOf(this); - - } else if (this.name.equals("Extended TILE") && this.sampling < tile_ext.length) { - tile_ext[this.sampling] = detectors.indexOf(this); - - } else { - System.out.println("Unknown calorimeter object: '" + this.name + "'" - + " some hits might not be displayed correctly."); - } - } - - /** - * Returns the y-x geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getYXUser() { - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - for (int i = 0; i < numPhi + 1; i++) { - hv[0][i] = rMin * Math.cos(phi0 + i * deltaPhi); - hv[1][i] = rMin * Math.sin(phi0 + i * deltaPhi); - hv[0][numPhi + 1 + i] = rMax * Math.cos(phi0 - i * deltaPhi); - hv[1][numPhi + 1 + i] = rMax * Math.sin(phi0 - i * deltaPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phi0, rMin, rMax)); - } - } - - /** - * Returns the rho-z geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getRZUser() { - double[] h, v; - - double etaMax = eta0 + numEta * deltaEta; - double etaMin; - if (eta0 <= 0.0) { - etaMin = -etaMax; - } else { - etaMin = eta0; - } - - // Calculate the polygon in the positive h and v. - if (name.indexOf("TILE") >= 0) { - h = new double[] {zMax, zMin, zMin, zMax}; - v = new double[] {rMax, rMax, rMin, rMin}; - } else { - double z0 = rMax*Math.sinh(etaMax); - double z1 = rMax*Math.sinh(etaMin); - double z2 = rMin*Math.sinh(etaMin); - double z3 = rMin*Math.sinh(etaMax); - - h = new double[] {z0, z1, z2, z3}; - v = new double[] {rMax, rMax, rMin, rMin}; - } - - // Clip the polygon. - ACoord coord = clipper.clipPolygon(h, v, h.length); - - // Copy it to negative v. - coord = new ACoord(coord, coord.mirrorV()); - if (eta0 > 0.0) { - // If it doesn't continue through h=0, copy it to negative h. - coord = new ACoord(coord, coord.mirrorH()); - } - - return coord; - } - - /** - * Returns the phi-rho geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getFRUser() { - double[][] hv = new double[2][]; - - hv[0] = new double[] {rMin, rMax, rMax, rMin}; - hv[1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the y-x geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getYXCell(int eta, int phi) { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - double[][] hv = new double[2][]; - double phiMin = phi0+phi*deltaPhi; - double phiMax = phiMin+deltaPhi; - - hv[0] = new double[] {rMax*Math.cos(phiMin), rMax*Math.cos(phiMax), - rMin*Math.cos(phiMax), rMin*Math.cos(phiMin)}; - hv[1] = new double[] {rMax*Math.sin(phiMin), rMax*Math.sin(phiMax), - rMin*Math.sin(phiMax), rMin*Math.sin(phiMin)}; - - return new ACoord(hv); - } - - /** - * Returns the rho-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getRZCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - int sign = getRSign(phi); - - if (side != 0) side /= Math.abs(side); - - if (name.indexOf("TILE") >= 0) { - // Outer layer of TILE has eta increments of two. - if (sampling == 2) eta = minEta + (eta-minEta)/2; - - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - - if (name.indexOf("Barrel") >= 0 && sampling == 1) { - double dr = (rMax-rMin); - double r0 = rMin; - double r1 = rMin+dr/2.; - double r2 = rMax; - double z0 = (rMin+dr/4.) * Math.sinh(etaMin); - double z1 = (rMax-dr/4.) * Math.sinh(etaMin); - double z2 = (rMin+dr/4.) * Math.sinh(etaMax); - double z3 = (rMax-dr/4.) * Math.sinh(etaMax); - - if (eta == this.minEta && this.zMin > 0) z0 = z1 = this.zMin; - if (eta == this.minEta + this.numEta - 1) z2 = z3 = this.zMax; - - hv[0] = new double[] {z3, z1, z1, z0, z0, z2, z2, z3}; - hv[1] = new double[] {r2, r2, r1, r1, r0, r0, r1, r1}; - } else { - double zMin = (rMin+rMax)/2. * Math.sinh(etaMin); - double zMax = (rMin+rMax)/2. * Math.sinh(etaMax); - - if (eta == this.minEta && this.zMin > 0)zMin = this.zMin; - if (eta == this.minEta + this.numEta - 1) zMax = this.zMax; - - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {rMax, rMax, rMin, rMin}; - } - } else if (name.indexOf("LAr") >= 0) { - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - - hv[0] = new double[] {rMax*Math.sinh(etaMax), rMax*Math.sinh(etaMin), - rMin*Math.sinh(etaMin), rMin*Math.sinh(etaMax)}; - hv[1] = new double[] {rMax, rMax, rMin, rMin}; - } else { - return ACoord.NO_DATA; - } - - // Clip the cell and send it to the right quadrant. - ACoord coord = clipper.clipPolygon(hv[0], hv[1], hv[0].length); - for (int i=0; i<coord.hv[0][0].length; i++) { - coord.hv[0][0][i] *= side; - coord.hv[1][0][i] *= sign; - } - - return coord; - } - - /** - * Returns the eta-phi geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getVPCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - double phiMin = Math.toDegrees(phi0 + phi*deltaPhi); - double phiMax = phiMin + Math.toDegrees(deltaPhi); - - side /= Math.abs(side); - - hv[0] = new double[] {side*etaMax, side*etaMin, side*etaMin, side*etaMax}; - hv[1] = new double[] { phiMax, phiMax, phiMin, phiMin}; - - return new ACoord(hv); - } - - /** - * Returns the eta value of the center (in eta) of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double eta value - */ - public double getEta(int eta, int side) { - if (side < 0) { - return -getEta(eta, -side); - } else { - if (name.indexOf("TILE") >= 0) { - // Outer layer of TILE has eta increments of two. - if (sampling == 2) eta = minEta + (eta-minEta)/2; - } - - return eta0 + (eta - minEta + 0.5) * deltaEta; - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelSiliconDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ABarrelSiliconDetector.java deleted file mode 100755 index 14e53e77d05..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelSiliconDetector.java +++ /dev/null @@ -1,276 +0,0 @@ -package atlantis.geometry; - -import atlantis.canvas.AWindow; -import atlantis.data.AS3DData; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionYX; -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -/** - * Class representing a pixel/SCT barrel detector part. - * Also implements methods to draw more detailed structure of the detector. - * - * @author Eric Jansen - */ -public class ABarrelSiliconDetector extends ADetector { - - private static List detectors = null; - - protected int layer; - protected double length; - protected double width; - protected double thickness; - protected int numZ; - protected int numPhi; - protected double tilt; - protected double r0; - protected double phi0; - protected double zMin; - protected double zMax; - - protected double deltaPhi; - protected double deltaZ; - protected double rMin; - protected double rMax; - - public ABarrelSiliconDetector(String name, String color, int layer, double length, double width, double thickness, - int numZ, int numPhi, double tilt, double r0, double phi0, double zMin, double zMax) { - super(name, " ", color); - - if (detectors == null) { - detectors = new ArrayList(); - } - detectors.add(this); - - this.layer = layer; - this.length = length; - this.width = width; - this.thickness = thickness; - this.numZ = numZ; - this.numPhi = numPhi; - this.tilt = Math.toRadians(tilt); - this.r0 = r0; - this.phi0 = Math.toRadians(phi0); - this.zMin = zMin; - this.zMax = zMax; - - this.deltaPhi = 2.*Math.PI / this.numPhi; - this.deltaZ = (this.zMax - this.zMin) / this.numZ; - - // We do not take thickness/2 and width/2 to have some extra margin - this.rMin = this.r0 - Math.abs(this.thickness*Math.cos(this.tilt)) - - Math.abs(this.width*Math.sin(this.tilt)); - this.rMax = this.r0 + Math.abs(this.thickness*Math.cos(this.tilt)) - + Math.abs(this.width*Math.sin(this.tilt)); - } - - /** - * Empties the list of instances of this class. - */ - public static void clear() { - if (detectors != null) { - detectors.clear(); - } - } - - /** - * This function draws the wafer/stave structure of the silicon detectors. It is called - * from ADetectorSystem.draw(). - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - public static void drawAdditionalItems(AWindow window, AGraphics ag, AProjection2D projection) { - AParameter inDetDetail = parameterStore.getUnknown("Det", "SiliconDetail"); - if (inDetDetail != null && detectors != null && inDetDetail.getStatus()) { - for (int i=0; i<detectors.size(); i++) { - ACoord coord = ACoord.NO_DATA; - ABarrelSiliconDetector detector = (ABarrelSiliconDetector) detectors.get(i); - if (projection instanceof AProjectionYX) { - coord = detector.getYXDetail(); - } else if (projection instanceof AProjectionRZ) { - coord = detector.getRZDetail(); - } else if (projection instanceof AProjectionFZ) { - coord = detector.getFZDetail(); - } else if (projection instanceof AProjectionFR) { - coord = detector.getYXDetail().convertYXToFR().includePhiWrapAround("FR"); - } - - if (coord != ACoord.NO_DATA) { - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "SiliconDetail").getI()]); - - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - for (int j=0; j<display.hv[0].length; j++) { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - } - - /** - * Determines if this element should be visible or not. - * @return visibility - */ - protected boolean isVisible() { - int cut = parameterStore.get("CutsInDet", "SCT").getI(); - - if (cut == AS3DData.CUT_INDET_SCT_ALL || cut == AS3DData.CUT_INDET_SCT_BARREL) { - return true; - } else { - return false; - } - } - - /** - * Returns the detector outline in the y-x projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getYXUser() { - if (!isVisible()) { - return ACoord.NO_DATA; - } - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) { - return ACoord.NO_DATA; - } - - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - - for (int i = 0; i < numPhi + 1; i++) { - hv[0][i] = rMin * Math.cos(phi0 + (i + 0.5) * deltaPhi); - hv[1][i] = rMin * Math.sin(phi0 + (i + 0.5) * deltaPhi); - - hv[0][numPhi + 1 + i] = rMax * Math.cos(phi0 - (i + 0.5) * deltaPhi); - hv[1][numPhi + 1 + i] = rMax * Math.sin(phi0 - (i + 0.5) * deltaPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phi0, rMin, rMax)); - } - } - - /** - * Returns the detector outline in the rho-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getRZUser() { - //if (!isVisible()) return ACoord.NO_DATA; - - double[][][] hv = new double[2][2][]; - - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFZUser() { - if (!isVisible()) return ACoord.NO_DATA; - - double[][] hv = new double[2][]; - - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-rho projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFRUser() { - if (!isVisible()) return ACoord.NO_DATA; - - double[][] hv = new double[2][]; - - hv[0] = new double[] {rMin, rMax, rMax, rMin}; - hv[1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the wafer/stave structure in the y-x projection. - * @return ACoord polygons representing the wafers/staves - */ - protected ACoord getYXDetail() { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - if (!isVisible()) return ACoord.NO_DATA; - - double[][][] hv = new double[2][numPhi][]; - for (int i=0; i<numPhi; i++) { - double phi = phi0 + i*deltaPhi; - - double x1 = r0*Math.cos(phi) + width/2.*Math.sin(phi+tilt) + thickness/2.*Math.cos(phi+tilt); - double x2 = r0*Math.cos(phi) - width/2.*Math.sin(phi+tilt) + thickness/2.*Math.cos(phi+tilt); - double x3 = r0*Math.cos(phi) - width/2.*Math.sin(phi+tilt) - thickness/2.*Math.cos(phi+tilt); - double x4 = r0*Math.cos(phi) + width/2.*Math.sin(phi+tilt) - thickness/2.*Math.cos(phi+tilt); - - double y1 = r0*Math.sin(phi) - width/2.*Math.cos(phi+tilt) + thickness/2.*Math.sin(phi+tilt); - double y2 = r0*Math.sin(phi) + width/2.*Math.cos(phi+tilt) + thickness/2.*Math.sin(phi+tilt); - double y3 = r0*Math.sin(phi) + width/2.*Math.cos(phi+tilt) - thickness/2.*Math.sin(phi+tilt); - double y4 = r0*Math.sin(phi) - width/2.*Math.cos(phi+tilt) - thickness/2.*Math.sin(phi+tilt); - - hv[0][i] = new double[] {x1, x2, x3, x4}; - hv[1][i] = new double[] {y1, y2, y3, y4}; - } - return new ACoord(hv); - } - - /** - * Returns the wafer/stave structure in the rho-z projection. - * @return ACoord polygons representing the wafers/staves - */ - protected ACoord getRZDetail() { - // if (!isVisible()) return ACoord.NO_DATA; - - double[][][] hv = new double[2][2*numZ][]; - - for (int i=0; i<numZ; i++) { - hv[0][i] = new double[] {zMin+(i+1)*deltaZ, zMin+i*deltaZ, zMin+i*deltaZ, zMin+(i+1)*deltaZ}; - hv[1][i] = new double[] {rMax, rMax, rMin, rMin}; - - hv[0][numZ+i] = new double[] {zMin+(i+1)*deltaZ, zMin+i*deltaZ, zMin+i*deltaZ, zMin+(i+1)*deltaZ}; - hv[1][numZ+i] = new double[] {-rMin, -rMin, -rMax, -rMax}; - } - return new ACoord(hv); - } - - /** - * Returns the wafer/stave structure in the phi-z projection. - * @return ACoord polygons representing the wafers/staves - */ - protected ACoord getFZDetail() { - if (!isVisible()) return ACoord.NO_DATA; - - // Phi geometry is a mess, draw only the staves in this projection. - double[][][] hv = new double[2][numZ+1][2]; - for (int i=0; i<=numZ; i++) { - hv[0][i][0] = zMin + i*deltaZ; - hv[1][i][0] = 360.; - hv[0][i][1] = zMin + i*deltaZ; - hv[1][i][1] = 0.; - } - - return new ACoord(hv).includePhiWrapAround("FZ"); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelTRTDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ABarrelTRTDetector.java deleted file mode 100755 index 8ccd0a79528..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ABarrelTRTDetector.java +++ /dev/null @@ -1,184 +0,0 @@ -package atlantis.geometry; - -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionYX; -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -/** - * Class representing a TRT barrel detector part. - * Also implements methods to draw more detailed structure of the detector. - * - * @author Eric Jansen - */ -public class ABarrelTRTDetector extends ADetector { - - private static List detectors = null; - - protected int layer; - protected int numPhi; - protected double rMin; - protected double rMax; - protected double phiIn; - protected double phiOut; - protected double zMin; - protected double zMax; - protected double deltaPhi; - - public ABarrelTRTDetector(String name, String color, int layer, int numPhi, double rMin, double rMax, - double phiIn, double phiOut, double zMin, double zMax) { - super(name, " ", color); - - if (detectors == null) { - detectors = new ArrayList(); - } - detectors.add(this); - - this.layer = layer; - this.numPhi = numPhi; - this.rMin = rMin; - this.rMax = rMax; - this.phiIn = Math.toRadians(phiIn); - this.phiOut = Math.toRadians(phiOut); - this.zMin = zMin; - this.zMax = zMax; - - this.deltaPhi = 2.*Math.PI / numPhi; - } - - /** - * Empties the list of instances of this class. - */ - public static void clear() { - if (detectors != null) { - detectors.clear(); - } - } - - /** - * This function draws the module structure of the TRT detector. It is called - * from ADetectorSystem.draw(). - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - public static void drawAdditionalItems(AWindow window, AGraphics ag, AProjection2D projection) { - AParameter inDetDetail = parameterStore.getUnknown("Det", "TRTDetail"); - if (inDetDetail != null && detectors != null && inDetDetail.getStatus()) { - for (int i=0; i<detectors.size(); i++) { - ACoord coord = ACoord.NO_DATA; - ABarrelTRTDetector detector = (ABarrelTRTDetector) detectors.get(i); - if (projection instanceof AProjectionYX) { - coord = detector.getYXDetail(); - } else if (projection instanceof AProjectionFR) { - coord = detector.getYXDetail().convertYXToFR().includePhiWrapAround("FR"); - } - - if (coord != ACoord.NO_DATA) { - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "TRTDetail").getI()]); - - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - for (int j=0; j<display.hv[0].length; j++) { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - } - - /** - * Returns the detector outline in the y-x projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getYXUser() { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - - for (int i = 0; i < numPhi + 1; i++) { - hv[0][i] = rMin * Math.cos(phiIn + i * deltaPhi); - hv[1][i] = rMin * Math.sin(phiIn + i * deltaPhi); - - hv[0][numPhi + 1 + i] = rMax * Math.cos(phiOut - i * deltaPhi); - hv[1][numPhi + 1 + i] = rMax * Math.sin(phiOut - i * deltaPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phiIn, rMin, rMax)); - } - } - - /** - * Returns the detector outline in the rho-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getRZUser() { - double[][][] hv = new double[2][2][]; - - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFZUser() { - return ACoord.NO_DATA; - } - - /** - * Returns the detector outline in the phi-rho projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFRUser() { - double[][] hv = new double[2][]; - - hv[0] = new double[] {rMin, rMax, rMax, rMin}; - hv[1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the module structure in the y-x projection. - * @return ACoord polygons representing the modules - */ - protected ACoord getYXDetail() { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - - double[][][] hv = new double[2][numPhi][]; - for (int i=0; i<numPhi; i++) { - double phiMin = i*deltaPhi; - double phiMax = (i+1)*deltaPhi; - - double x1 = rMax*Math.cos(phiMin+phiOut); - double x2 = rMax*Math.cos(phiMax+phiOut); - double x3 = rMin*Math.cos(phiMax+phiIn); - double x4 = rMin*Math.cos(phiMin+phiIn); - - double y1 = rMax*Math.sin(phiMin+phiOut); - double y2 = rMax*Math.sin(phiMax+phiOut); - double y3 = rMin*Math.sin(phiMax+phiIn); - double y4 = rMin*Math.sin(phiMin+phiIn); - - hv[0][i] = new double[] {x1, x2, x3, x4}; - hv[1][i] = new double[] {y1, y2, y3, y4}; - } - return new ACoord(hv); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetector.java deleted file mode 100755 index 68fda4c768e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetector.java +++ /dev/null @@ -1,172 +0,0 @@ -package atlantis.geometry; - -import atlantis.utils.AMath; -import atlantis.parameters.*; -import atlantis.graphics.ACoord; - -/** - * in ATLAS boxes are RPC and MDT in the barrel - */ - -public class ABoxDetector extends ADetector { - - double zMin; - double zMax; - double rMin; - double rMax; - double phi; - double excl; - double size; - String stationName; - int stationEta; - int stationPhi; - int sector; - - public ABoxDetector(String name, double zMin, double zMax, double rMin, - double rMax, double phi, double excl, double size, int stationEta, int stationPhi) { - super(name, " ", name.substring(0, 3)); - this.zMin=zMin; - this.zMax=zMax; - this.rMin=rMin; - this.rMax=rMax; - this.phi=phi; - this.excl=excl; - this.size=size; - this.stationName=name.substring(4, 7); - this.stationEta=stationEta; - this.stationPhi=stationPhi; - this.sector=((int)((phi+Math.PI/16)/(Math.PI/8)))%16; - } - - protected ACoord getFZUser() { - double cosPhi=Math.cos(phi); - double sinPhi=Math.sin(phi); - double d=size/2.; - double r=rMin; - double x=r*cosPhi-excl*sinPhi; - double y=r*sinPhi+excl*cosPhi; - double dsinPhi=d*sinPhi; - double dcosPhi=d*cosPhi; - double phi1=Math.toDegrees(Math.atan2(y-dcosPhi, x+dsinPhi)); - double phi2=Math.toDegrees(Math.atan2(y+dcosPhi, x-dsinPhi)); - - if(phi1<0.) phi1+=360.; - if(phi2<0.) phi2+=360.; - if(phi1-phi2>180.) phi1-=360.; - if(phi2-phi1>180.) phi2-=360.; - - return new ACoord(AMath.xBox((zMin+zMax)/2.,(zMax-zMin)/2.), - AMath.yBox((phi1+phi2)/2.,(phi1-phi2)/2.)); - } - - protected ACoord getRZUser() { - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff=Math.abs(phi-phiMid); - double sign=-1.; - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - sign=+1.; - return getXZRZUser(sign); - } - - protected ACoord getXZUser() { - AParameter p=parameterStore.get("XZ", "Phi"); - - // display muon data when phi is in the middle of a sector - if(p.getD() % 22.5 < 1e-2) { - int sect=(int)Math.round((p.getD() % 360.) / 22.5); - if(sector==sect) { - return getXZRZUser(1.); - } else if(sector==sect-8||sector==sect+8) { - return getXZRZUser(-1.); - } - } - return ACoord.NO_DATA; - } - - protected ACoord getXZRZUser(double sign) { - return new ACoord( - AMath.xBox( (zMin + zMax) / 2., (zMax - zMin) / 2.), - AMath.yBox( sign*(rMin + rMax) / 2., sign*(rMax - rMin) / 2.)); - } - - - protected ACoord getYXUser() { - return getYXUser(0); - } - - protected ACoord getFRUser() { - return convertYXToFR(getYXUser(1)); - } - - private ACoord getYXUser(int flag) { - int[] split= {12, 1, 12, 1}; - int numPoints=4; - boolean splitIt=parameterStore.get("YX", "FishEye").getStatus()||parameterStore.get("YX", "Clock").getStatus() - ||flag==1; - - if(splitIt) - numPoints=26; - double[] temp=new double[4]; - double[][] hv=new double[2][numPoints]; - double cosPhi=Math.cos(phi); - double sinPhi=Math.sin(phi); - double d=size/2.; - double r=rMin; - double x=r*cosPhi-excl*sinPhi; - double y=r*sinPhi+excl*cosPhi; - double dx=d*sinPhi; - double dy=d*cosPhi; - - hv[0][0]=x+dx; - hv[1][0]=y-dy; - hv[0][1]=x-dx; - hv[1][1]=y+dy; - r=rMax; - x=r*cosPhi-excl*sinPhi; - y=r*sinPhi+excl*cosPhi; - - hv[0][3]=x+dx; - hv[1][3]=y-dy; - hv[0][2]=x-dx; - hv[1][2]=y+dy; - if(splitIt) - for(int j=0; j<2; ++j) { - for(int k=0; k<4; ++k) - temp[k]=hv[j][k]; - AMath.splitArrayIntoPieces(temp, hv[j], split); - } - return new ACoord(hv); - } - - protected boolean equalsYX(ADetector o) { - if (o instanceof ABoxDetector) { - ABoxDetector that = (ABoxDetector) o; - return this.rMin == that.rMin && - this.rMax == that.rMax && - this.phi == that.phi && - this.size == that.size && - this.excl == that.excl; - } else - return false; - } - - protected boolean equalsRZ(ADetector o) { - if (o instanceof ABoxDetector) { - ABoxDetector that = (ABoxDetector) o; - return this.rMin == that.rMin && - this.rMax == that.rMax && - this.zMin == that.zMin && - this.zMax == that.zMax; - } else - return false; - } - - public double getZMin() { return zMin; } - public double getZMax() { return zMax; } - public double getRMin() { return rMin; } - public double getRMax() { return rMax; } - public double getPhi() { return phi; } - public double getSize() { return size; } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetectors.java b/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetectors.java deleted file mode 100755 index a4b10b15070..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ABoxDetectors.java +++ /dev/null @@ -1,168 +0,0 @@ -package atlantis.geometry; - -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import java.util.*; - - -/** - * ABoxDetector's contains all instances of ABoxDetector. - * In different projections not all Boxes need to be drawn - * as they may exactly overlap. Filling of these areas is - * slow, so only the Boxes needed are drawn in each projection. - * (That is why boxes are group into ABoxDetectors) - * This is achieved by making a drawlist before drawing. - */ -public final class ABoxDetectors extends ADetectors { - - private int numRZTypes; - private int[] typeRZ; - private int numYXTypes; - private int[] typeYX; - - private ABoxDetector[] box; - - public ABoxDetectors(List detectors) { - super(filterBoxDetectors(detectors)); - box= new ABoxDetector[det.length]; - for(int i=0;i<box.length;++i) - box[i]=(ABoxDetector)det[i]; - - typeYX=new int[numData]; - for(int i=0; i<numData; ++i) - typeYX[i]=-1; - - numYXTypes=0; - for(int i=0; i<numData; ++i) - if(typeYX[i]==-1) { - typeYX[i]=numYXTypes; - for(int j=i+1; j<numData; ++j) - if(typeYX[j]==-1&&det[i].equalsYX(det[j])) - typeYX[j]=numYXTypes; - numYXTypes++; - } - - typeRZ=new int[numData]; - for(int i=0; i<numData; ++i) - typeRZ[i]=-1; - - numRZTypes=0; - for(int i=0; i<numData; ++i) - if(typeRZ[i]==-1) { - typeRZ[i]=numRZTypes; - for(int j=i+1; j<numData; ++j) - if(typeRZ[j]==-1&&det[i].equalsRZ(det[j])) - typeRZ[j]=numRZTypes; - numRZTypes++; - } - } - - private static ADetector[] filterBoxDetectors(List detectors) { - - List tempDetectors=new ArrayList(detectors.size()); - Iterator it=detectors.iterator(); - - while(it.hasNext()) { - Object o=it.next(); - if(o instanceof ABoxDetector || o instanceof ATBxDetector) tempDetectors.add(o); - } - return (ADetector[])tempDetectors.toArray(new ADetector[tempDetectors.size()]); - } - - private void makeDrawListYX() { - int mode=parameterStore.get("YX", "Mode").getI(); - - if(mode==0) { - numDraw=numYXTypes; - for(int i=0; i<numData; ++i) - listdl[typeYX[i]]=i; - } else - numDraw=0; - } - - private void makeDrawListXZ() { - AParameter p=parameterStore.get("XZ", "Phi"); - - // display muon data when phi is in the middle of a sector - if(p.getD() % 22.5 < 1e-2) { - int sect=(int)Math.round((p.getD() % 360.) / 22.5); - int num=0; - for(int i=0; i<numData; i++) { - int s=box[i].sector; - if(s==sect||s==sect-8||s==sect+8) { - listdl[num++]=i; - } - } - numDraw=num; - } else { - numDraw=0; - } - } - - private void makeDrawListRZ() { - // first make the draw list - // for each type find out if it has both +ve and negative sign - int[] pos=new int[typeRZ.length]; - int[] neg=new int[typeRZ.length]; - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for(int i=0; i<numRZTypes; ++i) - neg[i]=pos[i]=-1; - - for(int i=0; i<numData; ++i) { - double phiDiff=Math.abs(box[i].phi-phiMid); - - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - pos[typeRZ[i]]=i; - else - neg[typeRZ[i]]=i; - } - - int num=0; - for(int i=0; i<numRZTypes; ++i) { - if(pos[i]!=-1) - listdl[num++]=pos[i]; - if(neg[i]!=-1) - listdl[num++]=neg[i]; - } - numDraw=num; - } - - private void makeDrawListFZ() { - int mode=parameterStore.get("FZ", "Mode").getI(); - - if(mode==0) - numDraw=0; - else { - int num=0; - - for(int i=0; i<numData; ++i) { - char type=det[i].getName().charAt(0); - char station=det[i].getName().charAt(5); - char io=det[i].getName().charAt(det[i].getName().length()-1); - - if((mode==1&&station=='M'&&io=='I'&&type=='R')||(mode==2&&station=='M'&&io=='O'&&type=='R') - ||(mode==3&&station=='O'&&type=='R')||(mode==4&&(station=='I'||station=='E')&&type=='M') - ||(mode==5&&station=='M'&&type=='M')||(mode==6&&station=='O'&&type=='M')) - listdl[num++]=i; - numDraw=num; - } - } - } - - protected void makeDrawList(String projection) { - if (projection.equals("YX") || projection.equals("FR") ) - makeDrawListYX(); - else if (projection.equals("FZ")) - makeDrawListFZ(); - else if (projection.equals("RZ")) - makeDrawListRZ(); - else if (projection.equals("XZ")) - makeDrawListXZ(); - else - numDraw=0; - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ACalorimeterDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ACalorimeterDetector.java deleted file mode 100755 index da80146936d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ACalorimeterDetector.java +++ /dev/null @@ -1,699 +0,0 @@ -package atlantis.geometry; - -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AClipper; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AIdHelper; -import atlantis.utils.AMath; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionYX; -import java.awt.Color; -import java.util.List; -import java.util.ArrayList; - -/** - * Abstract class representing a region of a certain sampling of a ATLAS - * calorimeter. Based on the parameters given to the constructor, the - * derived classes should be able to calculate the geometrical properties - * of the cells they contain. This behavior is required for drawing the data. - * - * @author Eric Jansen - */ -abstract public class ACalorimeterDetector extends ADetector { - - // Keep a static list of instances for easy access - protected static List detectors = null; - - // These arrays are used for fast cell to detector mapping. - protected static int[][][] lar = null; - protected static int[][] hec = null; - protected static int[] tile = null; - protected static int[] tile_ext = null; - protected static int[][] tile_gap = null; - protected static int[] mbts = null; - - protected int sampling; - protected int region; - protected double rMin; - protected double rMax; - protected double zMin; - protected double zMax; - protected double phi0; - protected int numPhi; - protected double deltaPhi; - protected double eta0; - protected double deltaEta; - protected int numEta; - protected int minEta; - - protected double detEtaMin; - protected double detEtaMax; - protected AClipper clipper; - - /** - * Constructs a new calorimeter object. - * @param name String name of the object - * @param color String name of the color used to draw this object - */ - public ACalorimeterDetector(String name, String color) { - super(name, " ", color); - - if (detectors == null) { - detectors = new ArrayList(40); - - // These numbers correspond to the maximum number of values that can - // be encoded in the identifier. - lar = new int[4][4][8]; - hec = new int[4][2]; - tile = new int[16]; - tile_ext = new int[16]; - tile_gap = new int[16][64]; - mbts = new int[2]; - - // Initialize them to -1, which means no detector element known. - for (int i=0; i<lar.length; i++) - for (int j=0; j<lar[i].length; j++) - for (int k=0; k<lar[i][j].length; k++) - lar[i][j][k] = -1; - - for (int i=0; i<hec.length; i++) - for (int j=0; j<hec[i].length; j++) - hec[i][j] = -1; - - for (int i=0; i<tile.length; i++) - tile[i] = -1; - - for (int i=0; i<tile_ext.length; i++) - tile_ext[i] = -1; - - for (int i=0; i<tile_gap.length; i++) - for (int j=0; j<tile_gap[i].length; j++) - tile_gap[i][j] = -1; - - for (int i=0; i<mbts.length; i++) - mbts[i] = -1; - } - - detectors.add(this); - } - - /** - * Returns one of the instances of this class. - * @param index int index of instance - * @return ACalorimeterDetector instance at the requested index - */ - public static ACalorimeterDetector get(int index) { - return (ACalorimeterDetector) detectors.get(index); - } - - /** - * Shows the number of instances of this class that have been created. - * @return int number of instances - */ - public static int count() { - if (detectors != null) { - return detectors.size(); - } else { - return 0; - } - } - - /** - * This functions maps the calorimeter cells to a geometry object. In principle we could - * compare every cell to every geometry object, but that would be too slow. Therefore we - * organize the geometry in an array structure. - * @param id int identifier of a cell - * @return int index of the geometry object in the detector array - */ - public static int getDetectorIndex(int id) { - if (detectors == null) return -1; - - try { - switch (AIdHelper.subDetector(id)) { - case 4: - switch (AIdHelper.larPart(id)) { - case 1: - // LAr EM - return lar[Math.abs(AIdHelper.larBarrelEndcap(id))] - [AIdHelper.larSampling(id)][AIdHelper.larRegion(id)]; - case 2: - // HEC - return hec[AIdHelper.larSampling(id)][AIdHelper.larRegion(id)]; - case 3: - // FCAL - return -1; - default: - return -1; - } - case 5: - switch (AIdHelper.tileSection(id)) { - case 1: - // TILE barrel - return tile[AIdHelper.tileSampling(id)]; - case 2: - // TILE extended barrel - return tile_ext[AIdHelper.tileSampling(id)]; - case 3: - // ITC gap/crack - return tile_gap[AIdHelper.tileSampling(id)][AIdHelper.tileTower(id)]; - case 4: - // MBTS - return -1; - default: - return -1; - } - default: - return -1; - } - } catch (AAtlantisException e) { - return -1; - } - } - - /** - * Clear the list of instances. This is called before reading another geometry file. - */ - public static void clear() { - if (detectors != null) { - detectors.clear(); - } - detectors = null; - lar = null; - hec = null; - tile = null; - tile_ext = null; - tile_gap = null; - mbts = null; - } - - /** - * Get the outline of a certain cell in a certain projection. - * @param projection AProjection projection - * @param eta int eta index of the cell - * @param phi int phi index of the cell - * @param side int side sign of the z coordinate of the cell - * @return ACoord cell outline - */ - public ACoord getCell(AProjection projection, int eta, int phi, int side) { - if (projection instanceof AProjectionYX) { - return getYXCell(eta, phi); - } else if (projection instanceof AProjectionRZ) { - return getRZCell(eta, phi, side); - } else if (projection instanceof AProjectionFR) { - return getFRCell(eta, phi); - } else if (projection instanceof AProjectionFZ) { - return getFZCell(eta, phi, side); - } else if (projection instanceof AProjectionVP) { - return getVPCell(eta, phi, side); - } else { - return ACoord.NO_DATA; - } - } - - /** - * Returns the y-x geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getYXCell(int eta, int phi) { - return ACoord.NO_DATA; - } - - /** - * Returns the rho-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getRZCell(int eta, int phi, int side) { - return ACoord.NO_DATA; - } - - /** - * Returns the phi-rho geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getFRCell(int eta, int phi) { - return convertYXToFR(getYXCell(eta, phi)); - } - - /** - * Returns the phi-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord - */ - public ACoord getFZCell(int eta, int phi, int side) { - return ACoord.NO_DATA; - } - - /** - * Returns the eta-phi geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getVPCell(int eta, int phi, int side) { - return ACoord.NO_DATA; - } - - /** - * Returns the eta value of the center (in eta) of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double eta value - */ - public double getEta(int eta, int side) { - if (side < 0) { - return -getEta(eta, -side); - } else { - return eta0 + (eta - minEta + 0.5) * deltaEta; - } - } - - /** - * Returns the lowest eta value of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double lowest eta value - */ - public double getEtaMin(int eta, int side) { - if (side < 0) { - return -getEtaMax(eta, -side); - } else { - return eta0 + (eta - minEta) * deltaEta; - } - } - - /** - * Returns the highest eta value of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double highest eta value - */ - public double getEtaMax(int eta, int side) { - if (side < 0) { - return -getEtaMin(eta, -side); - } else { - return eta0 + (eta - minEta + 1) * deltaEta; - } - } - - /** - * Returns the phi value of the center of a cell. - * @param phi int phi index of the cell - * @return double phi value - */ - public double getPhi(int phi) { - return phi0 + (phi + 0.5) * deltaPhi; - } - - /** - * Returns the lowest phi value of a cell. - * @param phi int phi index of the cell - * @return double lowest phi value - */ - public double getPhiMin(int phi) { - return phi0 + phi * deltaPhi; - } - - /** - * Returns the highest phi value of a cell. - * @param phi int phi index of the cell - * @return double highest phi value - */ - public double getPhiMax(int phi) { - return phi0 + (phi + 1) * deltaPhi; - } - - /** - * Determines on which side a certain cell should be drawn in the RZ projection, - * based on the phi angle the user has set in the menu. - * @param phi int phi index of the cell - * @return int 1 or -1, meaning top or bottom repectively - */ - public int getRSign(int phi) { - double cellPhi = phi0 + phi*deltaPhi + deltaPhi/2.; - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(cellPhi-phiMid); - if (phiDiff <= Math.PI/2.|| phiDiff > 3*Math.PI/2.) { - return 1; - } else { - return -1; - } - } - - /** - * Returns the number of cells in phi for this calorimeter part. - * @return int number of cells in phi - */ - public int getNumPhi() { - return numPhi; - } - - /** - * Returns the size of a cell in phi for this calorimeter part (this is the same for all cells). - * @return double size of a cell in radians - */ - public double getDeltaPhi() { - return deltaPhi; - } - - /** - * Returns the number of cells in eta for this calorimeter part. - * @return double number of cells in eta - */ - public int getNumEta() { - return numEta; - } - - /** - * Returns the size of a cell in eta for this calorimeter part (this is the same for all cells). - * @return double size of a cell in eta - */ - public double getDeltaEta() { - return deltaEta; - } - - /** - * Returns the center radius of the calorimeter part. - * @return double center radius - */ - public double getR() { - return (rMin+rMax)/2.; - } - - /** - * Returns the inner radius of the calorimter part. - * @return double inner radius - */ - public double getRMin() { - return rMin; - } - - /** - * Returns the outer radius of the calorimeter part. - * @return double outer radius - */ - public double getRMax() { - return rMax; - } - - /** - * Returns the center z of the calorimeter part. - * @return double center z - */ - public double getZ() { - return (zMin+zMax)/2.f; - } - - /** - * Returns the inner z of the calorimeter part. - * @return double inner z - */ - public double getZMin() { - return zMin; - } - - /** - * Returns the outer z of the calorimter part. - * @return double outer z - */ - public double getZMax() { - return zMax; - } - - /** - * Returns the inner eta of the calorimeter part. - * @return double inner eta - */ - public double getEtaMin() { - return eta0; - } - - /** - * Returns the outer eta of the calorimeter part. - * @return double outer eta - */ - public double getEtaMax() { - return eta0 + numEta*deltaEta; - } - - /** - * Returns the sampling of the calorimeter part. This corresponds to the layers of the calorimeter. - * @return int sampling - */ - public int getSampling() { - return sampling; - } - - /** - * Returns the region of this calorimeter part. Within a layer a new region is started when the - * size of the cells changes. - * @return int region - */ - public int getRegion() { - return region; - } - - /** - * Returns the eta index of the first cell in eta for this calorimeter part. - * @return int eta - */ - public int getFirstEta() { - return minEta; - } - - /** - * Returns the eta index of the last cell in eta for this calorimeter part. - * @return int eta - */ - public int getLastEta() { - if (sampling == 2 && name.indexOf("TILE") >= 0) - return minEta + 2*numEta; - else - return minEta + numEta-1; - } - - /** - * Returns the phi index of the first cell in phi for this calorimeter part. - * @return int phi - */ - public int getFirstPhi() { - // This is always 0, still we provide this method for consistency. - return 0; - } - - /** - * Returns the phi index of the last cell in phi for this calorimeter part. - * @return int phi - */ - public int getLastPhi() { - return numPhi-1; - } - - /** - * This function draws the module structure of the calorimeter. It is called - * from ADetectorSystem.draw(). - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - public static void drawAdditionalItems(AWindow window, AGraphics ag, AProjection2D projection) { - AParameter caloDetail = parameterStore.getUnknown("Det", "CaloDetail"); - if (caloDetail != null && detectors != null && caloDetail.getStatus()) - { - for (int i=0; i<detectors.size(); i++) - { - ACalorimeterDetector detector = (ACalorimeterDetector) detectors.get(i); - - // Only draw region 0 in YX, not the few different cells at the ends - if ((projection instanceof AProjectionYX && detector.getRegion() == 0) || projection instanceof AProjectionFR) - { - int start; - int mode = parameterStore.get("YX", "Mode").getI(); - if(mode==AProjectionYX.MODE_STANDARD) - //only needs one eta for standard view - start = detector.getFirstEta(); - else if(mode>=AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && mode <=AProjectionYX.MODE_HEC_4) - //need to loop over eta for endcaps - start = detector.getLastEta(); - else - start=0; - if(mode==AProjectionYX.MODE_STANDARD || (mode>=AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && mode <=AProjectionYX.MODE_HEC_4) || mode==AProjectionYX.MODE_MBTS) - { - for (int eta=start; eta>=detector.getFirstEta(); eta--) - { - for (int phi=detector.getFirstPhi(); phi<=detector.getLastPhi(); phi++) - { - ACoord coord = detector.getCell(projection, eta, phi, 1); - if (coord != ACoord.NO_DATA) { - ACoord display; - if (projection instanceof AProjectionYX) - display = window.calculateDisplay(projection.nonLinearTransform(coord)); - else - display = window.calculateDisplay(projection.nonLinearTransform( - coord.includePhiWrapAround("FR")) - ); - - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "CaloDetail").getI()]); - - for (int j=0; j<display.hv[0].length; j++) - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - else if((mode==AProjectionYX.MODE_LAR_ENDCAP_SUMMED && (detector.getName().equals("LAr Endcap Presampler")||detector.getName().equals("LAr_EC_Presampler"))) - || (mode==AProjectionYX.MODE_HEC_SUMMED && detector.getName().equals("HEC") && detector.getSampling()==0)) - { - //For summed endcaps only need to do this once - //The cells match the bining used but are not specific to the detector - //hence they do not all lie inside the detector - double etaBin=0.1,phiBin=(2*Math.PI/64); - int binvalue; - if(mode==AProjectionYX.MODE_HEC_SUMMED) - { - binvalue = parameterStore.get("YX", "HECBin").getI(); - } - else - { - binvalue = parameterStore.get("YX", "LArBin").getI(); - } - if(binvalue==3) - { - etaBin=0.1; - phiBin=(2*Math.PI/64); - } - else - { - etaBin*=binvalue; - phiBin*=binvalue; - } - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "CaloDetail").getI()]); - double firstZMin=detector.getZMin(); - //check etaSplit is set correct - if(binvalue==3) - { - setEtaSplit(); - } - //loop between values greater and less than the actual size - for(double Eta=1.2; Eta<3.3; Eta+=etaBin) - { - if(binvalue==3 && Eta>=parameterStore.get("YX", "SplitEta").getD()) - { - etaBin=0.2; - phiBin=(2*Math.PI/32); - } - double RMax=firstZMin/Math.sinh(Eta); - double RMin=firstZMin/Math.sinh(Eta+etaBin); - for(double Phi=0.0; Phi<(2*Math.PI); Phi+=phiBin) - { - double[][] hv = new double[2][]; - hv[0] = new double[] {RMax*Math.cos(Phi), RMax*Math.cos(Phi+phiBin), - RMin*Math.cos(Phi+phiBin), RMin*Math.cos(Phi)}; - hv[1] = new double[] {RMax*Math.sin(Phi), RMax*Math.sin(Phi+phiBin), - RMin*Math.sin(Phi+phiBin), RMin*Math.sin(Phi)}; - - ACoord coord = new ACoord(hv); - ACoord display; - - if (projection instanceof AProjectionYX) - display = window.calculateDisplay(projection.nonLinearTransform(coord)); - else - display = window.calculateDisplay(projection.nonLinearTransform( - coord.convertYXToFR().includePhiWrapAround("FR")) - ); - for(int j=0; j<display.hv[0].length; j++) - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - - } - else if (projection instanceof AProjectionRZ) - { - for (int eta=detector.getFirstEta(); eta<=detector.getLastEta(); eta++) - { - - for (int phi=detector.getFirstPhi(); - phi<=detector.getFirstPhi()+detector.getNumPhi()/2; - phi+=detector.getNumPhi()/2) - { - - for (int side=-1; side<=1; side+=2) { - ACoord coord = detector.getCell(projection, eta, phi, side); - - if (coord != ACoord.NO_DATA) - { - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "CaloDetail").getI()]); - ag.drawPolygon(display.hv[0][0], display.hv[1][0], display.hv[0][0].length); - } - } - } - } - } - else if (projection instanceof AProjectionFZ) - { - int eta = detector.getFirstEta(); - - for (int phi=detector.getFirstPhi(); phi<=detector.getLastPhi(); phi++) - { - for (int side=-1; side<=1; side+=2) - { - ACoord coord = detector.getCell(projection, eta, phi, side).includePhiWrapAround("FZ"); - - if (coord != ACoord.NO_DATA) - { - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "CaloDetail").getI()]); - - for (int j=0; j<display.hv[0].length; j++) - { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - } - } - } - } - - /** - * This function sets the value of EtaSplit to a minimum of 1.2 and - * to an accuracy of 1 decimal place - * 1.2 is minimum as is minimum of where cells outline is drawn - */ - public static void setEtaSplit() { - if(parameterStore.get("YX", "SplitEta").getD()<1.2) - parameterStore.get("YX", "SplitEta").setD(1.2); - else - { - int temp=(int) Math.floor(parameterStore.get("YX", "SplitEta").getD()*10.0); - parameterStore.get("YX", "SplitEta").setD(temp/10.0); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ADetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ADetector.java deleted file mode 100755 index b7196bfe34a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ADetector.java +++ /dev/null @@ -1,157 +0,0 @@ -package atlantis.geometry; - -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; - -/** - * Base class of all individual detectors - */ - -public abstract class ADetector { - - String name; - String projection; - String color; - AParameter fillColorParameter; - - protected static APar parameterStore = APar.instance(); - protected static AGlobals globals = AGlobals.instance(); - - final static protected double[][] NO_DETECTORS=new double[2][0]; - - ADetector(String name, String projection, String color) { - this.name=name; - this.projection=projection; - this.color=color; - fillColorParameter=APar.instance().get("Det", color+"Fill"); - } - - protected ACoord getYXUser() { - return ACoord.NO_DATA; - } - - protected ACoord getRZUser() { - return ACoord.NO_DATA; - } - - protected ACoord getYZUser() { - return ACoord.NO_DATA; - } - - protected ACoord getXZUser() { - return ACoord.NO_DATA; - } - - protected ACoord getFRUser() { - return ACoord.NO_DATA; - } - - protected ACoord getFZUser() { - return ACoord.NO_DATA; - } - - protected ACoord getVPUser() { - return ACoord.NO_DATA; - } - - protected ACoord getUser(String projection) { - if (projection.equals("YX")) - return getYXUser(); - else if (projection.equals("RZ")) - return getRZUser(); - else if (projection.equals("XZ")) - return getXZUser(); - else if (projection.equals("YZ")) - return getYZUser(); - else if (projection.equals("FZ")) - return getFZUser(); - else if (projection.equals("FR")) - return getFRUser(); - else if (projection.equals("VP")) - return getVPUser(); - else - return ACoord.NO_DATA; - } - - public String getName() { - return name; - } - - public int getFillColor() { - return fillColorParameter.getI(); - } - - protected boolean getDraw() { - return fillColorParameter.getStatus(); - } - - protected boolean equalsYX(ADetector that) { - return false; - } - - protected boolean equalsRZ(ADetector that) { - return false; - } - - protected ACoord convertYXToFR(ACoord coord) { - double phiLast=0.; - - for (int i=0; i<coord.hv[0].length; i++) { - for (int j=0; j<coord.hv[0][i].length; j++) { - double xx=coord.hv[0][i][j]; - double yy=coord.hv[1][i][j]; - double rho=Math.sqrt(xx*xx+yy*yy); - double phi=Math.toDegrees(Math.atan2(yy, xx)); - - if(phi<0.) - phi+=360.; - if(j>0) { - if(phi-phiLast>180.) phi-=360.; - if(phi-phiLast<-180.) phi+=360.; - } - coord.hv[0][i][j]=rho; - coord.hv[1][i][j]=phi; - phiLast=phi; - } - } - - return coord; - } - - protected double[][][] generateAnnulusTris(int numPhi, double phi0, - double rMin, double rMax) { - - //rMin *= 1.02; - - int numTris = 2 * (numPhi); - double[][][] hv = new double[2][numTris][3]; - - double deltaPhi = 2. * Math.PI / numPhi; - - for (int i = 0; i < numPhi; i++) { - hv[0][i][0] = rMax * Math.cos(phi0 + i * deltaPhi); - hv[1][i][0] = rMax * Math.sin(phi0 + i * deltaPhi); - - hv[0][i][1] = rMax * Math.cos(phi0 + (i + 1) * deltaPhi); - hv[1][i][1] = rMax * Math.sin(phi0 + (i + 1) * deltaPhi); - - float midi = ((float) i) + 0.5f; - hv[0][i][2] = rMin * Math.cos(phi0 + midi * deltaPhi); - hv[1][i][2] = rMin * Math.sin(phi0 + midi * deltaPhi); - - int offi = i + (numPhi); - hv[0][offi][0] = rMin * Math.cos(phi0 + midi * deltaPhi); - hv[1][offi][0] = rMin * Math.sin(phi0 + midi * deltaPhi); - - hv[0][offi][1] = rMax * Math.cos(phi0 + (i + 1) * deltaPhi); - hv[1][offi][1] = rMax * Math.sin(phi0 + (i + 1) * deltaPhi); - - hv[0][offi][2] = rMin * Math.cos(phi0 + (midi + 1) * deltaPhi); - hv[1][offi][2] = rMin * Math.sin(phi0 + (midi + 1) * deltaPhi); - } - - return hv; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ADetectorSystem.java b/graphics/AtlantisJava/src/atlantis/geometry/ADetectorSystem.java deleted file mode 100755 index e0c93a93856..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ADetectorSystem.java +++ /dev/null @@ -1,122 +0,0 @@ -package atlantis.geometry; - - -import java.awt.*; - -import atlantis.canvas.*; -import atlantis.graphics.*; -import atlantis.graphics.colormap.AColorMap; -import atlantis.gui.*; -import atlantis.parameters.*; -import atlantis.projection.*; - - -public class ADetectorSystem -{ - - private ADetectors[] detectors; - protected static String geometryName = null; - - protected static APar parameterStore = APar.instance(); - - ADetectorSystem(ADetectors[] detectors) - { - this.detectors=detectors; - } - - public ADetectors[] getDetectors() - { - return detectors; - } - - // The whole of atlas is drawn in one loop to avoid problem with frames - // overlapping - - - public void draw(AWindow window, AGraphics ag, AProjection2D projection) - { - if(!parameterStore.get("Det", "Detectors").getStatus()) return; - boolean drawFrames=parameterStore.get("Det", "HideDetectors").getStatus(); - //also draw frames for Grey/BW color maps - boolean colorBW=AColorMap.drawFrames(); - Color[] colorMap=AColorMap.getColors(); - ADetectors[] detectors=getDetectors(); - ACoord[] display=new ACoord[detectors.length]; - int[][] index=new int[detectors.length][]; - int[][] detColor=new int[detectors.length][]; - boolean[][] draw=new boolean[detectors.length][]; - int bkgColor = parameterStore.get("Color","BkgFill").getI(); - - for(int det=0; det<detectors.length; ++det) { - display[det]=window.calculateDisplay(detectors[det].getUser(projection)); - index[det]=display[det].index; - detColor[det]=detectors[det].getColor(index[det]); - draw[det]=detectors[det].getDraw(index[det]); - } - - boolean modeSelection = parameterStore.get(projection.getName(), "Mode").getI()==0 - ||(parameterStore.get(projection.getName(), "Mode").getI()>8 - &&(projection instanceof AProjectionYX||projection instanceof AProjectionFR)); - - for(int layer=0; layer<2; ++layer) - { - for(int det=0; det<detectors.length; ++det) - { - ADrawParameters dp=detectors[det].getDrawParameters(layer, 0); - ag.updateDrawParameters(dp); - for(int i=0; i<display[det].hv[0].length; ++i) - { - int numPoints=display[det].hv[0][i].length; - ag.setColor(colorMap[detColor[det][i]]); - if(draw[det][i]&& numPoints>0) - { - if(modeSelection) - { - if(layer==0 && (drawFrames||colorBW)) - { - if(colorBW) - ag.setColor(colorMap[AColorMap.BK]); - ag.drawPolygon(display[det].hv[0][i], display[det].hv[1][i], numPoints); - } - else if(layer==1) - { - if(drawFrames) - ag.setColor(colorMap[bkgColor]); - ag.fillPolygon(detectors[det], index[det][i], display[det].hv[0][i], - display[det].hv[1][i], numPoints); - } - } - else - { - if(layer==0) - { - if(drawFrames) - ag.setColor(colorMap[bkgColor]); - ag.fillPolygon(detectors[det], index[det][i], display[det].hv[0][i], - display[det].hv[1][i], numPoints); - } - else if(layer==1 && (drawFrames||colorBW)) - { - if(colorBW) - ag.setColor(colorMap[AColorMap.BK]); - ag.drawPolygon(display[det].hv[0][i], display[det].hv[1][i], numPoints); - } - } - } - } - } - } - ABarrelSiliconDetector.drawAdditionalItems(window, ag, projection); - AEndcapSiliconDetector.drawAdditionalItems(window, ag, projection); - ABarrelTRTDetector.drawAdditionalItems(window, ag, projection); - AEndcapTRTDetector.drawAdditionalItems(window, ag, projection); - ACalorimeterDetector.drawAdditionalItems(window, ag, projection); - } - - public static String getGeometryName() - { - return geometryName == null ? "n/a" : geometryName; - - } // getName() ------------------------------------------------------------ - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ADetectors.java b/graphics/AtlantisJava/src/atlantis/geometry/ADetectors.java deleted file mode 100755 index 1f11913e80d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ADetectors.java +++ /dev/null @@ -1,114 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.*; -import atlantis.parameters.APar; -import atlantis.projection.*; - -/** - * Base class of all collections of detectors - * All non muon geometry is in AGeometry.xml - * All muon geometry is in AMuonGeometry.xml - * ADetectors is the interface to the rest of the program and contains - * collections of detectors. - * When a line in our XML file describes several detectors these are stored - * individually. - */ -public abstract class ADetectors { - - protected ADetector[] det=null; - - protected int[] listdl; - protected int numDraw; - protected int numData; - - protected static APar parameterStore = APar.instance(); - - public ADetectors(ADetector[] det) { - this.det=det; - numData=det.length; - numDraw=0; - listdl=new int[numData]; - } - - public ADetector[] getDetectors() { - return det; - } - - protected void constructDefaultDrawList() { - numDraw=numData; - for(int i=0; i<numDraw; ++i) - listdl[i]=i; - } - - protected void makeDrawList(String projection){ - constructDefaultDrawList(); - } - - protected ACoord getUser(String projection) { - makeDrawList(projection); - int[] numPoly = new int[numDraw]; - int numTotal = 0; - for (int i=0; i<numDraw; i++) { - int len = det[listdl[i]].getUser(projection).hv[0].length; - numPoly[i] = len; - numTotal += len; - } - double[][][] hv = new double[2][numTotal][]; - int[] index = new int[numTotal]; - for (int i=0, k=0; i<numDraw; i++) { - double temp[][][] = det[listdl[i]].getUser(projection).hv; - for(int j = 0; j < numPoly[i]; j++, k++) { - hv[0][k] = temp[0][j]; - hv[1][k] = temp[1][j]; - index[k] = listdl[i]; - } - } - return new ACoord(hv, index); - } - - protected int[] getColor(int[] dl) { - int[] col=new int[dl.length]; - - for(int i=0; i<dl.length; ++i) - col[i]=det[dl[i]].getFillColor(); - return col; - } - - protected boolean[] getDraw(int[] dl) { - boolean[] draw=new boolean[dl.length]; - - for(int i=0; i<dl.length; ++i) - draw[i]=det[dl[i]].getDraw(); - return draw; - } - - public String getInfo(int index) { - return det[index].getName(); - } - - protected ADrawParameters getDrawParameters(int layer, int type) { - if(layer==0) - return new ADrawParameters(true, 0, 0, 0, 1, 0); - else - return new ADrawParameters(true, 0, 0, 1, 0, 0); - } - - protected ACoord getUserNoTransform(AProjection projection) { - String name=projection.getName(); - ACoord data=getUser(name); - if(name.charAt(0)=='F') - data.includePhiWrapAround(name); - return data; - } - - protected ACoord getUser(AProjection2D projection) { - return projection.nonLinearTransform(getUserNoTransform(projection)); - } - - /* - protected void draw(AWindow window,AGraphics ag,AProjection2D projection) { - // in a simple world the implementation would be here - throw new RuntimeException(); - } - */ -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ADiscDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ADiscDetector.java deleted file mode 100755 index a8241c1889c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ADiscDetector.java +++ /dev/null @@ -1,57 +0,0 @@ -package atlantis.geometry; - -import atlantis.utils.*; -import atlantis.graphics.ACoord; - -public class ADiscDetector extends ADetector { - - double rInner; - double rOuter; - int nInner; - int nOuter; - - ADiscDetector(String name, String projection, String color, double rInner, double rOuter, int nInner, int nOuter) { - super(name, projection, color); - this.rInner=rInner; - this.nInner=nInner; - this.rOuter=rOuter; - this.nOuter=nOuter; - } - - protected ACoord getYXUser() { - if (!projection.equals("YX")) { - return ACoord.NO_DATA; - } - - if (!globals.getUseOpenGL()) { - int numPoints = nInner + nOuter + 2; - double[][] hv = new double[2][numPoints]; - - for (int j = 0; j < nInner + 1; j++) { - hv[0][j] = rInner * Math.cos(Math.PI * 2 * j / nInner); - hv[1][j] = rInner * Math.sin(Math.PI * 2 * j / nInner); - } - for (int j = 0; j < nOuter + 1; j++) { - hv[0][j + nInner + 1] = rOuter * Math.cos(Math.PI * 2 * (nOuter - j) / nOuter); - hv[1][j + nInner + 1] = rOuter * Math.sin(Math.PI * 2 * (nOuter - j) / nOuter); - } - return new ACoord(hv); - } else { - //FIXME: - //Note that generateAnnulusTris can't really handle this different number - //of inner and outer points thing so we're just going to take the mean here - //Maybe one day we fix this somehow or just remove one of the ns - //All the other round detectors get along fine without it... - // -- Adam - return new ACoord(generateAnnulusTris((nInner + nOuter) / 2, 0.0, rInner, rOuter)); - } - } - - protected ACoord getFRUser() { - if(!projection.equals("FR")) return ACoord.NO_DATA; - return new ACoord (AMath.xBox((rInner+rOuter)/2.,(rOuter-rInner)/2.), - AMath.yBox(180.,180.)); - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCalorimeterDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCalorimeterDetector.java deleted file mode 100755 index a5df48ac54f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCalorimeterDetector.java +++ /dev/null @@ -1,328 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.graphics.AClipper; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AMath; - -/** - * Class representing a calorimeter part in the endcap section of ATLAS. - */ -public class AEndcapCalorimeterDetector extends ACalorimeterDetector { - - /** - * Constructs a new endcap calorimeter object - * @param name String name of the object - * @param color String name of the color used to draw this object - * @param sampling int sampling of this calorimeter part - * @param region int region of this calorimeter part - * @param rMin double inner radius - * @param rMax double outer radius - * @param zMin double inner z - * @param zMax double outer z - * @param eta0 double start of the first cell in eta - * @param deta double size of a cell in eta - * @param neta int number of cells in eta - * @param meta int eta index of the first cell - * @param phi0 double start of the first cell in phi - * @param nphi int number of cells in phi - */ - public AEndcapCalorimeterDetector(String name, String color, int sampling, int region, - double rMin, double rMax, double zMin, double zMax, - double eta0, double deta, int neta, int meta, - double phi0, int nphi) { - super(name, color); - - this.sampling = sampling; - this.region = region; - this.rMin = rMin; - this.rMax = rMax; - this.zMin = zMin; - this.zMax = zMax; - this.eta0 = eta0; - this.deltaEta = deta; - this.numEta = neta; - this.minEta = meta; - this.phi0 = Math.toRadians(phi0); - this.numPhi = nphi; - this.deltaPhi = 2.*Math.PI / numPhi; - - this.detEtaMin = AMath.etaAbs(this.zMin, this.rMax); - this.detEtaMax = AMath.etaAbs(this.zMax, this.rMax); - - // This one is used for clipping the cell geometry in rho-z. - this.clipper = new AClipper(zMin, zMax, rMin, rMax); - - // These arrays are used by the getDetectorIndex() method in ACalorimeterData. - // They provide fast mapping of hits to detectors. - if (this.name.indexOf("LAr") >= 0 && this.name.indexOf("Inner") >= 0 - && this.sampling < lar[3].length && this.region < lar[3][this.sampling].length) { - - lar[3][this.sampling][this.region] = detectors.indexOf(this); - } else if (this.name.indexOf("LAr") >= 0 && this.sampling < lar[2].length - && this.region < lar[2][this.sampling].length) { - - lar[2][this.sampling][this.region] = detectors.indexOf(this); - } else if (this.name.equals("HEC") && this.sampling < hec.length - && this.region < hec[this.sampling].length) { - - hec[this.sampling][this.region] = detectors.indexOf(this); - } else { - System.out.println("Unknown calorimeter object: '" + this.name + "'" - + " some hits might not be displayed correctly."); - } - } - - /** - * Returns the y-x geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getYXUser() { - int mode = parameterStore.get("YX", "Mode").getI(); - if ( mode < AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER) - return ACoord.NO_DATA; - else if((mode==AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && (name.equals("LAr Endcap Presampler")||name.equals("LAr_EC_Presampler"))) - || (name.equals("LAr Outer Endcap") && sampling==mode-AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER) - || (name.equals("LAr Inner Endcap") && sampling==mode-AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER-1) - || (name.equals("HEC") && sampling==mode-AProjectionYX.MODE_HEC_1) - || (mode==AProjectionYX.MODE_LAR_ENDCAP_SUMMED && name.indexOf("LAr")>=0) - || (mode==AProjectionYX.MODE_HEC_SUMMED && name.equals("HEC"))) - { - - double etaMax = eta0 + numEta * deltaEta; - double etaMin = eta0; - double r1, r2; - if (name.equals("HEC")) - { - r1=rMax; - r2=rMin; - } - else - { - if (name.indexOf("Inner") >= 0 || name.indexOf("Presampler") >= 0) - r1 = zMin/Math.sinh(etaMin); - else - r1=rMax; - r2 = zMin/Math.sinh(etaMax); - } - - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - for (int i = 0; i < numPhi + 1; i++) { - hv[0][i] = r2 * Math.cos(phi0 + i * deltaPhi); - hv[1][i] = r2 * Math.sin(phi0 + i * deltaPhi); - hv[0][numPhi + 1 + i] = r1 * Math.cos(phi0 - i * deltaPhi); - hv[1][numPhi + 1 + i] = r1 * Math.sin(phi0 - i * deltaPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phi0, r1, r2)); - } - } - else - return ACoord.NO_DATA; - } - - /** - * Returns the rho-z geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getRZUser() { - double h[], v[]; - double etaMax = eta0 + numEta * deltaEta; - double etaMin = eta0; - - // Calculate the polygon in the positive h and v. - if (name.indexOf("HEC") >= 0) { - h = new double[] {zMax, zMin, zMin, zMax}; - v = new double[] {rMax, rMax, rMin, rMin}; - } else { - double r0 = zMax/Math.sinh(etaMin); - double r1 = zMin/Math.sinh(etaMin); - double r2 = zMin/Math.sinh(etaMax); - double r3 = zMax/Math.sinh(etaMax); - - h = new double[] {zMax, zMin, zMin, zMax}; - v = new double[] {r0, r1, r2, r3}; - } - - // Clip the polygon. - ACoord coord = clipper.clipPolygon(h, v, h.length); - - // Copy it to negative v. - coord = new ACoord(coord, coord.mirrorV()); - // Copy it to negative h. - coord = new ACoord(coord, coord.mirrorH()); - - return coord; - } - - /** - * Returns the phi-rho geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getFRUser() { - return getYXUser().convertYXToFR(); - } - - /** - * Returns the phi-z geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getFZUser() { - double[][][] hv = new double[2][2][]; - double phiMin = 0.; - double phiMax = 360.; - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] {phiMax, phiMax, phiMin, phiMin}; - hv[0][1] = new double[] { -zMax, -zMin, -zMin, -zMax}; - hv[1][1] = new double[] {phiMax, phiMax, phiMin, phiMin}; - return new ACoord(hv); - } - - /** - * Returns the y-x geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getYXCell(int eta, int phi) - { - int mode = parameterStore.get("YX", "Mode").getI(); - if(mode < AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER || mode > AProjectionYX.MODE_HEC_SUMMED) - return ACoord.NO_DATA; - else if((mode==AProjectionYX.MODE_LAR_ENDCAP_SUMMED && name.indexOf("LAr")>=0) - || (mode==AProjectionYX.MODE_HEC_SUMMED && name.equals("HEC"))) - { - //don't need to carry out calculation just needs return a blank ACoord - double[][] hv = new double[2][]; - hv[0] = new double[] {0}; - hv[1] = new double[] {0}; - return new ACoord(hv); - } - else if((mode==AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER && (name.equals("LAr Endcap Presampler") || name.equals("LAr_EC_Presampler"))) - || (name.equals("LAr Outer Endcap") && sampling==mode-AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER) - || (name.equals("LAr Inner Endcap") && sampling==mode-AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER-1) - || (name.equals("HEC") && sampling==mode-AProjectionYX.MODE_HEC_1)) - { - double[][] hv = new double[2][]; - double phiMin = phi0+phi*deltaPhi; - double phiMax = phiMin+deltaPhi; - double newrMax=0, newrMin=0; - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - newrMax=zMin/Math.sinh(etaMin); - newrMin=zMin/Math.sinh(etaMax); - if (name.equals("HEC")) - { - if(newrMax>rMax) - newrMax=rMax; - if(newrMin<rMin) - newrMin=rMin; - } - hv[0] = new double[] {newrMax*Math.cos(phiMin), newrMax*Math.cos(phiMax), - newrMin*Math.cos(phiMax), newrMin*Math.cos(phiMin)}; - hv[1] = new double[] {newrMax*Math.sin(phiMin), newrMax*Math.sin(phiMax), - newrMin*Math.sin(phiMax), newrMin*Math.sin(phiMin)}; - return new ACoord(hv); - } - else - return ACoord.NO_DATA; - } - - /** - * Returns the rho-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getRZCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - int sign = getRSign(phi); - - // This shouldn't be 0, but just to be on the safe side. - if (side != 0) side /= Math.abs(side); - - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - - if (name.indexOf("HEC") >= 0) { - if (sampling == 0) { - double rMin = (zMin+zMax)/2. / Math.sinh(etaMax); - double rMax = (zMin+zMax)/2. / Math.sinh(etaMin); - - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {rMax, rMax, rMin, rMin}; - } else { - double dz = (zMax-zMin); - double z0 = zMin; - double z1 = zMin+dz/2.; - double z2 = zMax; - double r0 = (zMin+dz/4.) / Math.sinh(etaMax); - double r1 = (zMax-dz/4.) / Math.sinh(etaMax); - double r2 = (zMin+dz/4.) / Math.sinh(etaMin); - double r3 = (zMax-dz/4.) / Math.sinh(etaMin); - - hv[0] = new double[] {z2, z1, z1, z0, z0, z1, z1, z2}; - hv[1] = new double[] {r3, r3, r2, r2, r0, r0, r1, r1}; - } - } else { - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {zMax/Math.sinh(etaMin), zMin/Math.sinh(etaMin), - zMin/Math.sinh(etaMax), zMax/Math.sinh(etaMax)}; - } - - // Clip the cell and send it to the right quadrant. - ACoord coord = clipper.clipPolygon(hv[0], hv[1], hv[0].length); - for (int i=0; i<coord.hv[0][0].length; i++) { - coord.hv[0][0][i] *= side; - coord.hv[1][0][i] *= sign; - } - - return coord; - } - - /** - * Returns the phi-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord - */ - public ACoord getFZCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - double phiMin = Math.toDegrees(phi0 + phi*deltaPhi); - double phiMax = phiMin + Math.toDegrees(deltaPhi); - - side /= Math.abs(side); - - hv[0] = new double[] {side*zMax, side*zMin, side*zMin, side*zMax}; - hv[1] = new double[] { phiMax, phiMax, phiMin, phiMin}; - - return new ACoord(hv); - } - - /** - * Returns the eta-phi geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getVPCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - double etaMin = eta0+(eta-minEta)*deltaEta; - double etaMax = etaMin+deltaEta; - double phiMin = Math.toDegrees(phi0 + phi*deltaPhi); - double phiMax = phiMin + Math.toDegrees(deltaPhi); - - side /= Math.abs(side); - - hv[0] = new double[] {side*etaMax, side*etaMin, side*etaMin, side*etaMax}; - hv[1] = new double[] { phiMax, phiMax, phiMin, phiMin}; - - return new ACoord(hv); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCryostatDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCryostatDetector.java deleted file mode 100755 index 8d1122eba4b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapCryostatDetector.java +++ /dev/null @@ -1,158 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.graphics.AClipper; -import atlantis.projection.AProjectionYX; -import atlantis.utils.AMath; - -/** - * Class representing a detector part in the endcap cryostat section of ATLAS. - */ -public class AEndcapCryostatDetector extends ACalorimeterDetector { - - /** - * Constructs a new endcap calorimeter object - * @param name String name of the object - * @param color String name of the color used to draw this object - * @param sampling int sampling of this calorimeter part - * @param region int region of this calorimeter part - * @param rMin double inner radius - * @param rMax double outer radius - * @param zMin double inner z - * @param zMax double outer z - * @param neta int number of cells in eta - * @param nphi int number of cells in phi - */ - public AEndcapCryostatDetector(String name, String color, int sampling, int region, double rMin, - double rMax, double zMin, double zMax, int neta, int nphi) { - super(name, color); - - this.sampling = sampling; - this.region = region; - this.rMin = rMin; - this.rMax = rMax; - this.zMin = zMin; - this.zMax = zMax; - this.numEta = neta; - this.numPhi = nphi; - this.deltaPhi = 2.*Math.PI / numPhi; - this.phi0 = 0.0; - this.eta0 = AMath.etaAbs(this.zMin, this.rMin); - - this.detEtaMin = AMath.etaAbs(this.zMin, this.rMax); - this.detEtaMax = AMath.etaAbs(this.zMax, this.rMax); - - // This one is used for clipping the cell geometry in rho-z. - this.clipper = new AClipper(zMin, zMax, rMin, rMax); - - // These arrays are used by the getDetectorIndex() method in ACalorimeterData. - // They provide fast mapping of hits to detectors. - if (this.name.equals("Minimum Bias Trigger Scintillators")) { - mbts[this.sampling] = detectors.indexOf(this); - } else { - System.out.println("Unknown calorimeter object: '" + this.name + "'" - + " some hits might not be displayed correctly."); - } - } - - /** - * Returns the y-x geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getYXUser() { - int mode = parameterStore.get("YX", "Mode").getI(); - if (mode!=AProjectionYX.MODE_MBTS) - return ACoord.NO_DATA; - else - { - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - for (int j = 0; j < numPhi + 1; j++) { - hv[0][j] = rMin * Math.cos(Math.PI * 2 * j / numPhi); - hv[1][j] = rMin * Math.sin(Math.PI * 2 * j / numPhi); - } - for (int j = 0; j < numPhi + 1; j++) { - hv[0][j + numPhi + 1] = rMax * Math.cos(Math.PI * 2 * (numPhi - j) / numPhi); - hv[1][j + numPhi + 1] = rMax * Math.sin(Math.PI * 2 * (numPhi - j) / numPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phi0, rMin, rMax)); - } - } - } - - /** - * Returns the rho-z geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getRZUser() { - double h[], v[]; - // Calculate the polygon in the positive h and v. - h = new double[] {zMax, zMin, zMin, zMax}; - v = new double[] {rMax, rMax, rMin, rMin}; - // Clip the polygon. - ACoord coord = clipper.clipPolygon(h, v, h.length); - // Copy it to negative v. - coord = new ACoord(coord, coord.mirrorV()); - // Copy it to negative h. - coord = new ACoord(coord, coord.mirrorH()); - return coord; - } - - /** - * Returns the phi-rho geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getFRUser() { - return getYXUser().convertYXToFR(); - } - - /** - * Returns the y-x geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getYXCell(int eta, int phi) - { - int mode = parameterStore.get("YX", "Mode").getI(); - if(mode!=AProjectionYX.MODE_MBTS) - return ACoord.NO_DATA; - else - { - double[][] hv = new double[2][]; - double phiMin = Math.PI*2*phi/numPhi; - double phiMax = Math.PI*2*(1+phi)/numPhi; - hv[0] = new double[] {rMax*Math.cos(phiMin), rMax*Math.cos(phiMax), - rMin*Math.cos(phiMax), rMin*Math.cos(phiMin)}; - hv[1] = new double[] {rMax*Math.sin(phiMin), rMax*Math.sin(phiMax), - rMin*Math.sin(phiMax), rMin*Math.sin(phiMin)}; - return new ACoord(hv); - } - } - - /** - * Returns the rho-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getRZCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - int sign = getRSign(phi); - // This shouldn't be 0, but just to be on the safe side. - if (side != 0) side /= Math.abs(side); - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {rMax, rMax, rMin, rMin}; - // Clip the cell and send it to the right quadrant. - ACoord coord = clipper.clipPolygon(hv[0], hv[1], hv[0].length); - for (int i=0; i<coord.hv[0][0].length; i++) { - coord.hv[0][0][i] *= side; - coord.hv[1][0][i] *= sign; - } - return coord; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapSiliconDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AEndcapSiliconDetector.java deleted file mode 100755 index e28c5f16869..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapSiliconDetector.java +++ /dev/null @@ -1,220 +0,0 @@ -package atlantis.geometry; - -import atlantis.canvas.AWindow; -import atlantis.data.AS3DData; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionYX; -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -/** - * Class representing a pixel/SCT endcap detector part. - * Also implements methods to draw more detailed structure of the detector. - * - * @author Eric Jansen - */ -public class AEndcapSiliconDetector extends ADetector { - - private static List detectors = null; - - protected int layer; - protected double length; - protected double width; - protected double thickness; - protected int numZ; - protected int numPhi; - protected double phi0; - protected double zMin; - protected double zMax; - - protected double deltaPhi; - protected double deltaZ; - protected double rMin; - protected double rMax; - - public AEndcapSiliconDetector(String name, String color, int layer, double length, double width, double thickness, - int numZ, int numPhi, double rMin, double rMax, double phi0, double zMin, double zMax) { - super(name, " ", color); - - if (detectors == null) { - detectors = new ArrayList(); - } - detectors.add(this); - - this.layer = layer; - this.length = length; - this.width = width; - this.thickness = thickness; - this.numZ = numZ; - this.numPhi = numPhi; - this.rMin = rMin; - this.rMax = rMax; - this.phi0 = Math.toRadians(phi0); - this.zMin = zMin; - this.zMax = zMax; - - this.deltaPhi = 2.*Math.PI / this.numPhi; - this.deltaZ = (this.zMax - this.zMin) / this.numZ; - } - - /** - * Empties the list of instances of this class. - */ - public static void clear() { - if (detectors != null) { - detectors.clear(); - } - } - - /** - * This function draws the wafer/stave structure of the silicon detectors. It is called - * from ADetectorSystem.draw(). - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - public static void drawAdditionalItems(AWindow window, AGraphics ag, AProjection2D projection) { - AParameter inDetDetail = parameterStore.getUnknown("Det", "SiliconDetail"); - if (inDetDetail != null && detectors != null && inDetDetail.getStatus()) { - for (int i=0; i<detectors.size(); i++) { - ACoord coord = ACoord.NO_DATA; - AEndcapSiliconDetector detector = (AEndcapSiliconDetector) detectors.get(i); - if (projection instanceof AProjectionYX) { - coord = detector.getYXDetail(); - } else if (projection instanceof AProjectionFR) { - coord = detector.getYXDetail().convertYXToFR().includePhiWrapAround("FR"); - } - - if (coord != ACoord.NO_DATA) { - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "SiliconDetail").getI()]); - - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - for (int j=0; j<display.hv[0].length; j++) { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - } - - /** - * Determines if this element should be visible or not. - * @return visibility - */ - protected boolean isVisible() { - int cut = parameterStore.get("CutsInDet", "SCT").getI(); - - if (cut == AS3DData.CUT_INDET_SCT_ALL || cut == AS3DData.CUT_INDET_SCT_EC_NEG - || cut == AS3DData.CUT_INDET_SCT_EC_POS) { - return true; - } else { - return false; - } - } - - /** - * Returns the detector outline in the y-x projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getYXUser() { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - if (!isVisible()) return ACoord.NO_DATA; - - if (!globals.getUseOpenGL()) { - int numPoints = 2 * (numPhi + 1); - double[][] hv = new double[2][numPoints]; - - for (int i = 0; i < numPhi + 1; i++) { - hv[0][i] = rMin * Math.cos(phi0 + (i + 0.5) * deltaPhi); - hv[1][i] = rMin * Math.sin(phi0 + (i + 0.5) * deltaPhi); - - hv[0][numPhi + 1 + i] = rMax * Math.cos(phi0 - (i + 0.5) * deltaPhi); - hv[1][numPhi + 1 + i] = rMax * Math.sin(phi0 - (i + 0.5) * deltaPhi); - } - return new ACoord(hv); - } else { - return new ACoord(generateAnnulusTris(numPhi, phi0, rMin, rMax)); - } - } - - /** - * Returns the detector outline in the rho-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getRZUser() { - double[][][] hv = new double[2][4][]; - - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - - hv[0][2] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][2] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][3] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][3] = new double[] {-rMin, -rMin, -rMax, -rMax}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFZUser() { - if (!isVisible()) return ACoord.NO_DATA; - - double[][][] hv = new double[2][2][]; - - hv[0][0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] {360., 360., 0., 0.}; - hv[0][1] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-rho projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFRUser() { - if (!isVisible()) return ACoord.NO_DATA; - - return getYXUser().convertYXToFR(); - } - - /** - * Returns the wafer/stave structure in the y-x projection. - * @return ACoord polygons representing the wafers/staves - */ - protected ACoord getYXDetail() { - if (parameterStore.get("YX", "Mode").getI() != AProjectionYX.MODE_STANDARD) return ACoord.NO_DATA; - if (!isVisible()) return ACoord.NO_DATA; - - double[][][] hv = new double[2][numPhi][]; - for (int i=0; i<numPhi; i++) { - hv[0][i] = new double[] { - rMax*Math.sin(phi0+(i-0.5)*deltaPhi), - rMax*Math.sin(phi0+(i+0.5)*deltaPhi), - rMin*Math.sin(phi0+(i+0.5)*deltaPhi), - rMin*Math.sin(phi0+(i-0.5)*deltaPhi) - }; - hv[1][i] = new double[] { - rMax*Math.cos(phi0+(i-0.5)*deltaPhi), - rMax*Math.cos(phi0+(i+0.5)*deltaPhi), - rMin*Math.cos(phi0+(i+0.5)*deltaPhi), - rMin*Math.cos(phi0+(i-0.5)*deltaPhi) - }; - } - - return new ACoord(hv); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapTRTDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AEndcapTRTDetector.java deleted file mode 100755 index a23bfaf0d02..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AEndcapTRTDetector.java +++ /dev/null @@ -1,173 +0,0 @@ -package atlantis.geometry; - -import atlantis.canvas.AWindow; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -/** - * Class representing a TRT endcap detector part. - * Also implements methods to draw more detailed structure of the detector. - * - * @author Eric Jansen - */ -public class AEndcapTRTDetector extends ADetector { - - private static List detectors = null; - - protected int layer; - protected int numPhi; - protected double rMin; - protected double rMax; - protected double phi0; - protected double zMin; - protected double zMax; - protected double deltaPhi; - - public AEndcapTRTDetector(String name, String color, int layer, int numPhi, double rMin, double rMax, - double phi0, double zMin, double zMax) { - super(name, " ", color); - - if (detectors == null) { - detectors = new ArrayList(); - } - detectors.add(this); - - this.layer = layer; - this.numPhi = numPhi; - this.rMin = rMin; - this.rMax = rMax; - this.phi0 = Math.toRadians(phi0); - this.zMin = zMin; - this.zMax = zMax; - - this.deltaPhi = 2.*Math.PI / numPhi; - } - - /** - * Empties the list of instances of this class. - */ - public static void clear() { - if (detectors != null) { - detectors.clear(); - } - } - - /** - * This function draws the module structure of the TRT detector. It is called - * from ADetectorSystem.draw(). - * @param window AWindow window to use - * @param ag AGraphics graphics object to draw onto - * @param projection AProjection2D current projection - */ - public static void drawAdditionalItems(AWindow window, AGraphics ag, AProjection2D projection) { - AParameter inDetDetail = parameterStore.getUnknown("Det", "TRTDetail"); - if (inDetDetail != null && detectors != null && inDetDetail.getStatus()) { - for (int i=0; i<detectors.size(); i++) { - ACoord coord = ACoord.NO_DATA; - AEndcapTRTDetector detector = (AEndcapTRTDetector) detectors.get(i); - if (projection instanceof AProjectionRZ) { - coord = detector.getRZDetail(); - } else if (projection instanceof AProjectionFZ) { - coord = detector.getFZDetail(); - } - - if (coord != ACoord.NO_DATA) { - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[parameterStore.get("Det", "TRTDetail").getI()]); - - ACoord display = window.calculateDisplay(projection.nonLinearTransform(coord)); - for (int j=0; j<display.hv[0].length; j++) { - ag.drawPolygon(display.hv[0][j], display.hv[1][j], display.hv[0][j].length); - } - } - } - } - } - - /** - * Returns the detector outline in the y-x projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getYXUser() { - return ACoord.NO_DATA; - } - - /** - * Returns the detector outline in the rho-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getRZUser() { - double[][][] hv = new double[2][4][]; - - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - hv[0][2] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][2] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][3] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][3] = new double[] {-rMin, -rMin, -rMax, -rMax}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-z projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFZUser() { - double[][][] hv = new double[2][2][]; - - hv[0][0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] {360., 360., 0., 0.}; - hv[0][1] = new double[] {-zMax, -zMin, -zMin, -zMax}; - hv[1][1] = new double[] {360., 360., 0., 0.}; - - return new ACoord(hv); - } - - /** - * Returns the detector outline in the phi-rho projection. - * @return ACoord polygon representing the detector - */ - protected ACoord getFRUser() { - return ACoord.NO_DATA; - } - - /** - * Returns the module structure in the rho-z projection. - * @return ACoord polygons representing the modules - */ - protected ACoord getRZDetail() { - return ACoord.NO_DATA; - } - - /** - * Returns the module structure in the phi-z projection. - * @return ACoord polygons representing the modules - */ - protected ACoord getFZDetail() { - double[][][] hv = new double[2][2*numPhi][2]; - for (int i=0; i<numPhi; i++) { - hv[0][i][0] = zMin; - hv[1][i][0] = Math.toDegrees(phi0 + i*deltaPhi); - hv[0][i][1] = zMax; - hv[1][i][1] = Math.toDegrees(phi0 + i*deltaPhi); - hv[0][numPhi+i][0] = -zMax; - hv[1][numPhi+i][0] = Math.toDegrees(phi0 + i*deltaPhi); - hv[0][numPhi+i][1] = -zMin; - hv[1][numPhi+i][1] = Math.toDegrees(phi0 + i*deltaPhi); - } - - return new ACoord(hv).includePhiWrapAround("FZ"); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AGapCalorimeterDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/AGapCalorimeterDetector.java deleted file mode 100755 index a27a9872377..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AGapCalorimeterDetector.java +++ /dev/null @@ -1,179 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.parameters.AParameterUtilities; - -/** - * Class representing a calorimeter in the gap region between TILE and extended TILE. - * This is a fairly straightforward implementation of ACalorimeterDetector with only - * one cell per object. - * - * @author Eric Jansen - */ -public class AGapCalorimeterDetector extends ACalorimeterDetector { - - protected int eta; - - /** - * Constructs a new gap calorimeter object (one cell in eta). - * @param name String name of the object - * @param color String name of the color used to draw this object - * @param sampling int sampling of this calorimeter part - * @param region int region of this calorimeter part - * @param rMin double inner radius - * @param rMax double outer radius - * @param zMin double inner z - * @param zMax double outer z - * @param eta int eta index of this cell - * @param phi0 double start of the first cell in phi - * @param nphi int number of cells in phi - */ - public AGapCalorimeterDetector(String name, String color, int sampling, int region, - double rMin, double rMax, double zMin, double zMax, - int eta, double phi0, int nphi) { - super(name, color); - - // Just to be sure we take absolute values here. - this.sampling = Math.abs(sampling); - this.region = Math.abs(region); - this.eta = Math.abs(eta); - - this.rMin = rMin; - this.rMax = rMax; - this.zMin = zMin; - this.zMax = zMax; - this.phi0 = Math.toRadians(phi0); - this.numPhi = nphi; - this.deltaPhi = 2.*Math.PI/numPhi; - - // These arrays are used by the getDetectorIndex() method in ACalorimeterData. - // They provide fast mapping of hits to detectors. - if (this.name.indexOf("ITC") >= 0 && this.sampling < tile_gap.length - && this.eta < tile_gap[this.sampling].length) { - - tile_gap[this.sampling][this.eta] = detectors.indexOf(this); - } else { - System.out.println("Unknown calorimeter object: '" + this.name + "'" - + " some hits might not be displayed correctly."); - } - } - - /** - * Returns the eta value of the center (in eta) of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double eta value - */ - public double getEta(int eta, int side) { - if (side < 0) { - return -getEta(eta, -side); - } else { - return AParameterUtilities.eta((zMin+zMax)/2.f, (rMin+rMax)/2.f); - } - } - - /** - * Returns the lowest eta value of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double lowest eta value - */ - public double getEtaMin(int eta, int side) { - if (side < 0) { - return -getEtaMax(eta, -side); - } else { - return AParameterUtilities.eta((zMin+zMax)/2.f, rMax); - } - } - - /** - * Returns the highest eta value of a cell. - * @param eta int eta index of the cell - * @param side int sign of the z coordinate of the cell - * @return double highest eta value - */ - public double getEtaMax(int eta, int side) { - if (side < 0) { - return -getEtaMin(eta, -side); - } else { - return AParameterUtilities.eta((zMin+zMax)/2.f, rMin); - } - } - - /** - * Returns the rho-z geometry of the full calorimeter part. - * @return ACoord polygons representing geometry - */ - protected ACoord getRZUser() { - double[][][] hv; - if (zMin < 0) { - hv = new double[2][2][]; - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - } else { - hv = new double[2][4][]; - hv[0][0] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][0] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][1] = new double[] { zMax, zMin, zMin, zMax}; - hv[1][1] = new double[] {-rMin, -rMin, -rMax, -rMax}; - hv[0][2] = new double[] {-zMin, -zMax, -zMax, -zMin}; - hv[1][2] = new double[] { rMax, rMax, rMin, rMin}; - hv[0][3] = new double[] {-zMin, -zMax, -zMax, -zMin}; - hv[1][3] = new double[] {-rMin, -rMin, -rMax, -rMax}; - } - return new ACoord(hv); - } - - /** - * Returns the rho-z geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getRZCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - int sign = getRSign(phi); - - // This shouldn't be 0, but just to be on the safe side. - if (side != 0) { - side /= Math.abs(side); - } - - hv[0] = new double[] {zMax, zMin, zMin, zMax}; - hv[1] = new double[] {rMax, rMax, rMin, rMin}; - - // Send it to the right quadrant. - ACoord coord = new ACoord(hv); - for (int i=0; i<coord.hv[0][0].length; i++) { - coord.hv[0][0][i] *= side; - coord.hv[1][0][i] *= sign; - } - - return coord; - } - - /** - * Returns the eta-phi geometry of a specific cell in this calorimeter part. - * @param eta int eta index of cell - * @param phi int phi index of cell - * @param side int sign of the z coordinate of cell - * @return ACoord polygon representing cell geometry - */ - public ACoord getVPCell(int eta, int phi, int side) { - double[][] hv = new double[2][]; - double etaMin = AParameterUtilities.eta((zMin+zMax)/2.f, rMax); - double etaMax = AParameterUtilities.eta((zMin+zMax)/2.f, rMin); - double phiMin = Math.toDegrees(phi0 + phi*deltaPhi); - double phiMax = phiMin + Math.toDegrees(deltaPhi); - - side /= Math.abs(side); - - hv[0] = new double[] {side*etaMax, side*etaMin, side*etaMin, side*etaMax}; - hv[1] = new double[] { phiMax, phiMax, phiMin, phiMin}; - - return new ACoord(hv); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AGeneralDetectors.java b/graphics/AtlantisJava/src/atlantis/geometry/AGeneralDetectors.java deleted file mode 100755 index bb939996da5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AGeneralDetectors.java +++ /dev/null @@ -1,71 +0,0 @@ -package atlantis.geometry; - -import atlantis.parameters.APar; -import java.util.*; - -/** - * Used to store all detectors which are not part of the muon system - * these may be of different types. - */ - -public final class AGeneralDetectors extends ADetectors { - - public AGeneralDetectors(List detectors) { - super(filterGeneralDetectors(detectors)); - } - - private static ADetector[] filterGeneralDetectors(List detectors) { - - List tempDetectors=new ArrayList(detectors.size()); - Iterator it=detectors.iterator(); - - while(it.hasNext()) { - Object o=it.next(); - if((o instanceof ADetector)&&!(o instanceof ABoxDetector)&&!(o instanceof ATrapezoidDetector)) tempDetectors.add(o); - } - return (ADetector[])tempDetectors.toArray(new ADetector[tempDetectors.size()]); - } - - private void makeDrawListYX() { - int mode=parameterStore.get("YX", "Mode").getI(); - if(mode==0) { - int num=0; - for(int i=0; i<numData; ++i) - if(det[i].getName().indexOf("FCAL")<0) - listdl[num++]=i; - numDraw=num; - } - else if(mode>8) - { - int num=0; - for(int i=0; i<numData; ++i) - if((mode==9 && det[i].getName().equals("FCAL EM")) - ||(mode==10 && det[i].getName().equals("FCAL HAD 1")) - ||(mode==11 && det[i].getName().equals("FCAL HAD 2")) - ||(mode==12 && (det[i].getName().equals("LAr Endcap Presampler"))||det[i].getName().equals("LAr_EC_Presampler")) - ||(mode>=13 && mode<= 15 && (det[i].getName().equals("LAr Outer Endcap") || det[i].getName().equals("LAr Inner Endcap"))) - ||(mode>=16 && mode<= 19 && det[i].getName().equals("HEC")) - ||(parameterStore.get("YX", "DrawFCAL").getStatus() && mode==17 && det[i].getName().equals("FCAL EM")) - ||(parameterStore.get("YX", "DrawFCAL").getStatus() && mode==18 && det[i].getName().equals("FCAL HAD 1")) - ||(parameterStore.get("YX", "DrawFCAL").getStatus() && mode==19 && det[i].getName().equals("FCAL HAD 2")) - ||(mode==20 && (det[i].getName().indexOf("LAr")>=0 || det[i].getName().indexOf("Endcap")>=0 || det[i].getName().indexOf("EC")>=0)) - ||(mode==21 && det[i].getName().equals("HEC")) - ||(mode==22)&& det[i].getName().equals("Minimum Bias Trigger Scintillators")) - listdl[num++]=i; - numDraw=num; - } else - numDraw=0; - } - - protected void makeDrawList(String projection) { - if (projection.equals("YX") || projection.equals("FR")) - makeDrawListYX(); - else { - if(parameterStore.get(projection, "Mode").getI()==0) - constructDefaultDrawList(); - else - numDraw=0; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/AGeometryFromXMLReader.java b/graphics/AtlantisJava/src/atlantis/geometry/AGeometryFromXMLReader.java deleted file mode 100755 index 8b7eb48bf48..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/AGeometryFromXMLReader.java +++ /dev/null @@ -1,286 +0,0 @@ -package atlantis.geometry; - -import java.io.InputStream; -import java.util.List; -import java.util.ArrayList; - -import atlantis.output.AExceptionHandler; -import atlantis.utils.xml.AXMLErrorHandler; -import atlantis.utils.AUtilities; -import org.xml.sax.helpers.*; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.xml.sax.Attributes; - - -class AGeometryFromXMLReader extends DefaultHandler { - - private static final boolean VALIDATION=false; - private SAXParser parser; - - private static List<ADetector> detectors; - - public AGeometryFromXMLReader() { - try { - SAXParserFactory factory=SAXParserFactory.newInstance(); - - factory.setValidating(true); - factory.setNamespaceAware(true); - parser=factory.newSAXParser(); - if(VALIDATION) - parser.getXMLReader().setErrorHandler(new AXMLErrorHandler()); - } catch(Exception e) { - AExceptionHandler.processException("Cannot create AGeometryFromXMLReader", e); - } - } - - protected List<ADetector> readDetectorGeometryFromXML(String fileName) - { - detectors = new ArrayList<ADetector>(2500); - try - { - InputStream isGeom = AUtilities.getFileAsStream(fileName); - parser.parse(isGeom, this); - } - catch(Exception e) - { - String msg = "Error when reading geometry file:\n" + e.getMessage(); - AExceptionHandler.processException(msg, e); - } - - return detectors; - } - - static private double calculatePhi(String name, double phi0, int phiIndex) { - String technology = name.substring(0, 3); - if (technology.equals("TGC")) { - if (name.charAt(6) == 'E' && name.charAt(5) != '4') - return Math.toRadians(phi0) + (phiIndex - 1) * Math.PI / 24.; - else - return Math.toRadians(phi0) + (phiIndex - 1) * Math.PI / 12.; - } else { - return Math.toRadians(phi0) + (phiIndex - 1) * Math.PI / 4.; - } - } - - // ContentHandler Implementation - - public void startElement(String namespaceURI, String localName, String qName, Attributes atts) { - if(localName.equals("ABox")||localName.equals("ATBx")) { - String name=atts.getValue("n"); - double zi=Double.parseDouble(atts.getValue("zi")); - double zo=Double.parseDouble(atts.getValue("zo")); - double ri=Double.parseDouble(atts.getValue("ri")); - double ro=Double.parseDouble(atts.getValue("ro")); - double w=Double.parseDouble(atts.getValue("w")); - double dPhi=Double.parseDouble(atts.getValue("dphi")); - double rpci=Double.parseDouble(atts.getValue("RPCi")); - double rpco=Double.parseDouble(atts.getValue("RPCo")); - double s=Double.parseDouble(atts.getValue("sh")); - int stationEta=Integer.parseInt(atts.getValue("eta")); - String[] phis=atts.getValue("phi").split(" "); - - if(localName.equals("ABox")) { - for(int i=0; i<phis.length; ++i) - for(int zSide=-1; zSide<=1; zSide+=2) { - int stationPhi = Integer.parseInt(phis[i]); - double phi = calculatePhi(name, dPhi, stationPhi); - detectors.add(new ABoxDetector(name, zSide*zi, zSide*zo, ri+rpci, ro-rpco, phi, s, w, - zSide*stationEta, stationPhi)); - if(rpci>0.) - detectors.add(new ABoxDetector("RPC"+name.substring(3)+"_I", zSide*zi, zSide*zo, ri, - ri+rpci, phi, s, w, zSide*stationEta, stationPhi)); - if(rpco>0.) - detectors.add(new ABoxDetector("RPC"+name.substring(3)+"_O", zSide*zi, zSide*zo, - ro-rpco, ro, phi, s, w, zSide*stationEta, stationPhi)); - } - } else if(localName.equals("ATBx")) { - double zis=Double.parseDouble(atts.getValue("zis")); - double zos=Double.parseDouble(atts.getValue("zos")); - double ws=Double.parseDouble(atts.getValue("ws")); - double or=Double.parseDouble(atts.getValue("or")); - for(int i=0; i<phis.length; ++i) - for(int zSide=-1; zSide<=1; zSide+=2) { - int stationPhi = Integer.parseInt(phis[i]); - double phi = calculatePhi(name, dPhi, stationPhi); - detectors.add(new ATBxDetector(name, zSide*zi, zSide*zo, ri+rpci, ro-rpco, phi, s, w, - zSide*zis, zSide*zos, ws, or, zSide*stationEta, stationPhi)); - if(rpci>0.) - detectors.add(new ATBxDetector("RPC"+name.substring(3)+"_I", zSide*zi, zSide*zo, ri, - ri+rpci, phi, s, w, zSide*zis, zSide*zos, ws, or, zSide*stationEta, stationPhi)); - if(rpco>0.) - detectors.add(new ATBxDetector("RPC"+name.substring(3)+"_O", zSide*zi, zSide*zo, - ro-rpco, ro, phi, s, w, zSide*zis, zSide*zos, ws, or, zSide*stationEta, stationPhi)); - } - } - - } else if(localName.equals("ATrd")) { - String name=atts.getValue("n"); - double zi=Double.parseDouble(atts.getValue("zi")); - double zo=Double.parseDouble(atts.getValue("zo")); - double ri=Double.parseDouble(atts.getValue("ri")); - double ro=Double.parseDouble(atts.getValue("ro")); - - double wi=Double.parseDouble(atts.getValue("wi")); - double wo=Double.parseDouble(atts.getValue("wo")); - double dPhi=Double.parseDouble(atts.getValue("dphi")); - double alpha=Double.parseDouble(atts.getValue("a")); - int stationEta=Integer.parseInt(atts.getValue("eta")); - String[] phis=atts.getValue("phi").split(" "); - - for(int i=0; i<phis.length; ++i) { - for(int zSide = -1; zSide <= 1; zSide += 2) { - int stationPhi = Integer.parseInt(phis[i]); - double phi = calculatePhi(name, dPhi, stationPhi); - detectors.add(new ATrapezoidDetector(name, zSide*zi, zSide*zo, ri, ro, phi, wi, wo, - alpha, zSide*stationEta, stationPhi)); - } - } - } else if(localName.equals("ABarrelCalorimeter")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int sampling = Integer.parseInt(atts.getValue("sampling")); - int region = Integer.parseInt(atts.getValue("region")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - double eta0 = Double.parseDouble(atts.getValue("eta0")); - double deta = Double.parseDouble(atts.getValue("deta")); - int neta = Integer.parseInt(atts.getValue("neta")); - int meta = Integer.parseInt(atts.getValue("meta")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - detectors.add(new ABarrelCalorimeterDetector(name, color, sampling, region, rMin, rMax, - zMin, zMax, eta0, deta, neta, meta, phi0, nphi)); - } else if(localName.equals("AEndcapCalorimeter")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int sampling = Integer.parseInt(atts.getValue("sampling")); - int region = Integer.parseInt(atts.getValue("region")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - double eta0 = Double.parseDouble(atts.getValue("eta0")); - double deta = Double.parseDouble(atts.getValue("deta")); - int neta = Integer.parseInt(atts.getValue("neta")); - int meta = Integer.parseInt(atts.getValue("meta")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - detectors.add(new AEndcapCalorimeterDetector(name, color, sampling, region, rMin, rMax, - zMin, zMax, eta0, deta, neta, meta, phi0, nphi)); - } else if(localName.equals("AEndcapCryostat")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int sampling = Integer.parseInt(atts.getValue("sampling")); - int region = Integer.parseInt(atts.getValue("region")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - int neta = Integer.parseInt(atts.getValue("neta")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - detectors.add(new AEndcapCryostatDetector(name, color, sampling, region, rMin, rMax, zMin, - zMax, neta, nphi)); - } else if(localName.equals("AGapCalorimeter")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int sampling = Integer.parseInt(atts.getValue("sampling")); - int region = Integer.parseInt(atts.getValue("region")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - int eta = Integer.parseInt(atts.getValue("eta")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - detectors.add(new AGapCalorimeterDetector(name, color, sampling, region, rMin, rMax, - zMin, zMax, eta, phi0, nphi)); - } else if(localName.equals("ABarrelSiliconDetector")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int layer = Integer.parseInt(atts.getValue("layer")); - double length = Double.parseDouble(atts.getValue("length")); - double width = Double.parseDouble(atts.getValue("width")); - double thickness = Double.parseDouble(atts.getValue("thickness")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - int nz = Integer.parseInt(atts.getValue("nz")); - double tilt = Double.parseDouble(atts.getValue("tilt")); - double r0 = Double.parseDouble(atts.getValue("r0")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - detectors.add(new ABarrelSiliconDetector(name, color, layer, length, width, thickness, nz, - nphi, tilt, r0, phi0, zMin, zMax)); - } else if(localName.equals("AEndcapSiliconDetector")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int layer = Integer.parseInt(atts.getValue("layer")); - double length = Double.parseDouble(atts.getValue("length")); - double width = Double.parseDouble(atts.getValue("width")); - double thickness = Double.parseDouble(atts.getValue("thickness")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - int nz = Integer.parseInt(atts.getValue("nz")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - detectors.add(new AEndcapSiliconDetector(name, color, layer, length, width, thickness, nz, - nphi, rMin, rMax, phi0, zMin, zMax)); - } else if(localName.equals("ABarrelTRTDetector")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int layer = Integer.parseInt(atts.getValue("layer")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double phiIn = Double.parseDouble(atts.getValue("phiIn")); - double phiOut = Double.parseDouble(atts.getValue("phiOut")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - detectors.add(new ABarrelTRTDetector(name, color, layer, nphi, rMin, rMax, phiIn, phiOut, zMin, zMax)); - } else if(localName.equals("AEndcapTRTDetector")) { - String name = atts.getValue("n"); - String color = atts.getValue("c"); - int layer = Integer.parseInt(atts.getValue("layer")); - int nphi = Integer.parseInt(atts.getValue("nphi")); - double rMin = Double.parseDouble(atts.getValue("rMin")); - double rMax = Double.parseDouble(atts.getValue("rMax")); - double phi0 = Double.parseDouble(atts.getValue("phi0")); - double zMin = Double.parseDouble(atts.getValue("zMin")); - double zMax = Double.parseDouble(atts.getValue("zMax")); - detectors.add(new AEndcapTRTDetector(name, color, layer, nphi, rMin, rMax, phi0, zMin, zMax)); - } else if(localName.equals("ADisc")) { - String name=atts.getValue("n"); - String projection=atts.getValue("p"); - String color=atts.getValue("c"); - double rInner=Double.parseDouble(atts.getValue("rIn")); - double rOuter=Double.parseDouble(atts.getValue("rOut")); - int nInner=Integer.parseInt(atts.getValue("nIn")); - int nOuter=Integer.parseInt(atts.getValue("nOut")); - - detectors.add(new ADiscDetector(name, projection, color, rInner, rOuter, nInner, nOuter)); - } else if(localName.equals("ARectangle")) { - String name=atts.getValue("n"); - String projection=atts.getValue("p"); - String color=atts.getValue("c"); - double xMin=Double.parseDouble(atts.getValue("xMin")); - double xMax=Double.parseDouble(atts.getValue("xMax")); - double yMin=Double.parseDouble(atts.getValue("yMin")); - double yMax=Double.parseDouble(atts.getValue("yMax")); - boolean xReflect=atts.getValue("xR").equals("YES"); - boolean yReflect=atts.getValue("yR").equals("YES"); - - detectors.add(new ARectangleDetector(name, projection, color, xMin, xMax, yMin, yMax)); - if(xReflect) detectors.add(new ARectangleDetector(name, projection, color, -xMin, -xMax, yMin, - yMax)); - if(yReflect) detectors.add(new ARectangleDetector(name, projection, color, xMin, xMax, -yMin, - -yMax)); - if(xReflect&&yReflect) detectors.add(new ARectangleDetector(name, projection, color, -xMin, - -xMax, -yMin, -yMax)); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ARectangleDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ARectangleDetector.java deleted file mode 100755 index 3af8f2f9b90..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ARectangleDetector.java +++ /dev/null @@ -1,49 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.utils.AMath; - -public class ARectangleDetector extends ADetector -{ - double xMin; - double xMax; - double yMin; - double yMax; - - ARectangleDetector(String name, String projection, String color, double xMin, double xMax, double yMin, double yMax) - { - super(name, projection, color); - this.xMin = xMin; - this.xMax = xMax; - this.yMin = yMin; - this.yMax = yMax; - } - - protected ACoord getRZUser() - { - return getUser("RZ"); - } - - protected ACoord getFZUser() - { - return getUser("FZ"); - } - - protected ACoord getXZUser() - { - return getUser("XZ"); - } - - protected ACoord getYZUser() - { - return getUser("YZ"); - } - - protected ACoord getUser(String proj) - { - if (!projection.equals(proj)) - return ACoord.NO_DATA; - return new ACoord(AMath.xBox((xMin + xMax) / 2., (xMax - xMin) / 2.), AMath.yBox((yMin + yMax) / 2., (yMax - yMin) / 2.)); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ATBxDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ATBxDetector.java deleted file mode 100755 index e4c3dc8204e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ATBxDetector.java +++ /dev/null @@ -1,81 +0,0 @@ -package atlantis.geometry; - -import atlantis.graphics.ACoord; -import atlantis.utils.AMath; - -/** - * Special t shape Box used for MDT chambers near the feet. - * These are only different in th FZ projection - */ - -public class ATBxDetector extends ABoxDetector { - - double zis; - double zos; - double ws; - double or; - - public ATBxDetector(String name, double zMin, double zMax, double rMin, - double rMax, double phi, double excl, double size, double zis, double zos, - double ws, double or, int etaIndex, int phiIndex) { - super(name, zMin, zMax, rMin, rMax, phi, excl, size, etaIndex, phiIndex); - this.zis=zis; - this.zos=zos; - this.ws=ws; - this.or=or; - } - - protected ACoord getFZUser() { - double[][] hv=new double[2][8]; - double cosPhi=Math.cos(phi); - double sinPhi=Math.sin(phi); - double d=size/2.; - double r=rMin; - double x=r*cosPhi-excl*sinPhi; - double y=r*sinPhi+excl*cosPhi; - double dsinPhi=d*sinPhi; - double dcosPhi=d*cosPhi; - double phi1=Math.toDegrees(Math.atan2(y-dcosPhi, x+dsinPhi)); - double phi2=Math.toDegrees(Math.atan2(y+dcosPhi, x-dsinPhi)); - - if(phi1<0.) phi1+=360.; - if(phi2<0.) phi2+=360.; - if(phi1-phi2>180.) phi1-=360.; - if(phi2-phi1>180.) phi2-=360.; - double phiLower=Math.min(phi1, phi2); - double phiUpper=Math.max(phi1, phi2); - double phiMid=phiLower+ws/size*(phiUpper-phiLower); - hv[0][0]=zMin; - hv[0][1]=zMin; - hv[0][2]=zis; - hv[0][3]=zis; - hv[0][4]=zos; - hv[0][5]=zos; - hv[0][6]=zMax; - hv[0][7]=zMax; - if(or>90.) { - phiMid=phiLower+ws/size*(phiUpper-phiLower); - hv[1][0]=phiUpper; - hv[1][1]=phiMid; - hv[1][2]=phiMid; - hv[1][3]=phiLower; - hv[1][4]=phiLower; - hv[1][5]=phiMid; - hv[1][6]=phiMid; - hv[1][7]=phiUpper; - } else { - phiMid=phiUpper-ws/size*(phiUpper-phiLower); - hv[1][0]=phiLower; - hv[1][1]=phiMid; - hv[1][2]=phiMid; - hv[1][3]=phiUpper; - hv[1][4]=phiUpper; - hv[1][5]=phiMid; - hv[1][6]=phiMid; - hv[1][7]=phiLower; - } - - return new ACoord(hv); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetector.java b/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetector.java deleted file mode 100755 index 7850795a05c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetector.java +++ /dev/null @@ -1,211 +0,0 @@ -package atlantis.geometry; - - -import atlantis.utils.AMath; -import atlantis.parameters.*; -import atlantis.graphics.ACoord; - -/** - * In ATLAS Trapezoids are TGC and MDT in the endcap. - */ - -public class ATrapezoidDetector extends ADetector { - - double zMin; - double zMax; - double rMin; - double rMax; - double phi; - double sizeS; - double sizeL; - double alpha; - int stationEta; - int stationPhi; - int sector; - - public ATrapezoidDetector(String name, double zMin, double zMax, double rMin, - double rMax, double phi, double sizeS, double sizeL, - double alpha, int stationEta, int stationPhi) { - super(name, " ", name.substring(0, 3)); - this.zMin = zMin; - this.zMax = zMax; - this.rMin = rMin; - this.rMax = rMax; - this.phi = phi; - this.sizeS = sizeS; - this.sizeL = sizeL; - this.alpha = alpha; - this.stationEta = stationEta; - this.stationPhi = stationPhi; - this.sector = ( (int) ( (phi + Math.PI / 16) / (Math.PI / 8))) % 16; - } - - protected boolean equalsYX(ADetector o) { - if (o instanceof ATrapezoidDetector) { - ATrapezoidDetector that = (ATrapezoidDetector) o; - return this.rMin == that.rMin && - this.rMax == that.rMax && - this.phi == that.phi && - this.sizeS == that.sizeS && - this.sizeL == that.sizeL; - } else - return false; - } - - protected boolean equalsRZ(ADetector o) { - if (o instanceof ATrapezoidDetector) { - ATrapezoidDetector that = (ATrapezoidDetector) o; - return this.rMin == that.rMin && - this.rMax == that.rMax && - this.zMin == that.zMin && - this.zMax == that.zMax && - this.alpha == that.alpha; - } - else - return false; - } - - protected ACoord getRZUser() { - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi - phiMid); - double sign = -1.; - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) - sign = +1.; - return getXZRZUser(sign); - } - - protected ACoord getXZUser() { - AParameter p=parameterStore.get("XZ", "Phi"); - - // display muon data when phi is in the middle of a sector - if(p.getD() % 22.5 < 1e-2) { - int sect=(int)Math.round((p.getD() % 360.) / 22.5); - if (sector == sect) { - return getXZRZUser(1.); - } - else if (sector == sect - 8 || sector == sect + 8) { - return getXZRZUser( -1.); - } - } - return ACoord.NO_DATA; - } - - protected ACoord getXZRZUser(double sign) { - if (alpha == 0.) { - return new ACoord( - AMath.xBox( (zMin + zMax) / 2., (zMax - zMin) / 2.), - AMath.yBox(sign * (rMin + rMax) / 2., sign * (rMax - rMin) / 2.)); - } - else { - double[][] hv = new double[2][]; - double zMid = (zMin + zMax) / 2.; - double rMid = (rMin + rMax) / 2.; - double dRho = (rMax - rMin) / 2; - double dZ = (zMax - zMin) / 2; - double sinAlpha = Math.sin(Math.toRadians(alpha)); - double cosAlpha = Math.cos(Math.toRadians(alpha)); - - if (zMid * rMid > 0.) - sinAlpha *= -1.; - - hv[0] = new double[] { - zMid - sinAlpha * dRho - cosAlpha * dZ, - zMid - sinAlpha * dRho + cosAlpha * dZ, - zMid + sinAlpha * dRho + cosAlpha * dZ, - zMid + sinAlpha * dRho - cosAlpha * dZ}; - hv[1] = new double[] { - sign * (rMid + cosAlpha * dRho - sinAlpha * dZ), - sign * (rMid + cosAlpha * dRho + sinAlpha * dZ), - sign * (rMid - cosAlpha * dRho + sinAlpha * dZ), - sign * (rMid - cosAlpha * dRho - sinAlpha * dZ)}; - return new ACoord(hv); - } - } - - protected ACoord getFZUser() { - double deltaPhi = Math.max(Math.atan2(sizeL / 2., rMax), - Math.atan2(sizeS / 2., rMin)); - - if (alpha == 0.) { - return new ACoord( - AMath.xBox( (zMin + zMax) / 2., (zMax - zMin) / 2.), - AMath.yBox( Math.toDegrees(phi), Math.toDegrees(deltaPhi) )); - } - else { - double[][] hv = new double[2][]; - double zMid = (zMin + zMax) / 2.; - double rMid = (rMin + rMax) / 2.; - double dRho = (rMax - rMin) / 2; - double dZ = (zMax - zMin) / 2; - double sinAlpha = Math.sin(Math.toRadians(alpha)); - double cosAlpha = Math.cos(Math.toRadians(alpha)); - - if (zMid * rMid > 0.) - sinAlpha *= -1.; - - hv[0] = new double[] { - zMid - sinAlpha * dRho - cosAlpha * dZ, - zMid - sinAlpha * dRho - cosAlpha * dZ, - zMid + sinAlpha * dRho + cosAlpha * dZ, - zMid + sinAlpha * dRho + cosAlpha * dZ}; - hv[1] = new double[] { - Math.toDegrees(phi - deltaPhi), - Math.toDegrees(phi + deltaPhi), - Math.toDegrees(phi + deltaPhi), - Math.toDegrees(phi - deltaPhi)}; - return new ACoord(hv); - } - } - - protected ACoord getYXUser() { - return getYXUser(0); - } - - protected ACoord getFRUser() { - return convertYXToFR(getYXUser(1)); - } - - private ACoord getYXUser(int flag) { - int[] split= {12, 1, 12, 1}; - int numPoints=4; - boolean splitIt=parameterStore.get("YX", "FishEye").getStatus()||parameterStore.get("YX", "Clock").getStatus() - ||flag==1; - - if(splitIt) - numPoints=26; - double[] temp=new double[4]; - double[][] hv=new double[2][numPoints]; - double cosPhi=Math.cos(phi); - double sinPhi=Math.sin(phi); - double d=sizeS/2.; - double r=rMin; - double x=r*cosPhi; - double y=r*sinPhi; - double dx=d*sinPhi; - double dy=d*cosPhi; - - hv[0][0]=x+dx; - hv[1][0]=y-dy; - hv[0][1]=x-dx; - hv[1][1]=y+dy; - r=rMax; - x=r*cosPhi; - y=r*sinPhi; - d=sizeL/2.; - dx=d*sinPhi; - dy=d*cosPhi; - - hv[0][3]=x+dx; - hv[1][3]=y-dy; - hv[0][2]=x-dx; - hv[1][2]=y+dy; - if(splitIt) - for(int j=0; j<2; ++j) { - for(int k=0; k<4; ++k) - temp[k]=hv[j][k]; - AMath.splitArrayIntoPieces(temp, hv[j], split); - } - return new ACoord(hv); - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetectors.java b/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetectors.java deleted file mode 100755 index 943c34722fa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/ATrapezoidDetectors.java +++ /dev/null @@ -1,163 +0,0 @@ -package atlantis.geometry; - -// not quite correct for CSC (alpha!=0.) in YX and FR - -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import java.util.*; - -/** - * see comments in ABoxDetectors - */ - -public final class ATrapezoidDetectors extends ADetectors { - - private int numRZTypes; - private int[] typeRZ; - private int numYXTypes; - private int[] typeYX; - - private ATrapezoidDetector[] trapezoid; - - public ATrapezoidDetectors(List detectors) { - super(filterTrapezoidDetectors(detectors)); - trapezoid= new ATrapezoidDetector[det.length]; - for(int i=0;i<trapezoid.length;++i) - trapezoid[i]=(ATrapezoidDetector)det[i]; - - - typeYX=new int[numData]; - for(int i=0; i<numData; ++i) - typeYX[i]=-1; - - numYXTypes=0; - for(int i=0; i<numData; ++i) - if(typeYX[i]==-1) { - typeYX[i]=numYXTypes; - for(int j=i+1; j<numData; ++j) - if(typeYX[j]==-1&&det[i].equalsYX(det[j])) - typeYX[j]=numYXTypes; - numYXTypes++; - } - - typeRZ=new int[numData]; - for(int i=0; i<numData; ++i) - typeRZ[i]=-1; - - numRZTypes=0; - for(int i=0; i<numData; ++i) - if(typeRZ[i]==-1) { - typeRZ[i]=numRZTypes; - for(int j=i+1; j<numData; ++j) - if(typeRZ[j]==-1&&det[i].equalsRZ(det[j])) - typeRZ[j]=numRZTypes; - numRZTypes++; - } - } - - private static ADetector[] filterTrapezoidDetectors(List detectors) { - - List tempDetectors=new ArrayList(detectors.size()); - Iterator it=detectors.iterator(); - - while(it.hasNext()) { - Object o=it.next(); - if(o instanceof ATrapezoidDetector) tempDetectors.add(o); - } - return (ADetector[])tempDetectors.toArray(new ADetector[tempDetectors.size()]); - } - - private void makeDrawListYX() { - int mode=parameterStore.get("YX", "Mode").getI(); - - if(mode==0) - numDraw=0; - else { - int num=0; - for(int i=0; i<numData; ++i) { - double z=trapezoid[i].zMin; - String name=det[i].getName().substring(4, 6); - if(z>0.) - if((mode==1&&name.equals("T4"))||(mode==2&&name.equals("T1")) - ||(mode==3&&name.equals("T2"))||(mode==4&&name.equals("T3")) - ||(mode==5&&(name.equals("EI")||name.equals("CS")))||(mode==6&&name.equals("EE")) - ||(mode==7&&name.equals("EM"))||(mode==8&&name.equals("EO"))) - listdl[num++]=i; - numDraw=num; - } - } - } - - private void makeDrawListXZ() { - AParameter p=parameterStore.get("XZ", "Phi"); - - // display muon data when phi is in the middle of a sector - if(p.getD() % 22.5 < 1e-2) { - int sect=(int)Math.round((p.getD() % 360.) / 22.5); - int num=0; - for(int i=0; i<numData; i++) { - int s=trapezoid[i].sector; - - if(s==sect||s==sect-8||s==sect+8) { - listdl[num++]=i; - } - } - numDraw=num; - } else { - numDraw=0; - } - } - - private void makeDrawListRZ() { - // first make the draw list - // for each type find out if it has both +ve and negative sign - int[] pos=new int[typeRZ.length]; - int[] neg=new int[typeRZ.length]; - double phiMid=Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - for(int i=0; i<numRZTypes; ++i) - neg[i]=pos[i]=-1; - - for(int i=0; i<numData; ++i) { - double phiDiff=Math.abs(trapezoid[i].phi-phiMid); - - if(phiDiff<Math.PI/2.||phiDiff>3*Math.PI/2.) - pos[typeRZ[i]]=i; - else - neg[typeRZ[i]]=i; - } - - int num=0; - for(int i=0; i<numRZTypes; ++i) { - if(pos[i]!=-1) - listdl[num++]=pos[i]; - if(neg[i]!=-1) - listdl[num++]=neg[i]; - } - numDraw=num; - } - - private void makeDrawListFZ() { - if(parameterStore.get("FZ", "Mode").getI()==0) { - constructDefaultDrawList(); - } else { - numDraw=0; - } - } - - protected void makeDrawList(String projection) { - if (projection.equals("YX") || projection.equals("FR") ) - makeDrawListYX(); - else if (projection.equals("FZ")) - makeDrawListFZ(); - else if (projection.equals("RZ")) - makeDrawListRZ(); - else if (projection.equals("XZ")) - makeDrawListXZ(); - else - numDraw=0; - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/geometry/package.html b/graphics/AtlantisJava/src/atlantis/geometry/package.html deleted file mode 100644 index 8c66987e1f1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/geometry/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head></head> -<body> -<p>Classes handling the detector description - ADetectorSystem -contains the information used to draw detector components on the -screen.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/globals/AGlobals.java b/graphics/AtlantisJava/src/atlantis/globals/AGlobals.java deleted file mode 100644 index ce6bce2447e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/globals/AGlobals.java +++ /dev/null @@ -1,202 +0,0 @@ -/** - * - */ -package atlantis.globals; - -import java.awt.Frame; -import java.awt.GraphicsEnvironment; - - -/** - * Provides access to Atlantis global variables in a slightly less bad way than - * using the main atlantis.Atlantis class. - * - * @author waugh - * - */ -public class AGlobals { - /** The singleton instance. No point in lazy instantiation. */ - private static AGlobals globals = new AGlobals(); - - /** Get the singleton instance */ - public static AGlobals instance() {return globals;} - - /** Prevent instantiation except through singleton accessor. */ - private AGlobals() {} - - /** Normally the directory that Atlantis was loaded from. */ - private String homeDirectory; - - /** The version of AtlantisJava from Svn. */ - private String version; - - /** Flag for displaying HLTAutoKey data. */ - private boolean showHLTAutoKeys = false; - - /** Flag for using simple output, used by Minerva. */ - private int SIMPLE_OUTPUT = 0; - - /** This is the URL that is used as default for "Read events from URL". */ - private String LIVE_POINT_1_EVENTS_URL; - - /** The path to the user's configuration file. */ - private String userConfigFile; - - /** Whether to use OpenGL. */ - private boolean useOpenGL; - - /** Whether we are in demo mode. */ - private boolean demoMode; - - /** Component representing the GUI, if any. */ - private Frame guiFrame; - - /** - * Set the Atlantis home directory, normally the directory that Atlantis was loaded from. - * - * @param homeDirectory the Atlantis home directory - */ - public void setHomeDirectory(String homeDirectory) { - this.homeDirectory = homeDirectory; - } - - /** - * Get the Atlantis home directory, normally the directory that Atlantis was loaded from. - * - * @return the Atlantis home directory - */ - public String getHomeDirectory() { - return homeDirectory; - } - - /** - * Get AtlantisJava version. - * @return the Svn version, set in Atlantis.main() - */ - public String getVersion() { - return version; - } - - /** - * Set AtlantisJava version, called from Atlantis.main(). - * @param version the version to set - */ - public void setVersion(String version) { - this.version = version; - } - - /** - * Whether to show data with storeGateKey containing "HLTAutoKey". - * - * @return true to show, false to ignore - */ - public boolean showHLTAutoKeys() { - return showHLTAutoKeys; - } - - /** - * Whether to show data with storeGateKey containing "HLTAutoKey". - * - * @param showHLTAutoKeys true to show, false to ignore - */ - public void setHLTAutoKeys(boolean showHLTAutoKeys) { - this.showHLTAutoKeys = showHLTAutoKeys; - } - - /** - * @return the sIMPLE_OUTPUT - */ - public int getSimpleOutput() { - return SIMPLE_OUTPUT; - } - - /** - * @param sIMPLE_OUTPUT the sIMPLE_OUTPUT to set - */ - public void setSimpleOutput(int sIMPLE_OUTPUT) { - SIMPLE_OUTPUT = sIMPLE_OUTPUT; - } - - /** - * @return the URL for the Point 1 live events server - */ - public String getLivePoint1EventsURL() { - return LIVE_POINT_1_EVENTS_URL; - } - - /** - * @param livePoint1EventsURL the URL for the Point 1 live events server - */ - public void setLivePoint1EventsURL(String livePoint1EventsURL) { - LIVE_POINT_1_EVENTS_URL = livePoint1EventsURL; - } - - /** - * @param userConfigFilePath the path to the user's configuration file - */ - public void setUserConfigFile(String userConfigFilePath) { - this.userConfigFile = userConfigFilePath; - } - - /** - * @return the path to the user's configuration file - */ - public String getUserConfigFile() { - return this.userConfigFile; - } - - /** - * @return true if we should be using OpenGL - */ - public boolean getUseOpenGL() { - return useOpenGL; - } - - /** - * @param useOpenGL true to use OpenGL, false otherwise - */ - public void setUseOpenGL(boolean useOpenGL) { - this.useOpenGL = useOpenGL; - } - - /** - * Check whether we are in headless mode - * @return true if headless (no graphics available) - */ - public static boolean isAtlantisHeadless() { - return GraphicsEnvironment.isHeadless(); - } - - /** - * Whether the demo mode loop is running. - * @return true if in demo mode - */ - public boolean isDemoMode() { - return demoMode; - } - - /** - * Signal whether the demo loop is running. - * @param demoMode true when starting loop, false when stopping - */ - public void setDemoMode(boolean demoMode) { - this.demoMode = demoMode; - } - - /** - * For use as parent of dialogues, avoiding dependency on AGUI class itself. - * @return the GUI frame - */ - public Frame getGuiFrame() { - return guiFrame; - } - - /** - * Set the GUI frame, called from AGUI when the instance is created. - * @param guiFrame the GUI frame - */ - public void setGuiFrame(Frame guiFrame) { - this.guiFrame = guiFrame; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/globals/package.html b/graphics/AtlantisJava/src/atlantis/globals/package.html deleted file mode 100644 index e763965d1af..00000000000 --- a/graphics/AtlantisJava/src/atlantis/globals/package.html +++ /dev/null @@ -1,13 +0,0 @@ -<html> -<head></head> -<body> -<p>Provides access to Atlantis global variables.</p> -<p>This has been introduced as part of a process of breaking unwanted - dependencies between packages. This package can contain any required - global state so that other packages (atlantis.data etc.) do not need - to depend on the "atlantis" package that contains the main Atlantis - class, and which unavoidably depends on the rest of the - packages.</p> -<p>With luck this will prove not to be necessary in the long term!</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AAbstractGraphics2D.java b/graphics/AtlantisJava/src/atlantis/graphics/AAbstractGraphics2D.java deleted file mode 100755 index ddfeba3edb9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AAbstractGraphics2D.java +++ /dev/null @@ -1,315 +0,0 @@ -package atlantis.graphics; - -import java.awt.*; -import java.awt.font.*; -import java.awt.geom.*; -import java.awt.image.*; -import java.awt.image.renderable.*; - -/** - * This graphics is used when nothing should really be drawn on the screen - */ - -public abstract class AAbstractGraphics2D extends Graphics2D { - - public void transform(AffineTransform z) { - if(true) throw new RuntimeException(); - } - - public void fill(Shape z) { - if(true) throw new RuntimeException(); - } - - public void draw(Shape z) { - if(true) throw new RuntimeException(); - } - - public void drawImage(BufferedImage a, BufferedImageOp b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public boolean drawImage(Image a, AffineTransform b, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public void drawRenderedImage(RenderedImage a, AffineTransform z) { - if(true) throw new RuntimeException(); - } - - public void drawRenderableImage(RenderableImage a, AffineTransform z) { - if(true) throw new RuntimeException(); - } - - public void drawString(java.text.AttributedCharacterIterator a, float b, float z) { - if(true) throw new RuntimeException(); - } - - public void drawString(String a, int b, int z) { - if(true) throw new RuntimeException(); - } - - public void drawString(String a, float b, float z) { - if(true) throw new RuntimeException(); - } - - public void drawString(java.text.AttributedCharacterIterator a, int b, int z) { - if(true) throw new RuntimeException(); - } - - public void drawGlyphVector(GlyphVector a, float b, float z) { - if(true) throw new RuntimeException(); - } - - public boolean hit(Rectangle a, Shape b, boolean z) { - if(true) throw new RuntimeException(); - return false; - } - - public GraphicsConfiguration getDeviceConfiguration() { - if(true) throw new RuntimeException(); - return null; - } - - public void setComposite(Composite z) { - if(true) throw new RuntimeException(); - } - - public void setPaint(Paint z) { - if(true) throw new RuntimeException(); - } - - public void setStroke(Stroke z) { - if(true) throw new RuntimeException(); - } - - public void setRenderingHint(RenderingHints.Key a, Object z) { - if(true) throw new RuntimeException(); - } - - public Object getRenderingHint(RenderingHints.Key z) { - if(true) throw new RuntimeException(); - return null; - } - - public void setRenderingHints(java.util.Map z) { - if(true) throw new RuntimeException(); - } - - public void addRenderingHints(java.util.Map z) { - if(true) throw new RuntimeException(); - } - - public RenderingHints getRenderingHints() { - if(true) throw new RuntimeException(); - return null; - } - - public void translate(double a, double z) { - if(true) throw new RuntimeException(); - } - - public void translate(int a, int z) { - if(true) throw new RuntimeException(); - } - - public void rotate(double a, double b, double z) { - if(true) throw new RuntimeException(); - } - - public void rotate(double z) { - if(true) throw new RuntimeException(); - } - - public void scale(double a, double z) { - if(true) throw new RuntimeException(); - } - - public void shear(double a, double z) { - if(true) throw new RuntimeException(); - } - - public void setTransform(AffineTransform z) { - if(true) throw new RuntimeException(); - } - - public AffineTransform getTransform() { - if(true) throw new RuntimeException(); - return null; - } - - public Paint getPaint() { - if(true) throw new RuntimeException(); - return null; - } - - public Composite getComposite() { - if(true) throw new RuntimeException(); - return null; - } - - public void setBackground(Color z) { - if(true) throw new RuntimeException(); - } - - public Color getBackground() { - if(true) throw new RuntimeException(); - return null; - } - - public Stroke getStroke() { - if(true) throw new RuntimeException(); - return null; - } - - public void clip(Shape z) { - if(true) throw new RuntimeException(); - } - - public FontRenderContext getFontRenderContext() { - if(true) throw new RuntimeException(); - return null; - } - - public void setColor(Color z) { - if(true) throw new RuntimeException(); - } - - public Graphics create() { - if(true) throw new RuntimeException(); - return null; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, int f, int g, int h, int i, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public boolean drawImage(Image a, int b, int c, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public boolean drawImage(Image a, int b, int c, Color d, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, Color f, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, int f, int g, int h, int i, Color j, ImageObserver z) { - if(true) throw new RuntimeException(); - return false; - } - - public Color getColor() { - if(true) throw new RuntimeException(); - return null; - } - - public void fillRect(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void setPaintMode() { - if(true) throw new RuntimeException(); - } - - public void setXORMode(Color z) { - if(true) throw new RuntimeException(); - } - - public Font getFont() { - if(true) throw new RuntimeException(); - return null; - } - - public void setFont(Font z) { - if(true) throw new RuntimeException(); - } - - public FontMetrics getFontMetrics(Font z) { - if(true) throw new RuntimeException(); - return null; - } - - public Rectangle getClipBounds() { - if(true) throw new RuntimeException(); - return null; - } - - public void clipRect(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void setClip(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void setClip(Shape z) { - if(true) throw new RuntimeException(); - } - - public Shape getClip() { - if(true) throw new RuntimeException(); - return null; - } - - public void copyArea(int a, int b, int c, int d, int e, int z) { - if(true) throw new RuntimeException(); - } - - // public void drawLine(int a,int b,int c,int z) { if (true) throw new RuntimeException(); } - public void clearRect(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void drawRoundRect(int a, int b, int c, int d, int e, int z) { - if(true) throw new RuntimeException(); - } - - public void fillRoundRect(int a, int b, int c, int d, int e, int z) { - if(true) throw new RuntimeException(); - } - - public void drawOval(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void fillOval(int a, int b, int c, int z) { - if(true) throw new RuntimeException(); - } - - public void drawArc(int a, int b, int c, int d, int e, int z) { - if(true) throw new RuntimeException(); - } - - public void fillArc(int a, int b, int c, int d, int e, int z) { - if(true) throw new RuntimeException(); - } - - public void drawPolyline(int[] a, int[] b, int z) { - if(true) throw new RuntimeException(); - } - - public void drawPolygon(int[] a, int[] b, int z) { - if(true) throw new RuntimeException(); - } - - public void fillPolygon(int[] a, int[] b, int z) { - if(true) throw new RuntimeException(); - } - - public void dispose() { - if(true) throw new RuntimeException(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AClipper.java b/graphics/AtlantisJava/src/atlantis/graphics/AClipper.java deleted file mode 100755 index c525102c702..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AClipper.java +++ /dev/null @@ -1,226 +0,0 @@ -package atlantis.graphics; - -import atlantis.utils.AClipPolygon; -import atlantis.utils.APolygon; -import java.awt.Rectangle; - - -/** - * Implement uniform treatment of Clipping for screen, - * postscript and picking. - */ - -public class AClipper { - double[] upper; - double[] lower; - double[][] x; - boolean[][] below; - boolean[][] within; - boolean[][] above; - double hLower; - double hUpper; - double vLower; - double vUpper; - - public static final int NONE_WITHIN=0; - public static final int MAYBE_WITHIN=1; - public static final int ALL_WITHIN=2; - - public AClipper(double hLower, double hUpper, double vLower, double vUpper) { - - x=new double[2][2]; - upper=new double[2]; - lower=new double[2]; - below=new boolean[2][2]; - within=new boolean[2][2]; - above=new boolean[2][2]; - upper[0]=hUpper; - upper[1]=vUpper; - lower[0]=hLower; - lower[1]=vLower; - this.hUpper=hUpper; - this.hLower=hLower; - this.vUpper=vUpper; - this.vLower=vLower; - } - - public AClipper(Rectangle clipBounds) { - this(clipBounds.getX(), clipBounds.getX()+clipBounds.getWidth(), clipBounds.getY(), - clipBounds.getY()+clipBounds.getHeight()); - } - - public boolean isPointWithin(double h0, double v0) { - return hLower<=h0&&h0<=hUpper&&vLower<=v0&&v0<=vUpper; - } - - public boolean isLineWithin(double h0, double v0, double h1, double v1) { - int roughCheck=fastWithin(h0, v0, h1, v1); - - if(roughCheck==0) return false; - x[0][0]=h0; - x[1][0]=v0; - x[0][1]=h1; - x[1][1]=v1; - if(roughCheck==2) return true; - - update(0); - update(1); - - outer: - while(!lineFullyInside()) { - if(lineFullyOutside()) return false; - - for(int i=0; i<2; i++) - for(int point=0; point<2; point++) { - if(!within[i][point]) { - if(below[i][point]) { - x[1-i][point]+=((x[1-i][1-point]-x[1-i][point])/(x[i][1-point]-x[i][point])) - *(lower[i]-x[i][point]); - x[i][point]=lower[i]; - } else if(above[i][point]) { - x[1-i][point]+=((x[1-i][1-point]-x[1-i][point])/(x[i][1-point]-x[i][point])) - *(upper[i]-x[i][point]); - x[i][point]=upper[i]; - } - update(point); - continue outer; - } - } - } - // don't allow non-zero length line to be given zero length - // by th clipper - if((x[0][0]==x[0][1])&&(x[1][0]==x[1][1])) - return false; - return true; - } - - private void update(int p) { - for(int i=0; i<2; i++) { - below[i][p]=false; - within[i][p]=false; - above[i][p]=false; - if(x[i][p]<lower[i]) - below[i][p]=true; - else if(x[i][p]>upper[i]) - above[i][p]=true; - else - within[i][p]=true; - } - } - - public boolean lineFullyInside() { - boolean inside=true; - - for(int i=0; i<2; i++) - for(int j=0; j<2; j++) - inside=inside&&within[i][j]; - return inside; - } - - public boolean lineFullyOutside() { - boolean outside=false; - - for(int i=0; i<2; i++) { - outside=outside||(below[i][0]&&below[i][1]); - outside=outside||(above[i][0]&&above[i][1]); - } - return outside; - } - - public double[][] getHV() { - return x; - } - - public double getH0() { - return x[0][0]; - } - - public double getV0() { - return x[1][0]; - } - - public double getH1() { - return x[0][1]; - } - - public double getV1() { - return x[1][1]; - } - - public int fastWithin(double h0, double v0, double h1, double v1) { - if(h0<hLower&&h1<hLower) return NONE_WITHIN; - if(h0>hUpper&&h1>hUpper) return NONE_WITHIN; - if(v0<vLower&&v1<vLower) return NONE_WITHIN; - if(v0>vUpper&&v1>vUpper) return NONE_WITHIN; - if(hLower<=h0&&h0<=hUpper&&hLower<=h1&&h1<=hUpper&&vLower<=v0&&v0<=vUpper&&vLower<=v1 - &&v1<=vUpper) return ALL_WITHIN; - return MAYBE_WITHIN; - } - - public int fastWithin(double[] h, double[] v, int numPoints) { - if(numPoints==0) return NONE_WITHIN; - boolean firstWithin=hLower<=h[0]&&h[0]<=hUpper&&vLower<=v[0]&&v[0]<=vUpper; - - if(firstWithin) { - for(int i=1; i<numPoints; ++i) - if(!(hLower<=h[i]&&h[i]<=hUpper&&vLower<=v[i]&&v[i]<=vUpper)) return MAYBE_WITHIN; - return ALL_WITHIN; - } else { - if(h[0]<hLower) { - int num=1; - - for(int i=1; i<numPoints; ++i) - if(h[i]<hLower) - num++; - else - break; - if(num==numPoints) return NONE_WITHIN; - } - if(h[0]>hUpper) { - int num=1; - - for(int i=1; i<numPoints; ++i) - if(h[i]>hUpper) - num++; - else - break; - if(num==numPoints) return NONE_WITHIN; - } - if(v[0]<vLower) { - int num=1; - - for(int i=1; i<numPoints; ++i) - if(v[i]<vLower) - num++; - else - break; - if(num==numPoints) return NONE_WITHIN; - } - if(v[0]>vUpper) { - int num=1; - - for(int i=1; i<numPoints; ++i) - if(v[i]>vUpper) - num++; - else - break; - if(num==numPoints) return NONE_WITHIN; - } - return MAYBE_WITHIN; - } - } - - public ACoord clipPolygon(double[] h, double[] v, int numPoints) { - double[] clipH=new double[] { lower[0], upper[0], upper[0], lower[0] }; - double[] clipV=new double[] { lower[1], lower[1], upper[1], upper[1] }; - AClipPolygon clipArea=new AClipPolygon(clipH, clipV); - APolygon badPolygon=new APolygon(h, v); - - badPolygon.clip(clipArea); - h=badPolygon.getX(); - v=badPolygon.getY(); - return new ACoord(h, v); - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ACoord.java b/graphics/AtlantisJava/src/atlantis/graphics/ACoord.java deleted file mode 100755 index 71aa2156379..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ACoord.java +++ /dev/null @@ -1,355 +0,0 @@ -package atlantis.graphics; - -import atlantis.parameters.APar; -import atlantis.utils.*; - -/** - * Used to store a collection of User or display 2D coordinates of hits or tracks - * together with their indices in the corresponding AData - * (used for picking, colors etc.). N.B. the storage model is different for - * SYMBOLS/LINES(with two end points) than for POLYLINES/POLYGONS for - * efficiency reasons. Transformations between user/display coordinaates are based - * on ACoords. - */ -public class ACoord { - - private static ALogger logger = ALogger.getLogger(ACoord.class); - - public double[][][] hv; - public int[] index; - protected int type=POLYGONS; - public ADrawable source; - - final static public int SYMBOLS=1; - final static public int LINES=2; - final static public int POLYLINES=3; - final static public int POLYGONS=4; - final static public int DOTTED_POLYGONS=5; // for drawing missing ET in V-Plot - final static public int SMOOTH_POLYLINES=6; - final static public int TRANSPARENT_POLYGONS=7; - - final static public ACoord NO_DATA=new ACoord(new double[2][0][0], new int[0]); - final static public ACoord NO_POLYGONS=new ACoord(new double[2][0][0], new int[0]); - final static public ACoord NO_POLYLINES=new ACoord(new double[2][0][0], new int[0]); - final static public ACoord[] NO_HISTOGRAMS=new ACoord[0]; - - protected static APar parameterStore = APar.instance(); - - public ACoord(double h, double v, int index) { - this(h, v); - this.index=new int[] {index}; - } - - public ACoord(double h, double v) { - this.hv=new double[2][1][1]; - this.hv[0][0][0]=h; - this.hv[1][0][0]=v; - this.index=null; - this.type=SYMBOLS; - } - - public ACoord(double[] h, double[] v) { - this.hv=new double[2][1][]; - this.hv[0][0]=h; - this.hv[1][0]=v; - this.index=new int[] {0}; - } - - private ACoord(double[][] hv, int[] index) { - if(hv.length!=2) throw new IllegalArgumentException("hv.length="+hv.length); - this.hv = new double[2][1][0]; - this.hv[0][0]=hv[0]; - this.hv[1][0]=hv[1]; - this.index=index; - } - - private ACoord(double[][] hv, int[] index, ADrawable source) { - this(hv, index); - this.source=source; - } - - public ACoord(double[][] hv) { - if(hv.length!=2) throw new IllegalArgumentException("hv.length="+hv.length); - this.hv = new double[2][1][]; - this.hv[0][0]=hv[0]; - this.hv[1][0]=hv[1]; - this.index=null; - } - - public ACoord(double[][][] hv, int[] index) { - if(hv.length!=2) throw new IllegalArgumentException("hv.length="+hv.length); - this.hv=hv; - this.index=index; - } - - public ACoord(double[][][] hv, int[] index, ADrawable source) { - this(hv, index); - this.source=source; - } - - public ACoord(double[][][] hv) { - if(hv.length!=2) throw new IllegalArgumentException("hv.length="+hv.length); - this.hv=hv; - this.index=null; - } - - private ACoord(ACoord a) { - this.hv=new double[a.hv.length][][]; - for(int i=0; i<a.hv.length; i++) { - this.hv[i]=new double[a.hv[i].length][]; - for(int j=0; j<a.hv[i].length; j++) { - this.hv[i][j]=new double[a.hv[i][j].length]; - for(int k=0; k<a.hv[i][j].length; k++) - this.hv[i][j][k]=a.hv[i][j][k]; - } - } - this.index=new int[a.index.length]; - for(int i=0; i<a.index.length; i++) - this.index[i]=a.index[i]; - this.type=a.type; - this.source=a.source; - } - - public ACoord(double[][] hv, int[] index, ADrawable source, int type) { - this(hv, index, source); - this.type=type; - } - - public ACoord(double[][][] hv, int[] index, ADrawable source, int type) { - this(hv, index, source); - this.type=type; - } - - public ACoord(double[] h, double[] v, int[] index, ADrawable source) { - if(h.length!=v.length) - throw new IllegalArgumentException("h.length "+h.length+" !=v.length "+v.length); - if(h.length!=index.length) - throw new IllegalArgumentException("h.length "+h.length+" !=index.length "+index.length); - this.hv=new double[2][1][]; - this.hv[0][0]=h; - this.hv[1][0]=v; - this.index=index; - this.type=SYMBOLS; - this.source=source; - } - - public void print() { - for(int j=0; j<hv[0].length; j++) { - logger.debug(" index = "+index[j]); - for(int i=0; i<2; i++) { - if(i==0) - logger.debug("h "); - else - logger.debug("v "); - for(int k=0; k<hv[0][j].length; k++) - logger.debug((float)hv[i][j][k]+"\t"); - } - } - } - - // careful this does not make an independent copy - public ACoord(ACoord a, ACoord b) { - this.hv=new double[2][a.hv[0].length+b.hv[0].length][]; - this.index=new int[a.hv[0].length+b.hv[0].length]; - this.type=a.type; - this.source=a.source; - - for(int i=0; i<2; i++) { - int num=0; - - for(int j=0; j<a.hv[i].length; j++) { - this.hv[i][num]=a.hv[i][j]; - this.index[num]=a.index[j]; - num++; - } - for(int j=0; j<b.hv[i].length; j++) { - this.hv[i][num]=b.hv[i][j]; - this.index[num]=b.index[j]; - num++; - } - } - } - - public ACoord convertYXToFR() { - if(type==SYMBOLS||type==LINES) { - for(int j=0; j<hv[0][0].length; j++) { - double phiLast=0.; - - for(int i=0; i<hv[0].length; i++) { - double xx=hv[0][i][j]; - double yy=hv[1][i][j]; - double rho=Math.sqrt(xx*xx+yy*yy); - double phi=Math.toDegrees(Math.atan2(yy, xx)); - - if(phi<0.) - phi+=360.; - if(i>0) { - if(phi-phiLast>180.) phi-=360.; - if(phi-phiLast<-180.) phi+=360.; - } - hv[0][i][j]=rho; - hv[1][i][j]=phi; - phiLast=phi; - } - } - - } else { - for(int i=0; i<hv[0].length; i++) { - double phiLast=0.; - - for(int j=0; j<hv[0][i].length; j++) { - double xx=hv[0][i][j]; - double yy=hv[1][i][j]; - double rho=Math.sqrt(xx*xx+yy*yy); - double phi=Math.toDegrees(Math.atan2(yy, xx)); - - if(phi<0.) - phi+=360.; - if(j>0) { - if(phi-phiLast>180.) phi-=360.; - if(phi-phiLast<-180.) phi+=360.; - } - hv[0][i][j]=rho; - hv[1][i][j]=phi; - phiLast=phi; - } - } - } - return this; - } - - public ACoord includePhiWrapAround(String projectionName) { - // assumes phi is always the v coordinaate - int numFrames=parameterStore.get(projectionName, "FramesCount").getI(); - int initialFrame=parameterStore.get(projectionName, "InitialFrame").getI(); - - if(type==SYMBOLS||type==LINES) { - int numPoints=hv[1].length; - int numInitialData=hv[1][0].length; - - double[][][] hvtemp=new double[2][numPoints][numFrames*numInitialData]; - int[] indextemp=new int[numFrames*numInitialData]; - - int num=0; - - for(int f=initialFrame; f<initialFrame+numFrames; f++) { - for(int i=0; i<numInitialData; i++) { - if(index!=null) indextemp[num]=index[i]; - for(int j=0; j<numPoints; ++j) { - hvtemp[0][j][num]=this.hv[0][j][i]; - hvtemp[1][j][num]=this.hv[1][j][i]+f*360.; - } - num++; - } - } - hv=hvtemp; - if (index!=null) index=indextemp; - } else { - int numInitialData=hv[1].length; - double[][][] hvtemp=new double[2][numFrames*numInitialData][]; - int[] indextemp=new int[numFrames*numInitialData]; - - int num=0; - - for(int f=initialFrame; f<initialFrame+numFrames; f++) { - for(int i=0; i<numInitialData; i++) { - int numPoints=hv[1][i].length; - - hvtemp[0][num]=new double[numPoints]; - hvtemp[1][num]=new double[numPoints]; - for(int j=0; j<numPoints; j++) { - hvtemp[0][num][j]=this.hv[0][i][j]; - hvtemp[1][num][j]=this.hv[1][i][j]+f*360.; - } - if (index!=null) indextemp[num]=index[i]; - num++; - } - } - hv=hvtemp; - if (index!=null) index=indextemp; - } - return this; - } - - /** - * used in ATLAS context for the TRT - * Force data to be drawn as symbols if - * forceSymbols=true - * or - * all lines are smaller than minSize - */ - public ACoord toSymbols(boolean forceSymbols, int minSize) { - if(type==LINES) { - double dmax2=0.; - - for(int i=0; i<hv[0][0].length; i++) { - double dh=(hv[0][0][i]-hv[0][1][i]); - double dv=(hv[1][0][i]-hv[1][1][i]); - double d=dh*dh+dv*dv; - - if(d>dmax2) dmax2=d; - } - if(Math.sqrt(dmax2)<minSize||forceSymbols) { - type=SYMBOLS; - for(int i=0; i<hv[0][0].length; i++) { - hv[0][0][i]=(hv[0][0][i]+hv[0][1][i])/2.; - hv[1][0][i]=(hv[1][0][i]+hv[1][1][i])/2.; - } - } - } else if(type==POLYLINES||type==POLYGONS||type==TRANSPARENT_POLYGONS) { - double dmax2=0.; - - for(int j=0; j<hv[0].length; j++) { - for(int i=0; i<hv[0][j].length; i++) { - double dh=(hv[0][j][0]-hv[0][j][i]); - double dv=(hv[1][j][0]-hv[1][j][i]); - double d=dh*dh+dv*dv; - - if(d>dmax2) dmax2=d; - } - } - - if(Math.sqrt(dmax2)<minSize||forceSymbols) { - type=SYMBOLS; - double[][][] hvnew=new double[2][1][hv[0].length]; - - for(int j=0; j<hv[0].length; j++) { - double h=0.; - double v=0.; - - for(int i=0; i<hv[0][j].length; i++) { - h+=hv[0][j][i]; - v+=hv[1][j][i]; - } - h/=hv[0][j].length; - v/=hv[0][j].length; - hvnew[0][0][j]=h; - hvnew[1][0][j]=v; - } - hv=hvnew; - } - } - return this; - } - - public ACoord mirrorH () { - ACoord coord = new ACoord(this); - for(int i=0; i<coord.hv[0].length; i++) { - for(int j=0; j<coord.hv[0][i].length; j++) { - coord.hv[0][i][j] *= -1; - } - } - return coord; - } - - public ACoord mirrorV () { - ACoord coord = new ACoord(this); - for(int i=0; i<coord.hv[1].length; i++) { - for(int j=0; j<coord.hv[1][i].length; j++) { - coord.hv[1][i][j] *= -1; - } - } - return coord; - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ACursorFactory.java b/graphics/AtlantisJava/src/atlantis/graphics/ACursorFactory.java deleted file mode 100755 index 133abd8f8d4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ACursorFactory.java +++ /dev/null @@ -1,227 +0,0 @@ -package atlantis.graphics; - - -import java.awt.Toolkit; -import java.awt.Dimension; -import java.awt.Cursor; -import java.awt.Point; -import java.awt.Image; -import java.awt.dnd.DragSource; - -import atlantis.globals.AGlobals; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; - -/** - * Singleton class factory for producing cursors. - * Due to difference in the default cursors provided by the different OSs, - * all cursors are generated by Atlantis itself. - */ - -public class ACursorFactory { - - private static ALogger logger = ALogger.getLogger(ACursorFactory.class); - - /** singleton class, pointer to this instance */ - private static ACursorFactory instance; - - /** Cursor size string, either "64x64" or "32x32" */ - private String cursorSize; - - /** Cursor color string, either "bw" or "" */ - private String bAndW=""; - - /** - * @return true if if system supports custom cursors - */ - public boolean getCustomCursors() { return customCursors; } - private final boolean customCursors; - - /** - * @return the default Cursor - */ - public Cursor getDefaultCursor() { return defaultCursor; } - private Cursor defaultCursor = null; - - /** Drag-and-drop valid cursor */ - private Cursor dragValidCursor=null; - public Cursor getDragValidCursor() { return dragValidCursor; } - /** Drag-and-drop invalid cursor */ - private Cursor dragInvalidCursor=null; - public Cursor getDragInvalidCursor() { return dragValidCursor; } - - /** Zoom cursor */ - public Cursor getZoomCursor() { return zoomCursor; } - private Cursor zoomCursor=null; - /** Move cursor */ - public Cursor getMoveCursor() { return moveCursor; } - private Cursor moveCursor=null; - /** Rotate cursor */ - public Cursor getRotateCursor() { return rotateCursor; } - private Cursor rotateCursor=null; - - /** Pick cursor */ - public Cursor getPickCursor() { return pickCursor; } - private Cursor pickCursor=null; - /** Rectangular selection cursor */ - public Cursor getRectSelectCursor() { return rectSelectCursor; } - private Cursor rectSelectCursor=null; - - /** Syncro cursor */ - public Cursor getSyncCursor() { return syncCursor; } - private Cursor syncCursor=null; - /** FishEye cursor */ - public Cursor getFishEyeCursor() { return fishEyeCursor; } - private Cursor fishEyeCursor=null; - - /** FishEye symbol also needed as a FishEye on/off indicator */ - public Image getFishEyeIndicator() { return fishEyeIndicator; } - private Image fishEyeIndicator=null; - - /** ATLAS logo can be printed on canvas */ - public Image getAtlasLogo() { return atlasLogo; } - private Image atlasLogo=null; - - /** - * Public singleton instantiation accessor - * @return the singleton instance - */ - public static ACursorFactory getInstance() { - - //Check if we already have an instance - if (instance == null) instance = new ACursorFactory(); - - //Return the singleton instance - return instance; - } - - - /** Constructor */ - private ACursorFactory(){ - - logger.debug("Creating cursor and image factory ..."); - String FILE_SEPAR = System.getProperty("file.separator"); - String homeDirectory = AGlobals.instance().getHomeDirectory(); - - //Provide images and indicators even in headless mode - //Fisheye - String path = homeDirectory + "img" + FILE_SEPAR + - "cursor_fisheye_"+bAndW+"32x32.gif"; - fishEyeIndicator = AUtilities.getFileAsImageIcon(path).getImage(); - - //Atlas logo - path = homeDirectory + "img" + FILE_SEPAR + - "atlas_logo_big.png"; - atlasLogo = AUtilities.getFileAsImageIcon(path).getImage(); - - - //Don't create any cursors in headless mode - if (AGlobals.isAtlantisHeadless()){ - //Custom cursors not supported on this platform - customCursors=false; - return; - } - - //Check for best cursor size on this system - trying largest - Dimension bestCursorSize=Toolkit.getDefaultToolkit().getBestCursorSize(64,64); - - //Check if custom cursors are allowed - if (bestCursorSize.width > 0){ - - customCursors=true; - - //We only support 32x32 and 64x64 cursors. Check which one we are closer to - if (bestCursorSize.width < 48) cursorSize="32x32"; - else cursorSize="64x64"; - - //Check if we have enough colours for greyscale cursors - if (Toolkit.getDefaultToolkit().getMaximumCursorColors() < 255) - bAndW="bw_"; - else bAndW=""; - - logger.info("Using "+bAndW+cursorSize+" cursors"); - - //Now create the individual cursors - Toolkit tools = Toolkit.getDefaultToolkit(); - - - //Drag and drop cursors ----------------------------------------------- - - //Valid DnD - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_DnD_valid_" + cursorSize+ ".gif"; - Image validDnDImg = AUtilities.getFileAsImageIcon(path).getImage(); - - dragValidCursor=tools.createCustomCursor(validDnDImg, new Point(1, 1),"ValidDnD"); - - //Invalid Dnd - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_DnD_invalid_" + cursorSize + ".gif"; - Image invalidDnDImg = AUtilities.getFileAsImageIcon(path).getImage(); - dragInvalidCursor=tools.createCustomCursor(invalidDnDImg,new Point(9, 9),"InvalidDnD"); - - //Zoom, move and rotate cursors ----------------------------------------------- - //Zoom - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_zoom_"+bAndW+cursorSize+".gif"; - Image zoomImg = AUtilities.getFileAsImageIcon(path).getImage(); - zoomCursor=tools.createCustomCursor(zoomImg, new Point(9, 9),"Zoom"); - - //Move - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_move_" + cursorSize+".gif"; - Image moveImg = AUtilities.getFileAsImageIcon(path).getImage(); - moveCursor=tools.createCustomCursor(moveImg,new Point(10, 10),"Move"); - - //Rotate - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_rotate_"+bAndW+cursorSize+".gif"; - Image rotateImg = AUtilities.getFileAsImageIcon(path).getImage(); - rotateCursor=tools.createCustomCursor(rotateImg,new Point(11, 11),"Rotate"); - - //Pick and RectSelect cursors ----------------------------------------------- - //Pick - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_pick_"+cursorSize+".gif"; - Image pickImg = AUtilities.getFileAsImageIcon(path).getImage(); - pickCursor=tools.createCustomCursor(pickImg, new Point(6, 1),"Pick"); - - //Rectangle select - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_rectsel_"+cursorSize+".gif"; - Image rectSelectImg = AUtilities.getFileAsImageIcon(path).getImage(); - rectSelectCursor=tools.createCustomCursor(rectSelectImg,new Point(12, 12),"RectSelect"); - - //Syncro and FishEye cursors ----------------------------------------------------- - //Sync - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_sync_" + cursorSize + ".gif"; - Image syncImg = AUtilities.getFileAsImageIcon(path).getImage(); - syncCursor=tools.createCustomCursor(syncImg, new Point(10, 10),"Sync"); - - //FishEye - path = homeDirectory + "img" + FILE_SEPAR + - "cursor_fisheye_"+bAndW+cursorSize+".gif"; - Image fishEyeImg = AUtilities.getFileAsImageIcon(path).getImage(); - fishEyeCursor=tools.createCustomCursor(fishEyeImg, new Point(1, 8),"FishEye"); - - } else customCursors=false; - - - //Now check for any cursors that have not been set yet - //And set them to system defaults - if (defaultCursor == null) defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR); - - if (dragValidCursor == null) dragValidCursor = DragSource.DefaultMoveDrop; - if (dragInvalidCursor == null) dragInvalidCursor = DragSource.DefaultMoveNoDrop; - - if (zoomCursor == null) zoomCursor = new Cursor(Cursor.DEFAULT_CURSOR); - if (moveCursor == null) moveCursor = new Cursor(Cursor.MOVE_CURSOR); - if (rotateCursor == null) rotateCursor = new Cursor(Cursor.DEFAULT_CURSOR); - - if (pickCursor == null) pickCursor = new Cursor(Cursor.HAND_CURSOR); - if (rectSelectCursor == null) rectSelectCursor = new Cursor(Cursor.NW_RESIZE_CURSOR); - if (syncCursor == null) syncCursor = new Cursor(Cursor.CROSSHAIR_CURSOR); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ADrawParameters.java b/graphics/AtlantisJava/src/atlantis/graphics/ADrawParameters.java deleted file mode 100755 index 214b6e05b45..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ADrawParameters.java +++ /dev/null @@ -1,98 +0,0 @@ -package atlantis.graphics; - -import atlantis.graphics.colormap.AColorMap; - -import java.awt.Color; - -/** - * Contains graphics attributes of a collection of data - */ -public class ADrawParameters { - - boolean draw; - Color color; - int size; - int minSize=0; - boolean forceSymbols=false; - int lineWidth; - int frameWidth; - int symbol; - int drawOrFill=AGraphics.DRAW; - - public ADrawParameters(boolean draw, int color, int size, int lineWidth, int frameWidth, int symbol) { - Color[] colorMap=AColorMap.getColors(); - - this.draw=draw; - if(color!=-1) - this.color=colorMap[color]; - else - this.color=null; - this.size=size; - this.lineWidth=lineWidth; - this.frameWidth=frameWidth; - this.symbol=symbol; - } - - public ADrawParameters(boolean draw, int color, int size, int lineWidth, int frameWidth, int symbol, - boolean forceSymbols, int minSize, int drawOrFill) { - Color[] colorMap=AColorMap.getColors(); - - this.draw=draw; - if(color!=-1) - this.color=colorMap[color]; - else - this.color=null; - this.size=size; - this.lineWidth=lineWidth; - this.frameWidth=frameWidth; - this.symbol=symbol; - this.forceSymbols=forceSymbols; - this.minSize=minSize; - this.drawOrFill=drawOrFill; - } - - public ADrawParameters(boolean draw, Color color, int size, int lineWidth, int frameWidth, int symbol, int drawOrFill) { - this.draw=draw; - this.color=color; - this.size=size; - this.lineWidth=lineWidth; - this.frameWidth=frameWidth; - this.symbol=symbol; - this.drawOrFill=drawOrFill; - } - - public void setColor(int color) { - Color[] colorMap=AColorMap.getColors(); - - this.color=colorMap[color]; - } - - public void setFrameWidth(int width) { - this.frameWidth=width; - } - - public void setSize(int size) { - this.size=size; - } - - public boolean toBeDrawn() { - return draw; - } - - public int getSize() { - return size; - } - - public int getMinSize() { - return minSize; - } - - public boolean getForceSymbols() { - return forceSymbols; - } - - public int getDrawOrFill() { - return drawOrFill; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ADrawable.java b/graphics/AtlantisJava/src/atlantis/graphics/ADrawable.java deleted file mode 100755 index bf36d13b60e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ADrawable.java +++ /dev/null @@ -1,24 +0,0 @@ -package atlantis.graphics; - - -import atlantis.canvas.AWindow; -import atlantis.projection.AProjection2D; - - -public interface ADrawable { - void draw(AWindow window, AGraphics ag, AProjection2D projection); - int[] getColor(int[] dl); - int[] getType(int[] dl); - int getNumTypes(); - - /** - * The data are normally drawn in two layers - * (layer=0 is for frames) - * (layer=1 is the data) - * The data may be of more than 1 type which are drawn in sequence - * e.g. type=0 noise - * type=1 others - */ - ADrawParameters getDrawParameters(int layer, int type); -} - diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ADrawnGraphics2D.java b/graphics/AtlantisJava/src/atlantis/graphics/ADrawnGraphics2D.java deleted file mode 100755 index 5cd633a5e93..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ADrawnGraphics2D.java +++ /dev/null @@ -1,149 +0,0 @@ -package atlantis.graphics; - -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.PathIterator; -import java.util.ArrayList; -import java.util.HashMap; - -import atlantis.data.ACalorimeterData; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.data.AHistogram; -import atlantis.list.AList; -import atlantis.list.AListManager; -import atlantis.utils.ALogger; - -/** - * Simple graphics context simply decides whether something was drawn or not - */ - -public class ADrawnGraphics2D extends ATemplateGraphics2D -{ - private static ALogger logger = ALogger.getLogger(ADrawnGraphics2D.class); - private static AEventManager eventManager = AEventManager.instance(); - - private static HashMap map; - private static ArrayList histogramList; - - public ADrawnGraphics2D(Rectangle bounds) - { - super(bounds); - map = new HashMap(); - histogramList = new ArrayList(); - AEvent event = eventManager.getCurrentEvent(); - if (event != null) - { - AData[] data = event.getData(); - for (int i = 0; i < data.length; ++i) - { - map.put(data[i], new boolean[data[i].getNumData()]); - } - } - } // ADrawnGraphics2D() ---------------------------------------------------- - - ADrawnGraphics2D(ADrawnGraphics2D a) - { - super(a); - } // ADrawnGraphics2D() ---------------------------------------------------- - - public static void updateLastDrawn() - { - AListManager.getInstance().clearLastDrawn(); - AEvent event = eventManager.getCurrentEvent(); - if (event != null) - { - AData[] data = event.getData(); - for (int i = 0; i < data.length; ++i) - { - boolean[] drawn = (boolean[]) map.get(data[i]); - if (data[i] instanceof ACalorimeterData) - { - drawn = ((ACalorimeterData) data[i]).expandDrawn(drawn); - } - AListManager.getInstance().addLastDrawn(new AList(data[i], drawn)); - } - for (int i = 0; i < histogramList.size(); ++i) - { - boolean[] drawn = (boolean[]) map.get(histogramList.get(i)); - AListManager.getInstance().addLastDrawn(new AList((AData)histogramList.get(i), drawn)); - } - } - } // updateLastDrawn() ----------------------------------------------------- - - public Graphics create() - { - return new ADrawnGraphics2D(this); - } - - public void drawLine(double h0, double v0, double h1, double v1) - { - if (AGraphics.currentData != null) - { - ((boolean[]) map.get(AGraphics.currentData))[AGraphics.currentIndex] = true; - } - } - - public void fillRect(int h, int v, int width, int height) - { - double dh = width / 2.; - double dv = height / 2.; - drawLine(h - dh, v - dv, h + dh, v - dv); - drawLine(h + dh, v - dv, h + dh, v + dv); - drawLine(h + dh, v + dv, h - dh, v + dv); - drawLine(h - dh, v + dv, h - dh, v - dv); - } - - public void draw(Shape s) - { - PathIterator path = s.getPathIterator(null); - double[] coords = new double[6]; - double h0 = 0.; - double v0 = 0.; - double h1 = 0.; - double v1 = 0.; - while (!path.isDone()) - { - int segType = path.currentSegment(coords); - - switch (segType) - { - case PathIterator.SEG_MOVETO: - h0 = coords[0]; - v0 = coords[1]; - break; - - case PathIterator.SEG_LINETO: - case PathIterator.SEG_CUBICTO: - h1 = coords[0]; - v1 = coords[1]; - drawLine(h0, v0, h1, v1); - h0 = h1; - v0 = v1; - break; - - case PathIterator.SEG_CLOSE: - break; - - default: - logger.error(" Error unknown segment type"); - break; - } - path.next(); - } - } - - public void fill(Shape s) - { - draw(s); - } - - public void addHistogramData(AHistogram data) - { - histogramList.add(data); - map.put(data, new boolean[data.getNumData()]); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ADummyGraphics2D.java b/graphics/AtlantisJava/src/atlantis/graphics/ADummyGraphics2D.java deleted file mode 100755 index 9c8cded5a0a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ADummyGraphics2D.java +++ /dev/null @@ -1,215 +0,0 @@ -package atlantis.graphics; - -import java.awt.*; -import java.awt.image.*; -import java.awt.image.renderable.*; -import java.awt.geom.*; -import java.awt.font.*; - -/** - * This graphics is used when nothing should really be drawn on the screen - */ - -public class ADummyGraphics2D extends Graphics2D { - - private int x; - private int y; - private int width; - private int height; - - public ADummyGraphics2D() {} - - public Rectangle getClipBounds() { - return new Rectangle(x, y, width, height); - } - - public void setClip(int x, int y, int width, int height) { - this.x=x; - this.y=y; - this.width=width; - this.height=height; - } - - public void transform(AffineTransform z) {} - - public void fill(Shape z) {} - - public void draw(Shape z) {} - - public void drawImage(BufferedImage a, BufferedImageOp b, int c, int z) {} - - public boolean drawImage(Image a, AffineTransform b, ImageObserver z) { - return false; - } - - public void drawRenderedImage(RenderedImage a, AffineTransform z) {} - - public void drawRenderableImage(RenderableImage a, AffineTransform z) {} - - public void drawString(java.text.AttributedCharacterIterator a, float b, float z) {} - - public void drawString(String a, int b, int z) {} - - public void drawString(String a, float b, float z) {} - - public void drawString(java.text.AttributedCharacterIterator a, int b, int z) {} - - public void drawGlyphVector(GlyphVector a, float b, float z) {} - - public boolean hit(Rectangle a, Shape b, boolean z) { - return false; - } - - public GraphicsConfiguration getDeviceConfiguration() { - return null; - } - - public void setComposite(Composite z) {} - - public void setPaint(Paint z) {} - - public void setStroke(Stroke z) {} - - public void setRenderingHint(RenderingHints.Key a, Object z) {} - - public Object getRenderingHint(RenderingHints.Key z) { - return null; - } - - public void setRenderingHints(java.util.Map z) {} - - public void addRenderingHints(java.util.Map z) {} - - public RenderingHints getRenderingHints() { - return null; - } - - public void translate(double a, double z) {} - - public void translate(int a, int z) {} - - public void rotate(double a, double b, double z) {} - - public void rotate(double z) {} - - public void scale(double a, double z) {} - - public void shear(double a, double z) {} - - public void setTransform(AffineTransform z) {} - - public AffineTransform getTransform() { - return null; - } - - public Paint getPaint() { - return null; - } - - public Composite getComposite() { - return null; - } - - public void setBackground(Color z) {} - - public Color getBackground() { - return null; - } - - public Stroke getStroke() { - return null; - } - - public void clip(Shape z) {} - - public FontRenderContext getFontRenderContext() { - return null; - } - - public void setColor(Color z) {} - - public Graphics create() { - return null; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, int f, int g, int h, int i, ImageObserver z) { - return false; - } - - public boolean drawImage(Image a, int b, int c, ImageObserver z) { - return false; - } - - public boolean drawImage(Image a, int b, int c, Color d, ImageObserver z) { - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, Color f, ImageObserver z) { - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, ImageObserver z) { - return false; - } - - public boolean drawImage(Image a, int b, int c, int d, int e, int f, int g, int h, int i, Color j, ImageObserver z) { - return false; - } - - public Color getColor() { - return null; - } - - public void fillRect(int a, int b, int c, int z) {} - - public void setPaintMode() {} - - public void setXORMode(Color z) {} - - public Font getFont() { - return null; - } - - public void setFont(Font z) {} - - public FontMetrics getFontMetrics(Font z) { - return null; - } - - // public Rectangle getClipBounds () { return null;} - public void clipRect(int a, int b, int c, int z) {} - - // public void setClip(int a,int b,int c,int z) { } - public void setClip(Shape z) {} - - public Shape getClip() { - return null; - } - - public void copyArea(int a, int b, int c, int d, int e, int z) {} - - public void drawLine(int a, int b, int c, int z) {} - - public void clearRect(int a, int b, int c, int z) {} - - public void drawRoundRect(int a, int b, int c, int d, int e, int z) {} - - public void fillRoundRect(int a, int b, int c, int d, int e, int z) {} - - public void drawOval(int a, int b, int c, int z) {} - - public void fillOval(int a, int b, int c, int z) {} - - public void drawArc(int a, int b, int c, int d, int e, int z) {} - - public void fillArc(int a, int b, int c, int d, int e, int z) {} - - public void drawPolyline(int[] a, int[] b, int z) {} - - public void drawPolygon(int[] a, int[] b, int z) {} - - public void fillPolygon(int[] a, int[] b, int z) {} - - public void dispose() {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AGLPixelGraphics.java b/graphics/AtlantisJava/src/atlantis/graphics/AGLPixelGraphics.java deleted file mode 100644 index 299aa5fd26b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AGLPixelGraphics.java +++ /dev/null @@ -1,47 +0,0 @@ -package atlantis.graphics; - -import atlantis.canvas.AGLGraphics; - -/* - * This class subclasses APixelGraphics to allow some optimisations slightly - * higher up the graphics chain in cases where OpenGL renders faster in - * certain ways - * - * @author Adam Davison - */ - -public class AGLPixelGraphics extends APixelGraphics { - - protected AGLGraphics m_glg; - - public AGLPixelGraphics(AGLGraphics g) { - super(g); - m_glg = g; - } - - @Override - public void fillPolygon(double[] h, double[] v, int numPoints) { - /*int type = getContainmentType(h, v, numPoints, POLYGON); - if (type == FULLY_INSIDE || type == INTERSECTS) { - if (type == INTERSECTS) { - ACoord clipped = clipper.clipPolygon(h, v, numPoints); - h = clipped.hv[0][0]; - v = clipped.hv[1][0]; - numPoints = h.length; - }*/ - /*int[] hInt = new int[numPoints]; - int[] vInt = new int[numPoints]; - for (int i = 0; i < numPoints; ++i) { - hInt[i] = (int) h[i]; - vInt[i] = (int) v[i]; - }*/ - updateColor(); - m_glg.fillPolygon(h, v, numPoints); - //g.drawPolygon(hInt, vInt, numPoints); - /*} else if (type == CONTAINS) { - Rectangle bounds = g.getClipBounds(); - updateColor(); - g.fillRect((int) Math.rint(bounds.getX()), (int) Math.rint(bounds.getY()), (int) Math.rint(bounds.getWidth()), (int) Math.rint(bounds.getHeight())); - }*/ - } -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AGraphics.java b/graphics/AtlantisJava/src/atlantis/graphics/AGraphics.java deleted file mode 100755 index 225eb608a88..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AGraphics.java +++ /dev/null @@ -1,407 +0,0 @@ -package atlantis.graphics; - -import atlantis.canvas.AGLGraphics; -import java.awt.Color; -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Image; -import java.awt.Stroke; - -import atlantis.event.AData; -import atlantis.geometry.ADetectors; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; -import atlantis.utils.APolygon; - -import org.sourceforge.jlibeps.epsgraphics.*; -import org.apache.batik.svggen.SVGGraphics2D; - -/** - * Normally all drawing should be done on an AGraphics. For special uses, e.g. - * Braintest projections, standard Java Graphics may be used. To allow this, - * projections are always given a graphics which they must convert to an - * AGraphics with AGraphics.makeAGraphics. AGraphics provides picking of drawn - * objects. - */ - -public abstract class AGraphics -{ - protected Graphics2D g; - AClipper clipper = null; - Color currentColor; - Color lastDrawnColor = null; - Rectangle bounds; - int lineWidth = 1; - int size; - int symbol; - ADrawParameters lastDrawParameters = null; - - static AData currentData = null; - static ADetectors currentDetector = null; - static int currentIndex; - - public static final int SYMBOL_FILLED_BOX = 0; - public static final int SYMBOL_HORIZONTAL_LINE = 1; - public static final int SYMBOL_VERTICAL_LINE = 2; - public static final int SYMBOL_PLUS = 3; - public static final int SYMBOL_FILLED_CIRCLE = 4; - - public static final int DRAW = 0; - public static final int FILL = 1; - - protected static final int NUM_LAYERS = 2; - - protected static final int FULLY_INSIDE = 0; - protected static final int FULLY_OUTSIDE = 1; - protected static final int CONTAINS = 2; - protected static final int INTERSECTS = 3; - - protected static final int POLYGON = 0; - protected static final int POLYLINE = 1; - - AGraphics(Graphics g) - { - this.g = (Graphics2D) g; - if (g.getClipBounds() != null) - clipper = new AClipper(g.getClipBounds()); - currentColor = g.getColor(); - } - - public Graphics2D getGraphics2D() - { - return g; - } - - public static AGraphics makeAGraphics(Graphics g) - { - if (g instanceof EpsGraphics2D || g instanceof APickingGraphics2D || - g instanceof ADrawnGraphics2D || g instanceof SVGGraphics2D) - { - return new AVectorGraphics(g); - } - else if (g instanceof AGLGraphics) - { - return new AGLPixelGraphics((AGLGraphics)g); - } - else - { - return new APixelGraphics(g); - } - } - - public static void setCurrentDataAndIndex(AData current, int index) - { - currentData = current; - currentIndex = index; - } - - public static void setCurrentDetectorAndIndex(ADetectors current, int index) - { - currentDetector = current; - currentIndex = index; - } - - public static void clearCurrentDetectorAndIndex() - { - currentDetector = null; - currentIndex = -1; - } - - public static void clearCurrentDataAndIndex() - { - currentData = null; - currentIndex = -1; - } - - public void setFont(Font f) - { - g.setFont(f); - } - - public void setStroke(Stroke s) - { - g.setStroke(s); - } - - public void setColor(Color c) - { - currentColor = c; - } - - public void updateColor() - { - if (currentColor != lastDrawnColor) - { - g.setColor(currentColor); - lastDrawnColor = currentColor; - } - } - - public abstract void setLineWidth(int lineWidth); - - public void updateDrawParameters(ADrawParameters dp) - { - if (dp != lastDrawParameters) - { - setColor(dp.color); - lineWidth = Math.max(dp.lineWidth, 1) + 2 * dp.frameWidth; - setLineWidth(lineWidth); - size = dp.size + 2 * dp.frameWidth; - symbol = dp.symbol; - lastDrawParameters = dp; - } - } - - public void drawString(String str, double x, double y) - { - g.drawString(str, (int) x, (int) y); - } - - public void draw(Shape s) - { - g.draw(s); - } - - public void drawPoint(AData detector, int index, double h, double v, int pixelsH, int pixelsV) - { - setCurrentDataAndIndex(detector, index); - drawPoint(h, v, pixelsH, pixelsV); - clearCurrentDataAndIndex(); - } - - public void drawPoint(double h, double v, int pixelsH, int pixelsV) - { - if (clipper.isPointWithin(h, v)) - fillRect(h, v, pixelsH, pixelsV); - } - - public void drawSymbol(double h, double v) - { - if (clipper.isPointWithin(h, v)) - { - if (symbol == SYMBOL_FILLED_BOX) - { - fillRect(h, v, size, size); - } - else if (symbol == SYMBOL_HORIZONTAL_LINE) - { - fillRect(h, v, size, lineWidth); - } - else if (symbol == SYMBOL_VERTICAL_LINE) - { - fillRect(h, v, lineWidth, size); - } - else if (symbol == SYMBOL_PLUS) - { - fillRect(h, v, size, lineWidth); - fillRect(h, v, lineWidth, size); - } - else if (symbol == SYMBOL_FILLED_CIRCLE) - { - fillOval(h, v, size, size); - } - } - } - - //Draw an image at postion x,y of this graphics context - //Introduced for FishEye symbol showing FishEye status - public void drawImage(Image img, int x, int y){ - //Draw the image on screen - g.drawImage(img,x,y,null); - } - - - public void fillPolygon(AData detector, int index, double[] h, double[] v, int numPoints) - { - setCurrentDataAndIndex(detector, index); - fillPolygon(h, v, numPoints); - clearCurrentDataAndIndex(); - } - - public void fillRect(int h, int v, int width, int height) - { - updateColor(); - g.fillRect(h, v, width, height); - } - - public void fillOval(int h, int v, int width, int height) - { - g.fillOval(h, v, width, height); - } - - public abstract void drawPolyline(double[] h, double[] v, int numPoints); - - public abstract void drawDottedPolyline(double[] h, double[] v, int numPoints); - - public abstract void drawSmoothPolyline(double[] h0, double[] v0, int numPoints0); - - public abstract void drawLine(double h0, double v0, double h1, double v1); - - public abstract void drawPolygon(double[] h, double[] v, int numPoints); - - protected abstract void fillRect(double h, double v, int width, int height); - - protected abstract void fillOval(double h, double v, int width, int height); - - public void fillPolygon(ADetectors det, int index, double[] h, double[] v, int numPoints) - { - setCurrentDetectorAndIndex(det, index); - fillPolygon(h, v, numPoints); - clearCurrentDetectorAndIndex(); - } - - public void fillPolygon(double[] h, double[] v, int numPoints, float alpha) - { - Composite originalComposite = g.getComposite(); - int ACtype = AlphaComposite.SRC_OVER; - g.setComposite(AlphaComposite.getInstance(ACtype, alpha)); - fillPolygon(h, v, numPoints); - g.setComposite(originalComposite); - } - - protected int getContainmentType(double[] h, double[] v, int numPoints, int shape) - { - int within = clipper.fastWithin(h, v, numPoints); - if (within == AClipper.NONE_WITHIN) - return FULLY_OUTSIDE; - if (within == AClipper.ALL_WITHIN) - return FULLY_INSIDE; - for (int i = 0; i < numPoints - 1; ++i) - if (clipper.isLineWithin(h[i], v[i], h[i + 1], v[i + 1])) - return INTERSECTS; - if (shape == POLYGON && numPoints > 1) - if (clipper.isLineWithin(h[numPoints - 1], v[numPoints - 1], h[0], v[0])) - return INTERSECTS; - Rectangle bounds = g.getClipBounds(); - double xCentreClipped = bounds.getX() + bounds.getWidth() / 2.; - double yCentreClipped = bounds.getY() + bounds.getHeight() / 2.; - if (isPointInside(h, v, numPoints, xCentreClipped, yCentreClipped)) - return CONTAINS; - return FULLY_OUTSIDE; - } - - public abstract void fillPolygon(double[] h, double[] v, int numPoints); - - public void drawPolygon(APolygon p) - { - drawPolygon(p.getX(), p.getY(), p.nrNodes()); - } - - public static boolean isPointInside(double[] h, double[] v, int numPoints, double hP, double vP) - { - double[] a = new double[numPoints]; - - for (int i = 0; i < numPoints; ++i) - { - a[i] = Math.atan2(v[i] - vP, h[i] - hP); - } - double[] d = new double[numPoints]; - - for (int i = 0; i < numPoints; ++i) - { - if (i < numPoints - 1) - d[i] = a[i + 1] - a[i]; - else - d[i] = a[0] - a[i]; - if (d[i] > Math.PI) - d[i] -= 2. * Math.PI; - else if (d[i] < -Math.PI) - d[i] += 2. * Math.PI; - } - double sum = 0.; - - for (int i = 0; i < numPoints; ++i) - { - sum += d[i]; - } - if (Math.abs(sum) > Math.PI) - return true; - else - return false; - } - - public void draw(ACoord display) - { - ADrawable source = display.source; - - if (source == null) - return; - ADrawParameters adp = source.getDrawParameters(0, 0); - - if (adp.getForceSymbols() == true || adp.getMinSize() > 0) - display.toSymbols(adp.getForceSymbols(), adp.getMinSize()); - Color[] colorMap = AColorMap.getColors(); - int[] index = display.index; - int[] c = source.getColor(index); - int[] t = source.getType(index); - double[][] h = display.hv[0]; - double[][] v = display.hv[1]; - - for (int layer = 0; layer < NUM_LAYERS; layer++) - { - for (int type = 0; type < source.getNumTypes(); type++) - { - ADrawParameters dp = source.getDrawParameters(layer, type); - int drawType = dp.getDrawOrFill(); - updateDrawParameters(dp); - if (dp.draw) - { - for (int j = 0; j < t.length; j++) - { - if (t[j] == type) - { - if (layer == NUM_LAYERS - 1) - { - setColor(colorMap[c[j]]); - if (source instanceof AData) - setCurrentDataAndIndex((AData) source, index[j]); - } - if (display.type == ACoord.SYMBOLS) - drawSymbol(h[0][j], v[0][j]); - else if (display.type == ACoord.POLYGONS && h[j].length == 1) - drawSymbol(h[j][0], v[j][0]); - else if (display.type == ACoord.LINES) - drawLine(h[0][j], v[0][j], h[1][j], v[1][j]); - else if (display.type == ACoord.POLYLINES) - drawPolyline(h[j], v[j], h[j].length); - else if (display.type == ACoord.SMOOTH_POLYLINES) - drawSmoothPolyline(h[j], v[j], h[j].length); - else if (display.type == ACoord.DOTTED_POLYGONS) - drawDottedPolyline(h[j], v[j], h[j].length); - else if (display.type == ACoord.POLYGONS) - { - if (drawType == DRAW) - drawPolygon(h[j], v[j], h[j].length); - else if (drawType == FILL) - fillPolygon(h[j], v[j], h[j].length); - } - else if (display.type == ACoord.TRANSPARENT_POLYGONS) - { - if(g instanceof EpsGraphics2D){ - // setComposite is currently unsupported for EpsGraphics2D - // for now just draw as an outline, so we can still see - // jets and the underlying objects - drawPolygon(h[j], v[j], h[j].length); - } - else { - Composite originalComposite = g.getComposite(); - int ACtype = AlphaComposite.SRC_OVER; - g.setComposite(AlphaComposite.getInstance(ACtype, (float)APar.instance().get("Jet","Alpha").getD())); - fillPolygon(h[j], v[j], h[j].length); - g.setComposite(originalComposite); - } - } - clearCurrentDataAndIndex(); - } - } - } - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AIcon.java b/graphics/AtlantisJava/src/atlantis/graphics/AIcon.java deleted file mode 100644 index a2add88871f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AIcon.java +++ /dev/null @@ -1,28 +0,0 @@ -package atlantis.graphics; - -import java.awt.Frame; - -import javax.swing.ImageIcon; - -import atlantis.globals.AGlobals; -import atlantis.utils.AUtilities; - -/** - * - * @author waugh - * - */ -public class AIcon { - /** Set icon image for a frame to be the Atlantis icon. */ - public static void setIconImage(Frame f) - { - String path = AGlobals.instance().getHomeDirectory() + "img" + - System.getProperty("file.separator") + - "atlantis_icon.gif"; - ImageIcon ii = AUtilities.getFileAsImageIcon(path); - f.setIconImage(ii.getImage()); - - } // setIconImage() ----------------------------------------------------- - - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ALegoDraw.java b/graphics/AtlantisJava/src/atlantis/graphics/ALegoDraw.java deleted file mode 100755 index ab9137ea80a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ALegoDraw.java +++ /dev/null @@ -1,1150 +0,0 @@ -package atlantis.graphics; -import java.awt.BasicStroke; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Stroke; -import java.awt.geom.Point2D; - -import atlantis.canvas.AWindow; -import atlantis.event.AEvent; -import atlantis.data.ALVL1ResultData; -import atlantis.data.ATriggerInfoData; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.AEnumeratorParameter; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.utils.AMath; - -public class ALegoDraw -{ - - protected static APar parameterStore = APar.instance(); - - private static int legendHeight=0; - private static int lineHeight = 17;//seperation of lines - //colors to use in legend - - //width of lines in lego grid - private static float legoGridWidth = 1.6f; - private static float legoTowersWidth = 1.0f; - - private static Color textColor=Color.white, - backgroundColor=AColorMap.getColors()[parameterStore.get("Color", "BkgFill").getI()], - borderColor=Color.lightGray; - - public static Color getBackgroundColor() - { - return backgroundColor; - } - - public static void fillBackground(AWindow window, AGraphics ag) - { - - backgroundColor = AColorMap.getColors()[parameterStore.get("Color", "BkgFill").getI()]; // inherit bkg colour from main background colour - - ag.setColor(backgroundColor); - ag.fillRect(0, 0, window.getWidth(), window.getHeight()); - } - - public static void drawLegend(AWindow window, AGraphics ag, AEvent event, double met, double maxEt, double AODmaxEt) - { - //colors to use - textColor=Color.black; - if(backgroundColor.getBlue()+backgroundColor.getGreen()+backgroundColor.getRed() < 400) - textColor=Color.white; - //change the font size (reset at end) - float originalFontSize= ag.g.getFont().getSize2D(); - float newFontSize= (float) 0.9*originalFontSize; - ag.g.setFont(ag.g.getFont().deriveFont(newFontSize)); - //variables to locate where to write/draw - legendHeight = lineHeight+2;//distance from top of legend - int indent = window.getWidth()- 200;//distance from left of legend - int pos = 90;//distance to start writing second half of line - //loop over Lvl1resultdata collections - String[] colLvl1=event.getActiveCollectionNames("LVL1Result"); - ALVL1ResultData lvl1ResultData[] = null; - if(colLvl1.length>0) - lvl1ResultData = new ALVL1ResultData[colLvl1.length]; - for(int i=0;i<colLvl1.length;i++) - { - lvl1ResultData[i] = (ALVL1ResultData) event.get(colLvl1[i]); - } - ATriggerInfoData triggerInfoData = event.getTriggerInfoData(); - - //check window is large enough - if(window.getWidth()<250 || window.getHeight()<250) - { - drawWindowTooSmall(window, ag, indent); - //reset font size - ag.g.setFont(ag.g.getFont().deriveFont(originalFontSize)); - return; - } - - //draw main legend - if(parameterStore.get("LegoPlot", "MainLegend").getStatus()) - drawLegendMain(window, ag, event, met, maxEt, AODmaxEt, lvl1ResultData, indent, pos); - //draw lvl1 sumEt and missEt - if(parameterStore.get("LegoPlot", "L1EtLegend").getStatus()) - drawLegendL1ET(ag, lvl1ResultData, triggerInfoData, indent); - //draw the item list - boolean drawLegend=false; - if(!drawLegend && parameterStore.get("LegoPlot", "L1Items").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "L2Items").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "EFItems").getStatus())drawLegend=true; - if(drawLegend) - drawLegendItems(window, ag, lvl1ResultData, indent); - - //reset font size - ag.g.setFont(ag.g.getFont().deriveFont(originalFontSize)); - } - - public static void drawWindowTooSmall(AWindow window, AGraphics ag, int indent) - { - - //change indent to make legend smaller - indent+=135; - // create legend boarder with two concentric rectangles - // outer rectangle: - ag.setColor(borderColor); - ag.fillRect(indent - 4, 5, 65, 3*lineHeight); - // inner rectangle: - ag.setColor(backgroundColor); - ag.fillRect(indent - 4 + 2, 7, 65 - 4, 3*lineHeight-4); - ag.setColor(textColor); - ag.updateColor(); - - ag.drawString("Window", indent + 6, legendHeight); - legendHeight += lineHeight; - ag.drawString("too small", indent + 6, legendHeight); - legendHeight += lineHeight; - ag.drawString("for legend", indent + 6, legendHeight); - legendHeight += lineHeight; - } - - public static void drawLegendMain(AWindow window, AGraphics ag, AEvent event, double met, double maxEt, double AODmaxEt, ALVL1ResultData lvl1ResultData[], int indent, int pos) - { - - // create legend boarder with two concentric rectangles - // outer rectangle: - ag.setColor(borderColor); - //ag.fillRect(/*indent - 4*/window.getWidth()/1.8, /*5*/window.getHeight()/3.0, (int)(1-(window.getWidth()/1.8)), (int)(1-(window.getHeight()/3.0))); - ag.fillRect(indent - 4, 5, 200, 105); - - // inner rectangle: - ag.setColor(backgroundColor); - ag.fillRect(indent - 4 + 2, 7, 200 - 4, 105 - 4); - //ag.fillRect(/*indent - 4*/window.getWidth()/1.8 +2, /*5*/window.getHeight()/3.0 +2, (int)(1-(window.getWidth()/1.8))+4, (int)(1-(window.getHeight()/3.0))+4); - - ag.setColor(textColor); - ag.updateColor(); - - //First item Missing ET (may remove met box from plot later) - if(met!=0) - drawLegendPartMain1(ag, event, met, indent, pos); - else - ag.drawString("No Missing Et", indent + 6, legendHeight); - legendHeight += lineHeight; - ag.setColor(textColor); - ag.updateColor(); - - //Second item colourby - //make sure there are cells by checking the maximum energy - //and that there have been colours added to the colourset - //(can have maxE and no colours when scaling to AOD) - if(maxEt!=0 && AProjectionLegoPlot.colorset.size()>0) - drawLegendMain2(ag, indent, pos); - else - { - ag.setColor(textColor); - ag.updateColor(); - ag.drawString("No cells", indent + 6, legendHeight); - } - legendHeight += lineHeight; - ag.setColor(textColor); - ag.updateColor(); - - //Third item maximum height of towers - if(maxEt!=0 || AODmaxEt!=0) - drawLegendMain3(ag, maxEt, AODmaxEt, indent, pos); - else - { - ag.drawString("No towers", indent + 6, legendHeight); - legendHeight += lineHeight; - } - legendHeight += lineHeight; - ag.setColor(textColor); - ag.updateColor(); - - //Fourth item lvl1 result - if (lvl1ResultData == null){ - ag.drawString("Trigger Decision N/A", indent+6, legendHeight); - legendHeight+=lineHeight;//move by a line to keep same spacing - }else if (lvl1ResultData.length>1){ - ag.drawString(">1 LVL1Result collections selected", indent+6, legendHeight); - legendHeight+=lineHeight; - ag.drawString("View on event properties or choose 1", indent+6, legendHeight); - }else{ - drawLegendMain4(ag, lvl1ResultData[0], indent, pos); - } - legendHeight+=lineHeight; - ag.setColor(textColor); - ag.updateColor(); - } - - public static void drawLegendPartMain1(AGraphics ag, AEvent event, double met, int indent, int pos) - { - ag.setColor(AProjectionLegoPlot.defaultColorMap[parameterStore.get("ETMis", "Constant").getI()]); - //draw dashed line - ag.fillRect(indent + 6, 11, 5, 3); - ag.fillRect(indent + 6 + 10, 11, 5, 3); - ag.fillRect(indent + 6 + 20, 11, 5, 3); - ag.fillRect(indent + 6 + 30, 11, 5, 3); - ag.setColor(textColor); - ag.updateColor(); - String[] names = event.getActiveCollectionNames("ETMis"); - if(names.length==1) - ag.drawString("Missing ET= " + Math.round(met) + " GeV" , indent + 0.6*pos, legendHeight); - else - ag.drawString("Max Missing ET= " + Math.round(met) + " GeV" , indent + 0.6*pos, legendHeight); - } - - public static void drawLegendMain2(AGraphics ag, int indent, int pos) - { - String modeName; - if (AProjectionLegoPlot.mode == 0) - { - modeName="LAr"; - } - else if (AProjectionLegoPlot.mode == 1) - { - modeName="LVL1TriggerTower"; - } - else - { - modeName="LVL1JetElement"; - } - AEnumeratorParameter param = (AEnumeratorParameter) parameterStore.get(modeName, "ColorFunction"); - String colorFunction = param.getText(param.getI()); - ag.drawString(colorFunction + " (1-" + AProjectionLegoPlot.colorset.size() + ")",indent + pos, legendHeight); - int barwidth = 6, barheight = 6; - if(AProjectionLegoPlot.getDrawEMHAD()) - { - if(AProjectionLegoPlot.colorset.size()==2) - { - //for Em/had option should only have 2 colors - ag.setColor(AProjectionLegoPlot.defaultColorMap[AProjectionLegoPlot.colorEM]); - ag.fillRect(indent + barwidth * 2, 28, barwidth * 2, barheight); - ag.setColor(AProjectionLegoPlot.defaultColorMap[AProjectionLegoPlot.colorHad]); - ag.fillRect(indent + 2 * barwidth* 2, 28, barwidth * 2, barheight); - } - else - { - //if more colors then lists must be in use - int c = 0; - ++c; - ag.setColor(AProjectionLegoPlot.defaultColorMap[AProjectionLegoPlot.colorEM]); - ag.fillRect(indent + c * barwidth, 28, barwidth, barheight); - ++c; - ag.setColor(AProjectionLegoPlot.defaultColorMap[AProjectionLegoPlot.colorHad]); - ag.fillRect(indent + c * barwidth, 28, barwidth, barheight); - for (int i = 0; i <AProjectionLegoPlot.caloColorMap.length ; i++) - { - if (!AProjectionLegoPlot.colorset.contains(new Integer(i))) - continue; - if(i==AProjectionLegoPlot.colorEM || i==AProjectionLegoPlot.colorHad) - continue; - ++c; - ag.setColor(AProjectionLegoPlot.caloColorMap[i]); - ag.fillRect(indent + c * barwidth, 28, barwidth, barheight); - } - } - } - else - { - //if not Em/Had then loop over colors - int c = 0; - barwidth = 90/AProjectionLegoPlot.caloColorMap.length; - for (int i = 0; i <AProjectionLegoPlot.caloColorMap.length ; i++) - { - if (!AProjectionLegoPlot.colorset.contains(new Integer(i))) - continue; - ++c; - ag.setColor(AProjectionLegoPlot.caloColorMap[i]); - ag.fillRect(indent + c * barwidth, 28, barwidth, barheight); - } - } - } - - public static void drawLegendMain3(AGraphics ag, double maxEt, double AODmaxEt, int indent, int pos) - { - ag.drawString( "Height of tallest tower:", indent + 6, legendHeight); - //next line has the values - legendHeight += lineHeight; - if (parameterStore.get("LegoPlot", "ETAxisHeight").getD() > 0.0) - ag.drawString("User selection: " + Math.round(maxEt) + " GeV ", indent +6, legendHeight); - else if (parameterStore.get("LegoPlot", "ScaleToAOD").getStatus()) - ag.drawString("Scale to AOD: " + Math.round(maxEt) + " GeV ", indent +6, legendHeight); - else - { - if(maxEt!=0) - { - ag.drawString("Cells: " + Math.round(maxEt) + " GeV ", indent +6, legendHeight); - if(AODmaxEt!=0) - ag.drawString("AOD: " + Math.round(AODmaxEt) + " GeV ", indent + pos, legendHeight); - } - else - ag.drawString("AOD: " + Math.round(AODmaxEt) + " GeV ", indent + 6, legendHeight); - } - } - - public static void drawLegendMain4(AGraphics ag, ALVL1ResultData lvl1ResultData, int indent, int pos) - { - ag.drawString("Trigger Decision:", indent +6, legendHeight); - legendHeight+=lineHeight; - String[] trigRes={"NA","NA","NA"}; - int[] temp=new int[3]; - temp[0]=lvl1ResultData.getPassedL1(0); - temp[1]=lvl1ResultData.getPassedL2(0); - temp[2]=lvl1ResultData.getPassedEF(0); - for(int i=0;i<3;i++) - { - switch(temp[i]) - { - case -1: - trigRes[i]="N/C"; - break; - case 0: - trigRes[i]="failed"; - break; - case 1: - trigRes[i]="passed"; - break; - default: - trigRes[i]="NA"; - } - } - ag.drawString("L1:" + trigRes[0] +" L2:" + trigRes[1]+" EF:" + trigRes[2], indent +6, legendHeight); - } - - public static void drawLegendL1ET(AGraphics ag, ALVL1ResultData lvl1ResultData[], ATriggerInfoData triggerInfoData, int indent) - { - // create legend boarder with two concentric rectangles - // outer rectangle: - ag.setColor(borderColor); - ag.fillRect(indent - 4, legendHeight, 200, (int) (lineHeight*1.5)); - // inner rectangle: - ag.setColor(backgroundColor); - ag.fillRect(indent - 4 + 2, legendHeight + 2, 200 - 4, (int) (lineHeight*1.5 - 4)); - ag.setColor(textColor); - ag.updateColor(); - legendHeight+=lineHeight; - //if no trigger info and "All" Lvlresult selected display warning - if(triggerInfoData==null && lvl1ResultData!=null && lvl1ResultData.length>1){ - ag.drawString(">1 LVL1Result collections selected", indent+6, legendHeight); - legendHeight+=lineHeight; - return; - } - - float LVL1EtMiss=-1.0f,LVL1SumEt=-1.0f; - if(triggerInfoData!=null) - { - LVL1EtMiss=triggerInfoData.getEnergyEtMiss(0); - LVL1SumEt=triggerInfoData.getEnergySumEt(0); - } - else if(lvl1ResultData!=null && lvl1ResultData.length==1) - { - LVL1EtMiss=lvl1ResultData[0].getEnergyEtMiss(0); - LVL1SumEt=lvl1ResultData[0].getEnergySumEt(0); - } - String LVL1EtMissOutput,LVL1SumEtOutput; - if(LVL1EtMiss>0) - LVL1EtMissOutput=""+LVL1EtMiss; - else - LVL1EtMissOutput="N/A"; - if(LVL1SumEt>0) - LVL1SumEtOutput=""+LVL1SumEt; - else - LVL1SumEtOutput="N/A"; - - ag.drawString("L1-EtMiss: "+LVL1EtMissOutput+" L1-SumEt: "+LVL1SumEtOutput, indent , legendHeight); - legendHeight+=lineHeight; - } - - public static void drawLegendItems(AWindow window, AGraphics ag, ALVL1ResultData lvl1ResultData[], int indent) - { - // ag.setStroke(new BasicStroke(legoTowersWidth)); returning to original line width - - if(lvl1ResultData!=null && lvl1ResultData.length>1){ - //create legend boarder with two concentric rectangles - //outer rectangle: - ag.setColor(borderColor); - ag.fillRect(indent - 4, legendHeight, 200, (int) (lineHeight*5.5)); - // inner rectangle: - ag.setColor(backgroundColor); - ag.fillRect(indent - 4 + 2, legendHeight + 2, 200 - 4, (int) (lineHeight*5.5 - 4)); - ag.setColor(textColor); - ag.updateColor(); - legendHeight+=lineHeight; - ag.drawString(">1 LVL1Result collections selected", indent+6, legendHeight); - legendHeight+=lineHeight; - ag.drawString("Either select 1 LVL1Result collection", indent+6, legendHeight); - legendHeight+=lineHeight; - ag.drawString("from: Calo->LVL1Result", indent+6, legendHeight); - legendHeight+=lineHeight; - ag.drawString("or to see all items select:", indent+6, legendHeight); - legendHeight+=lineHeight; - ag.drawString("file->Event Properties", indent+6, legendHeight); - legendHeight+=lineHeight; - return; - } - - //output message to say no lvl1result - if(lvl1ResultData==null){ - ag.setColor(borderColor); - ag.updateColor(); - ag.fillRect(window.getWidth() -200 - 4, legendHeight+4, 200, (int) Math.round(1.5*lineHeight)); - ag.setColor(backgroundColor); - ag.updateColor(); - ag.fillRect(window.getWidth() -200 - 4 + 2, legendHeight +4+ 2, 200 - 4, (int) Math.round(1.5*lineHeight)-4); - ag.setColor(textColor); - ag.updateColor(); - legendHeight+=lineHeight; - ag.drawString("No LVL1Result collection in event", window.getWidth() - 200 + 2, legendHeight+4); - return; - } - - int origlineHeight =lineHeight;//save lineheight to be reset at end of function - lineHeight*=0.8;//for item list bunch together - int startrowHeight =legendHeight; - - //now output items in columns in new legend box - - //lists to draw - int dolist1 = parameterStore.get("LegoPlot", "L1Items").getStatus()?1:0; - int dolist2 = parameterStore.get("LegoPlot", "L2Items").getStatus()?1:0; - int dolist3 = parameterStore.get("LegoPlot", "EFItems").getStatus()?1:0; - - //number of items per column and number of columns - int maxItems=(int) Math.round(((0.8*window.getHeight()-legendHeight)/lineHeight )-0.5); - int columnWidth= 72; - int maxColumns=(int) Math.floor((0.9*window.getWidth())/columnWidth); - - // store items and headers - String[][] items=new String[3][]; - if(dolist1>0) items[0]=newList("---L1 items---", lvl1ResultData[0].getCtpItemListSplit(0,true)); - if(dolist2>0) items[1]=newList("---L2 items---", lvl1ResultData[0].getitemListL2Split(0,true)); - if(dolist3>0) items[2]=newList("---EF items---", lvl1ResultData[0].getitemListEFSplit(0,true)); - - //number of columns for each list - int[] num=new int[3]; - num[0]= (dolist1==0)? 0 : (int) Math.ceil(items[0].length/((double)maxItems)); - num[1]= (dolist2==0)? 0 : (int) Math.ceil(items[1].length/((double)maxItems)); - num[2]= (dolist3==0)? 0 : (int) Math.ceil(items[2].length/((double)maxItems)); - - boolean doWarning=false;//for printing see event properties message - //calculate total number of columns - if(num[0]+num[1]+num[2]>maxColumns){ - //too many in list so each can just have the average - int av = (int) Math.floor(maxColumns/((double)(dolist1+dolist2+dolist3))); - if(dolist1>0) num[0]=av; - if(dolist2>0) num[1]=av; - if(dolist3>0) num[2]=av; - doWarning=true; - } - int noOfColumns=num[0]+num[1]+num[2]; - - //now store each column into an array [column][row] - String[][] list=new String[noOfColumns][maxItems]; - int list_counter=0; - //loop over each list - for(int i=0; i<3; i++){ - //loop over items in a list - int item_counter=0; - //only loop over columns can display for each list - for(int j=0; j<num[i]; j++){ - //loop over all items for a column - for(int k=0; k<maxItems; k++){ - if(item_counter<items[i].length) - list[list_counter][k]=items[i][item_counter]; - else - list[list_counter][k]=""; - item_counter++; - } - //next column - list_counter++; - } - } - - // makes outer and inner borders of table: - ag.setColor(borderColor); - ag.fillRect(window.getWidth() -noOfColumns*columnWidth - 4, legendHeight, (int)(noOfColumns*columnWidth), (int) Math.round((maxItems+0.5)*lineHeight)); - - //draw columns - for(int i=0; i<noOfColumns; i++){ - //draw column to draw onto - legendHeight=startrowHeight; - ag.setColor(backgroundColor); - ag.updateColor(); - ag.fillRect(window.getWidth() -(noOfColumns-i)*columnWidth - 4 + 2, legendHeight + 2, columnWidth - 4, (int) Math.round((maxItems+0.5)*lineHeight)-4); - ag.setColor(textColor); - ag.updateColor(); - //draw item - for(int j=0; j<maxItems; j++){ - legendHeight+=lineHeight; - ag.drawString(list[i][j], window.getWidth() - (noOfColumns-i)*columnWidth + 2, legendHeight); - } - } - - //output warning if too many items - if(doWarning){ - legendHeight+=lineHeight; - //draw under columns - ag.setColor(borderColor); - ag.updateColor(); - ag.fillRect(window.getWidth() -90 - 4, legendHeight+4, 90, (int) Math.round(2.5*lineHeight)); - ag.setColor(backgroundColor); - ag.updateColor(); - ag.fillRect(window.getWidth() -90 - 4 + 2, legendHeight +4+ 2, 90 - 4, (int) Math.round(2.5*lineHeight)-4); - ag.setColor(textColor); - ag.updateColor(); - legendHeight+=lineHeight; - ag.drawString(" more items in", window.getWidth() - 90 + 2, legendHeight+4); - legendHeight+=lineHeight; - ag.drawString("event properties", window.getWidth() - 90 + 2, legendHeight+4); - } - lineHeight=origlineHeight;//reset line height - } - - static String[] newList(String first, String[] rest){ - int counter = 2;//1 for title 1 for N/A if needed - if(rest!=null) counter+=rest.length-1;//now don't need N/A - - String[] editedList=new String[counter]; - editedList[0]=first; - if(rest!=null){ - System.arraycopy(rest, 0, editedList, 1, rest.length); - }else{ - editedList[1]="N/A"; - } - - return editedList; - } - - static void drawline(AWindow window, AGraphics ag, Point2D.Double from, Point2D.Double to) - { - from=window.calculateDisplay(from); - to=window.calculateDisplay(to); - ag.drawLine( from.x,from.y,to.x,to.y); - } - - static void drawline(AWindow window, AGraphics ag, double fromX, double fromY, double toX, double toY) - { - Point2D.Double from= new Point2D.Double(fromX,fromY); - Point2D.Double to= new Point2D.Double(toX,toY); - drawline(window, ag, from, to); - } - - //converts from energy into eta coords - static void drawline(AWindow window, AGraphics ag, double fromX, double fromY, double toX, double toY, int etAxisMaximum) - { - fromY=-5-(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(fromY/etAxisMaximum)*0.9; - toY=-5-(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(toY/etAxisMaximum)*0.9; - Point2D.Double from= new Point2D.Double(fromX,fromY); - Point2D.Double to= new Point2D.Double(toX,toY); - drawline(window, ag, from, to); - } - - static void drawstring(AWindow window, AGraphics ag, String str, double hereX, double hereY) - { - Point2D.Double here= new Point2D.Double(hereX,hereY); - here=window.calculateDisplay(here); - ag.drawString(str, here.x,here.y); - } - - //converts from energy into eta coords - static void drawstring(AWindow window, AGraphics ag, String str, double hereX, double hereY, int etAxisMaximum) - { - hereY=-5-(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(hereY/etAxisMaximum)*0.9; - Point2D.Double here= new Point2D.Double(hereX,hereY); - here=window.calculateDisplay(here); - ag.drawString(str, here.x,here.y); - } - - public static void drawGrid(AWindow window, AGraphics ag, double maxEt) - { - ag.setStroke(new BasicStroke(legoGridWidth)); //setting grid line width - int width = window.getSize().width; - int dpi = 72; - // Set a scaling font size with window width (sqrt prevents text from going too small in the small window) - int newFontSize = (int) Math.round(35.0 * Math.sqrt(width) / (double) dpi); - - //change the font size (reset at end) - float originalFontSize= ag.g.getFont().getSize2D(); - Font f = new Font("SansSerif", Font.PLAIN, newFontSize); - ag.setFont(f); - - // Draw the scale and labels on Et axis - ag.setColor(Color.darkGray); - if(backgroundColor.getBlue()+backgroundColor.getGreen()+backgroundColor.getRed() < 400) - ag.setColor(Color.lightGray); - ag.updateColor(); - int etAxisMaximum=(int) maxEt;//convert to int for use later on - int etAxisScale = 10;//seperation of ticks in ET - if (AProjectionLegoPlot.defaultScale ==1 ) - { - etAxisScale=1; - } - else if (maxEt > 10.0) - { - //set scale to 0.1 of nearest hundred to maximum - etAxisScale = 10 * ((int) Math.ceil(maxEt / 100.0)); - } - else if (maxEt == 10.0) - { - etAxisScale = 5; - } - else if (maxEt < 10.0) - { - etAxisScale = 2; - } - double lowPhi=-360*AProjectionLegoPlot.getxz(window.getIndex()); - //lowPhi = 1; - int ticksizex = 10; - double ticksizey = 0.5; - //Draw Et axis - drawline(window,ag,lowPhi,0.0,lowPhi,etAxisMaximum, etAxisMaximum); - //Draw the ticks - for(int s = etAxisMaximum-etAxisScale; s >= 0.0; s-=etAxisScale) - { - drawline(window,ag,lowPhi, s,lowPhi + ticksizex,s, etAxisMaximum); - if (AProjectionLegoPlot.defaultScale ==1 ) - drawstring(window,ag,"10^" + Integer.toString( s + AProjectionLegoPlot.minimumofLogScale ),lowPhi + 2*ticksizex,s,etAxisMaximum); - else - drawstring(window,ag,Integer.toString( s ),lowPhi + 2*ticksizex,s,etAxisMaximum); - } - // Draw the title on Et axis - drawline(window,ag,lowPhi, etAxisMaximum,lowPhi + ticksizex,etAxisMaximum, etAxisMaximum); - if (AProjectionLegoPlot.defaultScale ==1) - drawstring(window,ag,"10^" + Integer.toString( etAxisMaximum + AProjectionLegoPlot.minimumofLogScale) + " ET (GeV)",lowPhi + 2*ticksizex,etAxisMaximum,etAxisMaximum); - else if(AProjectionLegoPlot.defaultScale ==2) - drawstring(window,ag,Integer.toString( etAxisMaximum ) + " ET (GeV)^1/2",lowPhi + 2*ticksizex,etAxisMaximum,etAxisMaximum); - else - drawstring(window,ag,Integer.toString( etAxisMaximum ) + " ET (GeV)",lowPhi + 2*ticksizex,etAxisMaximum,etAxisMaximum); - - // Draw a grid - int t = -1; - for (double p = 0.; p <= 1.; p += 1. / 8.) - { - // parallel to the right side - drawline(window, ag, 360*p+lowPhi, -5.0, 360*p, 5.0); - if (++t % 2 == 0) - { - // a tick - drawline(window,ag,360*p,5.0,360*p,5.0+ticksizey); - String str = new Integer(((int) (360. * p))).toString(); - drawstring(window,ag,str,360*p-7.0,5.0+2.0*Math.sqrt(ticksizey)); - } - } - //Draw the title on phi axis - drawstring(window,ag,AMath.PHI,0.6*360,5.0+3.0*Math.sqrt(ticksizey)); - - for (double e = 0.; e <= 1.; e += 1. / 10.) - { - // parallel to the bottom - drawline(window, ag, lowPhi*(1-e), 10.0*e-5.0, 360.0+lowPhi*(1-e), 10.0*e-5.0); - // a tick - drawline(window, ag, lowPhi*(1-e), 10.0*e-5.0, lowPhi*(1-e), 10.0*e-5.0+ticksizey); - String str = new Integer((int)Math.round(e*10)-5).toString(); - if (AProjectionLegoPlot.reverse) - str = new Integer((int)Math.round(-e*10)+5).toString(); - drawstring(window,ag,str,lowPhi*(1-e)-20, 10.0*e-5.0+3.0*Math.sqrt(ticksizey)); - } - //Draw the title on eta axis - drawstring(window,ag,AMath.ETA,0.5*lowPhi-30,+5.0*Math.sqrt(ticksizey)); - - //reset font size - ag.g.setFont(ag.g.getFont().deriveFont(originalFontSize)); - } - - public static void drawJet(double et, double eta, double phi, Color color, AWindow window, AGraphics ag, double radius) - { - ag.setStroke(new BasicStroke(legoTowersWidth)); //Setting Lego Towers Width - double x = (phi*360)/ AMath.TWO_PI;//x is phi converted from rad to deg - int numPoints = 128;//points around circumference of circle - double[][] hj = new double[2][numPoints]; - double[][] vj = new double[2][numPoints]; - int phiwrap = 0; - double old_jetx = -1; - int[] pj = new int[2]; - pj[0] = pj[1] = 0; - for (int p = 0; p < numPoints; p++) - { - //add on fraction of diameter of circle in phi - double jetx = x + radius*36 * Math.cos(AMath.TWO_PI * p / (numPoints - 1)); - if (jetx < 0) - jetx += 360; - if(jetx >= 360) - jetx -= 360; - if(old_jetx > 0) - { - double jetx_diff = Math.abs(jetx - old_jetx); - if(jetx_diff > 360 / 2) - phiwrap = (phiwrap + 1) % 2; - } - // remember the last jetx, to see if we've wrapped around next time - old_jetx = jetx; - double y = eta; - if (AProjectionLegoPlot.reverse) - y = -y; - //add on fraction of diameter of circle in eta - double jety = y + radius * Math.sin(AMath.TWO_PI * p / (numPoints - 1)); - jetx=AProjectionLegoPlot.adjustPhi(window,jetx,jety);//move phi value due to slant of eta axis - Point2D.Double[] corners=window.getUserCorners(); - if(jetx < corners[0].x || jetx > corners[1].x || jety < corners[1].y || jety > corners[2].y) - continue;//exits loop if not in limits of drawn plot - hj[phiwrap][pj[phiwrap]] = jetx; - vj[phiwrap][pj[phiwrap]] = jety; - ++pj[phiwrap]; - } - - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<pj[0]; i++) - { - p = window.calculateDisplay(hj[0][i],vj[0][i]); - hj[0][i]=p.x; - vj[0][i]=p.y; - } - p.x=0; p.y=0; - for(int i=0; i<pj[1]; i++) - { - p = window.calculateDisplay(hj[1][i],vj[1][i]); - hj[1][i]=p.x; - vj[1][i]=p.y; - } - Stroke origStroke = ag.getGraphics2D().getStroke(); - boolean drawFrames = AColorMap.drawFrames(); - //if drawing frames this part draws the frame otherwise draws the fill - ag.setStroke(new BasicStroke(3)); - if(drawFrames) - ag.setColor(AProjectionLegoPlot.defaultColorMap[AColorMap.BK]); - else - ag.setColor(color); - - if (pj[0] > 2) - { - ag.drawPolygon(hj[0], vj[0], pj[0]); - } - if (pj[1] > 2) - { - ag.drawPolygon(hj[1], vj[1], pj[1]); - } - - //this part will draw the fill color inside the frame if is not black otherwise already drawn - if(drawFrames && !color.equals(AProjectionLegoPlot.defaultColorMap[AColorMap.BK])) - { - ag.setStroke(new BasicStroke(1)); - ag.setColor(color); - - if (pj[0] > 2) - { - ag.drawPolygon(hj[0], vj[0], pj[0]); - } - if (pj[1] > 2) - { - ag.drawPolygon(hj[1], vj[1], pj[1]); - } - } - - //reset stroke - ag.setStroke(origStroke); - } - - public static void drawJetText(double et, double eta, double phi, Color color, AWindow window, AGraphics ag, double radius) - { - double x = (phi*360)/ AMath.TWO_PI;//x is phi converted from rad to deg - int numPoints = 128;//points around circumference of circle - double[][] hj = new double[2][numPoints]; - double[][] vj = new double[2][numPoints]; - int phiwrap = 0; - double old_jetx = -1; - int[] pj = new int[2]; - pj[0] = pj[1] = 0; - for (int p = 0; p < numPoints; p++) - { - //add on fraction of diameter of circle in phi - double jetx = x + radius*36 * Math.cos(AMath.TWO_PI * p / (numPoints - 1)); - if (jetx < 0) - jetx += 360; - if(jetx >= 360) - jetx -= 360; - if(old_jetx > 0) - { - double jetx_diff = Math.abs(jetx - old_jetx); - if(jetx_diff > 360 / 2) - phiwrap = (phiwrap + 1) % 2; - } - // remember the last jetx, to see if we've wrapped around next time - old_jetx = jetx; - double y = eta; - if (AProjectionLegoPlot.reverse) - y = -y; - //add on fraction of diameter of circle in eta - double jety = y + radius * Math.sin(AMath.TWO_PI * p / (numPoints - 1)); - jetx=AProjectionLegoPlot.adjustPhi(window,jetx,jety);//move phi value due to slant of eta axis - Point2D.Double[] corners=window.getUserCorners(); - if(jetx < corners[0].x || jetx > corners[1].x || jety < corners[1].y || jety > corners[2].y) - continue;//exits loop if not in limits of drawn plot - hj[phiwrap][pj[phiwrap]] = jetx; - vj[phiwrap][pj[phiwrap]] = jety; - ++pj[phiwrap]; - } - - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<pj[0]; i++) - { - p = window.calculateDisplay(hj[0][i],vj[0][i]); - hj[0][i]=p.x; - vj[0][i]=p.y; - } - - //draw the jet et as text - String s = Double.toString(et); - int dot = s.indexOf('.'); - String ss = s.substring(0, dot+0); - float originalFontSize= ag.g.getFont().getSize2D(); - float newFontSize= (float) 25.; - ag.g.setFont(ag.g.getFont().deriveFont(newFontSize)); - ag.g.setColor(color); - ag.drawString(" "+ss, hj[0][0], vj[0][0]); - ag.g.setFont(ag.g.getFont().deriveFont(originalFontSize)); - } - - public static void drawMissEt(AWindow window, AGraphics ag, int phi, double pt, Color color, double maxEt) - { - //color - ag.setColor(color); - - drawBox(window, ag, phi, 0, AProjectionLegoPlot.DRAW_MET, 0, pt, maxEt, 0.5); - - double phibinsize=360.0/AProjectionLegoPlot.nPhiCells; - double[] h = new double[4]; - double[] v = new double[4]; - double etaChange = 0.5; - for(double etaStart=-5.0; etaStart<5.0; etaStart+=2*etaChange) - { - v[0] = etaStart; - h[0] = AProjectionLegoPlot.adjustPhi(window,phi*phibinsize,v[0]); - v[1] = v[0]+etaChange; - h[1] = AProjectionLegoPlot.adjustPhi(window,phi*phibinsize,v[1]); - v[2] = v[1]; - h[2] = h[1] + phibinsize; - v[3] = v[0]; - h[3] = h[0] + phibinsize; - //convert to window coords - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<4; i++) - { - p = window.calculateDisplay(h[i],v[i]); - h[i]=p.x; - v[i]=p.y; - } - //draw - ag.fillPolygon(h, v, 4); - } - } - - public static void drawBox(AWindow window, AGraphics ag, int phi, int eta, int colouring, double et1, double et2, double maxEt, double boxsize) - { - Color drawingColor; - //if colouring < 0 ->AOD object, otherwise its cells - switch(colouring){ - case AProjectionLegoPlot.DRAW_MET: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("ETMis", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_MUON: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("Muon", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_ELECTRON: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("Electron", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_PHOTON: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("Photon", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_CLUSTER: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("Cluster", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_COMPOSITEPARTICLE: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("CompositeParticle", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_BJET: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("BJet", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_TAUJET: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("TauJet", "Constant").getI()]; - break; - case AProjectionLegoPlot.DRAW_JET: - drawingColor=AProjectionLegoPlot.defaultColorMap[parameterStore.get("Jet", "Constant").getI()]; - break; - default: drawingColor=AProjectionLegoPlot.caloColorMap[colouring]; - } - - int object = -colouring;//should be positive for "objects" and negative for calo cells - - //now check transparency option - //result is transparent if colouring is < 0 - switch(parameterStore.get("LegoPlot", "TowerOutlines").getI()){ - //AOD: colouring is already correct - case 0: break; - //cells: reverse so now AOD solid - case 1: colouring*=-1; break; - //both - case 2: colouring=-1; break; - //neither - case 3: colouring=1; break; - } - double phibinsize=360.0/AProjectionLegoPlot.nPhiCells; - double etabinsize=10.0/AProjectionLegoPlot.nEtaCells; - double x = phi*phibinsize;//x is real phi position - double y = eta*etabinsize-5;//y is real eta position - if (object>0) {phibinsize=360./64.; etabinsize=10./100.;} - double x1 = AProjectionLegoPlot.adjustPhi(window,x, y);//x1 is real phi position - double x2 = AProjectionLegoPlot.adjustPhi(window,x, y-etabinsize);//shifted x due to eta bin size - double[][] h = new double[3][4]; - double[][] v = new double[3][4]; - //adjust the values of the energies - et1=(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(et1/maxEt)*0.9; - et2=et1+(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(et2/maxEt)*0.9; - - double phishift = boxsize * (phibinsize/2); //to center towers with recpt eta-phi coordinates x1 and x2 - double etashift = boxsize * ((etabinsize)/2); - - //front - h[0][0] = x1 - phishift; - v[0][0] = y-et1 - etashift; // (bottom front) - h[0][1] = x1 - phishift; - v[0][1] = y-et2 - etashift; - h[0][2] = x1 + phishift; - v[0][2] = y-et2 - etashift; - h[0][3] = x1 + phishift; - v[0][3] = y-et1 - etashift; - //top - h[1][0] = x2 - phishift; - v[1][0] = y-et2- etashift-etashift; //SHIFT to make top squared - h[1][1] = x1 - phishift; - v[1][1] = y-et2 - etashift; - h[1][2] = x1 + phishift; - v[1][2] = y-et2 - etashift; - h[1][3] = x2 + phishift; - v[1][3] = y-et2- etashift-etashift; //SHIFT to make top squared - //side - h[2][0] = x2 - (phishift); - v[2][0] = y-(et2)- etashift -etashift; // top back SHIFT to make top squared - h[2][1] = x1 - phishift; - v[2][1] = y-et2 - etashift; // top front - h[2][2] = x1 - phishift; - v[2][2] = y-(et1) - etashift; // bottom front - h[2][3] = x2 - (phishift); - v[2][3] = y-et1 -(etashift); // bottom back - - - //convert to window coords - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<4; i++) - { - p = window.calculateDisplay(h[0][i],v[0][i]); - h[0][i]=p.x; - v[0][i]=p.y; - p.x=0; p.y=0; - p = window.calculateDisplay(h[1][i],v[1][i]); - h[1][i]=p.x; - v[1][i]=p.y; - p.x=0; p.y=0; - p = window.calculateDisplay(h[2][i],v[2][i]); - h[2][i]=p.x; - v[2][i]=p.y; - } - - //draw sides - ag.setColor(drawingColor); - if (colouring>=0) - ag.fillPolygon(h[2], v[2], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[2], v[2], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); //f specifies transparency fraction - } - else - ag.fillPolygon(h[2], v[2], 4, 0.8f); //f specifies transparency fraction - - //colour front - ag.setColor(drawingColor); - //draw front - if (colouring>=0) - ag.fillPolygon(h[0], v[0], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[0], v[0], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); //f specifies transparency fraction - } - else - ag.fillPolygon(h[0], v[0], 4, 0.8f); //f specifies transparency fraction - - //colour top - Color ddc = drawingColor.darker().darker(); - ag.setColor(new Color(ddc.getRed(),ddc.getGreen(),ddc.getBlue())); - //draw top - if (colouring>=0) - ag.fillPolygon(h[1], v[1], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[1], v[1], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); //f specifies transparency fraction - } - else - ag.fillPolygon(h[1], v[1], 4, 0.8f); //f specifies transparency fraction - - } - - //draw box method that can be used when not all the towers of certain object have assigned the same colour - the parameter color specifies the i color component - public static void drawBox(AWindow window, AGraphics ag, int phi, int eta, int colouring, Color color, double et1, double et2, double maxEt, double boxsize) - { - Color drawingColor; - switch(colouring){ - case AProjectionLegoPlot.DRAW_MET: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_MUON: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_ELECTRON: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_PHOTON: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_CLUSTER: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_COMPOSITEPARTICLE: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_BJET: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_TAUJET: - drawingColor= color; - break; - case AProjectionLegoPlot.DRAW_JET: - drawingColor= color; - break; - default: drawingColor=AProjectionLegoPlot.caloColorMap[colouring]; - } - - int object = -colouring;//should be positive for "objects" and negative for calo cells - - //now check transparency option - //result is transparent if colouring is < 0 - switch(parameterStore.get("LegoPlot", "TowerOutlines").getI()){ - //AOD: colouring is already correct - case 0: break; - //cells: reverse so now AOD solid - case 1: colouring*=-1; break; - //both - case 2: colouring=-1; break; - //neither - case 3: colouring=1; break; - } - double phibinsize=360.0/AProjectionLegoPlot.nPhiCells; - double etabinsize=10.0/AProjectionLegoPlot.nEtaCells; - double x = phi*phibinsize;//x is real phi position - double y = eta*etabinsize-5;//y is real eta position - if (object>0) {phibinsize=360./64.; etabinsize=10./100.;} - double x1 = AProjectionLegoPlot.adjustPhi(window,x, y);//x1 is real phi position - double x2 = AProjectionLegoPlot.adjustPhi(window,x, y-etabinsize);//shifted x due to eta bin size - double[][] h = new double[3][4]; - double[][] v = new double[3][4]; - //adjust the values of the energies - et1=(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(et1/maxEt)*0.9; - et2=et1+(1-AProjectionLegoPlot.getyz(window.getIndex()))*50*(et2/maxEt)*0.9; - - double phishift = boxsize * (phibinsize/2); //to center towers with recpt eta-phi coordinates x1 and x2 - double etashift = boxsize * ((etabinsize)/2); - - //front - h[0][0] = x1 - phishift; - v[0][0] = y-et1 - etashift; // (bottom front) - h[0][1] = x1 - phishift; - v[0][1] = y-et2 - etashift; - h[0][2] = x1 + phishift; - v[0][2] = y-et2 - etashift; - h[0][3] = x1 + phishift; - v[0][3] = y-et1 - etashift; - //top - h[1][0] = x2 - phishift; - v[1][0] = y-et2- etashift-etashift; //SHIFT to make top squared - h[1][1] = x1 - phishift; - v[1][1] = y-et2 - etashift; - h[1][2] = x1 + phishift; - v[1][2] = y-et2 - etashift; - h[1][3] = x2 + phishift; - v[1][3] = y-et2- etashift-etashift; //SHIFT to make top squared - //side - h[2][0] = x2 - (phishift); - v[2][0] = y-(et2)- etashift -etashift; // top back SHIFT to make top squared - h[2][1] = x1 - phishift; - v[2][1] = y-et2 - etashift; // top front - h[2][2] = x1 - phishift; - v[2][2] = y-(et1) - etashift; // bottom front - h[2][3] = x2 - (phishift); - v[2][3] = y-et1 -(etashift); // bottom back - - //convert to window coords - Point2D.Double p= new Point2D.Double(0,0); - for(int i=0; i<4; i++) - { - p = window.calculateDisplay(h[0][i],v[0][i]); - h[0][i]=p.x; - v[0][i]=p.y; - p.x=0; p.y=0; - p = window.calculateDisplay(h[1][i],v[1][i]); - h[1][i]=p.x; - v[1][i]=p.y; - p.x=0; p.y=0; - p = window.calculateDisplay(h[2][i],v[2][i]); - h[2][i]=p.x; - v[2][i]=p.y; - } - - //draw sides - ag.setColor(drawingColor); - if (colouring>=0) - ag.fillPolygon(h[2], v[2], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[2], v[2], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); - }else if (colouring == AProjectionLegoPlot.DRAW_BJET) { - ag.fillPolygon(h[2], v[2], 4, 0.4f); - }else - ag.fillPolygon(h[2], v[2], 4, 0.8f); //f specifies transparency fraction - - //colour front - ag.setColor(drawingColor); - //draw front - if (colouring>=0) - ag.fillPolygon(h[0], v[0], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[0], v[0], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); - }else if(colouring == AProjectionLegoPlot.DRAW_BJET) { - ag.fillPolygon(h[0], v[0], 4, 0.4f); - }else - ag.fillPolygon(h[0], v[0], 4, 0.8f); //f specifies transparency fraction - - //colour top - Color ddc = drawingColor.darker().darker(); - ag.setColor(new Color(ddc.getRed(),ddc.getGreen(),ddc.getBlue())); - //draw top - if (colouring>=0) - ag.fillPolygon(h[1], v[1], 4); - else if(colouring == AProjectionLegoPlot.DRAW_JET){ - ag.fillPolygon(h[1], v[1], 4, (float)APar.instance().get("Jet","AlphaJets").getD()); //f specifies transparency fraction - }else if(colouring == AProjectionLegoPlot.DRAW_BJET) { - ag.fillPolygon(h[1], v[1], 4, 0.4f); //f specifies transparency fraction - } - else - ag.fillPolygon(h[1], v[1], 4, 0.8f); //f specifies transparency fraction - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/graphics/APickingGraphics2D.java b/graphics/AtlantisJava/src/atlantis/graphics/APickingGraphics2D.java deleted file mode 100755 index 9757b84ccdd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/APickingGraphics2D.java +++ /dev/null @@ -1,432 +0,0 @@ -package atlantis.graphics; - -import java.awt.Graphics; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.PathIterator; -import java.util.ArrayList; - -import javax.swing.JPopupMenu; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.event.AData; -import atlantis.data.ATrackData; -import atlantis.data.ATrackResidualData; -import atlantis.list.AList; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjectionTrackResidual; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.ALogger; - -/** - * A very limited PostScript graphics context for output of Atlantis functions - * Any call to a none implemented will throw an exception - */ - -public class APickingGraphics2D extends ATemplateGraphics2D -{ - private static ALogger logger = ALogger.getLogger(APickingGraphics2D.class); - - public final static int PICK_HITS_AND_TRACKS = 0; - public final static int PICK_DETECTORS = 1; - public final static int MOVE = 2; - public final static int PICK_RESIDUAL = 3; - - public static int mode; - - static AData pickedData = null; - static ATrackResidualData pickedResidual = null; - static ArrayList pickedDetectors; - static int pickedIndex; - - public static Point pickedPoint; - static double minDist; - public static double pickedH; - public static double pickedV; - - private static JPopupMenu residualPopupMenu; - private static final String SHOW_RESIDUALS_X = "Show Residual X"; - private static final String SHOW_PULLS_X = "Show Pull X"; - - static - { - residualPopupMenu = new JPopupMenu(); - ActionListener residualPopupActionListener = - new APickingGraphics2D.ResidualPopupMenuActionListener(); - residualPopupMenu.add(SHOW_RESIDUALS_X).addActionListener(residualPopupActionListener); - residualPopupMenu.add(SHOW_PULLS_X).addActionListener(residualPopupActionListener); - } - - static class ResidualPopupMenuActionListener implements ActionListener - { - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - - // Use window "B" to show track residual - String residualWindowName = "B"; - if(ACanvas.getCanvas().isValidWindowName(residualWindowName)) - { - AWindow residualWindow = ACanvas.getCanvas().getWindow(residualWindowName); - AProjectionTrackResidual residualProj = - (AProjectionTrackResidual) AProjectionsManager.getProjection("TrackResidual"); - if (action.equals(SHOW_RESIDUALS_X)) - residualProj.setResidualType(ATrackResidualData.RESIDUAL_X); - else if (action.equals(SHOW_PULLS_X)) - residualProj.setResidualType(ATrackResidualData.PULL_X); - - // when this action is activated, the pickedData must be a track - ATrackData trackData = (ATrackData) pickedData; - residualProj.setResidual(trackData.getTrackResidual(pickedIndex)); - ACanvas.getCanvas().moveToFrontWindow(residualWindowName); - residualWindow.setProjection(residualProj); - } - else - AOutput.append("\nWindow " + residualWindowName + " is not available in current layout" - + "\n", ALogInterface.WARNING); - } - } - - public APickingGraphics2D(Rectangle bounds, int m, Point p) - { - super(bounds); - mode = m; - pickedPoint = p; - minDist = 10000000.; - if (mode != MOVE) - { - pickedData = null; - pickedIndex = -1; - } - if (pickedDetectors == null) - { - pickedDetectors = new ArrayList(); - } - else - { - pickedDetectors.clear(); - } - } - - APickingGraphics2D(APickingGraphics2D a) - { - super(a); - } - - public Graphics create() - { - return new APickingGraphics2D(this); - } - - public void drawLine(double h0, double v0, double h1, double v1) - { - if (mode == PICK_DETECTORS) - return; - if (AGraphics.currentData == null) - return; - if (mode == MOVE && - !(AGraphics.currentData == pickedData && AGraphics.currentIndex == pickedIndex)) - return; - double hPicked = pickedPoint.getX(); - double vPicked = pickedPoint.getY(); - // treat first two endpoints - double delH = h0 - hPicked; - double delV = v0 - vPicked; - double dist = delH * delH + delV * delV; - - if (dist < minDist) - { - minDist = dist; - setPicked(h0, v0); - } - delH = h1 - hPicked; - delV = v1 - vPicked; - dist = delH * delH + delV * delV; - if (dist < minDist) - { - minDist = dist; - setPicked(h1, v1); - } - // now treat point within line being closest - double h10 = h1 - h0; - double v10 = v1 - v0; - double hp0 = hPicked - h0; - double vp0 = vPicked - v0; - double size = h10 * h10 + v10 * v10; - - if (size > 0.0) - { - double u = (h10 * hp0 + v10 * vp0) / size; - - if (u > 0. && u < 1.) - { - double hClosest = h0 + u * h10; - double vClosest = v0 + u * v10; - - delH = hClosest - hPicked; - delV = vClosest - vPicked; - dist = delH * delH + delV * delV; - if (dist < minDist) - { - minDist = dist; - setPicked(hClosest, vClosest); - } - } - } - } - - public void fillRect(int h, int v, int width, int height) - { - if (mode == PICK_DETECTORS && AGraphics.currentDetector != null) - { - // Collect the different detector names. - String info = AGraphics.currentDetector.getInfo(AGraphics.currentIndex); - if (!pickedDetectors.contains(info)) - { - pickedDetectors.add(info); - } - } - double dh = width / 2.; - double dv = height / 2.; - drawLine(h - dh, v - dv, h + dh, v - dv); - drawLine(h + dh, v - dv, h + dh, v + dv); - drawLine(h + dh, v + dv, h - dh, v + dv); - drawLine(h - dh, v + dv, h - dh, v - dv); - } - - public void draw(Shape s) - { - PathIterator path = s.getPathIterator(null); - double[] coords = new double[6]; - double h0 = 0.; - double v0 = 0.; - double h1 = 0.; - double v1 = 0.; - double hInit = 0.; - double vInit = 0.; - while (!path.isDone()) - { - int segType = path.currentSegment(coords); - - switch (segType) - { - case PathIterator.SEG_MOVETO: - h0 = coords[0]; - v0 = coords[1]; - hInit = h0; - vInit = v0; - break; - - case PathIterator.SEG_LINETO: - case PathIterator.SEG_CUBICTO: - h1 = coords[0]; - v1 = coords[1]; - drawLine(h0, v0, h1, v1); - h0 = h1; - v0 = v1; - break; - - case PathIterator.SEG_CLOSE: - drawLine(h0, v0, hInit, vInit); - break; - - default: - logger.error(" Error unknown segment type"); - break; - } - path.next(); - } - } - - public void fill(Shape s) - { - if (mode == PICK_DETECTORS && AGraphics.currentDetector != null) - { - double[][] hv = getPolygon(s); - if (AGraphics.isPointInside(hv[0], hv[1], hv[0].length, pickedPoint.getX(), pickedPoint.getY())) - { - // Collect the different detector names. - String info = AGraphics.currentDetector.getInfo(AGraphics.currentIndex); - if (!pickedDetectors.contains(info)) - { - pickedDetectors.add(info); - } - } - } - else - { - draw(s); - } - } - - public double[][] getPolygon(Shape s) - { - double[] coords = new double[6]; - - int numPoints = 0; - PathIterator path = s.getPathIterator(null); - while (!path.isDone()) - { - int segType = path.currentSegment(coords); - switch (segType) - { - case PathIterator.SEG_MOVETO: - numPoints++; - break; - - case PathIterator.SEG_LINETO: - case PathIterator.SEG_CUBICTO: - numPoints++; - break; - - case PathIterator.SEG_CLOSE: - // numPoints++; - break; - - default: - break; - } - path.next(); - } - double[][] hv = new double[2][numPoints]; - numPoints = 0; - path = s.getPathIterator(null); - while (!path.isDone()) - { - int segType = path.currentSegment(coords); - - switch (segType) - { - case PathIterator.SEG_MOVETO: - hv[0][numPoints] = coords[0]; - hv[1][numPoints] = coords[1]; - numPoints++; - break; - - case PathIterator.SEG_LINETO: - case PathIterator.SEG_CUBICTO: - hv[0][numPoints] = coords[0]; - hv[1][numPoints] = coords[1]; - numPoints++; - break; - - case PathIterator.SEG_CLOSE: - // drawLine(h0,v0,hInit,vInit); - break; - - default: - logger.error(" Error unknown segment type"); - break; - } - path.next(); - } - return hv; - } - - private static void setPicked(double h, double v) - { - pickedData = AGraphics.currentData; - pickedIndex = AGraphics.currentIndex; - pickedH = h; - pickedV = v; - } - - public static AData getPickedData() - { - return pickedData; - - } // getPickedData() - - public static ATrackResidualData getPickedResidual() - { - return pickedResidual; - } - - public static int getPickedH() - { - return (int) Math.rint(pickedH); - } - - public static int getPickedV() - { - return (int) Math.rint(pickedV); - } - - public static AList getPickedHit() - { - if (pickedData != null) - return new AList(pickedData, pickedIndex); - else - return null; - } - - public static Integer getPickedHitIndex() - { - if (pickedData != null) - { - return new Integer(pickedIndex); - } - else - { - return null; - } - } - - public static void setPicked(AData data, int index) - { - pickedData = data; - pickedIndex = index; - } - - public static void setPicked(ATrackResidualData data) - { - pickedResidual = data; - } - - public static void printPicked() - { - if(mode == APickingGraphics2D.PICK_RESIDUAL) - { - AOutput.alwaysAppend("\n\n" + pickedResidual.getHitInfo(), ALogInterface.PICK); - mode = APickingGraphics2D.PICK_HITS_AND_TRACKS; - } - else - { - if (pickedData != null) - { - AOutput.alwaysAppend("\n\n" + pickedData.getHitInfo(pickedIndex), ALogInterface.PICK); - } - else if (pickedDetectors != null && pickedDetectors.size() > 0) - { - AOutput.alwaysAppend("\n\nYou are inside:\n", ALogInterface.PICK); - for (int i = 0; i < pickedDetectors.size(); i++) - { - AOutput.alwaysAppend(" " + pickedDetectors.get(i) + "\n", ALogInterface.PICK); - } - } - } - } - - /** - * Method is called after pick+n (navigate = show data associations) - */ - public static void navigatePicked() - { - if(pickedData != null) - { - String navigateInfo = pickedData.navigate(pickedIndex); - AOutput.alwaysAppend("\n" + navigateInfo + "\n", ALogInterface.PICK); - } - } - - public static void showTrackResiduals(AWindow window, int x, int y) - { - APickingGraphics2D.residualPopupMenu.show(window, x, y); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/APixelGraphics.java b/graphics/AtlantisJava/src/atlantis/graphics/APixelGraphics.java deleted file mode 100755 index 44a5136d93c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/APixelGraphics.java +++ /dev/null @@ -1,304 +0,0 @@ -package atlantis.graphics; - -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.geom.GeneralPath; - -/** - * This graphics is used for drawing on the screen and making pixel based - * images. In the end all drawing is done in pixels(integers). Picking is - * implemented here. Provide high quality pixel based drawing of thin frames - * around lines and areas, in the method draw. - */ -// When drawing borders could speed things up by only drawing what is needed -public class APixelGraphics extends AGraphics -{ - APixelGraphics(Graphics g) - { - super(g); - } - - public void setLineWidth(int lineWidth) - {} - - public void drawLine(double h0, double v0, double h1, double v1) - { - if (clipper.isLineWithin(h0, v0, h1, v1)) - { - double[][] hvClipped = clipper.getHV(); - double h0Clipped = hvClipped[0][0]; - double v0Clipped = hvClipped[1][0]; - double h1Clipped = hvClipped[0][1]; - double v1Clipped = hvClipped[1][1]; - if (lineWidth == 1) - { - updateColor(); - g.drawLine((int) h0Clipped, (int) v0Clipped, (int) h1Clipped, (int) v1Clipped); - } - else - { - drawThickLine(h0Clipped, v0Clipped, h1Clipped, v1Clipped); - } - } - - } // drawLine() - - private void drawThickLine(double h0, double v0, double h1, double v1) - { - // Drawing thick line this way is quicker than using setLine width - // correct for Postscipt - // pretty good for pixel device (assume java line drawing is Bresenhams - // or similar) - double h = Math.abs(h1 - h0); - double v = Math.abs(v1 - v0); - - for (int i = 0; i < lineWidth; ++i) - { - // 101/50 to avoid rounding toward 0 problem - int d = i + (101 - lineWidth) / 2 - 50; - - int h0new = (int) h0; - int v0new = (int) v0; - int h1new = (int) h1; - int v1new = (int) v1; - - if (h > v) - { - v0new += d; - v1new += d; - } - else - { - h0new += d; - h1new += d; - } - - // Caution!!! - // When point (h0, v0) or (h1, v1) is close to the border of the - // drawing area, after +/- d, the (h0new, v0new) or (h1new, v1new) - // might beyond the valid value range, which will cause an - // IndexArrayOutOfBound error thrown from g.drawLine method. - if(clipper.isLineWithin(h0new, v0new, h1new, v1new)) - { - updateColor(); - h0new = (int) clipper.getH0(); - v0new = (int) clipper.getV0(); - h1new = (int) clipper.getH1(); - v1new = (int) clipper.getV1(); - g.drawLine(h0new, v0new, h1new, v1new); - } - } - } - - public void drawSmoothLine(double h0, double v0, double ch0, double cv0, - double ch1, double cv1, double h1, double v1) - { - GeneralPath curve = new GeneralPath(); - for (int i=0; i<lineWidth; ++i) { - // 101/50 to avoid rounding toward 0 problem - int d = i + (101 - lineWidth) / 2 - 50; - float dh, dv; - - if (Math.abs(h1 - h0) > Math.abs(v1 - v0)) { - dh = 0; - dv = d; - } else { - dh = d; - dv = 0; - } - - curve.moveTo((float)h0+dh, (float)v0+dv); - curve.curveTo((float)ch0+dh, (float)cv0+dv, (float)ch1+dh, (float)cv1+dv, (float)h1+dh, (float)v1+dv); - } - updateColor(); - g.draw(curve); - } - - protected void fillRect(double h, double v, int width, int height) - { - updateColor(); - g.fillRect((int) (h - width / 2.), (int) (v - height / 2.), width, height); - } - - @Override - protected void fillOval(double h, double v, int width, int height) { - - g.fillOval((int) (h - width / 2.), (int) (v - height / 2.), width, height); - g.drawOval((int) (h - width / 2.), (int) (v - height / 2.), width, height); - } - - public void drawPolygon(double[] h, double[] v, int numPoints) - { - int type = getContainmentType(h, v, numPoints, POLYGON); - - if (type == FULLY_INSIDE || type == INTERSECTS) - { - for (int i = 0; i < numPoints - 1; ++i) - { - drawLine(h[i], v[i], h[i + 1], v[i + 1]); - } - if (numPoints > 1) - { - drawLine(h[numPoints - 1], v[numPoints - 1], h[0], v[0]); - } - } - } // drawPolygon() - - public void drawPolyline(double[] h, double[] v, int numPoints) - { - int type = getContainmentType(h, v, numPoints, POLYLINE); - if (type == FULLY_INSIDE || type == INTERSECTS) - { - // Some code here to simplify polylines by only drawing segments - // at least 1 pixel long, speeds up the ellipses for recvertices - // quite a lot since they're often very small but have thousands - // of line segments - AD - double lasth = 0.0; - double lastv = 0.0; - - for (int i = 0; i < numPoints - 1; ++i) { - if (i == 0) { - // Always draw something - lasth = h[1]; - lastv = v[1]; - drawLine(h[0], v[0], h[1], v[1]); - } - - double diffh = h[i+1] - lasth; - double diffv = v[i+1] - lastv; - - if ((diffh*diffh + diffv*diffv) > 1.0) { - drawLine(lasth, lastv, h[i + 1], v[i + 1]); - lasth = h[i+1]; - lastv = v[i+1]; - } - } - } - } // drawPolyline() - - public void drawDottedPolyline(double[] h, double[] v, int numPoints) - { - int type = getContainmentType(h, v, numPoints, POLYLINE); - if (type == FULLY_INSIDE || type == INTERSECTS) - { - for (int i = 0; i < numPoints - 1; i += 2) - drawLine(h[i], v[i], h[i + 1], v[i + 1]); - } - } // drawDottedPolyline() - - public void drawSmoothPolyline(double[] h0, double[] v0, int numPoints0) { - - // For curves having less than 3 points and for picking use the normal polyline. - if (numPoints0 < 3 || g instanceof APickingGraphics2D) { - drawPolyline(h0, v0, numPoints0); - return; - } - - int type = getContainmentType(h0, v0, numPoints0, POLYLINE); - if (type == FULLY_INSIDE || type == INTERSECTS) { - - int numPoints = 3 * numPoints0 - 2; - - // Add the control points to the array, at 1/3 and 2/3 - // between the already existing points. - float[] h = new float[numPoints]; - float[] v = new float[numPoints]; - for (int i=0; i<numPoints; i++) { - - switch (i%3) { - case 0: - // One of the fixed points. - h[i] = (float)h0[i/3]; - v[i] = (float)v0[i/3]; - break; - case 1: - // First control point. - h[i] = (float)(2./3. * h0[i/3] + 1./3. * h0[i/3+1]); - v[i] = (float)(2./3. * v0[i/3] + 1./3. * v0[i/3+1]); - break; - case 2: - // Second control point. - h[i] = (float)(1./3. * h0[i/3] + 2./3. * h0[i/3+1]); - v[i] = (float)(1./3. * v0[i/3] + 2./3. * v0[i/3+1]); - break; - } - } - - // Now we have a normal polyline (straight line segments between fixed points), - // but as a cubic Bezier curve. All we need to do to make it smooth is to move - // the control points away from the curve, in such a way that [control point 2] - - // [fixed point] - [control point 1] is a straight line for every fixed point. - // We do this by averaging the angles of the line segments on either side of a - // fixed point. - for (int i=3; i<numPoints-2; i+=3) { - double lenLeft = Math.sqrt(Math.pow(h[i]-h[i-1], 2) + Math.pow(v[i]-v[i-1], 2)); - double lenRight = Math.sqrt(Math.pow(h[i+1]-h[i], 2) + Math.pow(v[i+1]-v[i], 2)); - - // Without length we cannot define an angle, so skip the point. - if (lenLeft < 1e-6 || lenRight < 1e-6) continue; - - double phiLeft = Math.atan2(v[i]-v[i-1], h[i]-h[i-1]); - double phiRight = Math.atan2(v[i+1]-v[i], h[i+1]-h[i]); - - if (phiLeft-phiRight > Math.PI) { - phiRight += 2.*Math.PI; - } else if (phiRight-phiLeft > Math.PI) { - phiLeft += 2.*Math.PI; - } - - if (Math.abs(phiLeft-phiRight) > Math.PI/2.) { - // The line turns more than 90 degrees, this is wrong. Move the control points - // back in so they are the same as the point on the line. This disables the smooth - // curve locally, reverting to a normal connect-the-dots polyline. - h[i-1] = h[i+1] = h[i]; - v[i-1] = v[i+1] = v[i]; - } else { - // Calculate the desired angle for the tangent by weighting the angle on each side, - // the weight is inverse proportional to the distance to the next point. - double phi = (lenRight*phiLeft + lenLeft*phiRight) / (lenLeft+lenRight); - - h[i-1] = h[i] - (float)(lenLeft*Math.cos(phi)); - v[i-1] = v[i] - (float)(lenLeft*Math.sin(phi)); - h[i+1] = h[i] + (float)(lenRight*Math.cos(phi)); - v[i+1] = v[i] + (float)(lenRight*Math.sin(phi)); - } - } - - for (int i=0; i<numPoints-1; i+=3) { - drawSmoothLine(h[i], v[i], h[i+1], v[i+1], h[i+2], v[i+2], h[i+3], v[i+3]); - } - } - } - - public void fillPolygon(double[] h, double[] v, int numPoints) - { - int type = getContainmentType(h, v, numPoints, POLYGON); - if (type == FULLY_INSIDE || type == INTERSECTS) - { - if (type == INTERSECTS) - { - ACoord clipped = clipper.clipPolygon(h, v, numPoints); - h = clipped.hv[0][0]; - v = clipped.hv[1][0]; - numPoints = h.length; - } - int[] hInt = new int[numPoints]; - int[] vInt = new int[numPoints]; - for (int i = 0; i < numPoints; ++i) - { - hInt[i] = (int) h[i]; - vInt[i] = (int) v[i]; - } - updateColor(); - g.fillPolygon(hInt, vInt, numPoints); - drawPolygon(h, v, numPoints); - } - else if (type == CONTAINS) - { - Rectangle bounds = g.getClipBounds(); - updateColor(); - g.fillRect((int) Math.rint(bounds.getX()), (int) Math.rint(bounds.getY()), (int) Math.rint(bounds.getWidth()), (int) Math.rint(bounds.getHeight())); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/ATemplateGraphics2D.java b/graphics/AtlantisJava/src/atlantis/graphics/ATemplateGraphics2D.java deleted file mode 100755 index 12dcf005ccc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/ATemplateGraphics2D.java +++ /dev/null @@ -1,47 +0,0 @@ -package atlantis.graphics; - -import java.awt.*; - -/** - * A very limited template graphics which implements the default behaviour - * of the clip region. - */ - -public abstract class ATemplateGraphics2D extends ADummyGraphics2D { - - private Rectangle currentClip; - private Rectangle imageBounds; - - public ATemplateGraphics2D(Rectangle bounds) { - currentClip=new Rectangle(bounds); - imageBounds=new Rectangle(bounds); - } - - protected ATemplateGraphics2D(ATemplateGraphics2D parent) { - currentClip=new Rectangle(parent.currentClip); - imageBounds=new Rectangle(parent.imageBounds); - } - - public abstract Graphics create(); - - public Rectangle getClipBounds() { - return new Rectangle(currentClip); - } - - public void setClip(int x, int y, int width, int height) { - currentClip=new Rectangle(x, y, width, height); - } - - public void clipRect(int x, int y, int width, int height) { - currentClip=currentClip.intersection(new Rectangle(x, y, width, height)); - } - - public void translate(int x, int y) { - translate((double)x, (double)y); - } - - public void translate(double x, double y) { - currentClip.setLocation((int)Math.round(currentClip.x-x), (int)Math.round(currentClip.y-y)); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/AVectorGraphics.java b/graphics/AtlantisJava/src/atlantis/graphics/AVectorGraphics.java deleted file mode 100755 index 058f8c075aa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/AVectorGraphics.java +++ /dev/null @@ -1,309 +0,0 @@ -package atlantis.graphics; - -import java.awt.*; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; - -/** - * Used when drawing to postscript - */ -public class AVectorGraphics extends AGraphics { - - private GeneralPath path=new GeneralPath(); - - AVectorGraphics(Graphics g) { - super(g); - } - - public void setLineWidth(int lineWidth) { - setStroke(new BasicStroke(lineWidth)); - } - - public void drawLine(int h0, int v0, int h1, int v1) { - drawLine((double)h0, (double)v0, (double)h1, (double)v1); - } - - public void drawLine(double h0, double v0, double h1, double v1) { - if(clipper.isLineWithin(h0, v0, h1, v1)) { - double[][] hvClipped=clipper.getHV(); - double h0Clipped=hvClipped[0][0]; - double v0Clipped=hvClipped[1][0]; - double h1Clipped=hvClipped[0][1]; - double v1Clipped=hvClipped[1][1]; - - path.reset(); - path.moveTo((float)h0Clipped, (float)v0Clipped); - path.lineTo((float)h1Clipped, (float)v1Clipped); - updateColor(); - g.draw(path); - } - } - - protected void fillRect(double h, double v, int width, int height) { - path.reset(); - float h0=(float)h; - float v0=(float)v; - float dh=(float)(width/2.); - float dv=(float)(height/2.); - - path.moveTo(h0-dh, v0-dv); - path.lineTo(h0+dh, v0-dv); - path.lineTo(h0+dh, v0+dv); - path.lineTo(h0-dh, v0+dv); - path.closePath(); - updateColor(); - g.fill(path); - } - - protected void fillOval(double h, double v, int width, int height) { - - Ellipse2D oval = new Ellipse2D.Float((float)(h-width/2.), (float)(v-height/2.), width, height); - updateColor(); - g.fill(oval); - } - - public void drawPolygon(double[] h, double[] v, int numPoints) { - - int type=getContainmentType(h, v, numPoints, POLYGON); - if(type==FULLY_INSIDE||type==INTERSECTS) { - if(type==INTERSECTS) { - ACoord clipped=clipper.clipPolygon(h, v, numPoints); - h=clipped.hv[0][0]; - v=clipped.hv[1][0]; - numPoints=h.length; - } - - path.reset(); - for(int i=0; i<numPoints; ++i) { - if(i==0) - path.moveTo((float)h[i], (float)v[i]); - else - path.lineTo((float)h[i], (float)v[i]); - } - if(numPoints>0) { - path.closePath(); - updateColor(); - g.draw(path); - } - } - } - - public void drawPolyline(double[] h, double[] v, int numPoints) { - int type=getContainmentType(h, v, numPoints, POLYLINE); - if(type==FULLY_INSIDE||type==INTERSECTS) { - int start=0; - int end=numPoints-1; - - if(type==INTERSECTS) { - // clip polylines if there is only one interval - for(int i=0; i<numPoints-1; i++) { - if(clipper.isLineWithin(h[i], v[i], h[i+1], v[i+1])) { - start=i; - break; - } - } - for(int i=numPoints-1; i>start; i--) { - if(clipper.isLineWithin(h[i], v[i], h[i-1], v[i-1])) { - end=i; - break; - } - } - for(int i=start; i<end; i++) { - if(!clipper.isLineWithin(h[i], v[i], h[i+1], v[i+1])) { - start=0; - end=numPoints-1; - break; - } - } - } - - /* - if (type == INTERSECTS) { - ACoord clipped = clipper.clipPolygon(h, v, numPoints); - h = clipped.hv[0][0]; - v = clipped.hv[1][0]; - numPoints = h.length; - } - */ - - path.reset(); - for(int i=start; i<=end; ++i) { - if(i==start) - path.moveTo((float)h[i], (float)v[i]); - else - path.lineTo((float)h[i], (float)v[i]); - } - if(end-start>0) { - updateColor(); - g.draw(path); - } - } - } - - // very similar with drawPolyline, but draw a dotted instead - public void drawDottedPolyline(double[] h, double[] v, int numPoints) { - int type=getContainmentType(h, v, numPoints, POLYLINE); - if(type==FULLY_INSIDE||type==INTERSECTS) { - int start=0; - int end=numPoints-1; - - if(type==INTERSECTS) { - // clip polylines if there is only one interval - for(int i=0; i<numPoints-1; i++) { - if(clipper.isLineWithin(h[i], v[i], h[i+1], v[i+1])) { - start=i; - break; - } - } - for(int i=numPoints-1; i>start; i--) { - if(clipper.isLineWithin(h[i], v[i], h[i-1], v[i-1])) { - end=i; - break; - } - } - for(int i=start; i<end; i++) { - if(!clipper.isLineWithin(h[i], v[i], h[i+1], v[i+1])) { - start=0; - end=numPoints-1; - break; - } - } - } - - path.reset(); - boolean drawFlag = false; - for(int i=start; i<=end; ++i) { - if(drawFlag) - path.lineTo((float)h[i], (float)v[i]); - else - path.moveTo((float)h[i], (float)v[i]); - drawFlag = !drawFlag; - } - if(end-start>0) { - updateColor(); - g.draw(path); - } - } - - } - - public void drawSmoothPolyline(double[] h0, double[] v0, int numPoints0) { - - // For curves having less than 3 points and for picking use the normal polyline. - if (numPoints0 < 3 || g instanceof APickingGraphics2D) { - drawPolyline(h0, v0, numPoints0); - return; - } - - int type = getContainmentType(h0, v0, numPoints0, POLYLINE); - if (type == FULLY_INSIDE || type == INTERSECTS) { - - GeneralPath curve = new GeneralPath(); - int numPoints = 3 * numPoints0 - 2; - - // Add the control points to the array, at 1/3 and 2/3 - // between the already existing points. - float[] h = new float[numPoints]; - float[] v = new float[numPoints]; - for (int i=0; i<numPoints; i++) { - - switch (i%3) { - case 0: - // One of the fixed points. - h[i] = (float)h0[i/3]; - v[i] = (float)v0[i/3]; - break; - case 1: - // First control point. - h[i] = (float)(2./3. * h0[i/3] + 1./3. * h0[i/3+1]); - v[i] = (float)(2./3. * v0[i/3] + 1./3. * v0[i/3+1]); - break; - case 2: - // Second control point. - h[i] = (float)(1./3. * h0[i/3] + 2./3. * h0[i/3+1]); - v[i] = (float)(1./3. * v0[i/3] + 2./3. * v0[i/3+1]); - break; - } - } - - // Now we have a normal polyline (straight line segments between fixed points), - // but as a cubic Bezier curve. All we need to do to make it smooth is to move - // the control points away from the curve, in such a way that [control point 2] - - // [fixed point] - [control point 1] is a straight line for every fixed point. - // We do this by averaging the angles of the line segments on either side of a - // fixed point. - for (int i=3; i<numPoints-2; i+=3) { - double lenLeft = Math.sqrt(Math.pow(h[i]-h[i-1], 2) + Math.pow(v[i]-v[i-1], 2)); - double lenRight = Math.sqrt(Math.pow(h[i+1]-h[i], 2) + Math.pow(v[i+1]-v[i], 2)); - - // Without length we cannot define an angle, so skip the point. - if (lenLeft < 1e-6 || lenRight < 1e-6) continue; - - double phiLeft = Math.atan2(v[i]-v[i-1], h[i]-h[i-1]); - double phiRight = Math.atan2(v[i+1]-v[i], h[i+1]-h[i]); - - if (phiLeft-phiRight > Math.PI) { - phiRight += 2.*Math.PI; - } else if (phiRight-phiLeft > Math.PI) { - phiLeft += 2.*Math.PI; - } - - if (Math.abs(phiLeft-phiRight) > Math.PI/2.) { - // The line turns more than 90 degrees, this is wrong. Move the control points - // back in so they are the same as the point on the line. This disables the smooth - // curve locally, reverting to a normal connect-the-dots polyline. - h[i-1] = h[i+1] = h[i]; - v[i-1] = v[i+1] = v[i]; - } else { - // Calculate the desired angle for the tangent by weighting the angle on each side, - // the weight is inverse proportional to the distance to the next point. - double phi = (lenRight*phiLeft + lenLeft*phiRight) / (lenLeft+lenRight); - - h[i-1] = h[i] - (float)(lenLeft*Math.cos(phi)); - v[i-1] = v[i] - (float)(lenLeft*Math.sin(phi)); - h[i+1] = h[i] + (float)(lenRight*Math.cos(phi)); - v[i+1] = v[i] + (float)(lenRight*Math.sin(phi)); - } - } - - curve.moveTo(h[0], v[0]); - for (int i=3; i<numPoints; i+=3) { - curve.curveTo(h[i-2], v[i-2], h[i-1], v[i-1], h[i], v[i]); - } - - updateColor(); - g.draw(curve); - } - } - - public void fillPolygon(double[] h, double[] v, int numPoints) { - int type=getContainmentType(h, v, numPoints, POLYGON); - if(type==FULLY_INSIDE||type==INTERSECTS) { - if(type==INTERSECTS) { - ACoord clipped=clipper.clipPolygon(h, v, numPoints); - h=clipped.hv[0][0]; - v=clipped.hv[1][0]; - numPoints=h.length; - } - path.reset(); - - for(int i=0; i<numPoints; ++i) - if(i==0) - path.moveTo((float)h[i], (float)v[i]); - else - path.lineTo((float)h[i], (float)v[i]); - if(numPoints>0) { - path.closePath(); - updateColor(); - g.fill(path); - g.draw(path); - } - } else if(type==CONTAINS) { - Rectangle bounds=g.getClipBounds(); - updateColor(); - g.fillRect((int)Math.rint(bounds.getX()), (int)Math.rint(bounds.getY()), - (int)Math.rint(bounds.getWidth()), (int)Math.rint(bounds.getHeight())); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/colormap/AColorMap.java b/graphics/AtlantisJava/src/atlantis/graphics/colormap/AColorMap.java deleted file mode 100755 index 423a613163a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/colormap/AColorMap.java +++ /dev/null @@ -1,365 +0,0 @@ -package atlantis.graphics.colormap; - -import java.io.File; -import java.io.InputStream; -import java.awt.Color; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.NamedNodeMap; - -import atlantis.globals.AGlobals; -import atlantis.output.AExceptionHandler; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.utils.AUtilities; -import atlantis.utils.ALogger; -import atlantis.utils.xml.AXMLErrorHandler; - - -public final class AColorMap -{ - private static ALogger logger = ALogger.getLogger(AColorMap.class); - - private static final boolean VALIDATION = true; - final public static int NO_COLOR = -1; - final public static int INVISIBLE = -2; - static final public int BG = 8; //background - static final public int WH = 0; //white - static final public int GY = 14; //grey - static final public int RD = 20; //red - static final public int GN = 21; //green - static final public int BL = 22; //blue - static final public int YE = 23; //yellow - static final public int MA = 24; //magenta - static final public int CY = 25; //cyan - static final public int BK = 26; //black - static final public int OR = 27; //orange - static final public int CB = 28; //cornflower blue - private static final String[] mapNames = {"Default(1)", "Default(2)", "M4+M5", "GrayDet", - "Original", "Gray", "B/W", "HitCol", "GrayHitCol"}; - private static final String[] mapNamesPS = {"default1","default2","m4m5", "graydet", - "original", "gray", "bw", "hitcol", "grayhitcol"}; - private static MappedColor[][] maps; - private static int numColors; - private static int numMaps; - - // Color map indices. - public static final int COLOR_MAP_DEFAULT1 = 0; - public static final int COLOR_MAP_DEFAULT2 = 1; - public static final int COLOR_MAP_M4M5 = 2; - public static final int COLOR_MAP_GRAYDET = 3; - public static final int COLOR_MAP_ORIGINAL = 4; - public static final int COLOR_MAP_GRAY = 5; - public static final int COLOR_MAP_BW = 6; - public static final int COLOR_MAP_HITCOL = 7; - public static final int COLOR_MAP_GRAY_HITCOL = 8; - - //color map used if wrong value in config file - static int currentMap = COLOR_MAP_DEFAULT1; - - - public static void readColorMap(String name) - { - String fileName = null; - String FILE_SEPAR = System.getProperty("file.separator"); - - if(name != null && new File(name).canRead()) - { - // color map file specified as command line argument - fileName = name; - } - else - { - if(name != null) - { - logger.warn("Can't read color map file: " + name); - } - // color map file wasn't specified as command line argument - fileName = ".Atlantis-colormap.xml"; // default name - String fileNameFull = System.getProperty("user.home") + FILE_SEPAR + fileName; - if(new File(fileNameFull).canRead()) - { - // use existing user's color map file - fileName = fileNameFull; - } - else - { - // use default color map file from Atlantis distribution - fileName = AGlobals.instance().getHomeDirectory() + "configuration" + - FILE_SEPAR + "colormap.xml"; - } - } - - logger.info("Using color map file: " + fileName); - try - { - InputStream isColorMap = AUtilities.getFileAsStream(fileName); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(VALIDATION); - DocumentBuilder parser = factory.newDocumentBuilder(); - parser.setErrorHandler(new AXMLErrorHandler()); - Node colormap = parser.parse(isColorMap).getDocumentElement(); - NamedNodeMap cm = colormap.getAttributes(); - numMaps = Integer.parseInt(cm.getNamedItem("numMaps").getNodeValue(). - trim()); - numColors = Integer.parseInt(cm.getNamedItem("numColors"). - getNodeValue().trim()); - maps = new MappedColor[numMaps][numColors]; - NodeList list = colormap.getChildNodes(); - int count = list.getLength(); - for(int i = 0; i < count; i++) - { - Node mapping = list.item(i); - if(mapping.getNodeType() == Node.ELEMENT_NODE) - { - NamedNodeMap atts = mapping.getAttributes(); - try - { - int map = Integer.parseInt(atts.getNamedItem("map"). - getNodeValue().trim()); - int index = Integer.parseInt(atts.getNamedItem("index"). - getNodeValue().trim()); - int r = Integer.parseInt(atts.getNamedItem("r"). - getNodeValue().trim()); - int g = Integer.parseInt(atts.getNamedItem("g"). - getNodeValue().trim()); - int b = Integer.parseInt(atts.getNamedItem("b"). - getNodeValue().trim()); - if(map < maps.length) - { - if(index < maps[map].length) - { - maps[map][index] = new MappedColor(r, g, b, - index); - } - } - } - catch(NumberFormatException e) - { - AExceptionHandler.processException("Colour map error:\n" + - mapping, e); - } - } // if - } // for - } - catch(Exception e) - { - AExceptionHandler.processException("Error while reading colour map:\n" + - fileName, e); - } - for(int i = 0; i < maps.length; i++) - { - for(int j = 0; j < maps[i].length; j++) - { - if(maps[i][j] == null) - { - AOutput.append("\nColorMap (" + i + "," + j + - ") is not present", - ALogInterface.BAD_COMMAND); - } - } - } - - } // readColorMap() ----------------------------------------------------- - - - - public static int getNumMaps() - { - return numMaps; - } - - - public static int getNumColors() - { - return numColors; - } - - - /** - * Returns color map in the XML format. - * [Former method writeColorMap() was writing the XML data directly into - * the file.] - * @return String - */ - public static String getColorMapXML() - { - StringBuffer buffer = new StringBuffer(); - // color map DTD - buffer.append( - "<?xml version=\"1.0\"?>\n" + - "<!DOCTYPE colormap [\n" + - " <!ELEMENT colormap (Mapping*)>" + - " <!ATTLIST colormap\n" + - " numMaps CDATA #REQUIRED\n" + - " numColors CDATA #REQUIRED>\n" + - " <!ELEMENT Mapping EMPTY>\n" + - " <!ATTLIST Mapping\n" + - " map CDATA #REQUIRED\n" + - " index CDATA #REQUIRED\n" + - " r CDATA #REQUIRED\n" + - " g CDATA #REQUIRED\n" + - " b CDATA #REQUIRED>\n" + - "]>\n\n\n"); - buffer.append("<colormap numMaps=\"" + maps.length + - "\" numColors=\"" + maps[0].length + "\" >\n"); - for(int i = 0; i < maps.length; i++) - { - for(int j = 0; j < maps[i].length; j++) - { - int r = maps[i][j].getRed(); - int g = maps[i][j].getGreen(); - int b = maps[i][j].getBlue(); - buffer.append(" <Mapping map=\"" + i + "\" index=\"" + j + - "\" r=\"" + r + "\" g=\"" + g + "\" b=\"" + - b + "\"/>\n"); - } - } - buffer.append("</colormap>\n"); - return buffer.toString(); - - } // getColorMapXML() --------------------------------------------------- - - - - public static String getPSPrologColorMap() - { - StringBuffer s = new StringBuffer(); - String newLine = System.getProperty("line.separator"); - s.append(newLine); - for(int i = 0; i < maps.length; ++i) - { - s.append("/" + mapNamesPS[i] + "ColorMap" + newLine); - s.append("<<" + newLine); - for(int j = 0; j < maps[i].length; ++j) - s.append(" /C" + j + " [" + - String.format("%.3f",maps[i][j].getRed() / 255.) + " " - + String.format("%.3f",maps[i][j].getGreen() / 255.) + " " + - String.format("%.3f",maps[i][j].getBlue() / 255.) - + "]" + newLine); - s.append(">> def" + newLine); - s.append(newLine); - } - return s.toString(); - - } // getPSPrologColorMap() ---------------------------------------------- - - - - public static Color[] getColors(int map) - { - Color[] col = new Color[maps[map].length]; - for(int i = 0; i < col.length; ++i) - col[i] = (Color) maps[map][i]; - return col; - } - - //From hot (red), index 255, to cold (blue), index 0 - public static Color[] getShades(int num) - { - assert (num>=2); - Color[] col = new Color[num]; - col[0]=new Color(170,170,170);//grey for "other" - for(int i = 1; i < num-1; ++i) - col[i] = new Color(((255*i)/num),80,255-((255*i)/num)); - return col; - } - - public static Color[] getColors() - { - return getColors(currentMap); - } - - - public static void setColorMap(int map) - { - if(map >= 0 && map < maps.length) - { - currentMap = map; - APar parameterStore = APar.instance(); - parameterStore.get("Prefs","ColorMap").setI(map); - } - } - - - public static void setColorMap(String mapName) - { - for(int i = 0; i < mapNames.length; i++) - if(mapNames[i].equals(mapName)) - setColorMap(i); - } - - - public static int getColorMap() - { - return currentMap; - } - - public static boolean drawFrames() - { - if(currentMap==COLOR_MAP_GRAY || currentMap==COLOR_MAP_BW) - return true; - else - return false; - } - - public static String getPSColorMapName() - { - return mapNamesPS[getColorMap()]; - - } // getPSColorMapName() ------------------------------------------------ - - - public MappedColor getMappedColor(int colorIndex) - { - if(colorIndex < 0 && colorIndex >= maps[currentMap].length) - { - return null; - } - else - { - return maps[currentMap][colorIndex]; - } - } - - - public Color getColor(int colorIndex) - { - if(colorIndex < 0 && colorIndex >= maps[currentMap].length) - { - return null; - } - else - { - return(Color) maps[currentMap][colorIndex]; - } - } - - - public static String getTag(int colorIndex) - { - if(colorIndex < 0 && colorIndex >= maps[0].length) - { - return null; - } - else - { - return "C" + colorIndex; - } - } - - - public static String[] getMapNames() - { - return(String[]) mapNames.clone(); - } - - public static MappedColor[][] getMaps() { - return maps; - } - -} // class AColorMap ======================================================== diff --git a/graphics/AtlantisJava/src/atlantis/graphics/colormap/MappedColor.java b/graphics/AtlantisJava/src/atlantis/graphics/colormap/MappedColor.java deleted file mode 100755 index 53ace099fe8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/colormap/MappedColor.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2000, CERN, Geneva, Switzerland and University of Santa Cruz, California, U.S.A. -package atlantis.graphics.colormap; - - -import java.awt.Color; - - -/** - * - * @author Charles Loomis - **/ -public class MappedColor extends java.awt.Color { - - /** - * Index of the color in the color map. */ - protected int colorIndex; - - /** - * Value of the brightness/darkness of this color. Larger values - * indicate darker colors and vice versa. */ - protected int brightness; - - /** - * Constructor takes the RGB color components and the color index. */ - public MappedColor(int r, int g, int b, - int colorIndex) { - - // Call the Color constructor. - super(r, g, b); - - // Set the color index and brightness. - this.colorIndex=colorIndex; - brightness=0; - } - - /** - * Constructor takes the RGB color components, the color index, - * and the brightness. */ - public MappedColor(int r, int g, int b, - int colorIndex, - int brightness) { - - // Call the Color constructor. - super(r, g, b); - - // Set the color index and brightness. - this.colorIndex=colorIndex; - this.brightness=brightness; - } - - /** - * Make a brightened color based on this color. */ - public Color brighter() { - - int r=getRed()*10/7; - int g=getGreen()*10/7; - int b=getBlue()*10/7; - - r=Math.max(0, Math.min(255, r)); - g=Math.max(0, Math.min(255, g)); - b=Math.max(0, Math.min(255, b)); - - return (Color)new MappedColor(r, g, b, colorIndex, brightness-1); - } - - /** - * Make a darkened color based on this color. */ - public Color darker() { - - int r=getRed()*7/10; - int g=getGreen()*7/10; - int b=getBlue()*7/10; - - r=Math.max(0, Math.min(255, r)); - g=Math.max(0, Math.min(255, g)); - b=Math.max(0, Math.min(255, b)); - - return (Color)new MappedColor(r, g, b, colorIndex, brightness-1); - } - - /** - * Get the brightness of this color. */ - public int getBrightness() { - return brightness; - } - - /** - * Get the tag associated with this color. */ - public String getColorTag() { - return AColorMap.getTag(colorIndex); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ACallBack.java b/graphics/AtlantisJava/src/atlantis/graphics/dnd/ACallBack.java deleted file mode 100755 index 5cc4ec0a64c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ACallBack.java +++ /dev/null @@ -1,9 +0,0 @@ -package atlantis.graphics.dnd; - - -/** - * Used in the Drag and Drop operations. - */ -public interface ACallBack { - void callBack(Object from); -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDButton.java b/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDButton.java deleted file mode 100755 index f637b28172b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDButton.java +++ /dev/null @@ -1,88 +0,0 @@ -package atlantis.graphics.dnd; - -import java.awt.Point; -import java.awt.Graphics; -import javax.swing.JButton; -import java.awt.image.BufferedImage; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceListener; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceEvent; -import java.util.Vector; - -/** - * A button wich has Drag and Drop support ( see java.awt.dnd.*) - * Used by the rubberbands. - */ - -public class ADnDButton extends JButton - implements DragSourceListener, DragGestureListener, ACallBack { - - private DragSource dragSource; - private Vector dragListeners; - - public ADnDButton(String name) { - super(name); - setName(name); - - dragSource=DragSource.getDefaultDragSource(); - dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); - - dragListeners=new Vector(); - } - - // implementation of DragSourceListener - - // This method is invoked to signify that the Drag and Drop operation is complete. - public void dragDropEnd(DragSourceDropEvent dsde) {} - - // Called as the hotspot enters a platform dependent drop site. - public void dragEnter(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_VALID); - } - - // Called as the hotspot exits a platform dependent drop site. - public void dragExit(DragSourceEvent dse) { - dse.getDragSourceContext().setCursor(ADnDLabel.DROP_INVALID); - } - - // Called as the hotspot moves over a platform dependent drop site. - public void dragOver(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_VALID); - } - - // Called when the user has modified the drop gesture. - public void dropActionChanged(DragSourceDragEvent dsde) {} - - // implementation of DragGestureListener - - public void dragGestureRecognized(DragGestureEvent dge) { - BufferedImage resizeCursorImage=new BufferedImage(64, 64, BufferedImage.TYPE_4BYTE_ABGR); - - Graphics g=resizeCursorImage.getGraphics(); - - g.drawLine(0, 0, 64, 64); - g.dispose(); - - // return Toolkit.getDefaultToolkit().createCustomCursor(resizeCursorImage, center, "resize") - - - AObjectTransferable cbt=new AObjectTransferable(this); - - dragSource.startDrag(dge, ADnDLabel.DROP_INVALID, resizeCursorImage, new Point(0, 0), cbt, this); - } - - public void callBack(Object to) { - for(int i=0; i<dragListeners.size(); i++) - ((ADragListener)dragListeners.get(i)).dragPerformed(this, to, -1); - } - - public void addDragListener(ADragListener l) { - dragListeners.addElement(l); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDLabel.java b/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDLabel.java deleted file mode 100755 index 2b1873f5563..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADnDLabel.java +++ /dev/null @@ -1,184 +0,0 @@ -package atlantis.graphics.dnd; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceEvent; -import java.awt.dnd.DragSourceListener; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetEvent; -import java.awt.dnd.DropTargetListener; -import java.util.Vector; - -import javax.swing.JLabel; - -import atlantis.graphics.ACursorFactory; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; - -/** - * A label which has Drag and Drop support. - * Used in the Window Control. - */ -public class ADnDLabel extends JLabel -implements DropTargetListener, DragSourceListener, DragGestureListener { - - private DragSource dragSource=null; - private Vector dragListeners; - private boolean dragHighlight; - private String[] page; - - public JLabel getLabel() { - return this; - } - - public static final Cursor DROP_VALID; - public static final Cursor DROP_INVALID; - - static { - /* if(Toolkit.getDefaultToolkit().getBestCursorSize(64, 64).equals(new Dimension(64, 64))) { - DROP_VALID=Toolkit.getDefaultToolkit().createCustomCursor(Toolkit.getDefaultToolkit().getImage(Atlantis.getHomeDirectory() - +"img"+Atlantis.fileSep+"cursor_DnD_valid_64x64.gif"), - new Point(1, 1), "ValidDnD"); - DROP_INVALID=Toolkit.getDefaultToolkit().createCustomCursor(Toolkit.getDefaultToolkit().getImage(Atlantis.getHomeDirectory() - +"img"+Atlantis.fileSep+"cursor_DnD_invalid_64x64.gif"), - new Point(9, 9), "InvalidDnD"); - } else { - DROP_VALID=DragSource.DefaultMoveDrop; - DROP_INVALID=DragSource.DefaultMoveNoDrop; - } */ - DROP_VALID = ACursorFactory.getInstance().getDragValidCursor(); - DROP_INVALID = ACursorFactory.getInstance().getDragInvalidCursor(); - } - - public ADnDLabel(String name, boolean dragHighlight) { - super(name, JLabel.CENTER); - setName(name); - setOpaque(true); - page=null; - this.dragHighlight=dragHighlight; - - dragSource=new DragSource(); - dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); - this.setDropTarget(new DropTarget(this, this)); - dragListeners=new Vector(); - } - - public ADnDLabel(String name, String[] wnames, boolean dragHighlight) { - super(name, JLabel.CENTER); - setName(name); - setOpaque(true); - page=wnames; - this.dragHighlight=dragHighlight; - - dragSource=new DragSource(); - dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); - this.setDropTarget(new DropTarget(this, this)); - dragListeners=new Vector(); - } - - public Dimension getPreferredSize() { - return new Dimension(15, 15); - } - - // implementation of DropTargetListener - - private Color old; - - // Called when a drag operation has encountered the DropTarget. - public void dragEnter(DropTargetDragEvent dtde) { - dtde.acceptDrag(DnDConstants.ACTION_MOVE); - if(dragHighlight) { - old=getBackground(); - setBackground(new Color(150, 150, 150)); - } - } - - // The drag operation has departed the DropTarget without dropping. - public void dragExit(DropTargetEvent dte) { - if(dragHighlight) - setBackground(old); - } - - // Called when a drag operation is ongoing on the DropTarget. - public void dragOver(DropTargetDragEvent dtde) { - } - - // The drag operation has terminated with a drop on this DropTarget. - public void drop(DropTargetDropEvent dtde) { - try { - Transferable transferable=dtde.getTransferable(); - DataFlavor javaObjectDataFlavor=new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); - - if(transferable.isDataFlavorSupported(javaObjectDataFlavor)) { - dtde.acceptDrop(DnDConstants.ACTION_MOVE); - Object object=transferable.getTransferData(javaObjectDataFlavor); - - if(object instanceof ACallBack) - ((ACallBack)object).callBack(this); - else - fireDragEvent(object); - dtde.getDropTargetContext().dropComplete(true); - } else - AOutput.append("Cannot accept drop\n", ALogInterface.BAD_COMMAND); - } catch(Exception e) { - e.printStackTrace(); - dtde.rejectDrop(); - } - } - - private void fireDragEvent(Object from) { - for(int i=0; i<dragListeners.size(); i++) - ((ADragListener)dragListeners.get(i)).dragPerformed(from, this, -1); - } - - // Called if the user has modified the current drop gesture. - public void dropActionChanged(DropTargetDragEvent dtde) {} - - // implementation of DragSourceListener - - // This method is invoked to signify that the Drag and Drop operation is complete. - public void dragDropEnd(DragSourceDropEvent dsde) {} - - // Called as the hotspot enters a platform dependent drop site. - public void dragEnter(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(DROP_VALID); - } - - // Called as the hotspot exits a platform dependent drop site. - public void dragExit(DragSourceEvent dse) { - dse.getDragSourceContext().setCursor(DROP_INVALID); - } - - // Called as the hotspot moves over a platform dependent drop site. - public void dragOver(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(DROP_VALID); - } - - // Called when the user has modified the drop gesture. - public void dropActionChanged(DragSourceDragEvent dsde) {} - - // implementation of DragGestureListener - public void dragGestureRecognized(DragGestureEvent dge) { - dragSource.startDrag(dge, DROP_VALID, new AObjectTransferable(this), this); - } - - public void addDragListener(ADragListener l) { - dragListeners.addElement(l); - } - - public String[] returnPageName() - { - return page; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADragListener.java b/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADragListener.java deleted file mode 100755 index 429b9a0af14..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/dnd/ADragListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package atlantis.graphics.dnd; - - -/** - * The listener to drag operations. It is suported by ADnDLabel and ADnDButton. - */ -public interface ADragListener { - void dragPerformed(Object from, Object to, int action); -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/dnd/AObjectTransferable.java b/graphics/AtlantisJava/src/atlantis/graphics/dnd/AObjectTransferable.java deleted file mode 100755 index d823077f674..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/dnd/AObjectTransferable.java +++ /dev/null @@ -1,62 +0,0 @@ -package atlantis.graphics.dnd; - - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; - - -/** - * Used by Drag and Drop - * A implementation of a transferable which - * transfers an Java object (really an pointer to it). - */ -public class AObjectTransferable implements Transferable { - private Object object; - - /** - * Creates the Transferable which will transfer the specified object. - * @param object The object to be transferred - */ - public AObjectTransferable(Object object) { - this.object=object; - } - - /** - * Returns the transferred for a specific DataFlavor. - * @param flavor The DataFlavor for which to get the transferred object. - * @return The transferred object. - */ - public Object getTransferData(DataFlavor flavor) { - return object; - } - - /** - * Returns an array of DataFlavor objects indicating the flavors the - * data can be provided in. - * @return The set of available flavors. - */ - public DataFlavor[] getTransferDataFlavors() { - DataFlavor df=null; - - try { - df=new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); - } catch(ClassNotFoundException e) { - throw new Error("Cannot create DataFlavor.javaJVMLocalObjectMimeType "+e.getMessage()); - } - return new DataFlavor[] {df}; - } - - /** - * Returns whether or not the specified data flavor is - * supported by this transferable. - * @param flavor The data flavor that needs to be checked - * @return True if the flavor is supported. False Otherwise. - */ - public boolean isDataFlavorSupported(DataFlavor flavor) { - if(flavor.getHumanPresentableName().equals(DataFlavor.javaJVMLocalObjectMimeType)) - return true; - else - return false; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/encoders/AImageEncoder.java b/graphics/AtlantisJava/src/atlantis/graphics/encoders/AImageEncoder.java deleted file mode 100644 index a27b4f07d8b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/encoders/AImageEncoder.java +++ /dev/null @@ -1,167 +0,0 @@ -package atlantis.graphics.encoders; - -import atlantis.canvas.ACanvas; -import atlantis.utils.ALogger; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.File; -import java.io.FileOutputStream; -import java.io.BufferedOutputStream; - -import org.apache.batik.dom.svg.SVGDOMImplementation; -import org.apache.batik.svggen.SVGGraphics2D; - -import org.sourceforge.jlibeps.epsgraphics.*; -import org.w3c.dom.*; -import org.w3c.dom.svg.SVGDocument; - -/** - * Takes the image drawn on the canvas and encodes it in the given format - * @author sboeser - */ -public class AImageEncoder { - - //The logger - private final static ALogger logger = ALogger.getLogger(AImageEncoder.class); - - /** - * Grabs canvas and encodes the data in PNG format. - * @param imageWidth resulting image width - * @param imageHeight resulting image height - * @return byte[] - */ - public byte[] getPNGData(int imageWidth, int imageHeight){ - - // Draw image - Image image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB); - ACanvas.getCanvas().drawScaledCanvas(image.getGraphics(), imageWidth, imageHeight, "png"); - - // Encode as PNG. - PngEncoder encoder = new PngEncoder(image, true, PngEncoder.FILTER_NONE, 9); - byte[] data = encoder.pngEncode(); - return data; - - } - - /** - * Get a scaled version of the PNG image - mostly used to create thumbnails - * NOTE: in contrast to getPNGData, this will first create the image with given - * width and height and then scale everything (including window - * borders, title bar, etc...) - * @param width image width before scaling - * @param height image height before scaling - * @param scale the scale factor - * @return the PNG data - */ - public byte[] getScaledPNGData(int width, int height, double scale){ - - // Draw a temporary full-size image - Image inputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - ACanvas.getCanvas().drawScaledCanvas(inputImage.getGraphics(), width, height, "png"); - - //Calculate target height keeping aspect ratio - int targetHeight = (int)(scale*height); - int targetWidth = (int)(scale*width); - - - /** - * Now rescale the image in steps - do not use Image.getScaledInstance, - * which is outdated and way to slow! - */ - - while (inputImage.getWidth(null) != targetWidth){ - - //Resize by no more than a factor of two in one step - if (inputImage.getWidth(null)/targetWidth > 2. ){ - width = (int)(inputImage.getWidth(null)/2.); - height = (int)(inputImage.getHeight(null)/2.); - } else { - width = targetWidth; - height = targetHeight; - } - - //log for debugging - logger.debug("Rescaling image from "+inputImage.getWidth(null)+"x"+inputImage.getHeight(null)+ - " to "+width+"x"+height); - - //Now redraw that to the scaled image - BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - Graphics2D scaledGraphics = scaledImage.createGraphics(); - scaledGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC); - scaledGraphics.drawImage(inputImage, 0, 0, width, height, null); - scaledGraphics.dispose(); - - //Provide the scaled image as new input in case we need to rescale once more - inputImage = scaledImage; - } - - // Encode as PNG. - PngEncoder encoder = new PngEncoder(inputImage, true, PngEncoder.FILTER_NONE, 9); - byte[] data = encoder.pngEncode(); - return data; - - } - - - /** - * Grab canvas, encode the information as EPS and save to a file - * @param imageWidth image width - * @param imageHeight image height - * @param saveFile save file - */ - - public void saveEPS(int imageWidth, int imageHeight, File saveFile) throws IOException{ - - //Create the output stream - FileOutputStream fos = new FileOutputStream(saveFile); - BufferedOutputStream bos = new BufferedOutputStream(fos); - - // Create a new postscript graphics object - EpsGraphics2D g = new EpsGraphics2D("Atlantis",bos,0,0,imageWidth,imageHeight); - // Draw text as shapes - g.setAccurateTextMode(true); - // Draw into the postscript graphics - ACanvas.getCanvas().drawScaledCanvas(g, imageWidth, imageHeight, "eps"); - g.flush(); - g.close(); - fos.close(); - bos.close(); - - } - - /** - * Grab canvas, encode the information as SVG and save to a file - * @param imageWidth image width - * @param imageHeight image height - * @param saveFile save file - */ - - public void saveSVG(int imageWidth, int imageHeight, File saveFile) throws IOException{ - - // Document Object Model to define our SVG Document - DOMImplementation domImpl = - SVGDOMImplementation.getDOMImplementation(); - - // We need to write the SVG into a Document - String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; - SVGDocument doc = (SVGDocument) domImpl.createDocument(svgNS, "svg", null); - - // Construct an SVGGraphics2D from our Document - SVGGraphics2D g = new SVGGraphics2D(doc); - - g.setSVGCanvasSize(new Dimension(imageWidth, imageHeight)); - - // Paint the scaled Canvas onto our SVG Graphics2D - ACanvas.getCanvas().drawScaledCanvas(g, imageWidth, imageHeight, "svg"); - - // Stream the output into our chosen file - g.stream(saveFile.getAbsolutePath()); - - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/encoders/PngEncoder.java b/graphics/AtlantisJava/src/atlantis/graphics/encoders/PngEncoder.java deleted file mode 100755 index a9c7b5aa61b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/encoders/PngEncoder.java +++ /dev/null @@ -1,582 +0,0 @@ -package atlantis.graphics.encoders; - -// package com.keypoint; - - -import java.awt.*; -import java.awt.image.*; -import java.util.zip.*; -import java.io.*; - -/** - * PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file. - * The Image is presumed to use the DirectColorModel. - * - * Thanks to Jay Denny at KeyPoint Software - * http://www.keypoint.com/ - * who let me develop this code on company time. - * - * You may contact me with (probably very-much-needed) improvements, - * comments, and bug fixes at: - * - * david@catcode.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * A copy of the GNU LGPL may be found at - * http://www.gnu.org/copyleft/lesser.html, - * - * @author J. David Eisenberg - * @version 1.4, 31 March 2000 - * - * Added ImageObserver so that getHeight, getWidth calls work properly. - * - * @author M.Donszelmann - */ -public class PngEncoder extends Object implements ImageObserver { - - /** Constant specifying that alpha channel should be encoded. */ - public static final boolean ENCODE_ALPHA=true; - - /** Constant specifying that alpha channel should not be encoded. */ - public static final boolean NO_ALPHA=false; - - /** Constants for filters */ - public static final int FILTER_NONE=0; - public static final int FILTER_SUB=1; - public static final int FILTER_UP=2; - public static final int FILTER_LAST=2; - - protected byte[] pngBytes; - protected byte[] priorRow; - protected byte[] leftBytes; - protected Image image; - protected int width, height; - protected int bytePos, maxPos; - protected int hdrPos, dataPos, endPos; - protected CRC32 crc=new CRC32(); - protected long crcValue; - protected boolean encodeAlpha; - protected int filter; - protected int bytesPerPixel; - protected int compressionLevel; - - public PngEncoder() { - this(null, false, FILTER_NONE, 0); - } - - /** - * Class constructor specifying Image to encode, with no alpha channel encoding. - * - * @param image A Java Image object which uses the DirectColorModel - * @see java.awt.Image - */ - public PngEncoder(Image image) { - this(image, false, FILTER_NONE, 0); - } - - /** - * Class constructor specifying Image to encode, and whether to encode alpha. - * - * @param image A Java Image object which uses the DirectColorModel - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @see java.awt.Image - */ - public PngEncoder(Image image, boolean encodeAlpha) { - this(image, encodeAlpha, FILTER_NONE, 0); - } - - /** - * Class constructor specifying Image to encode, whether to encode alpha, and filter to use. - * - * @param image A Java Image object which uses the DirectColorModel - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @param whichFilter 0=none, 1=sub, 2=up - * @see java.awt.Image - */ - public PngEncoder(Image image, boolean encodeAlpha, int whichFilter) { - this(image, encodeAlpha, whichFilter, 0); - } - - /** - * Class constructor specifying Image source to encode, whether to encode alpha, filter to use, and compression level. - * - * @param image A Java Image object - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @param whichFilter 0=none, 1=sub, 2=up - * @param compLevel 0..9 - * @see java.awt.Image - */ - public PngEncoder(Image image, boolean encodeAlpha, int whichFilter, - int compLevel) { - this.image=image; - this.encodeAlpha=encodeAlpha; - setFilter(whichFilter); - if(compLevel>=0&&compLevel<=9) { - this.compressionLevel=compLevel; - } - } - - /** - * Set the image to be encoded - * - * @param image A Java Image object which uses the DirectColorModel - * @see java.awt.Image - */ - public void setImage(Image image) { - this.image=image; - pngBytes=null; - } - - /** method to wait for image */ - private int imageStatus; - - public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { - imageStatus=flags; - if(((flags&ALLBITS)==ALLBITS)||((flags&(ABORT|ERROR))!=0)) { - return false; - } - return true; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current image, specifying whether to encode alpha or not. - * - * @param encodeAlpha boolean false=no alpha, true=encode alpha - * @return an array of bytes, or null if there was a problem - */ - public byte[] pngEncode(boolean encodeAlpha) { - byte[] pngIdBytes= { -119, 80, 78, 71, 13, 10, 26, 10 }; - - if(image==null) { - return null; - } - - imageStatus=0; - boolean status=Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, this); - - if(!status) { - while(((imageStatus&(ALLBITS))==0)&&((imageStatus&(ABORT|ERROR))==0)) { - try { - Thread.sleep(100); - } catch(Exception e) {} - } - // FIXED: moved this inside the "if (!status)" area - if((imageStatus&(ALLBITS))==0) { - return null; - } - } - - width=image.getWidth(null); - height=image.getHeight(null); - - /* - * start with an array that is big enough to hold all the pixels - * (plus filter bytes), and an extra 200 bytes for header info - */ - pngBytes=new byte[((width+1)*height*3)+200]; - - /* - * keep track of largest byte written to the array - */ - maxPos=0; - - bytePos=writeBytes(pngIdBytes, 0); - hdrPos=bytePos; - writeHeader(); - dataPos=bytePos; - if(writeImageData()) { - writeEnd(); - pngBytes=resizeByteArray(pngBytes, maxPos); - } else { - pngBytes=null; - } - return pngBytes; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current image. - * Alpha encoding is determined by its setting in the constructor. - * - * @return an array of bytes, or null if there was a problem - */ - public byte[] pngEncode() { - return pngEncode(encodeAlpha); - } - - /** - * Set the alpha encoding on or off. - * - * @param encodeAlpha false=no, true=yes - */ - public void setEncodeAlpha(boolean encodeAlpha) { - this.encodeAlpha=encodeAlpha; - } - - /** - * Retrieve alpha encoding status. - * - * @return boolean false=no, true=yes - */ - public boolean getEncodeAlpha() { - return encodeAlpha; - } - - /** - * Set the filter to use - * - * @param whichFilter from constant list - */ - public void setFilter(int whichFilter) { - this.filter=FILTER_NONE; - if(whichFilter<=FILTER_LAST) { - this.filter=whichFilter; - } - } - - /** - * Retrieve filtering scheme - * - * @return int (see constant list) - */ - public int getFilter() { - return filter; - } - - /** - * Set the compression level to use - * - * @param level 0 through 9 - */ - public void setCompressionLevel(int level) { - if(level>=0&&level<=9) { - this.compressionLevel=level; - } - } - - /** - * Retrieve compression level - * - * @return int in range 0-9 - */ - public int getCompressionLevel() { - return compressionLevel; - } - - /** - * Increase or decrease the length of a byte array. - * - * @param array The original array. - * @param newLength The length you wish the new array to have. - * @return Array of newly desired length. If shorter than the - * original, the trailing elements are truncated. - */ - protected byte[] resizeByteArray(byte[] array, int newLength) { - byte[] newArray=new byte[newLength]; - int oldLength=array.length; - - System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength)); - return newArray; - } - - /** - * Write an array of bytes into the pngBytes array. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes(byte[] data, int offset) { - maxPos=Math.max(maxPos, offset+data.length); - if(data.length+offset>pngBytes.length) { - pngBytes=resizeByteArray(pngBytes, pngBytes.length+Math.max(1000, data.length)); - } - System.arraycopy(data, 0, pngBytes, offset, data.length); - return offset+data.length; - } - - /** - * Write an array of bytes into the pngBytes array, specifying number of bytes to write. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param nBytes The number of bytes to be written. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes(byte[] data, int nBytes, int offset) { - maxPos=Math.max(maxPos, offset+nBytes); - if(nBytes+offset>pngBytes.length) { - pngBytes=resizeByteArray(pngBytes, pngBytes.length+Math.max(1000, nBytes)); - } - System.arraycopy(data, 0, pngBytes, offset, nBytes); - return offset+nBytes; - } - - /** - * Write a two-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt2(int n, int offset) { - byte[] temp= { (byte)((n>>8)&0xff), (byte)(n&0xff) }; - return writeBytes(temp, offset); - } - - /** - * Write a four-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt4(int n, int offset) { - byte[] temp= { (byte)((n>>24)&0xff), (byte)((n>>16)&0xff), (byte)((n>>8)&0xff), (byte)(n&0xff) }; - return writeBytes(temp, offset); - } - - /** - * Write a single byte into the pngBytes array at a given position. - * - * @param b The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeByte(int b, int offset) { - byte[] temp= { (byte)b }; - return writeBytes(temp, offset); - } - - /** - * Write a string into the pngBytes array at a given position. - * This uses the getBytes method, so the encoding used will - * be its default. - * - * @param s The string to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - * @see java.lang.String#getBytes() - */ - protected int writeString(String s, int offset) { - return writeBytes(s.getBytes(), offset); - } - - /** - * Write a PNG "IHDR" chunk into the pngBytes array. - */ - protected void writeHeader() { - int startPos; - - startPos=bytePos=writeInt4(13, bytePos); - bytePos=writeString("IHDR", bytePos); - width=image.getWidth(null); - height=image.getHeight(null); - bytePos=writeInt4(width, bytePos); - bytePos=writeInt4(height, bytePos); - bytePos=writeByte(8, bytePos); // bit depth - bytePos=writeByte((encodeAlpha)?6:2, bytePos); // direct model - bytePos=writeByte(0, bytePos); // compression method - bytePos=writeByte(0, bytePos); // filter method - bytePos=writeByte(0, bytePos); // no interlace - crc.reset(); - crc.update(pngBytes, startPos, bytePos-startPos); - crcValue=crc.getValue(); - bytePos=writeInt4((int)crcValue, bytePos); - } - - /** - * Perform "sub" filtering on the given row. - * Uses temporary array leftBytes to store the original values - * of the previous pixels. The array is 16 bytes long, which - * will easily hold two-byte samples plus two-byte alpha. - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterSub(byte[] pixels, int startPos, int width) { - int i; - int offset=bytesPerPixel; - int actualStart=startPos+offset; - int nBytes=width*bytesPerPixel; - int leftInsert=offset; - int leftExtract=0; - - for(i=actualStart; i<startPos+nBytes; i++) { - leftBytes[leftInsert]=pixels[i]; - pixels[i]=(byte)((pixels[i]-leftBytes[leftExtract])%256); - leftInsert=(leftInsert+1)%0x0f; - leftExtract=(leftExtract+1)%0x0f; - } - } - - /** - * Perform "up" filtering on the given row. - * Side effect: refills the prior row with current row - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterUp(byte[] pixels, int startPos, int width) { - int i, nBytes; - byte current_byte; - - nBytes=width*bytesPerPixel; - - for(i=0; i<nBytes; i++) { - current_byte=pixels[startPos+i]; - pixels[startPos+i]=(byte)((pixels[startPos+i]-priorRow[i])%256); - priorRow[i]=current_byte; - } - } - - /** - * Write the image data into the pngBytes array. - * This will write one or more PNG "IDAT" chunks. In order - * to conserve memory, this method grabs as many rows as will - * fit into 32K bytes, or the whole image; whichever is less. - * - * - * @return true if no errors; false if error grabbing pixels - */ - protected boolean writeImageData() { - int rowsLeft=height; // number of rows remaining to write - int startRow=0; // starting row to process this time through - int nRows; // how many rows to grab at a time - - byte[] scanLines; // the scan lines to be compressed - int scanPos; // where we are in the scan lines - int startPos; // where this line's actual pixels start (used for filtering) - - byte[] compressedLines; // the resultant compressed lines - int nCompressed; // how big is the compressed area? - - PixelGrabber pg; - - bytesPerPixel=(encodeAlpha)?4:3; - - Deflater scrunch=new Deflater(compressionLevel); - ByteArrayOutputStream outBytes=new ByteArrayOutputStream(1024); - - DeflaterOutputStream compBytes=new DeflaterOutputStream(outBytes, scrunch); - try { - while(rowsLeft>0) { - nRows=Math.min(32767/(width*(bytesPerPixel+1)), rowsLeft); - // nRows = rowsLeft; - int[] pixels=new int[width*nRows]; - - pg=new PixelGrabber(image, 0, startRow, width, nRows, pixels, 0, width); - try { - pg.grabPixels(); - } catch(Exception e) { - System.err.println("interrupted waiting for pixels!"); - return false; - } - if((pg.getStatus()&ImageObserver.ABORT)!=0) { - System.err.println("image fetch aborted or errored"); - return false; - } - - /* - * Create a data chunk. scanLines adds "nRows" for - * the filter bytes. - */ - scanLines=new byte[width*nRows*bytesPerPixel+nRows]; - - if(filter==FILTER_SUB) { - leftBytes=new byte[16]; - } - if(filter==FILTER_UP) { - priorRow=new byte[width*bytesPerPixel]; - } - - scanPos=0; - startPos=1; - for(int i=0; i<width*nRows; i++) { - if(i%width==0) { - scanLines[scanPos++]=(byte)filter; - startPos=scanPos; - } - scanLines[scanPos++]=(byte)((pixels[i]>>16)&0xff); - scanLines[scanPos++]=(byte)((pixels[i]>>8)&0xff); - scanLines[scanPos++]=(byte)((pixels[i])&0xff); - if(encodeAlpha) { - scanLines[scanPos++]=(byte)((pixels[i]>>24)&0xff); - } - if((i%width==width-1)&&(filter!=FILTER_NONE)) { - if(filter==FILTER_SUB) { - filterSub(scanLines, startPos, width); - } - if(filter==FILTER_UP) { - filterUp(scanLines, startPos, width); - } - } - } - - /* - * Write these lines to the output area - */ - compBytes.write(scanLines, 0, scanPos); - - startRow+=nRows; - rowsLeft-=nRows; - } - compBytes.close(); - - /* - * Write the compressed bytes - */ - compressedLines=outBytes.toByteArray(); - nCompressed=compressedLines.length; - - crc.reset(); - bytePos=writeInt4(nCompressed, bytePos); - bytePos=writeString("IDAT", bytePos); - crc.update("IDAT".getBytes()); - bytePos=writeBytes(compressedLines, nCompressed, bytePos); - crc.update(compressedLines, 0, nCompressed); - - crcValue=crc.getValue(); - bytePos=writeInt4((int)crcValue, bytePos); - scrunch.finish(); - return true; - } catch(IOException e) { - System.err.println(e.toString()); - return false; - } - } - - /** - * Write a PNG "IEND" chunk into the pngBytes array. - */ - protected void writeEnd() { - bytePos=writeInt4(0, bytePos); - bytePos=writeString("IEND", bytePos); - crc.reset(); - crc.update("IEND".getBytes()); - crcValue=crc.getValue(); - bytePos=writeInt4((int)crcValue, bytePos); - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/graphics/layout/AFlowLayout.java b/graphics/AtlantisJava/src/atlantis/graphics/layout/AFlowLayout.java deleted file mode 100755 index 1d391e05e84..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/layout/AFlowLayout.java +++ /dev/null @@ -1,115 +0,0 @@ -package atlantis.graphics.layout; - -import java.awt.Container; -import java.awt.Insets; -import java.awt.LayoutManager; -import java.awt.Component; -import java.awt.Dimension; - -/** - * This Layout manager aranges the components in a flow like awt.FlowLayout. - * The difference is that this layout resizes the container to the minimum - * size after every layout operation, and therefore ensures that all components - * it laysout are visible. Nothing to do with the layout of the Atlantis canvas. - */ - -public class AFlowLayout implements LayoutManager { - private int hgap; - private int vgap; - - public AFlowLayout(int hgap, int vgap) { - this.hgap=hgap; - this.vgap=vgap; - } - - public void addLayoutComponent(String name, Component comp) {} - - public void removeLayoutComponent(Component comp) {} - - public Dimension minimumLayoutSize(Container target) { - return preferredLayoutSize(target); - } - - public Dimension preferredLayoutSize(Container target) { - Insets insets=target.getInsets(); - Dimension D=target.getSize(); - int W=D.width-insets.left-insets.right; - int L=hgap; - int y=vgap; - int w, h, hmax=0; - - for(int i=0; i<target.getComponentCount(); i++) { - Dimension d=target.getComponent(i).getPreferredSize(); - - w=d.width; - h=d.height; - - if(L+w+hgap<W) { - L+=w+hgap; - if(h>hmax) hmax=h; - } else { - L=hgap+w+hgap; - y+=hmax+vgap; - hmax=0; - if(h>hmax) hmax=h; - } - } - if(target.getComponentCount()>0) - y+=hmax+vgap; - - return new Dimension(W, y); - } - - public void layoutContainer(Container target) { - Insets insets=target.getInsets(); - Dimension D=target.getSize(); - int W=D.width-insets.left-insets.right; - int L=hgap; - int y=vgap; - int from=0; - int to=0; - int w, h, hmax=0; - - for(int i=0; i<target.getComponentCount(); i++) { - Dimension d=target.getComponent(i).getPreferredSize(); - - w=d.width; - h=d.height; - - if(L+w+hgap<W) { - L+=w+hgap; - to=i; - if(h>hmax) hmax=h; - } else { - layout(target, hgap+insets.left+(W/2-L/2), y, from, to); - L=hgap+w+hgap; - from=i; - to=i; - y+=hmax+vgap; - hmax=0; - if(h>hmax) hmax=h; - } - } - - if(target.getComponentCount()>0) - layout(target, hgap+insets.left+(W/2-L/2), y, from, to); - - /* - if (y + hmax + vgap != D.height) - SwingUtilities.invokeLater(new ARunAnotherLayout(target)); - */ - } - - public void layout(Container target, int x, int y, int from, int to) { - int xi=x; - - for(int i=from; i<=to; i++) { - Component comp=target.getComponent(i); - Dimension d=comp.getPreferredSize(); - - comp.setBounds(xi, y, d.width, d.height); - xi+=d.width+hgap; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/layout/AGridLayout.java b/graphics/AtlantisJava/src/atlantis/graphics/layout/AGridLayout.java deleted file mode 100755 index 034287a49e1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/layout/AGridLayout.java +++ /dev/null @@ -1,214 +0,0 @@ -package atlantis.graphics.layout; - -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.LayoutManager2; -import java.awt.Rectangle; - -import javax.swing.JComponent; -import javax.swing.SwingUtilities; - -import atlantis.canvas.ACanvas; - -/** - * This layout manager is a simplification of the - * <code>ConstrainedGridLayout</code> layout manager written by Charles A. - * Loomis. This layout manager hase two modes of operation: 1) CONSTRAINED - - * cell size is calculated by dividing the container size acording to aspect - * ratio. 2) PREFERRED - cell size is given at creation time - * - * @author Dumitru Petrusca. - */ -public class AGridLayout implements LayoutManager2 -{ - private Dimension gridSize; - private int cellSize; - private Dimension initialSize; - - public final static int CONSTRAINED = 0; - public final static int PREFERRED = 1; - private int layoutType; - private boolean secondLayout; - - final public static String GRID_SIZE_ERROR = "Grid size must have width and height > 0."; - - final public static String ASPECT_RATIO_ERROR = "Aspect ratio must have width and height > 0."; - - final public static String CONSTRAINT_ERROR = "Constraint must be a Rectangle with positive width and height."; - - final public static String AGRID_LAYOUT_CONSTRAINT = "ConstrainedGridLayout.RectangularConstraint"; - - /** - * Creates a new GridLayout of type CONSTRAINNED. - */ - public AGridLayout(Dimension gridSize, Dimension initialSize) - { - layoutType = CONSTRAINED; - setGridSize(gridSize); - secondLayout = true; - this.initialSize = initialSize; - } - - /** - * Creates a new GridLayout of type PREFERRED - */ - public AGridLayout(Dimension gridSize, int cellSize) - { - layoutType = PREFERRED; - setGridSize(gridSize); - this.cellSize = cellSize; - secondLayout = false; - initialSize = null; - } - - private void setGridSize(Dimension gridSize) - { - // Check that all of the dimensions given are reasonable. - if (gridSize.width <= 0 || gridSize.height <= 0 || gridSize.width > 100 || gridSize.height > 100) - throw new IllegalArgumentException(GRID_SIZE_ERROR); - - // Copy the information into the layout manager. - this.gridSize = new Dimension(0, 0); - this.gridSize.setSize(gridSize); - } - - public Dimension getGridSize() - { - return new Dimension(gridSize); - } - - /** - * Set (or reset) the constraints for the given component. - */ - public void setConstraints(Component comp, Rectangle constraints) - { - if (comp instanceof JComponent) - { - Rectangle copy = new Rectangle(constraints); - JComponent jc = (JComponent) comp; - - jc.putClientProperty(AGRID_LAYOUT_CONSTRAINT, copy); - } - } - - /** - * Get the constraints being used for the given component. - */ - public Rectangle getConstraints(Component comp) - { - Rectangle r = null; - - if (comp instanceof JComponent) - { - JComponent jc = (JComponent) comp; - Object constraint = jc.getClientProperty(AGRID_LAYOUT_CONSTRAINT); - - if (constraint instanceof Rectangle) - r = (Rectangle) constraint; - } - - return (r != null) ? new Rectangle(r) : null; - } - - // implementation of LayoutMamager interface - - public void addLayoutComponent(String name, Component comp) - {} - - public void removeLayoutComponent(Component comp) - {} - - public Dimension preferredLayoutSize(Container parent) - { - if (layoutType == CONSTRAINED) - { - Dimension d = parent.getSize(); - if (initialSize != null) - { - d = new Dimension(initialSize); - initialSize = null; - } - - int hCellSize = d.width / gridSize.width; - int vCellSize = d.height / gridSize.height; - if(ACanvas.getCanvas().getCurrentLayout().getName().equals("FULL SCREEN")) - { - return new Dimension(gridSize.width * hCellSize, gridSize.height * vCellSize); - } - cellSize = Math.min(hCellSize, vCellSize); - } - - return new Dimension(gridSize.width * cellSize, gridSize.height * cellSize); - } - - public Dimension minimumLayoutSize(Container parent) - { - return preferredLayoutSize(parent); - } - - public void layoutContainer(Container parent) - { - Dimension d = parent.getSize(); - int hCellSize = d.width / gridSize.width; - int vCellSize = d.height / gridSize.height; - int compCount = parent.getComponentCount(); - - for (int i = 0; i < compCount; i++) - { - Component comp = parent.getComponent(i); - Rectangle r = getConstraints(comp); - - if (r != null) - { - if(ACanvas.getCanvas().getCurrentLayout().getName().equals("FULL SCREEN")) - comp.setBounds(r.x * hCellSize, r.y * vCellSize, r.width * hCellSize, r.height * vCellSize); - else - comp.setBounds(r.x * cellSize, r.y * cellSize, r.width * cellSize, r.height * cellSize); - } - } - - if (secondLayout) - SwingUtilities.invokeLater(new ARunAnotherLayout(parent)); - } - - // implementation of LayoutMamager2 interface - - /** - * Adds the specified component to the layout, using the specified - * constraint object. - */ - public void addLayoutComponent(Component comp, Object constraints) - { - if (constraints instanceof Rectangle) - { - Rectangle r = (Rectangle) constraints; - - if (r.width <= 0 || r.height <= 0) - throw new IllegalArgumentException(CONSTRAINT_ERROR); - - setConstraints(comp, r); - } - else if (constraints != null) - throw new IllegalArgumentException(CONSTRAINT_ERROR); - } - - public Dimension maximumLayoutSize(Container target) - { - return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - public float getLayoutAlignmentX(Container target) - { - return 0.5f; - } - - public float getLayoutAlignmentY(Container target) - { - return 0.5f; - } - - public void invalidateLayout(Container target) - {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/layout/ARunAnotherLayout.java b/graphics/AtlantisJava/src/atlantis/graphics/layout/ARunAnotherLayout.java deleted file mode 100755 index ce1330374e3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/layout/ARunAnotherLayout.java +++ /dev/null @@ -1,26 +0,0 @@ -package atlantis.graphics.layout; - - -import java.awt.Container; -import java.awt.Window; -import javax.swing.SwingUtilities; - - -/** - * Used by the Layout Managers to invoke another layout operation. - * Needed to resize the canvas preserving aspect ratio. - */ - -public class ARunAnotherLayout implements Runnable { - private Container parent; - - public ARunAnotherLayout(Container parent) { - this.parent=parent; - } - - public void run() { - Window window=SwingUtilities.getWindowAncestor(parent); - - if(window!=null) window.pack(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/graphics/package.html b/graphics/AtlantisJava/src/atlantis/graphics/package.html deleted file mode 100644 index 0d498ed4259..00000000000 --- a/graphics/AtlantisJava/src/atlantis/graphics/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<html> -<head></head> -<body> -<p>2D graphical classes, graphical primitives.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/gui/AAboutDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AAboutDialog.java deleted file mode 100755 index 62546b20970..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AAboutDialog.java +++ /dev/null @@ -1,214 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.Font; -import java.awt.Color; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - -import javax.swing.JPanel; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JTextPane; -import javax.swing.BorderFactory; -import javax.swing.JFrame; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.utils.AUtilities; - - -/** - * - * About information dialog (Help -> About) - * - * @author Zdenek Maxa, Mark Stockton - */ -public class AAboutDialog extends JFrame -{ - - private static JPanel a_panel1 = null; - private static JPanel a_panel2 = null; - private static JPanel a_panel3 = null; - private static JPanel a_panel4 = null; - private static JPanel a_textPanel = null; - private static JLabel a_label1 = null; - private static JTextPane a_label2 = null; - private static JLabel a_label3 = null; - private static JTextPane a_label4 = null; - - private static JPanel m_panel1 = null; - private static JPanel m_panel2 = null; - private static JPanel m_panel3 = null; - private static JPanel m_panel4 = null; - private static JPanel m_textPanel = null; - private static JLabel m_label1 = null; - private static JTextPane m_label2 = null; - private static JTextPane m_label3 = null; - private static JTextPane m_label4 = null; - - private static JPanel c_panel1 = null; - - private static JPanel mainPanel = null; - - - private static JButton closeButton = null; - - private static AAboutDialog instance = null; - - private static final AGlobals globals = AGlobals.instance(); - - - private AAboutDialog(String title) - { - super(title); - try - { - createGUI(); - pack(); - } - catch(Exception ex) - { - ex.printStackTrace(); - } - - AIcon.setIconImage(this); - - } // AAboutDialog() ----------------------------------------------------- - - - - private void createGUI() - { - // top panel - atlantis - a_panel1 = new JPanel(); - a_panel1.setLayout(new GridLayout(1,2)); - - // top left text panel (4 lines of text) - a_panel2 = new JPanel(); - a_label2 = new JTextPane(); - Font font = new Font(a_panel2.getFont().getName(), - Font.BOLD, - a_panel2.getFont().getSize() + 6); - a_label2.setFont(font); - a_label2.setEditable(false); - a_label2.setBackground(a_panel2.getBackground()); - a_label2.setText(AGlobals.instance().getVersion()); - a_panel2.add(a_label2); - - a_panel3 = new JPanel(); - a_label3 = new JLabel("Event display for ATLAS"); - a_panel3.add(a_label3); - - a_panel4 = new JPanel(); - a_label4 = new JTextPane(); - a_label4.setBackground(a_panel4.getBackground()); - a_label4.setForeground(Color.blue); - a_label4.setText("http://www.cern.ch/atlantis" + "\n" + - "hn-atlas-AtlantisDisplay@cern.ch"); - a_label4.setEditable(false); - a_panel4.add(a_label4); - - a_textPanel = new JPanel(); - a_textPanel.setLayout(new GridLayout(3,1)); - a_textPanel.add(a_panel2); - a_textPanel.add(a_panel3); - a_textPanel.add(a_panel4); - - a_panel1.add(a_textPanel); - - String FILE_SEPAR = System.getProperty("file.separator"); - String homeDirectory = AGlobals.instance().getHomeDirectory(); - - // top right atlantis image - String path = homeDirectory + "img" + FILE_SEPAR + - "atlantis_log.gif"; - a_label1 = new JLabel(AUtilities.getFileAsImageIcon(path)); - a_panel1.add(a_label1); - - // middle panel - minerva - m_panel1 = new JPanel(); - m_panel1.setLayout(new GridLayout(1,2)); - - // middle left minerva image - path = homeDirectory + "img" + FILE_SEPAR + - "minerva_log.gif"; - m_label1 = new JLabel(AUtilities.getFileAsImageIcon(path)); - m_panel1.add(m_label1); - - // middle right text panel - m_panel2 = new JPanel(); - m_label2 = new JTextPane(); - m_label2.setFont(font); - m_label2.setEditable(false); - m_label2.setBackground(m_panel2.getBackground()); - m_label2.setText("MINERVA"); - m_panel2.add(m_label2); - - m_panel3 = new JPanel(); - m_label3 = new JTextPane(); - m_label3.setBackground(m_panel3.getBackground()); - m_label3.setEditable(false); - m_label3.setText(" Masterclass INvolving Event \n Recognition Visualised with Atlantis"); - m_panel3.add(m_label3); - - m_panel4 = new JPanel(); - m_label4 = new JTextPane(); - m_label4.setBackground(m_panel4.getBackground()); - m_label4.setForeground(Color.blue); - m_label4.setText("http://www.cern.ch/atlas-minerva"); - m_label4.setEditable(false); - m_panel4.add(m_label4); - - m_textPanel = new JPanel(); - m_textPanel.setLayout(new GridLayout(3,1)); - m_textPanel.add(m_panel2); - m_textPanel.add(m_panel3); - m_textPanel.add(m_panel4); - - m_panel1.add(m_textPanel); - - // bottom panel - close button - c_panel1 = new JPanel(new BorderLayout()); - closeButton = new JButton("Close"); - closeButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AAboutDialog.getInstance().dispose(); - } - }); - c_panel1.add(closeButton, BorderLayout.EAST); - c_panel1.setBorder(BorderFactory.createEmptyBorder(15, 0, 15, 15)); - - - // main panel - mainPanel = new JPanel(); - mainPanel.setLayout(new BorderLayout()); - mainPanel.add(a_panel1, BorderLayout.NORTH); - mainPanel.add(m_panel1, BorderLayout.CENTER); - mainPanel.add(c_panel1, BorderLayout.SOUTH); - - this.getContentPane().add(mainPanel, BorderLayout.CENTER); - - this.setResizable(false); - - this.setLocation(globals.getGuiFrame().getLocation()); - - } // createGUI() -------------------------------------------------------- - - - public static AAboutDialog getInstance() - { - if(instance == null) - { - instance = new AAboutDialog("About Atlantis"); - } - return instance; - - } // getInstance() ------------------------------------------------------ - - - -} // class AAboutDialog ===================================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/ACheckBox.java b/graphics/AtlantisJava/src/atlantis/gui/ACheckBox.java deleted file mode 100755 index f4af0033a9f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ACheckBox.java +++ /dev/null @@ -1,33 +0,0 @@ -package atlantis.gui; - -import java.awt.event.ActionListener; -import javax.swing.JCheckBox; - -/** - * This class does not generate an ActionEvent - * when the setSelected() method is called. - */ -public class ACheckBox extends JCheckBox { - ActionListener listener; - - public ACheckBox(String text) { - super(text); - } - - public ACheckBox() { - super(); - } - - public void addActionListener(ActionListener l) { - if(listener==null) { - super.addActionListener(listener); - listener=l; - } - } - - public void setSelected(boolean b) { - if(listener!=null) super.removeActionListener(listener); - super.setSelected(b); - if(listener!=null) super.addActionListener(listener); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ACheckNode.java b/graphics/AtlantisJava/src/atlantis/gui/ACheckNode.java deleted file mode 100755 index e2bac2cf8a3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ACheckNode.java +++ /dev/null @@ -1,86 +0,0 @@ -package atlantis.gui; - -import java.util.Iterator; -import atlantis.parameters.AParameter; -import atlantis.parameters.AStatusParameter; -import atlantis.parameters.ACommandProcessor; -import hep.wired.util.DefaultTristateTreeNode; -import hep.wired.util.TristateCheckBox; - -/** - * - * @author Qiang - */ - -public class ACheckNode extends DefaultTristateTreeNode { - - public static final byte SINGLE_SELECTION = 0; - - public static final byte MULTI_SELECTION = 1; - - private byte selectionMode; - - private AParameter parameter; - - public ACheckNode(Object userObject, boolean selectionValue, byte selectionMode, AParameter parameter) { - super(userObject, selectionValue, true); - setSelectionMode(selectionMode); - this.parameter = parameter; - } - - public void setSelectionMode(byte selectionMode) { - this.selectionMode = selectionMode; - } - - public byte getSelectionMode() { - return this.selectionMode; - } - - public AParameter getParameter(){ - return this.parameter; - } - - public void updateState(){ - if(children!=null){ - int checkedNumber = 0; - for(Iterator it=children.iterator(); it.hasNext();){ - ACheckNode aChildNode = (ACheckNode)it.next(); - aChildNode.updateState(); - if(aChildNode.isSelected()) - checkedNumber++; - } - if(checkedNumber==0) - this.setSelected(false); - else - this.setSelected(true); - } else{ - ACheckBox cellComponent = (ACheckBox)getUserObject(); - cellComponent.setSelected(getParameter().getStatus()); - setSelected(cellComponent.isSelected()); - } - } - - public void getClicked(boolean selectionFlag, boolean statusChange) { - setSelected(selectionFlag); - if((parameter instanceof AStatusParameter) && statusChange){ - // a leaf node is found here - AStatusParameter theStatusParameter = (AStatusParameter)parameter; - ACommandProcessor.receive(theStatusParameter.getName()); - theStatusParameter.apply(); - } else{ - // parameter is either AStatusRootParameter or AStatusGroupParameter - if((selectionMode==MULTI_SELECTION) && (children!=null)){ - ((TristateCheckBox)this.getUserObject()).setSelected(selectionFlag); - for(Iterator it=children.iterator(); it.hasNext();){ - ACheckNode aChildNode = (ACheckNode)it.next(); - // either AStatusGrooupParameter node or AStatusParameter node - aChildNode.getClicked(selectionFlag, !(aChildNode.isSelected()==selectionFlag)); - } - } - } - if(parent!=null){ - ((ACheckNode)parent).updateState(); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AClosingConfirmationDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AClosingConfirmationDialog.java deleted file mode 100755 index 3872b0960e5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AClosingConfirmationDialog.java +++ /dev/null @@ -1,63 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import javax.swing.JOptionPane; - -import atlantis.config.ADefaultValues; -import atlantis.utils.ALogger; - -/** - * - * Atlantis application closing confirmation dialog. - * All Atlantis closing actions can be added here and this - * class shall be used for closing the application. - * - */ -public class AClosingConfirmationDialog extends WindowAdapter -{ - private static ALogger logger = ALogger.getLogger(AClosingConfirmationDialog.class); - - private Frame adaptee; - - - public AClosingConfirmationDialog(Frame adaptee) - { - this.adaptee = adaptee; - - } // AClosingConfirmationDialog() --------------------------------------- - - - - public void windowClosing(WindowEvent e) - { - exitApp(); - - } // windowClosing() ---------------------------------------------------- - - - - public void exitApp() - { - - String msg = "Do you really want to quit Atlantis?"; - int i = JOptionPane.showConfirmDialog(adaptee, msg, "Exit Atlantis", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null); - if(i == JOptionPane.YES_OPTION) - { - logger.debug("Shutting down, going to save runtime values..."); - ADefaultValues.saveRuntimeValues(); - logger.warn("Shutting down, calling System.exit(0)"); - System.exit(0); - } - else - { - return; - } - - } // exitApp() ---------------------------------------------------------- - - - -} // class AClosingConfirmationDialog ======================================= diff --git a/graphics/AtlantisJava/src/atlantis/gui/AColorComboBoxRenderer.java b/graphics/AtlantisJava/src/atlantis/gui/AColorComboBoxRenderer.java deleted file mode 100755 index d0eed9427aa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AColorComboBoxRenderer.java +++ /dev/null @@ -1,126 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Graphics; -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.ToolTipManager; -import javax.swing.BorderFactory; -import javax.swing.JList; -import javax.swing.ListCellRenderer; -import javax.swing.border.Border; - -import atlantis.graphics.colormap.AColorMap; - -/** - * The class used as a renderer when displaying the colors in the UI. - */ -public class AColorComboBoxRenderer extends JLabel - implements ListCellRenderer { - - private ColorIcon icon=new ColorIcon(); - private Border selectedBorder; - private Border deselectedBorder=BorderFactory.createEmptyBorder(2, 2, 2, 2); - - public Component getListCellRendererComponent( - JList list, Object value, int index, - boolean isSelected, boolean cellHasFocus) { - - int colorIndex=((Integer)value).intValue(); - Color[] colorMap=AColorMap.getColors(); - Color color=colorMap[colorIndex]; - - icon.setColor(color); - setIcon(icon); - setText(""+((Integer)value).intValue()); - - if(isSelected) { - selectedBorder=BorderFactory.createLineBorder(list.getSelectionBackground(), 2); - - setBorder(selectedBorder); - - ToolTipManager.sharedInstance().setInitialDelay(1); - ToolTipManager.sharedInstance().setReshowDelay(1); - - String message; - - if(color.equals(Color.black)) - message="Black: "; - else if(color.equals(Color.blue)) - message="Blue: "; - else if(color.equals(Color.cyan)) - message="Cyan: "; - else if(color.equals(Color.darkGray)) - message="DarkGray: "; - else if(color.equals(Color.gray)) - message="Gray: "; - else if(color.equals(Color.green)) - message="Green: "; - else if(color.equals(Color.lightGray)) - message="LightGray: "; - else if(color.equals(Color.magenta)) - message="Magenta: "; - else if(color.equals(Color.orange)) - message="Orange: "; - else if(color.equals(Color.pink)) - message="Pink: "; - else if(color.equals(Color.red)) - message="Red: "; - else if(color.equals(Color.white)) - message="White: "; - else if(color.equals(Color.yellow)) - message="Yellow: "; - else - message=""; - - list.setToolTipText(message+color.getRed()+", "+color.getGreen()+", "+color.getBlue()); - } else setBorder(deselectedBorder); - - return this; - } - - private static class ColorIcon implements Icon { - private int w, h; - private Color color; - - public ColorIcon() { - this(Color.gray, 50, 15); - } - - public ColorIcon(Dimension d) { - this.w=d.width; - this.h=d.height; - } - - public ColorIcon(Color color, int w, int h) { - this.color=color; - this.w=w; - this.h=h; - } - - public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(Color.black); - g.drawRect(x, y, w-1, h-1); - g.setColor(color); - g.fillRect(x+1, y+1, w-2, h-2); - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color=color; - } - - public int getIconWidth() { - return w; - } - - public int getIconHeight() { - return h; - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AColorHelpDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AColorHelpDialog.java deleted file mode 100755 index 695a2814bd3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AColorHelpDialog.java +++ /dev/null @@ -1,260 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; - -import javax.swing.JFrame; -import javax.swing.JTextField; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; - -/** - * The help dialog displays the current color of objects - * - * @author Mark Stockton - */ -public class AColorHelpDialog extends JFrame implements WindowListener -{ - private static JTextField[] textField; - public static Color[] colorMap = AColorMap.getColors(); - private static AColorHelpDialog instance = null; - - private static APar parameterStore = APar.instance(); - private static AEventManager eventManager = AEventManager.instance(); - - public static AColorHelpDialog getInstance() - { - if (AGlobals.isAtlantisHeadless()) { - return null; - } - if (instance == null) - instance = new AColorHelpDialog(); - return instance; - } - - public void update() - { - if(!this.isVisible()) - return; - getContentPane().removeAll(); - validate(); - - String[] dataObjectsToDisplay={"RVx", "TRT", "SiCluster", "SiClusterRDO", "S3D", "PixelCluster", "PixelRDO", "TrigS3D", - "MDT", "CSC", "RPC", "TGC", - "EmTauROI", "JetROI", "MuonROI", "LVL1TriggerTower", "LVL1JetElement", - "STr", "SNP", "SMTr", "SVx"}; - String[] dataObjectsWithCollectionsToDisplay={"InDetTrack", "InDetSegment", "Cluster", "MuonTrack", - "MuonSegment", "Jet", "ETMis", "BJet","Electron","Muon","Photon","TauJet","CompositeParticle"}; - String[] geometryObjectsToDisplay={"PIXFill", "SILFill", "TRTFill", "SolFill", "ECALFill", - "HCALFill", "RPCFill", "TGCFill", "MDTFill", "CSCFill", "BkgFill"}; - - int numObjects = Math.max(dataObjectsWithCollectionsToDisplay.length,dataObjectsToDisplay.length); - int numOfColumns = 4; - getContentPane().setLayout(new GridLayout(numObjects+1,numOfColumns)); - textField = new JTextField[(numObjects+1)*4]; - AEvent event = eventManager.getCurrentEvent(); - - //table column titles - fillTextField(0, Color.white, Color.black, " Geometry color"); - fillTextField(1, Color.white, Color.black, " Color of objects without collections"); - fillTextField(2, Color.white, Color.black, " Color of objects with collections"); - fillTextField(3, Color.white, Color.black, " Object Collection"); - - //loop over objects - for(int j=0; j<numObjects; j++) - { - int i=4*j + 4; - //display geometry color - if(j<geometryObjectsToDisplay.length) - { - String source = "Det"; - if(geometryObjectsToDisplay[j].equals("BkgFill")) - source = "Color"; - Color backgroundColor=colorMap[parameterStore.get(source, geometryObjectsToDisplay[j]).getI()]; - //display screen name - String text=parameterStore.get(source, geometryObjectsToDisplay[j]).getScreenName(); - fillTextField(i, backgroundColor, text); - }else{ - fillTextField(i);//nothing to display - } - - i++; - //display object without collection color - if(j<dataObjectsToDisplay.length){ - fillTextField(i,dataObjectsToDisplay[j]); - }else{ - fillTextField(i);//nothing to display - } - - i++; - //display object with collection color - if(j<dataObjectsWithCollectionsToDisplay.length){ - fillTextField(i,dataObjectsWithCollectionsToDisplay[j]); - }else{ - fillTextField(i);//nothing to display - } - - //display object collection - i++; - if(j<dataObjectsWithCollectionsToDisplay.length){ - //get collections - String[] collections=event.getActiveCollectionNames(dataObjectsWithCollectionsToDisplay[j]); - String text; - //check is on/has collectons/not all selected - if(!parameterStore.get("Data", dataObjectsWithCollectionsToDisplay[j]).getStatus() || - collections==null || collections.length==0) - text = "n/a"; - else if(collections.length>1) - text = ">1 selected"; - else - { - text = collections[0].substring(dataObjectsWithCollectionsToDisplay[j].length()); - } - fillTextField(i, Color.white, Color.black, text); - - }else{ - fillTextField(i);//nothing to display - } - } - - invalidate(); - pack(); - } - - /** - * Fills the text field with chosen colours and text - * foreground colour and text can be null to just fill background - * - * @param index - textfield index - * @param background - background colour - * @param foreground - foreground color - * @param text - text to display - */ - private void fillTextField(int index, Color background, Color foreground, String text) - { - if(textField[index]==null) - textField[index]=new JTextField(); - textField[index].setEditable(false); - textField[index].setBackground(background); - if(foreground!=null) - textField[index].setForeground(foreground); - if(text!=null) - textField[index].setText(text); - getContentPane().add(textField[index]); - } - - /** - * Will fill a blank text field - * - * @param index - textfield index - */ - private void fillTextField(int index) - { - //nothing to display so set color to be the - //same as the outline color of the text boxes - fillTextField(index, (new Color(184,207,229)), null, null); - } - - /** - * Automatically decides the forground text colour - * depending on the background color - * - * @param index - textfield index - * @param background - background colour - * @param text - text to display - */ - private void fillTextField(int index, Color background, String text) - { - //find out if too dark for black text - if( background.getBlue()==background.getRed() - && background.getBlue()==background.getGreen() - && background.getBlue()<=128) - fillTextField(index, background, Color.white, text); - else - fillTextField(index, background, Color.black, text); - } - - /** - * Get information from object for background - * colour and objedct name + status gives the text - * - * @param index - textfield index - * @param object - name of object - */ - private void fillTextField(int index, String object) - { - //if color by constant or has no colour option (e.g. vertex) - if(parameterStore.get(object, "ColorFunction")==null - || parameterStore.get(object, "ColorFunction").getI()==0) - { - Color backgroundColor=colorMap[parameterStore.get(object, "Constant").getI()]; - String text = object; - if(!parameterStore.get("Data", object).getStatus()) - text += " - data type not active"; - fillTextField(index, backgroundColor, text); - } - else - { - String text = object; - if(parameterStore.get("Data", object).getStatus()) - text += " is not being colored constant"; - else - text += " - data type not active"; - fillTextField(index, Color.white, Color.black, text); - } - } - - private AColorHelpDialog() - { - this.setTitle("Current window Geometry and Object colors and Object Collection"); - AIcon.setIconImage(this); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - - this.update(); - this.setResizable(false); - addWindowListener(this); - - // set the initial location - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - int screenHeight = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getHeight()); - this.setLocation((int) Math.max(0, 0.1*screenWidth), (int) Math.max(0, 0.1*screenHeight)); - } - - public void dispose() - { - instance = null; - super.dispose(); - } - - public void windowOpened(WindowEvent e) - { - this.update(); - } - - public void windowClosing(WindowEvent e) - {} - - public void windowClosed(WindowEvent e) - {} - - public void windowIconified(WindowEvent e) - {} - - public void windowDeiconified(WindowEvent e) - {} - - public void windowActivated(WindowEvent e) - {} - - public void windowDeactivated(WindowEvent e) - {} - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/gui/AColorMapDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AColorMapDialog.java deleted file mode 100755 index e0b91297e22..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AColorMapDialog.java +++ /dev/null @@ -1,109 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.JRadioButton; - -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; -import atlantis.graphics.colormap.AColorMap; - -/** - * This dialog is displayed when the user wants to change the current color set. - */ -public class AColorMapDialog extends JDialog implements ActionListener -{ - private JPanel choosePanel; - private JPanel buttonsPanel; - private JButton okButton, cancelButton; - private JRadioButton selected; - - private static final AGlobals globals = AGlobals.instance(); - - public AColorMapDialog() - { - super(globals.getGuiFrame(), "Select Map Dialog", true); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - setResizable(false); - - choosePanel = new JPanel(); - choosePanel.setBorder(BorderFactory.createTitledBorder(" Select Color Map ")); - - ButtonGroup group = new ButtonGroup(); - - choosePanel.setLayout(new GridLayout(5, 1)); - for (int i = 0; i < AColorMap.getMapNames().length - 2; i++) - { // quick fix to not select hitcolor CT - JRadioButton r = new JRadioButton(AColorMap.getMapNames()[i]); - - r.addActionListener(this); - if (AColorMap.getColorMap() == i) - { - selected = r; - r.setSelected(true); - } - else - r.setSelected(false); - group.add(r); - choosePanel.add(r); - } - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(choosePanel, BorderLayout.CENTER); - - okButton = new JButton("OK"); - okButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AColorMap.setColorMap(selected.getText()); - ACanvas.getCanvas().repaintAllFromScratch(); - dispose(); - } - }); - - cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - dispose(); - } - }); - - buttonsPanel = new JPanel(); - buttonsPanel.add(okButton); - buttonsPanel.add(cancelButton); - getContentPane().add(buttonsPanel, BorderLayout.SOUTH); - pack(); - - // set the initial location - Frame owner = globals.getGuiFrame(); - int guiWidth = owner.getWidth(); - int guiHeight = owner.getHeight(); - int guiX = owner.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if(guiX+guiWidth+(dialogWidth-guiWidth)/2>screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max(0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), Math.max(0, (guiHeight - dialogHeight) / 3)); - setVisible(true); - } - - public void actionPerformed(ActionEvent e) - { - selected = (JRadioButton) e.getSource(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AColorMapEditor.java b/graphics/AtlantisJava/src/atlantis/gui/AColorMapEditor.java deleted file mode 100755 index 1c534d12967..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AColorMapEditor.java +++ /dev/null @@ -1,281 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Font; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JColorChooser; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; - -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; -import atlantis.graphics.colormap.AColorMap; -import atlantis.graphics.colormap.MappedColor; -import atlantis.graphics.layout.AFlowLayout; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.ADragListener; -import atlantis.utils.AUtilities; - -/** - * The dialog allows the user to edit the colors maps (at runtime). - */ -public class AColorMapEditor extends JDialog implements ADragListener -{ - private static AColorMapEditor instance; - private ADnDLabel[][] labels = new ADnDLabel[AColorMap.getNumMaps()][AColorMap.getNumColors()]; - private int colorMap; - private int index; - private MappedColor previousColor; - private ADnDLabel source; - - private JPanel colorPanel, buttonsPanel; - private JButton okButton, applyButton, cancelButton; - - private static final AGlobals globals = AGlobals.instance(); - - private AColorMapEditor() - { - super(globals.getGuiFrame(), "Color Map Editor", false); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - setResizable(false); - colorPanel = new JPanel(); - colorPanel.setLayout(new GridLayout(AColorMap.getNumColors() + 1, AColorMap.getNumMaps() + 1, 0, 0)); - - // creating the names row - JLabel padding = new JLabel(""); - colorPanel.add(padding); - for (int i = 0; i < AColorMap.getNumMaps(); i++) - { - JLabel label = new JLabel(" " + AColorMap.getMapNames()[i] + " ", JLabel.CENTER); - label.setFont(new Font("Dialog", Font.BOLD, 14)); - colorPanel.add(label); - } - - // creating the color table - Color[] col; - MouseListener labelMouseListener = new LabelMouseListener(); - - for (int j = 0; j < AColorMap.getNumColors(); j++) - { - JLabel label = new JLabel("" + j, JLabel.CENTER); - label.setFont(new Font("Dialog", Font.BOLD, 14)); - colorPanel.add(label); - for (int i = 0; i < AColorMap.getNumMaps(); i++) - { - col = AColorMap.getColors(i); - labels[i][j] = new ADnDLabel("text", false); - labels[i][j].addDragListener(this); - labels[i][j].setOpaque(true); - labels[i][j].setBackground(col[j]); - labels[i][j].setForeground(col[j]); - labels[i][j].setToolTipText(col[j].getRed() + ", " + col[j].getGreen() + ", " + col[j].getBlue()); - setLineBorder(labels[i][j]); - labels[i][j].addMouseListener(labelMouseListener); - colorPanel.add(labels[i][j]); - } - } - - buttonsPanel = new JPanel(); - buttonsPanel.setLayout(new AFlowLayout(10, 10)); - - okButton = new JButton("OK"); - okButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - applyColors(); - dispose(); - instance = null; - } - }); - buttonsPanel.add(okButton); - - applyButton = new JButton("Apply"); - applyButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - applyColors(); - } - }); - buttonsPanel.add(applyButton); - - cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - dispose(); - instance = null; - } - }); - buttonsPanel.add(cancelButton); - - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(colorPanel, BorderLayout.CENTER); - getContentPane().add(buttonsPanel, BorderLayout.SOUTH); - pack(); - - // set the initial location - Frame owner = globals.getGuiFrame(); - int guiWidth = owner.getWidth(); - int guiHeight = owner.getHeight(); - int guiX = owner.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if(guiX+guiWidth+(dialogWidth-guiWidth)/2>screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max(0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), Math.max(0, (guiHeight - dialogHeight) / 3)); - setVisible(true); - } - - public static AColorMapEditor getInstance() - { - if (instance == null) - { - instance = new AColorMapEditor(); - } - return instance; - } - - public void updateColors() - { - if (instance != null) - { - MappedColor[][] maps = AColorMap.getMaps(); - for (int i = 0; i < maps.length; i++) - for (int j = 0; j < maps[i].length; j++) - { - Color c = maps[i][j]; - - labels[i][j].setBackground(c); - labels[i][j].setForeground(c); - labels[i][j].setToolTipText(c.getRed() + ", " + c.getGreen() + ", " + c.getBlue()); - } - repaint(); - } - } - - public void dragPerformed(Object from, Object to, int action) - { - ADnDLabel fromLabel = (ADnDLabel) from; - ADnDLabel toLabel = (ADnDLabel) to; - - toLabel.setBackground(fromLabel.getBackground()); - } - - class LabelMouseListener extends MouseAdapter - { - public void mouseClicked(MouseEvent e) - { - if (SwingUtilities.isLeftMouseButton(e)) - { - source = (ADnDLabel) e.getSource(); - Color color = JColorChooser.showDialog(instance, "Color Map Editor - Chooser", source.getBackground()); - if (color != null) - { - source.setBackground(color); - source.setForeground(color); - setLineBorder(source); - source.setToolTipText(color.getRed() + ", " + color.getGreen() + ", " + color.getBlue()); - } - } - } - - public void mousePressed(MouseEvent e) - { - source = (ADnDLabel) e.getSource(); - getPosition(); - - if (AUtilities.isRightMouseButton(e)) - { - if (index < 8) - for (int j = 8; j < AColorMap.getNumColors(); j++) - labels[colorMap][j].setBackground(labels[colorMap][index].getBackground()); - else - for (int j = 0; j < 8; j++) - labels[colorMap][j].setForeground(labels[colorMap][index].getForeground()); - - } - else if (SwingUtilities.isMiddleMouseButton(e)) - { - MappedColor[][] maps = AColorMap.getMaps(); - previousColor = maps[colorMap][index]; - MappedColor c = maps[colorMap][index]; - - if (c.getGreen() > 128) - maps[colorMap][index] = maps[colorMap][AColorMap.BK]; - else - maps[colorMap][index] = maps[colorMap][AColorMap.WH]; - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - - public void mouseReleased(MouseEvent e) - { - if (AUtilities.isRightMouseButton(e)) - { - if (index < 8) - for (int j = 8; j < AColorMap.getNumColors(); j++) - labels[colorMap][j].setBackground(labels[colorMap][j].getForeground()); - else - for (int j = 0; j < 8; j++) - labels[colorMap][j].setForeground(labels[colorMap][j].getBackground()); - } - else if (SwingUtilities.isMiddleMouseButton(e)) - { - MappedColor[][] maps = AColorMap.getMaps(); - maps[colorMap][index] = previousColor; - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - } - - private void setLineBorder(JComponent comp) - { - comp.setBorder(BorderFactory.createLineBorder(new Color(207, 207, 207), 3)); - } - - private void getPosition() - { - for (int i = 0; i < AColorMap.getNumMaps(); i++) - for (int j = 0; j < AColorMap.getNumColors(); j++) - if (labels[i][j] == source) - { - colorMap = i; - index = j; - break; - } - } - - private void applyColors() - { - MappedColor[][] maps = AColorMap.getMaps(); - for (int i = 0; i < maps.length; i++) - for (int j = 0; j < maps[i].length; j++) - { - Color c = labels[i][j].getBackground(); - - maps[i][j] = new MappedColor(c.getRed(), c.getGreen(), c.getBlue(), j); - } - AGUI.getGUI().repaintTable(); - ACanvas.getCanvas().repaintAllFromScratch(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AComboBox.java b/graphics/AtlantisJava/src/atlantis/gui/AComboBox.java deleted file mode 100755 index d91a35879b6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AComboBox.java +++ /dev/null @@ -1,51 +0,0 @@ -package atlantis.gui; - - -import java.awt.event.ItemListener; -import javax.swing.JComboBox; - - -/** - * This class does not generate an ItemEvent - * when the setSelectedItem() method is called. - */ - -public class AComboBox extends JComboBox { - private ItemListener listener; - - /** - * Just calls the superclass constructor. - */ - public AComboBox() { - super(); - } - - /** - * Set the GUIItemListener to be informed of ItemEvents. - * Only one listener is allowed. - * @param aListener - */ - public void setGUIItemListener(ItemListener aListener) { - // Remove any existing listeners. - for (ItemListener listener : this.getItemListeners()) this.removeItemListener(listener); - super.addItemListener(aListener); - listener=aListener; - } - - /** - * Check whether the GUIItemListener has already been set. - * @return true if this AComboBox has a GUIItemListener - */ - public boolean hasGUIItemListener() {return (listener!=null);} - - /** - * Set the selected item without telling any item listeners. - * @param item - */ - public void setGUISelectedItem(Object item) { - if(listener!=null) super.removeItemListener(listener); - super.setSelectedItem(item); - if(listener!=null) super.addItemListener(listener); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AConfigWriter.java b/graphics/AtlantisJava/src/atlantis/gui/AConfigWriter.java deleted file mode 100755 index a903e939ef4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AConfigWriter.java +++ /dev/null @@ -1,417 +0,0 @@ -package atlantis.gui; - -import java.awt.geom.Point2D; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.util.Vector; - -import javax.swing.JOptionPane; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParametersGroup; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; - -/** - * - * <ul><li>Reads the configuration file (given file name) and makes the corrections - * according to the actual configuration which might have been changed by the - * user.</li> - * <li>Reads parameters differences (values from the parameters store).</li> - * <li>Reads canvas / window configuration.</li> - * <li>Creates XML config files from three above parts.</li></ul> - * - * <p>Writes out the current status. This is not a robust piece of code and make - * break if the format of config.xml is changed by hand. - * This class should throw an exception if there is a problem. - * </p> - * - * @author Gary Taylor, Zdenek Maxa - */ -public class AConfigWriter -{ - - private static ALogger logger = ALogger.getLogger(AConfigWriter.class); - - protected static APar parameterStore = APar.instance(); - - private AConfigWriter() - { - } - - /** - * Main method from the class - * @param sourceFile String - * @return String - */ - public static String getConfiguration(String sourceFile) - { - logger.trace("Trying to read the distribution configuration ..."); - String config = null; - StringBuffer output = new StringBuffer(""); - - config = readConfiguration(sourceFile); - - if(config != null) - { - logger.debug("Loading source configuration successful."); - output.append(config); - output.append(getParametersDifferences()); - output.append(getWindowCorners()); - output.append("\n</AtlantisConfiguration>\n"); - return output.toString(); - } - else - { - logger.error("Loading source configuration failed."); - return null; - } - } // getConfiguration() ------------------------------------------------- - - - - private static String getParametersDifferences() - { - StringBuffer output = new StringBuffer(""); - - output.append("\n\n"); - output.append("\t<ParameterDifferences>\n"); - - AParametersGroup[][] group = parameterStore.getUIGroups(); - for(int i = 0; i < group.length; i++) - { - for(int j = 0; j < group[i].length; j++) - { - Vector v = group[i][j].getParameters(999); - for(int k = 0; k < v.size(); ++k) - { - output.append(((AParameter)v.elementAt(k)).getDifferences(group[i][j].getGroupName())); - } - } - } - output.append("\t</ParameterDifferences>\n\n"); - - return output.toString(); - - } // getParametersDifferences() ----------------------------------------- - - - - private static String getWindowCorners() - { - StringBuffer output = new StringBuffer(""); - - output.append("\n\n"); - output.append("\t<WindowCorners>\n"); - - String[] windowNames = ACanvas.getCanvas().getKnownWindowNames(); - - for(int i = 0; i < windowNames.length; i++) - { - Point2D.Double[] corners = - ACanvas.getCanvas().getWindow(windowNames[i]).getUserCorners(); - if(corners != null) - { - output.append("\t\t<CORNERS windowName=\"" + - windowNames[i] + "\""); - for(int j = 0; j < corners.length; ++j) - { - output.append(" x" + j + "=\"" + corners[j].getX() + "\""); - output.append(" y" + j + "=\"" + corners[j].getY() + "\""); - } - output.append("/>\n"); - } - } - - output.append("\t</WindowCorners>\n\n\n"); - - return output.toString(); - } // getWindowCorners() ------------------------------------------------- - - - // Read one logic line from xml file - // contain <....> or <..../> - private static String readLogicLine(BufferedReader reader) throws IOException - { - String startLine = reader.readLine(); - if(startLine == null) - return null; - - StringBuffer logicLine = new StringBuffer(startLine); - - while(logicLine.indexOf("<") >= 0 && logicLine.indexOf(">") < 0) - { - logicLine.append("\n"); - logicLine.append(reader.readLine()); - } - return logicLine.toString(); - } - - - private static String readConfiguration(String fileName) - { - String groupName = ""; - String parameterName = ""; - AParameter aParam = null; - BufferedReader curr = null; - String str; - StringBuffer buffer = new StringBuffer(""); // working buffer - StringBuffer output = new StringBuffer(""); // final result - boolean inComment = false; - - try - { - logger.debug("Trying to open configuration file: " + fileName); - InputStream fis = AUtilities.getFileAsStream(fileName); - InputStreamReader isr = new InputStreamReader(fis); - curr = new BufferedReader(isr, 10000); - - while((str = readLogicLine(curr)) != null) - { - buffer = new StringBuffer(str); - // in a comment ? - if(buffer.indexOf("<!--") >= 0) - { - inComment = true; - } - if(buffer.indexOf("-->") >= 0) - { - inComment = false; - } - if(!inComment) - { - // nearly finished writing - if(buffer.indexOf("</Parameters>") >= 0) - { - output.append(buffer); - output.append("\n"); - break; - } - - // modification in the initialisation - if(buffer.indexOf("<Canvas") >= 0) { - buffer = replace(buffer, "startupLayout", ACanvas.getCanvas().getCurrentLayout().getName()); - String ar = Double.toString(ACanvas.getCanvas().getAspectRatio()); - buffer = replace(buffer, "aspectRatio", ar); - } - - if(buffer.indexOf("<UsedWindow") >= 0) - { - String name = get(buffer, "name"); - if(name != null) - { - AWindow w = ACanvas.getCanvas().getWindow(name); - if(w != null) - { - if(w.getProjection() != null) - { - buffer = replace(buffer, "projection", w.getProjection().getName()); - } - buffer = replace(buffer, "group", w.getGroupName()); - } - } - } - - if(buffer.indexOf("<Layout") >= 0) - { - String name = get(buffer, "name"); - if(name != null && name.equals(ACanvas.getCanvas().getCurrentLayout().getName())) - { - buffer = replace(buffer, "startupWindow", ACanvas.getCanvas().getCurrentWindowName()); - buffer = replace(buffer, "startup", ACanvas.getCanvas().getStartupString()); - } - } - - // new group encountered - if(buffer.indexOf("<Group") >= 0) - { - groupName = get(buffer, "name"); - } - - // new parameter encountered - aParam = null; - if(buffer.indexOf(" fn=\"") >= 0 && - buffer.indexOf("<StatusRoot") < 0 && - buffer.indexOf("<StatusGroup") < 0) - { - parameterName = removeSpaces(get(buffer, "fn")); - aParam = parameterStore.getUnknown(groupName, parameterName); - } - if(aParam != null) - { - // replacing status - if(buffer.indexOf(" st=\"") >= 0) - { - String status = "OFF"; - if(aParam.getStatus()) - { - status = "ON"; - } - buffer = replace(buffer, "st", status); - } - - // replacing value - if(buffer.indexOf(" va=\"") >= 0) - { - String value = aParam.getValue(); - - if(parameterName.equals("Area/Energy")) - { - value = "0.0"; - } - // for instance Track Collections listbox should - // always remain: - // sn="Track Collections" va="0" pv="none=0" - // current 'value' mustn't be put there - else if(parameterName.endsWith("Collections")) - { - value = "0"; - } - buffer = replace(buffer, "va", value); - - } - - // replacing operator - if(buffer.indexOf(" dop=\"") >= 0) - { - String dop = aParam.getOperator(); - if(dop.equals("<")) - { - dop = "<"; - } - if(dop.equals("<=")) - { - dop = "≤"; - } - if(dop.equals(">")) - { - dop = ">"; - } - if(dop.equals(">=")) - { - dop = "≥"; - } - buffer = replace(buffer, "dop", dop); - } - - // replacing scope - if(buffer.indexOf(" scope=\"") >= 0) - { - if(aParam.getScope() == AParameter.GLOBAL) - { - buffer = replace(buffer, "scope", "GLOBAL"); - } - else if(aParam.getScope() == AParameter.LOCAL) - { - buffer = replace(buffer, "scope", "LOCAL"); - } - } - else if(buffer.indexOf(" fn=\"") > 0) - { - // in a parameter - adding scope if needed - if(aParam.getScope() != parameterStore.getGroup(groupName).getScope()) - { - int index = buffer.indexOf("/>"); - if(index > 0) - { - if(aParam.getScope() == AParameter.GLOBAL) - { - buffer.insert(index, - " scope=\"GLOBAL\""); - } - else - { - buffer.insert(index, - " scope=\"LOCAL\""); - } - } - } - } - } // aParam != null - } // !inComment - output.append(buffer); - output.append("\n"); - } // while - curr.close(); - } // try - catch(IOException ex) - { - String m = "I/O error occured when reading the source " + - "configuration file: " + fileName; - logger.error(m); - logger.debug(m, ex); - output = null; - } - catch(AAtlantisException ae) - { - //throw ae; - } - - - return (output != null) ? output.toString() : null; - - } // readConfiguration() ------------------------------------------------ - - - - /** - * Removing spaces from the parameter name - * @param name String - * @return String - */ - private static String removeSpaces(String name) - { - StringBuffer strBuffer = new StringBuffer(name); - int i = 0; - while(i < strBuffer.length()) - { - if(Character.isWhitespace(strBuffer.charAt(i))) - { - strBuffer.deleteCharAt(i); - } - else - { - i++; - } - } - return new String(strBuffer); - } // removeSpaces() ----------------------------------------------------- - - - private static StringBuffer replace(StringBuffer s, String variable, String text) - { - int name = s.indexOf(variable + "=\""); - if(name >= 0) - { - int start = s.indexOf("\"", name); - int stop = s.indexOf("\"", start + 1); - s.delete(start + 1, stop); - s.insert(start + 1, text); - } - - return s; - } // replace() ---------------------------------------------------------- - - - private static String get(StringBuffer s, String variable) - { - // insert a space before the variable name to prevent from the variable - // name is a substring of another variable name - int name = s.indexOf(" " + variable + "=\""); - if(name >= 0) - { - int start = s.indexOf("\"", name); - int stop = s.indexOf("\"", start + 1); - return s.substring(start + 1, stop); - } - return null; - } // get() -------------------------------------------------------------- - -} // class AConfigWriter ==================================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/AControlButton.java b/graphics/AtlantisJava/src/atlantis/gui/AControlButton.java deleted file mode 100755 index 007cd042757..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AControlButton.java +++ /dev/null @@ -1,84 +0,0 @@ -package atlantis.gui; - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.Timer; -import javax.swing.JButton; - -/** - * This class is not used at the moment. - * Was used to control animation. - */ -public class AControlButton extends JButton { - - public static final int STANDARD_ACTION=0; - public static final int ACCELERATED_ACTION=1; - - private ActionListener controlListener; - private ActionEvent standardAction, acceleratedAction; - private long ticks; - private Timer timer; - private int initialDelay; - private int tickLength; - private int accelerationLimit; - private boolean ignoreClick=false; - - public AControlButton(String text, int initialDelay, int tickLength, int accelerationLimit) { - super(text); - this.initialDelay=initialDelay; - this.tickLength=tickLength; - this.accelerationLimit=accelerationLimit; - initialize(); - } - - private void initialize() { - standardAction=new ActionEvent(this, 0, "", STANDARD_ACTION); - acceleratedAction=new ActionEvent(this, 0, "", ACCELERATED_ACTION); - - timer=new Timer(tickLength, new ActionListener() { - public void actionPerformed(ActionEvent e) { - ticks++; - fireControlActionPerformed(); - ignoreClick=true; - } - }); - timer.setInitialDelay(initialDelay); - - addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - ticks=0; - timer.restart(); - } - - public void mouseReleased(MouseEvent e) { - timer.stop(); - } - - public void mouseClicked(MouseEvent e) { - if(ignoreClick) - ignoreClick=false; - else - fireControlActionPerformed(); - } - }); - - } - - private void fireControlActionPerformed() { - if(controlListener!=null) { - if(ticks>accelerationLimit) - controlListener.actionPerformed(acceleratedAction); - else - controlListener.actionPerformed(standardAction); - } - } - - public void addControlActionListener(ActionListener controlListener) { - if(this.controlListener!=null) - throw new Error("AControlButton supports only 1 listener"); - this.controlListener=controlListener; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ACrashReporter.java b/graphics/AtlantisJava/src/atlantis/gui/ACrashReporter.java deleted file mode 100644 index d47949481a8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ACrashReporter.java +++ /dev/null @@ -1,232 +0,0 @@ -// NOTE: revert to previous version once support for Java 1.5 is dropped - -package atlantis.gui; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.globals.AGlobals; -import java.awt.Desktop; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.lang.Thread.UncaughtExceptionHandler; -import java.net.URI; -import java.net.URLEncoder; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; - -/** - * This class handles any unhandled exception (program crash). It asks the user for - * permission to submit a crash report by e-mail and pre-formats the message. It then - * fires the default system mail client with this message to allow the user to add - * additional commands and send it. - * - * @author Eric Jansen - */ -public class ACrashReporter implements UncaughtExceptionHandler { - - // Dialog asking for permission to report the crash - private static final String title = "An uncaught exception occured"; - private static final String msg = - "An uncaught exception occured!\n\n" - + "Please help us prevent this in the future by reporting this incident.\n" - + "If you click yes, Atlantis will try to open your mail client and create\n" - + "a preformatted crash report for you. You can review the information\n" - + "and add additional comments before it is sent.\n\n" - + "Do you want to report this crash?"; - - // Address that receives crash reports, chopped up in case spiders go through this code - private static final String address = "atlas-atlantis-developers" + "@" + "cern" + "." + "ch"; - - // Tag for easy filtering, prefix for the mail subject - private static final String tag = "[crash-report] "; - - // System properties included in the report - private static final String[] properties = { - "java.version", "java.vendor", "java.vm.specification.version", - "java.vm.specification.vendor", "java.vm.specification.name", "java.vm.version", - "java.vm.vendor", "java.vm.name", "java.specification.version", "java.specification.vendor", - "java.specification.name", "os.name", "os.arch", "os.version"}; - - /** Flag indicating whether CrashReporter has already been shown */ - private static boolean shownCrashReporter = false; - - /** - * Exception handler for uncaught exceptions in Atlantis. The only way to - * "handle" such an exception is to tell the developers that they failed. - * So that is what we will do. - * @param t thread - * @param e uncaught exception - */ - public void uncaughtException(Thread t, Throwable e) { - // Ensure this only happens once - if (shownCrashReporter) return; - shownCrashReporter = true; - - int confirm = JOptionPane.showConfirmDialog(null, msg, title, - JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null); - - if (confirm == JOptionPane.YES_OPTION) { - String report = "### Please explain briefly what you did when the problem occured (optional)\n\n"; - - report += "\n### Exception information\n\n"; - report += getExceptionInformation(e); - - report += "\n### General information\n\n"; - report += getGeneralInformation(); - - report += "\n### Event information\n\n"; - report += getEventInformation(); - - // If possible, we open the mail client and create a new message - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - - if (desktop.isSupported(Desktop.Action.MAIL)) { - String subject = getSubject(e); - try { - URI uri = new URI("mailto:" + address + "?SUBJECT=" - + encode(subject) + "&BODY=" + encode(report)); - desktop.mail(uri); - } catch (Throwable ex) { - // Something went wrong, save report to file instead - saveToFile(report); - } - } else { - // No mail support, save report to file instead - saveToFile(report); - } - } else { - // No desktop support, save report to file instead - saveToFile(report); - } - } - } - - /** - * Provides mail encoding of a string (URLEncoding but with %20 for space) - * @param s string to encode - * @return encoded string - */ - private static String encode(String s) { - try { - return URLEncoder.encode(s, "utf-8").replaceAll("\\+", "%20"); - } catch (Throwable ex) { - return s; - } - } - - /** - * This provides is the backup option if starting the mail client doesn't - * work. The report will be saved to a local file and we ask the user to - * send it. - * @param report crash report contents - */ - private void saveToFile(String report) { - String directory = AGlobals.instance().getHomeDirectory(); - JFileChooser chooser = new JFileChooser(directory); - chooser.setDialogTitle("Save crash report"); - chooser.setSelectedFile(new File("crash-report.txt")); - - // Remind people where this report should go at the top of the file - report = "### Atlantis crash report, please send to " + address + "\n\n" - + report; - - // Continue asking until the user chooses a valid file or cancels - while (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { - File file = chooser.getSelectedFile(); - try { - OutputStream out = new FileOutputStream(file.getAbsolutePath()); - out.write(report.getBytes()); - out.close(); - - JOptionPane.showMessageDialog(null, "The crash report has been saved successfully.\n" - + "Please send the file to " + address); - return; - } catch (Throwable ex) { - JOptionPane.showMessageDialog(null, "Cannot write file: " + ex.toString()); - } - } - } - - /** - * Takes the exception and finds the most helpful mail subject, in general - * the exact location of the crash should be helpful when dealing with a - * lot of reports. - * @param e uncaught exception - * @return subject string - */ - private static String getSubject(Throwable e) { - StackTraceElement[] st = e.getStackTrace(); - if (st.length > 0) { - return tag + st[0].toString(); - } else { - return tag + e.toString(); - } - } - - /** - * Formats general information about the system, Java and Atlantis - * @return information string - */ - private static String getGeneralInformation() { - StringBuilder s = new StringBuilder(); - s.append("Atlantis version = " + AGlobals.instance().getVersion() + "\n"); - - for (String property : properties) { - String value = System.getProperty(property); - if (value == null) { - value = "(not set)"; - } - s.append(property + " = " + value + "\n"); - } - - return s.toString(); - } - - /** - * Formats stack trace and exception information - * @param e unhandled exception - * @return information string - */ - private static String getExceptionInformation(Throwable e) { - StringBuilder s = new StringBuilder(); - String pad = ""; - - s.append(e.toString() + "\n\n"); - - StackTraceElement[] st = e.getStackTrace(); - for (StackTraceElement traceline : st) { - s.append(pad + traceline + "\n"); - pad = " "; - } - - return s.toString(); - } - - /** - * Formats event information, such as source, file, run/event and datatypes - * @return information string - */ - private static String getEventInformation() { - StringBuilder s = new StringBuilder(); - AEventManager eventManager = AEventManager.instance(); - AEvent event = eventManager.getCurrentEvent(); - if (event == null) { - return "(no current event)"; - } - - s.append("Source = " + event.getSourceName() + "\n"); - s.append("Run = " + event.getRunNumber() + "\n"); - s.append("Event = " + event.getEventNumber() + "\n"); - - s.append("\nData types present:\n"); - String[][] info = event.getInfo(); - for (String[] item : info) { - s.append(" " + item[0] + " (" + item[1] + ")\n"); - } - - return s.toString(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ADefaultCellAttribute.java b/graphics/AtlantisJava/src/atlantis/gui/ADefaultCellAttribute.java deleted file mode 100755 index 1a17ebd0ef9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ADefaultCellAttribute.java +++ /dev/null @@ -1,129 +0,0 @@ -package atlantis.gui; - -import java.awt.Dimension; - -public class ADefaultCellAttribute -{ - public static final int ROW = 0; - public static final int COLUMN = 1; - - // - // !!!! CAUTION !!!!! - // these values must be synchronized to Table data - // - protected int rowSize; - protected int columnSize; - protected int[][][] span; - - public ADefaultCellAttribute() - { - this(1, 1); - } - - public ADefaultCellAttribute(int numRows, int numColumns) - { - setSize(new Dimension(numColumns, numRows)); - } - - protected void initValue() - { - for (int i = 0; i < span.length; i++) - { - for (int j = 0; j < span[i].length; j++) - { - span[i][j][COLUMN] = 1; - span[i][j][ROW] = 1; - } - } - } - - public int[] getSpan(int row, int column) - { - if (isOutOfBounds(row, column)) - { - int[] ret_code = { 1, 1 }; - return ret_code; - } - return span[row][column]; - } - - public boolean isVisible(int row, int column) - { - if (isOutOfBounds(row, column)) - return false; - if ((span[row][column][COLUMN] < 1) - || (span[row][column][ROW] < 1)) - return false; - return true; - } - - public void combine(int[] rows, int[] columns) - { - if (isOutOfBounds(rows, columns)) - return; - int rowSpan = rows.length; - int columnSpan = columns.length; - int startRow = rows[0]; - int startColumn = columns[0]; - for (int i = 0; i < rowSpan; i++) - { - for (int j = 0; j < columnSpan; j++) - { - if ((span[startRow + i][startColumn + j][COLUMN] != 1) - || (span[startRow + i][startColumn + j][ROW] != 1)) - { - return; - } - } - } - for (int i = 0, ii = 0; i < rowSpan; i++, ii--) - { - for (int j = 0, jj = 0; j < columnSpan; j++, jj--) - { - span[startRow + i][startColumn + j][COLUMN] = jj; - span[startRow + i][startColumn + j][ROW] = ii; - } - } - span[startRow][startColumn][COLUMN] = columnSpan; - span[startRow][startColumn][ROW] = rowSpan; - } - - public Dimension getSize() - { - return new Dimension(rowSize, columnSize); - } - - public void setSize(Dimension size) - { - columnSize = size.width; - rowSize = size.height; - span = new int[rowSize][columnSize][2]; // 2: COLUMN,ROW - initValue(); - } - - protected boolean isOutOfBounds(int row, int column) - { - if ((row < 0) || (rowSize <= row) || (column < 0) - || (columnSize <= column)) - { - return true; - } - return false; - } - - protected boolean isOutOfBounds(int[] rows, int[] columns) - { - for (int i = 0; i < rows.length; i++) - { - if ((rows[i] < 0) || (rowSize <= rows[i])) - return true; - } - for (int i = 0; i < columns.length; i++) - { - if ((columns[i] < 0) || (columnSize <= columns[i])) - return true; - } - return false; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ADemoDialog.java b/graphics/AtlantisJava/src/atlantis/gui/ADemoDialog.java deleted file mode 100755 index be69b6c21e2..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ADemoDialog.java +++ /dev/null @@ -1,434 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSeparator; -import javax.swing.JSpinner; -import javax.swing.JTextField; -import javax.swing.SpinnerNumberModel; -import javax.swing.SwingConstants; -import javax.swing.WindowConstants; -import javax.swing.border.Border; - -import java.util.Arrays; -import java.util.Vector; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.projection.AProjectionsManager; -import atlantis.parameters.ACommandProcessor; -import atlantis.utils.ALogger; - - - - - -/** - * A Dialog in which user can set parameters for demo mode, as well as start and - * stop the demo mode. This class holds and controls the demo loop thread. - * This is a singleton, but there is no point why it needs to be. - * - * @author Sebastian Boeser (with traces from Qiang Lu) - */ -public class ADemoDialog extends JFrame implements ActionListener -{ - //Get a logger - private final static ALogger logger = ALogger.getLogger(ADemoDialog.class); - - //Some GUI elements - private JSpinner timerSpinner; - private SpinnerNumberModel timerSpinnerModel; - private static final Integer TIMER_MIN = new Integer(1); - private static final Integer TIMER_MAX = new Integer(120); - private static final Integer TIMER_INIT = new Integer(3); - - //The text label showing the projection sequence - private JTextField sequenceTextField = null; - //And the panel housing these - private JPanel projControlPanel=null; - - //The action buttons - private JButton startButton = null; - private JButton stopButton = null; - private JButton closeButton = null; - - - //The thread that is runing the loop - private ADemoLoop demo = null; - - private static final AGlobals globals = AGlobals.instance(); - - //The singleton instance - private static ADemoDialog instance = null; - - /** - * Public access-instantiation accessor - * @return the singleton instance - */ - public static ADemoDialog getInstance(){ - //Create instance if needed - if (instance == null) instance = new ADemoDialog(); - //and return it - return instance; - } - - /** - * Private Constructor - */ - private ADemoDialog() { - super("Demo"); - createGUI(); - pack(); - } - - // initialize the GUI - private void createGUI() - { - JPanel timerControlPanel = createTimeControlPanel(); - projControlPanel = createProjControlPanel(); - JPanel buttonControlPanel = createButtonControlPanel(); - - JPanel contentPane = new JPanel(new GridBagLayout()); - contentPane.setOpaque(true); - GridBagConstraints c = new GridBagConstraints(); - c.weightx = 1; - c.weighty = 1; - c.gridwidth = GridBagConstraints.REMAINDER; - c.fill=GridBagConstraints.HORIZONTAL; - c.anchor = GridBagConstraints.CENTER; - contentPane.add(timerControlPanel, c); - contentPane.add(projControlPanel, c); - contentPane.add(buttonControlPanel, c); - this.setResizable(false); - this.setContentPane(contentPane); - this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - this.setAlwaysOnTop(true); - - // set the initial location - Frame gui = globals.getGuiFrame(); - int guiWidth = gui.getWidth(); - int guiHeight = gui.getHeight(); - int guiX = gui.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if(guiX + guiWidth + (dialogWidth - guiWidth) / 2 > screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), - Math.max(0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), - Math.max(0, (guiHeight - dialogHeight) / 3)); - AIcon.setIconImage(this); - } - - private JPanel createTimeControlPanel() - { - - JPanel aPanel = new JPanel(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - aPanel.setOpaque(true); - //aPanel.setPreferredSize(new Dimension(FRAME_WIDTH, PANEL_HEIGHT)); - aPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); - - //Add timer label - JLabel timerLabel= new JLabel("Interval"); - c.gridwidth = 1; - c.fill = GridBagConstraints.HORIZONTAL; - c.weightx=1; - c.gridx=0; - aPanel.add(timerLabel,c); - //Add timer spinner - timerSpinner = new JSpinner(); - timerSpinner.setEnabled(true); - timerSpinnerModel = new SpinnerNumberModel(TIMER_INIT, TIMER_MIN, - TIMER_MAX, new Integer(1)); - timerSpinner.setModel(timerSpinnerModel); - c.gridwidth = 1; - c.weightx=1; - c.fill = GridBagConstraints.HORIZONTAL; - c.gridx=1; - aPanel.add(timerSpinner,c); - //Add units label - c.weightx = 0.5; - c.gridwidth = GridBagConstraints.REMAINDER; - c.gridx=2; - aPanel.add(new JLabel(" sec"),c); - - - //Add the labels for th selected projections - c.gridx=GridBagConstraints.RELATIVE; - c.weightx=1; - c.gridwidth=1; - aPanel.add(new JLabel("Sequence:"), c); - - //Now generate the sequence label and make it span the remaining columns - sequenceTextField = new JTextField(); - c.gridwidth=GridBagConstraints.REMAINDER; - c.fill=GridBagConstraints.HORIZONTAL; - aPanel.add(sequenceTextField,c); - - return aPanel; - } - - private JPanel createProjControlPanel() - { - - JPanel aPanel = new JPanel(new GridLayout(3,4)); - aPanel.setOpaque(true); - Border outerBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5); - Border innerBorder = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.GRAY), - "Add Projection / Action"); - aPanel.setBorder(BorderFactory.createCompoundBorder(outerBorder, innerBorder)); - - //Create the list of check boxes - for (String projName : AProjectionsManager.getKnownProjectionNames()){ - - //Check wether this projection name should be used in the demo dialog - if (AProjectionsManager.useProjectionInDemoMode(projName)){ - - //Create the respective button with the screen name of the projection - String projScreenName = AProjectionsManager.getProjection(projName).getScreenName(); - JButton projButton = new JButton(projScreenName); - //Store the name of the projection as the name of the JCheckBox - //Where we can retrieve it once the demo dialog is started - projButton.setName(projName); - projButton.setFocusPainted(false); - - //Add ourselves as action listener of this button - projButton.addActionListener(this); - aPanel.add(projButton); - } - } - //Also add a "next event" button - JButton nextEvtBut = new JButton("Next event"); - nextEvtBut.setName("NE"); - nextEvtBut.addActionListener(this); - aPanel.add(nextEvtBut); - - return aPanel; - } - - private JPanel createButtonControlPanel() - { - //final int PANEL_HEIGHT = 40; - Dimension buttonDimension = new Dimension(100,25); - - JPanel aPanel = new JPanel(new GridBagLayout()); - aPanel.setOpaque(true); - //aPanel.setPreferredSize(new Dimension(FRAME_WIDTH, PANEL_HEIGHT)); - aPanel.setBorder(BorderFactory.createEmptyBorder(5,5,10,5)); - - GridBagConstraints c = new GridBagConstraints(); - startButton = new JButton("Start"); - //startButton.setFocusPainted(false); - startButton.setEnabled(true); - startButton.setPreferredSize(buttonDimension); - startButton.addActionListener(this); - c.weightx = 1; - c.weighty = 1; - c.anchor = GridBagConstraints.CENTER; - aPanel.add(startButton, c); - stopButton = new JButton("Stop"); - stopButton.setFocusPainted(false); - stopButton.setEnabled(false); - stopButton.setPreferredSize(buttonDimension); - stopButton.addActionListener(this); - aPanel.add(stopButton, c); - JSeparator aSeparator = new JSeparator(SwingConstants.VERTICAL); - //aSeparator.setPreferredSize(new Dimension(5, PANEL_HEIGHT)); - aPanel.add(aSeparator, c); - closeButton = new JButton("Close"); - closeButton.setFocusPainted(false); - closeButton.setEnabled(true); - closeButton.setPreferredSize(buttonDimension); - closeButton.addActionListener(this); - c.gridwidth = GridBagConstraints.REMAINDER; - aPanel.add(closeButton, c); - - return aPanel; - } - - /** - * @return true if demo thread is running, otherwise false - */ - boolean isRunning(){ - //no thread -> false - if (demo == null) return false; - //otherwise use thread status - return demo.isRunning(); - } - - - // return interval in millisecond - int getTimerInterval() - { - return 1000 * timerSpinnerModel.getNumber().intValue(); - } - - public void setTimerInterval(Integer intervalInSec) - { - try { - timerSpinnerModel.setValue(intervalInSec); - } catch (IllegalArgumentException iae){ - //Just ignore in case of illegal argument - } - } - - - /** - * Set the sequence of projections - * @param projNames colon seperated list of projection names - */ - public void setSequence(String projNames){ - //store this in our text entry - sequenceTextField.setText(projNames); - } - - /** - * Set the default sequence - */ - public void setDefaultSequence(){ - //Create default sequence - StringBuilder sequence = new StringBuilder(); - //Add all default projections - for (String projName : AProjectionsManager.getKnownProjectionNames()){ - if (AProjectionsManager.defaultProjectionInDemoMode(projName)) - sequence.append(projName+":"); - } - //End sequence with next event - sequence.append("NE"); - //And set this in the text field - sequenceTextField.setText(sequence.toString()); - } - - /** - * @return a vector with the names of the projections - */ - private Vector<String> getSequence() - { - return new Vector<String>(Arrays.asList(sequenceTextField.getText().split(":"))); - } - - /** - * Validate whether the given sequence is valid - * @return the number of selected projections - */ - private boolean validateSequence() - { - //Get the projections sequence - Vector<String> sequence = getSequence(); - - //Check on number of projections - if(sequence.size() < 1){ - JOptionPane.showMessageDialog(this, - "No projection/event is selected, please select at least select one", - "Warning", JOptionPane.WARNING_MESSAGE); - return false; - } - - //Now check each item of the sequence for validity - for (String projName : sequence){ - //The "new event" action is an exception here - if (projName.equals("NE")) continue; - //check wether this is a known and allowed projection - if ((! Arrays.asList(AProjectionsManager.getKnownProjectionNames()).contains(projName)) || - (! AProjectionsManager.useProjectionInDemoMode(projName))) - { - JOptionPane.showMessageDialog(this, - "Not a valid projection name: '"+projName+"'", - "Warning", JOptionPane.WARNING_MESSAGE); - return false; - } - - } - - //Seems all okay - return true; - } - - - - /** - * Start the demo thread - */ - public void startDemo() - { - - //First make sure some projections have been selected - if (!validateSequence()) return; - - //Set single full window mode - ACommandProcessor.receive("WW"); - - //Start the demo, setting "stopOnNoMoreEvents" to false - //TODO: make stopOnNoMoreEvents a checkbox in the Dialog - demo = new ADemoLoop(getTimerInterval(),getSequence(),false); - demo.startDemoLoop(); - //Now disable all GUI elements - timerSpinner.setEnabled(false); - sequenceTextField.setEnabled(false); - for (Component comp: projControlPanel.getComponents()) comp.setEnabled(false); - startButton.setEnabled(false); - stopButton.setEnabled(true); - closeButton.setEnabled(false); - //Do not allowe the user to close the window, so he doesn't loose access - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - - /** - * Stop the demo thread - */ - synchronized void stopDemo() - { - //exit the demo - demo.stopDemoLoop(); - //Now reenable all GUI elements - timerSpinner.setEnabled(true); - sequenceTextField.setEnabled(true); - for (Component comp: projControlPanel.getComponents()) comp.setEnabled(true); - stopButton.setEnabled(false); - startButton.setEnabled(true); - closeButton.setEnabled(true); - - this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - } - - /** - * Implementation of the Action listener - * - gets called for every button that is pressed - * @param e the action event - */ - public void actionPerformed(ActionEvent e) { - //Check for action buttons first - if (e.getSource() == startButton ) startDemo(); - else if (e.getSource() == stopButton) stopDemo(); - else if (e.getSource() == closeButton ) dispose(); - //this should be one of the projection buttons - else { - //get the projectio name to append - String projName = ((JButton)e.getSource()).getName(); - //get the existing sequence - String sequence = sequenceTextField.getText(); - //append new projection - sequence += ((sequence.length()!=0) ? ":" : "") + projName; - //Set this as new sequence - sequenceTextField.setText(sequence); - } - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ADemoFileChooser.java b/graphics/AtlantisJava/src/atlantis/gui/ADemoFileChooser.java deleted file mode 100755 index c9768ef7aab..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ADemoFileChooser.java +++ /dev/null @@ -1,41 +0,0 @@ -package atlantis.gui; - -import java.awt.Component; -import java.io.File; - -import atlantis.config.ADefaultValues; - -/** -* A dialog which appears when a user asks to read a new event. -* -* @author Qiang Lu -*/ -public class ADemoFileChooser extends AXMLFileChooser -{ - private File fileSelected; - - public ADemoFileChooser(String path, Component parent) - { - super(path, parent); - } - - public boolean processSelectedFile(File file) - { - if (file.canRead()) - { - // save last visited location - ADefaultValues.set("LastEventFilesSourceDir", file.getParent() + - System.getProperty("file.separator")); - - fileSelected = file; - return true; - } - return false; - } - - public File getFileSelected() - { - return fileSelected; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ADemoLoop.java b/graphics/AtlantisJava/src/atlantis/gui/ADemoLoop.java deleted file mode 100755 index 85f387a9708..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ADemoLoop.java +++ /dev/null @@ -1,200 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.util.ArrayList; - -import atlantis.canvas.ACanvas; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionsManager; -import atlantis.parameters.ACommandProcessor; -import atlantis.utils.ALogger; -import java.awt.event.ActionListener; -import java.util.Iterator; -import java.util.Vector; -import javax.swing.JOptionPane; - -import javax.swing.Timer; - -/** - * A class to automatically loop over different projections given in a - * colon-seperated list. The special projection name "NE" stands for next event. - * This is also used in headless mode to generate an event loop. The stopOnNoMoreEvents - * allows to control wether the loop ends if no more events can be obtained. - * - * NOTE: The previous implementation of this was using java.awt.Thread - we are - * far from providing the standards of a thread-safe application. - * - * @author Sebastian Boeser - */ -public class ADemoLoop extends Timer implements ActionListener -{ - //The logger - private static ALogger logger = ALogger.getLogger(ADemoLoop.class); - - //whether to stop the loop if there are no more events - private boolean stopOnNoMoreEvents = false; - - //A list of projections to show - private final ArrayList<String> projectionList = new ArrayList<String>(); - - //An iterator that loops through the list above - private Iterator<String> projIter = null; - - private static final AGlobals globals = AGlobals.instance(); - - /** - * Fully specified Constructor - * @param sleepTime time to sleep inbetween projections in milliseconds - * @param projectionList list of projections to loop through - * @param stopOnNoMoreEvents wether to stop loop if there are no more events - */ - public ADemoLoop(int sleepTime, Vector<String> projectionList, boolean stopOnNoMoreEvents){ - - //Initialize the timer - super(sleepTime,null); - addActionListener(this); - - //Initialize the timer to start immediately only on first event - setInitialDelay(0); - - //Store the list of projections - for (String projName : projectionList) - this.projectionList.add(projName); - - //Set the stop on no more events flag - this.stopOnNoMoreEvents = stopOnNoMoreEvents; - - } - - - /*** - * prepare the demo loop and start the timer thread - */ - public void startDemoLoop(){ - AGlobals.instance().setDemoMode(true); - - //be verbose - logger.trace("Starting demo loop with interval "+Integer.toString(getDelay())+ - " ms and projections "+projectionList.toString()); - - //Generate the list iterator to point to the start of the list - projIter = projectionList.listIterator(0); - - //Finally start the loop - start(); - } - - /** - * stop the demo loop - */ - public void stopDemoLoop(){ - stop(); - globals.setDemoMode(true); - } - - /** - * This gets fired by the timer every time after it returns from sleep - * @param event the action event - */ - public void actionPerformed(ActionEvent event) { - - //If we have reached the end, start from beginning - if (! projIter.hasNext()) projIter = projectionList.listIterator(0); - - //proceed to next element in list - String projName = projIter.next(); - - //add debugging output - logger.trace("Next in demo loop: "+projName); - - //Check if this is a next event tag - if (projName.equals("NE")) { - //Change the event or stop loop if this did not succeed - if (!changeEvent()) { - //stop the loop - stop(); - //notify everyone that we are done (so the application can finish) - synchronized(this) { notifyAll(); } - } - - //Immediatly go to the next projection if this is not just a nextEvent again - Iterator<String> nextProjIter = projIter; - if (nextProjIter.hasNext() && (!nextProjIter.next().equals("NE"))) restart(); - //be verbose - logger.trace("Timer is"+(isRunning()?" running":" stopped")+" with "+getDelay()+" ms delay"); - } - //else just change the projection - else changeProjection(projName); - - } - - - /** - * Change the current projection to the one given by projName - * and select that as active projeciton in the GUI - * @param projName the name of the projection - */ - private void changeProjection(String projName) - { - //First get the projection object - AProjection p = AProjectionsManager.getProjection(projName); - //And set the projection - ACanvas.getCanvas().getCurrentWindow().setProjection(p); - //Make sure aspect ratio is always okay - if(projName.equals("YX")||projName.equals("RZ")||projName.equals("XZ")||projName.equals("YZ")) - ((AProjection2D) p).setAspectRatio1(ACanvas.getCanvas().getCurrentWindow()); - //Finally Change the current GUI selection by signaling the command processor - ACommandProcessor.receive(projName + "."); - } - - /** - * Switch to the next event - * @return if the return value is true, the loop will be continued, otherwise not - */ - private boolean changeEvent(){ - Frame gui = globals.getGuiFrame(); - //try reading the next event - try{ - //Then get next event - AEventManager eventManager = AEventManager.instance(); - eventManager.nextEvent(); - return true; - } catch (NoMoreEventsException ex) { - //Just wait for next event - logger.info("No next event for demo - "+((stopOnNoMoreEvents)?"stopping loop":"keeping same")); - //return wether loop shall be stopped due to this or not. - return (!stopOnNoMoreEvents); - } catch (InvalidEventSourceException ex) { - //log warning - logger.warn("Invalid event source for demo - " - +((stopOnNoMoreEvents)?"stopping loop":"will try again") - +"\n"+ex.getCauseMessages()); - //quit here in headless mode - if (AGlobals.isAtlantisHeadless()) return (!stopOnNoMoreEvents); - //Otherwise give a user warning - JOptionPane.showMessageDialog(gui, - "Invalid event source for demo - stopping loop", - "Warning", JOptionPane.WARNING_MESSAGE); - //Always quit the loop if not in headless mode - return false; - } catch (ReadEventException ex) { - //log warning - logger.warn("Received invalid event - stopping loop:\n"+ex.getCauseMessages()); - //and tell user unless we are in headless - if (AGlobals.isAtlantisHeadless()) return false; - //in headless mode, don't show a dialog - JOptionPane.showMessageDialog(gui, - "Received invalid event for demo - stopping loop", - "Warning", JOptionPane.WARNING_MESSAGE); - return false; - } - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/gui/AEventLoopDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AEventLoopDialog.java deleted file mode 100755 index 152bc9f5c2c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AEventLoopDialog.java +++ /dev/null @@ -1,346 +0,0 @@ -package atlantis.gui; - -import java.util.Date; - -import java.awt.Color; -import java.awt.Frame; -import java.awt.event.WindowListener; -import java.awt.event.WindowEvent; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.BorderLayout; -import java.awt.Dimension; - -import java.text.SimpleDateFormat; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.border.Border; -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; -import javax.swing.SpinnerNumberModel; -import javax.swing.Timer; - -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.output.ALogInterface; -import atlantis.utils.ALogger; - - -/** - * Read events in a loop using a given timer intervall - * This is a singleton class using the getInstance pattern. - * - * @author Sebastian Boeser - */ -public class AEventLoopDialog extends JFrame - implements WindowListener, ActionListener, ChangeListener -{ - // the logger - private static ALogger logger = ALogger.getLogger(AEventLoopDialog.class); - - private static final AGlobals globals = AGlobals.instance(); - - //create singleton instance - private static AEventLoopDialog instance; - - // some GUI attributes - private static final String TITLE = "Event loop"; - private static final Integer SPINNER_INIT = new Integer(4); - private static final Integer SPINNER_MIN = new Integer(1); - private static final Integer SPINNER_MAX = new Integer(120); - private static final Integer SPINNER_STEP = new Integer(2); - - // We don't need more than one button - private static JButton button = null; - - //The update time in seconds - private static JSpinner updateIntervalSpinner = null; - //A logging pane - private static ALogPane log = null; - - // The update timer - private static final Timer timer = new Timer(SPINNER_INIT*1000,null); - - - private AEventLoopDialog() - { - //Create dialog with title - super(TITLE); - - //Construct GUI - createGUI(); - - } // AReadEventFromServerDialog() --------------------------------------- - - /** - * @return the singleton instance - */ - public static AEventLoopDialog getInstance(){ - if (instance == null) instance = new AEventLoopDialog(); - return instance; - } // getInstance() ------------------------------------------------------ - - - /** - * Non-static set functions so user is forced to obtain an instance first - * @param UpdateInterval the update intervall - */ - public void setUpdateInterval(int UpdateInterval) { - try { - updateIntervalSpinner.setValue(UpdateInterval); - } catch (IllegalArgumentException iae){ - //Just ignore in case of an invalid argument - } - } - - /** - * Design of the dialog - panels, buttons, etc - */ - private void createGUI() { - - //Definde default component gap - final int defaultGap = 5; - final Border defaultBorder = BorderFactory.createEmptyBorder(5, 10, 5, 10); - - /** - * Looping panel - */ - //Create a spinner for the update time - SpinnerNumberModel numberModel = new SpinnerNumberModel(SPINNER_INIT, SPINNER_MIN, SPINNER_MAX, SPINNER_STEP); - updateIntervalSpinner = new JSpinner(numberModel); - updateIntervalSpinner.addChangeListener(this); - - // looping panel - JPanel loopingPanel = new JPanel(); - loopingPanel.setLayout(new BorderLayout(defaultGap, 0)); - loopingPanel.setBorder(defaultBorder); - loopingPanel.add(updateIntervalSpinner, BorderLayout.CENTER); - loopingPanel.add(new JLabel("[secs]"), BorderLayout.EAST); - - - /** - * Main action buttons - */ - // action button panel - JPanel buttonsPanel = new JPanel(); - buttonsPanel.setLayout(new BorderLayout(0, 0)); - buttonsPanel.setBorder(defaultBorder); - button = new JButton("Start"); - //Set a preferred size so it doesn't change if we change its label - button.setPreferredSize(new Dimension(100,25)); - buttonsPanel.add(button, BorderLayout.CENTER); - //React when button is pressed - button.addActionListener(this); - - //the top row panel - JPanel topRowPanel = new JPanel(); - topRowPanel.setLayout(new BorderLayout(defaultGap, 0)); - topRowPanel.add(loopingPanel, BorderLayout.CENTER); - topRowPanel.add(buttonsPanel, BorderLayout.EAST); - - - - /** - * Logging panel - */ - // the logging panel at the bottom - JPanel logPanel = new JPanel(); - logPanel.setLayout(new BorderLayout(0, 0)); - logPanel.setBorder(defaultBorder); - //Add a logpane to it - log = new ALogPane(); - log.setEnabled(true); - log.setBorder(BorderFactory.createLineBorder(Color.black)); - log.setRequestFocusEnabled(false); - log.setPreferredSize(new Dimension(350, 200)); - logPanel.add(log, BorderLayout.CENTER); - - - // main panel - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BorderLayout(0, 0)); - // logPanel must be CENTER to be resisable vertically (otherwise, - // it keeps its size), hence upper part must be extra panel for - // NORTH position to accommodate topRowPanel and loopingPanel - JPanel upperMainPanel = new JPanel(); - upperMainPanel.setLayout(new BorderLayout(0, 0)); - upperMainPanel.add(topRowPanel, BorderLayout.NORTH); - mainPanel.add(upperMainPanel, BorderLayout.NORTH); - mainPanel.add(logPanel, BorderLayout.CENTER); - - // Finally add this MainPanel - getContentPane().add(mainPanel, BorderLayout.CENTER); - - //arrange all GUI items - pack(); - - //Set location to top left GUI corner so it does not hide Canvas - setLocation(globals.getGuiFrame().getLocation()); - - //give it a nice icon when minimized - AIcon.setIconImage(this); - - - /** - * end of dialog design, set listeners and handlers - */ //add ourselfs as state listeners to catch closing - addWindowListener(this); - - //also set ourselfs as action handler for the timer - timer.addActionListener(this); - //And have the timer start immediately on the first event - timer.setInitialDelay(0); - - - - } // createGUI() -------------------------------------------------------- - - /** - * State change events are only generated by the updateIntervalSpinner - * @param e the Change event - */ - public void stateChanged(ChangeEvent e) { - //Set timer delay to new value - timer.setDelay((Integer)updateIntervalSpinner.getValue()*1000); - } - - /** - * Stop event loop when closing the window - * @param e the Window event - */ - public void windowClosing(WindowEvent e){ - - //Make sure the timer is not running anymore - if (timer.isRunning()) stopEventLoop(); - - } // closeActionsAndDispose() ------------------------------------------ - - /** - * Small helper to print a message with timestamp to the log - * @param msg the message - */ - private void timeStampedLog(String msg){ - - //Record the time of the incident - SimpleDateFormat dateForm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - log.append("\n"+dateForm.format(new Date())+" ",ALogInterface.NORMAL_BOLD); - log.append(msg); - } - - - /** - * Try to read the next event from the server, handle all exceptions - */ - private void getNextEvent() { - - //try reading the next event - try{ - //tell the user - timeStampedLog("Reading next event..."); - //Then get next event - AEventManager.instance().nextEvent(); - } catch (NoMoreEventsException ex) { - //Just wait for next event - log.append("\n -- No next event available"); - logger.info("No next event available:\n"+ex.getCauseMessages()); - } catch (InvalidEventSourceException ex) { - //Do not break loop on invalid event source -- good for ACR - log.append("\n -- Invalid event source"); - logger.warn("Invalid event source:\n"+ex.getCauseMessages()); - } catch (ReadEventException ex) { - //Don't break loop on invalid events - log.append("\n -- Received invalid event"); - logger.warn("Received invalid event:\n"+ex.getCauseMessages()); - } - } - - /** - * Stop the event loop, reenabling all GUI elements - */ - private void stopEventLoop(){ - - //Stop the timer loop - timer.stop(); - - //Reset button label and states - button.setText("Start"); - updateIntervalSpinner.setEnabled(true); - - //tell the user - timeStampedLog("Stopped event loop..."); - } - - /** - * Start the event loop, disable all GUI elements - is public to facilitate - * automated start of event loop (e.g with command-line options) - */ - public void startEventLoop(){ - - //tell the user - timeStampedLog("Starting event loop..."); - - //enable/disable buttons - updateIntervalSpinner.setEnabled(false); - button.setText("Stop"); - - //Stop the timer loop - timer.start(); - - } - - /** - * Called every time the button is hit or we get a callback from the timer - * @param e the action event - */ - public void actionPerformed(ActionEvent e) { - - //Check if we got called from the timer loop - if (e.getSource() == timer){ - //If so just read next event and return - getNextEvent(); - return; - } - - //Being called because button was hit. - //Check if event loop is running - stop it - if (timer.isRunning()) { - stopEventLoop(); - } else { - startEventLoop(); - } - } - - - /** - * Show the dialog - */ - public void showDialog() { - - // clear the iconified bit (no matter whether or not it is iconified) - setExtendedState(getExtendedState() & ~Frame.ICONIFIED); - setVisible(true); - - } // show() ---------------------------------------------------- - - - /** - * Empty default implementation of WindowListeners - * @param e - */ - public void windowOpened(WindowEvent e) {} - public void windowClosed(WindowEvent e) {} - public void windowIconified(WindowEvent e) {} - public void windowDeiconified(WindowEvent e) {} - public void windowActivated(WindowEvent e) {} - public void windowDeactivated(WindowEvent e) {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AEventPropertiesDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AEventPropertiesDialog.java deleted file mode 100755 index 8b7a7a33278..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AEventPropertiesDialog.java +++ /dev/null @@ -1,721 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.Font; -import java.awt.Frame; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.util.List; -import java.util.Vector; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.JTable; -import javax.swing.JScrollPane; - -import com.Ostermiller.util.CSVParser; - -import atlantis.data.ACalorimeterData; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.data.ALVL1ResultData; -import atlantis.event.ANewEventListener; -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.graphics.layout.AFlowLayout; -import atlantis.data.ATriggerInfoData; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; - -/** - * The dialog which is used to display the current event properties. - */ -public class AEventPropertiesDialog extends JFrame implements ANewEventListener -{ - private static ALogger logger = ALogger.getLogger(AEventPropertiesDialog.class); - private static AEventManager eventManager = AEventManager.instance(); - - private JTable table, propertiesTable, level1Table, level2Table, - eventFilterTable, trigInfoItemsTable, trigInfoStreamTable, - userSelectedTable, mbtsTable; - private JPanel buttonsPanel; - private JTabbedPane tabbedPane; - private JButton okButton; - private JButton refreshButton; - private static AEventPropertiesDialog instance = null; - protected static String[] USER_ITEMS = null; - private static final String LOOKUP_FILENAME = "epusti.csv"; - private static final AGlobals globals = AGlobals.instance(); - private static final String LOOKUP_FILE = - globals.getHomeDirectory() + "configuration" + - System.getProperty("file.separator") + - LOOKUP_FILENAME; - - public static boolean isInUse() - { - if(instance ==null || !instance.isVisible()) - return false; - else - return true; - } - - public static AEventPropertiesDialog getInstance() - { - if (instance == null) - instance = new AEventPropertiesDialog(); - return instance; - } - - public AEventPropertiesDialog() - { - Frame gui = globals.getGuiFrame(); - eventManager.addNewEventListener(this); - this.setTitle("Event Properties Dialog"); - AIcon.setIconImage(this); - // setResizable(false); - - // From Java 1.5 we can tell the window to be always on top - this.setAlwaysOnTop(true); - - // check whether there is any event data are present - if (eventManager.getCurrentEvent() == null) - { - JOptionPane.showMessageDialog(gui, - "Current event is null\n" + "(no event data currently present)", - "Event null", JOptionPane.WARNING_MESSAGE); - return; - } - - try - { - readFromLookupFile(); - } - catch(AAtlantisException ex) - { - logger.warn(": reading " + LOOKUP_FILE + - " failed, user trigger items will not " + - "be available, reason: " + ex.getMessage(), ex); - } - - fillTabbedPane(0); - addButtonPane(); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - pack(); - - // set the initial location - int guiWidth = gui.getWidth(); - int guiHeight = gui.getHeight(); - int guiX = gui.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit() - .getScreenSize().getWidth()); - if (guiX + guiWidth + (dialogWidth - guiWidth) / 2 > screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max( - 0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), - Math.max(0, (guiHeight - dialogHeight) / 3)); - - setVisible(true); - } - - private void readFromLookupFile() throws AAtlantisException - { - if(USER_ITEMS==null) - { - try - { - InputStream is = AUtilities.getFileAsStream(LOOKUP_FILE); - CSVParser parser = new CSVParser(is); - parser.setCommentStart("#"); - String valueArray = parser.nextValue(); // shall now contain all values - CSVParser parserArray = new CSVParser(new StringReader(valueArray)); - String[][] s = parserArray.getAllValues(); - if(s!=null) - { - USER_ITEMS = s[0]; - } - } - catch (IOException e) - { - throw new AAtlantisException("exception while reading file: " + - LOOKUP_FILE); - } - catch (AAtlantisException e) - { - throw e; - } - } - } - - - public void dispose() - { - instance = null; - super.dispose(); - } - - public void updatePane() - { - - JTabbedPane currentTabbedPane = (JTabbedPane) getContentPane().getComponent(0); - int currentIndex = currentTabbedPane.getSelectedIndex(); - getContentPane().removeAll(); - validate(); - - fillTabbedPane(currentIndex); - addButtonPane(); - - pack(); - } - - private void addButtonPane() - { - okButton = new JButton("OK"); - okButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - dispose(); - } - }); - - // Add button to refresh data after cuts have been applied - refreshButton = new JButton("Refresh Cuts"); - refreshButton.setToolTipText("Display data passing cuts for active window"); - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - updatePane(); - } - }); - - buttonsPanel = new JPanel(new AFlowLayout(10, 5)); - buttonsPanel.add(okButton); - buttonsPanel.add(refreshButton); - getContentPane().add(buttonsPanel, BorderLayout.SOUTH); - - - - } - - /** fills the tabbed pane with the event information - * @param index the currently selected index - */ - private void fillTabbedPane(int index) - { - fillTablePane(); - AEvent event = eventManager.getCurrentEvent(); - - //now need to loop over the lvl1result collections - Vector<String> keys = event.getCollections().get("LVL1Result"); - ALVL1ResultData lvl1ResultData[]=null; - if(keys!=null){ - lvl1ResultData = new ALVL1ResultData[keys.size()]; - for(int i=0; i<keys.size();i++) - { - String colLvl1= "LVL1Result" + (String)keys.elementAt(i); - lvl1ResultData[i] = (ALVL1ResultData) event.get(colLvl1); - } - } - - ATriggerInfoData triggerInfoData = event.getTriggerInfoData(); - fillPropertiesPane(lvl1ResultData, triggerInfoData); - String[][] L1_items = fillLevel1Pane(lvl1ResultData); - String[][] L2_items = fillLevel2Pane(lvl1ResultData); - String[][] EF_items = fillEventFilterPane(lvl1ResultData); - fillTrigInfoItemsPane(triggerInfoData); - fillTrigInfoStreamPane(triggerInfoData); - fillUserSelectedPane(L1_items, L2_items, EF_items); - fillmbtsPane(); - - tabbedPane = new JTabbedPane(); - tabbedPane.addTab("Number of Hits", new JScrollPane(table)); - tabbedPane.addTab("Properties", new JScrollPane(propertiesTable)); - tabbedPane.addTab("Level 1 Trigger Items", new JScrollPane(level1Table)); - tabbedPane.addTab("Level 2 Trigger Items", new JScrollPane(level2Table)); - tabbedPane.addTab("Event Filter Trigger Items", new JScrollPane(eventFilterTable)); - tabbedPane.addTab("Trigger Info Items", new JScrollPane(trigInfoItemsTable)); - tabbedPane.addTab("Trigger Info Stream Tag", new JScrollPane(trigInfoStreamTable)); - tabbedPane.addTab("User Selected Trigger Items", new JScrollPane(userSelectedTable)); - tabbedPane.addTab("All MBTS cell details", new JScrollPane(mbtsTable)); - tabbedPane.setSelectedIndex(index); - - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(tabbedPane, BorderLayout.CENTER); - } - - private void fillTablePane() - { - // For total data and data passing cuts, use .getInfoDraw() - // for total event data, use getInfo() - table = new JTable(eventManager.getCurrentEvent().getInfoDraw(), - new String[] { "detector / datatype", "data items", "passing cuts" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - table.setRowHeight(20); - table.setFont(new Font("Monospaced", Font.PLAIN, 16)); - table.getColumnModel().getColumn(0).setPreferredWidth(350); - table.getColumnModel().getColumn(1).setPreferredWidth(100); - table.getColumnModel().getColumn(2).setPreferredWidth(100); - } - - private void fillPropertiesPane(ALVL1ResultData lvl1ResultData[], ATriggerInfoData triggerInfoData) - { - double et = 0; - List<ACalorimeterData> calo = eventManager.getCurrentEvent().getCalorimeters(); - - for (int i = 0; i < calo.size(); i++) - et += calo.get(i).getTotalTransverseEnergy(); - - String[][] properties; - - if (lvl1ResultData == null) - { - if(triggerInfoData==null) - { - properties = new String[2][2]; - properties[1][0] = "Trigger Decision"; - properties[1][1] = "N/A"; - } - else - { - properties = new String[7][2]; - properties[1][0] = "Trigger Decision"; - properties[1][1] = "N/A"; - properties[2][0] = "Trigger Info: Level 1 EtMiss"; - properties[2][1] = String.valueOf(triggerInfoData.getEnergyEtMiss(0)); - properties[3][0] = "Trigger Info: Level 1 SumEt"; - properties[3][1] = String.valueOf(triggerInfoData.getEnergyEtMiss(0)); - properties[4][0] = "Trigger Info: ExtL1ID"; - properties[4][1] = triggerInfoData.getTrigInfoExtL1ID(0); - properties[5][0] = "Trigger Info: Lvl1Type"; - properties[5][1] = triggerInfoData.getTrigInfoLvl1Type(0); - properties[6][0] = "Trigger Info: Status"; - properties[6][1] = triggerInfoData.getTrigInfoStatus(0); - - } - } - else - { - properties = new String[5*lvl1ResultData.length+6][2]; - - //output the trigger info: - properties[1][0] = "Trigger Info: Level 1 EtMiss"; - properties[2][0] = "Trigger Info: Level 1 SumEt"; - properties[3][0] = "Trigger Info: ExtL1ID"; - properties[4][0] = "Trigger Info: Lvl1Type"; - properties[5][0] = "Trigger Info: Status"; - - if(triggerInfoData!=null) - { - properties[1][1] = String.valueOf(triggerInfoData.getEnergyEtMiss(0)); - properties[2][1] = String.valueOf(triggerInfoData.getEnergySumEt(0)); - properties[3][1] = triggerInfoData.getTrigInfoExtL1ID(0); - properties[4][1] = triggerInfoData.getTrigInfoLvl1Type(0); - properties[5][1] = triggerInfoData.getTrigInfoStatus(0); - }else{ - properties[1][1] = "N/A"; - properties[2][1] = "N/A"; - properties[3][1] = "N/A"; - properties[4][1] = "N/A"; - properties[5][1] = "N/A"; - } - - for(int j=0; j<lvl1ResultData.length;j++){ - int ref=j*5;//reference to allow >1 collection in the list - String name=lvl1ResultData[j].getStoreGateKey(); - - properties[6+ref][0] = name + ": Level 1 result"; - properties[7+ref][0] = name + ": Level 2 result"; - properties[8+ref][0] = name + ": Event Filter result"; - properties[9+ref][0] = name + ": Level 1 EtMiss"; - properties[10+ref][0] = name + ": Level 1 SumEt"; - - int[] temp=new int[3]; - temp[0]=lvl1ResultData[j].getPassedL1(0); - temp[1]=lvl1ResultData[j].getPassedL2(0); - temp[2]=lvl1ResultData[j].getPassedEF(0); - for(int i=0;i<3;i++) - { - switch(temp[i]) - { - case -1: - properties[i+6+ref][1]="N/C"; - break; - case 0: - properties[i+6+ref][1]="failed"; - break; - case 1: - properties[i+6+ref][1]="passed"; - break; - default: - properties[i+6+ref][1]="N/A"; - } - } - float LVL1EtMiss=lvl1ResultData[j].getEnergyEtMiss(0); - float LVL1SumEt=lvl1ResultData[j].getEnergySumEt(0); - if(LVL1EtMiss>0) - properties[9+ref][1] = String.valueOf(LVL1EtMiss); - else - properties[9+ref][1] = "N/A"; - if(LVL1SumEt>0) - properties[10+ref][1] = String.valueOf(LVL1SumEt); - else - properties[10+ref][1] = "N/A"; - } - } - - //first item always Transv. Energy - properties[0][0] = "Transv. Energy (GeV)"; - properties[0][1] = String.format("%.2f",et); - - propertiesTable = new JTable(properties, new String[] { "Name", "Value" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - propertiesTable.setRowHeight(20); - propertiesTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - propertiesTable.getColumnModel().getColumn(0).setPreferredWidth(350); - propertiesTable.getColumnModel().getColumn(1).setPreferredWidth(100); - } - - private String[][] fillLevel1Pane(ALVL1ResultData lvl1ResultData[]) - { - String[][] properties; - - if (lvl1ResultData == null) - { - properties = new String[1][2]; - properties[0][0] = "N/A"; - properties[0][1] = "N/A"; - } - else - { - String[][] items=new String[lvl1ResultData.length][]; - String[][] prescales=new String[lvl1ResultData.length][]; - int numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - items[j]=lvl1ResultData[j].getCtpItemListSplit(0,false); - prescales[j]=lvl1ResultData[j].getPrescaleListL1Split(0); - numItems+=items[j].length; - } - properties = new String[numItems][2]; - numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - String name=lvl1ResultData[j].getStoreGateKey(); - for(int i=0; i<items[j].length; i++) - { - properties[numItems][0]= name + ": " + items[j][i]; - properties[numItems][1]=(prescales[j] != null && i<prescales[j].length) ? prescales[j][i]: "N/A"; - numItems++; - } - } - } - level1Table = new JTable(properties, new String[] { "Item passed", "Prescale"}) { - public boolean isCellEditable(int row, int column) { return false; } - }; - level1Table.setRowHeight(20); - level1Table.setFont(new Font("Monospaced", Font.PLAIN, 16)); - level1Table.getColumnModel().getColumn(0).setPreferredWidth(350); - level1Table.getColumnModel().getColumn(1).setPreferredWidth(100); - - return properties; - } - - private String[][] fillLevel2Pane(ALVL1ResultData lvl1ResultData[]) - { - String[][] properties; - - if (lvl1ResultData == null) - { - properties = new String[1][2]; - properties[0][0] = "N/A"; - properties[0][1] = "N/A"; - } - else - { - String[][] items=new String[lvl1ResultData.length][]; - String[][] prescales=new String[lvl1ResultData.length][]; - int numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - items[j]=lvl1ResultData[j].getitemListL2Split(0,false); - prescales[j]=lvl1ResultData[j].getPrescaleListL2Split(0); - numItems+=items[j].length; - } - properties = new String[numItems][2]; - numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - String name=lvl1ResultData[j].getStoreGateKey(); - for(int i=0; i<items[j].length; i++) - { - properties[numItems][0]= name + ": " + items[j][i]; - properties[numItems][1]=(prescales[j] != null && i<prescales[j].length) ? prescales[j][i]: "N/A"; - numItems++; - } - } - } - level2Table = new JTable(properties, new String[] { "Item passed", "Prescale" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - level2Table.setRowHeight(20); - level2Table.setFont(new Font("Monospaced", Font.PLAIN, 16)); - level2Table.getColumnModel().getColumn(0).setPreferredWidth(350); - level2Table.getColumnModel().getColumn(1).setPreferredWidth(100); - - return properties; - } - - private String[][] fillEventFilterPane(ALVL1ResultData lvl1ResultData[]) - { - String[][] properties; - - if (lvl1ResultData == null) - { - properties = new String[1][2]; - properties[0][0] = "N/A"; - properties[0][1] = "N/A"; - } - else - { - String[][] items=new String[lvl1ResultData.length][]; - String[][] prescales=new String[lvl1ResultData.length][]; - int numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - items[j]=lvl1ResultData[j].getitemListEFSplit(0,false); - prescales[j]=lvl1ResultData[j].getPrescaleListEFSplit(0); - numItems+=items[j].length; - } - properties = new String[numItems][2]; - numItems=0; - for(int j=0; j<lvl1ResultData.length;j++){ - String name=lvl1ResultData[j].getStoreGateKey(); - for(int i=0; i<items[j].length; i++) - { - properties[numItems][0]= name + ": " + items[j][i]; - properties[numItems][1]=(prescales[j] != null && i<prescales[j].length) ? prescales[j][i]: "N/A"; - numItems++; - } - } - } - eventFilterTable = new JTable(properties, new String[] { "Item passed", "Prescale" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - eventFilterTable.setDefaultEditor(String.class, null); - eventFilterTable.setRowHeight(20); - eventFilterTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - eventFilterTable.getColumnModel().getColumn(0).setPreferredWidth(350); - eventFilterTable.getColumnModel().getColumn(1).setPreferredWidth(100); - - return properties; - } - - private void fillTrigInfoItemsPane(ATriggerInfoData triggerInfoData) - { - String[][] properties; - - if (triggerInfoData == null) - { - properties = new String[1][3]; - properties[0][0] = "N/A"; - properties[0][1] = "N/A"; - properties[0][2] = "N/A"; - } - else - { - String[] itemsL1=triggerInfoData.getTrigInfoL1SplitHex(0); - String[] itemsL2=triggerInfoData.getTrigInfoL2SplitHex(0); - String[] itemsEF=triggerInfoData.getTrigInfoEFSplitHex(0); - //find list with largest amount of items - int items = Math.max(Math.max(itemsL1.length, itemsL2.length),itemsEF.length); - properties = new String[items][3]; - for(int i=0; i<items; i++) - { - properties[i][0]= (i<itemsL1.length) ? itemsL1[i] : ""; - properties[i][1]= (i<itemsL2.length) ? itemsL2[i] : ""; - properties[i][2]= (i<itemsEF.length) ? itemsEF[i] : ""; - } - } - trigInfoItemsTable = new JTable(properties, new String[] { "L1", "L2", "EF" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - trigInfoItemsTable.setRowHeight(20); - trigInfoItemsTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - trigInfoItemsTable.getColumnModel().getColumn(0).setPreferredWidth(100); - trigInfoItemsTable.getColumnModel().getColumn(1).setPreferredWidth(100); - trigInfoItemsTable.getColumnModel().getColumn(1).setPreferredWidth(100); - - } - - private void fillTrigInfoStreamPane(ATriggerInfoData triggerInfoData) - { - String[][] properties; - - if (triggerInfoData == null) - { - properties = new String[1][1]; - properties[0][0] = "N/A"; - } - else - { - String[] items=triggerInfoData.getTrigInfoStreamTagSplit(0); - properties = new String[items.length][1]; - for(int i=0; i<items.length; i++) - { - properties[i][0]=items[i]; - } - } - trigInfoStreamTable = new JTable(properties, new String[] { "Stream Tag"}) { - public boolean isCellEditable(int row, int column) { return false; } - }; - trigInfoStreamTable.setRowHeight(20); - trigInfoStreamTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - trigInfoStreamTable.getColumnModel().getColumn(0).setPreferredWidth(450); - } - - private void fillUserSelectedPane(String[][] L1_items, String[][] L2_items, String[][] EF_items) - { - String[][] properties; - if (USER_ITEMS==null) - { - properties = new String[1][2]; - properties[0][0] = "Please add items to: " + LOOKUP_FILENAME; - properties[0][1] = "N/A"; - } - else - { - Vector<String> v_c1 = new Vector<String>();//column 1 - item - Vector<String> v_c2 = new Vector<String>();//column 2 - prescales - Vector<String> v_u = new Vector<String>();//user items - for(int i=0; i<USER_ITEMS.length; i++) - { - v_u.add(USER_ITEMS[i]); - } - //loop over L1 items - for(int j=0; j<L1_items.length; j++) - { - for(int i=0; i<v_u.size(); i++) - { - if(v_u.elementAt(i).equals(L1_items[j][0])) - { - v_c1.add(L1_items[j][0]); - v_c2.add(L1_items[j][1]); - v_u.remove(i); - } - } - } - //if still have user items left loop over L2 - if(v_u.size()>0) - { - for(int j=0; j<L2_items.length; j++) - { - for(int i=0; i<v_u.size(); i++) - { - if(v_u.elementAt(i).equals(L2_items[j][0])) - { - v_c1.add(L2_items[j][0]); - v_c2.add(L2_items[j][1]); - v_u.remove(i); - } - } - } - } - //if still have user items left loop over EF - if(v_u.size()>0) - { - for(int j=0; j<EF_items.length; j++) - { - for(int i=0; i<v_u.size(); i++) - { - if(v_u.elementAt(i).equals(EF_items[j][0])) - { - v_c1.add(EF_items[j][0]); - v_c2.add(EF_items[j][1]); - v_u.remove(i); - } - } - } - } - //now store items in String[][] - properties = new String[v_c1.size()][2]; - for(int i=0; i<v_c1.size(); i++) - { - properties[i][0]=v_c1.elementAt(i).toString(); - properties[i][1]=v_c2.elementAt(i).toString(); - } - } - userSelectedTable = new JTable(properties, new String[] { "Item passed", "Prescale" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - userSelectedTable.setRowHeight(20); - userSelectedTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - userSelectedTable.getColumnModel().getColumn(0).setPreferredWidth(350); - userSelectedTable.getColumnModel().getColumn(1).setPreferredWidth(100); - } - - private void fillmbtsPane() - { - ACalorimeterData calorimeter=null; - List<ACalorimeterData> detectors = eventManager.getCurrentEvent().getCalorimeters(); - for (int det = 0; det < detectors.size(); det++) - { - ACalorimeterData testcalorimeter = detectors.get(det); - if (!testcalorimeter.getName().equals("MBTS")) continue; - if(testcalorimeter.getNumData()>0) calorimeter=testcalorimeter; - } - - - String[][] properties; - if (calorimeter==null) - { - properties = new String[1][5]; - properties[0][0] = "N/A"; - properties[0][1] = "N/A"; - properties[0][2] = "N/A"; - properties[0][3] = "N/A"; - properties[0][4] = "N/A"; - } - else - { - properties = new String[calorimeter.getNumData()][5]; - //AMBTSData mbtsdata = calorimeter.eta[i]; - for (int i = 0; i < calorimeter.getNumData(); ++i) - { - properties[i][0] = "" + i; - properties[i][1] = "" + String.format("%.3f",(calorimeter.getET(i))); - properties[i][2] = "" + String.format("%.1f",calorimeter.getEta(i)); - properties[i][3] = "" + String.format("%.1f",calorimeter.getPhi(i)); - properties[i][4] = "" + calorimeter.getSampling(i); - } - } - mbtsTable = new JTable(properties, new String[] { "Index", "Energy (MeV)", "Type", "Module", "Channel" }) { - public boolean isCellEditable(int row, int column) { return false; } - }; - mbtsTable.setRowHeight(20); - mbtsTable.setFont(new Font("Monospaced", Font.PLAIN, 16)); - mbtsTable.getColumnModel().getColumn(0).setPreferredWidth(90); - mbtsTable.getColumnModel().getColumn(1).setPreferredWidth(90); - mbtsTable.getColumnModel().getColumn(2).setPreferredWidth(90); - mbtsTable.getColumnModel().getColumn(3).setPreferredWidth(90); - mbtsTable.getColumnModel().getColumn(4).setPreferredWidth(90); - } - - /** - * Implementing NewEvent listener - * @param event the new event - */ - public void newEvent(AEvent event) { - if (isInUse()) updatePane(); - } - - - - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AEventQueue.java b/graphics/AtlantisJava/src/atlantis/gui/AEventQueue.java deleted file mode 100755 index 081e214dd29..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AEventQueue.java +++ /dev/null @@ -1,165 +0,0 @@ -package atlantis.gui; - -import java.awt.EventQueue; -import java.awt.AWTEvent; -import java.awt.Frame; -import java.awt.event.KeyEvent; -import atlantis.parameters.APar; -import atlantis.canvas.ACanvas; -import atlantis.data.AG4StepData; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.interactions.AModifier; -import javax.swing.JOptionPane; -import atlantis.utils.ALogger; - -/** - * Because we use Mouse Actions and Keyboard Modifiers (letters) we need a way of - * getting all the keyboard events independent of the focussed compenent. This is - * done by catching them directly from the Event Queue. So, we just replace the - * default Java Queue by this one. - */ -public class AEventQueue extends EventQueue { - - /** - * Contains the code of the key (is some key is pressed) - * or KeyEvent.VK_UNDEFINED if no key is holded down. - */ - private static int keyboardState; - private static AModifier defInt = new AModifier(KeyEvent.VK_UNDEFINED, false, ""); - - private KeyEvent keyEvent; - - private final static ALogger logger = ALogger.getLogger(AEventQueue.class); - private static AEventManager eventManager = AEventManager.instance(); - - private static boolean isRightMouseButton; - - protected static APar parameterStore = APar.instance(); - - private static final AGlobals globals = AGlobals.instance(); - - public static int getKeyboardState() { - int ret = 0; - - if (keyboardState == KeyEvent.VK_UNDEFINED) { - ret = defInt.getKeyCode(); - } else { - ret = keyboardState; - } - - // Bit of a hack because fastzoom is handled differently from other - // interactions - if (ret == KeyEvent.VK_F) { - parameterStore.get("Projection", "SkipData").setStatus(true); - } else { - parameterStore.get("Projection", "SkipData").setStatus(false); - } - - return ret; - } - - public static AModifier getDefault() { - return defInt; - } - - public static void setDefault(AModifier mod) { - defInt = mod; - - } - - public static int getKeyboardDefault() { - return defInt.getKeyCode(); - } - - public static boolean getIntRightMouseButton() { - if (keyboardState == KeyEvent.VK_UNDEFINED) { - // Non-default action selected, use the right click option from it - return defInt.getRightClick() || isRightMouseButton; - } else { - return isRightMouseButton; - } - } - - // FIXME: isRightMouseButton sometimes has spurious true value: see Trac #488 - protected void dispatchEvent(AWTEvent event) { - Frame gui = globals.getGuiFrame(); - super.dispatchEvent(event); - - if(event instanceof KeyEvent) { - keyEvent=(KeyEvent)event; -// this is the right mouse click on single mouse button mac's - switch(keyEvent.getID()) { - case KeyEvent.KEY_PRESSED: - if(keyEvent.getKeyCode()==17) { - isRightMouseButton=true; - return; - } - keyboardState=keyEvent.getKeyCode(); - //atlantis.utils.AOutput.append(" key pressed :" + keyboardState + ":\n", atlantis.utils.ALogPane.NORMAL_BOLD); - - if (keyEvent.getKeyCode()==33){//page up - System.out.println("Go to previous event"); - try { - eventManager.previousEvent(); - } catch (NoMoreEventsException nme) { - String msg = "Already at first event from this source!"; - JOptionPane.showMessageDialog(gui, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies) { - String msg = "Not a valid event source - please select one!"; - JOptionPane.showMessageDialog(gui, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree) { - String msg = "Can not read event(s)!"; - JOptionPane.showMessageDialog(gui, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } - if (keyEvent.getKeyCode()==34) {//page down - System.out.println("Go to next event"); - try { - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "Already at last event from this source!"; - JOptionPane.showMessageDialog(gui, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies) { - String msg = "Not a valid event source - please select one!"; - JOptionPane.showMessageDialog(gui, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree) { - String msg = "Can not read event(s)!"; - JOptionPane.showMessageDialog(gui, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } - - if (keyEvent.getKeyCode()==47) {// "/" - AG4StepData.ReadG4Steps(); - }//key "/" - - if (keyEvent.getKeyCode() == KeyEvent.VK_F) { - parameterStore.get("Projection", "SkipData").setStatus(true); - } - break; - - case KeyEvent.KEY_RELEASED: - if (keyEvent.getKeyCode() == 17) { - isRightMouseButton = false; - return; - } - keyboardState = KeyEvent.VK_UNDEFINED; - if (keyEvent.getKeyCode() == KeyEvent.VK_F) { - parameterStore.get("Projection", "SkipData").setStatus(false); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - break; - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AEventSourceToolBar.java b/graphics/AtlantisJava/src/atlantis/gui/AEventSourceToolBar.java deleted file mode 100644 index 8f5534a6dd5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AEventSourceToolBar.java +++ /dev/null @@ -1,523 +0,0 @@ - -package atlantis.gui; - -import atlantis.config.ADefaultValues; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource; -import atlantis.event.ANewEventSourceListener; -import atlantis.event.AURLEventSource; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NavigationMode; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.event.AStreamedEventSource; -import atlantis.event.AStreamedEventSource.InvalidStreamException; -import atlantis.globals.AGlobals; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Vector; -import javax.swing.Box; -import javax.swing.ButtonGroup; -import javax.swing.DefaultComboBoxModel; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.JRadioButton; -import javax.swing.JTextField; -import javax.swing.JToolBar; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; - -/** - * This toolbar contains all the elements to set a new event source or stream, - * browse through the events or set the event navigation mode - * @author maillard - * @author sboeser - */ -class AEventSourceToolBar extends JToolBar implements ANewEventSourceListener { - - /** The text field that allows us to enter a new event source */ - private JTextField addressBar; - - /** The event stream selection combo box */ - private JComboBox eventStreamComboBox; - - /** The radio buttons that allow to select the event navigation mode */ - private JRadioButton randomButton, sequentialButton, loopButton; - - /** The logger */ - private final static ALogger logger = ALogger.getLogger(AEventSourceToolBar.class); - - private static AEventManager eventManager = AEventManager.instance(); - - /** Spacing between components in the toolbar */ - private static int SPACE = 4; - - /** - * Constructor - */ - public AEventSourceToolBar() { - - //call parent constructor - super(); - - setFloatable(false); - - //Get the path to the icon files - String iconPath = AGlobals.instance().getHomeDirectory()+"img"+System.getProperty("file.separator"); - - // setting up the 'open file' button - ImageIcon openIcon = AUtilities.getFileAsImageIcon(iconPath+"toolbar_open.png"); - JButton openFile = new JButton(openIcon); - openFile.setVerticalTextPosition(JButton.BOTTOM); - openFile.setHorizontalTextPosition(JButton.CENTER); - openFile.setMargin(new Insets(2, 2, 2, 2)); - openFile.setToolTipText("Open local file"); - // And add an action listener for it - openFile.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - openFileButtonAction(); - } - }); - // adding the open file button to the toolbar - - add(Box.createHorizontalStrut(SPACE)); - add(openFile); - add(Box.createHorizontalStrut(SPACE)); - - // setting up the address bar - addressBar = new JTextField(30); - // and an action listener - addressBar.addActionListener( new ActionListener() { - public void actionPerformed(ActionEvent e) { - addressBarAction((JTextField)e.getSource()); - } - }); - // adding the address bar to the toolbar - add(addressBar); - - //Set up previous and next buttons - ImageIcon nextIcon = AUtilities.getFileAsImageIcon(iconPath+"toolbar_next.png"); - ImageIcon previousIcon = AUtilities.getFileAsImageIcon(iconPath+"toolbar_previous.png"); - - JButton nextButton = new JButton(nextIcon); - JButton previousButton = new JButton(previousIcon); - - //customize and add action listener for next - nextButton.setName("nextButton"); - nextButton.setVerticalTextPosition(JButton.BOTTOM); - nextButton.setHorizontalTextPosition(JButton.CENTER); - nextButton.setMargin(new Insets(2, 2, 2, 2)); - nextButton.setToolTipText("Next event (PageDown)"); - nextButton.addActionListener(new ActionListener(){ - public void actionPerformed(ActionEvent e){ - nextButtonAction(); - } - }); - - //customize and add action listener for previous - previousButton.setName("previousButton"); - previousButton.setVerticalTextPosition(JButton.BOTTOM); - previousButton.setHorizontalTextPosition(JButton.CENTER); - previousButton.setMargin(new Insets(2, 2, 2, 2)); - previousButton.setToolTipText("Previous event (PageUp)"); - previousButton.addActionListener(new ActionListener(){ - public void actionPerformed(ActionEvent e){ - previousButtonAction(); - } - }); - //Add both to toolbar - add(Box.createHorizontalStrut(SPACE)); - add(previousButton); - add(nextButton); - add(Box.createHorizontalStrut(SPACE)); - - //Next add a seperator - addSeparator(); - - //Add a combo box, but set it to invisble - String[] streamNames = { "--n/a--" }; - eventStreamComboBox = new JComboBox(streamNames); - eventStreamComboBox.setVisible(false); - add(eventStreamComboBox); - - // set up the navigation mode button icons - ImageIcon sequentialIcon = AUtilities.getFileAsImageIcon(iconPath+"mode_sequential.png"); - ImageIcon loopIcon = AUtilities.getFileAsImageIcon(iconPath+"mode_loop.png"); - ImageIcon randomIcon = AUtilities.getFileAsImageIcon(iconPath+"mode_random.png"); - ImageIcon sequentialIconOn = AUtilities.getFileAsImageIcon(iconPath+"mode_sequential_on.png"); - ImageIcon loopIconOn = AUtilities.getFileAsImageIcon(iconPath+"mode_loop_on.png"); - ImageIcon randomIconOn = AUtilities.getFileAsImageIcon(iconPath+"mode_random_on.png"); - - //put these buttons in a group - ButtonGroup group = new ButtonGroup(); - // sequential mode - sequentialButton = new JRadioButton(sequentialIcon); - sequentialButton.setOpaque(false); - sequentialButton.setSelectedIcon(sequentialIconOn); - sequentialButton.setToolTipText("Sequential mode"); - sequentialButton.setName("Sequential mode"); - // loop mode - loopButton = new JRadioButton(loopIcon); - loopButton.setSelectedIcon(loopIconOn); - loopButton.setOpaque(false); - loopButton.setToolTipText("Loop mode"); - loopButton.setName("Loop mode"); - // random mode - randomButton = new JRadioButton(randomIcon); - randomButton.setOpaque(false); - randomButton.setSelectedIcon(randomIconOn); - randomButton.setToolTipText("Random mode"); - randomButton.setName("Random mode"); - // the mode buttons are initially disabled, since we - // don't know which event source will be loaded first - sequentialButton.setEnabled(false); - loopButton.setEnabled(false); - randomButton.setEnabled(false); - - // when one of the buttons is pressed, set the required display mode - sequentialButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - navigationModeAction(NavigationMode.SEQUENTIAL); - } - }); - - loopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - navigationModeAction(NavigationMode.LOOP); - } - }); - - randomButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - navigationModeAction(NavigationMode.RANDOM); - } - }); - //Add all buttons to the group - group.add(sequentialButton); - group.add(loopButton); - group.add(randomButton); - - add(sequentialButton); - add(loopButton); - add(randomButton); - } - - /** - * Called whenever the event text field changed - */ - private synchronized void addressBarAction(JTextField tf){ - - //Get the new text - String sourceName = tf.getText(); - - // if sourceName is a local path but doesn't provide an [type]://, - // prepend file:// as default - if(! sourceName.contains("://")) sourceName = "file://" + sourceName; - try { - eventManager.setEventSource(sourceName); - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - JOptionPane.showMessageDialog(this, "No more events found from this source!", "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies) { - JOptionPane.showMessageDialog(this, "Not a valid event source: "+sourceName, "Invalid event source", JOptionPane.ERROR_MESSAGE); - logger.error(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - JOptionPane.showMessageDialog(this, "Cannot read event(s).", "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } - - /** - * Called whenever the previous button is pressed - */ - private synchronized void previousButtonAction(){ - - try { - eventManager.previousEvent(); - } catch (NoMoreEventsException nme) { - String msg = "Already at first event from this source!"; - JOptionPane.showMessageDialog(this, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies ){ - String msg = "Not a valid event source - please select one!"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - String msg = "Can not read event(s)!"; - JOptionPane.showMessageDialog(this, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - refreshAddressBar(); - } - - /** - * Called whenever the next button is pressed - */ - private synchronized void nextButtonAction(){ - try { - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "Already at last event from this source!"; - JOptionPane.showMessageDialog(this, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies ){ - String msg = "Not a valid event source - please select one!"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - String msg = "Can not read event(s)!"; - JOptionPane.showMessageDialog(this, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - refreshAddressBar(); - } - - /** - * Update the address bar to show the current event source - */ - private synchronized void refreshAddressBar(){ - AEventSource source = eventManager.getEventSource(); - AEvent event = eventManager.getCurrentEvent(); - if (source != null && event != null) { - // if the source is a URL, we should always use '/' as the separator - // else we'll use the system file separator - if (source instanceof AURLEventSource) { - addressBar.setText(source.getSourceName() + "/" + event.getSourceName()); - } else { - addressBar.setText(source.getSourceName() + System.getProperty("file.separator") + event.getSourceName()); - } - } - } - - /** - * Open a file dialog and read the selected event or directory - */ - private synchronized void openFileButtonAction(){ - //get the last location from the default values - String lastLoc = ADefaultValues.get("LastEventFilesSourceDir"); - //Create a file chooser dialog - AReadFileChooser fileDialog = new AReadFileChooser(lastLoc); - //Check if the user pressed ok in the dialog - if ( fileDialog.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - //Get the selected file path, prepend file:// - String fullFilePath = "file://" + fileDialog.getSelectedFile().getPath(); - - try { - //Now set this as a new event source - eventManager.setEventSource(fullFilePath); - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "No events found from this source!"; - JOptionPane.showMessageDialog(this, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies ){ - String msg = "Not a valid event source"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - String msg = "Can not read event(s)"; - JOptionPane.showMessageDialog(this, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } // okay pressed - otherwise do nothing - } // openFileButtonAction() ---------------------------------------------------- - - /** - * Called whenever the navigation mode is changed in the GUI - */ - private synchronized void navigationModeAction( NavigationMode mode ){ - try { - eventManager.setNavigationMode(mode); } - catch (InvalidEventSourceException ies) { - JOptionPane.showMessageDialog(this, ies.getCauseMessages(), "Invalid navigation mode", JOptionPane.ERROR_MESSAGE); - } - } - - /** - * Called whenever the event stream is changed in the GUI - */ - private synchronized void selectedStreamAction(AStreamedEventSource source){ - - //Get the newly selected stream - String stream = (String) eventStreamComboBox.getSelectedItem(); - - try { - //Try to set a new stream - source.setStream(stream); - //Also get a new event - eventManager.nextEvent(); - //And update the event source field - refreshAddressBar(); - - } catch (NoMoreEventsException nme){ - //In case we already have the latest event from this stream - ignore - } catch (InvalidStreamException ise) { - //This can happen if the stream list changes inbetween - //opening the popup and selecting an item - String msg = "Cannot set stream '"+stream+"' for event source"; - JOptionPane.showMessageDialog(this, msg, "Invalid stream", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+ise.getCauseMessages()); - //Also clear the stream list - eventStreamComboBox.removeAllItems(); - } catch (InvalidEventSourceException ies) { - //This can happen if the source turned invalid inbetween - //opening the popup and selecting an item - String msg = "Invalid event source when setting new stream"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+ies.getCauseMessages()); - //Also clear the stream list - eventStreamComboBox.removeAllItems(); - } catch (ReadEventException ree){ - //Do nothing special with stream list in this case - String msg = "Can not read event from new stream '"+stream+"'"; - JOptionPane.showMessageDialog(this, msg, "Invalid event", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+ree.getCauseMessages()); - } - - } - - /** - * This is called whenever the event stream combo is poped up - * Use this to update the event list every time - */ - private synchronized void updateEventStreamCombo(AStreamedEventSource eventSource){ - /** - * NOTE: We are NOT using "removeAllItems" + "addItems" to update the - * combo box as this will always fire a new ActionEvent with the first - * added Item. The proper way to do is to change the data model, as the - * new data model will only fire AFTER the user selected from the open - * ComboBox. - */ - - //Create an empty list - Vector<String> streamNames = new Vector<String>(); - - try { - //Get the stream names - streamNames = eventSource.getAvailableStreams(); - } catch (InvalidEventSourceException ies) { - //If we fail to update the list show some messages - //NOTE: we can not show dialog here, as this will steal the focus - // from the combo box, so it does not pop-down later on - String msg = "Invalid event source when getting stream list"; - //JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+ies.getCauseMessages()); - } - - //In any case update the stream list by setting a new data model - // -- even if it is empty - finally { - //Create a new data model - DefaultComboBoxModel newDataModel = new DefaultComboBoxModel(streamNames); - //Select the same stream we had before, if its still there - newDataModel.setSelectedItem(eventStreamComboBox.getSelectedItem()); - //Now install the new DataModel - eventStreamComboBox.setModel(newDataModel); - } - } - - /** - * This implementation of the ANewEventSourceListener gets called whenever - * the event source changes in AEventManager - * @param eventSource the new event source (final as being bound by combo action listener) - */ - public synchronized void newEventSource(final AEventSource eventSource) { - - //Stream selection is off by default - eventStreamComboBox.setVisible(false); - - //Check if this event source supports streams - if (eventSource instanceof AStreamedEventSource){ - - AStreamedEventSource streamedSource = (AStreamedEventSource) eventSource; - - //Update the list in the event stream combo box - updateEventStreamCombo(streamedSource); - - //Temporarily remove all the update handler - for (ActionListener al : eventStreamComboBox.getActionListeners()) - eventStreamComboBox.removeActionListener(al); - for (PopupMenuListener pml : eventStreamComboBox.getPopupMenuListeners()) - eventStreamComboBox.removePopupMenuListener(pml); - - try { - //Now right away select the stream given by the event source - eventStreamComboBox.setSelectedItem(((AStreamedEventSource) eventSource).getStream()); - } catch (InvalidEventSourceException ies) { - //If we fail to update the list show some messages - String msg = "Invalid event source when getting stream list"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+ies.getCauseMessages()); - } catch (NoMoreEventsException nme) { - //If we fail to update the list show some messages - String msg = "No streams (yet) available for this source"; - JOptionPane.showMessageDialog(this, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.error(msg+"\n"+nme.getCauseMessages()); - } - - //(Re-)set the update handler - eventStreamComboBox.addActionListener( new ActionListener () { - public void actionPerformed(ActionEvent e) { - selectedStreamAction((AStreamedEventSource)eventSource); - } - }); - - //Also have the combobox update its item list every time the - //popup is selected - eventStreamComboBox.addPopupMenuListener(new PopupMenuListener(){ - //update stream list when popup appears - public void popupMenuWillBecomeVisible(PopupMenuEvent e) { - updateEventStreamCombo((AStreamedEventSource)eventSource); - } - //Do nothing in other cases - public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} - public void popupMenuCanceled(PopupMenuEvent e) {} - } - ); - - //Finally make it visible - eventStreamComboBox.setVisible(true); - } - - //And repaint to show/hide the combo box - repaint(); - - // disable all the mode buttons - sequentialButton.setEnabled(false); - loopButton.setEnabled(false); - randomButton.setEnabled(false); - - // enable the modes that are supported by the current event source - // and mark the current display mode as active - if(eventSource.supportsNavigationMode(NavigationMode.SEQUENTIAL)) { - if(eventSource.getNavigationMode() == NavigationMode.SEQUENTIAL) - sequentialButton.setSelected(true); - sequentialButton.setEnabled(true); - } - - if(eventSource.supportsNavigationMode(NavigationMode.LOOP)) { - if(eventSource.getNavigationMode() == NavigationMode.LOOP) - loopButton.setSelected(true); - loopButton.setEnabled(true); - } - - if(eventSource.supportsNavigationMode(NavigationMode.RANDOM)) { - if(eventSource.getNavigationMode() == NavigationMode.RANDOM) - randomButton.setSelected(true); - randomButton.setEnabled(true); - } - - // change the address in the address bar to the current event source - refreshAddressBar(); - - } // newEventSource() ----------------------------------------------------- -} - diff --git a/graphics/AtlantisJava/src/atlantis/gui/AFileControl.java b/graphics/AtlantisJava/src/atlantis/gui/AFileControl.java deleted file mode 100755 index 7cf12548f0e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AFileControl.java +++ /dev/null @@ -1,210 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JMenu; -import javax.swing.JOptionPane; -import javax.swing.JSeparator; - -import atlantis.config.ADefaultValues; -import atlantis.data.AG4StepData; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.utils.ALogger; -import javax.swing.JFileChooser; - - -/** - * The File menu in the GUI. - */ -public class AFileControl extends JMenu -{ - private static ALogger logger = ALogger.getLogger(AFileControl.class); - private static AEventManager eventManager = AEventManager.instance(); - private static final AGlobals globals = AGlobals.instance(); - - public AFileControl() - { - super("File"); - - add("Read Event Locally").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - readEventLocally(); - - } - }); // add("Read Event Locally") - - add("Read Event From URL (live)").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - readEventFromURL(); - } - }); // add("Read Event From URL") - - add(new JSeparator()); - - add("Loop over events").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AEventLoopDialog.getInstance().showDialog(); - } - }); - - add(new JSeparator()); - - add("Save Image of Canvas").addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - //Create a new dialog - ASaveCanvasDialog dialog = new ASaveCanvasDialog(); - //And show it - dialog.showDialog(); - } - }); - - add(new JSeparator()); - - add("Event Properties").addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - AEventPropertiesDialog.getInstance().setVisible(true); - } - }); // add("Event Properties") - - add(new JSeparator()); - - add("Read Geometry").addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - new AReadGeometryChooser(); - } - }); // add("Read Geometry") - - add("Read G4Steps").addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - AG4StepData.ReadG4Steps(); - } - }); // add ("Read G4Steps") - - int userLevel = APar.instance().getUserLevel(); - if(userLevel>=3) // TODO: Use name for "debug" instead of magic number - { - add("Memory information").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - System.gc(); - long total = Runtime.getRuntime().totalMemory(); - long free = Runtime.getRuntime().freeMemory(); - long max = Runtime.getRuntime().maxMemory(); - int fac = 1024 * 1024; // Mega factor - String newLine = System.getProperty("line.separator"); - AOutput.append("\nMemory information:"+newLine, ALogInterface.NORMAL); - AOutput.append(" total: " + total + " B " + total / fac + " MB"+newLine, ALogInterface.NORMAL); - AOutput.append(" free : " + free + " B " + free / fac + " MB"+newLine, ALogInterface.NORMAL); - AOutput.append(" max : " + max + " B " + max / fac + " MB"+newLine, ALogInterface.NORMAL); - } - }); - - } // if(logger.isDebugEnabled()) - - add(new JSeparator()); - - add("Exit").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - new AClosingConfirmationDialog(globals.getGuiFrame()).exitApp(); - } - }); - - } // AFileControl() ----------------------------------------------------- - - - /** - * Open a file dialog and read the selected event or directory - */ - private static void readEventLocally(){ - Frame gui = globals.getGuiFrame(); - //get the last location from the default values - String lastLoc = ADefaultValues.get("LastEventFilesSourceDir"); - //Create a file chooser dialog - AReadFileChooser fileDialog = new AReadFileChooser(lastLoc); - //Check if the user pressed ok in the dialog - if ( fileDialog.showOpenDialog(gui) == JFileChooser.APPROVE_OPTION) { - //Get the selected file path, prepend file:// - String fullFilePath = "file://" + fileDialog.getSelectedFile().getPath(); - - try { - //Now set this as a new event source - eventManager.setEventSource(fullFilePath); - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "No events found from this source!"; - JOptionPane.showMessageDialog(gui, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies ){ - String msg = "Not a valid event source"; - JOptionPane.showMessageDialog(gui, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - String msg = "Can not read event(s)"; - JOptionPane.showMessageDialog(gui, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } // okay pressed - otherwise do nothing - } - - - private static void readEventFromURL() - { - // URL may end with .zip - archive of event files, .xml - single - // XML event file (in this case Read Next, Previous works on the web - // directory starting from this single file) or URL only of a web - // directory (string input considered to end with whatever else) - - // in this case Atlantis gets the first event in the directory, - // Read Next, Previous work as expected - // this URL should always start with http:// - - Frame gui = globals.getGuiFrame(); - String urlString = JOptionPane.showInputDialog(gui, - "Enter URL:", AGlobals.instance().getLivePoint1EventsURL()); - - //Make sure this is a proper string - otherwise abort - if(urlString == null || urlString.trim().length()==0) return; - - // event manager further distinguishes the particular event - // reader whether URL ends with .zip or .xml - try { - //Now set this as a new event source - eventManager.setEventSource(urlString); - eventManager.nextEvent(); - } catch (NoMoreEventsException nme) { - String msg = "No events found from this source!"; - JOptionPane.showMessageDialog(gui, msg, "No more events", JOptionPane.ERROR_MESSAGE); - logger.warn(nme.getCauseMessages()); - } catch (InvalidEventSourceException ies ){ - String msg = "Not a valid event source"; - JOptionPane.showMessageDialog(gui, msg, "Invalid source", JOptionPane.ERROR_MESSAGE); - logger.warn(ies.getCauseMessages()); - } catch (ReadEventException ree ){ - String msg = "Can not read event(s)"; - JOptionPane.showMessageDialog(gui, msg, "Read error", JOptionPane.ERROR_MESSAGE); - logger.warn(ree.getCauseMessages()); - } - } // readEventFromURL() ------------------------------------------------- - -} // class AFileControl ===================================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/AGUI.java b/graphics/AtlantisJava/src/atlantis/gui/AGUI.java deleted file mode 100644 index a4327b37958..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AGUI.java +++ /dev/null @@ -1,572 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; - -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.JFrame; -import javax.swing.JMenuBar; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; - -import java.net.Authenticator; -import java.util.List; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.ALayoutChangeListener; -import atlantis.canvas.AWindow; -import atlantis.event.AEventInfoPrinter; -import atlantis.event.AEventManager; -import atlantis.event.AEventSource.InvalidEventSourceException; -import atlantis.event.AEventSource.NoMoreEventsException; -import atlantis.event.AEventSource.ReadEventException; -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.ADragListener; -import atlantis.list.AListManager; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.ACommandProcessor; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParameterChangeListener; -import atlantis.parameters.AParameterSuperGroup; -import atlantis.parameters.AParametersGroup; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import javax.swing.*; - -/** - * The Atlantis Graphical User Interface - * This is a singleton class (and probably one of the few cases where this is - * justified!). By implementing the ALayoutChangeListener it adjusts its size to - * the canvas size. - */ -public class AGUI extends JFrame implements ChangeListener, -ALayoutChangeListener, -AParameterChangeListener -{ - private final static ALogger logger = ALogger.getLogger(AGUI.class); - private final static AGlobals globals = AGlobals.instance(); - public AEventManager eventManager = AEventManager.instance(); - - private static AGUI instance; - - private static APar parameterStore = APar.instance(); - - /** Limit the total width of Atlantis to this number of pixels (0 = screen width). */ - private int maxWidth = 0; - - private AItemTabbedPane[] tabbedPane; - private AParametersPage[][] pages; - private AParametersGroup[][] groups; - private ChangeListener[] tabChangeListener; - private ChangeListener outerTabChangeListener; - private JPanel panel; - private JSplitPane split; - private JTabbedPane outerTabbedPane; - private AInteractionToolBar interactionToolBar; - - /** - * Public singleton instantian-accessor - * @return the singleton instance - */ - public static AGUI getGUI() - { - //Don't create any GUI in headless mode - if (AGlobals.isAtlantisHeadless()) return null; - //Create the GUI if it does not exist - if (instance == null) { - instance = new AGUI(); - globals.setGuiFrame(instance); - } - //return the singleton instance - return instance; - } - - /** - * Private singleton constructor - */ - private AGUI() - { - //intialize parent - super("Atlantis GUI"); - - //be verbose - logger.debug("Creating GUI..."); - - // AClosingConfirmationDialog class handles closing Atlantis - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - this.addWindowListener(new AClosingConfirmationDialog(this)); - - getContentPane().setLayout(new BorderLayout()); - AIcon.setIconImage(this); - - // Creating all menu bar items - JMenuBar menuBar = constructAndGetMenuBar(); - setJMenuBar(menuBar); // set menubar to this frame - - // Create a new toolbar for the event sources - AEventSourceToolBar toolBar = new AEventSourceToolBar(); - toolBar.setName("Atlantis event source toolbar"); - //Does not go into main panel as it need BorderLayout - add(toolBar, BorderLayout.PAGE_START); - // register as an event source listener - eventManager.addNewEventSourceListener(toolBar); - - // building the panel with our own layout manager - // Why do we actually need it?? - panel = new JPanel(new AGUILayoutManager()); - - // setting the Window Control - AWindowControl windowControl = new AWindowControl(); - windowControl.setName("windowControl"); - panel.add(windowControl, AGUILayoutManager.AVAILABLExPREFERRED); - - // setting the Parameters Table - groups = parameterStore.getUIGroups(); - pages = new AParametersPage[groups.length][]; - tabbedPane = new AItemTabbedPane[groups.length]; - tabChangeListener = new TabChangeListener[groups.length]; - - for(int i = 0; i < groups.length; i++) - { - pages[i] = new AParametersPage[groups[i].length]; - tabbedPane[i] = new AItemTabbedPane(JTabbedPane.LEFT); - - for(int j = 0; j < groups[i].length; j++) - { - pages[i][j] = new AParametersPage(groups[i][j]); - String title = groups[i][j].getScreenName(); - tabbedPane[i].addTab(title, null, - pages[i][j], groups[i][j].getToolTip()); - pages[i][j].setName(title); - if(groups[i][j].getScreenName().equals("Residual") || - groups[i][j].getScreenName().equals("Physics") ) - tabbedPane[i].setEnabledAt(tabbedPane[i].getTabCount()-1, false); - } - tabbedPane[i].setSelectedIndex(-1); - tabChangeListener[i] = new TabChangeListener(); - tabbedPane[i].addChangeListener(tabChangeListener[i]); - tabbedPane[i].addMouseListener(new MouseAdapter() - { - public void mousePressed(MouseEvent e) - { - if(AUtilities.isRightMouseButton(e)) - { - JTabbedPane tabbedPane = (JTabbedPane) e.getSource(); - int tab = tabbedPane.getUI().tabForCoordinate(tabbedPane, e.getX(), e.getY()); - int parentTab = ((JTabbedPane) tabbedPane.getParent()).getSelectedIndex(); - if(tab != -1) - { - String helpName = groups[parentTab][tab]. - getGroupName(); - AHelpSystem.getInstance().showPage(helpName); - } - } - } - }); - } - // for loop - setting the outer Table - - outerTabbedPane = new AItemTabbedPane(JTabbedPane.TOP); - outerTabbedPane.setName("parameterGroups"); - List<AParameterSuperGroup> superGroups = parameterStore.getUISuperGroups(); - for(int i = 0; i < superGroups.size(); i++) { - AParameterSuperGroup superGroup = superGroups.get(i); - String title = superGroup.getName(); - String toolTip = superGroup.getToolTip(); - outerTabbedPane.addTab(title, null, tabbedPane[i], toolTip); - tabbedPane[i].setName(title); - } - outerTabChangeListener = new OuterTabChangeListener(); - outerTabbedPane.addChangeListener(outerTabChangeListener); - outerTabbedPane.addMouseListener(new MouseAdapter() - { - public void mousePressed(MouseEvent e) - { - if(AUtilities.isRightMouseButton(e)) - { - JTabbedPane tabbedPane = (JTabbedPane) e.getSource(); - int tab = tabbedPane.getUI().tabForCoordinate(tabbedPane, e.getX(), e.getY()); - if(tab != -1) - { - String helpName = tabbedPane.getTitleAt(tab); - AHelpSystem.getInstance().showPage(helpName); - } - } - } - }); - panel.add(outerTabbedPane, AGUILayoutManager.AVAILABLExAVAILABLE); - - // Set up the output (log) pane. - AMainLogPane outputDisplay = new AMainLogPane(); - // Make it available to all - AOutput.setOutput(outputDisplay); - // Display details of each new event - AEventInfoPrinter eventInfoPrinter = new AEventInfoPrinter(outputDisplay); - eventManager.addNewEventListener(eventInfoPrinter); - // Put it in the GUI - split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel, outputDisplay); - split.setOneTouchExpandable(true); - split.setResizeWeight(0.75); //Give 25% to the log pane by default - getContentPane().add(split); - - // setting the window, projection and group listeners - ACanvas.getCanvas().addWindowChangeListener(this); - String[] wName = ACanvas.getCanvas().getKnownWindowNames(); - for(int i = 0; i < wName.length; i++) { - AWindow w = ACanvas.getCanvas().getWindow(wName[i]); - w.addProjectionChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - AWindow window = (AWindow) e.getSource(); - if(window.equals(ACanvas.getCanvas().getCurrentWindow())) { - if(interactionToolBar != null) panel.remove(interactionToolBar); - interactionToolBar = window.getInteractionToolBar(); - if(interactionToolBar == null) - window.getInteractionManager().forgetContext(); - else { - // the interactions tabpanes are added here - panel.add(interactionToolBar, AGUILayoutManager.AVAILABLExPREFERRED, 0); - interactionToolBar.connect(); - validate(); - } - } - } - }); - - w.addGroupChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - AWindow window = (AWindow) e.getSource(); - if(window.equals(ACanvas.getCanvas().getCurrentWindow())) - setSelectedTab(window.getGroupName()); - } - }); - } - - // Set Authenticator for password-protected URL access to use - // APasswordDialog. - Authenticator.setDefault(APasswordDialog.getAuthenticator(this)); - - } // AGUI() ------------------------------------------------------------- - - - - /** - * Limit the total width of Atlantis to this number of pixels. - * - * @param maxWidth the maximum allowed width in pixels (0 = screen width) - */ - public void setMaxWidth(int maxWidth) { - this.maxWidth = maxWidth; - } - - /** - * Constructs all menu bar (master) items and returns its instance - * @return JMenuBar - */ - private JMenuBar constructAndGetMenuBar() - { - JMenuBar menuBar = new JMenuBar(); - menuBar.add(new AFileControl()); // File menu bar item - menuBar.add(new APreferencesControl()); // Preferences menu bar item - menuBar.add(new AListsControl()); // List manager - - // Spacing, remaining buttons are aligned to the right - menuBar.add(Box.createHorizontalGlue()); - - // Reset button - AMenuButton defaults = new AMenuButton("Reset"); - defaults.setToolTipText("Reload default settings"); - defaults.setBorder(null); - defaults.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - restoreDefaults(); - } - }); - menuBar.add(defaults); - - // Demo button - AMenuButton demoButton = new AMenuButton("Demo"); - demoButton.setToolTipText("Start Demo mode"); - demoButton.setBorder(null); - demoButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - ADemoDialog.getInstance().setVisible(true); - } - }); - menuBar.add(demoButton); - - // Help menu item - menuBar.add(new AHelpControl()); - - return menuBar; - - } // constructAndGetMenuBar() ------------------------------------------- - - - - /** - * This gets called when the current layout changes in ACanvas - */ - public void layoutChanged(ACanvas canvas) { - - // adapt the width of the GUI - Rectangle screenSize = canvas.getScreenSize(); - - int useWidth = screenSize.width; - if (maxWidth > 0 && useWidth > maxWidth) { - useWidth = maxWidth; - } - - Rectangle canvbound = canvas.getStartupCanvasSize(); - int guiHeight = canvbound.height; - if (canvas.getCurrentLayout().getName().equals("FULL SCREEN")) { - int guiWidth = useWidth / 4; - setBounds(useWidth * 3 / 4, 0, guiWidth, guiHeight); - // minimise the gui in fullscreen mode - int state = getExtendedState(); - state |= JFrame.ICONIFIED; - setExtendedState(state); - } else { - int guiWidth = useWidth - canvbound.width - canvbound.x; - setBounds(canvbound.x + canvbound.width, canvbound.y, guiWidth, guiHeight); - } - } // layoutChanged() ----------------------------------------------------- - - /** - * This gets called when the current window changes in ACanvas - * @param e The ChangeEvent from the Window - */ - public void stateChanged(ChangeEvent e) - { - setSelectedTab(ACanvas.getCanvas().getCurrentWindow().getGroupName()); - if(interactionToolBar != null) panel.remove(interactionToolBar); - interactionToolBar = ACanvas.getCanvas().getCurrentWindow().getInteractionToolBar(); - // if there is an InteractionToolBar for this window (and projection) - // add it to the GUI. - if(interactionToolBar != null) - { - interactionToolBar.setName("Atlantis interaction toolbar"); - panel.add(interactionToolBar, AGUILayoutManager.AVAILABLExPREFERRED, 0); - interactionToolBar.connect(); - } - validate(); - } // stateChanged() ----------------------------------------------------- - - - - private void setSelectedTab(String newTabName) - { - for(int i = 0; i < groups.length; i++) - for(int j = 0; j < groups[i].length; j++) - if(groups[i][j].getGroupName().equals(newTabName)) - { - for(int k = 0; k < groups.length; k++) - if(k != i) - { - if(tabbedPane[k].getSelectedIndex() != -1) - { - tabbedPane[k].removeChangeListener(tabChangeListener[k]); - tabbedPane[k].setSelectedIndex( -1); - tabbedPane[k].addChangeListener(tabChangeListener[k]); - } - } - tabbedPane[i].removeChangeListener(tabChangeListener[i]); - tabbedPane[i].setSelectedIndex(j); - tabbedPane[i].addChangeListener(tabChangeListener[i]); - outerTabbedPane.setSelectedIndex(i); - if(pages[i][j].pTable != null) - pages[i][j].pTable.refresh(); - break; - } - } // setSelectedTab() --------------------------------------------------- - - - - public String getCurrentGroup() - { - return ACanvas.getCanvas().getCurrentWindow().getGroupName(); - } // getCurrentGroup() -------------------------------------------------- - - - - public void refresh() - { - if(groups != null) - { - for(int i = 0; i < groups.length; i++) - for(int j = 0; j < groups[i].length; j++) - if(pages[i][j].pTable != null) - pages[i][j].pTable.refresh(); - } - } // refresh() ---------------------------------------------------------- - - - public void repaintTable() - { - if(tabbedPane != null) - for(int i = 0; i < tabbedPane.length; i++) - if(tabbedPane[i] != null) - tabbedPane[i].repaint(); - } // repaintTable() ----------------------------------------------------- - - - - /** - * Restore all the default configuration - */ - public void restoreDefaults() - { - //restore default parameters - parameterStore.restoreDefaults(); - //reset primary vertex in current event if there is one - if (eventManager.getCurrentEvent() != null) { - eventManager.getCurrentEvent().setPrimaryVertex(); - } - //reset all list - AListManager.getInstance().reset(); - //Finally refresh GUI and canvas - this.refresh(); - ACanvas.getCanvas().restoreDefaults(); - - } // restoreDefaults() -------------------------------------------------- - - - - class TabChangeListener implements ChangeListener - { - public void stateChanged(ChangeEvent e) - { - JTabbedPane tabbedPane = (JTabbedPane) e.getSource(); - int index = tabbedPane.getSelectedIndex(); - if(index > -1) - { - int parentIndex = ((JTabbedPane) tabbedPane.getParent()). - getSelectedIndex(); - String name = groups[parentIndex][index].getGroupName(); - ACommandProcessor.receive(name + "."); - pages[parentIndex][index].repaint(); - pages[parentIndex][index].pTable.refresh(); - if(groups[parentIndex][index].getUIUsage() == - AParametersGroup.PROJECTION) - { - AProjection p = AProjectionsManager.getProjection(name); - ACanvas.getCanvas().getCurrentWindow().setProjection(p); - } - } - - } // stateChanged() ------------------------------------------------- - - } // class TabChangeListener ============================================ - - - - class OuterTabChangeListener implements ChangeListener - { - public void stateChanged(ChangeEvent e) - { - JTabbedPane tabbedPane = (JTabbedPane) e.getSource(); - int parentIndex = tabbedPane.getSelectedIndex(); - if(parentIndex > -1) - { - JTabbedPane child = (JTabbedPane) tabbedPane.getSelectedComponent(); - if(child.getTabCount() == 0) - { - child.setSelectedIndex( -1); - } - else - { - int index = 0; - String name = groups[parentIndex][index].getGroupName(); - // for projections don't change the current one - if(groups[parentIndex][index].getUIUsage() == - AParametersGroup.PROJECTION) - { - name = ACanvas.getCanvas().getCurrentWindow().getProjection(). - getName(); - for(int i = 0; i < groups[parentIndex].length; ++i) - { - if(groups[parentIndex][i].getGroupName().equals(name)) - index = i; - } - } - ACommandProcessor.receive(name + "."); - pages[parentIndex][index].repaint(); - pages[parentIndex][index].pTable.refresh(); - if(groups[parentIndex][index].getUIUsage() == - AParametersGroup.PROJECTION) - { - AProjection p = AProjectionsManager.getProjection(name); - ACanvas.getCanvas().getCurrentWindow().setProjection(p); - } - } - } - - } // stateChanged() ------------------------------------------------- - - } // class OuterTabChangeListener ======================================= - - - - static class TabDragListener implements ADragListener - { - public void dragPerformed(Object from, Object to, int action) - { - String wName; - if(to instanceof ADnDLabel) - wName = ((ADnDLabel) to).getText(); - else if(to instanceof AWindow) - wName = ((AWindow) to).getName(); - else - wName = "???"; - JTabbedPane tp = (JTabbedPane) from; - String tabName = tp.getTitleAt(tp.getSelectedIndex()); - AOutput.append("Drag of " + tabName + " into window " + wName + "\n", - ALogInterface.COMMAND); - parameterStore.copyCurrentGroupLocalsTo(wName); - ACanvas.getCanvas().getWindow(wName).repaintFromScratch(); - - } // dragPerformed() ------------------------------------------------ - - } // class TabDragListener ============================================== - - @Override - public void parameterChanged(AParameter parameter) { - this.repaintTable(); - - if(parameter.getName().equals("Mode")){ - int calomode = parameterStore.get("LegoPlot", "Mode").getI(); - - //set different nphicells and netacells combinations depending on the <calo view> selection as it is used in the L1Calo configuration file - if (calomode== 0){ - parameterStore.get("LegoPlot", "nphicells").setI(128); - parameterStore.get("LegoPlot", "netacells").setI(200); - } - else if (calomode== 1){ - parameterStore.get("LegoPlot", "nphicells").setI(64); - parameterStore.get("LegoPlot", "netacells").setI(100); - } - else if (calomode== 2){ - parameterStore.get("LegoPlot", "nphicells").setI(32); - parameterStore.get("LegoPlot", "netacells").setI(50); - } - } - } - -} // class AGUI ============================================================= diff --git a/graphics/AtlantisJava/src/atlantis/gui/AGUILayoutManager.java b/graphics/AtlantisJava/src/atlantis/gui/AGUILayoutManager.java deleted file mode 100755 index f7959d5155e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AGUILayoutManager.java +++ /dev/null @@ -1,131 +0,0 @@ -package atlantis.gui; - -import java.awt.Container; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.LayoutManager2; -import javax.swing.JComponent; -import javax.swing.JToolBar; - -/** - * The layout manager used by the GUI. It arranges the componets in a column. - * The width is set to that of the window. - * The height is set to the preffered height of the component. - * One of the components will take all the remaining space. - */ -public class AGUILayoutManager implements LayoutManager2 { - - private final static int PxP=0; - private final static int AxP=1; - private final static int AxA=2; - - public final static Integer PREFERREDxPREFERRED=new Integer(PxP); - public final static Integer AVAILABLExPREFERRED=new Integer(AxP); - public final static Integer AVAILABLExAVAILABLE=new Integer(AxA); - - private final static String AGUI_LAYOUT_CONSTRAINT="AGUILayoutManager.StringConstraint"; - - /** - * Get the constraints registered for given component. - */ - public Integer getConstraints(Component comp) { - JComponent jc=(JComponent)comp; - - Integer constraint=(Integer)jc.getClientProperty(AGUI_LAYOUT_CONSTRAINT); - - return constraint; - } - - public void addLayoutComponent(Component comp, Object constraint) { - if(!(comp instanceof JComponent)) - throw new Error("AGUILayoutManager: not a JComponent"); - - if(!(constraint instanceof Integer)) - throw new Error("AGUILayoutManager: not a Integer"); - - JComponent jc=(JComponent)comp; - - jc.putClientProperty(AGUI_LAYOUT_CONSTRAINT, constraint); - } - - public void layoutContainer(Container parent) { - int W=parent.getSize().width; - int H=parent.getSize().height; - - Component[] comp=parent.getComponents(); - int[] constraint=new int[comp.length]; - - int AxA_Index=comp.length; - - for(int i=0; i<comp.length; i++) { - constraint[i]=getConstraints(comp[i]).intValue(); - if(constraint[i]==AxA) AxA_Index=i; - } - - int hi=0; - - for(int i=0; i<AxA_Index; i++) { - comp[i].setSize(W, 0); - Dimension cSize=comp[i].getPreferredSize(); - - switch(constraint[i]) { - case PxP: - comp[i].setBounds((W-cSize.width)/2, hi, cSize.width, cSize.height); - break; - - case AxP: - comp[i].setBounds(0, hi, W, cSize.height); - break; - } - hi+=cSize.height; - } - - int hi2=H; - - for(int i=comp.length-1; i>AxA_Index; i--) { - comp[i].setSize(W, 0); - Dimension cSize=comp[i].getPreferredSize(); - - hi2-=cSize.height; - switch(constraint[i]) { - case PxP: - comp[i].setBounds((W-cSize.width)/2, hi2, cSize.width, cSize.height); - break; - - case AxP: - comp[i].setBounds(0, hi2, W, cSize.height); - break; - } - } - - if(AxA_Index!=comp.length) - comp[AxA_Index].setBounds(0, hi, W, hi2-hi); - } - - public Dimension minimumLayoutSize(Container parent) { - return new Dimension(0, 0); - } - - public Dimension preferredLayoutSize(Container parent) { - return new Dimension(0, 0); - } - - public float getLayoutAlignmentX(Container target) { - return 0.5f; - } - - public float getLayoutAlignmentY(Container target) { - return 0.5f; - } - - public Dimension maximumLayoutSize(Container target) { - return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - public void addLayoutComponent(String name, Component comp) {} - - public void removeLayoutComponent(Component comp) {} - - public void invalidateLayout(Container target) {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AGUIUtilities.java b/graphics/AtlantisJava/src/atlantis/gui/AGUIUtilities.java deleted file mode 100644 index e699def52eb..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AGUIUtilities.java +++ /dev/null @@ -1,167 +0,0 @@ -package atlantis.gui; - -import java.awt.Component; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.filechooser.FileFilter; - -import atlantis.globals.AGlobals; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AUtilities; - -/** - * Utility methods related to the GUI. Moved from utils.Utilities. - * - * @author waugh - */ -public class AGUIUtilities { - - private static final AGlobals globals = AGlobals.instance(); - - /** - * Save file dialog. Show the dialog with prepared name of the file in - * the directory. Returns the selected directory. - * - * @param component JDialog - * @param directory String - * @param fileName String - * @param data byte[] - * @param title String - * @param ext extension for file filter - * return selectedDirectory String - */ - public static String chooseFileAndWrite(Component component, String directory, - String fileName, byte[] data, String title, String ext) - throws AAtlantisException - { - String selectedDirectory = directory; - - if(directory == null) - { - directory = AGlobals.instance().getHomeDirectory(); - } - - JFileChooser chooser = new JFileChooser(directory); - chooser.setDialogTitle(title); - chooser.setSelectedFile(new File(fileName)); - SaveDialogFileFilter filter = new SaveDialogFileFilter(ext); - chooser.setFileFilter(filter); - - int returnVal = chooser.showSaveDialog(component); - - if(returnVal == JFileChooser.APPROVE_OPTION) - { - String absPath = chooser.getSelectedFile().getAbsolutePath(); - File f = new File(absPath); - if(f.exists()) - { - try - { - renameFile(absPath, title); - } - catch(Exception ex) - { - throw new AAtlantisException(ex.getMessage()); - } - } - // the selected file either existed and is now successfully - // renamed, or didn't exist so can proceed to store data - try - { - OutputStream s = - new BufferedOutputStream(new FileOutputStream(absPath)); - s.write(data); - s.close(); - selectedDirectory = chooser.getSelectedFile().getParent(); - } - catch(FileNotFoundException ex) - { - String msg = "Couldn't create the file.\nInsufficient permissions."; - throw new AAtlantisException(msg); - } - catch(IOException ex) - { - String msg = "IO Error when writing the\ndata into the file."; - throw new AAtlantisException(msg); - } - } - return selectedDirectory; - - } // chooseFileAndWrite() ----------------------------------------------- - - - /** - * renames file (backup when saving configuration, canvas plot, etc) - * to 'name' + backup suffix - */ - private static void renameFile(String name, String title) throws Exception - { - String backupSuffix = "-backup_on_" + AUtilities.getDateTimeString(); - String dstName = name + backupSuffix; - String errorMsg = "Renaming\n" + name + "\nto\n" + dstName + "\nfailed."; - String msg = name + "\nexists and was successfully renamed to\n" + dstName; - - try - { - AUtilities.logger.debug("Renaming file " + name + " to " + dstName + " ..."); - File f = new File(name); - if(! f.renameTo(new File(dstName))) - { - AUtilities.logger.error(errorMsg); - throw new Exception(errorMsg); - } - AUtilities.logger.debug(msg); - JOptionPane.showMessageDialog(globals.getGuiFrame(), msg, title, - JOptionPane.INFORMATION_MESSAGE); - } - catch(Exception ex) - { - AUtilities.logger.debug(ex.getMessage(), ex); - throw new Exception(errorMsg); - } - - } // renameFile() ------------------------------------------------------- - - - private static class SaveDialogFileFilter extends FileFilter - { - private String extension = null; - - public SaveDialogFileFilter(String acceptedExtension) - { - extension = acceptedExtension; - } - - // accept all directories and all files of "extension" - public boolean accept(File f) - { - if (f.isDirectory()) - { - return true; - } - - String s = f.getName(); - - if(s.toLowerCase().endsWith(extension)) - { - return true; - } - - return false; - } - - public String getDescription() - { - return extension; - } - - } // SaveDialogFileFilter =================================================== - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AHelpControl.java b/graphics/AtlantisJava/src/atlantis/gui/AHelpControl.java deleted file mode 100755 index 787c56609d7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AHelpControl.java +++ /dev/null @@ -1,45 +0,0 @@ -package atlantis.gui; - -import javax.swing.JMenu; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * The Help menu in the GUI. - */ -public class AHelpControl extends JMenu -{ - public AHelpControl() - { - super("Help"); - add("Online Help System").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AHelpSystem.getInstance().showPage("HelpHowTo"); - } - }); - add("Modifier Keys").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AMouseHelpDialog.getInstance().setVisible(true); - } - }); - add("Current color and collection summary").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AColorHelpDialog.getInstance().setVisible(true); - } - }); - add("About...").addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AAboutDialog.getInstance().setVisible(true); - } - }); - - } // AHelpControl() ----------------------------------------------------- -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AHelpSystem.java b/graphics/AtlantisJava/src/atlantis/gui/AHelpSystem.java deleted file mode 100755 index 43ee7551bd7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AHelpSystem.java +++ /dev/null @@ -1,118 +0,0 @@ -package atlantis.gui; - -import atlantis.graphics.AIcon; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.ALogger; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Toolkit; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.net.URL; - -import javax.help.BadIDException; -import javax.help.HelpSet; -import javax.help.JHelp; -import javax.swing.JFrame; - - - -public class AHelpSystem extends JFrame -{ - private static ALogger logger = ALogger.getLogger(AHelpSystem.class); - - private static AHelpSystem instance = null; - private static String hsPath = "jhelpset.hs"; - private static JHelp helpViewer = null; - - - static - { - HelpSet hs = getHelpSet(hsPath); - // HelpBroker hb = hs.createHelpBroker(); - helpViewer = new JHelp(hs); - helpViewer.setCurrentID("HelpHowTo"); - } - - - private AHelpSystem() - { - super("Atlantis Online Help"); - addWindowListener(new WindowAdapter() - { - public void windowClosing(WindowEvent e) - { - dispose(); - instance = null; - } - }); - this.getContentPane().add(helpViewer); - this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - AIcon.setIconImage(this); - this.setSize(900, 600); - - } // AHelpSystem() ------------------------------------------------------ - - - - public static AHelpSystem getInstance() - { - if(instance == null) - { - instance = new AHelpSystem(); - } - return instance; - - } // getInstance() ------------------------------------------------------ - - - - public void showPage(String pageName) - { - try - { - helpViewer.setCurrentID(pageName); - // clear the iconified bit (no matter whether or not it is - // current iconified) - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - this.setLocation((int)(Math.max(0, (screenSize.getWidth()-this.getWidth())/2)), (int)((screenSize.getHeight()-this.getHeight())/3)); - this.setExtendedState(this.getExtendedState() & ~Frame.ICONIFIED); - this.setVisible(true); - } - catch(BadIDException ex) - { - AOutput.alwaysAppend("\nNo help for \"" + pageName + "\", sorry.\n", - ALogInterface.BAD_COMMAND); - } - - } // showPage() --------------------------------------------------------- - - - - private static HelpSet getHelpSet(String helpSetFile) - { - HelpSet hs = null; - // ClassLoader cl = this.getClass().getClassLoader(); // if not static - ClassLoader cl = AHelpSystem.class.getClassLoader(); - try - { - // helpSetFile must contain just the name of HelpSet file (.hs), - // .jar file containing the whole help must be in the classpath - // then the file is successfully found. returns null if helpSetFile - // contains the whole absolute / relative path - URL hsURL = HelpSet.findHelpSet(cl, helpSetFile); - // hs = new HelpSet(null, hsURL); - hs = new HelpSet(cl, hsURL); - } - catch(Exception ee) - { - logger.error("AHelpSystem: " + ee.getMessage(), ee); - logger.error("AHelpSystem: " + helpSetFile + " not found"); - } - return hs; - - } // getHelpSet() ------------------------------------------------------- - - -} // class AHelpSystem ====================================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/AInteractionToolBar.java b/graphics/AtlantisJava/src/atlantis/gui/AInteractionToolBar.java deleted file mode 100755 index ff7e0e65234..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AInteractionToolBar.java +++ /dev/null @@ -1,429 +0,0 @@ -package atlantis.gui; - -import java.awt.FlowLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import java.lang.reflect.Constructor; -import java.util.Hashtable; -import java.util.Vector; - -import javax.swing.ButtonGroup; -import javax.swing.ImageIcon; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JToggleButton; -import javax.swing.JToolBar; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.globals.AGlobals; -import atlantis.graphics.layout.AFlowLayout; -import atlantis.interactions.AInteractionGroup; -import atlantis.interactions.AInteractionsConfigReader; -import atlantis.interactions.AInteractionsManager; -import atlantis.output.AExceptionHandler; -import atlantis.projection.AProjectionsManager; -import atlantis.utils.AUtilities; -import javax.swing.*; - -/** - * The ToolBar that appears in the GUI and shows the set of interactions for a - * window. - * @author maillard - */ - -public class AInteractionToolBar extends JToolBar { - // the interactionsmanager this toolbar talks to - private AInteractionsManager iManager; - - // currently selected group - private AInteractionGroup currentGroup; - - /* previously selected group, needed for the history feature: - * when we select a global interaction (eg SyncCursors), then all windows will use it. - * If then we deselect it, all the windows will go back to their previous interactions */ - private AInteractionGroup previousGroup; - - // a panel that displays the additional controls needed by some interaction groups - private JPanel controls; - - // base path for all radio button icons - private final static String iconBasePath = - AGlobals.instance().getHomeDirectory()+"img"+System.getProperty("file.separator")+"interaction_"; - - // button group for all radio buttons - private ButtonGroup buttonGroup; - - // vector containing all interactionsgroups belonging to this toolbar - Vector<AInteractionGroup> groups; - - // make the pool for holding the Interactions Control and the projections Menus - private static Hashtable<String, Hashtable<String, AInteractionToolBar>> interactionControlsPool = - new Hashtable<String, Hashtable<String, AInteractionToolBar>>(20); - - public static Hashtable<String, Hashtable<String, JPopupMenu>> interactionMenusPool = - new Hashtable<String, Hashtable<String, JPopupMenu>>(20); - - /** - * Creates an InteractionToolBar to work with a particular - * InteractionsManager. - * - * @param iManager The InteractionsManager. - */ - public AInteractionToolBar(AInteractionsManager iManager) { - // call parent constructor - super(); - this.setLayout(new AFlowLayout(5, 5)); - - //make the toolbar non-detachable (can not be detachable - //as long as it does not sit inside an BorderLayout) - this.setFloatable(false); - this.setOpaque(false); - - this.iManager = iManager; - - groups = new Vector<AInteractionGroup>(); - controls = new JPanel(); - buttonGroup = new ButtonGroup(); - } - - /** - * Returns the InteractionsManager associated with this InteractionToolBar. - * - * @return The InteractionsManager - */ - public AInteractionsManager getInteractionsManager() { - return iManager; - } - - /** - * Called each time by the InteractionsManager when the ToolBar is connected - * to it. Should be used to perform some initializations. - */ - public void connect() { - iManager.setContext(getSelectedGroup()); - if (getSelectedGroup() != null) - AMouseHelpDialog.getInstance().processInteractionChange(getSelectedGroup().getInteractions()); - } - - /** - * Adds the group to the InteractionToolBar. The group can - * register some interactions. - * @param group the group to be added. - */ - public void addGroup(AInteractionGroup group, String toolTipText) { - groups.addElement(group); - final String groupName = group.getGroupName(); - - // set up a button for the interaction group - String iconPath = iconBasePath + groupName.toLowerCase() + ".png"; - - ImageIcon newIcon = AUtilities.getFileAsImageIcon(iconPath); - JToggleButton newButton = new JToggleButton(newIcon); - newButton.setName(group.getGroupName()); - newButton.setToolTipText(toolTipText); - - // add the action listener - newButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - buttonClicked(groupName); - } - }); - - // add the mouse listener for the help system - newButton.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - // if the user right clicks on a button - if (AUtilities.isRightMouseButton(e)) { - JToggleButton butt = (JToggleButton) e.getSource(); - // find the corresponding interactions group - if(findGroup(butt.getName()) != null) { - String className = findGroup(butt.getName()).getClass().getName(); - String temp = className.substring(className.lastIndexOf('.') + ".A".length()); - className = temp.substring(0, temp.length() - "Group".length()); - // show the help page for the group - AHelpSystem.getInstance().showPage(className); - } - } - } - }); - - // remove the controls panel so that the new button will - // not appear after it - this.remove(controls); - - // add the button to the ButtonGroup and to the ToolBar - buttonGroup.add(newButton); - this.add(newButton); - - // now we can put the controls panel back - this.add(controls,-1); - - // repaint the toolbar - this.validate(); - this.repaint(); - } - - /** - * Returns an array containing all the groups registered in this ToolBar. - * @return the groups - */ - public AInteractionGroup[] getGroups() { - return (AInteractionGroup[]) groups.toArray(new AInteractionGroup[0]); - } - - /** - * Returns the current interactionsgroup. - * @return the selected group. - */ - public AInteractionGroup getSelectedGroup() { - return currentGroup; - } - - /** - * Returns the name of the current interactionsgroup. - * - * @return the selected group name. - */ - public String getSelectedGroupName() { - return currentGroup.getGroupName(); - } - - /** - * Sets the interactionsgroup given its name, by - * performing a click on it. - * @param groupName the name of the group. - */ - public void setSelectedGroup(String groupName) { - // loop through the interaction groups - for(AInteractionGroup iG : groups) { - // find the one with the corresponding name - if(iG.getGroupName().equals(groupName)) { - // click the corresponding button - for(int i = 0; i < groups.size(); i++) { - if(this.getComponentAtIndex(i) instanceof JToggleButton - && this.getComponentAtIndex(i).getName().equals(groupName)) { - ((JToggleButton) this.getComponentAtIndex(i)).doClick(); - return; - } - } - } - } - } - - /** - * Returns a group based on its name - * @return the interactionsgroup (if found) or null - */ - public AInteractionGroup findGroup(String screenName) { - for(AInteractionGroup iG : groups) { - if(iG.getGroupName().equals(screenName)) return iG; - } - return null; - } - - /** - * Activate the default interactionsgroup (the first one) - */ - public void setDefaultGroup() { - // if there are any interaction groups - if (groups.size() > 0) { - // select the first one - setSelectedGroup(groups.elementAt(0).getGroupName()); - } - } - - /** - * Restore the previously selected group, if there was one. - */ - public void restorePreviousGroup() { - if (previousGroup != null) - this.setSelectedGroup(previousGroup.getGroupName()); - } - - /** - * This gets called when one of the buttons in the toolbar - * is clicked. It notifies the InteractionManager. - * @param groupName the name of the InteractionGroup to be activated - */ - public void buttonClicked(String groupName) { - AInteractionGroup deselectedGroup = currentGroup; - // loop through the groups - for(AInteractionGroup iG : groups) { - // find the one with the corresponding name - if(iG.getGroupName().equals(groupName)) { - // notify the interactionsmanager of the change - iManager.setContext(iG); - - // remove the old additional controls panel, add the new one - this.remove(controls); - if(iG.hasAdditionalControls()) controls = iG.getAdditionalControls(); - else controls = new JPanel(); - this.add(controls,-1); - if (this.getParent() != null) { - this.getParent().validate(); - } - - // take care of the history (previousGroup remembers the last non-global group) - AMouseHelpDialog.getInstance().processInteractionChange(iG.getInteractions()); - if (currentGroup != null && currentGroup.isWindowGroup()) { - previousGroup = currentGroup; - } - currentGroup = iG; - - if(ACanvas.getCanvas().getCurrentWindow() != null) - // if the interactionsgroup is global, update the other windows - if ((iG.isCanvasGroup()) && iManager.getWindow().isCurrent()) { - String[] wName = ACanvas.getCanvas().getCurrentLayout().getWindowNames(); - for (int i = 0; i < wName.length; i++) - if (!wName[i].equals(iManager.getWindow().getName())) { - ACanvas.getCanvas().getWindow(wName[i]) - .getInteractionToolBar().setSelectedGroup(iG.getGroupName()); - } - } - // if a global interactionsgroup was deselected, restore the - // previous groups in all the other windows - if(deselectedGroup != null && deselectedGroup.isCanvasGroup() - && iManager.getWindow().isCurrent()) { - String[] wName = ACanvas.getCanvas().getCurrentLayout().getWindowNames(); - for (int i = 0; i < wName.length; i++) - if (!wName[i].equals(iManager.getWindow().getName())) - ACanvas.getCanvas().getWindow(wName[i]) - .getInteractionToolBar().restorePreviousGroup(); - } - } - } - } - - /** - * Used to get the InteractionControl object for a specific window and projection. - * @param wName The name of the window - * @param pName The name of the projection - * @return The AInteractionToolBar for that window and projection - */ - public static AInteractionToolBar getInteractionToolBar(String wName, String pName) { - if(!ACanvas.getCanvas().isValidWindowName(wName)) - throw new Error("Invalid window name"); - - if(!AProjectionsManager.isValidProjection(pName)) - throw new Error("Invalid projection name"); - - Hashtable<String, AInteractionToolBar> list = interactionControlsPool.get(wName); - - if(list==null) { - list=new Hashtable<String, AInteractionToolBar>(10); - interactionControlsPool.put(wName, list); - } - - AInteractionToolBar control=list.get(pName); - - if(control==null) { - control=makeInteractionToolBar(ACanvas.getCanvas().getWindow(wName), - AInteractionsConfigReader.getNode(pName)); - // if there really existed an InteractionControl register it. - if(control!=null) - list.put(pName, control); - } - - return control; - } - - /** - * Returns the Interaction's PopupMenu. - * @param window - * @return the new popup menu object - */ - public static JPopupMenu getInteractionMenu(AWindow window) { - String wName=window.getName(); - String pName=window.getProjection().getName(); - - if(!ACanvas.getCanvas().isValidWindowName(wName)) - throw new Error("Invalid window name"); - - if(!AProjectionsManager.isValidProjection(pName)) - throw new Error("Invalid projection name"); - - Hashtable<String, JPopupMenu> list=interactionMenusPool.get(wName); - - if(list==null) { - list=new Hashtable<String, JPopupMenu>(10); - interactionMenusPool.put(wName, list); - } - - JPopupMenu menu=list.get(pName); - - if(menu==null) { - menu=makePopupMenu(getInteractionToolBar(wName, pName)); - list.put(pName, menu); - } - - return menu; - } - - /** Creates the AInteractionToolBar and returns a pointer to it - * - * @param window - * @param node - * @return the interaction tool bar - */ - public static AInteractionToolBar makeInteractionToolBar(AWindow window, Node node) { - // check whether we really got a Node with information. If not return null; - if(node==null) return null; - - AInteractionToolBar root=new AInteractionToolBar(window.getInteractionManager()); - - NodeList childs=node.getChildNodes(); - - for(int i=0; i<childs.getLength(); i++) { - Node child=childs.item(i); - - if(child.getNodeType()==Node.ELEMENT_NODE) { - String fileName=child.getAttributes().getNamedItem("fileName").getNodeValue(); - String screenName=child.getAttributes().getNamedItem("screenName").getNodeValue(); - String toolTip=child.getAttributes().getNamedItem("toolTip").getNodeValue(); - - if(child.getNodeName().equals("Panel")) - root.addGroup(makeInteractionGroup(window, fileName, screenName), toolTip); - } - } - - //Also select the default interaction group - root.setDefaultGroup(); - - return root; - } - - private static AInteractionGroup makeInteractionGroup( - AWindow window, String fileName, String screenName) { - Object group=null; - - try { - Constructor[] c=Class.forName("atlantis.interactions.A"+fileName+"Group").getDeclaredConstructors(); - - group=c[0].newInstance(new Object[] {window.getInteractionManager()}); - } catch(Exception e) { - e.printStackTrace(); - AExceptionHandler.processException("Cannot make interaction group "+"A"+fileName+"Group", e); - } - ((AInteractionGroup)group).setGroupName(screenName); - return(AInteractionGroup)group; - } - - private static JPopupMenu makePopupMenu(AInteractionToolBar root) { - JPopupMenu menu=new JPopupMenu(); - - AInteractionGroup[] panels=root.getGroups(); - - for(int i=0; i<panels.length; i++) - menu.add(panels[i].getPopupItem()); - - return menu; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AItemTabbedPane.java b/graphics/AtlantisJava/src/atlantis/gui/AItemTabbedPane.java deleted file mode 100755 index 901642ad4d7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AItemTabbedPane.java +++ /dev/null @@ -1,144 +0,0 @@ -package atlantis.gui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.event.*; - -// Gary- DnD facility commented out as it does not fully work -// ( Window control is left in funny state) -// and is not something i have ever used..... - -/** - * A TabbedPane which generates events when a tab is selected - * and when a tab is deselected. - * Provides DnD support. - */ -public class AItemTabbedPane extends JTabbedPane - implements // for Item Selectability - ItemSelectable, ChangeListener { -// // for drag and drop -// DragSourceListener, DragGestureListener, ACallBack { - - private Component current; - private Component previous; - private ItemListener itemListener; - private ItemEvent itemEvent; - -// private DragSource dragSource=null; -// private Vector dragListeners; - - public AItemTabbedPane(int tabPlacement) { - super(tabPlacement); - // tabs don't change on right click rather help appears. - setUI(new ATabbedPaneUI()); - - current=null; - previous=null; - this.addChangeListener(this); - -// // initializing drag and drop -// dragSource=new DragSource(); -// dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); - -// dragListeners=new Vector(); - } - - public Component getPreviousSelectedComponent() { - if(previous==null) - return getSelectedComponent(); - else - return previous; - } - - public void stateChanged(ChangeEvent e) { - previous=current; - - if((current!=null)&&(itemListener!=null)) { - itemEvent=new ItemEvent(this, 0, current, ItemEvent.DESELECTED); - itemListener.itemStateChanged(itemEvent); - } - - current=getSelectedComponent(); - - if(itemListener!=null) { - itemEvent=new ItemEvent(this, 0, current, ItemEvent.SELECTED); - itemListener.itemStateChanged(itemEvent); - } - } - - // Add a listener to recieve item events when the state of an tab changes. - public void addItemListener(ItemListener l) { - itemListener=l; - } - - // Returns the selected items or null if no items are selected. - public Object[] getSelectedObjects() { - return null; - } - - // Removes an item listener. - public void removeItemListener(ItemListener l) { - if(itemListener.equals(l)) - itemListener=null; - } - - public Dimension getPreferredSize() { - this.getLayout().layoutContainer(this); - return super.getPreferredSize(); - } - -/* - // implementation of DragSourceListener - - // This method is invoked to signify that the Drag and Drop operation is complete. - public void dragDropEnd(DragSourceDropEvent dsde) {} - - // Called as the hotspot enters a platform dependent drop site. - public void dragEnter(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_VALID); - } - - // Called as the hotspot exits a platform dependent drop site. - public void dragExit(DragSourceEvent dse) { - dse.getDragSourceContext().setCursor(ADnDLabel.DROP_INVALID); - } - - // Called as the hotspot moves over a platform dependent drop site. - public void dragOver(DragSourceDragEvent dsde) { - dsde.getDragSourceContext().setCursor(ADnDLabel.DROP_VALID); - } - - // Called when the user has modified the drop gesture. - public void dropActionChanged(DragSourceDragEvent dsde) {} - - // implementation of DragGestureListener - - public void dragGestureRecognized(DragGestureEvent dge) { - Point p=dge.getDragOrigin(); - - if(getSelectedIndex()==getUI().tabForCoordinate(this, p.x, p.y)) { - AObjectTransferable cbt=new AObjectTransferable(this); - - dragSource.startDrag(dge, ADnDLabel.DROP_INVALID, cbt, this); - } - } - - public void callBack(Object to) { - for(int i=0; i<dragListeners.size(); i++) - ((ADragListener)dragListeners.get(i)).dragPerformed(this, to, -1); - } - - public void addDragListener(ADragListener l) { - dragListeners.addElement(l); - } - - public void addChangeListener(ChangeListener l) { - super.addChangeListener(l); - } - - public void removeChangeListener(ChangeListener l) { - super.removeChangeListener(l); - } -*/ -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ALayoutDialog.java b/graphics/AtlantisJava/src/atlantis/gui/ALayoutDialog.java deleted file mode 100755 index 93e07f52794..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ALayoutDialog.java +++ /dev/null @@ -1,109 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.JRadioButton; - -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; - -/** - * A dialog which lets the user to select between the different layouts of the - * canvas. - */ -public class ALayoutDialog extends JDialog implements ActionListener -{ - private JPanel choosePanel; - private JPanel buttonsPanel; - private JButton okButton, cancelButton; - private JRadioButton selected; - - private static final AGlobals globals = AGlobals.instance(); - - public ALayoutDialog() - { - super(globals.getGuiFrame(), "Layout Properties Dialog", true); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - setResizable(false); - - choosePanel = new JPanel(); - choosePanel.setBorder(BorderFactory.createTitledBorder(" Select Layout ")); - - String[] layoutNames = ACanvas.getCanvas().getLayoutNames(); - ButtonGroup group = new ButtonGroup(); - - choosePanel.setLayout(new GridLayout(layoutNames.length, 1)); - for (int i = 0; i < layoutNames.length; i++) - { - JRadioButton r = new JRadioButton(layoutNames[i]); - - r.addActionListener(this); - if (ACanvas.getCanvas().getCurrentLayout().getName().equals(layoutNames[i])) - { - selected = r; - r.setSelected(true); - } - else - r.setSelected(false); - group.add(r); - choosePanel.add(r); - } - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(choosePanel, BorderLayout.CENTER); - - okButton = new JButton("OK"); - okButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - ACanvas.getCanvas().setCurrentLayout(selected.getText()); - dispose(); - ACanvas.getCanvas().bringToFront(); - } - }); - - cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - dispose(); - } - }); - - buttonsPanel = new JPanel(); - buttonsPanel.add(okButton); - buttonsPanel.add(cancelButton); - getContentPane().add(buttonsPanel, BorderLayout.SOUTH); - pack(); - - // set the initial location - AGUI gui = AGUI.getGUI(); - int guiWidth = gui.getWidth(); - int guiHeight = gui.getHeight(); - int guiX = gui.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if(guiX+guiWidth+(dialogWidth-guiWidth)/2>screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max(0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), Math.max(0, (guiHeight - dialogHeight) / 3)); - setVisible(true); - } - - public void actionPerformed(ActionEvent e) - { - selected = (JRadioButton) e.getSource(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ALazyPanel.java b/graphics/AtlantisJava/src/atlantis/gui/ALazyPanel.java deleted file mode 100755 index d6caed6c259..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ALazyPanel.java +++ /dev/null @@ -1,109 +0,0 @@ -package atlantis.gui; - -import java.awt.Graphics; -import javax.swing.JPanel; - -/** - * LazyPanel is an abstract base class that provides functionality - * to defer populating a Panel object until it is actually viewed. - * This is extremely useful when using CardLayout and tab panel - * views because it allows the construction of the subviews to - * be done on a pay-as-you-go basis instead of absorbing all the cost - * of construction up front. - * - * If subclasses choose to override any of the following methods, - * it is their responsibility to ensure their overridden methods - * call the parent's method first. The methods are: - * - * public void paint (Graphics) - * public void paintComponents(Graphics) - * public void paintAll (Graphics) - * public void repaint () - * public void repaint (long) - * public void repaint (int, int, int, int) - * public void repaint (long, int, int, int, int) - * public void update (Graphics) - * - * Each of these methods ensures the panel is constructed - * and then simply forwards the call to the parent class. - * - * You use this class by extending it and moving as much of the - * constructor code as possible from the child class into the method - * lazyConstructor. - */ - -public abstract class ALazyPanel extends JPanel { - - // We want to call the lazyConstructor only once. - private boolean lazyConstructorCalled=false; - - public void paint(Graphics g) { - callLazyConstructor(); - super.paint(g); - } - - public void paintAll(Graphics g) { - callLazyConstructor(); - super.paintAll(g); - } - - public void paintComponents(Graphics g) { - callLazyConstructor(); - super.paintComponents(g); - } - - public void repaint() { - callLazyConstructor(); - super.repaint(); - } - - public void repaint(long l) { - callLazyConstructor(); - super.repaint(l); - } - - public void repaint(int i1, int i2, int i3, int i4) { - callLazyConstructor(); - super.repaint(i1, i2, i3, i4); - } - - public void repaint(long l, int i1, int i2, int i3, int i4) { - callLazyConstructor(); - super.repaint(l, i1, i2, i3, i4); - } - - public void update(Graphics g) { - callLazyConstructor(); - super.update(g); - } - - /** - * Force the lazyConstructor() method implemented in the child class - * to be called. If this method is called more than once on - * a given object, all calls but the first do nothing. - */ - public synchronized final void callLazyConstructor() { - // The general idea below is as follows: - // 1) See if this method has already been successfully called. - // If so, return without doing anything. - // - // 2) Otherwise ... call the lazy constructor. - // 3) Call validate so that any components added are visible. - // 4) Note that we have run. - - if((lazyConstructorCalled==false)&&(getParent()!=null)) { - lazyConstructor(); - lazyConstructorCalled=true; - validate(); - } - } - - /** - * This method must be implemented by any child class. Most of - * the component creation code that would have gone in the constructor - * of the child goes here instead. See the example - * at the top. - */ - abstract protected void lazyConstructor(); - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AListsControl.java b/graphics/AtlantisJava/src/atlantis/gui/AListsControl.java deleted file mode 100755 index 4e8810bc05c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AListsControl.java +++ /dev/null @@ -1,28 +0,0 @@ -package atlantis.gui; - -import atlantis.list.AListManager; -import atlantis.utils.AUtilities; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -/** - * The preferences menu. - */ -public class AListsControl extends AMenuButton { - - public AListsControl() { - super("Lists"); - this.setToolTipText("List control dialog" ); - this.setBorder(null); - this.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - if (AUtilities.isRightMouseButton(e)) { - AHelpSystem.getInstance().showPage("Lists"); - } else { - AListManager.getInstance().showLists(); - } - } - }); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ALogPane.java b/graphics/AtlantisJava/src/atlantis/gui/ALogPane.java deleted file mode 100644 index 693c6f4be77..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ALogPane.java +++ /dev/null @@ -1,205 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTextPane; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.Style; -import javax.swing.text.StyleConstants; -import javax.swing.text.StyleContext; - -import atlantis.output.ALogInterface; -import atlantis.utils.ALogger; - -/** - * This class is a subclass of JTextPane which can be used for any kind of - * logging/text output window in Atlantis. It unifies the old AOutput and - * ALogOutput classes - * - * @author Adam Davison - */ -public class ALogPane extends JScrollPane implements ALogInterface { - - private static ALogger logger = ALogger.getLogger(ALogPane.class); - private Style m_systemDefaultStyle = null; - - private JTextPane m_textPane; - private JPopupMenu m_popupMenu; - private JMenuItem m_menuItemClearTextPane; - - public ALogPane() { - m_textPane = new JTextPane(); - m_textPane.setEditable(false); - m_textPane.setBackground(Color.white); - - setViewportView(m_textPane); - setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - - // popup menu at text pane (info output at the bottom of the GUI) - m_popupMenu = new JPopupMenu(); - m_menuItemClearTextPane = new JMenuItem("Erase info output"); - m_menuItemClearTextPane.addActionListener(new PopupMenuActionListener(this)); - m_popupMenu.add(m_menuItemClearTextPane); - - m_textPane.addMouseListener(new PopupMenuListener_textPane(m_popupMenu)); - - // create style which are used to add text to the document - StyleContext context = StyleContext.getDefaultStyleContext(); - Style defaultStyle = context.getStyle(StyleContext.DEFAULT_STYLE); - - Style newStyle = m_textPane.addStyle(NORMAL, defaultStyle); - - StyleConstants.setFontFamily(newStyle, "Courier"); - StyleConstants.setFontSize(newStyle, 14); - - newStyle = m_textPane.addStyle(NORMAL_BOLD, defaultStyle); - StyleConstants.setFontFamily(newStyle, "Courier"); - StyleConstants.setFontSize(newStyle, 14); - StyleConstants.setBold(newStyle, true); - - newStyle = m_textPane.addStyle(COMMAND, defaultStyle); - StyleConstants.setFontFamily(newStyle, "Courier"); - StyleConstants.setFontSize(newStyle, 14); - StyleConstants.setForeground(newStyle, Color.blue); - - newStyle = m_textPane.addStyle(BAD_COMMAND, defaultStyle); - StyleConstants.setFontFamily(newStyle, "Courier"); - StyleConstants.setFontSize(newStyle, 14); - StyleConstants.setForeground(newStyle, Color.red); - - newStyle = m_textPane.addStyle(WARNING, defaultStyle); - // was Courier - didn't print some greek letters under Linux - StyleConstants.setFontFamily(newStyle, "Arial"); - StyleConstants.setFontSize(newStyle, 15); - StyleConstants.setBold(newStyle, true); - StyleConstants.setForeground(newStyle, Color.red); - - newStyle = m_textPane.addStyle(TITLE, defaultStyle); - StyleConstants.setFontFamily(newStyle, "Courier"); - StyleConstants.setFontSize(newStyle, 16); - StyleConstants.setItalic(newStyle, true); - StyleConstants.setForeground(newStyle, Color.blue); - - newStyle = m_textPane.addStyle(PICK, defaultStyle); - // was Courier - didn't print some greek letters under Linux - StyleConstants.setFontFamily(newStyle, "Arial"); - - StyleConstants.setFontSize(newStyle, 13); - StyleConstants.setItalic(newStyle, true); - StyleConstants.setForeground(newStyle, Color.blue); - - // This is the way ALogOutput styled it's text, perhaps we should - // use NORMAL instead to unify the look of all the output boxes? - AD - m_systemDefaultStyle = context.getStyle(StyleContext.DEFAULT_STYLE); - } - - @Override - public synchronized void append(String s) { - append(s, m_systemDefaultStyle); - } - - @Override - public synchronized void append(String s, String style) { - append(s, m_textPane.getStyle(style)); - } - - private synchronized void append(String s, Style style) { - Document document = m_textPane.getDocument(); - try { - int size = document.getLength(); - - // if the string being appended gets too long, which happens in the - // demo mode runs and leads to OutOfMemory here, cut off the first - // half of the string in the information output - if (size > 51200) // 50kB - { - document.remove(0, size / 2); - - // another option of cutting the string would be - // (but it doesn't preserve styles): - // String text = textPane.getText(); - // textPane.setText(""); // clear all - // s = text.substring(size / 2, size - 1) + s; - - size = document.getLength(); - } - - document.insertString(size, s, style); - - // set the scrollbar to the bottom of the window - // previous solution: - // scrollPane.getViewport().setViewPosition(new Point(0, 9999999)); - // was sometimes crashing with IndexOutOfBoundException - m_textPane.setCaretPosition(document.getLength()); - - if (style.equals(ALogInterface.BAD_COMMAND) || style.equals(ALogInterface.WARNING)) { - Toolkit.getDefaultToolkit().beep(); - } - } catch (BadLocationException e) { - logger.error("Problem in ALogPane", e); - } - } - - @Override - public void clear() { - m_textPane.setText(""); - } - -} - -class PopupMenuListener_textPane extends MouseAdapter -{ - private JPopupMenu popupMenu; - - PopupMenuListener_textPane(JPopupMenu popupMenu) - { - this.popupMenu = popupMenu; - } - - public void mousePressed(MouseEvent evt) - { - showPopupMenu(evt); - } - - public void mouseReleased(MouseEvent evt) - { - showPopupMenu(evt); - } - - private void showPopupMenu(MouseEvent evt) - { - // decides whether right 'trigger' action was performed to show - // the popup menu (on the text pane - info output in GUI) - if (evt.isPopupTrigger()) - { - popupMenu.show(evt.getComponent(), evt.getX(), evt.getY()); - } - } - -} // class PopupMenuListener_textPane ======================================= - -class PopupMenuActionListener implements ActionListener -{ - ALogInterface adaptee; - - PopupMenuActionListener(ALogInterface adaptee) - { - this.adaptee = adaptee; - } - - // clear info output if the popup menu item was pressed - public void actionPerformed(ActionEvent e) - { - adaptee.clear(); - } - -} // class PopupMenuActionListener ========================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/AMainLogPane.java b/graphics/AtlantisJava/src/atlantis/gui/AMainLogPane.java deleted file mode 100644 index c493fad653f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AMainLogPane.java +++ /dev/null @@ -1,13 +0,0 @@ -package atlantis.gui; - -/** - * The main logging pane showing user information - * @author Adam Davison - */ -public class AMainLogPane extends ALogPane { - - public AMainLogPane() { - super(); - append("Welcome to Atlantis !\n", TITLE); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AMenuButton.java b/graphics/AtlantisJava/src/atlantis/gui/AMenuButton.java deleted file mode 100644 index 3a939230f0d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AMenuButton.java +++ /dev/null @@ -1,46 +0,0 @@ -package atlantis.gui; - -import java.awt.Dimension; -import java.awt.FontMetrics; -import javax.swing.JMenuItem; - -/** - * AMenuButton is an object that acts like a JMenuItem but looks like a JMenu. - * This is for the buttons that we add directly to the menu bar. It does not - * allow the layout manager to change it size. - * - * @author Eric Jansen - */ -public class AMenuButton extends JMenuItem { - - /** Extra space needed to make JMenuItem and JMenu look the same */ - private static int EXTRA_SPACE = 6; - - /** Initial preferred size */ - private Dimension size; - - public AMenuButton(String title) { - super(title); - setOpaque(false); - - FontMetrics fm = getFontMetrics(getFont()); - size = super.getPreferredSize(); - size.width = getMargin().left + fm.stringWidth(title) - + getMargin().right + EXTRA_SPACE; - } - - @Override - public Dimension getMinimumSize() { - return size; - } - - @Override - public Dimension getMaximumSize() { - return size; - } - - @Override - public Dimension getPreferredSize() { - return size; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AMouseHelpDialog.java b/graphics/AtlantisJava/src/atlantis/gui/AMouseHelpDialog.java deleted file mode 100755 index c8c691abe24..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AMouseHelpDialog.java +++ /dev/null @@ -1,312 +0,0 @@ -package atlantis.gui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Font; -import java.awt.Frame; -import java.awt.Toolkit; -import java.util.ArrayList; -import java.util.EventObject; -import java.util.Iterator; -import java.util.Vector; - -import javax.swing.JFrame; -import javax.swing.JTable; -import javax.swing.event.CellEditorListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.ButtonGroup; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableModel; -import javax.swing.table.TableCellRenderer; -import javax.swing.JRadioButton; - -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.interactions.AInteraction; -import atlantis.interactions.AModifier; - -import java.awt.event.*; - -/** - * This dialog is used to display the mouse modifiers which are currently active - * Once more a singleton, but at least a proper one (private constructor) - */ -public class AMouseHelpDialog extends JFrame { - - private static JTable table; - static Object[][] rowData; - static Object[] columnNames; - private static AMouseHelpDialog instance; - private static final AGlobals globals = AGlobals.instance(); - - /** - * Private singleton constructor - */ - private AMouseHelpDialog() { - super("Help - Modifier Keys"); - - AIcon.setIconImage(this); - - table = new JTable() { - public TableCellRenderer getCellRenderer(int row, int column) { - if (column == 0) { - return new RadioRenderer(); - } - // else... - return super.getCellRenderer(row, column); - } - - public TableCellEditor getCellEditor(int row, int column) { - if (column == 0) { - return new RadioEditor(); - } else { - return super.getCellEditor(row, column); - } - } - }; - - table.setRowHeight(20); - - table.setFont(new Font("Monospaced", Font.PLAIN, table.getFont().getSize())); - table.setRowSelectionAllowed(false); - - getContentPane().add(table.getTableHeader(), BorderLayout.NORTH); - getContentPane().add(table, BorderLayout.CENTER); - setResizable(false); - - // From Java 1.5 we can tell the window to be always on top - this.setAlwaysOnTop(true); - - this.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - // Reset key modifier when closing the window - AEventQueue.setDefault(AModifier.nothing); - } - }); - - pack(); - - } - - /** - * Get an instance of this singleton - * @return the AMouseHelpDialog instance - */ - public static AMouseHelpDialog getInstance() { - //Make sure no GUI object is created in headless mode - if (AGlobals.isAtlantisHeadless()) return null; - - //Create instance if it does not exist - if (instance == null) instance = new AMouseHelpDialog(); - return instance; - } - - - /** - * Overwrite setVisible to ensure proper placement of the dialog - * @param visible wether the dialog should be visible - */ - @Override - public void setVisible(boolean visible){ - - //Set the proper location on the screen - Frame gui = globals.getGuiFrame(); - int guiWidth = gui.getWidth(); - int guiX = gui.getX(); - int guiY = gui.getY(); - int dialogWidth = (int) instance.getPreferredSize().getWidth(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if (guiX + guiWidth + (dialogWidth - guiWidth) / 2 > screenWidth) - instance.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max(0, guiY)); - else - instance.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), Math.max(0, guiY)); - - //And finally do set it visible! - super.setVisible(visible); - } - - public static void processInteractionChange(Vector interactions) { - if (ACanvas.getCanvas().getCurrentWindow() == null) - return; - - AModifier[] modifiers = ACanvas.getCanvas().getCurrentWindow().getInteractionManager().getMouseModifiers(); - ArrayList<AModifier> m = new ArrayList<AModifier>(); - for (int i = 0; i < modifiers.length; ++i) - m.add(modifiers[i]); - for (int i = 0; i < interactions.size(); ++i) { - AModifier[] mod = ((AInteraction) interactions.get(i)).getModifiers(); - for (int j = 0; j < mod.length; ++j) - m.add(mod[j]); - } - - // remove duplicates - for (int i = 0; i < m.size(); ++i) - for (int j = i + 1; j < m.size(); ++j) - if (m.get(i) != null && m.get(j) != null && ((AModifier)m.get(i)).sameAs((AModifier)m.get(j))) { - m.set(i, null); - } - - Iterator<AModifier> it = m.iterator(); - while (it.hasNext()) - if (it.next() == null) - it.remove(); - - // sort - for (int i = 0; i < m.size(); ++i) - for (int j = i + 1; j < m.size(); ++j) { - String n = m.get(i).toKeyString(); - String o = m.get(j).toKeyString(); - if (o.length() > n.length() || (o.length() == n.length() && (o.length() > 0 && (o.charAt(0) < n.charAt(0))))) { - AModifier temp = m.get(i); - m.set(i, m.get(j)); - m.set(j, temp); - } - } - - int foundnull = -1; - for (int i = 0; i < m.size(); i++) { - AModifier mod = (AModifier)m.get(i); - if (mod.sameAs(AModifier.nothing)) { - foundnull = i; - } - } - - if (foundnull == -1) { - m.add(AModifier.nothing); - } - - ButtonGroup bgroup = new ButtonGroup(); - - rowData = new Object[m.size()][3]; - for (int i = 0; i < rowData.length; ++i) { - AModifier mod = (AModifier)m.get(i); - JRadioButton but = new MouseHelpRadio(mod); - - if (mod.sameAs(AEventQueue.getDefault())) { - but.setSelected(true); - } - - if (mod.sameAs(AModifier.nothing)) { - foundnull = i; - } - - bgroup.add(but); - - rowData[i][0] = but; - rowData[i][1] = mod.toKeyString(); - rowData[i][2] = mod.toDescString(); - } - - columnNames = new String[] { "", "Key", "Action" }; - TableModel model = new AbstractTableModel() { - public String getColumnName(int column) { - return columnNames[column].toString(); - } - - public int getRowCount() { - return rowData.length; - } - - public int getColumnCount() { - return columnNames.length; - } - - public Object getValueAt(int row, int col) { - return rowData[row][col]; - } - - public boolean isCellEditable(int row, int column) { - if (column == 0) { - return true; - } else { - return false; - } - } - - public void setValueAt(Object value, int row, int col) { - rowData[row][col] = value; - fireTableCellUpdated(row, col); - } - }; - - table.setModel(model); - table.getColumnModel().getColumn(0).setPreferredWidth(22); - table.getColumnModel().getColumn(1).setPreferredWidth(80); - table.getColumnModel().getColumn(2).setPreferredWidth(300); - instance.pack(); - } - - private static class MouseHelpRadio extends JRadioButton { - - AModifier m_mod; - - public MouseHelpRadio(AModifier mod) { - m_mod = mod; - - this.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (isSelected()) { - AEventQueue.setDefault(m_mod); - } - // Previously selected radio button doesn't always paint it's - // unselection if you aren't careful - getParent().repaint(); - } - }); - } - - } - - private static class RadioRenderer implements TableCellRenderer { - - public RadioRenderer() { - } - - public Component getTableCellRendererComponent(JTable table, Object value, - boolean isSelected, boolean hasFocus, int row, int column) { - - return (JRadioButton)value; - } - - } - - private static class RadioEditor implements TableCellEditor { - - private JRadioButton button; - - public RadioEditor() { - - } - - public Object getCellEditorValue() { - return button; - } - - public boolean shouldSelectCell(EventObject anEvent) { - return false; - } - - public boolean isCellEditable(EventObject anEvent) { - return true; - } - - public void removeCellEditorListener(CellEditorListener l) { - } - - public void addCellEditorListener(CellEditorListener l) { - } - - public boolean stopCellEditing() { - return true; - } - - public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { - button = (JRadioButton)value; - return button; - } - - public void cancelCellEditing() { - } - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/gui/AMultiSpanCellTableUI.java b/graphics/AtlantisJava/src/atlantis/gui/AMultiSpanCellTableUI.java deleted file mode 100755 index cf0054cee6d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AMultiSpanCellTableUI.java +++ /dev/null @@ -1,81 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Graphics; -import java.awt.Rectangle; - -import javax.swing.JComponent; -import javax.swing.plaf.basic.BasicTableUI; -import javax.swing.table.TableCellRenderer; - -public class AMultiSpanCellTableUI extends BasicTableUI -{ - public void paint(Graphics g, JComponent c) - { - for (int index = 0; index < table.getRowCount(); index++) - { - paintRow(g, index); - } - } - - private void paintRow(Graphics g, int row) - { - AParamGUIDataModel tableModel = (AParamGUIDataModel) table.getModel(); - ADefaultCellAttribute cellAtt = tableModel.getCellAttribute(); - int numColumns = table.getColumnCount(); - - for (int column = 0; column < numColumns; column++) - { - Rectangle cellRect = table.getCellRect(row, column, true); - int cellRow, cellColumn; - if (cellAtt.isVisible(row, column)) - { - cellRow = row; - cellColumn = column; - } - else - { - cellRow = row + cellAtt.getSpan(row, column)[ADefaultCellAttribute.ROW]; - cellColumn = column + cellAtt.getSpan(row, column)[ADefaultCellAttribute.COLUMN]; - } - paintCell(g, cellRect, cellRow, cellColumn); - } - } - - private void paintCell(Graphics g, Rectangle cellRect, int row, int column) - { - int spacingHeight = table.getRowMargin(); - int spacingWidth = table.getColumnModel().getColumnMargin(); - - Color c = g.getColor(); - g.setColor(table.getGridColor()); - g.drawRect(cellRect.x, cellRect.y, cellRect.width - 1, - cellRect.height - 1); - g.setColor(c); - - cellRect.setBounds(cellRect.x + spacingWidth / 2, cellRect.y - + spacingHeight / 2, cellRect.width - spacingWidth, - cellRect.height - spacingHeight); - - if (table.isEditing() && table.getEditingRow() == row - && table.getEditingColumn() == column) - { - Component component = table.getEditorComponent(); - component.setBounds(cellRect); - component.validate(); - } - else - { - TableCellRenderer renderer = table.getCellRenderer(row, column); - Component component = table.prepareRenderer(renderer, row, column); - - if (component.getParent() == null) - { - rendererPane.add(component); - } - rendererPane.paintComponent(g, component, table, cellRect.x, - cellRect.y, cellRect.width, cellRect.height, true); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AMutableCheckBox.java b/graphics/AtlantisJava/src/atlantis/gui/AMutableCheckBox.java deleted file mode 100755 index 92390995e52..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AMutableCheckBox.java +++ /dev/null @@ -1,183 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.LayoutManager; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.Vector; - -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.LookAndFeel; - -import atlantis.utils.AUtilities; - -/** - * Used to display the status and the operator(<,>,=..etc) of a Cut Parameter. - */ -public class AMutableCheckBox extends JPanel { - private JLabel label; - private ACheckBox checkBox; - private javax.swing.Timer timer; - private JPopupMenu popup; - private String selectedText; - private ActionListener statusActionListener, textActionListener; - private Vector oper=new Vector(); - - public AMutableCheckBox(String name) { - setLayout(new AMutableCheckBoxLayout()); - setBorder(null); - - checkBox=new ACheckBox(name); - checkBox.setBackground(new Color(204, 204, 204)); - checkBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if(statusActionListener!=null) - statusActionListener.actionPerformed(new ActionEvent(get(), 0, "")); - } - }); - add("CHECKBOX", checkBox); - - popup=new JPopupMenu(); - } - - // must be called after all the parameters whose added - public void finalizeConstruction() { - label=new JLabel("", JLabel.CENTER); - label.setBorder(BorderFactory.createLineBorder(new Color(153, 153, 153), 1)); - LookAndFeel.installColorsAndFont(label, "CheckBox.background", "CheckBox.foreground", - "CheckBox.font"); - add("LABEL", label); - - // setting the timmer and popup (if more than 2 supportedOperators) - if(oper.size()>2) { - timer=new javax.swing.Timer(50, new ActionListener() { - public void actionPerformed(ActionEvent e) { - Dimension d=label.getSize(); - - popup.show(label, 0, d.height); - } - }); - timer.setRepeats(false); - } - - // setting the mouse listeners - if(oper.size()<=2) - label.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - if(AUtilities.isRightMouseButton(e)||oper.size()==1){ - return; - } - String text0=(String)oper.elementAt(0); - String text1=(String)oper.elementAt(1); - - if(selectedText.equals(text0)) setSelectedText(text1); - else if(selectedText.equals(text1)) setSelectedText(text0); - - if(textActionListener!=null) - textActionListener.actionPerformed(new ActionEvent(get(), 0, "")); - } - }); - else - label.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - if(!AUtilities.isRightMouseButton(e)) - timer.start(); - } - - public void mouseReleased(MouseEvent e) { - if(!AUtilities.isRightMouseButton(e)) - timer.stop(); - } - }); - } - - private JPanel get() { - return this; - } - - public ACheckBox getCheckBox(){ - return checkBox; - } - - public void addItem(String s) { - oper.addElement(s); - - popup.add(s).addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JMenuItem item=(JMenuItem)e.getSource(); - - setSelectedText(item.getText()); - if(textActionListener!=null) - textActionListener.actionPerformed(new ActionEvent(get(), 0, "")); - } - }); - } - - public void setSelectedText(String text) { - selectedText=text; - label.setText(selectedText); - } - - public String getSelectedText() { - return selectedText; - } - - public boolean getStatus() { - return checkBox.isSelected(); - } - - public void setStatus(boolean status) { - checkBox.setSelected(status); - } - - public void addTextActionListener(ActionListener listener) { - textActionListener=listener; - } - - public void addStatusActionListener(ActionListener listener) { - statusActionListener=listener; - } - - public void setForeground(Color color) { - if(checkBox!=null) - checkBox.setForeground(color); - } -} - -class AMutableCheckBoxLayout implements LayoutManager { - private Component checkBox, label; - - public void addLayoutComponent(String name, Component comp) { - if(name.equals("CHECKBOX")) checkBox=comp; - else if(name.equals("LABEL")) label=comp; - } - - public void layoutContainer(Container parent) { - Dimension p=parent.getSize(); - Dimension l=label.getPreferredSize(); - Dimension c=checkBox.getPreferredSize(); - - checkBox.setBounds(0, (p.height-c.height)/2, p.width-l.width-10, c.height); - label.setBounds(p.width-l.width-10, -1, l.width+10+1, p.height+2); - } - - public Dimension minimumLayoutSize(Container parent) { - return new Dimension(10, 10); - } - - public Dimension preferredLayoutSize(Container parent) { - return new Dimension(100, 100); - } - - // Removes the specified component from the layout. - public void removeLayoutComponent(Component comp) {} -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AOpenGLControl.java b/graphics/AtlantisJava/src/atlantis/gui/AOpenGLControl.java deleted file mode 100644 index 3df9c139c01..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AOpenGLControl.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package atlantis.gui; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.canvas.AWindowGLView; -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.ButtonGroup; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JRadioButtonMenuItem; -import javax.swing.JSeparator; -import javax.swing.event.MenuEvent; -import javax.swing.event.MenuListener; - -/** - * - * @author Adam - */ -public class AOpenGLControl extends JMenu implements MenuListener, ActionListener { - - private ButtonGroup m_bg = new ButtonGroup(); - private JRadioButtonMenuItem m_fsaa0 = new JRadioButtonMenuItem("No AA"); - private JRadioButtonMenuItem m_fsaa2 = new JRadioButtonMenuItem("2x FSAA"); - private JRadioButtonMenuItem m_fsaa4 = new JRadioButtonMenuItem("4x FSAA"); - private JRadioButtonMenuItem m_fsaa6 = new JRadioButtonMenuItem("6x FSAA"); - private JRadioButtonMenuItem m_fsaa8 = new JRadioButtonMenuItem("8x FSAA"); - private JCheckBoxMenuItem m_blendborder = new JCheckBoxMenuItem("Blend Border"); - private boolean m_updating = false; - - public AOpenGLControl() { - super("OpenGL"); - - m_bg.add(m_fsaa0); - m_bg.add(m_fsaa2); - m_bg.add(m_fsaa4); - m_bg.add(m_fsaa6); - m_bg.add(m_fsaa8); - - add(m_fsaa0); - add(m_fsaa2); - add(m_fsaa4); - add(m_fsaa6); - add(m_fsaa8); - add(new JSeparator()); - add(m_blendborder); - - m_fsaa0.addActionListener(this); - m_fsaa2.addActionListener(this); - m_fsaa4.addActionListener(this); - m_fsaa6.addActionListener(this); - m_fsaa8.addActionListener(this); - - m_blendborder.addActionListener(this); - - addMenuListener(this); - } - - public void menuSelected(MenuEvent e) { - m_updating = true; - - int maxFSAA = AWindowGLView.getMaxFSAA(); - - m_fsaa2.setEnabled(false); - m_fsaa4.setEnabled(false); - m_fsaa6.setEnabled(false); - m_fsaa8.setEnabled(false); - - if (maxFSAA >= 2) { - m_fsaa2.setEnabled(true); - - if (maxFSAA >= 4) { - m_fsaa4.setEnabled(true); - - if (maxFSAA >= 6) { - m_fsaa6.setEnabled(true); - - if (maxFSAA >= 8) { - m_fsaa8.setEnabled(true); - } - } - } - } - - int currentFSAA = AWindowGLView.getCurrentFSAA(); - - switch (currentFSAA) { - case 0: - m_fsaa0.setSelected(true); - break; - case 2: - m_fsaa2.setSelected(true); - break; - case 4: - m_fsaa4.setSelected(true); - break; - case 6: - m_fsaa6.setSelected(true); - break; - case 8: - m_fsaa8.setSelected(true); - break; - default: - break; - } - - m_updating = false; - } - - public void menuDeselected(MenuEvent e) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void menuCanceled(MenuEvent e) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void actionPerformed(ActionEvent e) { - if (m_updating) { - return; - } - - JMenuItem src = (JMenuItem) (e.getSource()); - - if (src == m_fsaa0) { - AWindowGLView.setCurrentFSAA(0); - } else if (src == m_fsaa2) { - AWindowGLView.setCurrentFSAA(2); - } else if (src == m_fsaa4) { - AWindowGLView.setCurrentFSAA(4); - } else if (src == m_fsaa6) { - AWindowGLView.setCurrentFSAA(6); - } else if (src == m_fsaa8) { - AWindowGLView.setCurrentFSAA(8); - } else if (src == m_blendborder) { - int oldr = AWindow.BORDER_BACKGROUND_COLOR.getRed(); - int oldg = AWindow.BORDER_BACKGROUND_COLOR.getGreen(); - int oldb = AWindow.BORDER_BACKGROUND_COLOR.getBlue(); - int oldselr = AWindow.BORDER_SELECTED_BACKGROUND_COLOR.getRed(); - int oldselg = AWindow.BORDER_SELECTED_BACKGROUND_COLOR.getGreen(); - int oldselb = AWindow.BORDER_SELECTED_BACKGROUND_COLOR.getBlue(); - if (m_blendborder.getState()) { - AWindow.BORDER_BACKGROUND_COLOR = new Color(oldr, oldg, oldb, 127); - AWindow.BORDER_SELECTED_BACKGROUND_COLOR = new Color( - oldselr, oldselg, oldselb, 127); - } else { - AWindow.BORDER_BACKGROUND_COLOR = new Color(oldr, oldg, oldb, 255); - AWindow.BORDER_SELECTED_BACKGROUND_COLOR = new Color( - oldselr, oldselg, oldselb, 255); - } - ACanvas.getCanvas().repaintAllFromScratch(); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AParamGUIDataModel.java b/graphics/AtlantisJava/src/atlantis/gui/AParamGUIDataModel.java deleted file mode 100755 index b1b03a9a1eb..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AParamGUIDataModel.java +++ /dev/null @@ -1,173 +0,0 @@ -package atlantis.gui; - -import java.awt.Component; -import java.util.EventObject; -import java.util.Vector; - -import javax.swing.JTable; -import javax.swing.JTree; -import javax.swing.event.CellEditorListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableCellRenderer; - -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.parameters.AParametersGroup; -import atlantis.parameters.AStatusRootParameter; - -/** - * The data model used to create the custom tables which contain parameters. - */ -class AParamGUIDataModel extends AbstractTableModel implements - TableCellEditor, TableCellRenderer -{ - private Vector<AParameter> parametersList; - // if there is a tree in a cell, the height of the cell should be decided by the tree - private int[] rowHeight; - // indicate if there is a tree in this table - private boolean isTree = false; - private JTree tree = null; - private int treeRowNumber = -1; - private ADefaultCellAttribute cellAtt; - - AParamGUIDataModel(AParametersGroup group) - { - parametersList = group.getParameters(APar.instance().getUserLevel()); - rowHeight = new int[parametersList.size()]; - - cellAtt = new ADefaultCellAttribute(rowHeight.length, 2); - - for (int i = 0; i < parametersList.size(); i++) - { - AParameter p = (AParameter) parametersList.elementAt(i); - if (!p.isInitialized()) - p.initialize(); - if (p instanceof AStatusRootParameter) - { - isTree = true; - tree = (JTree) ((AStatusRootParameter) p).getNameComponent(); - treeRowNumber = i; - rowHeight[i] = tree.getRowCount() - * (int) (tree.getRowBounds(0).getHeight()); - int[] columns = { 0, 1 }; - int[] rows = { i }; - cellAtt.combine(rows, columns); - } - else - rowHeight[i] = 25; - } - } - - public ADefaultCellAttribute getCellAttribute() - { - return cellAtt; - } - - int getRowHeight(int rowIndex) - { - return rowHeight[rowIndex]; - } - - public int getTreeRow() - { - return treeRowNumber; - } - - public boolean hasTree() - { - return isTree; - } - - public JTree getTree() - { - return tree; - } - - public int getRowCount() - { - return parametersList.size(); - } - - public int getColumnCount() - { - return 2; - } - - public Object getValueAt(int rowIndex, int columnIndex) - { - return new Integer(0); - } - - public boolean isCellEditable(int rowIndex, int columnIndex) - { - return true; - } - - public void refresh() - { - for (int i = 0; i < parametersList.size(); i++) - { - AParameter p = (AParameter) parametersList.elementAt(i); - p.refresh(); - } - } - - // TableCellRenderer implementation - public Component getTableCellRendererComponent(JTable table, Object value, - boolean isSelected, boolean hasFocus, int row, int column) - { - return getTableCellEditorComponent(table, value, isSelected, row, - column); - } - - // TableCellEditor implementation - public Component getTableCellEditorComponent(JTable table, Object value, - boolean isSelected, int row, int column) - { - AParameter p = (AParameter) parametersList.elementAt(row); - switch (column) - { - case 0: - return p.getNameComponent(); - case 1: - return p.getValueComponent(); - default: - return null; - } - } - - public AParameter getParameter(int row) - { - return (AParameter) parametersList.elementAt(row); - } - - public Object getCellEditorValue() - { - return new Integer(0); - } - - public boolean isCellEditable(EventObject anEvent) - { - return true; - } - - public boolean shouldSelectCell(EventObject anEvent) - { - return true; - } - - public boolean stopCellEditing() - { - return true; - } - - public void cancelCellEditing() - {} - - public void addCellEditorListener(CellEditorListener l) - {} - - public void removeCellEditorListener(CellEditorListener l) - {} -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AParametersPage.java b/graphics/AtlantisJava/src/atlantis/gui/AParametersPage.java deleted file mode 100755 index 6217ed42aa0..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AParametersPage.java +++ /dev/null @@ -1,44 +0,0 @@ -package atlantis.gui; - -import atlantis.graphics.layout.AFlowLayout; -import atlantis.parameters.ACommand; -import atlantis.parameters.AParametersGroup; -import javax.swing.JScrollPane; -import javax.swing.JPanel; - -/** - * Used to display a table of parameters together with their associated - * commands in the Parameters Control. - */ -public class AParametersPage extends ALazyPanel { - private AParametersGroup group; - AParametersTable pTable; - - public AParametersPage(AParametersGroup group) { - this.group=group; - } - - protected void lazyConstructor() { - setLayout(new AGUILayoutManager()); - setBorder(null); - - add(createCommandsPanel(group), AGUILayoutManager.AVAILABLExPREFERRED); - - pTable=new AParametersTable(group); - pTable.setName(group.getScreenName()); - add(new JScrollPane(pTable), AGUILayoutManager.AVAILABLExAVAILABLE); - } - - private JPanel createCommandsPanel(AParametersGroup group) { - JPanel commandPanel=new JPanel(new AFlowLayout(5, 5)); - - commandPanel.setBorder(null); - ACommand[] commands=group.getCommands(); - - for(int j=0; j<commands.length; j++) - commandPanel.add(commands[j]); - - return commandPanel; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AParametersTable.java b/graphics/AtlantisJava/src/atlantis/gui/AParametersTable.java deleted file mode 100755 index 869510eaf7f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AParametersTable.java +++ /dev/null @@ -1,253 +0,0 @@ -package atlantis.gui; - -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.Enumeration; - -import javax.swing.JPopupMenu; -import javax.swing.JTable; -import javax.swing.JTree; -import javax.swing.event.ListSelectionEvent; -import javax.swing.table.TableColumn; - -import atlantis.parameters.AParameter; -import atlantis.parameters.AParametersGroup; -import atlantis.parameters.AStatusRootParameter; -import atlantis.utils.AUtilities; - -/** - * The graphical object which contains all the parameter of a single group. - * Appears in the GUI. - */ -public class AParametersTable extends JTable -{ - private TableColumn column; - private AParamGUIDataModel dataModel; - public final static String SET_GLOBAL = "Set Global"; - public final static String SET_LOCAL = "Set Local"; - public final static String SET_ALL_GLOBAL = "Set All Global"; - public final static String SET_ALL_LOCAL = "Set All Local"; - - public AParametersTable(AParametersGroup g) - { - super(); - dataModel = new AParamGUIDataModel(g); - setModel(dataModel); - for (int i = 0; i < dataModel.getRowCount(); i++) - this.setRowHeight(i, dataModel.getRowHeight(i)); - if (dataModel.hasTree()) - { - JTree theTree = dataModel.getTree(); - theTree.addTreeExpansionListener(new ATreeExpansionListener( - theTree, this, dataModel.getTreeRow())); - } - column = getColumnModel().getColumn(0); - column.setHeaderValue("Name"); - column.setCellEditor(dataModel); - column.setCellRenderer(dataModel); - column.setPreferredWidth(110); - column = getColumnModel().getColumn(1); - column.setHeaderValue("Value"); - column.setCellEditor(dataModel); - column.setCellRenderer(dataModel); - column.setPreferredWidth(100); - setUI(new AMultiSpanCellTableUI()); - setCellSelectionEnabled(true); - - addMouseListener(new MouseAdapter() { - private int pressedX; - private int pressedY; - - public void mousePressed(MouseEvent e) - { - int clickedRow = rowAtPoint(e.getPoint()); - int clickedCol = columnAtPoint(e.getPoint()); - final AParameter p = ((AParamGUIDataModel) getModel()) - .getParameter(clickedRow); - if ((p instanceof AStatusRootParameter) && (clickedCol == 0)) - { - MouseListener[] theMLs = ((JTree) p.getNameComponent()) - .getMouseListeners(); - for (int i = 0; i < theMLs.length; i++) - { - if (theMLs[i] instanceof AStatusRootParameter.NodeSelectionListener) - { - Rectangle clickedRec = getCellRect(clickedRow, - clickedCol, false); - ((AStatusRootParameter.NodeSelectionListener) theMLs[i]) - .setOffset(clickedRec.x, clickedRec.y); - e.translatePoint(-clickedRec.x, -clickedRec.y); - if (AUtilities.isRightMouseButton(e)) - theMLs[i].mousePressed(e); - else - { - pressedX = e.getX(); - pressedY = e.getY(); - } - } - } - return; - } - if (AUtilities.isRightMouseButton(e) && (clickedCol == 0)) - { - JPopupMenu popupMenu = new JPopupMenu(); - if (p.getScope() == AParameter.LOCAL) - { - popupMenu.add(SET_GLOBAL).addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) - { - p.changeScope(AParameter.GLOBAL); - refresh(); - } - }); - } - else - { - popupMenu.add(SET_LOCAL).addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) - { - p.changeScope(AParameter.LOCAL); - refresh(); - } - }); - } - popupMenu.show(AParametersTable.this, e.getX(), e.getY()); - } - } - - // have no idea why mouseClicked cannot be invoked when clicking the - // table - // only mousePressed & mouseReleased can be invoked - public void mouseReleased(MouseEvent e) - { - int clickedRow = rowAtPoint(e.getPoint()); - // when the position of mouse releasing is out of the table, - // clickedRow = -1 - // e.g. when you change a value of a combo box, and the list of - // this combo box is rather long - if (clickedRow < 0) - return; - int clickedCol = columnAtPoint(e.getPoint()); - final AParameter p = ((AParamGUIDataModel) getModel()) - .getParameter(clickedRow); - if ((p instanceof AStatusRootParameter) && (clickedCol == 0)) - { - MouseListener[] theMLs = ((JTree) p.getNameComponent()) - .getMouseListeners(); - for (int i = 0; i < theMLs.length; i++) - { - if (theMLs[i] instanceof AStatusRootParameter.NodeSelectionListener) - { - Rectangle clickedRec = getCellRect(clickedRow, - clickedCol, false); - ((AStatusRootParameter.NodeSelectionListener) theMLs[i]) - .setOffset(clickedRec.x, clickedRec.y); - e.translatePoint(-clickedRec.x, -clickedRec.y); - if ((pressedX == e.getX()) - && (pressedY == e.getY())) - theMLs[i].mouseClicked(e); - } - } - return; - } - } - }); - // needed but I don't know why gary 25/10/2002 - refresh(); - } - - public void refresh() - { - dataModel.refresh(); - setEditingColumn(2); - setEditingRow(0); - } - - public Rectangle getCellRect(int row, int column, boolean includeSpacing) - { - Rectangle sRect = super.getCellRect(row, column, includeSpacing); - if ((row < 0) || (column < 0) || (getRowCount() <= row) - || (getColumnCount() <= column)) - { - return sRect; - } - ADefaultCellAttribute cellAtt = ((AParamGUIDataModel) getModel()).getCellAttribute(); - if (!cellAtt.isVisible(row, column)) - { - int temp_row = row; - int temp_column = column; - row += cellAtt.getSpan(temp_row, temp_column)[ADefaultCellAttribute.ROW]; - column += cellAtt.getSpan(temp_row, temp_column)[ADefaultCellAttribute.COLUMN]; - } - int[] n = cellAtt.getSpan(row, column); - - int index = 0; - int columnMargin = getColumnModel().getColumnMargin(); - Rectangle cellFrame = new Rectangle(); - int aCellHeight = sRect.height + rowMargin; - cellFrame.y = sRect.y; - cellFrame.height = n[ADefaultCellAttribute.ROW] * aCellHeight; - - Enumeration enumeration = getColumnModel().getColumns(); - while (enumeration.hasMoreElements()) - { - TableColumn aColumn = (TableColumn) enumeration.nextElement(); - cellFrame.width = aColumn.getWidth() + columnMargin; - if (index == column) - break; - cellFrame.x += cellFrame.width; - index++; - } - for (int i = 0; i < n[ADefaultCellAttribute.COLUMN] - 1; i++) - { - TableColumn aColumn = (TableColumn) enumeration.nextElement(); - cellFrame.width += aColumn.getWidth() + columnMargin; - } - - if (!includeSpacing) - { - Dimension spacing = getIntercellSpacing(); - cellFrame.setBounds(cellFrame.x + spacing.width / 2, cellFrame.y - + spacing.height / 2, cellFrame.width - spacing.width, - cellFrame.height - spacing.height); - } - return cellFrame; - } - - public void columnSelectionChanged(ListSelectionEvent e) - { - repaint(); - } - - public void valueChanged(ListSelectionEvent e) - { - int firstIndex = e.getFirstIndex(); - int lastIndex = e.getLastIndex(); - if (firstIndex == -1 && lastIndex == -1) - { - repaint(); - } - Rectangle dirtyRegion = getCellRect(firstIndex, 0, false); - int numCoumns = getColumnCount(); - int index = firstIndex; - for (int i = 0; i < numCoumns; i++) - { - dirtyRegion.add(getCellRect(index, i, false)); - } - index = lastIndex; - for (int i = 0; i < numCoumns; i++) - { - dirtyRegion.add(getCellRect(index, i, false)); - } - repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, - dirtyRegion.height); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/APasswordDialog.java b/graphics/AtlantisJava/src/atlantis/gui/APasswordDialog.java deleted file mode 100755 index eb54cbf2ec8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/APasswordDialog.java +++ /dev/null @@ -1,203 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.awt.Container; -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.JPasswordField; -import javax.swing.JLabel; -import javax.swing.BoxLayout; - -import java.net.PasswordAuthentication; -import java.net.Authenticator; - -import atlantis.utils.ALogger; - -/** - * Provides a dialogue to prompt the user for a username and password for - * reading events from a password-protected URL. - * - * @author waugh - */ -public class APasswordDialog extends JDialog -{ - private static final long serialVersionUID = 1L; - - private static ALogger logger = ALogger.getLogger(APasswordDialog.class); - // input fields - protected JTextField userField; - protected JPasswordField passwordField; - // authentication object containing username and password - protected PasswordAuthentication pwAuth; - - /** - * Create APasswordDialog belonging to given frame - * @param frame owner of dialogue - */ - protected APasswordDialog(Frame frame, String prompt) { - // There is almost certainly a better way to do the layout... - super(frame,"Password Dialogue",true); - Container contentPane = getContentPane(); - - // Create panels to place in content pane - JPanel mainPanel = new JPanel(); - JPanel labelPanel = new JPanel(); - JPanel inputPanel = new JPanel(); - JPanel buttonPanel = new JPanel(); - - // Create components (labels, inputs) to put in panels - JLabel label = new JLabel(prompt); - JLabel userLabel = new JLabel("User name"); - JLabel passwordLabel = new JLabel("Password"); - userField = new JTextField(15); - passwordField = new JPasswordField(15); - JButton okButton = new JButton("OK"); - JButton cancelButton = new JButton("Cancel"); - - // Associate labels with corresponding input fields - userLabel.setLabelFor(userField); - passwordLabel.setLabelFor(passwordField); - - // Specify layout of dialogue - contentPane.setLayout(new BoxLayout(contentPane,BoxLayout.Y_AXIS)); - mainPanel.setLayout(new BoxLayout(mainPanel,BoxLayout.X_AXIS)); - labelPanel.setLayout(new BoxLayout(labelPanel,BoxLayout.Y_AXIS)); - inputPanel.setLayout(new BoxLayout(inputPanel,BoxLayout.Y_AXIS)); - buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS)); - - // Put everything together: components in panels... - contentPane.add(label); - contentPane.add(mainPanel); - contentPane.add(buttonPanel); - - mainPanel.add(labelPanel); - mainPanel.add(inputPanel); - - labelPanel.add(userLabel); - labelPanel.add(passwordLabel); - - inputPanel.add(userField); - inputPanel.add(passwordField); - - buttonPanel.add(okButton); - buttonPanel.add(cancelButton); - - // click OK: construct authentication object from given name/password - okButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) { - String userName = userField.getText(); - char[] password = passwordField.getPassword(); - pwAuth = new PasswordAuthentication(userName,password); - dispose(); - } - } - ); - - // click cancel: dispose of dialogue with no authentication object - cancelButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) { - pwAuth = null; - dispose(); - } - } - ); - pack(); - - // set position on screen (otherwise defaults to top left) - int guiWidth = frame.getWidth(); - int guiHeight = frame.getHeight(); - int guiX = frame.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth()); - if(guiX+guiWidth+(dialogWidth-guiWidth)/2>screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max(0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), Math.max(0, (guiHeight - dialogHeight) / 3)); - - } - - /** - * Create APasswordDialog belonging to given frame, with default prompt - * @param frame owner of dialogue - */ - protected APasswordDialog(Frame frame) { - this(frame,"Authentication required"); - } - - /** Gets authentication object - * - * @return PasswordAuthentication object required by Authenticator - */ - protected PasswordAuthentication getPasswordAuthentication() { - return pwAuth; - } - - /** - * Displays username/password dialogue and returns authentication object. - * @param frame owner of dialogue, e.g. Atlantis GUI - * @prompt prompt to show user - * @return authentication object constructed from entered username/password, - * or null if dialogue cancelled - */ - public static PasswordAuthentication showDialog(Frame frame, String prompt) { - APasswordDialog d = new APasswordDialog(frame,prompt); - d.setVisible(true); - return d.getPasswordAuthentication(); - } - - /** - * Displays username/password dialogue with default prompt and returns authentication object. - * @param frame owner of dialogue, e.g. Atlantis GUI - * @return authentication object constructed from entered username/password, - * or null if dialogue cancelled - */ - public static PasswordAuthentication showDialog(Frame frame) { - APasswordDialog d = new APasswordDialog(frame); - d.setVisible(true); - return d.getPasswordAuthentication(); - } - - /** - * Constructs and returns Authenticator object as required by - * java.net.Authenticator.setDefault() - * @param f owner of dialogue, e.g. Atlantis GUI - * @return Authenticator that will create APasswordDialog when called - */ - public static Authenticator getAuthenticator(Frame f) { - return new PasswordAuthenticator(f); - } - - /** - * Private nested Authenticator subclass to be instantiated and returned - * by getAuthenticator(). - * @author waugh - */ - private static class PasswordAuthenticator extends Authenticator { - protected Frame f; - public PasswordAuthenticator(Frame frame) {f=frame;} - protected PasswordAuthentication getPasswordAuthentication() { - logger.info("Authentication required: requesting host:"+getRequestingHost()); - logger.info("Authentication required: requesting site:"+getRequestingSite()); - logger.info("Authentication required: requesting protocol:"+getRequestingProtocol()); - logger.info("Authentication required: requesting prompt:"+getRequestingPrompt()); - logger.info("Authentication required: requesting scheme:"+getRequestingScheme()); - // logger.info("Authentication required: requesting URL:"+getRequestingURL()); - String prompt = "Authentication required by host "+getRequestingHost()+ - " with prompt \""+getRequestingPrompt()+"\""; - return APasswordDialog.showDialog(f,prompt); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/APointerPositionWindow.java b/graphics/AtlantisJava/src/atlantis/gui/APointerPositionWindow.java deleted file mode 100755 index dffdc697ca1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/APointerPositionWindow.java +++ /dev/null @@ -1,175 +0,0 @@ -package atlantis.gui; - -import java.awt.Color; -import java.awt.Frame; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; - -import javax.swing.JFrame; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTextPane; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; - -import java.awt.BorderLayout; -import java.awt.event.MouseListener; -import javax.swing.JLabel; - - -/** - * The pointer postion window apears when selected in the preferences menu or - * by using o+right click. - * - * @author Sebastian Boeser - */ -public class APointerPositionWindow extends JFrame - implements WindowListener, ActionListener, MouseListener - -{ - private static JLabel infoLabel; - private static JPopupMenu popupMenu; - private static JMenuItem menuItemClearTextPane; - private static JTextPane textPane; - private static JScrollPane scrollPane; - private static APointerPositionWindow instance = null; - private static final AGlobals globals = AGlobals.instance(); - - public static APointerPositionWindow getInstance() - { - if (instance == null) - instance = new APointerPositionWindow(); - return instance; - } - - private APointerPositionWindow() - { - this.setTitle("Your Pointer Position"); - AIcon.setIconImage(this); - - //delete window if closed - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - addWindowListener(this); - - //Tell user how to use this - infoLabel = new JLabel(); - infoLabel.setText("To output your pointer position use: O + Right click\n"); - - // popup menu at text pane (info output at bottom half of window) - popupMenu = new JPopupMenu(); - menuItemClearTextPane = new JMenuItem("Erase output"); - menuItemClearTextPane.addActionListener(this); - popupMenu.add(menuItemClearTextPane); - - // Text panel to show coordinates - textPane = new JTextPane(); - textPane.setEditable(false); - textPane.setBackground(Color.white); - textPane.setText("Coordinates will be displayed here\n"); - textPane.addMouseListener(this); - - // Embedd in a scroll frame - scrollPane = new JScrollPane(textPane); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - - add(infoLabel,BorderLayout.NORTH); - add(scrollPane,BorderLayout.CENTER); - - // set the initial location - Frame gui = globals.getGuiFrame(); - int guiWidth = gui.getWidth(); - int guiHeight = gui.getHeight(); - int guiX = gui.getX(); - int dialogWidth = (int) this.getPreferredSize().getWidth(); - int dialogHeight = (int) this.getPreferredSize().getHeight(); - int screenWidth = Math.round((float) Toolkit.getDefaultToolkit() - .getScreenSize().getWidth()); - if (guiX + guiWidth + (dialogWidth - guiWidth) / 2 > screenWidth) - this.setLocation(Math.max(0, screenWidth - dialogWidth), Math.max( - 0, (guiHeight - dialogHeight) / 3)); - else - this.setLocation(Math.max(0, guiX + (guiWidth - dialogWidth) / 2), - Math.max(0, (guiHeight - dialogHeight) / 3)); - //Layout the window - pack(); - } - - public static void append(String s) - { - String text = textPane.getText(); - int size = text.length(); - //just as a precaution incase too many coordinates output - if(size > 51200) // 50kB - { - textPane.setText(""); // clear all - text = text.substring(size / 2, size - 1) + "\n"; - } - s = text + "\n" + s; - textPane.setText(s); - } - - void clearTextPane(ActionEvent e) - { - textPane.setText("Coordinates will be displayed here\n"); - } - - public void dispose() - { - instance = null; - super.dispose(); - } - - // clear info output if the popup menu item was pressed - public void actionPerformed(ActionEvent e) - { - clearTextPane(e); - } - - - public void windowClosed(WindowEvent e) - { - // when this window is disposed, the menu item is switched off - APreferencesControl.setPosMenuItem(false); - } - - public void mousePressed(MouseEvent evt) - { - showPopupMenu(evt); - } - - public void mouseReleased(MouseEvent evt) - { - showPopupMenu(evt); - } - - private void showPopupMenu(MouseEvent evt) - { - // decides whether right 'trigger' action was performed to show - // the popup menu (on the text pane - info output in GUI) - if (evt.isPopupTrigger()) - { - popupMenu.show(evt.getComponent(), evt.getX(), evt.getY()); - } - } - - // Empty implementations of unused windows events - public void windowOpened(WindowEvent e){} - public void windowClosing(WindowEvent e){} - public void windowIconified(WindowEvent e){} - public void windowDeiconified(WindowEvent e){} - public void windowActivated(WindowEvent e){} - public void windowDeactivated(WindowEvent e){} - - // Empty implementation of unused mouse events - public void mouseClicked(MouseEvent e) {} - public void mouseEntered(MouseEvent e) {} - public void mouseExited(MouseEvent e) {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/APopupHelper.java b/graphics/AtlantisJava/src/atlantis/gui/APopupHelper.java deleted file mode 100644 index ef1dd510ce0..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/APopupHelper.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * APopupHelper.java - * - * Created on 24 October 2007, 09:12 - * - * @author Adam Davison - */ - -package atlantis.gui; - -import javax.swing.JPopupMenu; -import javax.swing.JMenuItem; -import java.awt.Point; -import java.awt.Component; - -/** - * - * @author Adam Davison - */ - -public class APopupHelper { - - public static void showPopupMenu(Point p, Component window, JMenuItem[] items) { - JPopupMenu pop = getPopupMenu(items); - - if (pop == null) { - return; - } - - pop.show(window, (int)p.getX(), (int)p.getY()); - } - - public static JPopupMenu getPopupMenu(JMenuItem[] items) { - - if (items == null) { - return null; - } - - JPopupMenu jp = new JPopupMenu(); - - for (int i = 0; i < items.length; i++) { - jp.add(items[i]); - } - - return jp; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/APreferencesControl.java b/graphics/AtlantisJava/src/atlantis/gui/APreferencesControl.java deleted file mode 100755 index f329c437e38..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/APreferencesControl.java +++ /dev/null @@ -1,429 +0,0 @@ -package atlantis.gui; - -import java.io.File; -import java.awt.Frame; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JMenu; -import javax.swing.JOptionPane; -import javax.swing.JSeparator; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.ALegendWindow; -import atlantis.globals.AGlobals; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.APar; -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; - - -/** - * Preferences menu item - * - * @author Gary Taylor, Zdenek Maxa - */ -public class APreferencesControl extends JMenu implements ActionListener, ItemListener -{ - private static ALogger logger = ALogger.getLogger(APreferencesControl.class); - - private static AGlobals globals = AGlobals.instance(); - - protected static APar parameterStore = APar.instance(); - - private static final String LAYOUT = "Change Canvas Layout"; - private static final String SELECT_COLOR_MAP = "Select Color Map"; - private static final String COLOR_MAP_EDITOR = "Color Map Editor"; - private static final String READ_COLOR_MAP = "Read Color Map"; - private static final String WRITE_COLOR_MAP = "Save Current Color Map"; - private static final String WRITE_CONFIG = "Save Current Configuration"; - private static final String POINTER_POSITION = "Show Pointer Position Window"; - private static final String LEGEND = "Show Legend Window"; - private static final String CANVAS_TITLE = "Show Canvas Title"; - private static final String WINDOW_TITLES = "Show Window Titles"; - private static final String FISHEYE_LOGO = "Show Fisheye Indicator"; - private static final String HIDE_SCALES = "Hide Scales"; - private static final String ATLAS_LOGO = "Show ATLAS logo on saved images"; - private static final String ANTI_ALIASING = "Use Anti-Aliasing"; - private static final String OPEN_GL = "Use OpenGL"; - - private static JCheckBoxMenuItem posMenuItem; - private static JCheckBoxMenuItem legMenuItem; - private static JCheckBoxMenuItem canvasTitleMenuItem; - private static JCheckBoxMenuItem windowTitleMenuItem; - private static JCheckBoxMenuItem fisheyeIndicatorMenuItem; - private static JCheckBoxMenuItem hideScalesMenuItem; - private static JCheckBoxMenuItem atlasLogoMenuItem; - private static JCheckBoxMenuItem aliasMenuItem; - private static JCheckBoxMenuItem openglMenuItem; - - // ---------------------------------------------------------------------- - - public APreferencesControl() - { - super("Preferences"); - this.setToolTipText("Preferences"); - - add(SELECT_COLOR_MAP).addActionListener(this); - add(COLOR_MAP_EDITOR).addActionListener(this); - add(READ_COLOR_MAP).addActionListener(this); - add(WRITE_COLOR_MAP).addActionListener(this); - - add(new JSeparator()); - - add(LAYOUT).addActionListener(this); - add(WRITE_CONFIG).addActionListener(this); - - add(new JSeparator()); - - posMenuItem = new JCheckBoxMenuItem(POINTER_POSITION, false); - posMenuItem.addItemListener(this); - add(posMenuItem); - - legMenuItem = new JCheckBoxMenuItem(LEGEND, false); - legMenuItem.addItemListener(this); - add(legMenuItem); - - add(new JSeparator()); - - canvasTitleMenuItem = new JCheckBoxMenuItem(CANVAS_TITLE, parameterStore.get("Prefs", "CanvasTitle").getStatus()); - canvasTitleMenuItem.addItemListener(this); - add(canvasTitleMenuItem); - - windowTitleMenuItem = new JCheckBoxMenuItem(WINDOW_TITLES, parameterStore.get("Prefs", "WindowTitle").getStatus()); - windowTitleMenuItem.addItemListener(this); - add(windowTitleMenuItem); - - fisheyeIndicatorMenuItem = new JCheckBoxMenuItem(FISHEYE_LOGO, parameterStore.get("Prefs", "FisheyeIndicator").getStatus()); - fisheyeIndicatorMenuItem.addItemListener(this); - add(fisheyeIndicatorMenuItem); - - hideScalesMenuItem = new JCheckBoxMenuItem(HIDE_SCALES, parameterStore.get("Prefs", "HideScales").getStatus()); - hideScalesMenuItem.addItemListener(this); - add(hideScalesMenuItem); - - atlasLogoMenuItem = new JCheckBoxMenuItem(ATLAS_LOGO, parameterStore.get("Prefs", "AtlasLogo").getStatus()); - atlasLogoMenuItem.addItemListener(this); - add(atlasLogoMenuItem); - - - add(new JSeparator()); - - aliasMenuItem = new JCheckBoxMenuItem(ANTI_ALIASING, parameterStore.get("Prefs", "AntiAlias").getStatus()); - aliasMenuItem.addItemListener(this); - add(aliasMenuItem); - - openglMenuItem = new JCheckBoxMenuItem(OPEN_GL, parameterStore.get("Prefs", "OpenGL").getStatus()); - openglMenuItem.addItemListener(this); - - if (globals.getUseOpenGL()) { - add(new JSeparator()); - add(new AOpenGLControl()); - } - } // APreferencesControl() ---------------------------------------------- - - - - public void itemStateChanged(ItemEvent e) - { - if(((JCheckBoxMenuItem)e.getSource()).getText().equals(CANVAS_TITLE)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - { - parameterStore.get("Prefs", "CanvasTitle").setStatus(true); - ACanvas.getCanvas().getTitleBar().setVisible(true); - } - else - { - parameterStore.get("Prefs", "CanvasTitle").setStatus(false); - ACanvas.getCanvas().getTitleBar().setVisible(false); - } - ACanvas.getCanvas().validate(); - ACanvas.getCanvas().repaint(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(POINTER_POSITION)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - APointerPositionWindow.getInstance().setVisible(true); - else - APointerPositionWindow.getInstance().dispose(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(LEGEND)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - { - ALegendWindow legendWindow = ALegendWindow.getInstance(); - // Want to deselect legend menu item if legend window is closed - legendWindow.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - setLegMenuItem(false); - } - }); - - legendWindow.setVisible(true); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - else - ALegendWindow.getInstance().dispose(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(WINDOW_TITLES)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "WindowTitle").setStatus(true); - else - parameterStore.get("Prefs", "WindowTitle").setStatus(false); - ACanvas.getCanvas().repaintAllFromScratch(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(FISHEYE_LOGO)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "FisheyeIndicator").setStatus(true); - else - parameterStore.get("Prefs", "FisheyeIndicator").setStatus(false); - ACanvas.getCanvas().repaintAllFromScratch(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(HIDE_SCALES)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "HideScales").setStatus(true); - else - parameterStore.get("Prefs", "HideScales").setStatus(false); - - ACanvas.getCanvas().repaintAllFromScratch(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(ATLAS_LOGO)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "AtlasLogo").setStatus(true); - else - parameterStore.get("Prefs", "AtlasLogo").setStatus(false); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(ANTI_ALIASING)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "AntiAlias").setStatus(true); - else - parameterStore.get("Prefs", "AntiAlias").setStatus(false); - ACanvas.getCanvas().repaintAllFromScratch(); - } - else if(((JCheckBoxMenuItem)e.getSource()).getText().equals(OPEN_GL)) - { - if(e.getStateChange() == ItemEvent.SELECTED) - parameterStore.get("Prefs", "OpenGL").setStatus(true); - else - parameterStore.get("Prefs", "OpenGL").setStatus(false); - System.out.println("No effect at present"); - } - } // itemStateChanged() ------------------------------------------------- - - - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - - if(LAYOUT.equals(action)) - { - new ALayoutDialog(); - } - else if(SELECT_COLOR_MAP.equals(action)) - { - new AColorMapDialog(); - } - else if(COLOR_MAP_EDITOR.equals(action)) - { - AColorMapEditor.getInstance().setVisible(true); - } - else if(READ_COLOR_MAP.equals(action)) - { - new AReadColorMapChooser().showMyDialog(); - } - else if(WRITE_COLOR_MAP.equals(action)) - { - writeColorMap(); - } - else if(WRITE_CONFIG.equals(action)) - { - writeConfiguration(); - } - - } // actionPerformed() -------------------------------------------------- - - - - private static void writeColorMap() - { - String fileName = ".Atlantis-colormap.xml"; - String title = "Saving current color map"; - Frame gui = globals.getGuiFrame(); - - logger.debug("Going to write customised color map file ..."); - String data = AColorMap.getColorMapXML(); - - // color map data should be ready and valid - store it into file - try - { - AGUIUtilities.chooseFileAndWrite(gui, System.getProperty("user.home"), - fileName, data.getBytes(), title, "xml"); - logger.debug("Current color map written (or cancelled by user)."); - } - catch(AAtlantisException ex) - { - JOptionPane.showMessageDialog(gui, ex.getMessage(), - title, JOptionPane.ERROR_MESSAGE); - logger.debug(ex.getMessage(), ex); - } - - } // writeColorMap() ---------------------------------------------------- - - - - private static void writeConfiguration() - { - String FILE_SEPAR = System.getProperty("file.separator"); - String fileName = globals.getUserConfigFile(); - String title = "Saving current configuration"; - String fileNameFull = System.getProperty("user.home") + FILE_SEPAR + fileName; - String sourceFileNameFull = ""; - Frame gui = globals.getGuiFrame(); - - logger.debug("Writing customised configuration ..."); - - // get currently used configuration file and data from it - File user = new File(fileNameFull); - if(user.canRead()) - { - sourceFileNameFull = fileNameFull; - logger.debug("User has already got " + fileNameFull + - " this will be used as source."); - } - else - { - sourceFileNameFull = globals.getHomeDirectory() + - "configuration" + FILE_SEPAR + - "config.xml"; - logger.debug(sourceFileNameFull + " will be used as source."); - - } - - String data = AConfigWriter.getConfiguration(sourceFileNameFull); - if(data == null) - { - String msg = "Error when reading source configuration from file\n" + - sourceFileNameFull; - logger.error(msg); - JOptionPane.showMessageDialog(gui, msg, title, - JOptionPane.INFORMATION_MESSAGE); - return; - } - - // configuration data should be ready and valid - store it into file - try - { - logger.debug("Current customised configuration made, going to save it ..."); - AGUIUtilities.chooseFileAndWrite(gui, System.getProperty("user.home"), - fileName, data.getBytes(), title, "xml"); - logger.debug("Saving customised configuration successful (or cancelled by user)."); - } - catch(AAtlantisException ex) - { - String m = ex.getMessage(); - JOptionPane.showMessageDialog(gui, m, title, - JOptionPane.ERROR_MESSAGE); - logger.error(m); - logger.debug(m, ex); - } - - } // writeConfiguration() ----------------------------------------------- - - public static void setPosMenuItem(boolean selected) - { - posMenuItem.setSelected(selected); - } - - public static void setLegMenuItem(boolean selected) - { - legMenuItem.setSelected(selected); - } - - public static void setWindowTitleMenuItem(boolean selected) - { - windowTitleMenuItem.setSelected(selected); - parameterStore.get("Prefs", "WindowTitle").setStatus(selected); - } - - public static void setFisheyeIndicatorMenuItem(boolean selected) - { - fisheyeIndicatorMenuItem.setSelected(selected); - parameterStore.get("Prefs", "FisheyeIndicator").setStatus(selected); - } - - public static void setHideScalesMenuItem(boolean selected) - { - hideScalesMenuItem.setSelected(selected); - parameterStore.get("Prefs", "HideScales").setStatus(selected); - } - - public static void setAtlasLogoMenuItem(boolean selected) - { - atlasLogoMenuItem.setSelected(selected); - parameterStore.get("Prefs", "AtlasLogo").setStatus(selected); - } - - public static void setAliasMenuItem(boolean selected) - { - if (!AGlobals.isAtlantisHeadless()) { - aliasMenuItem.setSelected(selected); - } - parameterStore.get("Prefs", "AntiAlias").setStatus(selected); - } - - public static boolean getWindowTitleMenuItem() - { - if(windowTitleMenuItem!=null) - return windowTitleMenuItem.isSelected(); - else - return parameterStore.get("Prefs", "WindowTitle").getStatus(); - } - - public static boolean getFisheyeIndicatorMenuItem() - { - if(fisheyeIndicatorMenuItem!=null) - return fisheyeIndicatorMenuItem.isSelected(); - else - return parameterStore.get("Prefs", "FisheyeIndicator").getStatus(); - } - - public static boolean getHideScalesMenuItem() - { - if(hideScalesMenuItem!=null) - return hideScalesMenuItem.isSelected(); - else - return parameterStore.get("Prefs", "HideScales").getStatus(); - } - - - public static boolean getAtlasLogoMenuItem() - { - if(atlasLogoMenuItem!=null) - return atlasLogoMenuItem.isSelected(); - else - return parameterStore.get("Prefs", "AtlasLogo").getStatus(); - } - - public static boolean getAliasMenuItem() - { - return parameterStore.get("Prefs", "AntiAlias").getStatus(); - /*if(aliasMenuItem!=null) - return aliasMenuItem.isSelected(); - else - return false;*/ - } - -} // class APreferencesControl ============================================== diff --git a/graphics/AtlantisJava/src/atlantis/gui/AReadColorMapChooser.java b/graphics/AtlantisJava/src/atlantis/gui/AReadColorMapChooser.java deleted file mode 100755 index 303935d5c1e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AReadColorMapChooser.java +++ /dev/null @@ -1,35 +0,0 @@ -package atlantis.gui; - -import java.io.File; - -import atlantis.canvas.ACanvas; -import atlantis.globals.AGlobals; -import atlantis.graphics.colormap.AColorMap; - -/** - * The dialog which appears when a user asks to read a new colormap - */ -public class AReadColorMapChooser extends AXMLFileChooser -{ - private static final String FILE_SEPAR = System.getProperty("file.separator"); - private static final AGlobals globals = AGlobals.instance(); - - public AReadColorMapChooser() - { - super(System.getProperty("user.dir") + FILE_SEPAR - + "configuration" + FILE_SEPAR + "colormap.xml", globals.getGuiFrame()); - } - - public boolean processSelectedFile(File file) - { - if (file.canRead()) - { - AColorMap.readColorMap(file.getPath()); - AColorMapEditor.getInstance().updateColors(); - AGUI.getGUI().repaintTable(); - ACanvas.getCanvas().repaintAllFromScratch(); - return true; - } - return false; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AReadFileChooser.java b/graphics/AtlantisJava/src/atlantis/gui/AReadFileChooser.java deleted file mode 100755 index 48ff7472657..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AReadFileChooser.java +++ /dev/null @@ -1,103 +0,0 @@ -package atlantis.gui; - -import java.io.File; - -import javax.swing.JFileChooser; -import javax.swing.filechooser.FileFilter; -import javax.swing.JCheckBox; -import javax.swing.JPanel; - -import java.awt.Component; -import java.awt.BorderLayout; - -import atlantis.config.ADefaultValues; - -/** - * This dialog appears when a user asks to read events from a file - * @author sboeser - */ -public class AReadFileChooser extends JFileChooser { - //Check box indicating to set the new default location - private JCheckBox defaultLoc = null; - - /** - * Constructor with a default path - * @param path the default path - */ - public AReadFileChooser(String path) { - - //Create a file chooser pointing to path - //Use users default dir if null - super(path); - - //Create a new panel with the checkbox - JPanel p = new JPanel(); - defaultLoc = new JCheckBox("default location"); - p.setLayout(new BorderLayout()); - p.add(defaultLoc, BorderLayout.SOUTH); - setAccessory(p); - - - setFileFilter(new XMLFilter()); - } - - /** - * Show the dialog waiting for user input - */ - @Override - public int showOpenDialog(Component parent) { - - //Get the return state - int state = super.showOpenDialog(parent); - - //Store the default location if user pressed ok - if (state == APPROVE_OPTION) { - //Only if checkbox is ticked - if (defaultLoc.isSelected()) { - // save last visited location - ADefaultValues.set("LastEventFilesSourceDir", - getSelectedFile().getParent() + System.getProperty("file.separator")); - } - } - - //return the result state - return state; - } - - /** - * A filter for XML files - */ - private static class XMLFilter extends FileFilter { - - /** - * Acceptance algorithm for xml files and directories - * @param file the file to test - * @return true if accepted - */ - public boolean accept(File file) { - - //accept all directories - if (file.isDirectory()) return true; - - //check the file ending - String name = file.getName().toLowerCase(); - - if (name.endsWith(".xml")) return true; - if (name.endsWith(".zip")) return true; - if (name.endsWith(".gzip")) return true; - if (name.endsWith(".gz")) return true; - - //None of the requested criteria matched - return false; - } - - /** - * Gives a description of the files that are accepted by this filter - * @return string with list of file endings - */ - public String getDescription() { - return ".xml, .zip, .gzip, .gz"; - } - } -} - diff --git a/graphics/AtlantisJava/src/atlantis/gui/AReadGeometryChooser.java b/graphics/AtlantisJava/src/atlantis/gui/AReadGeometryChooser.java deleted file mode 100755 index ae77061aeea..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AReadGeometryChooser.java +++ /dev/null @@ -1,79 +0,0 @@ -package atlantis.gui; - -import atlantis.geometry.AEndcapTRTDetector; - -import java.awt.Frame; -import java.io.File; -import javax.swing.JOptionPane; - -import atlantis.canvas.ACanvas; -import atlantis.data.ACalorimeterData; -import atlantis.geometry.AAtlasDetector; -import atlantis.geometry.ABarrelSiliconDetector; -import atlantis.geometry.ABarrelTRTDetector; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.geometry.AEndcapSiliconDetector; -import atlantis.globals.AGlobals; - - -/** - * The dialog which appears when a user asks to read in geometry XML file - */ -public class AReadGeometryChooser extends AXMLGeometryChooser { - - private static final AGlobals globals = AGlobals.instance(); - - public AReadGeometryChooser() { - super(); - } - - public void fileChosen(int state) { - Frame gui = globals.getGuiFrame(); - do { - if(state==APPROVE_OPTION) { - File file=getSelectedFile(); - - if(file!=null) - if(file.canRead()) { - processSelectedFile(file); - break; - } else { - JOptionPane.showMessageDialog(gui, - "Unable to open " + file, "IO Error", JOptionPane.ERROR_MESSAGE); - } - } else - break; - state=showOpenDialog(gui); - } while(true); - } - - public boolean processSelectedFile(File file) - { - if(file.canRead()) - { - // ACalorimterDetector keeps a list of its instances, clear this list. - ACalorimeterDetector.clear(); - ABarrelSiliconDetector.clear(); - AEndcapSiliconDetector.clear(); - ABarrelTRTDetector.clear(); - AEndcapTRTDetector.clear(); - - String muonname = file.getParent() + System.getProperty("file.separator") + - file.getName().substring(0, 1) + "Muon" + - file.getName().substring(1); - File mufile = new File(muonname); - if(mufile.canRead()) - { - AAtlasDetector.setDetector(new AAtlasDetector(file.getAbsolutePath(), muonname)); - } - else - { - AAtlasDetector.setDetector(new AAtlasDetector(file.getAbsolutePath())); - } - ACalorimeterData.remakeHitToGeometryMapping(); - ACanvas.getCanvas().repaintAllFromScratch(); - return true; - } - return false; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ASaveCanvasDialog.java b/graphics/AtlantisJava/src/atlantis/gui/ASaveCanvasDialog.java deleted file mode 100755 index 2f0d67a3982..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ASaveCanvasDialog.java +++ /dev/null @@ -1,477 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.image.RasterFormatException; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.filechooser.FileFilter; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.canvas.ACanvas; -import atlantis.utils.AAtlantisException; -import atlantis.utils.AUtilities; -import atlantis.config.ADefaultValues; -import atlantis.globals.AGlobals; -import atlantis.graphics.encoders.AImageEncoder; -import atlantis.utils.ALogger; - - -/** - * Dialog window for saving a picture of the current canvas. This dialog allows - * the user to pick the resolution and file type. - * - * @author Eric Jansen - * @author Sebastian Boeser - */ -public class ASaveCanvasDialog extends JFileChooser - implements PropertyChangeListener { - - private final ALogger logger = ALogger.getLogger(ASaveCanvasDialog.class); - private static AEventManager eventManager = AEventManager.instance(); - private static final AGlobals globals = AGlobals.instance(); - - // GUI component that contains the resolution selection panel. - private AResolutionChooser resolutionChooser; - - // Possible image widths shown to user. Heights are fixed by layout restrictions. - private final int[] IMAGE_WIDTHS = {800, 1024, 2400, 5000};//{512, 800, 1024, 2400}; - - // Default selected image width. Also the (fixed) width of the EPS images. - private final int DEFAULT_IMAGE_WIDTH = 1; - - // String holding the default file name, need to be reset after change of file type. - private String defaultFileName = null; - - // Private image encoder instance - private final AImageEncoder imageEncoder = new AImageEncoder(); - - - /** - * Constructor creating the dialog - */ - public ASaveCanvasDialog() - { - //Initialize the file chooser dialog - super(ADefaultValues.get("LastCanvasPlotSaveDir")); - setDialogTitle("Save Canvas"); - - //Add file filters - addChoosableFileFilter(new AFileFilter("eps", "Encapsulated Postscript (*.eps)")); - addChoosableFileFilter(new AFileFilter("png", "Portable Network Graphics (*.png)")); - addChoosableFileFilter(new AFileFilter("svg", "Scalable Vector Graphics (*.svg)")); - - //Set default values - setAcceptAllFileFilterUsed(false); - // In OpenJDK JRE filter is set to null by setAcceptAllFileFilterUsed, so - // have to set it to something: - setFileFilter(getChoosableFileFilters()[1]); - - //Add the resoluton chooser - resolutionChooser = new AResolutionChooser(); - setAccessory(resolutionChooser); - addPropertyChangeListener(this); - - //Set a default file name and extension - defaultFileName = makeEventFileName() + "-" + AUtilities.getDateTimeString(); - String ext = ((AFileFilter) getFileFilter()).getExtension(); - setSelectedFile(new File(defaultFileName + "." + ext)); - } - - /** - * Pops up the "Save Canvas" dialog. - */ - public void showDialog(){ - //Show dialog with GUI as parent - showSaveDialog(globals.getGuiFrame()); - } - - - /** - * @return the defualt file name - */ - public String getDefaultFileName() - { - return defaultFileName; - } - - /** - * Get the currently selected image width. - * @return selected image width - */ - public int getImageWidth() - { - return resolutionChooser.getImageWidth(); - } - - - - /** - * Gets the image height on this button. - * @return image height - */ - public int getImageHeight() - { - return resolutionChooser.getImageHeight(); - } - - - - /** - * Called when the user has selected a file and pushes the save button. - * This function will only - * approve the selection when the actual saving was successful. - */ - @Override - public void approveSelection() - { - Frame gui = globals.getGuiFrame(); - File file = new File(getSelectedFile().getAbsolutePath()); - - // If the file exists and the user does not want to overwrite it, cancel the save operation. - // The dialog is still on screen and the user can pick another file. - if (file.exists() && JOptionPane.showConfirmDialog(gui, "File exists, overwrite?", - "File exists", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) - return; - - // All exceptions are handled equally: the user is sent back to the save canvas dialog. - try { - String type = ((AFileFilter)getFileFilter()).getExtension(); - // Since EPS files can be pretty big, they're saved directly - if (type.equals("eps")){ - // Since vector images are scalable, the image size only determines the relative size of - // the data objects. To make the generated EPS independent of the canvas size, we always - // rescale the image to the default size. - int width = IMAGE_WIDTHS[DEFAULT_IMAGE_WIDTH]; - int height = ACanvas.getCanvas().getRespectiveHeight(width); - imageEncoder.saveEPS(width,height,file); - } else if (type.equals("png")) { - // Generate the canvas image in memory - byte[] data; - int width = resolutionChooser.getImageWidth(); - int height = resolutionChooser.getImageHeight(); - data = imageEncoder.getPNGData(width,height); - // And finally write the image to the selected file. - OutputStream stream = new BufferedOutputStream(new FileOutputStream(file.getAbsolutePath())); - stream.write(data); - stream.close(); - } else if (type.equals("svg")){ - // Since vector images are scalable, the image size only determines the relative size of - // the data objects. To make the generated EPS independent of the canvas size, we always - // rescale the image to the default size. - int width = IMAGE_WIDTHS[DEFAULT_IMAGE_WIDTH]; - int height = ACanvas.getCanvas().getRespectiveHeight(width); - imageEncoder.saveSVG(width,height,file); - } else{ - //Throw an exception if none of the above - throw new AAtlantisException("Unknown image type: '" + type + "'"); - } - } - catch(RasterFormatException e) - { - JOptionPane.showMessageDialog(gui, - "The chosen resolution for canvas is too high, try a lower option!", - "Error saving canvas", JOptionPane.INFORMATION_MESSAGE); - AGUI.getGUI().restoreDefaults(); - this.cancelSelection(); - } catch(Exception e) - { - // Show a dialog with the error message. - JOptionPane.showMessageDialog(AGUI.getGUI(), e.getMessage(), - "Error saving canvas", JOptionPane.ERROR_MESSAGE); - - // The selection is not approved, the user has to select another file or type. - return; - } - - // This approves the selection and ends the saving processs. - super.approveSelection(); - ADefaultValues.set("LastCanvasPlotSaveDir", file.getParent() + - System.getProperty("file.separator")); - - } - - - - /** - * Property change listener for the JFileChooser - * @param e property change event sent by JFileChooser - */ - public void propertyChange(PropertyChangeEvent e) - { - if (e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) - { - String oldExt = ((AFileFilter)e.getOldValue()).getExtension(); - String newExt = ((AFileFilter)e.getNewValue()).getExtension(); - - if ((oldExt.equals("eps") || oldExt.equals("svg")) && !(newExt.equals("eps") || newExt.equals("svg"))) - { - for (int i=0; i<resolutionChooser.getComponentCount(); i++) - { - resolutionChooser.getComponent(i).setEnabled(true); - } - } - else if (!(oldExt.equals("eps") || oldExt.equals("svg")) && ((newExt.equals("eps")) || newExt.equals("svg"))) - { - for (int i=0; i<resolutionChooser.getComponentCount(); i++) - resolutionChooser.getComponent(i).setEnabled(false); - } - - // The behaviour of the JFileChooser is somewhat strange. Regardless of what the user has entered, - // the input text field will be emptied when the user selects another file type. It is impossible - // to retrieve the text that was in this field, so we just reset the default file name. - if (getSelectedFile() == null) - { - // Reset our default with the new extension - setSelectedFile(new File(defaultFileName + "." + newExt)); - updateUI(); - rescanCurrentDirectory(); - } - } - } - - - - /** - * Generates a file name based on the current event name and the visible projections. - * @return auto generated image file name - */ - private static String makeEventFileName() - { - String name = "Untitled"; - AEvent ev = eventManager.getCurrentEvent(); - if(ev != null) - { - name = ev.getSourceName(); - if(name.toLowerCase().endsWith(".xml")) - { - // current event comes from XML file, run and event number - // are probably already part of the current filename - name = name.substring(0, name.length() - 4); - } - else - { - // current event was probably retrieved online, add run and - // event numbers into the file name of the canvas plot - if(! ("n/a".equals(ev.getRunNumber()) && - "n/a".equals(ev.getEventNumber()))) - { - name += "_" + ev.getRunNumber() + "_" + ev.getEventNumber(); - } - } - } - - ACanvas canvas = ACanvas.getCanvas(); - String[] windows = canvas.getCurrentLayout().getWindowNames(); - StringBuilder listWindows = new StringBuilder(); - for(int i = 0; i < windows.length; i++) - { - if(canvas.isReallyOnScreen(canvas.getWindow(windows[i]))) - { - listWindows.append("-" + canvas.getWindow(windows[i]).getProjection().getName()); - } - } - name += listWindows.toString(); - - return name; - } - - - - /** - * GUI component for the resolution selection panel. - */ - class AResolutionChooser extends JPanel implements ActionListener - { - /** Currently selected button. */ - private AResolutionButton selectedButton; - - /** - * Constructor. - */ - public AResolutionChooser() - { - super(new GridLayout(IMAGE_WIDTHS.length+1, 1)); - setBorder(BorderFactory.createTitledBorder(" Resolution: ")); - - ButtonGroup group = new ButtonGroup(); - for (int i=0; i<IMAGE_WIDTHS.length; i++) - { - int width = IMAGE_WIDTHS[i]; - int height = ACanvas.getCanvas().getRespectiveHeight(IMAGE_WIDTHS[i]); - - AResolutionButton button = new AResolutionButton(width, height); - button.addActionListener(this); - if(i == DEFAULT_IMAGE_WIDTH) - { - selectedButton = button; - button.setSelected(true); - } - group.add(button); - add(button); - } - } - - /** - * Get the currently selected image width. - * @return selected image width - */ - public int getImageWidth() - { - return selectedButton.getImageWidth(); - } - - /** - * Gets the currently selected image height. - * @return selected image height - */ - public int getImageHeight() - { - return selectedButton.getImageHeight(); - } - - public void updateResolutions() - { - for (int i=0; i<getComponentCount(); i++) - { - if (getComponent(i) instanceof AResolutionButton) - { - AResolutionButton button = (AResolutionButton)getComponent(i); - int height = ACanvas.getCanvas().getRespectiveHeight(button.getImageWidth()); - button.setImageHeight(height); - } - } - } - - - - /** - * Action listener for the resolution panel. - * @param e performed action - */ - public void actionPerformed(ActionEvent e) - { - selectedButton = (AResolutionButton)e.getSource(); - } - - /** - * Radio button for the resolution chooser. - */ - public class AResolutionButton extends JRadioButton - { - /** Image width for this button. */ - int imageWidth; - /** Image height for this button. */ - int imageHeight; - - /** - * Constructor. - * @param targetWidth image width this button corresponds to - * @param targetHeight image height this button corresponds to - */ - public AResolutionButton(int imageWidth, int imageHeight) - { - super(imageWidth + "x" + imageHeight); - this.imageWidth = imageWidth; - this.imageHeight = imageHeight; - } - - /** - * Gets the image width on this button. - * @return image width - */ - public int getImageWidth() - { - return imageWidth; - } - - /** - * Gets the image height on this button. - * @return image height - */ - public int getImageHeight() - { - return imageHeight; - } - - public void setImageHeight(int imageHeight) - { - this.imageHeight = imageHeight; - setText(imageWidth + "x" + imageHeight); - } - } - } - - /** - * Simple filter class that filters files by extension. - */ - private static class AFileFilter extends FileFilter - { - /** File extension. */ - private String extension; - /** Description of the file type this filter shows. */ - private String description; - - /** - * Constructs a file filter. - * @param extension file extension that passes the filter - * @param description description of the file type this filter selects - */ - public AFileFilter(String extension, String description) - { - super(); - this.extension = extension; - this.description = description; - } - - /** - * Decides if the filter allows a file to pass or not - * @param f file under consideration - * @return decision of the filter - */ - public boolean accept(File f) - { - //Accept all directories - if (f.isDirectory()) return true; - - //Accept all files that end with given extension - if (f.getName().toLowerCase().endsWith(extension)) return true; - - //Nothing else - return false; - } - - /** - * Get the extension this filter filters on. - * @return file extension - */ - public String getExtension() - { - return extension; - } - - /** - * Get description of the filter. - * @return description - */ - public String getDescription() - { - return description; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AStartupWindow.java b/graphics/AtlantisJava/src/atlantis/gui/AStartupWindow.java deleted file mode 100755 index 4743e6d2081..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AStartupWindow.java +++ /dev/null @@ -1,86 +0,0 @@ -package atlantis.gui; - -import atlantis.globals.AGlobals; -import atlantis.graphics.AIcon; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import java.awt.*; -import javax.swing.*; - - -/** - * The startup window appears when the program starts up and displays the - * progress of the operation. No need for this to be a singleton at all. - */ -public class AStartupWindow { - - //add a logger - private final ALogger logger = ALogger.getLogger(AStartupWindow.class); - - //the frame showing the startup image and progress - private final JFrame frame = (AGlobals.isAtlantisHeadless()) ? null : new JFrame(); - - //how often we will update the progress bar - private final int progressUpdateDiff; - - //GUI items that will be updated - private JLabel text = null; - private JProgressBar progress = null; - - public AStartupWindow(int numUpdates) { - - //Store how often we will update the progress bar - progressUpdateDiff=(int)100./numUpdates; - - //Don't do anything in headless mode - if (AGlobals.isAtlantisHeadless()) return; - - frame.getContentPane().setLayout(new BorderLayout()); - - String fileName = AGlobals.instance().getHomeDirectory() + "img" + - System.getProperty("file.separator") + "atlas.jpg"; - ImageIcon icon = AUtilities.getFileAsImageIcon(fileName); - - frame.getContentPane().add(new JLabel(icon), BorderLayout.CENTER); - text = new JLabel("Welcome to Atlantis", JLabel.CENTER); - JPanel p = new JPanel(); - - p.setLayout(new GridLayout(2, 1)); - p.add(text); - progress = new JProgressBar(0, 100); - progress.setStringPainted(true); - p.add(progress); - frame.getContentPane().add(p, BorderLayout.SOUTH); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - frame.setLocation(screenSize.width / 4, screenSize.height / 3); - frame.setUndecorated(true); - AIcon.setIconImage(frame); - frame.setTitle("Atlantis starting up..."); - frame.pack(); - frame.setVisible(true); - } - - /** - * Update the frame and log to the logger - * @param newText the new text for the startup window - */ - public void updateText(String newText) { - //Also send this to the logger - logger.info(newText); - - //Don't do graphics update in headless mode - if (AGlobals.isAtlantisHeadless()) return; - - //Update text and progress bar - text.setText(newText); - progress.setValue(progress.getValue()+progressUpdateDiff); - } - - /** - * When dispsoing this object, also dispose of the frame - */ - public void dispose(){ - if (frame!=null) frame.dispose(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ATabbedPaneUI.java b/graphics/AtlantisJava/src/atlantis/gui/ATabbedPaneUI.java deleted file mode 100755 index ea5cf518a7d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ATabbedPaneUI.java +++ /dev/null @@ -1,35 +0,0 @@ -package atlantis.gui; - -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -import javax.swing.JComponent; -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.metal.MetalTabbedPaneUI; - -import atlantis.utils.AUtilities; - -/** - * Once installed on a TabbedPane this UI will allow changing the tabs only with - * the left mouse button. By default this is possible with any button. - * In Atlantis the right mouse button provides help - */ - -public class ATabbedPaneUI extends MetalTabbedPaneUI { - - public static ComponentUI createUI(JComponent c) { - return new ATabbedPaneUI(); - } - - protected MouseListener createMouseListener() { - return new myMouseHandler(); - } - - public class myMouseHandler extends MouseHandler { - public void mousePressed(MouseEvent e) { - if(!AUtilities.isRightMouseButton(e)) - super.mousePressed(e); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ATextField.java b/graphics/AtlantisJava/src/atlantis/gui/ATextField.java deleted file mode 100755 index a7aae0b222b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ATextField.java +++ /dev/null @@ -1,31 +0,0 @@ -package atlantis.gui; - - -import java.awt.event.ActionListener; -import javax.swing.JTextField; - - -/** - * This textfield will not generate an event when the setText() function is called. - */ - -public class ATextField extends JTextField { - ActionListener listener; - - public ATextField() { - super(); - } - - public void addActionListener(ActionListener l) { - if(listener==null) { - super.addActionListener(l); - listener=l; - } - } - - public void setText(String t) { - if(listener!=null) super.removeActionListener(listener); - super.setText(t); - if(listener!=null) super.addActionListener(listener); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ATreeCellRenderer.java b/graphics/AtlantisJava/src/atlantis/gui/ATreeCellRenderer.java deleted file mode 100755 index 3979507b6ff..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ATreeCellRenderer.java +++ /dev/null @@ -1,34 +0,0 @@ -package atlantis.gui; - -import java.awt.*; -import javax.swing.*; -import javax.swing.tree.*; -import atlantis.parameters.AStatusParameter; -import hep.wired.util.TristateCheckBox; - -public class ATreeCellRenderer implements TreeCellRenderer { - - public ATreeCellRenderer() { - } - - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean isSelected, - boolean expanded, boolean leaf, int row, boolean hasFocus) { - if(value instanceof ACheckNode){ - ACheckNode cellNode = (ACheckNode)value; - cellNode.updateState(); - if (cellNode.getParameter() instanceof AStatusParameter){ - ACheckBox cellComponent = (ACheckBox)cellNode.getUserObject(); - cellComponent.setBorderPaintedFlat(true); - return cellComponent; - } else{ - TristateCheckBox cellComponent = (TristateCheckBox)cellNode.getUserObject(); - cellComponent.setState(cellNode.getState()); - cellComponent.setBorderPaintedFlat(true); - return cellComponent; - } - } - - return new JLabel("not a checkNode"); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/ATreeExpansionListener.java b/graphics/AtlantisJava/src/atlantis/gui/ATreeExpansionListener.java deleted file mode 100755 index cb7d0b79160..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/ATreeExpansionListener.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ATreeExpansionListener.java - * - * Created on 17 March 2005, 15:55 - */ - -package atlantis.gui; - -import javax.swing.event.TreeExpansionListener; -import javax.swing.event.TreeExpansionEvent; -import javax.swing.JTree; - -/** - * - * @author Qiang - */ -public class ATreeExpansionListener implements TreeExpansionListener { - - private JTree tree; - - private AParametersTable table; - - // the row number which the tree locates - private int treeRow; - - /** Creates a new instance of ATreeExpansionListener */ - public ATreeExpansionListener(JTree tree, AParametersTable table, int treeRow) { - this.tree = tree; - this.table = table; - this.treeRow = treeRow; - } - - public void treeExpanded(TreeExpansionEvent event) { - int newHeight = tree.getRowCount() * (int)(tree.getRowBounds(0).getHeight()); - table.setRowHeight(treeRow, newHeight); - } - - public void treeCollapsed(TreeExpansionEvent event) { - int newHeight = tree.getRowCount() * (int)(tree.getRowBounds(0).getHeight()); - table.setRowHeight(treeRow, newHeight); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AWindowControl.java b/graphics/AtlantisJava/src/atlantis/gui/AWindowControl.java deleted file mode 100755 index abac35788b1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AWindowControl.java +++ /dev/null @@ -1,190 +0,0 @@ -package atlantis.gui; - -import atlantis.canvas.ALayoutChangeListener; -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.canvas.ALayout; -import atlantis.graphics.layout.AFlowLayout; -import atlantis.graphics.layout.AGridLayout; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.ADragListener; -import atlantis.parameters.ACommandProcessor; -import atlantis.utils.*; -import java.util.*; -import javax.swing.BorderFactory; -import javax.swing.SwingUtilities; -import javax.swing.JPanel; -import java.awt.Color; -import java.awt.Rectangle; -import java.awt.Dimension; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.event.*; - -/** - * Allows user to select the current window and to - * copy between windows. - */ -public class AWindowControl extends JPanel - implements ALayoutChangeListener, ADragListener { - - private String selectedWindowName; - private Vector pages=new Vector(10); - - public AWindowControl getPanel() { - return this; - } - - public AWindowControl() { - super(); - setLayout(new AFlowLayout(10, 10)); - - addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - if(AUtilities.isRightMouseButton(e)) - AHelpSystem.getInstance().showPage("WindowControl"); - } - }); - - // registering as a listener to of window lock changes - ACanvas.getCanvas().addLockChangeListener(new ChangeListener() { - - public void stateChanged(ChangeEvent e) { - for(int i=0; i<pages.size(); i++) { - Hashtable page=(Hashtable)pages.elementAt(i); - Enumeration labels=page.elements(); - while(labels.hasMoreElements()) { - ADnDLabel label=(ADnDLabel)labels.nextElement(); - if(ACanvas.getCanvas().getWindow(label.getName()).isLocked()) - label.setForeground(Color.red); - else - label.setForeground(Color.black); - } - } - } - }); - - // registering as a listener to APar - ACanvas.getCanvas().addLayoutChangeListener(this); - - ACanvas.getCanvas().addWindowChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - ADnDLabel label; - - if(selectedWindowName!=null) - for(int i=0; i<pages.size(); i++) { - Hashtable page=(Hashtable)pages.elementAt(i); - - label=(ADnDLabel)page.get(selectedWindowName); - if(label!=null) - label.setBackground(new Color(207, 207, 207)); - } - - selectedWindowName=ACanvas.getCanvas().getCurrentWindow().getName(); - for(int i=0; i<pages.size(); i++) { - Hashtable page=(Hashtable)pages.elementAt(i); - - label=(ADnDLabel)page.get(selectedWindowName); - if(label!=null) - label.setBackground(Color.white); - } - } - }); - } - - // function gets called when the current layout is changed in APar - public void layoutChanged(ACanvas c) { - removeAll(); - ALayout layout = c.getCurrentLayout(); - Dimension d=layout.getSize(); - WindowMouseListener windowMouseListener=new WindowMouseListener(); - - // adding new set of pages - pages.clear(); - String[] pageNames=layout.getPageNames(); - Hashtable pageHashtable; - - for(int i=0; i<pageNames.length; i++) { - String[] wNames=layout.getPageContent(pageNames[i]); - - JPanel page=new JPanel(new AGridLayout(d, 15)); - - pageHashtable=new Hashtable(); - for(int k=0; k<wNames.length; k++) { - Rectangle constraint=layout.getWindowConstraints(wNames[k]); - ADnDLabel w=new ADnDLabel(wNames[k], wNames, true); - - w.setBorder(BorderFactory.createLineBorder(new Color(150, 150, 150))); - pageHashtable.put(wNames[k], w); - page.add(w, constraint); - w.addMouseListener(windowMouseListener); - w.addDragListener(this); - } - - pages.addElement(pageHashtable); - add(page); - setToolTipText("Current Layout - "+layout.getName()); - revalidate(); - repaint(); - } - } - - public void dragPerformed(Object from, Object to, int action) { - if((from instanceof ADnDLabel)&&(to instanceof ADnDLabel)) - ACanvas.getCanvas().copyWindowSettings(((ADnDLabel)from).getText(), ((ADnDLabel)to).getText()); - } - - private Hashtable findPage(String[] wNames) - { - for (int i = 0; i < pages.size(); i++) - { - int matches = 0; - Hashtable page = (Hashtable)pages.get(i); - - for (int j = 0; j < wNames.length; j++) - { - if (page.containsKey(wNames[j])) - matches++; - else break; - } - if (matches == wNames.length) - return page; - } - return null; - } - - class WindowMouseListener extends MouseAdapter { - - public void mousePressed(MouseEvent e) { - ADnDLabel label = (ADnDLabel) e.getSource(); - - if (AUtilities.isRightMouseButton(e)) { - if (AEventQueue.getKeyboardState() == KeyEvent.VK_A) { - - String[] pageName = label.returnPageName(); - Hashtable page = findPage(pageName); - if(page==null) - return; - - for (Enumeration labels = page.elements(); labels.hasMoreElements(); ) { - label = (ADnDLabel) labels.nextElement(); - if (label != null) - ACommandProcessor.receive("W" + label.getName()); - } - } - else { - AWindow.getPopupMenu().show(label, e.getX(), e.getY()); - ACommandProcessor.receive("W" + label.getName()); - } - } - } - - public void mouseReleased(MouseEvent e) { - ADnDLabel label=(ADnDLabel)e.getSource(); - - if(SwingUtilities.isLeftMouseButton(e)) { - ACommandProcessor.receive("W"+label.getName()); - } - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AXMLFileChooser.java b/graphics/AtlantisJava/src/atlantis/gui/AXMLFileChooser.java deleted file mode 100755 index b5c2421bfcd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AXMLFileChooser.java +++ /dev/null @@ -1,108 +0,0 @@ -package atlantis.gui; - -import java.awt.Component; -import java.io.File; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.filechooser.FileFilter; - - - -/** - * A GUI component used choose a specific XML file - */ -public abstract class AXMLFileChooser extends JFileChooser -{ - private Component parent = null; - - public abstract boolean processSelectedFile(File file); - - - public AXMLFileChooser(String fileName, Component parent) - { - super(); - this.parent = parent; - - setFileFilter(new XMLFilter()); - if (fileName == null) - { - setCurrentDirectory(new File(System.getProperty("user.dir"))); - } - else - { - File f = new File(fileName); - if (f.isFile()) - { - setCurrentDirectory(new File(f.getAbsolutePath())); - setSelectedFile(f); - } - else - { - setCurrentDirectory(f); - } - } - - } // AXMLFileChooser() -------------------------------------------------- - - - - public void showMyDialog() - { - do - { - int state = showOpenDialog(this.parent); - if(state == APPROVE_OPTION) - { - File file = getSelectedFile(); - if(file != null) - { - if(processSelectedFile(file)) - { - break; - } - else - { - JOptionPane.showMessageDialog(parent, - "Unable to open\n" + file, "IO Error", - JOptionPane.ERROR_MESSAGE); - } - } - } - else - { - break; - } - } - while(true); - - } // showMyDialog() ----------------------------------------------------- - - - - private static class XMLFilter extends FileFilter - { - // Accept all directories and all valid files. - public boolean accept(File f) - { - if(f.isDirectory()) - { - return true; - } - - String s = f.getName(); - - if(s.toLowerCase().endsWith(".xml") || s.toLowerCase().endsWith(".zip") - || s.toLowerCase().endsWith(".gzip") || s.toLowerCase().endsWith(".gz")) - return true; - - return false; - } - - - public String getDescription() - { - return ".xml, .zip, .gzip, .gz"; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/AXMLGeometryChooser.java b/graphics/AtlantisJava/src/atlantis/gui/AXMLGeometryChooser.java deleted file mode 100755 index c790d8aeee8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/AXMLGeometryChooser.java +++ /dev/null @@ -1,73 +0,0 @@ -package atlantis.gui; - -import java.awt.Frame; -import java.io.File; -import javax.swing.*; -import javax.swing.filechooser.*; - -import atlantis.globals.AGlobals; - - -/** - * A GUI component used choose a specific XML file - */ -public abstract class AXMLGeometryChooser extends JFileChooser { - - private static final AGlobals globals = AGlobals.instance(); - - public AXMLGeometryChooser(String fileName) { - super(); - String FILE_SEPAR = System.getProperty("file.separator"); - Frame gui = globals.getGuiFrame(); - setFileFilter(new XMLFilter()); - setCurrentDirectory(new File(System.getProperty("user.dir")+FILE_SEPAR+ - "geometry")); - if(fileName!=null) - setSelectedFile(new File(System.getProperty("user.dir")+FILE_SEPAR - +fileName)); - do { - int state=showOpenDialog(gui); - if(state==APPROVE_OPTION) { - File file=getSelectedFile(); - if(file!=null) - if(processSelectedFile(file)) - break; - else { - JOptionPane.showMessageDialog(gui, - "Unable to open " + file, "IO Error", JOptionPane.ERROR_MESSAGE); - } - } else - break; - } while(true); - } - - - public AXMLGeometryChooser() { - this(null); - } - - - public abstract boolean processSelectedFile(File file); - - - private static class XMLFilter extends FileFilter { - // Accept all directories and all XML files. - - public boolean accept(File f) { - if(f.isDirectory()) - return true; - - String s=f.getName(); - if(s.startsWith("AMuon")) return false; - if(s.equals("config.xml")) return false; - if(s.equals("pdg.xml")) return false; - if(s.toLowerCase().lastIndexOf(".xml")==s.length()-".xml".length()) return true; - return false; - } - - public String getDescription() { - return ".xml"; - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/gui/package.html b/graphics/AtlantisJava/src/atlantis/gui/package.html deleted file mode 100644 index 67b415276a2..00000000000 --- a/graphics/AtlantisJava/src/atlantis/gui/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head></head> -<body> -<p>Maintenance of GUI components (layouts, tabbed panes, etc). The -contents (not the structure) of the GUI is defined in config.xml. -</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxGroup.java deleted file mode 100755 index 88cb802db3d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -package atlantis.interactions; - - -public class A3DBoxGroup extends AInteractionGroup { - - private A3DBoxInteraction transformInteraction; - - public A3DBoxGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - transformInteraction=new A3DBoxInteraction(); - this.addInteraction(transformInteraction); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxInteraction.java deleted file mode 100755 index 7d264df9cc7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/A3DBoxInteraction.java +++ /dev/null @@ -1,202 +0,0 @@ -package atlantis.interactions; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.event.KeyEvent; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; - -import javax.swing.JMenuItem; - -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection3DBox; -import atlantis.graphics.ACursorFactory; - -/** - * The Zoom and Rotate interaction. - */ -public class A3DBoxInteraction extends AInteraction implements - ASleepMouseDragListener, AMousePressListener, AEnterExitListener -{ - private static final int ZOOM_MODE = 0; - private static final int HORIZONTAL_ZOOM_MODE = 1; - private static final int VERTICAL_ZOOM_MODE = 2; - private static final int ROTATE_MODE = 3; - - private int d = 10; - private Point2D.Double p0; - private int previousKey = KeyEvent.VK_UNDEFINED; - private int mode; - - public A3DBoxInteraction() - { - super(1, AUTOMATIC_REPAINT, SCREEN_COORDINATES, false); - - // The center of the ellipse is in (0, 0) in User Space - // dummy for now - hr[0] = new Ellipse2D.Double(-d / 2, -d / 2, d, d); - } - - public void connect(AInteractionsManager manager) - { - super.connect(manager); - } - - public int getPressButton() - { - return AInteractionsManager.LEFT; - } - - public int init(Point2D.Double p, int key) - { - keyChange(p, key); - return -1; - } - - public void pressed(Point2D.Double p, int button, int key) - {} - - public int getButton() - { - return AInteractionsManager.LEFT; - } - - public void start(Point2D.Double p, int region, int key) - {} - - private void keyChange(Point2D.Double p, int key) - { - p0 = p; - - switch (key) - { - case KeyEvent.VK_UNDEFINED: - mode = ZOOM_MODE; - break; - - case KeyEvent.VK_H: - mode = HORIZONTAL_ZOOM_MODE; - break; - - case KeyEvent.VK_V: - mode = VERTICAL_ZOOM_MODE; - break; - - case KeyEvent.VK_R: - mode = ROTATE_MODE; - break; - - case KeyEvent.VK_Z: - mode = ZOOM_MODE; - break; - } - } - - public void drag(Point2D.Double p, int region, int key) - { - if (key != previousKey) - { - keyChange(p, key); - previousKey = key; - } - - double zf; - AProjection proj = window.getProjection(); - Point2D.Double center = ((AProjection3DBox) proj).getCenter(window); - - switch (mode) - { - case ZOOM_MODE: - zf = p0.distance(center.getX(), center.getY()) - / p.distance(center.getX(), center.getY()); - ((AProjection3DBox) proj).zoom(zf); - p0 = p; - window.repaintFromScratch(); - break; - case HORIZONTAL_ZOOM_MODE: - zf = Math.abs((p0.getX() - center.getX()) - / (p.getX() - center.getX())); - ((AProjection3DBox) proj).zoomHorizontal(zf); - p0 = p; - window.repaintFromScratch(); - break; - case VERTICAL_ZOOM_MODE: - zf = Math.abs((p0.getY() - center.getY()) - / (p.getY() - center.getY())); - ((AProjection3DBox) proj).zoomVertical(zf); - p0 = p; - window.repaintFromScratch(); - break; - case ROTATE_MODE: - AParameter phiPar = parameterStore.get(proj.getName(), "Phi"); - double height = window.getCurrDisp().getHeight(); - double deltaV = p.getY() - p0.getY(); - phiPar.setD(adjustPhi(phiPar.getD() + 360. * deltaV / height)); - p0 = p; - window.repaintFromScratch(); - break; - } - } - - private double adjustPhi(double phi) - { - while (phi < 0) - phi += 360; - while (phi > 360) - phi -= 360; - return phi; - } - - public void stop() - {} - - public void cancel() - {} - - public void paint(Graphics2D g) - { - Point2D.Double p = ((AProjection3DBox) window.getProjection()).getCenter(window); - g.setColor(Color.red); - g.fillOval((int) (p.x - d / 2), (int) (p.y - d / 2), d, d); - } - - public void entered() - { -// if (region == 0) - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public void exited() - { - // if (region == 0) - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public int getPopupType() - { - return APopupListener.WINDOW_POPUP; - } - - /*public void showPopup(Point p, int region) - { - popupMenu.show(window, p.x, p.y); - }*/ - - public JMenuItem[] getPopupItems() { - return null; - } - - public AModifier[] getModifiers() - { - return new AModifier[] { - new AModifier(KeyEvent.VK_UNDEFINED, false, "Change the volume of the box"), - new AModifier(KeyEvent.VK_Z, false, "Change the volume of the box"), - new AModifier(KeyEvent.VK_H, false, "Change the length of the box"), - new AModifier(KeyEvent.VK_V, false, "Change the height of the box"), - new AModifier(KeyEvent.VK_R, false, "Rotate around axis of box") - }; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AClockGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AClockGroup.java deleted file mode 100755 index 8bfd75d8ffe..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AClockGroup.java +++ /dev/null @@ -1,62 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.ACanvas; -import atlantis.parameters.APar; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import javax.swing.JCheckBox; -import javax.swing.JPanel; - -public class AClockGroup extends AInteractionGroup { - - private AClockInteraction clockInteraction; - private JCheckBox checkbox; - // the panel that will contain the additional controls for the interactions - private JPanel additionalControls; - - public AClockGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - - clockInteraction=new AClockInteraction(); - addInteraction(clockInteraction); - - // create the additional controls panel - additionalControls = new JPanel(); - - checkbox=new JCheckBox("on/off", false); - checkbox.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - switch(e.getStateChange()) { - case ItemEvent.SELECTED: - parameterStore.get("YX", "Clock").setStatus(true); - break; - - case ItemEvent.DESELECTED: - parameterStore.get("YX", "Clock").setStatus(false); - break; - } - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - }); - additionalControls.add(checkbox); - } - - public void connect() { - checkbox.setSelected(parameterStore.get("YX", "Clock").getStatus()); - } - - /** - * this interaction group has additional controls, so return true - */ - - public boolean hasAdditionalControls() { - return true; - } - /** - * returns the additional controls - */ - public JPanel getAdditionalControls() { - return additionalControls; - } - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AClockInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AClockInteraction.java deleted file mode 100755 index 13a44dbe9f5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AClockInteraction.java +++ /dev/null @@ -1,103 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - -import atlantis.graphics.*; -import atlantis.parameters.*; -import atlantis.projection.*; -import atlantis.utils.*; - - -public class AClockInteraction extends AInteraction - implements ASleepMouseDragListener { - - private ALineSegment line; - private double phi; - - public AClockInteraction() { - super(1, WINDOW_TOTAL_REPAINT, WORLD_COORDINATES, false); - // double phi = APar.get("YX","Phi").getD()*AMath.DEGREES_TO_RADIANS+Math.PI; - double phi=Math.toRadians(parameterStore.get("YX", "Phi").getD()); - - line=new ALineSegment(0, 0, 1500*Math.cos(phi), 1500*Math.sin(phi), 10); - hr[0]=line; - } - - public RectangularShape getScreenHotRegion(int region) { - if(region==0) - return new ALineSegment(window.calculateDisplay(line.p1), window.calculateDisplay(line.p2), 10); - else - return null; - } - - public int init(Point2D.Double p, int key) { - return 1; - } - - public int getButton() { - return AInteractionsManager.LEFT; - } - - public void start(Point2D.Double p, int region, int key) { - // if(parameterStore.get("YX","Clock").getStatus()) - if(region==0) - parameterStore.get("YX", "Clock").setD(0.0000001); - else if(region==1) { - AProjection2D projection=(AProjection2D)window.getProjection(); - Point2D.Double p0=projection.inverseNonLinearTransform(p); - - this.phi=Math.atan2(p0.y, p0.x); - } - } - - public void drag(Point2D.Double p, int region, int key) { - if(region==0) { - double phi=Math.atan2(p.y, p.x); - - // phi+=Math.PI; - if(phi<0) phi+=2*Math.PI; - parameterStore.get("YX", "Phi").setD(Math.toDegrees(phi)); - } else if(region==1&¶meterStore.get("YX", "Clock").getStatus()) { - double phiPrime=Math.atan2(p.y, p.x); - double phi0=Math.toRadians(parameterStore.get("YX", "Phi").getD()); - double deltaPhiPrime=phiPrime-phi0; - - if(deltaPhiPrime<-Math.PI) deltaPhiPrime+=2*Math.PI; - if(deltaPhiPrime>Math.PI) deltaPhiPrime-=2*Math.PI; - double deltaPhi=this.phi-phi0; - - if(deltaPhi<-Math.PI) deltaPhi+=2*Math.PI; - if(deltaPhi>Math.PI) deltaPhi-=2*Math.PI; - - if((deltaPhi>0.&&deltaPhiPrime-deltaPhi>0.)||(deltaPhi<0.&&deltaPhiPrime-deltaPhi<0.)) { - double a=(deltaPhi*Math.PI-deltaPhiPrime*Math.abs(deltaPhi))/(deltaPhiPrime-deltaPhi); - - parameterStore.get("YX", "Clock").setD(Math.min(Math.max(Math.PI/a, 0.000001), 7.)); - } else { - parameterStore.get("YX", "Clock").setD(0.000001); - } - } - } - - public void stop() {} - - public void cancel() {} - - public void paint(Graphics2D g) { - // double phi = parameterStore.get("YX","Phi").getD()*AMath.DEGREES_TO_RADIANS+Math.PI; - double phi=Math.toRadians(parameterStore.get("YX", "Phi").getD()); - - line.p2.setLocation(1500*Math.cos(phi), 1500*Math.sin(phi)); - ALineSegment screenLine=(ALineSegment)getScreenHotRegion(0); - - AGraphics ag=AGraphics.makeAGraphics(g); - - ag.updateDrawParameters(frameDrawParameters); - ag.drawLine(screenLine.p1.x, screenLine.p1.y, screenLine.p2.x, screenLine.p2.y); - ag.updateDrawParameters(drawParameters); - ag.drawLine(screenLine.p1.x, screenLine.p1.y, screenLine.p2.x, screenLine.p2.y); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AEnterExitListener.java b/graphics/AtlantisJava/src/atlantis/interactions/AEnterExitListener.java deleted file mode 100755 index 7bc8fdb6fb4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AEnterExitListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package atlantis.interactions; - - -/** - * The listener is supported by AInteractionsManager, - * it generated events when the mouse is entering or exiting a Hot Region. - */ -public interface AEnterExitListener { - - void entered(); - void exited(); -} - diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeChangeListener.java b/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeChangeListener.java deleted file mode 100644 index 5b6c091c363..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeChangeListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package atlantis.interactions; - -/** - * Interface for all FishEyeChangeListener classes. Each time the FishEye - * parameters are changed, all listeners are called with the new paremeters - * @author sboeser - */ -public interface AFishEyeChangeListener { - - /** - * This method gets called each time new fisheye parameters are set - * @param status the new fishEye status - * @param value the new fishEye value - */ - abstract public void fishEyeChange(boolean status, double value); - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeGroup.java deleted file mode 100755 index d2784b78266..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeGroup.java +++ /dev/null @@ -1,116 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.ACanvas; -import java.awt.event.*; -import javax.swing.JCheckBox; -import javax.swing.JFormattedTextField; -import javax.swing.JLabel; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.text.NumberFormat; - -public class AFishEyeGroup extends AInteractionGroup implements AFishEyeChangeListener { - - private final AFishEyeInteraction fishEyeInteraction; - private final JCheckBox checkbox; - private final JFormattedTextField valueField; - // the panel that will contain the additional controls for the interactions - private JPanel additionalControls; - -//Format, label and label string for value field - private NumberFormat valueFormat; - private JLabel valueLabel; - private static String valueString = "Value: "; - - public AFishEyeGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - - fishEyeInteraction=new AFishEyeInteraction(); - addInteraction(fishEyeInteraction); - - // create the additional controls panel - additionalControls = new JPanel(); - - checkbox=new JCheckBox("on/off", false); - checkbox.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - switch(e.getStateChange()) { - case ItemEvent.SELECTED: - fishEyeInteraction.setStatus(true); - //fishEyeInteraction.getParameter("FishEye").setStatus(true); - break; - - case ItemEvent.DESELECTED: - fishEyeInteraction.setStatus(false); - //fishEyeInteraction.getParameter("FishEye").setStatus(false); - break; - } - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - }); - -//Create the label - valueLabel = new JLabel(valueString); - valueFormat = NumberFormat.getNumberInstance(); - valueFormat.setMaximumIntegerDigits(2); - valueField=new JFormattedTextField(valueFormat); - valueField.setToolTipText("Enter fish eye value between 0 and 25"); - valueField.setValue(new Double(0)); - valueField.setColumns(3); - valueField.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - Number value =(Number)valueField.getValue(); - double dvalue = value.doubleValue(); - if(dvalue>0 && dvalue<25) - { - fishEyeInteraction.setValue(dvalue); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - else - { - Double val = new Double(fishEyeInteraction.getValue()); - valueField.setValue(val); - } - } - }); - - JPanel nestedPanel = new JPanel(); - nestedPanel.add(valueLabel); - nestedPanel.add(valueField); - - JPanel borderPanel = new JPanel(new BorderLayout()); - borderPanel.add(checkbox, BorderLayout.WEST); - borderPanel.add(nestedPanel, BorderLayout.EAST); - - additionalControls.add(borderPanel); - - } - - public void connect() { - super.connect(); - - //Only after we are connected to a window, add ourselves as update listener - fishEyeInteraction.addFishEyeChangeListener(this); - } - - public void fishEyeChange(boolean status, double value) { - valueField.setValue(value); - checkbox.setSelected(status); - } - - /** - * FishEye has additional controls, so return true - */ - public boolean hasAdditionalControls() { - return true; - } - - /** - * return the additional controls - */ - public JPanel getAdditionalControls() { - return additionalControls; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeInteraction.java deleted file mode 100755 index b1abf8608b4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AFishEyeInteraction.java +++ /dev/null @@ -1,389 +0,0 @@ -package atlantis.interactions; - -import atlantis.graphics.ACursorFactory; -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.projection.*; -import java.awt.Graphics2D; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.ActionListener; -import javax.swing.JMenuItem; -import java.awt.geom.*; -import java.util.Vector; - -/** - * The FishEye transformation will expand the central part of the display, - * while keeping the outer borders. This helps in e.g. expanding the inner detector region. - **/ - -public class AFishEyeInteraction extends AInteraction - implements ASleepMouseDragListener, ActionListener, AEnterExitListener { - - //A list of listeners for fishEye changes - private Vector<AFishEyeChangeListener> fishEyeChangeListeners = new Vector<AFishEyeChangeListener>(); - - private final int d=20; - private final int region = 0; - private Point2D.Double firstP; - private JMenuItem[] popupItems; - - private final static String TOGGLE_FISHEYE="Fish Eye On/Off"; - - /** - * Create a new FishEye interaction - */ - public AFishEyeInteraction() { - super(1, WINDOW_TOTAL_REPAINT, WORLD_COORDINATES, false); - - hr[0]=new Ellipse2D.Double(0, 0, d, d); - - popupItems = new JMenuItem[] { - new JMenuItem(TOGGLE_FISHEYE), - }; - - for (int i = 0; i < popupItems.length; i++) { - popupItems[i].addActionListener(this); - } - } - - - /** - * Initialize FishEye transformation using an inital point - */ - public int init(Point2D.Double p, int key) { - - AProjection2D projection=(AProjection2D)window.getProjection(); - - firstP=new Point2D.Double(Math.abs(p.x), Math.abs(p.y)); - firstP=projection.inverseNonLinearTransform(firstP); - - return region; - } - - /** - * Returns the button this interaction uses - **/ - public int getButton() { - return AInteractionsManager.LEFT; - } - - /** - * Get projection parameters using APar - **/ - private AParameter getParameter(String name) { - AProjection projection=window.getProjection(); - - if(projection instanceof AProjectionYX) - return parameterStore.get("YX", name); - else if(projection instanceof AProjectionRZ) - return parameterStore.get("RZ", name); - else if(projection instanceof AProjection3D) - return parameterStore.get("3D", name); - else if(projection instanceof AProjectionYZ||projection instanceof AProjectionXZ) - return parameterStore.get("XZ", name); - else if(projection instanceof AProjectionFR) - return parameterStore.get("FR", name); - else if(projection instanceof AProjectionFZ) - return parameterStore.get("FZ", name); - else - throw new Error("Fish Eye should be used ONLY in YX, RZ, FZ and FR"); - } - - /** - * Get new FishEye parameter if mouse has moved to p in YX projection - **/ - private void updateYX(Point2D.Double p, int key) { - double r1=Math.sqrt(firstP.x*firstP.x+firstP.y*firstP.y); - double r2=Math.sqrt(p.x*p.x+p.y*p.y); - double rTo=getParameter("rTo").getD(); - - if(r1<rTo&&r2>rTo) return; - if(r2<rTo&&r1>rTo) return; - - double newFishEyeValue=1000*(r2-r1)/(r1*rTo-r1*r2); - - if(newFishEyeValue<0||newFishEyeValue>25) return; - - setValue(newFishEyeValue); - fireFishEyeChange(getStatus(),getValue()); - } - - /** - * Get new FishEye parameter if mouse has moved to p in RZ projection - **/ - private void updateRZ(Point2D.Double p, int key) { - double newFishEyeValue=0; - - switch(key) { - case KeyEvent.VK_UNDEFINED: - case KeyEvent.VK_F: - case KeyEvent.VK_H: - double z1=firstP.x; - double z2=Math.abs(p.x); - double zTo=getParameter("zTo").getD(); - - if(z1<zTo&&z2>zTo) return; - if(z2<zTo&&z1>zTo) return; - - newFishEyeValue=1000*(z2-z1)/(z1*zTo-z1*z2); - break; - - case KeyEvent.VK_V: - double r1=Math.abs(firstP.y); - double r2=Math.abs(p.y); - double rTo=getParameter("rTo").getD(); - - if(r1<rTo&&r2>rTo) return; - if(r2<rTo&&r1>rTo) return; - - newFishEyeValue=1000*(r2-r1)/(r1*rTo-r1*r2); - break; - } - - if(newFishEyeValue<0||newFishEyeValue>25) return; - setValue(newFishEyeValue); - fireFishEyeChange(getStatus(),getValue()); - } - - /** - * Get new FishEye parameter if mouse has moved to p in XZ projection - **/ - private void updateXZ(Point2D.Double p, int key) { - double newFishEyeValue=0; - - switch(key) { - case KeyEvent.VK_UNDEFINED: - case KeyEvent.VK_F: - case KeyEvent.VK_H: - double z1=firstP.x; - double z2=Math.abs(p.x); - double zTo=getParameter("zTo").getD(); - - if(z1<zTo&&z2>zTo) return; - if(z2<zTo&&z1>zTo) return; - - newFishEyeValue=1000*(z2-z1)/(z1*zTo-z1*z2); - break; - - case KeyEvent.VK_V: - double r1=Math.abs(firstP.y); - double r2=Math.abs(p.y); - double rTo=getParameter("yTo").getD(); - - if(r1<rTo&&r2>rTo) return; - if(r2<rTo&&r1>rTo) return; - - newFishEyeValue=1000*(r2-r1)/(r1*rTo-r1*r2); - break; - } - - if(newFishEyeValue<0||newFishEyeValue>25) return; - setValue(newFishEyeValue); - fireFishEyeChange(getStatus(),getValue()); - } - - /** - * Get new FishEye parameter if mouse has moved to p in Phi-R projection - **/ - private void updateFR(Point2D.Double p, int key) { - double r1=firstP.x; - double r2=p.x; - double rTo=getParameter("rTo").getD(); - - if(r1<rTo&&r2>rTo) return; - if(r2<rTo&&r1>rTo) return; - - double newFishEyeValue=1000*(r2-r1)/(r1*rTo-r1*r2); - - if(newFishEyeValue<0||newFishEyeValue>25) return; - - setValue(newFishEyeValue); - fireFishEyeChange(getStatus(),getValue()); - } - - /** - * Get new FishEye parameter if mouse has moved to p in Phi-Z projection - **/ - private void updateFZ(Point2D.Double p, int key) { - double z1=Math.abs(firstP.x); - double z2=Math.abs(p.x); - double zTo=getParameter("zTo").getD(); - - if(z1<zTo&&z2>zTo) return; - if(z2<zTo&&z1>zTo) return; - - double newFishEyeValue=1000*(z2-z1)/(z1*zTo-z1*z2); - - if(newFishEyeValue<0||newFishEyeValue>25) return; - - setValue(newFishEyeValue); - fireFishEyeChange(getStatus(),getValue()); - } - - /** - * Change FishEye parameter for corresponding projection - * if mouse is draged - **/ - public void drag(Point2D.Double p, int region, int key) { - if(!getParameter("FishEye").getStatus()) return; - - AProjection proj=window.getProjection(); - - if(proj instanceof AProjectionYX) - updateYX(p, key); - else if(proj instanceof AProjectionRZ||proj instanceof AProjection3D) - updateRZ(p, key); - else if(proj instanceof AProjectionXZ||proj instanceof AProjectionYZ) - updateXZ(p, key); - else if(proj instanceof AProjectionFR) - updateFR(p, key); - else if(proj instanceof AProjectionFZ) - updateFZ(p, key); - } - - // Empty interface implementations - public void stop() {} - public void start(Point2D.Double p, int region, int key) {} - public void cancel() {} - public void paint(Graphics2D g) {} - - public int getPopupType() { - return APopupListener.WINDOW_POPUP; - } - - /*public void showPopup(Point p, int region) { - popupMenu.show(window, p.x, p.y); - }*/ - - public JMenuItem[] getPopupItems() { - return popupItems; - } - - - /** - * Implementaiton of the ActionListener - * @param e - */ - public void actionPerformed(ActionEvent e) { - String action=e.getActionCommand(); - - if(action.equals(TOGGLE_FISHEYE)) { - //toggle the fisheye status - setStatus(!getStatus()); - //Update the window - window.repaintFromScratch(); - //And the GUI - fireFishEyeChange(getStatus(),getValue()); - } - } - - /** - * Public method so it can be called from the AFishEyeGroup to change the - * fish eye amount to a fixed value - * @param value the new value - */ - public void setValue(double value){ - getParameter("FishEye").setD(value); - } - - /** - * Return FishEye value (e.g to update the FishEye panel) - * @return the fishEye value - */ - public double getValue(){ - return getParameter("FishEye").getD(); - } - - /** - * Public method so it can be called externally from the AFishEyeGroup - * @param status true or false - */ - public void setStatus(boolean status) { - getParameter("FishEye").setStatus(status); - } - - /** - * @return the current fishEye status(true or false) - */ - public boolean getStatus() { - return getParameter("FishEye").getStatus(); - } - - /** - * Gets called each time we enter a window in which this interaction is active - */ - public void entered(){ - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getFishEyeCursor()); - } - - /** - * Gets called each time we leave a window in which this interaction is active - */ - public void exited(){ - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - /** - * Return modifier keys for this projection - * - F for Fast (only detectors are update) - * - V for react only to Vertical mouse movement (only in RZ and XZ projection) - * - H for react only to Horizontal mouse movement (only in RZ and XZ projection, default) - **/ - public AModifier[] getModifiers(){ - if(window.getProjection() instanceof AProjectionRZ || - window.getProjection() instanceof AProjectionXZ) { - return new AModifier[] { - new AModifier(KeyEvent.VK_F, false, "Fast (data not drawn)"), - new AModifier(KeyEvent.VK_V, false, "Vertically defined FishEye"), - new AModifier(KeyEvent.VK_UNDEFINED, false, "Horizontally defined FishEye"), - new AModifier(KeyEvent.VK_H, false, "Horizontally defined FishEye") - }; - } else { - - return new AModifier[] { - new AModifier(KeyEvent.VK_F, false, "Fast (data not drawn)") - }; - } - } - - /** - * Add a new listener for FishEyeChange incidents - * @param listener to be added to list - */ - public void addFishEyeChangeListener(AFishEyeChangeListener listener) { - //Add this listener - fishEyeChangeListeners.addElement(listener); - //And bring it up to date - listener.fishEyeChange(getStatus(), getValue()); - - } - - /** - * Remove a listener from the liste - * @param listener to be removed from list - */ - public void removeFishEyeChangeListener(AFishEyeChangeListener listener) { - //Remove this listener - fishEyeChangeListeners.removeElement(listener); - } - - /** - * Call fishEyeChange method of all FishEyeChange listeners - * @param status the new fisheye status - * @param value the new fisheye value - */ - private void fireFishEyeChange(boolean status, double value) { - - // Loop over all listeners - for (AFishEyeChangeListener listener : fishEyeChangeListeners) - { - // give them the new status - listener.fishEyeChange(status,value); - } - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AInteraction.java deleted file mode 100755 index 446aedc3f93..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AInteraction.java +++ /dev/null @@ -1,323 +0,0 @@ -package atlantis.interactions; - -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.Point2D; -import java.awt.geom.RectangularShape; -import java.awt.Point; -import javax.swing.JPopupMenu; -import javax.swing.JMenuItem; - -import atlantis.canvas.AWindow; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.gui.APopupHelper; -import atlantis.parameters.APar; -import atlantis.utils.APolygon; - -/** - * The abstract supperclass of all the Atlantis interactions. - */ -public abstract class AInteraction -{ - protected static APar parameterStore = APar.instance(); - - /** When the inteaction does'nt need repainting */ - public final static int NO_REPAINT = 0; - - /** - * When the inteaction needs an automatic repainting (acoording to its hot - * regions) - */ - public final static int AUTOMATIC_REPAINT = 1; - - /** When the inteaction needs an repaint of all windows */ - public final static int ALL_WINDOWS_REPAINT = 3; - - /** When the inteaction needs to reapint from scratch its window */ - public final static int WINDOW_TOTAL_REPAINT = 4; - - /** - * The constant used to specify that the interaction wants SCREEN - * COORDINATES - */ - public final static int SCREEN_COORDINATES = 0; - - /** The constant used to specify that the interaction wants WORLD COORDINATES */ - public final static int WORLD_COORDINATES = 1; - - protected final static ADrawParameters frameDrawParameters = new ADrawParameters(true, AColorMap.BK, 4, 1, 1, AGraphics.SYMBOL_FILLED_BOX); - - protected final static ADrawParameters drawParameters = new ADrawParameters(true, AColorMap.WH, 4, 1, 0, AGraphics.SYMBOL_FILLED_BOX); - - protected AWindow window; - protected static final int ctrlPtSize = 1; - protected RectangularShape[] hr; - protected Point2D.Double[] pt; - protected Rectangle oldAffectedRegion; - protected int hotRegionsCount; - protected int repaintMode; - protected int coordinatesType; - protected boolean isPrintable; - - /** - * Creates a new Interaction. - * - * @param hotRegionsCount The number of hot regions used be the interaction - * @param repaintMode The type of repaint wanted. Could be: NO_REPAINT, - * AUTOMATIC_REPAINT, WINDOW_REPAINT, ALL_WINDOWS_REPAINT, - * WINDOW_TOTAL_REPAINT, ALL_WINDOWS_TOTAL_REPAINT. - * @param coordinatesType Could be: SCREEN_COORDINATES, WORLD_COORDINATES. - * @param isPrintable A boolean which indicates whether or not this - * interaction should be printable. - */ - public AInteraction(int hotRegionsCount, int repaintMode, int coordinatesType, boolean isPrintable) - { - - this.hotRegionsCount = hotRegionsCount; - this.repaintMode = repaintMode; - this.coordinatesType = coordinatesType; - this.isPrintable = isPrintable; - - hr = new RectangularShape[hotRegionsCount]; - - /* - * pt = new Point2D.Double[getPointsToIncludeCount()]; for (int i = 0; i < - * pt.length; i++) pt[i] = new Point2D.Double(0, 0); - */ - } - - /** - * Called by the InteractionsManager when the interaction gets connected to - * it. - */ - public void connect(AInteractionsManager manager) - { - this.window = manager.getWindow(); - } - - /** - * Called by the InteractionsManager when the interaction gets disconnected - * from it. - */ - public void disconnect() - { - this.window = null; - } - - /** - * Called by the window on which this interaction works in order to allow - * the interaction to draw on it. - * - * @param g The graphical context on which to draw. - */ - public abstract void paint(Graphics2D g); - - /** - * This method should convert any hot region used by interaction from user - * coordinates to screen coordinates. - * - * @param region The number of the hot region which needs to be converted. - * @return The new RectangularShape object which contains the converted - * region. - */ - public RectangularShape getScreenHotRegion(int region) - { - switch (coordinatesType) - { - case AInteraction.SCREEN_COORDINATES: - return hr[region]; - - case AInteraction.WORLD_COORDINATES: - RectangularShape screenShape = (RectangularShape) hr[region].clone(); - Point2D.Double center = window.calculateDisplay(screenShape.getCenterX(), screenShape.getCenterY()); - double w = screenShape.getWidth(); - double h = screenShape.getHeight(); - - screenShape.setFrame(center.x - w / 2, center.y - w / 2, w, h); - return screenShape; - - default: - return null; - } - } - - /** - * Returns an APolygon made up of the first 4 Hot Regions. - * - * @return The APolygon. - */ - public APolygon getAPolygon() - { - APolygon p = new APolygon(); - - for (int i = 0; i < 4; i++) - p.addPoint(hr[i].getCenterX(), hr[i].getCenterY()); - - return p; - } - - /** - * Sets the x-coordinate of the center of a RectangularShape. - * - * @param shape The shape to set the center to. - * @param x The new x-coordinate of the center. - */ - protected void setCenterX(RectangularShape shape, double x) - { - double w = shape.getWidth(); - double h = shape.getHeight(); - - shape.setFrame(x - w / 2, shape.getY(), w, h); - } - - /** - * Sets the y-coordinate of the center of a RectangularShape. - * - * @param shape The shape to set the center to. - * @param y The new y-coordinate of the center. - */ - protected void setCenterY(RectangularShape shape, double y) - { - double w = shape.getWidth(); - double h = shape.getHeight(); - - shape.setFrame(shape.getX(), y - h / 2, w, h); - } - - /** - * Sets the center of a RectangularShape to (x, y). - * - * @param shape The shape to set the center to. - * @param x The new x-coordinate of the center. - * @param y The new y-coordinate of the center. - */ - protected void setCenter(RectangularShape shape, double x, double y) - { - double w = shape.getWidth(); - double h = shape.getHeight(); - - shape.setFrame(x - w / 2, y - h / 2, w, h); - } - - /** - * Returns the center of an arbitrary hot-region. - * - * @param s The RectangularShape object the center of which is required - * @return The center in double format - */ - public Point2D.Double getCenter(RectangularShape s) - { - return new Point2D.Double(s.getCenterX(), s.getCenterY()); - } - - /** - * Returns the distance between two hot-regions. The result depends on the - * coordinates type. - * - * @param region1 The first region - * @param region2 The second region - * @return The distance - */ - protected double getRadius(int region1, int region2) - { - double dx = hr[region1].getCenterX() - hr[region2].getCenterX(); - double dy = hr[region1].getCenterX() - hr[region2].getCenterY(); - - return Math.sqrt(dx * dx + dy * dy); - } - - /** - * Returns the distance between a point and a hot-regions. The result - * depends on the coordinates type. - * - * @param x The x coordinate of the point - * @param y The y coordinate of the point - * @param region The region index to be used to get the region itself - * @return The distance - */ - protected double getRadius(double x, double y, int region) - { - double dx = x - hr[region].getCenterX(); - double dy = y - hr[region].getCenterY(); - - return Math.sqrt(dx * dx + dy * dy); - } - - /** - * Returns the distance between the center (0, 0) and a hot-regions. The - * result depends on the coordinates type. - * - * @param s The hot-region - * @return The distance - */ - protected double getRadius(RectangularShape s) - { - return s.getCenterX() * s.getCenterX() + s.getCenterY() * s.getCenterY(); - } - - /** - * Retirns the angle made by the line connecting the two hot-regions and the - * horizontal axis. - * - * @param region1 The first region - * @param region2 The second region - * @return the angle in radians. - */ - protected double getAngle(int region1, int region2) - { - double dx = hr[region1].getCenterX() - hr[region2].getCenterX(); - double dy = hr[region1].getCenterY() - hr[region2].getCenterY(); - - if (dx != 0 || dy != 0) - // is this correct - return Math.atan2(dx, dy); - else - return 0.; - } - - protected void drawActivePoint(double x, double y, AGraphics g) - { - g.updateDrawParameters(frameDrawParameters); - g.drawSymbol(x, y); - g.updateDrawParameters(drawParameters); - g.drawSymbol(x, y); - } - - protected void drawActivePoint(int region, AGraphics g) - { - g.updateDrawParameters(frameDrawParameters); - g.drawSymbol(hr[region].getCenterX(), hr[region].getCenterY()); - g.updateDrawParameters(drawParameters); - g.drawSymbol(hr[region].getCenterX(), hr[region].getCenterY()); - } - - protected void drawLine(int region1, int region2, AGraphics g) - { - g.drawLine(hr[region1].getCenterX(), hr[region1].getCenterY(), hr[region2].getCenterX(), hr[region2].getCenterY()); - } - - public boolean isPrintable() - { - return isPrintable; - } - - public AModifier[] getModifiers() - { - return new AModifier[0]; - } - - public void showPopupMenu(Point p, int region) { - APopupHelper.showPopupMenu(p, window, getPopupItems()); - } - - public JPopupMenu getPopupMenu() { - return APopupHelper.getPopupMenu(getPopupItems()); - } - - public JMenuItem[] getPopupItems() { - return null; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AInteractionGroup.java deleted file mode 100755 index fece4376137..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionGroup.java +++ /dev/null @@ -1,143 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.ACanvas; -import atlantis.parameters.APar; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import java.util.Vector; - - -/** - * The InteractionGroup groups interactions of the same kind under a single - * object. The InteractionToolBar deals with the InteractionGroups instead - * of dealing with the interactions directly. - */ -public abstract class AInteractionGroup { - protected static APar parameterStore = APar.instance(); - - /** A group type which once made current affects only the window in which it works*/ - public static final int WINDOW_GROUP=0; - - /** A group type which once made current affects all the windows of the Canvas*/ - public static final int CANVAS_GROUP=1; - - protected String name; - protected String toolTip; - protected AInteractionsManager iManager; - private int groupType; - private boolean isCurrent=false; - private Vector<AInteraction> interactions; - - /** - * Creates an InteractionGroup of a specific type - * and connected to some InteractionsManager - * @param groupType The type of the interface. Can be: WINDOW_GROUP or CANVAS_GROUP - * @param iManager The InteractionsManager to which this group will be connected. - */ - public AInteractionGroup(int groupType, AInteractionsManager iManager) { - - this.groupType=groupType; - this.iManager=iManager; - - interactions=new Vector<AInteraction>(); - } - - public void setGroupName(String name) { - this.name=name; - } - - public String getGroupName() { - return name; - } - - public void setToolTip(String toolTip) { - this.toolTip=toolTip; - } - - public String getToolTip() { - return toolTip; - } - - public JMenuItem getPopupItem() { - JMenuItem item=new JMenuItem(name); - - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - ACanvas.getCanvas().getCurrentWindow().getInteractionToolBar().setSelectedGroup(name); - } - }); - - return item; - } - - /** - * Called by the InteractionsManager when the group gets connected to it. - */ - public void connect() {} - - /** - * Called by the InteractionsManager when the group gets disconnected from it. - */ - public void disconnect() {} - - public boolean isWindowGroup() { - return(groupType==WINDOW_GROUP); - } - - public boolean isCanvasGroup() { - return(groupType==CANVAS_GROUP); - } - - /** - * Checks if any additional controls are provided by the current interaction group - * @return true if the interaction group has additional controls - */ - public boolean hasAdditionalControls() { return false; } - - /** - * Returns the additional controls for the current interaction group - * @return the panel containing the additional controls - */ - - public JPanel getAdditionalControls() { return new JPanel(); } - - /** - * Registers a new interaction which will be available with this group. - * @param i The Interaction to be registered. - */ - protected void addInteraction(AInteraction i) { - interactions.addElement(i); - if(isCurrent) - iManager.setContext(this); - } - - /** - * Removes a previously registered interaction from the group. - * @param i The Interaction to be removed. - */ - protected void removeInteraction(AInteraction i) { - interactions.remove(i); - } - - /** - * Removes all previously registered interactions from the group. - */ - protected void removeAllInteractions() { - interactions.clear(); - } - - public Vector<AInteraction> getInteractions() { - return interactions; - } - - /** - * Used to help copying of group. The group should set its internal state to be - * the same as the state of the given group. - * @param givenGroup The group to be copied. - */ - public void setGroupState(AInteractionGroup givenGroup) {} - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsConfigReader.java b/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsConfigReader.java deleted file mode 100644 index 8b4dcaeb95f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsConfigReader.java +++ /dev/null @@ -1,69 +0,0 @@ -package atlantis.interactions; - -import java.util.Hashtable; -import java.util.Map.Entry; -import java.util.Set; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.projection.AProjectionsManager; - -/** - * Handles the "Interactions" node in the XML configuration file: - * <ul> - * <li>store the InteractionControl node for each projection</li> - * <li>process the lists of available/default projections in demo mode</li> - * </ul> - * - * @author waugh - */ -public class AInteractionsConfigReader { - - /** The set of XML nodes with projection information (name : node). */ - private final static Hashtable<String,Node> projectionNodes = new Hashtable<String, Node>(); - - /** - * Read and process the Interactions information from the XML configuration file. - * - * @param node The XML Node which contains the <bold>Interactions</bold> node. - */ - public static void readInteractions(Node node) { - initProjectionNodes(node); - setAvailableProjectionsInDemoMode(); - } - - /** - * Get the configuration XML node corresponding to a given projection. - * - * @param projectionName the name of the projection - * @return the corresponding InteractionControl node - */ - public static Node getNode(String projectionName) { - return projectionNodes.get(projectionName); - } - - private static void initProjectionNodes(Node node) { - NodeList childNodes=node.getChildNodes(); - for(int i=0; i<childNodes.getLength(); i++) { - Node child=childNodes.item(i); - - if(child.getNodeType()==Node.ELEMENT_NODE) { - String name=child.getAttributes().getNamedItem("projectionName").getNodeValue(); - projectionNodes.put(name, child); - } - } - } - - private static void setAvailableProjectionsInDemoMode() { - Set<Entry<String, Node>> entries = projectionNodes.entrySet(); - for (Entry<String,Node> entry : entries) { - String name = entry.getKey(); - Node node = entry.getValue(); - boolean availableInDemoMode = node.getAttributes().getNamedItem("availableInDemoMode").getNodeValue().equals("YES"); - boolean defaultInDemoMode = node.getAttributes().getNamedItem("defaultInDemoMode").getNodeValue().equals("YES"); - if (availableInDemoMode) AProjectionsManager.makeProjectionAvailableInDemoMode(name); - if (defaultInDemoMode) AProjectionsManager.makeProjectionDefaultInDemoMode(name); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsManager.java b/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsManager.java deleted file mode 100755 index 40b0a2d484f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AInteractionsManager.java +++ /dev/null @@ -1,535 +0,0 @@ -package atlantis.interactions; - -import java.awt.Rectangle; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.WindowFocusListener; -import java.awt.event.WindowEvent; -import java.awt.geom.Point2D; -import java.awt.geom.RectangularShape; -import java.util.LinkedList; -import java.util.Vector; - -import javax.swing.JPopupMenu; -import javax.swing.SwingUtilities; -import javax.swing.JMenuItem; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.gui.AEventQueue; -import atlantis.gui.AInteractionToolBar; -import atlantis.gui.APointerPositionWindow; -import atlantis.gui.APreferencesControl; -import atlantis.projection.AProjectionTrackResidual; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjection2D; - -/** - * The InteractionsManager connects to the corresponding window in order to - * provide basic functionality to the interactions. - */ -public class AInteractionsManager -implements MouseListener, MouseMotionListener, WindowFocusListener { - - public final static int LEFT=0; - public final static int MIDDLE=1; - public final static int RIGHT=2; - public final static int ALL=3; - - private final static int safetySize=5; - - private AWindow window; //The window that is monitored by this interaction manager - private LinkedList<AInteraction> interactions; //A list of all the interactions linked to this manager - private AInteraction dragInter; - private int dragInterHotRegion; -// private AInteraction mcInteraction; //This one is set but not used by anything -// private int mcRegion; //This one is set but not used by anything - private RectangularShape[] old_hr; - private AInteractionGroup previousInterface; - private AModifier[] mouseModifiers; - private boolean origAlias=false; - - /** - * Creates an InteractionsManager to work with a specific window. - * @param _window The window with wich the InteractionsManager should work. - */ - public AInteractionsManager(AWindow _window) { - this.window=_window; - - interactions=new LinkedList<AInteraction>(); -// mcInteraction=null; -// mcRegion=-1; - - window.addMouseListener(this); - window.addMouseMotionListener(this); - - mouseModifiers=new AModifier[] { - new AModifier(KeyEvent.VK_O, true, "Output of pointer position"), - new AModifier(KeyEvent.VK_W, true, "Window Menu pops up"), - new AModifier(KeyEvent.VK_I, true, "Interaction Manager pops up"), - new AModifier(KeyEvent.VK_UNDEFINED, true, "Interaction Menu pops up") - }; - } - - public AModifier[] getMouseModifiers() { - return mouseModifiers; - } - - // Implementation of MouseListener - - public void mousePressed(MouseEvent e) { - - if(!ACanvas.getCanvas().getCurrentWindow().equals(window)) - ACanvas.getCanvas().setCurrentWindow(window.getName()); - - if(AInteractionsManager.isIntRightMouseButton(e)) - switch(AEventQueue.getKeyboardState()) { - - case KeyEvent.VK_W: - if(!(window.getProjection() instanceof AProjectionTrackResidual)) - AWindow.getPopupMenu().show(window, e.getX(), e.getY()); - return; - - case KeyEvent.VK_I: - JPopupMenu menu=AInteractionToolBar.getInteractionMenu(window); - - menu.show(window, e.getX(), e.getY()); - return; - - case KeyEvent.VK_O: - Point2D.Double position =window.calculateUser(e.getX(),e.getY()); - //If LegoPlot need to alter phi coord using reverse of the adjustPhi function - if( window.getProjection() instanceof AProjectionLegoPlot) - position.x=-AProjectionLegoPlot.adjustPhi(window,-position.x,position.y); - //Apply inverse non-linear transforms, if in 2D projection - if ( window.getProjection() instanceof AProjection2D) - position = ((AProjection2D)window.getProjection()).inverseNonLinearTransform(position); - //Add labels - String positionX = window.getProjection().getXLabel() + parseUnits(position.x, window.getProjection().getXUnits()); - String positionY = window.getProjection().getYLabel() + parseUnits(position.y, window.getProjection().getYUnits()); - APreferencesControl.setPosMenuItem(true);//shows window if not already visible - APointerPositionWindow.getInstance().toFront();//brings to front - APointerPositionWindow.append(positionX + ", " + positionY + "\n"); - return; - } - - processMousePressed(e); - - if(dragInter!=null) { - dragInter.hr=old_hr; - ((AMouseDragListener)dragInter).cancel(); -// if(dragInter instanceof AEnterExitListener) -// ((AEnterExitListener)dragInter).exited(dragInterHotRegion); - repaintInteraction(dragInter); - dragInter=null; - return; - } - - if(AInteractionsManager.isIntRightMouseButton(e)) - if(processPopupShow(e)) - return; - - if(setupDraggingByHotRegion(e)) return; - if(initializeSleepingInteraction(e)) return; - } - - private boolean processPopupShow(MouseEvent e) { - for(int i=interactions.size()-1; i>=0; i--) { - AInteraction interaction=(AInteraction)interactions.get(i); - - for(int region=0; region<interaction.hr.length; region++) { - if(interaction.getScreenHotRegion(region).contains(e.getPoint())) { - interaction.showPopupMenu(e.getPoint(), region); - return true; - } - } - } - - for(int i=interactions.size()-1; i>=0; i--) { - AInteraction interaction=(AInteraction)interactions.get(i); - - //Turn off right click menu for pick interaction - JMenuItem[] projmenu = (interaction instanceof APickInteraction) ? null : window.getProjection().getPopupItems(); - JMenuItem[] intmenu = (interaction instanceof APickInteraction) ? null : interaction.getPopupItems(); - - JPopupMenu finalmenu = new JPopupMenu(); - - // Combine projection and interaction menus - for (int it = 0; intmenu != null && it < intmenu.length; it++) { - finalmenu.add(intmenu[it]); - } - - if (projmenu != null && projmenu.length > 0 && - intmenu != null && intmenu.length > 0) { - - finalmenu.addSeparator(); - } - - for (int it = 0; projmenu != null && it < projmenu.length; it++) { - finalmenu.add(projmenu[it]); - } - - if (finalmenu.getComponentCount() != 0) { - finalmenu.show(window, (int)e.getPoint().getX(), (int)e.getPoint().getY()); - } - } - - return false; - } - - public void mouseReleased(MouseEvent e) { - if(dragInter!=null) { - ((AMouseDragListener)dragInter).stop(); -// if(dragInter instanceof AEnterExitListener) -// ((AEnterExitListener)dragInter).exited(dragInterHotRegion); - repaintInteraction(dragInter); - dragInter=null; - } - //reset anti-alias - if(origAlias && !(dragInter instanceof ASelection)) - APreferencesControl.setAliasMenuItem(true); - } - - public void mouseClicked(MouseEvent e) {} - - /** - * This function is called each time we enter the window this interaction manager is assigned to - */ - public void mouseEntered(MouseEvent e) { - - //Loop over interaction list from the end - for(int i=interactions.size()-1; i>=0; i--) { - - //get the interaction - AInteraction interaction=(AInteraction)interactions.get(i); - - //Check if this one listens to Enter/Exit events - if (interaction instanceof AEnterExitListener){ - ((AEnterExitListener)interaction).entered(); - } - } - } - - /** - * This function is called each time we exit the window this interaction manager is assigned to - */ - public void mouseExited(MouseEvent e) { - - //Loop over interaction list from the end - for(int i=interactions.size()-1; i>=0; i--) { - - //get the interaction - AInteraction interaction=(AInteraction)interactions.get(i); - - //Check if this one listens to Enter/Exit events - if (interaction instanceof AEnterExitListener) - ((AEnterExitListener)interaction).exited(); - } - } - - private void processMousePressed(MouseEvent e) { - //update if using anti-alias so can switch off during drag - if(!(dragInter instanceof ASelection)) - origAlias = APreferencesControl.getAliasMenuItem(); - for(int i=interactions.size()-1; i>=0; i--) { - AInteraction interaction=(AInteraction)interactions.get(i); - - if(!(interaction instanceof AMousePressListener)) continue; - AMousePressListener clickListener=(AMousePressListener)interaction; - - if(clickListener.getPressButton()!=AInteractionsManager.ALL) - if(clickListener.getPressButton()!=getButton(e)) continue; - Point2D.Double p=null; - - switch(interaction.coordinatesType) { - case AInteraction.SCREEN_COORDINATES: - p=new Point2D.Double(e.getX(), e.getY()); - break; - - case AInteraction.WORLD_COORDINATES: - // p = window.calculateUser(inverseNonLinearTransform(e.getPoint())); - p=window.calculateUser(e.getPoint()); - break; - } - clickListener.pressed(p, getButton(e), AEventQueue.getKeyboardState()); - setTopZOrder(interaction); - repaintInteraction(interaction); - } - } - - // Implementation of MouseMotionListener - - public void mouseDragged(MouseEvent e) { - if(dragInter==null) return; - - //switch off anti-alias - if(origAlias && !(dragInter instanceof ASelection)) - APreferencesControl.setAliasMenuItem(false); - Point2D.Double p=new Point2D.Double(e.getX(), e.getY()); - - if(dragInter.coordinatesType==AInteraction.WORLD_COORDINATES) - // p = dragInter.manager.getWindow().calculateUser(inverseNonLinearTransform(p)); - p=window.calculateUser(p); - - ((AMouseDragListener)dragInter).drag(p, dragInterHotRegion, AEventQueue.getKeyboardState()); - repaintInteraction(dragInter); - } - - //This function is called every time the mouse is moved on the window - public void mouseMoved(MouseEvent e) { - } - - // Implementation of WindowsFocusListener - - /** - * Get called each time the canvas has obtained a focus - */ - public void windowGainedFocus(WindowEvent e) { - //Check if the mouse is over this window (or any of its children) - if (getWindow().getMousePosition(true) != null){ - //raise a mouseEntered event, so the cursor gets updated - this.mouseEntered(null); - } - } - - /** - * Get called each time the canvas has lost a focus - */ - public void windowLostFocus(WindowEvent e) {} - - //Methods belonging to this class - - /** - * Returns all the interactions associated with this InteractionsManager. - * @return The LinkedList containing the interactions. - * DO NOT CHANGE THIS LINKEDLIST, JUST READ IT. - */ - public LinkedList<AInteraction> getInteractions() { - return interactions; - } - - public AWindow getWindow() { - return window; - } - - /** - * This function disconnects the current pannel and all it's - * interactions from the InteractionsManager. - */ - public void forgetContext() { - // Disconnect all the old interactions - if(previousInterface!=null) previousInterface.disconnect(); - for(int i=0; i<interactions.size(); i++) { - AInteraction inter=(AInteraction)interactions.get(i); - - inter.disconnect(); - } - - // Clear the list and repaint the window - interactions.clear(); - window.repaint(); - } - - /** - * Sets the current interaction interface and adds its interactions to the list - * (removing first the old interface and its interactions). - * @param iFace The new interface. - */ - public void setContext(AInteractionGroup iFace) { - forgetContext(); - - if(iFace!=null) - { - // add to the list, connect and repaint the new interactions - Vector<AInteraction> iFaceInter=iFace.getInteractions(); - - for(int i=0; i<iFaceInter.size(); i++) { - AInteraction inter=(AInteraction)iFaceInter.get(i); - interactions.addLast(inter); - inter.connect(this); - repaintInteraction(inter); - } - - iFace.connect(); - } - previousInterface=iFace; - } - - private void repaintInteraction(AInteraction interaction) { - switch(interaction.repaintMode) { - case AInteraction.NO_REPAINT: - return; - - case AInteraction.ALL_WINDOWS_REPAINT: - window.repaint(); - ACanvas.getCanvas().repaintOthers(window); - return; - - case AInteraction.WINDOW_TOTAL_REPAINT: - window.repaintFromScratch(); - return; - - case AInteraction.AUTOMATIC_REPAINT: - Rectangle regionToRedraw=interaction.getScreenHotRegion(0).getBounds(); - - for(int i=1; i<interaction.hr.length; i++) - regionToRedraw.add(interaction.getScreenHotRegion(i).getBounds()); - - if((interaction.pt!=null)&&(interaction.pt.length!=0)) - for(int i=0; i<interaction.pt.length; i++) - regionToRedraw.add(getScreenPointToInclude(interaction, i)); - - regionToRedraw.x-=safetySize; - regionToRedraw.y-=safetySize; - regionToRedraw.width+=2*safetySize; - regionToRedraw.height+=2*safetySize; - - if(interaction.oldAffectedRegion==null) - window.repaint(regionToRedraw); - else - window.repaint(SwingUtilities.computeUnion(interaction.oldAffectedRegion.x, - interaction.oldAffectedRegion.y, interaction.oldAffectedRegion.width, - interaction.oldAffectedRegion.height, new Rectangle(regionToRedraw))); - - interaction.oldAffectedRegion=regionToRedraw; - return; - } - } - - /** - * This method converts the specified "point to include" from user - * coordinates to screen coordinates. - * If the point is already in screen coordinates it just returns it. - */ - private Point2D.Double getScreenPointToInclude(AInteraction interaction, int n) { - switch(interaction.coordinatesType) { - case AInteraction.SCREEN_COORDINATES: - return interaction.pt[n]; - - case AInteraction.WORLD_COORDINATES: - return window.calculateDisplay(interaction.pt[n]); - - default: - return null; - } - } - - private boolean setupDraggingByHotRegion(MouseEvent e) { - for(int i=interactions.size()-1; i>=0; i--) { - AInteraction interaction=(AInteraction)interactions.get(i); - - if(!(interaction instanceof AMouseDragListener)) continue; - AMouseDragListener dInter=(AMouseDragListener)interaction; - - if(dInter.getButton()!=getButton(e)) continue; - - for(int j=0; j<interaction.hr.length; j++) { - if(interaction.getScreenHotRegion(j).contains(e.getPoint())) { - dragInter=interaction; - dragInterHotRegion=j; - - old_hr=new RectangularShape[dragInter.hr.length]; - for(int region=0; region<dragInter.hr.length; region++) - old_hr[region]=(RectangularShape)dragInter.hr[region].clone(); - - Point2D.Double p=new Point2D.Double(e.getX(), e.getY()); - - if(interaction.coordinatesType==AInteraction.WORLD_COORDINATES) - p=window.calculateUser(p); - - // add this statement to guarantee "p0" in AZMRInteraction is initialized - // maybe need more analysis here - if(dragInter instanceof AZMRInteraction) - ((ASleepMouseDragListener)dragInter).init(p, AEventQueue.getKeyboardState()); - - setTopZOrder(dragInter); - ((AMouseDragListener)dragInter).start(p, dragInterHotRegion, AEventQueue.getKeyboardState()); - repaintInteraction(dragInter); - return true; - } - } - } - return false; - } - - private boolean initializeSleepingInteraction(MouseEvent e) { - for(int i=interactions.size()-1; i>=0; i--) { - AInteraction interaction=(AInteraction)interactions.get(i); - - if(interaction instanceof ASleepMouseDragListener) { - ASleepMouseDragListener sdListener=(ASleepMouseDragListener)interaction; - - if(sdListener.getButton()==getButton(e)) { - dragInter=interaction; - - old_hr=new RectangularShape[dragInter.hr.length]; - for(int region=0; region<dragInter.hr.length; region++) - old_hr[region]=(RectangularShape)dragInter.hr[region].clone(); - - Point2D.Double p=new Point2D.Double(e.getX(), e.getY()); - - if(interaction.coordinatesType==AInteraction.WORLD_COORDINATES) - p=window.calculateUser(p); - - dragInterHotRegion=((ASleepMouseDragListener)dragInter).init(p, AEventQueue.getKeyboardState()); - - setTopZOrder(dragInter); - ((AMouseDragListener)dragInter).start(p, dragInterHotRegion, AEventQueue.getKeyboardState()); -// if(dragInter instanceof AEnterExitListener) -// ((AEnterExitListener)dragInter).entered(dragInterHotRegion); - - repaintInteraction(dragInter); - return true; - } - } - } - - return false; - } - - private void setTopZOrder(AInteraction ineraction) { - interactions.remove(ineraction); - interactions.addLast(ineraction); - repaintInteraction((AInteraction)interactions.getLast()); - } - - private int getButton(MouseEvent e) { - if(SwingUtilities.isLeftMouseButton(e)) - return LEFT; - else if(SwingUtilities.isMiddleMouseButton(e)) - return MIDDLE; - else if(AInteractionsManager.isIntRightMouseButton(e)) - return RIGHT; - else - return -1; - } - - private static boolean isIntRightMouseButton(MouseEvent e) - { - return SwingUtilities.isRightMouseButton(e) || - AEventQueue.getIntRightMouseButton(); - } - - private String parseUnits(double d, String units) - { - //covert units and value units shown are cm by default - double abs = Math.abs(d); - if(units.equals("(cm)")) - { - if (abs >= 100.) - return ": " + Math.rint(1000. * d / 100.) / 1000. + " m"; - else if (abs >= 1.) - return ": " + Math.rint(1000. * d / 1.) / 1000. + " cm"; - else if (abs >= 0.1) - return ": " + Math.rint(1000. * d / 0.1) / 1000. + " mm"; - else - return ": " + Math.rint(d / 0.0001) + " um"; - } - else - { - return ": " + Math.rint(1000. * d / 1.) / 1000. + units; - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ALineSegment.java b/graphics/AtlantisJava/src/atlantis/interactions/ALineSegment.java deleted file mode 100755 index 7fe3cfe1acf..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ALineSegment.java +++ /dev/null @@ -1,165 +0,0 @@ -package atlantis.interactions; - - -import atlantis.utils.AVector; -import java.awt.geom.*; - - -/** - * A implementation of the java.awt.RectangularShape which - * represents a segment of a line. - */ -public class ALineSegment extends RectangularShape implements PathIterator { - - Point2D.Double p1; - Point2D.Double p2; - double thickness; - - public ALineSegment(Point2D.Double p1, Point2D.Double p2, double thickness) { - this.p1=p1; - this.p2=p2; - this.thickness=thickness; - } - - public ALineSegment(double x1, double y1, double x2, double y2, double thickness) { - this.p1=new Point2D.Double(x1, y1); - this.p2=new Point2D.Double(x2, y2); - this.thickness=thickness; - } - - private Point2D.Double[] calculateNodes() { - AVector v1=new AVector(p1, p2).makeUnitary().scale(thickness/2).rotate(Math.PI/2); - AVector v2=new AVector(p1, p2).makeUnitary().scale(thickness/2).rotate(-Math.PI/2); - - Point2D.Double[] p=new Point2D.Double[4]; - - p[0]=new Point2D.Double(p1.x+v1.dx, p1.y+v1.dy); - p[1]=new Point2D.Double(p2.x+v1.dx, p2.y+v1.dy); - p[2]=new Point2D.Double(p2.x+v2.dx, p2.y+v2.dy); - p[3]=new Point2D.Double(p1.x+v2.dx, p1.y+v2.dy); - - return p; - } - - public Rectangle2D getBounds2D() { - Point2D.Double[] p=calculateNodes(); - - double minX, minY, maxX, maxY; - - minX=maxX=p[0].x; - minY=maxY=p[0].y; - - for(int i=1; i<p.length; i++) { - if(p[i].x<minX) minX=p[i].x; - if(p[i].x>maxX) maxX=p[i].x; - if(p[i].y<minY) minY=p[i].y; - if(p[i].y>maxY) maxY=p[i].y; - } - - return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY); - } - - public boolean contains(double x, double y) { - boolean c=false; - Point2D.Double[] p=calculateNodes(); - - for(int i=0, j=p.length-1; i<p.length; j=i++) - if((((p[i].y<=y)&&(y<p[j].y))||((p[j].y<=y)&&(y<p[i].y))) - &&(x<(p[j].x-p[i].x)*(y-p[i].y)/(p[j].y-p[i].y)+p[i].x) - ) c=!c; - - return c; - } - - public boolean intersects(double x, double y, double w, double h) { - return false; - } - - public boolean contains(double x, double y, double w, double h) { - return false; - } - - public PathIterator getPathIterator(AffineTransform at) { - lineNumber=-1; - return this; - } - - public void setFrame(double x, double y, double w, double h) {} - - public boolean isEmpty() { - return false; - } - - public double getWidth() { - return getBounds2D().getWidth(); - } - - public double getHeight() { - return getBounds2D().getHeight(); - } - - public double getX() { - return getBounds2D().getX(); - } - - public double getY() { - return getBounds2D().getY(); - } - - // PathIterator implementation - int lineNumber; - - // Returns the coordinates and type of the current path segment in the iteration. - public int currentSegment(double[] coords) { - Point2D.Double[] p=calculateNodes(); - - if(lineNumber==-1) { - coords[0]=p[0].x; - coords[1]=p[0].y; - return PathIterator.SEG_MOVETO; - } - - if(lineNumber==4) return PathIterator.SEG_CLOSE; - - coords[0]=p[lineNumber].x; - coords[1]=p[lineNumber].y; - return PathIterator.SEG_LINETO; - } - - public int currentSegment(float[] coords) { - Point2D.Double[] p=calculateNodes(); - - if(lineNumber==-1) { - coords[0]=(float)p[0].x; - coords[1]=(float)p[0].y; - return PathIterator.SEG_MOVETO; - } - - if(lineNumber==4) return PathIterator.SEG_CLOSE; - - coords[0]=(float)p[lineNumber].x; - coords[1]=(float)p[lineNumber].y; - return PathIterator.SEG_LINETO; - } - - // Returns the winding rule for determining the interior of the path. - public int getWindingRule() { - return PathIterator.WIND_NON_ZERO; - } - - public boolean isDone() { - if(lineNumber>4) - return true; - else - return false; - } - - public void next() { - lineNumber++; - } - - public String toString() { - return "ALineSegment["+p1.x+", "+p1.y+", "+p2.x+", "+p2.y+"]"; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AModifier.java b/graphics/AtlantisJava/src/atlantis/interactions/AModifier.java deleted file mode 100644 index d1b57d65f83..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AModifier.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * AModifier.java - * - * Created on 16 July 2007, 12:17 by Adam Davison <adamd at hep.ucl.ac.uk> - */ - -package atlantis.interactions; - -import java.awt.event.KeyEvent; - -/** - * A structure for holding details of an interaction modifier key - * - * @author Adam Davison - */ -public class AModifier { - - public static AModifier nothing = new AModifier(KeyEvent.VK_UNDEFINED, false, "Default interaction"); - - private int m_keycode; - private char m_keychar; - - // Won't use mouse button id's from MouseEvent because i have some memory - // of this not being very platform independant, can fiddle this if we need - // middle click or something later. - private boolean m_right; - - private String m_desc; - - public AModifier(int keycode, boolean right, String desc) { - m_keycode = keycode; - m_keychar = (char)keycode; - m_right = right; - m_desc = desc; - } - - public int getKeyCode() { - return m_keycode; - } - - public char getKeyChar() { - return m_keychar; - } - - public boolean getRightClick() { - return m_right; - } - - public String toKeyString() { - String ret = ""; - if (m_keycode != KeyEvent.VK_UNDEFINED) { - ret = String.valueOf(m_keychar); - if (m_right) { - ret = ret.concat(" + "); - } - } - - if (m_right) { - ret = ret.concat("Right"); - } - - return ret; - } - - public String toDescString() { - return m_desc; - } - - // Two interactions are pretty much the same even if they have different - // descriptions, hence I won't override equals here and cause problems - // putting these things in containers or anything. - public boolean sameAs(AModifier acmp) { - if (acmp == null) { return false; } - - if (acmp.getKeyCode() != getKeyCode()) { - return false; - } - - if (acmp.getRightClick() != getRightClick()) { - return false; - } - - return true; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AMouseDragListener.java b/graphics/AtlantisJava/src/atlantis/interactions/AMouseDragListener.java deleted file mode 100755 index 155f9126f2e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AMouseDragListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package atlantis.interactions; - - -import java.awt.geom.*; - - -/** - * Implemented by the interactions to get drag events - * from the InteractionsManager. - */ -public interface AMouseDragListener { - - // Should return one of the LEFT, MIDDLE or RIGHT constants from AWindow - int getButton(); - - void start(Point2D.Double p, int region, int key); - void drag(Point2D.Double p, int region, int key); - void stop(); - void cancel(); -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AMousePressListener.java b/graphics/AtlantisJava/src/atlantis/interactions/AMousePressListener.java deleted file mode 100755 index a71c7ca2187..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AMousePressListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package atlantis.interactions; - - -import java.awt.geom.*; - - -/** - * Implemented by the interactions to get press events - * from the InteractionsManager. - */ -public interface AMousePressListener { - - int getPressButton(); - void pressed(Point2D.Double p, int button, int key); -} - diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ANZMRGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/ANZMRGroup.java deleted file mode 100644 index 713743861be..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ANZMRGroup.java +++ /dev/null @@ -1,16 +0,0 @@ -package atlantis.interactions; - -/** - * - * @author Adam Davison - */ -public class ANZMRGroup extends AInteractionGroup { - - private ANZMRInteraction transformInteraction; - - public ANZMRGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - transformInteraction=new ANZMRInteraction(); - this.addInteraction(transformInteraction); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ANZMRInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/ANZMRInteraction.java deleted file mode 100644 index 99ac11f99f3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ANZMRInteraction.java +++ /dev/null @@ -1,80 +0,0 @@ -package atlantis.interactions; - -import atlantis.nge.ANManager; -import atlantis.nge.ANPickDrawer; -import atlantis.nge.ANPickResultPrinter; -import atlantis.nge.ANProjection; -import atlantis.nge.ANProjection3D; -import atlantis.nge.ANProjectionPhysics; -import java.awt.Graphics2D; -import java.awt.geom.Point2D.Double; - -/** - * - * @author Adam Davison, Mark Stockton - */ -public class ANZMRInteraction extends AInteraction implements ASleepMouseDragListener, AMousePressListener { - - private Double m_last = null; - - public ANZMRInteraction() { - super(0, WINDOW_TOTAL_REPAINT, SCREEN_COORDINATES, false); - } - - @Override - public void paint(Graphics2D g) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void doRotation(double dx, double dy) { - ANProjection np = (ANManager.getManager().getFrameManager(window).getTargetProjection()); - if (np instanceof ANProjection3D) { - ((ANProjection3D) np).dPhi((float) (dx / 4.0)); - ((ANProjection3D) np).dElev((float) (dy / 4.0)); - }else if (np instanceof ANProjectionPhysics) { - ((ANProjectionPhysics) np).dPhi((float) (dx / 4.0)); - ((ANProjectionPhysics) np).dElev((float) (dy / 4.0)); - } - } - - public int getButton() { - return AInteractionsManager.LEFT; - } - - public void start(Double p, int region, int key) { - m_last = p; - } - - public void drag(Double p, int region, int key) { - double dx = (p.getX() - m_last.getX()); - double dy = (p.getY() - m_last.getY()); - - doRotation(dx,dy); - - m_last = p; - } - - public void stop() { - - } - - public void cancel() { - - } - - public int init(Double p, int key) { - return -1; - } - - public int getPressButton() { - return AInteractionsManager.ALL; - } - - public void pressed(Double p, int button, int key) { - System.out.println("ZMR PRESS: " + p.getX() + ":" + p.getY()); - ANPickDrawer pd = new ANPickDrawer(window, window.getWidth(), window.getHeight(), - (int)p.getX(), (int)p.getY(), new ANPickResultPrinter()); - pd.doPick(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AParallelogramSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/AParallelogramSelection.java deleted file mode 100755 index 75e3f512cbc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AParallelogramSelection.java +++ /dev/null @@ -1,119 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -public class AParallelogramSelection extends ASelection { - final private static int STARTING_WIDTH=25; - - public AParallelogramSelection() { - super(6); - } - - public int init(Point2D.Double p, int key) { - isValid=false; - - setCenter(hr[0], p.x-STARTING_WIDTH, p.y); - setCenter(hr[1], p.x-STARTING_WIDTH, p.y); - setCenter(hr[2], p.x+STARTING_WIDTH, p.y); - setCenter(hr[3], p.x+STARTING_WIDTH, p.y); - setCenter(hr[4], p.x, p.y); - setCenter(hr[5], p.x, p.y); - - region=5; - return region; - } - - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - - double dx, dy; - - switch(region) { - case 4: - dx=hr[0].getCenterX()-hr[4].getCenterX(); - dy=hr[0].getCenterY()-hr[4].getCenterY(); - - setCenter(hr[region], p.x, p.y); - setCenter(hr[0], p.x+dx, p.y+dy); - setCenter(hr[3], p.x-dx, p.y-dy); - break; - - case 5: - dx=hr[1].getCenterX()-hr[5].getCenterX(); - dy=hr[1].getCenterY()-hr[5].getCenterY(); - - setCenter(hr[region], p.x, p.y); - setCenter(hr[1], p.x+dx, p.y+dy); - setCenter(hr[2], p.x-dx, p.y-dy); - break; - - case 0: - case 3: - setCenter(hr[region], p.x, p.y); - - dx=hr[region].getCenterX()-hr[4].getCenterX(); - dy=hr[region].getCenterY()-hr[4].getCenterY(); - - if(region==3) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[1], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - setCenter(hr[2], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - setCenter(hr[0], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[3], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - break; - - case 1: - case 2: - setCenter(hr[region], p.x, p.y); - - dx=hr[region].getCenterX()-hr[5].getCenterX(); - dy=hr[region].getCenterY()-hr[5].getCenterY(); - - if(region==2) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[1], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - setCenter(hr[2], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - setCenter(hr[0], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[3], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - break; - } - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - /** - * Make the affine transform which corresponds to this - * paralleogram-shaped selection. - */ - public Point2D.Double[] getCorners() { - int first=getUpperLeftRegion(); - - // Calculate the opposite index. - int third=(first+2)%4; - - // Now use the cross-product to determine which of the - // remaining points is the one which keep the path going - // clockwise. - int second=(first+1)%4; - double dx0=hr[third].getCenterX()-hr[first].getCenterX(); - double dy0=hr[third].getCenterY()-hr[first].getCenterY(); - double dx1=hr[second].getCenterX()-hr[first].getCenterX(); - double dy1=hr[second].getCenterY()-hr[first].getCenterY(); - - if(dx0*dy1-dy0*dx1>0) second=(first+3)%4; - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/APickGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/APickGroup.java deleted file mode 100755 index e45447479dd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/APickGroup.java +++ /dev/null @@ -1,102 +0,0 @@ -package atlantis.interactions; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JComboBox; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPanel; - -import atlantis.canvas.ACanvas; -import atlantis.parameters.APar; - -public class APickGroup extends AInteractionGroup -{ - private APickInteraction pickInteraction; - private JComboBox mode; - // the panel that will contain the additional controls for the interactions - private JPanel additionalControls; - - private final static String HITS = "Event Data"; - private final static String DETECTORS = "Detectors"; - - public APickGroup(AInteractionsManager iManager) - { - super(AInteractionGroup.CANVAS_GROUP, iManager); - - // create the additional controls panel - additionalControls = new JPanel(); - - pickInteraction = new APickInteraction(); - addInteraction(pickInteraction); - mode = new JComboBox(); - mode.addItem(HITS); - mode.addItem(DETECTORS); - if (parameterStore.get("Event", "PickingMode").getI() == 0) - mode.setSelectedItem(HITS); - else - mode.setSelectedItem(DETECTORS); - mode.addActionListener(new ModeListener()); - additionalControls.add(mode); - } - - /** - * pick has additional controls, so return true - */ - public boolean hasAdditionalControls() { - return true; - } - - /** - * returns the additional controls - */ - public JPanel getAdditionalControls() { - return additionalControls; - } - - public JMenuItem getPopupItem() - { - // generating the menu - JMenu menu = new JMenu(name); - ActionListener l = new PopUpListener(); - - menu.add(HITS).addActionListener(l); - menu.add(DETECTORS).addActionListener(l); - return menu; - } - - public void connect() - { - super.connect(); - if (parameterStore.get("Event", "PickingMode").getI() == 0) - mode.setSelectedItem(HITS); - else - mode.setSelectedItem(DETECTORS); - } - - class PopUpListener implements ActionListener - { - public void actionPerformed(ActionEvent e) - { - ACanvas.getCanvas().getCurrentWindow().getInteractionToolBar().setSelectedGroup(name); - mode.setSelectedItem(e.getActionCommand()); - if (e.getActionCommand().equals(HITS)) - parameterStore.get("Event", "PickingMode").setI(0); - else if (e.getActionCommand().equals(DETECTORS)) - parameterStore.get("Event", "PickingMode").setI(1); - } - } - - class ModeListener implements ActionListener - { - public void actionPerformed(ActionEvent e) - { - if (mode.getSelectedItem().equals(HITS)) - parameterStore.get("Event", "PickingMode").setI(0); - else if (mode.getSelectedItem().equals(DETECTORS)) - parameterStore.get("Event", "PickingMode").setI(1); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/APickInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/APickInteraction.java deleted file mode 100755 index a12cdce3ee1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/APickInteraction.java +++ /dev/null @@ -1,419 +0,0 @@ -package atlantis.interactions; - -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.AWTException; -import java.awt.geom.Point2D; -import java.awt.event.KeyEvent; -import javax.swing.SwingUtilities; - -import atlantis.list.AList; -import atlantis.list.AListManager; -import atlantis.nge.ANManager; -import atlantis.nge.ANProjectionPhysics; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.ALVL1TriggerTowerData; -import atlantis.data.AMuonHitData; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionNPhysics; -import atlantis.projection.AProjectionTrackResidual; -import atlantis.projection.AProjectionsManager; -import atlantis.event.AData; -import atlantis.data.AJetData; -import atlantis.data.ACalorimeterData; -import atlantis.data.ALArData; -import atlantis.data.ASVxData; -import atlantis.data.ARVxData; -import atlantis.data.ATILEData; -import atlantis.data.ATrackData; -import atlantis.graphics.ACursorFactory; -import atlantis.graphics.APickingGraphics2D; -import atlantis.utils.AMath; - - - -public class APickInteraction extends AInteraction implements AMousePressListener, AEnterExitListener -{ - - public APickInteraction() - { - super(0, NO_REPAINT, SCREEN_COORDINATES, false); - } - - - - public int getPressButton() - { - return AInteractionsManager.ALL; - } - - - - private void showCaloPulseShapePlot(AList picked, boolean withcurve) - { - Integer i = APickingGraphics2D.getPickedHitIndex(); - if(i != null) - { - ACalorimeterData c = (ACalorimeterData) picked.getSource(); - c.plotPulseShapes(i.intValue(), withcurve); - } - } - - - - private void showTriggerPulseShapePlot(AList picked) - { - Integer i = APickingGraphics2D.getPickedHitIndex(); - if(i != null) - { - ALVL1TriggerTowerData t = (ALVL1TriggerTowerData) picked.getSource(); - t.plotPulseShapes(i.intValue()); - } - } - - - - private void ignorePickedItem(AList picked) - { - Integer i = APickingGraphics2D.getPickedHitIndex(); - if(i != null) - { - AData d = (AData) picked.getSource(); - String k = d.getStoreGateKey() != null ? ":" + d.getStoreGateKey() : ""; - String m = "\n\n" + d.getNameScreenName() + k + " ID " + - d.getIdFromIndex(i.intValue()) + " (index " + i.intValue() + - ") will be invisible and ignored " + - "(until removed from the Invisible list)"; - AOutput.alwaysAppend(m, ALogInterface.WARNING); - AListManager.getInstance().addInvisible(picked); - } - - } - - - - private void showMuonSector(AList picked) - { - if(picked.getSource() instanceof AMuonHitData) - { - int sector = ((AMuonHitData) picked.getSource()).getSector(picked.getItems()[0]); - int signRZ = ((AMuonHitData) picked.getSource()).getRZSign(picked.getItems()[0]); - if(signRZ == -1) - { - sector = (sector + 8) % 16; - } - parameterStore.get("YZ", "Phi").setD(sector * 22.5); - window.repaintFromScratch(); - } - } - - - - private void showTrackResidualPlot(AList picked) - { - AData pickedData = picked.getSource(); - if(pickedData instanceof ATrackData) - { - if(((ATrackData)pickedData).getResidualStatus()) - { - APickingGraphics2D.showTrackResiduals(window, - (int) APickingGraphics2D.getPickedH(), (int) APickingGraphics2D.getPickedV()); - } - else - { - AOutput.append("\nNo residual information available for this track\n", - ALogInterface.PICK); - } - } - } - - private void showJetView(AList picked) - { - AData pickedData = picked.getSource(); - if(pickedData instanceof AJetData){ - - // Use window "B" to show jets - String jetWindowName = "B"; - if(!ACanvas.getCanvas().isValidWindowName(jetWindowName)) - { - AOutput.append("\nWindow " + jetWindowName + " is not available in current layout" - + "\n", ALogInterface.WARNING); - } - else if(window.getName().equals(jetWindowName)){ - AOutput.append("\nPlease select jet view from a window other than window " + jetWindowName, ALogInterface.WARNING); - } - else{ - AWindow jetWindow = ACanvas.getCanvas().getWindow(jetWindowName); - - //set as NYX to get transition - AProjectionNPhysics jetProj = - (AProjectionNPhysics) AProjectionsManager.getProjection("NPhysics"); - - //setup the projection - ACanvas.getCanvas().moveToFrontWindow(jetWindowName); - jetWindow.setProjection(jetProj); - - //configure the projection - jetProj.configureFrame(ANManager.getManager().getFrameManager(jetWindow)); - ANProjectionPhysics finalProj = (ANProjectionPhysics) ANManager.getManager().getFrameManager(jetWindow).getTargetProjection(); - - AJetData jd = ((AJetData) pickedData); - int index=picked.getItems()[0]; - finalProj.lookAt(jd, index); - } - } - } - - - /** - * @param picked AList - * Check if picked data is SimVertex or RecVertex (RVx) and use the values - * as Atlantis primary vertex: Projection->eta/phi menu - */ - private void setAtlantisPrimaryVertex(AList picked) - { - Integer i = APickingGraphics2D.getPickedHitIndex(); - AData pickedData = picked.getSource(); - double[] vtx = null; - - if(i != null) - { - if(pickedData instanceof ARVxData) - { - vtx = ((ARVxData) pickedData).getVertex(i.intValue()); - } - if(pickedData instanceof ASVxData) - { - vtx = ((ASVxData) pickedData).getVertex(i.intValue()); - } - - if(vtx != null) - { - parameterStore.get("Event", "XVtx").setD(vtx[0]); - parameterStore.get("Event", "YVtx").setD(vtx[1]); - parameterStore.get("Event", "ZVtx").setD(vtx[2]); - AOutput.append("\n\nPrimary vertex set: Projection->" + - AMath.PHI + AMath.ETA + ":\n" + - " XVtx = " + String.format("%.5f",vtx[0]) + " cm\n" + - " YVtx = " + String.format("%.5f",vtx[1]) + " cm\n" + - " ZVtx = " + String.format("%.5f",vtx[2]) + " cm\n", - ALogInterface.WARNING); - } - } - - } // setAtlantisPrimaryVertex() ----------------------------------------- - - - - public void pressed(Point2D.Double p, int button, int key) - { - Point ps = null; - Point pw = null; - int pickingMode = parameterStore.get("Event", "PickingMode").getI(); - - if(button == AInteractionsManager.LEFT) - { - if(key == KeyEvent.VK_C) - { - AListManager.getInstance().clearHighlightAndMassCalculation(); - } - else - { - Rectangle bounds = window.getBounds(); - bounds.setLocation(0, 0); - window.paintWindowFromScratch(new APickingGraphics2D(bounds, - pickingMode, new Point((int) p.x, (int) p.y))); - - // this call prints pick information (calls datatype's getHitInfo()) - if(!(key == KeyEvent.VK_L)) - { - APickingGraphics2D.printPicked(); - } - AList picked = APickingGraphics2D.getPickedHit(); - - if(picked != null && pickingMode == APickingGraphics2D.PICK_HITS_AND_TRACKS) - { - - // highlight by default (not only when key==KeyEvent.VK_H) - AListManager.getInstance().highlight(picked); - - // try to always show calo pulse shapes plot by default - // if no key modifier is pressed - if(picked.getSource() instanceof ACalorimeterData && - key == KeyEvent.KEY_LOCATION_UNKNOWN) - { - showCaloPulseShapePlot(picked, true); - } - // 2009-01-19 for LAr only, see comment at - // the ALArData.plotADCCounts() method - if(picked.getSource() instanceof ACalorimeterData && - key == KeyEvent.VK_D) - { - showCaloPulseShapePlot(picked, false); - } - if(picked.getSource() instanceof ATILEData && - key == KeyEvent.VK_T) { - - Integer i = APickingGraphics2D.getPickedHitIndex(); - if (i != null) { - ATILEData c = (ATILEData) picked.getSource(); - c.plotPulseShapesWithTiming(i.intValue()); - } - } - if(picked.getSource() instanceof ALVL1TriggerTowerData && - key == KeyEvent.KEY_LOCATION_UNKNOWN) - { - showTriggerPulseShapePlot(picked); - } - - if(picked.getSource() instanceof AJetData) - { - double phi = ((AJetData) picked.getSource()).getPhi(picked.getItems()[0]); - parameterStore.get("XZ", "Phi").setD(Math.toDegrees(phi)); - } - - switch(key) - { - case KeyEvent.VK_A: - AListManager.getInstance().add(picked); - break; - case KeyEvent.VK_S: - showMuonSector(picked); - break; - case KeyEvent.VK_N: - APickingGraphics2D.navigatePicked(); - break; - case KeyEvent.VK_R: - showTrackResidualPlot(picked); - break; - case KeyEvent.VK_V: - setAtlantisPrimaryVertex(picked); - break; - case KeyEvent.VK_I: - ignorePickedItem(picked); - break; - case KeyEvent.VK_J: - if(parameterStore.get("Prefs", "OpenGL").getStatus()){ - showJetView(picked); - } - break; - case KeyEvent.VK_M: - AListManager.getInstance().massCalc(picked); - break; - case KeyEvent.VK_L: // Mass calculation for Neutral Decay scenarios - AListManager.getInstance().massCalcV0(picked); - break; - case KeyEvent.VK_P: // Calculate delta Phi for picked objects - AListManager.getInstance().deltaR(picked); - break; - - - } // switch - - } - else if(pickingMode == APickingGraphics2D.PICK_DETECTORS) - { - AListManager.getInstance().clearHighlight(); - } - } - - } // if(button == AInteractionsManager.LEFT) - - else if(button == AInteractionsManager.RIGHT) - { - Rectangle bounds = window.getBounds(); - bounds.setLocation(0, 0); - window.paintWindowFromScratch(new APickingGraphics2D(bounds, APickingGraphics2D.MOVE, - new Point((int) p.x, (int) p.y))); - } - - if(pickingMode != APickingGraphics2D.PICK_DETECTORS) - { - if(APickingGraphics2D.getPickedData() != null - || APickingGraphics2D.getPickedResidual() != null) - { - /* int numEvents = Atlantis.getEventManager().getNumberOfEvents(); - if(numEvents > 0) - { - AOutput.append("\n(" + ++numEvents + " events currently displayed)\n", ALogPane.PICK); - }*/ - - //TODO fix to avoid problems with nge - if(window==null) - return; - - pw = new Point(APickingGraphics2D.getPickedH(), APickingGraphics2D.getPickedV()); - if(pw.x != 0 && pw.y != 0) - try - { - ps = new Point(pw); - SwingUtilities.convertPointToScreen(ps, window); - new Robot().mouseMove(ps.x, ps.y); - } - catch(AWTException e) - {} - else - { - AOutput.alwaysAppend("\n\nYou must pick before you can move", ALogInterface.BAD_COMMAND); - } - } - else - { - if(!(window.getProjection() instanceof AProjectionTrackResidual)) - AOutput.alwaysAppend("\n\nNothing to pick", ALogInterface.BAD_COMMAND); - } - } - - } // pressed() ------------------------------------------------------------ - - - public void paint(Graphics2D g) - {} - - /** - * Gets called each time we enter a window in which this interaction is active - */ - public void entered() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getPickCursor()); - } - - /** - * Gets called each time we leave a window in which this interaction is active - */ - public void exited() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public AModifier[] getModifiers() - { - AModifier[] mods = new AModifier[] { - new AModifier(KeyEvent.VK_UNDEFINED, false, "Pick"), - new AModifier(KeyEvent.VK_UNDEFINED, true, "Move to last picked"), - new AModifier(KeyEvent.VK_A, false, "Add to the current (active) list"), - new AModifier(KeyEvent.VK_C, false, "Clear highlighted and calculation lists"), - new AModifier(KeyEvent.VK_D, false, "Plot ADC counts (digits) only"), - new AModifier(KeyEvent.VK_T, false, "Plot raw and cell time pulses (TILE only)"), - new AModifier(KeyEvent.VK_I, false, "Ignore (make invisible) picked hits/tracks"), - new AModifier(KeyEvent.VK_L, false, "Add to the V0 mass calculation list"), - new AModifier(KeyEvent.VK_M, false, "Add to the mass calculation list"), - new AModifier(KeyEvent.VK_P, false, "Calculate Delta R for 2 tracks"), - new AModifier(KeyEvent.VK_N, false, "Navigate (show data associations)"), - new AModifier(KeyEvent.VK_R, false, "Plot track residuals if available"), - new AModifier(KeyEvent.VK_S, false, "Select this muon Sector"), - new AModifier(KeyEvent.VK_V, false, "Set prim.vertex from picked rec/sim vertex"), - new AModifier(KeyEvent.VK_J, false, "Jet view (OpenGL only)") - }; - - return mods; - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/APopupListener.java b/graphics/AtlantisJava/src/atlantis/interactions/APopupListener.java deleted file mode 100755 index f7b462043d6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/APopupListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package atlantis.interactions; - - -import java.awt.Point; - - -/** - * The interactions implement this listener to get popup trigger events. - */ -public interface APopupListener { - int REGION_POPUP=0; - int WINDOW_POPUP=1; - - int getPopupType(); - void showPopup(Point p, int region); -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ARectangleSelection.java deleted file mode 100755 index 818dd6120b2..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleSelection.java +++ /dev/null @@ -1,95 +0,0 @@ -package atlantis.interactions; - -import java.awt.Graphics2D; -import java.awt.geom.Point2D; - -import atlantis.graphics.ACursorFactory; -import atlantis.graphics.AGraphics; - -public class ARectangleSelection extends ASelection implements AEnterExitListener -{ - public ARectangleSelection() - { - super(4); - } - - public int init(Point2D.Double p, int key) - { - isValid = false; - - for (int i = 0; i < 4; i++) - setCenter(hr[i], p.x, p.y); - - this.region = 2; - return region; - } - - public void drag(Point2D.Double p, int region, int key) - { - isValid = true; - - // Update the active control point. - setCenter(hr[region], p.x, p.y); - - // Get the opposite control point. - int oppCtrlPt = (region + 2) % 4; - double xOpp = hr[oppCtrlPt].getCenterX(); - double yOpp = hr[oppCtrlPt].getCenterY(); - - // Now choose the next control point so that we maintain a - // clockwise order to the points. - int otherCtrlPt = ((p.x < xOpp && p.y > yOpp) || (p.x > xOpp && p.y < yOpp)) ? 1 : 3; - - otherCtrlPt = (region + otherCtrlPt) % 4; - - // Set the other two control points. - setCenter(hr[otherCtrlPt], p.x, yOpp); - otherCtrlPt = (otherCtrlPt + 2) % 4; - setCenter(hr[otherCtrlPt], xOpp, p.y); - } - - public void paint(Graphics2D g) - { - if (!isValid) - return; - - AGraphics ag = AGraphics.makeAGraphics(g); - - ag.updateDrawParameters(frameDrawParameters); - ag.drawPolygon(getAPolygon()); - ag.updateDrawParameters(drawParameters); - ag.drawPolygon(getAPolygon()); - drawActivePoint(region, ag); - } - - public Point2D.Double[] getCorners() - { - int first = getUpperLeftRegion(); - - // Calculate the adjacent partner and the opposite corner. - int second = (first + 1) % 4; - int third = (first + 2) % 4; - - return convert(first, second, third); - } - - /** - * Get called each time we enter a window in which this interaction is - * active - */ - public void entered() - { - // Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getRectSelectCursor()); - } - - /** - * Get called each time we leave a window in which this interaction is active - */ - public void exited() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleVPSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ARectangleVPSelection.java deleted file mode 100755 index 8d26e25ff33..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleVPSelection.java +++ /dev/null @@ -1,524 +0,0 @@ -package atlantis.interactions; - -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.Point2D; -import javax.swing.JMenuItem; -import java.util.List; -import java.util.ArrayList; - -import atlantis.event.AData; -import atlantis.event.AEventManager; -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.ACalorimeterData; -import atlantis.event.AEvent; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.ADragListener; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.utils.AMath; -import atlantis.utils.A3Vector; - -public class ARectangleVPSelection extends ARectangleSelection - implements ActionListener, ADragListener -{ - - public final static String RUBBERBAND_WHOLE_WINDOW = "Rubberband Whole Window"; - public final static String ZOOM_LAR = "Zoom LAr"; - public final static String ZOOM_CALORIMETERS = "Zoom Calorimeters"; - public final static String CUT_ETAPHI = "Cut ( " + AMath.ETA + AMath.PHI + " cut )"; - public final static String PRINT_CONTENTS = "Print Contents"; - public final static String SHOW_IN_3DBOX = "Show in 3DBox"; - public final static String TURN_OFF_ETAPHI_CUT = "Turn off " + CUT_ETAPHI; - - private static AEventManager eventManager = AEventManager.instance(); - - public ARectangleVPSelection() - { - super(); - - addActionButton(ZOOM_LAR, this, this); - addActionButton(ZOOM_CALORIMETERS, this, this); - addActionButton(CUT_ETAPHI, this, this); - addActionButton(RUBBERBAND_WHOLE_WINDOW, this, this); - addActionButton(PRINT_CONTENTS, this, this); - addActionButton(SHOW_IN_3DBOX, this, this); - - } - - - - @Override - public JMenuItem[] getPopupItems() - { - ArrayList al = new ArrayList(); - if (window.getUnzoomPossible()) - { - JMenuItem item = new JMenuItem("Unzoom"); - al.add(item); - item.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoom(); - } - }); - } - if(window.getUnzoomAllPossible(ZOOM_LAR)) - { - JMenuItem item = new JMenuItem("Unzoom LAr"); - al.add(item); - item.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) { - window.unzoom(ARectangleVPSelection.ZOOM_LAR); - } - }); - } - if(window.getUnzoomAllPossible(ZOOM_CALORIMETERS)) - { - JMenuItem item = new JMenuItem("Unzoom Calorimeters"); - al.add(item); - item.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) { - window.unzoom(ZOOM_CALORIMETERS); - } - }); - } - if (window.getUnzoomFullPossible()) - { - JMenuItem item = new JMenuItem("Unzoom Full"); - al.add(item); - item.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoomFull(); - } - }); - } - - JMenuItem rww = new JMenuItem(RUBBERBAND_WHOLE_WINDOW); - rww.addActionListener(this); - - JMenuItem toec = new JMenuItem(TURN_OFF_ETAPHI_CUT); - toec.addActionListener(this); - - al.add(rww); - al.add(toec); - - // Can't cast arrays very easily... - JMenuItem[] ret = new JMenuItem[al.size()]; - for (int i = 0; i < al.size(); i++) { - ret[i] = (JMenuItem)al.get(i); - } - - return ret; - } - - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - - if(ZOOM_LAR.equals(action)) - { - performZoom(ZOOM_LAR); - } - else if(ZOOM_CALORIMETERS.equals(action)) - { - performZoom(ZOOM_CALORIMETERS); - } - else if(CUT_ETAPHI.equals(action)) - { - applyCutIn(window.getName()); - } - else if(RUBBERBAND_WHOLE_WINDOW.equals(action)) - { - rubberbandWholeWindow(); - } - else if(PRINT_CONTENTS.equals(action)) - { - performOperationWithCuts(PRINT_CONTENTS); - } - else if(SHOW_IN_3DBOX.equals(action)) - { - tracksTo3DBox(); - } - else if(TURN_OFF_ETAPHI_CUT.equals(action)) - { - turnOffEtaPhiCuts(); - } - - } - - - private void turnOffEtaPhiCuts() - { - parameterStore.get("CutsATLAS", "CutPhi").setStatus(false); - parameterStore.get("CutsATLAS", "CutEta").setStatus(false); - String warning = "\n\nCuts -> ATLAS -> Cut " + AMath.ETA + " deactivated" + - "\nCuts -> ATLAS -> Cut " + AMath.PHI + " deactivated\n\n"; - AOutput.append(warning, ALogInterface.WARNING); - ACanvas.getCanvas().repaintAllFromScratch(); - - } - - - - private void tracksTo3DBox() { - Point2D.Double[] corners = getCorners(); - double eta = (corners[2].x + corners[0].x) / 2.; - double phi = Math.toRadians((corners[2].y + corners[0].y) / 2.); - - A3Vector ray = A3Vector.fromEtaPhiR(eta, phi, 1.0); - - // Need to make sure we change existing 3DBoxes - parameterStore.get("3D", "xAxis").changeScope(AParameter.GLOBAL); - parameterStore.get("3D", "yAxis").changeScope(AParameter.GLOBAL); - parameterStore.get("3D", "zAxis").changeScope(AParameter.GLOBAL); - parameterStore.get("3D", "xAxis").setD(ray.x); - parameterStore.get("3D", "yAxis").setD(ray.y); - parameterStore.get("3D", "zAxis").setD(ray.z); - - // 3DBoxes can be anywhere on the screen: - ACanvas.getCanvas().repaintAllFromScratch(); - } - - - public void dragPerformed(Object from, Object to, int action) - { - if (to instanceof ADnDLabel) - { - applyCutIn(((ADnDLabel) to).getText()); - } - else if (to instanceof AWindow) - { - applyCutIn(((AWindow) to).getName()); - } - } - - - - private boolean checkEtaPhiCutValues(double eta, double phi, - double cutPhi, double cutEta) - { - if (!(parameterStore.get("CutsATLAS", "PhiMiddle").validateValue(phi) && - parameterStore.get("CutsATLAS", "EtaMiddle").validateValue(eta) && - parameterStore.get("CutsATLAS", "CutPhi").validateValue(cutPhi) && - parameterStore.get("CutsATLAS", "CutEta").validateValue(cutEta))) - { - String etaphi = AMath.ETA + AMath.PHI; - AOutput.append("\nOperation cancelled: " + etaphi + - " cut values outside allowed range\n", ALogInterface.WARNING); - return false; - - } - else - { - return true; - } - - } - - - - public void applyCutIn(String zoomWindowName) - { - Point2D.Double[] corners = getCorners(); - double eta = (corners[2].x + corners[0].x) / 2.; - double cutEta = Math.abs((corners[2].x - corners[0].x)) / 2.; - double phi = (corners[2].y + corners[0].y) / 2.; - double cutPhi = Math.abs((corners[2].y - corners[0].y)) / 2.; - double rhoVPlot = AProjectionVP.getRhoZoomVPlot(); - double zVPlot = AProjectionVP.getZZoomVPlot(); - double zVtx = parameterStore.get("Event", "ZVtx").getD(); - double zLower = Math.max(Math.min(rhoVPlot * AMath.tanLambda(eta - cutEta) + zVtx, 0.), -zVPlot); - double zUpper = Math.min(Math.max(rhoVPlot * AMath.tanLambda(eta + cutEta) + zVtx, 0.), zVPlot); - - if(! checkEtaPhiCutValues(eta, phi, cutPhi, cutEta)) - { - return; - } - - String currentWindowName = window.getName(); - - parameterStore.selectWindowParameters(zoomWindowName); - parameterStore.get("CutsATLAS", "PhiMiddle").setD(phi); - parameterStore.get("CutsATLAS", "EtaMiddle").setD(eta); - parameterStore.get("CutsATLAS", "CutPhi").setD(cutPhi); - parameterStore.get("CutsATLAS", "CutPhi").setStatus(true); - parameterStore.get("CutsATLAS", "CutEta").setD(cutEta); - parameterStore.get("CutsATLAS", "CutEta").setStatus(true); - - String warning = "\n\nCuts -> ATLAS -> Cut " + AMath.ETA + " now active" + - "\nCuts -> ATLAS -> Cut " + AMath.PHI + " now active\n\n"; - AOutput.append(warning, ALogInterface.WARNING); - - AWindow zoomWindow = ACanvas.getCanvas().getWindow(zoomWindowName); - AProjection zoomProjection = zoomWindow.getProjection(); - - if (zoomProjection instanceof AProjectionFR) - { - zoomWindow.setUserCorners(0., rhoVPlot, phi - cutPhi, phi + cutPhi); - } - else if (zoomProjection instanceof AProjectionFZ) - { - zoomWindow.setUserCorners(zLower, zUpper, phi - cutPhi, phi + cutPhi); - } - else if (zoomProjection instanceof AProjectionVP) - { - if (!zoomWindowName.equals(currentWindowName)) - zoomWindow.setUserCorners(eta - cutEta, eta + cutEta, phi - cutPhi, phi + cutPhi); - } - else if (zoomProjection instanceof AProjectionYX) - { - zoomWindow.setUserCorners(-rhoVPlot, rhoVPlot, -rhoVPlot, rhoVPlot); - } - else if (zoomProjection instanceof AProjectionXZ) - { - double rhoZoom = Math.min(rhoVPlot, 110.); - - zoomWindow.setUserCorners(zLower, zUpper, 0., rhoZoom); - parameterStore.get("XZ", "Phi").setD(AMath.nearestPhiDegrees(phi)); - } - else if (zoomProjection instanceof AProjectionYZ) - { - double rhoZoom = Math.min(rhoVPlot, 110.); - - zoomWindow.setUserCorners(zLower, zUpper, -rhoZoom, rhoZoom); - parameterStore.get("YZ", "Phi").setD(AMath.nearestPhiDegrees(phi)); - } - else if (zoomProjection instanceof AProjectionRZ) - { - zoomWindow.setUserCorners(zLower, zUpper, 0., rhoVPlot); - parameterStore.get("RZ", "Phi").setD(AMath.nearestPhiDegrees(phi)); - } - parameterStore.restoreWindowParameters(); - - // don't repaint just the current window after cut(s) are applied, - // but repaint everything (all windows) - // zoomWindow.repaintFromScratch(); - ACanvas.getCanvas().repaintAllFromScratch(); - - } - - public void performZoom(String typeOfZoom) - { - int numberOfWindows=0; - - if(ZOOM_LAR.equals(typeOfZoom)) - { - numberOfWindows = 4; - } - else if(ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - numberOfWindows = 8; - } - - AWindow currentWindow = window; - String name = currentWindow.getName(); - currentWindow.saveLayout(); - boolean scaleStatus = currentWindow.getScaleStatus(); - Point2D.Double[] zoomedCorners = getCorners(); - layoutChange(typeOfZoom); - int nameIndex=-1; - for (int i = 0; i < numberOfWindows; i++) - { - String wName = Integer.toString(i + 1); - AWindow w = ACanvas.getCanvas().getWindow(wName); - //dont zoom current window as will not save corners correctly - if (w != null && !name.equals(wName)) - { - w.saveParameters(typeOfZoom); - ACanvas.getCanvas().copyWindowSettings(currentWindow.getName(), wName); - w.saveCorners(typeOfZoom); - w.setUserCorners(zoomedCorners); - w.setScaleStatus(scaleStatus); - parameterStore.selectWindowParameters(wName); - parameterStore.get("VP", "Mode").setI(AProjectionVP.MODE_ECAL_LAYER_0 + i); - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(w.getName()); - w.repaintFromScratch(); - } - else if(name.equals(wName)) - { - nameIndex=i; - } - } - //now do zoom of current window if needed - if(nameIndex>0) - { - currentWindow.saveParameters(typeOfZoom); - currentWindow.saveCorners(typeOfZoom); - currentWindow.setUserCorners(zoomedCorners); - currentWindow.setScaleStatus(scaleStatus); - parameterStore.selectWindowParameters(name); - parameterStore.get("VP", "Mode").setI(AProjectionVP.MODE_ECAL_LAYER_0 + nameIndex); - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(name); - currentWindow.repaintFromScratch(); - } - for (int i = 0; i < numberOfWindows; i++) - if (name.equals(Integer.toString(i + 1))) - invalidate(); - } - - public void layoutChange(String typeOfZoom) - { - // change layout - if(!ACanvas.getCanvas().getCurrentLayout().getName().equals("SQUARE")) - { - ACanvas.getCanvas().setCurrentLayout("SQUARE"); - } - - // print info message - AOutput.append("\nWindows changed to: \n",ALogInterface.TITLE); - AOutput.append("Window 1: ECAL sampling 0\n",ALogInterface.NORMAL); - AOutput.append("Window 2: ECAL sampling 1\n",ALogInterface.NORMAL); - AOutput.append("Window 3: ECAL sampling 2\n",ALogInterface.NORMAL); - AOutput.append("Window 4: ECAL sampling 3\n",ALogInterface.NORMAL); - - if(ZOOM_CALORIMETERS.equals(typeOfZoom)) - { - AOutput.append("Window 5: HCAL sampling 0\n",ALogInterface.NORMAL); - AOutput.append("Window 6: HCAL sampling 1\n",ALogInterface.NORMAL); - AOutput.append("Window 7: HCAL sampling 2\n",ALogInterface.NORMAL); - AOutput.append("Window 8: HCAL sampling 3\n",ALogInterface.NORMAL); - } - } - - - private void printContents() - { - // get all data within selection (eta/phi cut already applied) - AEvent event = eventManager.getCurrentEvent(); - StringBuffer output = new StringBuffer("Data inside Rubberband selection:"); - // hits and tracks first - List hitsAndTracks = event.getHitsAndTracks(window.getProjection()); - for(int i = 0; i < hitsAndTracks.size(); i++) - { - String info = ((AData) hitsAndTracks.get(i)).getVPHitInfo(); - if(! "".equals(info)) - { - output.append("\n" + info); - } - } - - // calorimeters (as they are handled differently) - List cal = event.getCalorimeters(); - for (int i = 0; i < cal.size(); i++) - { - ACalorimeterData calorimeter = (ACalorimeterData) cal.get(i); - calorimeter.makeDrawList(); - String info = calorimeter.getVPHitInfo(); - if(! "".equals(info)) - { - output.append("\n" + info); - } - } - - AOutput.alwaysAppend("\n" + output + "\n", ALogInterface.PICK); - - } - - - - /** - * Apply eta phi cuts based on the selected (rubberband region), then - * perform the desired operation with data in the selection and - * restore previous cuts settings. - */ - private void performOperationWithCuts(String operation) - { - // which corners fall into eta/phi rubberband selection - Point2D.Double[] corners = getCorners(); - double eta = (corners[2].x + corners[0].x) / 2.; - double cutEta = Math.abs((corners[2].x - corners[0].x)) / 2.; - double phi = (corners[2].y + corners[0].y) / 2.; - double cutPhi = Math.abs((corners[2].y - corners[0].y)) / 2.; - - if(! checkEtaPhiCutValues(eta, phi, cutPhi, cutEta)) - { - return; - } - - // need to temporarily apply eta/phi cut, but get the current - // eta/phi cut values first and save them - AParameter phiPar = parameterStore.get("CutsATLAS", "PhiMiddle"); - AParameter cutPhiPar = parameterStore.get("CutsATLAS", "CutPhi"); - AParameter etaPar = parameterStore.get("CutsATLAS", "EtaMiddle"); - AParameter cutEtaPar = parameterStore.get("CutsATLAS", "CutEta"); - double oldEta = etaPar.getD(); - double oldCutEta = cutEtaPar.getD(); - boolean oldCutEtaStatus = cutEtaPar.getStatus(); - double oldPhi = phiPar.getD(); - double oldCutPhi = cutPhiPar.getD(); - boolean oldCutPhiStatus = cutPhiPar.getStatus(); - - // set new (temporary) values of eta/phi cuts according to selection - phiPar.setD(phi); - etaPar.setD(eta); - cutPhiPar.setD(cutPhi); - cutPhiPar.setStatus(true); - cutEtaPar.setD(cutEta); - cutEtaPar.setStatus(true); - - if(PRINT_CONTENTS.equals(operation)) - { - printContents(); - } - - // set back the previous eta/phi cut values - phiPar.setD(oldPhi); - etaPar.setD(oldEta); - cutPhiPar.setD(oldCutPhi); - cutPhiPar.setStatus(oldCutPhiStatus); - cutEtaPar.setD(oldCutEta); - cutEtaPar.setStatus(oldCutEtaStatus); - - } // printContents() ---------------------------------------------------- - - - - public void rubberbandWholeWindow() - { - Rectangle curr = window.getCurrDisp(); - - double x = curr.getX(); - double y = curr.getY(); - double w = curr.getWidth(); - double h = curr.getHeight(); - - setCenter(hr[0], x, y); - setCenter(hr[1], x + w, y); - setCenter(hr[2], x + w, y + h); - setCenter(hr[3], x, y + h); - isValid = true; - region = 1; - stop(); - window.repaint(); - oldAffectedRegion = curr; - int safetySize = 5; - - oldAffectedRegion.x -= safetySize; - oldAffectedRegion.y -= safetySize; - oldAffectedRegion.width += 2 * safetySize; - oldAffectedRegion.height += 2 * safetySize; - - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleYXSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ARectangleYXSelection.java deleted file mode 100755 index 0a01c70592c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARectangleYXSelection.java +++ /dev/null @@ -1,320 +0,0 @@ -package atlantis.interactions; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.Point2D; -import java.util.ArrayList; - -import javax.swing.JMenuItem; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.graphics.dnd.ADragListener; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionsManager; - -/** - * Contains the function for selecting zoom endcap layers and summed endcaps - * - * @author Mark Stockton - */ -public class ARectangleYXSelection extends ARectangleSelection implements ActionListener, ADragListener -{ - public final static String ZOOM_SUMMED = "summed"; - public final static String ZOOM_LAYERS = "layers"; - - public ARectangleYXSelection() - { - super(); - addActionButton("Zoom Summed Endcaps", new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if (e.getActionCommand().equals("Zoom Summed Endcaps")) - performZoom(ZOOM_SUMMED); - } - }); - addActionButton("Zoom Endcap Layers -", new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if (e.getActionCommand().equals("Zoom Endcap Layers -")) - zoomLayersMinus(); - } - }); - addActionButton("Zoom Endcap Layers +", new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if (e.getActionCommand().equals("Zoom Endcap Layers +")) - zoomLayersPlus(); - } - }); - addActionButton("Zoom Both Endcap Layers", new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if (e.getActionCommand().equals("Zoom Both Endcap Layers")) - zoomLayersCombined(); - } - }); - } - - public void zoomLayersMinus() - { - parameterStore.get("CutsCalo", "FCAL").setI(0); - parameterStore.get("CutsCalo", "LAr").setI(0); - parameterStore.get("CutsCalo", "HEC").setI(-2); - performZoom(ZOOM_LAYERS); - } - - public void zoomLayersPlus() - { - parameterStore.get("CutsCalo", "FCAL").setI(1); - parameterStore.get("CutsCalo", "LAr").setI(1); - parameterStore.get("CutsCalo", "HEC").setI(2); - performZoom(ZOOM_LAYERS); - } - - public void zoomLayersCombined() - { - parameterStore.get("CutsCalo", "FCAL").setI(-1); - parameterStore.get("CutsCalo", "LAr").setI(-1); - parameterStore.get("CutsCalo", "HEC").setI(-1); - performZoom(ZOOM_LAYERS); - } - - public void performZoom(String typeOfZoom) - { - int numberOfWindows=0; - if(typeOfZoom.equals(ZOOM_SUMMED)) - numberOfWindows=4; - else if(typeOfZoom.equals(ZOOM_LAYERS)) - numberOfWindows=8; - - AWindow currentWindow = window; - String name = currentWindow.getName(); - currentWindow.saveLayout(); - boolean scaleStatus = currentWindow.getScaleStatus(); - Point2D.Double[] zoomedCorners = getCorners(); - //change layout and print info message - layoutChange(typeOfZoom); - int nameIndex=-1; - for (int i = numberOfWindows; i >=1; i--) - { - String wName = Integer.toString(i); - AWindow w = ACanvas.getCanvas().getWindow(wName); - //dont zoom current window as will not save corners correctly - if (w != null && !name.equals(wName)) - { - w.saveParameters(typeOfZoom); - ACanvas.getCanvas().copyWindowSettings(currentWindow.getName(), wName); - w.saveCorners(typeOfZoom); - w.setUserCorners(zoomedCorners); - w.setScaleStatus(scaleStatus); - parameterStore.selectWindowParameters(wName); - - if(typeOfZoom.equals(ZOOM_SUMMED)) - zoomSummedOptions(i-1); - else if(typeOfZoom.equals(ZOOM_LAYERS)) - parameterStore.get("YX", "Mode").setI(AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER + i -1); - - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(w.getName()); - w.repaintFromScratch(); - } - else if(name.equals(wName)) - { - nameIndex=i; - } - } - //now do zoom of current window if needed - if(nameIndex>0) - { - currentWindow.saveParameters(typeOfZoom); - currentWindow.saveCorners(typeOfZoom); - currentWindow.setUserCorners(zoomedCorners); - currentWindow.setScaleStatus(scaleStatus); - parameterStore.selectWindowParameters(name); - if(typeOfZoom.equals(ZOOM_SUMMED)) - zoomSummedOptions(nameIndex-1); - else if(typeOfZoom.equals(ZOOM_LAYERS)) - parameterStore.get("YX", "Mode").setI(AProjectionYX.MODE_LAR_ENDCAP_PRESAMPLER + nameIndex -1); - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(name); - currentWindow.repaintFromScratch(); - } - for (int i = 1; i <= numberOfWindows; i++) - if (name.equals(Integer.toString(i))) - invalidate(); - //if doing layers zoom last window shows rhoZ view - if(typeOfZoom.equals(ZOOM_LAYERS)) - zoomLastWindow(scaleStatus, name); - } - - public void layoutChange(String typeOfZoom) - { - if(typeOfZoom.equals(ZOOM_SUMMED)) - { - //change layout - if(!ACanvas.getCanvas().getCurrentLayout().getName().equals("FOUR SQUARES")) - ACanvas.getCanvas().setCurrentLayout("FOUR SQUARES"); - //print info message - AOutput.append("\nWindows changed to:\n",ALogInterface.TITLE); - AOutput.append("Window 1: LAr Endcap -\n",ALogInterface.NORMAL); - AOutput.append("Window 2: LAr Endcap +\n",ALogInterface.NORMAL); - AOutput.append("Window 3: HEC -\n",ALogInterface.NORMAL); - AOutput.append("Window 4: HEC +\n",ALogInterface.NORMAL); - } - else if(typeOfZoom.equals(ZOOM_LAYERS)) - { - //change layout - if(!ACanvas.getCanvas().getCurrentLayout().getName().equals("SQUARE")) - ACanvas.getCanvas().setCurrentLayout("SQUARE"); - //print info message - AOutput.append("\nWindows changed to:\n",ALogInterface.TITLE); - AOutput.append("Window 1: LAr Endcap Presampler\n",ALogInterface.NORMAL); - AOutput.append("Window 2: LAr Endcap 1\n",ALogInterface.NORMAL); - AOutput.append("Window 3: LAr Endcap 2\n",ALogInterface.NORMAL); - AOutput.append("Window 4: LAr Endcap 3\n",ALogInterface.NORMAL); - AOutput.append("Window 5: HEC 1\n",ALogInterface.NORMAL); - AOutput.append("Window 6: HEC 2\n",ALogInterface.NORMAL); - AOutput.append("Window 7: HEC 3\n",ALogInterface.NORMAL); - AOutput.append("Window 8: HEC 4\n",ALogInterface.NORMAL); - AOutput.append("Window 9: rhoZ view showing both endcaps\n",ALogInterface.NORMAL); - } - } - - public void zoomSummedOptions(int i) - { - parameterStore.get("CutsCalo", "LAr").changeScope(AParameter.LOCAL); - parameterStore.get("CutsCalo", "HEC").changeScope(AParameter.LOCAL); - switch (i) - { - case 0: - parameterStore.get("CutsCalo", "LAr").setI(0); - parameterStore.get("CutsCalo", "HEC").setI(-1); - break; - case 1: - parameterStore.get("CutsCalo", "LAr").setI(1); - parameterStore.get("CutsCalo", "HEC").setI(-1); - break; - case 2: - parameterStore.get("CutsCalo", "LAr").setI(-1); - parameterStore.get("CutsCalo", "HEC").setI(-2); - break; - case 3: - parameterStore.get("CutsCalo", "LAr").setI(-1); - parameterStore.get("CutsCalo", "HEC").setI(2); - break; - } - parameterStore.get("YX", "Mode").setI(AProjectionYX.MODE_LAR_ENDCAP_SUMMED + (int) Math.floor(i/2)); - } - - public void zoomLastWindow(boolean scaleStatus, String name) - { - String wName = Integer.toString(9); - AWindow w = ACanvas.getCanvas().getWindow(wName); - //want last window to be RZ view but won't change its zoom - AProjection p = AProjectionsManager.getProjection("RZ"); - w.setProjection(p); - Point2D.Double[] newCorners = new Point2D.Double[3]; - //FIXME hardcoded geometry of endcaps - //set region to be round the endcaps - newCorners[0]=new Point2D.Double(-650.0, 225); - newCorners[1]=new Point2D.Double(650.0, 225); - newCorners[2]=new Point2D.Double(650.0, -225); - - w.setUserCorners(newCorners); - w.setScaleStatus(scaleStatus); - parameterStore.selectWindowParameters(wName); - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(w.getName()); - w.repaintFromScratch(); - if (name.equals(wName)) - invalidate(); - } - - public void dragPerformed(Object from, Object to, int action) - {} - - public JMenuItem[] getPopupItems() { - ArrayList al = new ArrayList(); - if(window.getUnzoomPossible()) - { - JMenuItem it = new JMenuItem("Unzoom"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoom(); - } - }); - al.add(it); - } - if(window.getUnzoomAllPossible(ZOOM_LAYERS)) - { - JMenuItem it = new JMenuItem("Unzoom layers"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoom(ZOOM_LAYERS); - } - }); - al.add(it); - } - if(window.getUnzoomAllPossible(ZOOM_SUMMED)) - { - JMenuItem it = new JMenuItem("Unzoom summed"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoom(ZOOM_SUMMED); - } - }); - al.add(it); - } - if (window.getUnzoomFullPossible()) - { - JMenuItem it = new JMenuItem("Unzoom Full"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoomFull(); - } - }); - al.add(it); - } - // Can't cast arrays very easily... - JMenuItem[] ret = new JMenuItem[al.size()]; - for(int i = 0; i < al.size(); i++) - { - ret[i] = (JMenuItem) (al.get(i)); - } - return ret; - } - - public void actionPerformed(ActionEvent e) { - String action=e.getActionCommand(); - if(action.equals("Unzoom")) { - window.unzoom(); - } - if(action.equals("Unzoom layers")) { - window.unzoom(ZOOM_LAYERS); - } - if(action.equals("Unzoom summed")) { - window.unzoom(ZOOM_SUMMED); - } - if(action.equals("Unzoom Full")) { - window.unzoomFull(); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARotatedRectangleSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ARotatedRectangleSelection.java deleted file mode 100755 index 3cf0fd33bbe..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARotatedRectangleSelection.java +++ /dev/null @@ -1,211 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -public class ARotatedRectangleSelection extends ASelection { - - // The initial starting width of the first and last sides. - private final static int STARTING_WIDTH=25; - - public ARotatedRectangleSelection() { - super(6); - } - - // Initialize the control points given the starting point (x,y). - public int init(Point2D.Double p, int key) { - isValid=false; - - setCenter(hr[0], p.x-STARTING_WIDTH, p.y); - setCenter(hr[1], p.x-STARTING_WIDTH, p.y); - setCenter(hr[2], p.x+STARTING_WIDTH, p.y); - setCenter(hr[3], p.x+STARTING_WIDTH, p.y); - setCenter(hr[4], p.x, p.y); - setCenter(hr[5], p.x, p.y); - - region=5; - return region; - } - - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - double dx, dy, deltax, deltay, angle, radius; - - switch(region) { - case 0: - radius=getRadius(p.x, p.y, 4); - angle=getAngle(); - - deltax=p.x-hr[4].getCenterX(); - deltay=p.y-hr[4].getCenterY(); - - dx=-Math.round(radius*Math.sin(angle)); - dy=Math.round(radius*Math.cos(angle)); - - if(deltax*dx+deltay*dy<0) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[0], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[3], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - setCenter(hr[1], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - setCenter(hr[2], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - break; - - case 1: - radius=getRadius(p.x, p.y, 5); - angle=getAngle(); - - deltax=p.x-hr[5].getCenterX(); - deltay=p.y-hr[5].getCenterY(); - - dx=-Math.round(radius*Math.sin(angle)); - dy=Math.round(radius*Math.cos(angle)); - - if(deltax*dx+deltay*dy<0) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[0], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[3], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - setCenter(hr[1], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - setCenter(hr[2], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - break; - - case 2: - radius=getRadius(p.x, p.y, 5); - angle=getAngle(); - - deltax=p.x-hr[5].getCenterX(); - deltay=p.y-hr[5].getCenterX(); - - dx=-Math.round(radius*Math.sin(angle)); - dy=Math.round(radius*Math.cos(angle)); - - if(deltax*dx+deltay*dy<0) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[0], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - setCenter(hr[3], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[1], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - setCenter(hr[2], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - break; - - case 3: - radius=getRadius(p.x, p.y, 4); - angle=getAngle(); - - deltax=p.x-hr[4].getCenterX(); - deltay=p.y-hr[4].getCenterY(); - - dx=-Math.round(radius*Math.sin(angle)); - dy=Math.round(radius*Math.cos(angle)); - - if(deltax*dx+deltay*dy<0) { - dx=-dx; - dy=-dy; - } - - setCenter(hr[0], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - setCenter(hr[3], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[1], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - setCenter(hr[2], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - break; - - case 4: - case 5: - radius=getRadius(hr[0].getCenterX(), hr[0].getCenterY(), 4); - - // Update the active control point. - setCenter(hr[region], p.x, p.y); - angle=getAngle(); - - dx=-Math.round(radius*Math.sin(angle)); - dy=Math.round(radius*Math.cos(angle)); - - setCenter(hr[0], hr[4].getCenterX()+dx, hr[4].getCenterY()+dy); - setCenter(hr[3], hr[4].getCenterX()-dx, hr[4].getCenterY()-dy); - setCenter(hr[1], hr[5].getCenterX()+dx, hr[5].getCenterY()+dy); - setCenter(hr[2], hr[5].getCenterX()-dx, hr[5].getCenterY()-dy); - break; - } - } - - private double getAngle() { - double deltax=hr[5].getCenterX()-hr[4].getCenterX(); - double deltay=hr[5].getCenterY()-hr[4].getCenterY(); - - if(deltax!=0||deltay!=0) - return Math.atan2(deltay, deltax); - else - return 0.; - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - /** - * Make the affine transform which corresponds to this rectangular selection. - */ - public Point2D.Double[] getCorners() { - int first=getUpperLeftRegion(); - - // Calculate the index of the opposite corner. - int third=(first+2)%4; - - // Now use the cross-product to determine which of the - // remaining points is the one which keep the path going - // clockwise. - int second=(first+1)%4; - double dx0=hr[third].getCenterX()-hr[first].getCenterX(); - double dy0=hr[third].getCenterY()-hr[first].getCenterY(); - double dx1=hr[second].getCenterX()-hr[first].getCenterX(); - double dy1=hr[second].getCenterY()-hr[first].getCenterY(); - - if(dx0*dy1-dy0*dx1>0) - second=(first+3)%4; - // Get the appropriate radius. - int centerIndex=(first==0||first==3)?4:5; - double radius=getRadius(hr[first].getCenterX(), hr[first].getCenterY(), centerIndex); - double angle=getAngle(); - // Calculate the delta-x and delta-y for the points. - double dx=Math.abs(radius*Math.sin(angle)); - double dy=Math.abs(radius*Math.cos(angle)); - // Get the sign of the offsets from the control points. - double sdx; - double sdy; - - // The point closest to the origin. - centerIndex=(first==0||first==3)?4:5; - sdx=((hr[first].getCenterX()-hr[centerIndex].getCenterX())>0)?1.:-1.; - sdy=((hr[first].getCenterY()-hr[centerIndex].getCenterY())>0)?1.:-1.; - double x0=hr[centerIndex].getCenterX()+sdx*dx; - double y0=hr[centerIndex].getCenterY()+sdy*dy; - - // The next point clockwise. - centerIndex=(second==0||second==3)?4:5; - sdx=((hr[second].getCenterX()-hr[centerIndex].getCenterX())>0)?1.:-1.; - sdy=((hr[second].getCenterY()-hr[centerIndex].getCenterY())>0)?1.:-1.; - double x1=hr[centerIndex].getCenterX()+sdx*dx; - double y1=hr[centerIndex].getCenterY()+sdy*dy; - - // The next point clockwise. - centerIndex=(third==0||third==3)?4:5; - sdx=((hr[third].getCenterX()-hr[centerIndex].getCenterX())>0)?1.:-1.; - sdy=((hr[third].getCenterY()-hr[centerIndex].getCenterY())>0)?1.:-1.; - double x2=hr[centerIndex].getCenterX()+sdx*dx; - double y2=hr[centerIndex].getCenterY()+sdy*dy; - - // The control points are in the correct order, so we can just - // call the utility function of the parent. - return convert(x0, y0, x1, y1, x2, y2); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandGroup.java deleted file mode 100755 index fe8e54b62bd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandGroup.java +++ /dev/null @@ -1,109 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.ACanvas; -import atlantis.output.AExceptionHandler; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JMenuItem; -import javax.swing.JMenu; -import javax.swing.JComboBox; -import javax.swing.JPanel; - -import java.lang.reflect.Constructor; -import java.util.HashMap; - -public class ARubberbandGroup extends AInteractionGroup { - - private final static String[] RUBBERBAND_NAMES= {"Rectangle", "RotatedRectangle", "Parallelogram", - "Square", "XSkew", "YSkew", "XSlice", "YSlice"}; - - private HashMap rubberbands; - private JComboBox rbComboBox; - // the panel that will contain the additional controls for the interactions - private JPanel additionalControls; - - public ARubberbandGroup(AInteractionsManager manager) { - super(AInteractionGroup.WINDOW_GROUP, manager); - - // create the additional controls panel - additionalControls = new JPanel(); - - rubberbands=new HashMap(); - rbComboBox=new JComboBox(); - - for(int i=0; i<RUBBERBAND_NAMES.length; i++) { - rbComboBox.addItem(RUBBERBAND_NAMES[i]); - try { - Constructor[] c=Class.forName("atlantis.interactions.A"+RUBBERBAND_NAMES[i]+"Selection").getDeclaredConstructors(); - - rubberbands.put(RUBBERBAND_NAMES[i], c[0].newInstance(new Object[] {})); - } catch(Exception e) { - AExceptionHandler.processException("Cannot make selection "+"A"+RUBBERBAND_NAMES[i] - +"Selection", - e); - } - } - - rbComboBox.addActionListener(new RuberbandListener()); - additionalControls.add(rbComboBox); - - changeRubberband(); - } - - /** - * rubberband has additional controls, so return true - */ - public boolean hasAdditionalControls() { - return true; - } - - /** - * returns the additional controls - */ - public JPanel getAdditionalControls() { - return additionalControls; - } - - private void changeRubberband() { - String item=(String)rbComboBox.getSelectedItem(); - - removeAllInteractions(); - addInteraction((AInteraction)rubberbands.get(item)); - iManager.setContext(this); - } - - // generating the menu - public JMenuItem getPopupItem() { - JMenu menu=new JMenu(name); - ActionListener l=new PopupListener(); - - for(int i=0; i<RUBBERBAND_NAMES.length; i++) - menu.add(RUBBERBAND_NAMES[i]).addActionListener(l); - - return menu; - } - - public void setGroupState(AInteractionGroup givenGroup) { - if(givenGroup instanceof ARubberbandGroup) { - ARubberbandGroup panel=(ARubberbandGroup)givenGroup; - - this.rbComboBox.setSelectedIndex(panel.rbComboBox.getSelectedIndex()); - } - } - - class RuberbandListener implements ActionListener { - public void actionPerformed(ActionEvent e) { - changeRubberband(); - } - } - - - class PopupListener implements ActionListener { - public void actionPerformed(ActionEvent e) { - ACanvas.getCanvas().getCurrentWindow().getInteractionToolBar().setSelectedGroup(name); - rbComboBox.setSelectedItem(e.getActionCommand()); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandYXGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandYXGroup.java deleted file mode 100755 index 705da5e8e13..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ARubberbandYXGroup.java +++ /dev/null @@ -1,109 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.ACanvas; -import atlantis.output.AExceptionHandler; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JMenuItem; -import javax.swing.JMenu; -import javax.swing.JComboBox; -import javax.swing.JPanel; - -import java.lang.reflect.Constructor; -import java.util.HashMap; - -public class ARubberbandYXGroup extends AInteractionGroup { - - private final static String[] RUBBERBAND_NAMES= {"RectangleYX", "RotatedRectangle", "Parallelogram", - "Square", "XSkew", "YSkew", "XSlice", "YSlice"}; - - private HashMap rubberbands; - private JComboBox rbComboBox; - // the panel that will contain the additional controls for the interactions - private JPanel additionalControls; - - public ARubberbandYXGroup(AInteractionsManager manager) { - super(AInteractionGroup.WINDOW_GROUP, manager); - - // create the additional controls panel - additionalControls = new JPanel(); - - rubberbands=new HashMap(); - rbComboBox=new JComboBox(); - - for(int i=0; i<RUBBERBAND_NAMES.length; i++) { - rbComboBox.addItem(RUBBERBAND_NAMES[i]); - try { - Constructor[] c=Class.forName("atlantis.interactions.A"+RUBBERBAND_NAMES[i]+"Selection").getDeclaredConstructors(); - - rubberbands.put(RUBBERBAND_NAMES[i], c[0].newInstance(new Object[] {})); - } catch(Exception e) { - AExceptionHandler.processException("Cannot make selection "+"A"+RUBBERBAND_NAMES[i] - +"Selection", - e); - } - } - - rbComboBox.addActionListener(new RuberbandListener()); - additionalControls.add(rbComboBox); - - changeRubberband(); - } - - /** - * rubberband has additional controls, so return true - */ - public boolean hasAdditionalControls() { - return true; - } - - /** - * returns the additional controls - */ - public JPanel getAdditionalControls() { - return additionalControls; - } - - private void changeRubberband() { - String item=(String)rbComboBox.getSelectedItem(); - - removeAllInteractions(); - addInteraction((AInteraction)rubberbands.get(item)); - iManager.setContext(this); - } - - // generating the menu - public JMenuItem getPopupItem() { - JMenu menu=new JMenu(name); - ActionListener l=new PopupListener(); - - for(int i=0; i<RUBBERBAND_NAMES.length; i++) - menu.add(RUBBERBAND_NAMES[i]).addActionListener(l); - - return menu; - } - - public void setGroupState(AInteractionGroup givenGroup) { - if(givenGroup instanceof ARubberbandYXGroup) { - ARubberbandYXGroup panel=(ARubberbandYXGroup)givenGroup; - - this.rbComboBox.setSelectedIndex(panel.rbComboBox.getSelectedIndex()); - } - } - - class RuberbandListener implements ActionListener { - public void actionPerformed(ActionEvent e) { - changeRubberband(); - } - } - - - class PopupListener implements ActionListener { - public void actionPerformed(ActionEvent e) { - ACanvas.getCanvas().getCurrentWindow().getInteractionToolBar().setSelectedGroup(name); - rbComboBox.setSelectedItem(e.getActionCommand()); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyGroup.java deleted file mode 100755 index 05a6d681437..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -package atlantis.interactions; - - -public class AScaleCopyGroup extends AInteractionGroup { - - AScaleCopyInteraction scaleCopyInteraction; - - public AScaleCopyGroup(AInteractionsManager iManager) { - super(AInteractionGroup.CANVAS_GROUP, iManager); - scaleCopyInteraction=new AScaleCopyInteraction(); - this.addInteraction(scaleCopyInteraction); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyInteraction.java deleted file mode 100755 index 6e4492014d7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AScaleCopyInteraction.java +++ /dev/null @@ -1,24 +0,0 @@ -package atlantis.interactions; - -import java.awt.*; -import java.awt.geom.*; - -public class AScaleCopyInteraction extends AInteraction { - - public AScaleCopyInteraction() { - super(1, AUTOMATIC_REPAINT, SCREEN_COORDINATES, false); - hr[0]=new Rectangle2D.Double(0, 0, 0, 0); - } - - public void paint(Graphics2D g) {} - - public void connect(AInteractionsManager manager) { - super.connect(manager); - window.setScaleCopyStatus(true); - } - - public void disconnect() { - window.setScaleCopyStatus(false); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ASelection.java deleted file mode 100755 index 1a7b181aea5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASelection.java +++ /dev/null @@ -1,455 +0,0 @@ -package atlantis.interactions; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - -import java.awt.GridLayout; -import java.awt.Point; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Dimension; -import java.awt.Polygon; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import java.awt.geom.Ellipse2D; - -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JMenuItem; -import javax.swing.JButton; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.graphics.ADrawnGraphics2D; -import atlantis.graphics.AGraphics; -import atlantis.graphics.ACoord; -import atlantis.graphics.dnd.ADnDButton; -import atlantis.graphics.dnd.ADnDLabel; -import atlantis.graphics.dnd.ADragListener; -import atlantis.gui.AGUI; -import atlantis.gui.ALogPane; -import atlantis.list.AListManager; -import atlantis.list.AList; -import atlantis.output.AExceptionHandler; -import atlantis.output.AOutput; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; - - - -/** - * The superclass of all the selection (rubberband) interactions. - */ -public abstract class ASelection extends AInteraction - implements ASleepMouseDragListener, ActionListener -{ - - private static ALogger logger = ALogger.getLogger(ASelection.class); - - private JPanel actionsPanel; - private GridLayout actionsPanelLayout; - private int d = 10; - private boolean[][] map; - protected final static int radius = 10; - protected int region; - protected boolean isValid = false; - - - public final static String ZOOM = "Zoom"; - public final static String NEW_LIST = "New List"; - public final static String SUMMARIZE = "Summarize"; - - - - public ASelection(int hotRegionsCount) - { - super(hotRegionsCount, AUTOMATIC_REPAINT, SCREEN_COORDINATES, true); - - for(int i = 0; i < hr.length; i++) - { - hr[i] = new Ellipse2D.Double(0, 0, radius, radius); - } - - actionsPanelLayout = new GridLayout(0, 1); - actionsPanel = new JPanel(actionsPanelLayout); - - - addActionButton(ZOOM, new ADragListener() - { - public void dragPerformed(Object from, Object to, int action) - { - if(to instanceof ADnDLabel) - { - zoomIn(((ADnDLabel) to).getText()); - } - else if(to instanceof AWindow) - { - zoomIn(((AWindow) to).getName()); - } - invalidate(); - } - }, - new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.saveCorners(); - window.setUserCorners(getCorners()); - invalidate(); - } - }); - - - addActionButton(NEW_LIST, new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if(e.getActionCommand().equals(NEW_LIST)) - { - Point2D.Double[] zoomedCorners = getCorners(); - Point2D.Double[] userCorners = window.getUserCorners(); - window.setUserCornersNoRepaint(zoomedCorners); - Rectangle bounds = window.getBounds(); - bounds.setLocation(0, 0); - window.paintWindowFromScratch(new ADrawnGraphics2D(bounds)); - ADrawnGraphics2D.updateLastDrawn(); - AListManager.getInstance().copyLastDrawn(); - AListManager.getInstance().showLists(); - window.setUserCornersNoRepaint(userCorners); - } - } - }); - - - addActionButton(SUMMARIZE, new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - if(e.getActionCommand().equals(SUMMARIZE)) - { - Point2D.Double[] zoomedCorners = getCorners(); - Point2D.Double[] userCorners = window.getUserCorners(); - window.setUserCornersNoRepaint(zoomedCorners); - Rectangle bounds = window.getBounds(); - bounds.setLocation(0, 0); - window.paintWindowFromScratch(new ADrawnGraphics2D(bounds)); - ADrawnGraphics2D.updateLastDrawn(); - AListManager.getInstance().summarize(); - window.setUserCornersNoRepaint(userCorners); - } - } - }); - - } // ASelection() --------------------------------------------------------- - - - - - public void invalidate() - { - isValid = false; - actionsPanel.setVisible(false); - } - - - public void addActionButton(String buttonName, ADragListener dragList, - ActionListener clickList) - { - ADnDButton b = new ADnDButton(buttonName); - b.setFocusPainted(false); - b.addActionListener(clickList); - b.addDragListener(dragList); - actionsPanelLayout.setRows(actionsPanelLayout.getRows() + 1); - actionsPanel.add(b); - actionsPanel.setSize(actionsPanel.getPreferredSize()); - } - - - public void addActionButton(String buttonName, ActionListener clickListener) - { - JButton b = new JButton(buttonName); - b.setFocusPainted(false); - b.addActionListener(clickListener); - actionsPanelLayout.setRows(actionsPanelLayout.getRows() + 1); - actionsPanel.add(b); - actionsPanel.setSize(actionsPanel.getPreferredSize()); - } - - - public JMenuItem[] getPopupItems() - { - ArrayList<JMenuItem> al = new ArrayList<JMenuItem>(); - if(window.getUnzoomPossible()) - { - JMenuItem it = new JMenuItem("Unzoom"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoom(); - } - }); - al.add(it); - } - if(window.getUnzoomFullPossible()) - { - JMenuItem it = new JMenuItem("Unzoom Full"); - it.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - window.unzoomFull(); - } - }); - al.add(it); - } - // Can't cast arrays very easily... - JMenuItem[] ret = new JMenuItem[al.size()]; - for(int i = 0; i < al.size(); i++) - { - ret[i] = al.get(i); - } - return ret; - - } - - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - if(action.equals("Unzoom")) - { - window.unzoom(); - } - } - - - public int getPopupType() - { - return APopupListener.WINDOW_POPUP; - } - - - public void connect(AInteractionsManager manager) - { - super.connect(manager); - window.getView().add(actionsPanel); - if(isValid) - { - actionsPanel.setVisible(true); - } - else - { - actionsPanel.setVisible(false); - } - window.validate(); - } - - - public void disconnect() - { - window.getView().remove(actionsPanel); - } - - - public int getButton() - { - return AInteractionsManager.LEFT; - } - - - public void start(Point2D.Double p, int region, int key) - { - this.region = region; - actionsPanel.setVisible(false); - } - - - public void cancel() {} - - - private boolean canLayout(int i0, int j0) - { - Dimension panelSize = actionsPanel.getSize(); - panelSize.width = (int) Math.ceil((panelSize.width + d) / (double) d); - panelSize.height = (int) Math.ceil((panelSize.height + d) / (double) d); - for(int j = 0; j < panelSize.height; j++) - { - for(int i = 0; i < panelSize.width; i++) - { - if(i0 + i > map[0].length - 1)return false; - if(j0 + j > map.length - 1)return false; - if(map[j0 + j][i0 + i] == false)return false; - } - } - return true; - - } - - - private Point calculateBestPosition() - { - AWindow w = window; - Dimension size = w.getView().getSize(); - int ny = (int) Math.ceil(size.height / (double) d); - int nx = (int) Math.ceil(size.width / (double) d); - map = new boolean[ny][nx]; - Polygon p = new Polygon(); - for(int i = 0; i < 4; i++) - { - p.addPoint((int) hr[i].getCenterX(), (int) hr[i].getCenterY()); - } - - for(int j = 0; j < map.length; j++) - { - for(int i = 0; i < map[0].length; i++) - { - if(p.intersects(i * d, j * d, d, d) || p.contains(i * d, j * d, d, d)) - { - map[j][i] = false; - } - else - { - map[j][i] = true; - } - } - } - - for(int j = 0; j < map.length; j++) - { - for(int i = 0; i < map[0].length; i++) - { - if(canLayout(i, j)) - { - map[j][i] = true; - } - else - { - map[j][i] = false; - } - } - } - - int x0 = (int) hr[region].getMaxX(); - int y0 = (int) hr[region].getMaxY(); - int i_min = 0, j_min = 0; - double dist, dist_min = 1e10; - for(int j = 0; j < map.length; j++) - { - for(int i = 0; i < map[0].length; i++) - { - if(map[j][i] == true) - { - dist = Math.hypot(x0 - i*d, y0 - j*d); - if(dist < dist_min) - { - i_min = i; - j_min = j; - dist_min = dist; - } - } - } - } - - return new Point(i_min * d + d / 2, j_min * d + d / 2); - } - - - public void stop() - { - if(isValid) - { - Point p = calculateBestPosition(); - actionsPanel.setLocation(p.x, p.y); - actionsPanel.setVisible(true); - window.revalidate(); - } - } - - - protected int getUpperLeftRegion() - { - int point = 0; - double savedValue = getRadius(hr[0]); - for(int i = 1; i < 4; i++) - { - double value = getRadius(hr[i]); - if(value < savedValue) - { - savedValue = value; - point = i; - } - } - return point; - } - - - protected Point2D.Double[] convert( - double x0, double y0, double x1, double y1, double x2, double y2) - { - if(!isValid) - { - return window.getUserCorners(); - } - if(Math.abs(getAPolygon().getArea()) == 0) - { - return window.getUserCorners(); - } - - double[][][] hv = new double[2][1][3]; - hv[0][0][0] = x0; - hv[1][0][0] = y0; - hv[0][0][1] = x1; - hv[1][0][1] = y1; - hv[0][0][2] = x2; - hv[1][0][2] = y2; - ACoord d = window.calculateUser(new ACoord(hv)); - Point2D.Double[] corners = new Point2D.Double[3]; - for(int i = 0; i < 3; i++) - { - corners[i] = new Point2D.Double(d.hv[0][0][i], d.hv[1][0][i]); - } - - return corners; - } - - - protected Point2D.Double[] convert(int region1, int region2, int region3) - { - return convert(hr[region1].getCenterX(), hr[region1].getCenterY(), - hr[region2].getCenterX(), - hr[region2].getCenterY(), hr[region3].getCenterX(), - hr[region3].getCenterY()); - } - - - public abstract Point2D.Double[] getCorners(); - - - protected void paintStandard(Graphics2D g) - { - if(isValid) - { - AGraphics ag = AGraphics.makeAGraphics(g); - ag.updateDrawParameters(frameDrawParameters); - ag.drawPolygon(getAPolygon()); - drawLine(4, 5, ag); - ag.updateDrawParameters(drawParameters); - ag.drawPolygon(getAPolygon()); - drawLine(4, 5, ag); - drawActivePoint(region, ag); - } - } - - - public void zoomIn(String zoomWindow) - { - String currentWindow = window.getName(); - ACanvas.getCanvas().copyWindowSettings(currentWindow, zoomWindow); - ACanvas.getCanvas().getWindow(zoomWindow).setUserCorners(getCorners()); - } - -} // class ASelection ======================================================= diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASkewGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/ASkewGroup.java deleted file mode 100755 index 70057212cca..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASkewGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -package atlantis.interactions; - - -public class ASkewGroup extends AInteractionGroup { - - ASkewInteraction skewInteraction; - - public ASkewGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - skewInteraction=new ASkewInteraction(); - this.addInteraction(skewInteraction); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASkewInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/ASkewInteraction.java deleted file mode 100755 index a338f168638..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASkewInteraction.java +++ /dev/null @@ -1,123 +0,0 @@ -package atlantis.interactions; - -import atlantis.canvas.AWindow; -import atlantis.parameters.APar; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjection; -import atlantis.projection.AProjectionRZ; -import java.awt.*; -import java.awt.geom.*; -import java.awt.event.*; -import javax.swing.*; - -/** - * The interaction that performs a skew on the picture. - */ -public class ASkewInteraction extends AInteraction - implements ASleepMouseDragListener, ActionListener { - - private int d=20; - private Point2D.Double p0; - private JMenuItem[] popupItems; - private final static String NO_SKEW="Set No Skew"; - - public ASkewInteraction() { - super(1, WINDOW_TOTAL_REPAINT, WORLD_COORDINATES, false); - - popupItems = new JMenuItem[] { - new JMenuItem(NO_SKEW) - }; - - popupItems[0].addActionListener(this); - - // The center of the ellipse is in (0, 0) in User Space - hr[0]=new Ellipse2D.Double(-d/2, -d/2, d, d); - } - - public int init(Point2D.Double p, int key) { - p0=p; - return 0; - } - - public int getButton() { - return AInteractionsManager.LEFT; - } - - public void start(Point2D.Double p, int region, int key) {} - - public void drag(Point2D.Double p, int region, int key) { - AProjection proj=window.getProjection(); - - if(proj instanceof AProjectionFR) { - performFRSkew(-(p.y-p0.y)/p0.x, window); - } else if(proj instanceof AProjectionFZ) { - performFZSkew(-(p.y-p0.y)/p0.x, window); - } else if(proj instanceof AProjectionRZ) { - if(key==KeyEvent.VK_V) - performFZSkew(-(p.y-p0.y)/p0.x, window); - else - performRZSkew(-(p.x-p0.x)/p0.y, window); - } - } - - public static void performFRSkew(double f, AWindow window) { - Point2D.Double[] corners=window.getUserCorners(); - - for(int i=0; i<corners.length; i++) - corners[i].y+=f*corners[i].x; - - window.setUserCorners(corners); - } - - public static void performFZSkew(double f, AWindow window) { - Point2D.Double[] corners=window.getUserCorners(); - - double zVtx=parameterStore.get("Event", "ZVtx").getD(); - - for(int i=0; i<corners.length; i++) - corners[i].y+=f*(corners[i].x-zVtx); - - window.setUserCorners(corners); - } - - public static void performRZSkew(double f, AWindow window) { - Point2D.Double[] corners=window.getUserCorners(); - - for(int i=0; i<corners.length; i++) - corners[i].x+=f*corners[i].y; - - window.setUserCorners(corners); - } - - public void stop() {} - - public void cancel() {} - - public void paint(Graphics2D g) {} - - public int getPopupType() { - return APopupListener.WINDOW_POPUP; - } - - public JMenuItem[] getPopupItems() { - return popupItems; - } - - public void actionPerformed(ActionEvent e) { - - } - public AModifier[] getModifiers(){ - if(window.getProjection() instanceof AProjectionRZ) { - return new AModifier[] { - new AModifier(KeyEvent.VK_V, false, "Y Skew"), - new AModifier(KeyEvent.VK_H, false, "X Skew"), - new AModifier(KeyEvent.VK_UNDEFINED, false, "X Skew") - }; - } else { - return new AModifier[0]; - } - } - - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASleepMouseDragListener.java b/graphics/AtlantisJava/src/atlantis/interactions/ASleepMouseDragListener.java deleted file mode 100755 index 60b145d8b13..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASleepMouseDragListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package atlantis.interactions; - - -import java.awt.geom.*; - - -/** - * This listener extends AMouseDragListener in order to make it possible to - * get drag events even without any hot region. - */ -public interface ASleepMouseDragListener extends AMouseDragListener { - int init(Point2D.Double p, int key); -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASquareSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/ASquareSelection.java deleted file mode 100755 index 0f12dae04d5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASquareSelection.java +++ /dev/null @@ -1,87 +0,0 @@ -package atlantis.interactions; - -import java.awt.Graphics2D; -import java.awt.geom.Point2D; - -import atlantis.graphics.AGraphics; -import atlantis.utils.AMath; - -public class ASquareSelection extends ASelection -{ - public ASquareSelection() - { - super(5); - } - - public int init(Point2D.Double p, int key) - { - isValid = false; - - for (int i = 0; i < 5; i++) - setCenter(hr[i], p.x, p.y); - - this.region = 2; - return region; - } - - public void drag(Point2D.Double p, int region, int key) - { - isValid = true; - - if (region == 4) - { - double dx = p.x - hr[4].getCenterX(); - double dy = p.y - hr[4].getCenterY(); - - for (int i = 0; i < 5; i++) - setCenter(hr[i], hr[i].getCenterX() + dx, hr[i].getCenterY() + dy); - } - else - { - double ratio = ((double) window.getSize().width) / ((double) window.getSize().height); - - double sx1 = AMath.getSign(p.x - hr[4].getCenterX()); - double sy1 = AMath.getSign(p.y - hr[4].getCenterY()); - double sx2 = sy1; - double sy2 = sx1; - double dy = getRadius(p.x, p.y, 4) / Math.sqrt(1 + ratio * ratio); - double dx = dy * ratio; - - setCenter(hr[region], hr[4].getCenterX() + dx * sx1, hr[4].getCenterY() + dy * sy1); - setCenter(hr[(region + 2) % 4], hr[4].getCenterX() - dx * sx1, hr[4].getCenterY() - dy * sy1); - - setCenter(hr[(region + 1) % 4], hr[4].getCenterX() - dx * sx2, hr[4].getCenterY() + dy * sy2); - setCenter(hr[(region + 3) % 4], hr[4].getCenterX() + dx * sx2, hr[4].getCenterY() - dy * sy2); - } - } - - public void paint(Graphics2D g) - { - if (isValid) - { - AGraphics ag = AGraphics.makeAGraphics(g); - - ag.updateDrawParameters(frameDrawParameters); - ag.drawPolygon(getAPolygon()); - drawLine(0, 2, ag); - drawLine(1, 3, ag); - ag.updateDrawParameters(drawParameters); - ag.drawPolygon(getAPolygon()); - drawLine(0, 2, ag); - drawLine(1, 3, ag); - drawActivePoint(region, ag); - } - } - - public Point2D.Double[] getCorners() - { - int first = getUpperLeftRegion(); - - // Calculate the adjacent partner and the opposite corner. - int second = (first + 1) % 4; - int third = (first + 2) % 4; - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsGroup.java deleted file mode 100755 index 4a74be687a7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -package atlantis.interactions; - - -public class ASynchroCursorsGroup extends AInteractionGroup { - - private ASynchroCursorsInteraction mmSelection; - - public ASynchroCursorsGroup(AInteractionsManager iManager) { - super(AInteractionGroup.CANVAS_GROUP, iManager); - - mmSelection=new ASynchroCursorsInteraction(); - addInteraction(mmSelection); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsInteraction.java deleted file mode 100755 index 9f7915a17dc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/ASynchroCursorsInteraction.java +++ /dev/null @@ -1,483 +0,0 @@ -package atlantis.interactions; - -import java.awt.Graphics2D; -import java.awt.event.KeyEvent; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; - -import atlantis.canvas.ACanvas; -import atlantis.graphics.ACoord; -import atlantis.graphics.ACursorFactory; -import atlantis.graphics.AGraphics; -import atlantis.parameters.APar; -import atlantis.parameters.AParameterUtilities; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.utils.AMath; - -public class ASynchroCursorsInteraction extends AInteraction - implements ASleepMouseDragListener, AEnterExitListener -{ - /** - * The position of the moving marker in 3D. Phi is in degrees. - * (Must be static) - */ - private static double rho, phi, z, sign_rho; - - private static final double NOT_DEFINED = 9999.0; - private static final double RHO_MAX = 3000.0; - private static final double PHI_MAX = 400.0; - private static final double Z_MAX = 3000.0; - private static final double ETA_MAX = 10.0; - - private static int key = 0; - protected int radius = 10; - - public ASynchroCursorsInteraction() - { - super(1, ALL_WINDOWS_REPAINT, WORLD_COORDINATES, true); - hr[0] = new Ellipse2D.Double(0, 0, radius, radius); - } - - public int getButton() - { - return AInteractionsManager.LEFT; - } - - /** - * Initialize the control points based on the starting point - */ - public int init(Point2D.Double p, int key) - { - this.key = key; - setCenter(hr[0], p.x, p.y); - // ACanvas.getCanvas().repaintOthers(window); - return 0; - } - - public void start(Point2D.Double p, int region, int key) - { - //call drag to update the cursor even if only a button is pressed - drag(p,region,key); - } - - /** - * Move the active control point to the point (x, y). - * - * @param pInput the input point - * @param region the region - * @param key the current key being pressed - */ - public void drag(Point2D.Double pInput, int region, int key) - { - this.key = key; - AProjection2D projection = (AProjection2D) window.getProjection(); - - Point2D.Double p = projection.inverseNonLinearTransform(pInput); - - setCenter(hr[0], p.x, p.y); - - rho = NOT_DEFINED; - z = NOT_DEFINED; - phi = NOT_DEFINED; - sign_rho = 1.; - - if (projection instanceof AProjectionYX) - { - phi = Math.toDegrees(Math.atan2(p.y, p.x)); - if (phi < 0.) - phi += 360.; - rho = AParameterUtilities.getRhoSign(p.x, p.y) * Math.sqrt(p.x * p.x + p.y * p.y); - } - else if (projection instanceof AProjectionFR) - { - phi = p.y; - rho = p.x; - } - else if (projection instanceof AProjectionFZ) - { - phi = p.y; - z = p.x; - } - else if (projection instanceof AProjectionRZ) - { - rho = Math.abs(p.y); - if (p.y < 0.) - sign_rho = -1.; - z = p.x; - } - else if (projection instanceof AProjectionYZ) - { - z = p.x; - } - else if (projection instanceof AProjectionXZ) - { - z = p.x; - } - else if (projection instanceof AProjectionVP) - { - phi = p.y; - rho = parameterStore.get("VP", "RMax").getD(); - double eta = p.x; - - z = parameterStore.get("Event", "ZVtx").getD() + 0.5 * rho * (Math.exp(eta) - 1. / Math.exp(eta)); - } - else if (projection instanceof AProjectionLegoPlot) - { - // added by Mark Stockton - // update parameters - AProjectionLegoPlot.update(); - //reverse the adjustPhi function - p.x=-(AProjectionLegoPlot.adjustPhi(window,-p.x,p.y)); - if(p.x>-1.0 && p.x<361.0 && p.y>-5.01 && p.y<5.01) - { - phi=p.x; - rho = parameterStore.get("VP", "RMax").getD(); - double eta=p.y; - if (AProjectionLegoPlot.reverse) - eta = -eta; - z = parameterStore.get("Event", "ZVtx").getD() + 0.5 * rho * (Math.exp(eta) - 1. / Math.exp(eta)); - } - } - if (key == KeyEvent.VK_P && phi != NOT_DEFINED) - { - double phiRZ = phi + 90.; - - if (phiRZ < 0.) - phiRZ += 360; - if (phiRZ > 360.) - phiRZ -= 360; - parameterStore.get("RZ", "Phi").setD(phiRZ); - parameterStore.get("RZ", "Phi").globalize(ACanvas.getCanvas().getCurrentWindow().getIndex()); - ACanvas.getCanvas().repaintAllFromScratch(); - } - else - ACanvas.getCanvas().repaintOthers(window); - } - - public void cancel() - {} - - public void stop() - {} - - public void paint(Graphics2D g) - { - // must use the window version of the parameters - parameterStore.selectWindowParameters(window.getName()); - AProjection2D projection = (AProjection2D) window.getProjection(); - AGraphics ag = AGraphics.makeAGraphics(g); - - for (int i = 0; i < 2; i++) - { - if (i == 0) - ag.updateDrawParameters(frameDrawParameters); - else - ag.updateDrawParameters(drawParameters); - - if (projection instanceof AProjectionYX) - { - if (phi != NOT_DEFINED) - { - double r = (rho == NOT_DEFINED) ? RHO_MAX : Math.abs(rho); - double cosPhi = Math.cos(Math.toRadians(phi)); - double sinPhi = Math.sin(Math.toRadians(phi)); - - Point2D.Double p = window.calculateDisplay(projection.nonLinearTransform(0, 0)); - Point2D.Double p1 = window.calculateDisplay(projection.nonLinearTransform(r * cosPhi, r * sinPhi)); - Point2D.Double p2 = window.calculateDisplay(projection.nonLinearTransform(RHO_MAX * cosPhi, RHO_MAX * sinPhi)); - Point2D.Double p3 = window.calculateDisplay(projection.nonLinearTransform(-RHO_MAX * cosPhi, -RHO_MAX * sinPhi)); - - if (key == KeyEvent.VK_P) - { - ag.drawLine(p2.x, p2.y, p3.x, p3.y); - } - else - { - ag.drawLine(p.x, p.y, p2.x, p2.y); - if (rho != NOT_DEFINED) - ag.drawSymbol(p1.x, p1.y); - } - - } - else if (rho != NOT_DEFINED) - { - int numPoints = 48; - double[][][] hv = new double[2][1][numPoints]; - - for (int j = 0; j < numPoints; j++) - { - hv[0][0][j] = rho * Math.cos(Math.PI * 2 * j / 48); - hv[1][0][j] = rho * Math.sin(Math.PI * 2 * j / 48); - } - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawPolygon(d.hv[0][0], d.hv[1][0], numPoints); - } - } - else if (projection instanceof AProjectionFR) - { - int numPoints = 5; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = Math.abs(rho); - hv[1][0][0] = phi; - hv[0][0][1] = Math.abs(rho); - hv[1][0][1] = 0.; - hv[0][0][2] = Math.abs(rho); - hv[1][0][2] = RHO_MAX; - hv[0][0][3] = 0.; - hv[1][0][3] = phi; - hv[0][0][4] = RHO_MAX; - hv[1][0][4] = phi; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - if (rho != NOT_DEFINED) - ag.drawLine(d.hv[0][0][1], d.hv[1][0][1], d.hv[0][0][2], d.hv[1][0][2]); - if (phi != NOT_DEFINED) - ag.drawLine(d.hv[0][0][3], d.hv[1][0][3], d.hv[0][0][4], d.hv[1][0][4]); - if (rho != NOT_DEFINED && phi != NOT_DEFINED) - ag.drawSymbol(d.hv[0][0][0], d.hv[1][0][0]); - } - else if (projection instanceof AProjectionFZ) - { - int numPoints = 5; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = z; - hv[1][0][0] = phi; - hv[0][0][1] = z; - hv[1][0][1] = 0.; - hv[0][0][2] = z; - hv[1][0][2] = PHI_MAX; - hv[0][0][3] = -Z_MAX; - hv[1][0][3] = phi; - hv[0][0][4] = Z_MAX; - hv[1][0][4] = phi; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - if (z != NOT_DEFINED) - ag.drawLine(d.hv[0][0][1], d.hv[1][0][1], d.hv[0][0][2], d.hv[1][0][2]); - if (phi != NOT_DEFINED) - ag.drawLine(d.hv[0][0][3], d.hv[1][0][3], d.hv[0][0][4], d.hv[1][0][4]); - if (z != NOT_DEFINED && phi != NOT_DEFINED) - ag.drawSymbol(d.hv[0][0][0], d.hv[1][0][0]); - } - else if (projection instanceof AProjectionRZ) - { - if (rho != NOT_DEFINED && phi != NOT_DEFINED && z != NOT_DEFINED && (rho != 0. || z != 0.)) - { - int numPoints = 15; - double[][][] hv = new double[2][1][numPoints]; - - double dr, dz; - if (Math.abs(rho/RHO_MAX) > Math.abs(z/Z_MAX)) { - dr = RHO_MAX / (numPoints-1); - dz = z * (RHO_MAX / ((numPoints-1)*rho)); - } else { - dz = AMath.getSign(z) * Z_MAX / (numPoints-1); - dr = rho * Math.abs(Z_MAX / ((numPoints-1)*z)); - } - - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - - if (phiMid > AMath.TWO_PI) - phiMid -= AMath.TWO_PI; - double phiDiff = Math.abs(Math.toRadians(phi) - phiMid); - - if (phiDiff > Math.PI / 2. && phiDiff < 3 * Math.PI / 2.) - dr *= -1; - - for (int j=0; j<numPoints; j++) { - hv[0][0][j] = j*dz; - hv[1][0][j] = j*dr; - } - - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawSmoothPolyline(d.hv[0][0], d.hv[1][0], numPoints); - } - else - { - int numPoints = 5; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = z; - hv[1][0][0] = rho * sign_rho; - hv[0][0][1] = z; - hv[1][0][1] = -RHO_MAX; - hv[0][0][2] = z; - hv[1][0][2] = RHO_MAX; - hv[0][0][3] = -Z_MAX; - hv[1][0][3] = rho * sign_rho; - hv[0][0][4] = Z_MAX; - hv[1][0][4] = rho * sign_rho; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - if (z != NOT_DEFINED) - ag.drawLine(d.hv[0][0][1], d.hv[1][0][1], d.hv[0][0][2], d.hv[1][0][2]); - if (rho != NOT_DEFINED) - ag.drawLine(d.hv[0][0][3], d.hv[1][0][3], d.hv[0][0][4], d.hv[1][0][4]); - if (z != NOT_DEFINED && rho != NOT_DEFINED) - ag.drawSymbol(d.hv[0][0][0], d.hv[1][0][0]); - } - } - else if (projection instanceof AProjectionYZ) - { - if (rho != NOT_DEFINED && phi != NOT_DEFINED && z != NOT_DEFINED) - { - int numPoints = 2; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = 0.; - hv[1][0][0] = 0.; - double phiRot = AProjectionXZ.getPhi(); - - hv[0][0][1] = z; - hv[1][0][1] = rho * Math.sin(phiRot); - - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawLine(d.hv[0][0][0], d.hv[1][0][0], d.hv[0][0][1], d.hv[1][0][1]); - ag.drawSymbol(d.hv[0][0][1], d.hv[1][0][1]); - } - else if (z != NOT_DEFINED) - { - int numPoints = 2; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = z; - hv[1][0][0] = -RHO_MAX; - hv[0][0][1] = z; - hv[1][0][1] = RHO_MAX; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawLine(d.hv[0][0][0], d.hv[1][0][0], d.hv[0][0][1], d.hv[1][0][1]); - } - } - else if (projection instanceof AProjectionXZ) - { - if (rho != NOT_DEFINED && phi != NOT_DEFINED && z != NOT_DEFINED) - { - int numPoints = 2; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = 0.; - hv[1][0][0] = 0.; - double phiRot = AProjectionXZ.getPhi(); - - hv[0][0][1] = z; - hv[1][0][1] = rho * Math.cos(phiRot); - - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawLine(d.hv[0][0][0], d.hv[1][0][0], d.hv[0][0][1], d.hv[1][0][1]); - ag.drawSymbol(d.hv[0][0][1], d.hv[1][0][1]); - } - else if (z != NOT_DEFINED) - { - int numPoints = 2; - double[][][] hv = new double[2][1][numPoints]; - - hv[0][0][0] = z; - hv[1][0][0] = -RHO_MAX; - hv[0][0][1] = z; - hv[1][0][1] = RHO_MAX; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - ag.drawLine(d.hv[0][0][0], d.hv[1][0][0], d.hv[0][0][1], d.hv[1][0][1]); - } - } - else if (projection instanceof AProjectionVP) - { - int numPoints = 5; - double[][][] hv = new double[2][1][numPoints]; - double eta = 1.; - - if (z != NOT_DEFINED && rho != NOT_DEFINED) - eta = AParameterUtilities.eta(z, rho); - hv[0][0][0] = eta; - hv[1][0][0] = phi; - hv[0][0][1] = eta; - hv[1][0][1] = 0.; - hv[0][0][2] = eta; - hv[1][0][2] = PHI_MAX; - hv[0][0][3] = -ETA_MAX; - hv[1][0][3] = phi; - hv[0][0][4] = ETA_MAX; - hv[1][0][4] = phi; - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - - if (z != NOT_DEFINED && rho != NOT_DEFINED) - ag.drawLine(d.hv[0][0][1], d.hv[1][0][1], d.hv[0][0][2], d.hv[1][0][2]); - if (phi != NOT_DEFINED) - ag.drawLine(d.hv[0][0][3], d.hv[1][0][3], d.hv[0][0][4], d.hv[1][0][4]); - - if (z != NOT_DEFINED && phi != NOT_DEFINED && rho != NOT_DEFINED) - ag.drawSymbol(d.hv[0][0][0], d.hv[1][0][0]); - } - else if (projection instanceof AProjectionLegoPlot) - { - //added by Mark Stockton - double eta = 1.; - double[][][] hv = new double[2][1][3]; - Point2D.Double[] userCorners = window.getUserCorners(); - Point2D.Double[] displayCorners = window.getDisplayCorners(); - //update parameters - AProjectionLegoPlot.update(); - if (z != NOT_DEFINED && rho != NOT_DEFINED) - eta = AParameterUtilities.eta(z, rho); - if (AProjectionLegoPlot.reverse) - eta = -eta; - hv[0][0][0] = AProjectionLegoPlot.adjustPhi(window,phi,eta); - hv[1][0][0] = eta; - //top of plot coordinate - hv[0][0][1] = AProjectionLegoPlot.adjustPhi(window,phi,userCorners[0].y); - hv[1][0][1] = userCorners[0].y; - //bottom of plot coordinate - hv[0][0][2] = AProjectionLegoPlot.adjustPhi(window,phi,userCorners[2].y); - hv[1][0][2] = userCorners[2].y; - //convert to screen positions - ACoord d = window.calculateDisplay(projection.nonLinearTransform(new ACoord(hv))); - if (z != NOT_DEFINED && rho != NOT_DEFINED) - ag.drawLine(0, d.hv[1][0][0], displayCorners[1].x, d.hv[1][0][0]);//eta line - if (phi != NOT_DEFINED) - ag.drawLine(d.hv[0][0][1], d.hv[1][0][1],d.hv[0][0][2], d.hv[1][0][2]);//phi line - if (z != NOT_DEFINED && phi != NOT_DEFINED && rho != NOT_DEFINED) - ag.drawSymbol(d.hv[0][0][0], d.hv[1][0][0]);//square where axis cross - } - } - parameterStore.restoreWindowParameters(); - } - - /** - * Gets called each time we enter a window in which this interaction is active - */ - public void entered() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getSyncCursor()); - } - - /** - * Gets called each time we leave a window in which this interaction is active - */ - public void exited() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getSyncCursor()); - } - - public AModifier[] getModifiers() - { - return new AModifier[] { new AModifier(KeyEvent.VK_P, false, "Copy phi to RZ projection" ) }; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AVPSelectionGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AVPSelectionGroup.java deleted file mode 100755 index c439d48ee42..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AVPSelectionGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -package atlantis.interactions; - - -public class AVPSelectionGroup extends AInteractionGroup { - - private ARectangleVPSelection rectangleVPSelection; - - public AVPSelectionGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - - rectangleVPSelection=new ARectangleVPSelection(); - addInteraction(rectangleVPSelection); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AWindowInfoInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AWindowInfoInteraction.java deleted file mode 100755 index 80d439b8e5f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AWindowInfoInteraction.java +++ /dev/null @@ -1,73 +0,0 @@ -package atlantis.interactions; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.geom.Point2D; - -import atlantis.graphics.ACursorFactory; - -public class AWindowInfoInteraction extends AInteraction implements AMouseDragListener, AEnterExitListener -{ - // private int width=64; - private Point pickedPoint; - private Color c; - - public AWindowInfoInteraction() - { - super(1, AUTOMATIC_REPAINT, SCREEN_COORDINATES, true); - - this.c = Color.white; - - // hr[0] = new Rectangle2D.Double(x, y, width, width); - pickedPoint = new Point(0, 0); - } - - public int getButton() - { - return AInteractionsManager.LEFT; - } - - public void paint(Graphics2D g) - { - g.setColor(c); - g.fill(hr[0]); - - /* - * g.fillRect(hr[0].getX(), hr[0].getY(), hr[0].getWidth(), - * hr[0].getHeight()); - */ - } - - public void start(Point2D.Double p, int region, int key) - { - pickedPoint.setLocation(p.x - hr[0].getX(), p.y - hr[0].getY()); - } - - public void drag(Point2D.Double p, int region, int key) - { - hr[0].setFrame(p.x - pickedPoint.x, p.y - pickedPoint.y, hr[0].getWidth(), hr[0].getHeight()); - } - - public void stop() - {} - - public void cancel() - {} - - public void entered() - { - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public void exited() - { - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public int getPopupType() - { - return APopupListener.REGION_POPUP; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AXSkewSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/AXSkewSelection.java deleted file mode 100755 index 1aac47fd38e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AXSkewSelection.java +++ /dev/null @@ -1,124 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -/** - * A panel which selects a parallogram-shaped region in which two - * sides are parallel to the y-axis and the other two are skewed with - * respect to the x-axis. - * - * @author Charles Loomis - **/ -public class AXSkewSelection extends ASelection { - - final private static int STARTING_WIDTH=25; - - public AXSkewSelection() { - super(6); - } - - /** - * Initialize the control points based in the starting point - */ - public int init(Point2D.Double p, int key) { - isValid=false; - - setCenter(hr[0], p.x-STARTING_WIDTH, p.y); - setCenter(hr[1], p.x-STARTING_WIDTH, p.y); - setCenter(hr[2], p.x+STARTING_WIDTH, p.y); - setCenter(hr[3], p.x+STARTING_WIDTH, p.y); - setCenter(hr[4], p.x, p.y); - setCenter(hr[5], p.x, p.y); - - region=5; - return region; - } - - /** - * Move the active control point to the point (x,y). - */ - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - - double width; - - // Change what is done depending on which control point is active. - switch(region) { - case 0: - width=p.x-hr[4].getCenterX(); - setCenterX(hr[0], hr[4].getCenterX()+width); - setCenterX(hr[1], hr[5].getCenterX()+width); - setCenterX(hr[2], hr[5].getCenterX()-width); - setCenterX(hr[3], hr[4].getCenterX()-width); - break; - - case 1: - width=p.x-hr[5].getCenterX(); - setCenterX(hr[0], hr[4].getCenterX()+width); - setCenterX(hr[1], hr[5].getCenterX()+width); - setCenterX(hr[2], hr[5].getCenterX()-width); - setCenterX(hr[3], hr[4].getCenterX()-width); - break; - - case 2: - width=p.x-hr[5].getCenterX(); - setCenterX(hr[0], hr[4].getCenterX()-width); - setCenterX(hr[1], hr[5].getCenterX()-width); - setCenterX(hr[2], hr[5].getCenterX()+width); - setCenterX(hr[3], hr[4].getCenterX()+width); - break; - - case 3: - width=p.x-hr[4].getCenterX(); - setCenterX(hr[0], hr[4].getCenterX()-width); - setCenterX(hr[1], hr[5].getCenterX()-width); - setCenterX(hr[2], hr[5].getCenterX()+width); - setCenterX(hr[3], hr[4].getCenterX()+width); - break; - - case 4: - width=hr[4].getCenterX()-hr[0].getCenterX(); - setCenter(hr[region], p.x, p.y); - setCenter(hr[0], p.x-width, p.y); - setCenter(hr[3], p.x+width, p.y); - break; - - case 5: - width=hr[4].getCenterX()-hr[0].getCenterX(); - setCenter(hr[region], p.x, p.y); - setCenter(hr[1], p.x-width, p.y); - setCenter(hr[2], p.x+width, p.y); - break; - } - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - /** - * Make the affine transform which corresponds to this skewed region. - */ - public Point2D.Double[] getCorners() { - int first=getUpperLeftRegion(); - - // Calculate which is the opposite corner. - int third=(first+2)%4; - - // Now use the cross-product to determine which of the - // remaining points is the one which keep the path going clockwise. - int second=(first+1)%4; - double dx0=hr[third].getCenterX()-hr[first].getCenterX(); - double dy0=hr[third].getCenterY()-hr[first].getCenterY(); - double dx1=hr[second].getCenterX()-hr[first].getCenterX(); - double dy1=hr[second].getCenterY()-hr[first].getCenterY(); - - if(dx0*dy1-dy0*dx1>0) second=(first+3)%4; - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AXSliceSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/AXSliceSelection.java deleted file mode 100755 index 596f81aa6e8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AXSliceSelection.java +++ /dev/null @@ -1,79 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -/** - * A panel which selects a slice of the window in the x-direction. - * That is, it selects a rectangular region with a height equal to the - * full height of the window and with an adjustable width. - * - * @author Charles Loomis - **/ -public class AXSliceSelection extends ASelection { - - public AXSliceSelection() { - super(6); - } - - public int init(Point2D.Double p, int key) { - isValid=false; - - int ymax=window.getSize().height; - int ymid=ymax/2; - - setCenter(hr[0], p.x, 0); - setCenter(hr[1], p.x, 0); - setCenter(hr[2], p.x, ymax); - setCenter(hr[3], p.x, ymax); - setCenter(hr[4], p.x, ymid); - setCenter(hr[5], p.x, ymid); - - region=5; - return region; - } - - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - - switch(region) { - case 0: - case 3: - case 4: - setCenterX(hr[0], p.x); - setCenterX(hr[3], p.x); - setCenterX(hr[4], p.x); - break; - - case 1: - case 2: - case 5: - setCenterX(hr[1], p.x); - setCenterX(hr[2], p.x); - setCenterX(hr[5], p.x); - break; - } - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - public Point2D.Double[] getCorners() { - // Sort out which are the three control points. - int first=0; - int second=1; - int third=2; - - if(hr[1].getCenterX()<hr[0].getCenterX()) { - first=1; - second=0; - third=3; - } - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AYSkewSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/AYSkewSelection.java deleted file mode 100755 index 9e98bde0f40..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AYSkewSelection.java +++ /dev/null @@ -1,124 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -/** - * A panel which selects a parallogram-shaped region in which two - * sides are parallel to the y-axis and the other two are skewed with - * respect to the x-axis. - * - * @author Charles Loomis - **/ -public class AYSkewSelection extends ASelection { - - final private static int STARTING_WIDTH=25; - - public AYSkewSelection() { - super(6); - } - - /** - * Initialize the control points based in the starting point - */ - public int init(Point2D.Double p, int key) { - isValid=false; - - setCenter(hr[0], p.x, p.y-STARTING_WIDTH); - setCenter(hr[1], p.x, p.y-STARTING_WIDTH); - setCenter(hr[2], p.x, p.y+STARTING_WIDTH); - setCenter(hr[3], p.x, p.y+STARTING_WIDTH); - setCenter(hr[4], p.x, p.y); - setCenter(hr[5], p.x, p.y); - - region=5; - return region; - } - - /** - * Move the active control point to the point (x,y). - */ - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - - double width; - - // Change what is done depending on which control point is active. - switch(region) { - case 0: - width=p.y-hr[4].getCenterY(); - setCenterY(hr[0], hr[4].getCenterY()+width); - setCenterY(hr[1], hr[5].getCenterY()+width); - setCenterY(hr[2], hr[5].getCenterY()-width); - setCenterY(hr[3], hr[4].getCenterY()-width); - break; - - case 1: - width=p.y-hr[5].getCenterY(); - setCenterY(hr[0], hr[4].getCenterY()+width); - setCenterY(hr[1], hr[5].getCenterY()+width); - setCenterY(hr[2], hr[5].getCenterY()-width); - setCenterY(hr[3], hr[4].getCenterY()-width); - break; - - case 2: - width=p.y-hr[5].getCenterY(); - setCenterY(hr[0], hr[4].getCenterY()-width); - setCenterY(hr[1], hr[5].getCenterY()-width); - setCenterY(hr[2], hr[5].getCenterY()+width); - setCenterY(hr[3], hr[4].getCenterY()+width); - break; - - case 3: - width=p.y-hr[4].getCenterY(); - setCenterY(hr[0], hr[4].getCenterY()-width); - setCenterY(hr[1], hr[5].getCenterY()-width); - setCenterY(hr[2], hr[5].getCenterY()+width); - setCenterY(hr[3], hr[4].getCenterY()+width); - break; - - case 4: - width=hr[4].getCenterY()-hr[0].getCenterY(); - setCenter(hr[region], p.x, p.y); - setCenter(hr[0], p.x, p.y-width); - setCenter(hr[3], p.x, p.y+width); - break; - - case 5: - width=hr[4].getCenterY()-hr[0].getCenterY(); - setCenter(hr[region], p.x, p.y); - setCenter(hr[1], p.x, p.y-width); - setCenter(hr[2], p.x, p.y+width); - break; - } - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - /** - * Make the affine transform which corresponds to this skewed region. - */ - public Point2D.Double[] getCorners() { - int first=getUpperLeftRegion(); - - // Calculate which is the opposite corner. - int third=(first+2)%4; - - // Now use the cross-product to determine which of the - // remaining points is the one which keep the path going clockwise. - int second=(first+1)%4; - double dx0=hr[third].getCenterX()-hr[first].getCenterX(); - double dy0=hr[third].getCenterY()-hr[first].getCenterY(); - double dx1=hr[second].getCenterX()-hr[first].getCenterX(); - double dy1=hr[second].getCenterY()-hr[first].getCenterY(); - - if(dx0*dy1-dy0*dx1>0) second=(first+3)%4; - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AYSliceSelection.java b/graphics/AtlantisJava/src/atlantis/interactions/AYSliceSelection.java deleted file mode 100755 index 41c0a8293cd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AYSliceSelection.java +++ /dev/null @@ -1,79 +0,0 @@ -package atlantis.interactions; - - -import java.awt.*; -import java.awt.geom.*; - - -/** - * A panel which selects a slice of the window in the x-direction. - * That is, it selects a rectangular region with a height equal to the - * full height of the window and with an adjustable width. - * - * @author Charles Loomis - **/ -public class AYSliceSelection extends ASelection { - - public AYSliceSelection() { - super(6); - } - - public int init(Point2D.Double p, int key) { - isValid=false; - - int xmax=window.getSize().width; - int xmid=xmax/2; - - setCenter(hr[0], 0, p.y); - setCenter(hr[1], 0, p.y); - setCenter(hr[2], xmax, p.y); - setCenter(hr[3], xmax, p.y); - setCenter(hr[4], xmid, p.y); - setCenter(hr[5], xmid, p.y); - - region=5; - return region; - } - - public void drag(Point2D.Double p, int region, int key) { - isValid=true; - - switch(region) { - case 0: - case 3: - case 4: - setCenterY(hr[0], p.y); - setCenterY(hr[3], p.y); - setCenterY(hr[4], p.y); - break; - - case 1: - case 2: - case 5: - setCenterY(hr[1], p.y); - setCenterY(hr[2], p.y); - setCenterY(hr[5], p.y); - break; - } - } - - public void paint(Graphics2D g) { - paintStandard(g); - } - - public Point2D.Double[] getCorners() { - // Sort out which are the three control points. - int first=1; - int second=2; - int third=3; - - if(hr[1].getCenterY()>hr[0].getCenterY()) { - first=0; - second=3; - third=2; - } - - return convert(first, second, third); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AZMRGroup.java b/graphics/AtlantisJava/src/atlantis/interactions/AZMRGroup.java deleted file mode 100755 index 9b6903d9fb4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AZMRGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -package atlantis.interactions; - - -public class AZMRGroup extends AInteractionGroup { - - private AZMRInteraction transformInteraction; - - public AZMRGroup(AInteractionsManager iManager) { - super(AInteractionGroup.WINDOW_GROUP, iManager); - transformInteraction=new AZMRInteraction(); - this.addInteraction(transformInteraction); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/AZMRInteraction.java b/graphics/AtlantisJava/src/atlantis/interactions/AZMRInteraction.java deleted file mode 100755 index db82da56f33..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/AZMRInteraction.java +++ /dev/null @@ -1,700 +0,0 @@ -package atlantis.interactions; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; - -import javax.swing.JMenuItem; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.event.AEventManager; -import atlantis.graphics.ACursorFactory; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.projection.AProjection; -import atlantis.projection.AProjection2D; -import atlantis.projection.AProjection3D; -import atlantis.projection.AProjectionFR; -import atlantis.projection.AProjectionFZ; -import atlantis.projection.AProjectionLegoPlot; -import atlantis.projection.AProjectionRZ; -import atlantis.projection.AProjectionVP; -import atlantis.projection.AProjectionXZ; -import atlantis.projection.AProjectionYX; -import atlantis.projection.AProjectionYZ; -import atlantis.utils.AMath; -import atlantis.utils.AVector; - -/** - * The Zoom, Move and Rotate interaction. - */ -public class AZMRInteraction extends AInteraction implements - ASleepMouseDragListener, AMousePressListener, AEnterExitListener, ActionListener -{ - // when these values are reached on any of the coordinates, zooming takes - // no longer any effect - private static final double MINIMAL_ZOOM_LIMIT = 0.001; // [cm] = 10 um - private static final double MAXIMAL_ZOOM_LIMIT = 100000; // [cm] = 1000 m - - private static final int ZOOM_MODE = 0; - private static final int HORIZONTAL_ZOOM_MODE = 1; - private static final int VERTICAL_ZOOM_MODE = 2; - private static final int ROTATE_MODE = 3; - private static final int MOVE_MODE = 5; - - private int centerMarkRadius = 6; - private Point2D.Double p0; - private int previousKey = KeyEvent.VK_UNDEFINED; - private int mode; - private JMenuItem[] popupItems; - private final static String TO_CENTER_OF_DETECTOR = "To Center Of Detector"; - private final static String CENTER_PICTURE = "Center The Picture"; - private final static String ASPECT_RATIO_1 = "Aspect Ratio 1"; - private final static String UNZOOM_FULL = "Unzoom Full"; - - // if false, none of the ZMR interactions will have the red central dot - // painted - private static boolean paintCenterDot = true; - - public AZMRInteraction() - { - super(1, AUTOMATIC_REPAINT, WORLD_COORDINATES, false); - - popupItems = new JMenuItem[] { - new JMenuItem(TO_CENTER_OF_DETECTOR), - new JMenuItem(CENTER_PICTURE), - new JMenuItem(UNZOOM_FULL)}; - - for (int i = 0; i < popupItems.length; i++) { - popupItems[i].addActionListener(this); - } - - // The center of the ellipse is in (0, 0) in User Space - hr[0] = new Ellipse2D.Double(-centerMarkRadius / 2, - -centerMarkRadius / 2, centerMarkRadius, centerMarkRadius); - - //By default we are in zoom mode - mode = ZOOM_MODE; - } - - public static void setPaintCenterDot(boolean state) - { - paintCenterDot = state; - } - - public void connect(AInteractionsManager manager) - { - super.connect(manager); - Point2D.Double c = ((AProjection2D) window.getProjection()).getCenter(); - - setCenter(hr[0], c.x, c.y); - } - - public int getPressButton() - { - return AInteractionsManager.LEFT; - } - - public int init(Point2D.Double p, int key) - { - keyChange(p, key); - return -1; - } - - public void pressed(Point2D.Double p, int button, int key) - { - if (key == KeyEvent.VK_C) - setCenter(hr[0], p.x, p.y); - if (key == KeyEvent.VK_0){ - double[] primaryVertex = AEventManager.instance().getCurrentEvent().getPrimaryVertex(); - if(window.getProjection().getName().equals("YX")) setCenter(hr[0], primaryVertex[0], primaryVertex[1]); - if(window.getProjection().getName().equals("RZ")) { - double phiMid2 = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(Math.atan2(primaryVertex[1], primaryVertex[0]) - phiMid2); - int s=-1; - if (phiDiff < Math.PI / 2. || phiDiff > 3 * Math.PI / 2.) s = 1; - setCenter(hr[0], primaryVertex[2], s*Math.sqrt(primaryVertex[0]*primaryVertex[0]+primaryVertex[1]*primaryVertex[1])); - } - } - } - - public int getButton() - { - return AInteractionsManager.LEFT; - } - - public void start(Point2D.Double p, int region, int key) - {} - - private double getHd0(Point2D.Double p) - { - Point2D.Double[] c = window.getUserCorners(); - AVector v21 = new AVector(c[2].x, c[2].y, c[1].x, c[1].y); - AVector v10 = new AVector(c[1].x, c[1].y, c[0].x, c[0].y); - Point2D.Double center = getCenter(hr[0]); - - return p.distance(AMath.intersectionPoint(center, v21, p, v10)); - } - - private double getVd0(Point2D.Double p) - { - Point2D.Double[] c = window.getUserCorners(); - AVector v01 = new AVector(c[0].x, c[0].y, c[1].x, c[1].y); - AVector v12 = new AVector(c[1].x, c[1].y, c[2].x, c[2].y); - Point2D.Double center = getCenter(hr[0]); - - return p.distance(AMath.intersectionPoint(center, v01, p, v12)); - } - - private void keyChange(Point2D.Double p, int key) - { - p0 = p; - - switch (key) - { - case KeyEvent.VK_UNDEFINED: - mode = ZOOM_MODE; - break; - - case KeyEvent.VK_H: - mode = HORIZONTAL_ZOOM_MODE; - break; - - case KeyEvent.VK_V: - mode = VERTICAL_ZOOM_MODE; - break; - - case KeyEvent.VK_R: - mode = ROTATE_MODE; - break; - - case KeyEvent.VK_M: - mode = MOVE_MODE; - break; - - case KeyEvent.VK_Z: - mode = ZOOM_MODE; - break; - } - - //Update cursor mode when key changes - setCursorMode(); - } - - public void drag(Point2D.Double p, int region, int key) - { - - if (key != previousKey) - { - keyChange(p, key); - previousKey = key; - } - - double zf; - Point2D.Double center = getCenter(hr[0]); - AProjection proj = window.getProjection(); - - switch (mode) - { - case ZOOM_MODE: - zf = p0.distance(center.x, center.y) - / p.distance(center.x, center.y); - performZoom(getCenter(hr[0]), zf, window); - break; - - case HORIZONTAL_ZOOM_MODE: - zf = getHd0(p0) / getHd0(p); - performHorizontalZoom(center, zf, window); - break; - - case VERTICAL_ZOOM_MODE: - zf = getVd0(p0) / getVd0(p); - performVerticalZoom(center, zf, window); - break; - - case ROTATE_MODE: - if ((proj instanceof AProjectionFR) - || (proj instanceof AProjectionFZ) - || (proj instanceof AProjectionVP)) - performPhiRotation(p.y - p0.y, window); - else if (proj instanceof AProjectionLegoPlot) - performLegoRotation(center, p.x - p0.x, p.y - p0.y, window); - else - { - if ((proj instanceof AProjectionRZ) - || (proj instanceof AProjectionXZ) - || (proj instanceof AProjectionYZ) - || (proj instanceof AProjection3D)) - { - AParameter phiPar = parameterStore.get(proj.getName(), "Phi"); - if (proj instanceof AProjection3D) - { - Point2D.Double pDisp = window.calculateDisplay(p); - Point2D.Double p0Disp = window.calculateDisplay(p0); - double height = window.getCurrDisp().getHeight(); - double deltaV = pDisp.getY() - p0Disp.getY(); - phiPar.setD(adjustPhi(phiPar.getD() + 360. * deltaV - / height)); - } - else - phiPar.setD(adjustPhi(phiPar.getD() + (p.y - p0.y))); - p0 = p; - ACanvas.getCanvas().repaintAllFromScratch(); - } - else - { - double alpha = AMath.getAngle(p0, center) - - AMath.getAngle(p, center); - - performRotation(alpha, center, window); - if (proj instanceof AProjectionYX) - { - AParameter phiPar = parameterStore.get(proj.getName(), "Phi"); - - phiPar.setD(adjustPhi(phiPar.getD() + Math.toDegrees(alpha))); - } - } - } - break; - - case MOVE_MODE: - if ((proj instanceof AProjectionFR) - || (proj instanceof AProjectionFZ) - || (proj instanceof AProjectionVP)) - { - performMove(p.x - p0.x, 0, window); - performPhiRotation(p.y - p0.y, window); - } - else - performMove(p.x - p0.x, p.y - p0.y, window); - break; - } - } // drag() - // --------------------------------------------------------------- - - private double adjustPhi(double phi) - { - while (phi < 0) - phi += 360; - while (phi > 360) - phi -= 360; - return phi; - } - - public void stop() - {} - - public void cancel() - {} - - public void paint(Graphics2D g) - { - Point2D.Double p = window.calculateDisplay(getCenter(hr[0])); - - //don't draw red dot if not drawing the lego plot - //(i.e. when just drawing the legend) - boolean paintingJustLegoLegend = false; - if(window.getProjection().getName().equals("LegoPlot")) - { - parameterStore.selectWindowParameters(window.getName()); - if(!parameterStore.get("LegoPlot","DrawPlot").getStatus()) - paintingJustLegoLegend=true; - parameterStore.restoreWindowParameters(); - } - - if (paintCenterDot && !paintingJustLegoLegend) - { - g.setColor(Color.red); - g.fillOval((int) (p.x - centerMarkRadius / 2), - (int) (p.y - centerMarkRadius / 2), centerMarkRadius, - centerMarkRadius); - } - } - - /** - * Check the coordinates of the corners. If any of the limits was already - * reached, zooming / unzooming takes no longer any effect. - * - * @param corners Double - * @return boolean - */ - private static boolean checkCornerLimits(Point2D.Double[] corners) - { - - for (int i = 0; i < corners.length; i++) - { - //Get the difference in x and y off this corner and the next - //There is at most 3 corners - this will give us all of the combinations - double dX=Math.abs(corners[i].x-corners[(i+1)%(corners.length-1)].x); - double dY=Math.abs(corners[i].y-corners[(i+1)%(corners.length-1)].y); - //Coordinates will differ in only x OR y, get the one that does - double dMax = Math.max(dX,dY); - //Check that corner coordinate difference is within limits - if ((dMax < MINIMAL_ZOOM_LIMIT) || (dMax > MAXIMAL_ZOOM_LIMIT)) - { - AOutput.alwaysAppend("zoom / unzoom limit reached\n", - ALogInterface.NORMAL); - return false; - } - } - return true; - } // checkTheCornerLimits() - - - public static void performZoom(Point2D.Double center, double zf, - AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - for (int i = 0; i < corners.length; i++) - { - corners[i].x = center.x + (corners[i].x - center.x) * zf; - corners[i].y = center.y + (corners[i].y - center.y) * zf; - } - - if (!checkCornerLimits(corners)) - { - return; // zooming has already reached its limit - } - - window.setUserCorners(corners); - } - - public static void performRotation(double angle, Point2D.Double center, - AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - double cos = Math.cos(angle); - double sin = Math.sin(angle); - - for (int i = 0; i < corners.length; i++) - { - double dx = corners[i].x - center.x; - double dy = corners[i].y - center.y; - - corners[i].x = center.x + dx * cos - dy * sin; - corners[i].y = center.y + dx * sin + dy * cos; - } - - window.setUserCorners(corners); - } - - public static void performMinus90Rotation(AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - AVector v12 = new AVector(corners[1], corners[2]); - double x3 = corners[0].x + v12.dx; - double y3 = corners[0].y + v12.dy; - - corners[0].setLocation(corners[1]); - corners[1].setLocation(corners[2]); - corners[2].setLocation(x3, y3); - - window.setUserCorners(corners); - } - - public static void performPlus90Rotation(AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - AVector v12 = new AVector(corners[1], corners[2]); - double x3 = corners[0].x + v12.dx; - double y3 = corners[0].y + v12.dy; - - corners[2].setLocation(corners[1].x, corners[1].y); - corners[1].setLocation(corners[0].x, corners[0].y); - corners[0].setLocation(x3, y3); - - window.setUserCorners(corners); - } - - public static void performPhiRotation(double dPhi, AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - for (int i = 0; i < corners.length; i++) - corners[i].y -= dPhi; - - window.setUserCorners(corners); - } - - public void performLegoRotation(Point2D.Double center, double dPhi, - double dEta, AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - if (dPhi != 0.0 || dEta != 0.0) - { - //get original phi coord in 0-360 range - double centerX = -AProjectionLegoPlot.adjustPhi(window, -center.x, center.y); - - corners[0].x -= (dPhi); - // x offset=xz*360 so xz=change/360 - AProjectionLegoPlot.setxz(window.getIndex(), AProjectionLegoPlot - .getxz(window.getIndex()) - + (dPhi) / 360); - - if (AProjectionLegoPlot.getyz(window.getIndex()) < 1.0 - || (dEta) > 0.0) - { - corners[0].y -= (dEta); - corners[1].y -= (dEta); - // y offset=yz*50 so yz=change/50 - AProjectionLegoPlot.setyz(window.getIndex(), - AProjectionLegoPlot.getyz(window.getIndex()) - (dEta) - / 50); - } - - //now have changed xz recalcuate phi coordinte - center.x = AProjectionLegoPlot.adjustPhi(window, centerX, center.y); - setCenter(hr[0], center.x, center.y); - - window.setUserCorners(corners); - } - } - - public static void performHorizontalZoom(Point2D.Double center, double f, - AWindow window) - { - Point2D.Double[] c = window.getUserCorners(); - AVector v21 = new AVector(c[2].x, c[2].y, c[1].x, c[1].y); - Point2D.Double center1 = new Point2D.Double(center.x + v21.dx, center.y - + v21.dy); - Point2D.Double p0 = AMath - .intersectionPoint(c[0], c[1], center, center1); - - AVector v0 = new AVector(p0, c[0]).scale(f); - AVector v1 = new AVector(p0, c[1]).scale(f); - - c[0].x = p0.x + v0.dx; - c[0].y = p0.y + v0.dy; - - c[1].x = p0.x + v1.dx; - c[1].y = p0.y + v1.dy; - - v21.invert(); - p0.setLocation(p0.x + v21.dx, p0.y + v21.dy); - c[2].x = p0.x + v1.dx; - c[2].y = p0.y + v1.dy; - - if (!checkCornerLimits(c)) - { - return; // zooming has already reached its limit - } - - window.setUserCorners(c); - - } - - public static void performVerticalZoom(Point2D.Double center, double f, - AWindow window) - { - Point2D.Double[] c = window.getUserCorners(); - AVector v01 = new AVector(c[0].x, c[0].y, c[1].x, c[1].y); - Point2D.Double center1 = new Point2D.Double(center.x + v01.dx, center.y - + v01.dy); - Point2D.Double p0 = AMath - .intersectionPoint(c[1], c[2], center, center1); - - AVector v1 = new AVector(p0, c[1]).scale(f); - AVector v2 = new AVector(p0, c[2]).scale(f); - - c[1].x = p0.x + v1.dx; - c[1].y = p0.y + v1.dy; - - c[2].x = p0.x + v2.dx; - c[2].y = p0.y + v2.dy; - - v01.invert(); - p0.setLocation(p0.x + v01.dx, p0.y + v01.dy); - c[0].x = p0.x + v1.dx; - c[0].y = p0.y + v1.dy; - - if (!checkCornerLimits(c)) - { - return; // zooming has already reached its limit - } - - window.setUserCorners(c); - - } - - public static void performMove(double dx, double dy, AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - - for (int i = 0; i < corners.length; i++) - { - corners[i].x -= dx; - corners[i].y -= dy; - } - - window.setUserCorners(corners); - } - - public static Line2D.Double getMiddleHorizontalLine(AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - AVector v12 = new AVector(corners[1], corners[2]).scale(0.5); - - return new Line2D.Double(corners[0].x + v12.dx, corners[0].y + v12.dy, - corners[1].x + v12.dx, corners[1].y + v12.dy); - } - - public static Line2D.Double getMiddleVerticalLine(AWindow window) - { - Point2D.Double[] corners = window.getUserCorners(); - AVector v10 = new AVector(corners[1], corners[0]).scale(0.5); - - return new Line2D.Double(corners[1].x + v10.dx, corners[1].y + v10.dy, - corners[2].x + v10.dx, corners[2].y + v10.dy); - } - - public static void performFlip(Line2D.Double line, AWindow window) - { - if (line == null) - return; - - Point2D.Double[] corners = window.getUserCorners(); - double dSquare = Point2D.distanceSq(line.x1, line.y1, line.x2, line.y2); - - for (int i = 0; i < corners.length; i++) - { - double u = (1 / dSquare) - * ((corners[i].x - line.x1) * (line.x2 - line.x1) + (corners[i].y - line.y1) - * (line.y2 - line.y1)); - - double x0 = line.x1 + u * (line.x2 - line.x1); - double y0 = line.y1 + u * (line.y2 - line.y1); - - corners[i].x = 2 * x0 - corners[i].x; - corners[i].y = 2 * y0 - corners[i].y; - } - - window.setUserCorners(corners); - } - - /** - * Set cursor acording to current mode - */ - public void setCursorMode(){ - //check which mode we have - switch (mode) - { - case ZOOM_MODE: - window.setCursor(ACursorFactory.getInstance().getZoomCursor()); - break; - - case HORIZONTAL_ZOOM_MODE: - window.setCursor(ACursorFactory.getInstance().getZoomCursor()); - break; - - case VERTICAL_ZOOM_MODE: - window.setCursor(ACursorFactory.getInstance().getZoomCursor()); - break; - - case ROTATE_MODE: - window.setCursor(ACursorFactory.getInstance().getRotateCursor()); - break; - - case MOVE_MODE: - window.setCursor(ACursorFactory.getInstance().getMoveCursor()); - break; - } - } - - /** - * Gets called each time we enter a window in which this interaction is active - */ - public void entered() - { - //Set mouse cursor according to current mode - setCursorMode(); - } - - /** - * Gets called each time we leave a window in which this interaction is active - */ - public void exited() - { - //Set mouse cursor - window.setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - public int getPopupType() - { - return APopupListener.WINDOW_POPUP; - } - - public JMenuItem[] getPopupItems() { - return popupItems; - } - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - - if (action.equals(TO_CENTER_OF_DETECTOR)) - { - Point2D.Double c = ((AProjection2D) window.getProjection()) - .getCenter(); - - setCenter(hr[0], c.x, c.y); - window.repaint(); - } - else if (action.equals(CENTER_PICTURE)) - { - Point2D.Double[] c = window.getUserCorners(); - AVector v02 = new AVector(c[0].x, c[0].y, c[2].x, c[2].y) - .scale(0.5); - double xc = c[0].x + v02.dx; - double yc = c[0].y + v02.dy; - AVector vC0 = new AVector(xc, yc, 0, 0); - AProjection proj = window.getProjection(); - if (proj instanceof AProjectionLegoPlot) - vC0 = new AVector(xc, yc, 180 * (1 - AProjectionLegoPlot - .getxz(window.getIndex())), -5); - // 180*(1-AProjectionLegoPlot.xz), -5 is different center as center - // of plot is not at 0,0 - - for (int i = 0; i < c.length; i++) - { - c[i].x += vC0.dx; - c[i].y += vC0.dy; - } - window.setUserCorners(c); - } else if (action.equals(ASPECT_RATIO_1)) { - ((AProjection2D) window.getProjection()).setAspectRatio1(window); - } - else if (action.equals(UNZOOM_FULL)) - { - window.setUserCorners(((AProjection2D) window.getProjection()). - calculateNoZoomCorners(window.getSize())); - } - } - - public AModifier[] getModifiers() - { - return new AModifier[] { - new AModifier(KeyEvent.VK_UNDEFINED, false, "Zoom"), - new AModifier(KeyEvent.VK_Z, false, "Zoom"), - new AModifier(KeyEvent.VK_H, false, "Horizonatal Zoom"), - new AModifier(KeyEvent.VK_V, false, "Vertical Zoom"), - new AModifier(KeyEvent.VK_R, false, "Rotate"), - new AModifier(KeyEvent.VK_F, false, "Fast Zoom"), - new AModifier(KeyEvent.VK_M, false, "Move (pan)"), - new AModifier(KeyEvent.VK_C, false, "Modify Central Point") - }; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/interactions/package.html b/graphics/AtlantisJava/src/atlantis/interactions/package.html deleted file mode 100644 index 85cfaaddcc8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/interactions/package.html +++ /dev/null @@ -1,11 +0,0 @@ -<html> -<head></head> -<body> -<p>This package contains implementation of various interactions with -the application such as the main ZMR (1Zoom Move Rotation), Fisheye, -etc. Each AWindow has an AInteractionManager which tells the current -interaction, e.g. ZMR, about what is happening with the mouse on that -window. -</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/list/AColorIcon.java b/graphics/AtlantisJava/src/atlantis/list/AColorIcon.java deleted file mode 100755 index a77acc2917d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/list/AColorIcon.java +++ /dev/null @@ -1,69 +0,0 @@ -package atlantis.list; - - -import javax.swing.Icon; -import java.awt.*; - -import atlantis.graphics.colormap.AColorMap; - - -// icon with size and color - -class AColorIcon implements Icon { - private int w, h; - private int colorIndex; - - public AColorIcon() { - this(AColorMap.WH, 50, 15); - } - - public AColorIcon(Dimension d) { - this.w=d.width; - this.h=d.height; - } - - public AColorIcon(int colorIndex, int w, int h) { - this.colorIndex=colorIndex; - this.w=w; - this.h=h; - } - - public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(Color.black); - g.drawRect(x, y, w-1, h-1); - if(colorIndex==AColorMap.INVISIBLE) { - g.setColor(AColorMap.getColors()[AColorMap.WH]); - g.fillRect(x+1, y+1, w-2, h-2); - g.setColor(Color.black); - g.drawLine(x, y, x+w-1, y+h-1); - g.drawLine(x, y+h-1, x+w-1, y); - } else if(colorIndex==AColorMap.NO_COLOR) { - g.setColor(AColorMap.getColors()[AColorMap.WH]); - g.fillRect(x+1, y+1, w-2, h-2); - g.setColor(Color.black); - int xc=x+w/2; - int yc=y+h/2; - g.drawLine(xc, yc-2, xc, yc+2); - g.drawLine(xc-2, yc, xc+2, yc); - } else { - g.setColor(AColorMap.getColors()[colorIndex]); - g.fillRect(x+1, y+1, w-2, h-2); - } - } - - public int getColorIndex() { - return colorIndex; - } - - public void setColorIndex(int colorIndex) { - this.colorIndex=colorIndex; - } - - public int getIconWidth() { - return w; - } - - public int getIconHeight() { - return h; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/list/AList.java b/graphics/AtlantisJava/src/atlantis/list/AList.java deleted file mode 100755 index 7377bef99e9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/list/AList.java +++ /dev/null @@ -1,128 +0,0 @@ -package atlantis.list; - -import atlantis.event.AData; - -/** - * Instance of AList as seen in AListManager (Lists) - * source references instance of the datatype in the list - * <ul> - * <li>itemsIndex is a list of indices (Atlantis internal datatitems indices) - * of the particular datape which are in the list</li> - * <li>itemsID is a list of dataitems IDs of the datatype in the list</li> - * </ul> - * - * <p>index and id is identical for Track for instance, but different for - * calo cells. When masking data on cross-event basis, IDs are necessary - * (e.g. masking hot calo cells based on their IDs)</p> - * - * <p>Copyright: Copyright (c) 2002</p> - * - * @author not attributable - * @version 1.0 - */ -public class AList -{ - private AData source; - private int[] itemsIndex; - private int[] itemsID; - - - /** - * - * @param data AData - * @param singleItem int - index of the dataitem to put in the list - */ - public AList(AData data, int singleItem) - { - source = data; - itemsIndex = new int[] { singleItem }; - itemsID = new int[] { source.getIdFromIndex(singleItem) }; - - } // AList() ------------------------------------------------------------ - - - - public AList(AData data, boolean[] drawn) - { - source = data; - int num = 0; - for(int i = 0; i < drawn.length; ++i) - { - if(drawn[i]) - { - num++; - } - } - - itemsIndex = new int[num]; - itemsID = new int[num]; - num = 0; - - for(int i = 0; i < drawn.length; ++i) - { - if(drawn[i]) - { - itemsIndex[num] = i; - itemsID[num] = source.getIdFromIndex(i); - num++; - } - } - - } // AList() ------------------------------------------------------------ - - - - /** - * String representation of the AList instance. Returns the datatype name, - * resp. screen name and if there one item in the only, then the item's - * ID. If there are more items, it says the number of dataitems. - * @return String - */ - public String toString() - { - String key = source.getStoreGateKey(); - String sn = source.getNameScreenName(); - String name = key != null ? sn + ":" + key : sn; - - if(itemsIndex.length == 1) - { - return name + " " + source.getIdFromIndex(itemsIndex[0]); - } - else - { - return name + " (" + itemsIndex.length + " items)"; - } - - } // toString() --------------------------------------------------------- - - - - public AData getSource() - { - return source; - - } // getSource() -------------------------------------------------------- - - - - /** - * Returns indices of the items in the list (internal Atlantis indices - * which are *sometimes* identical with IDs) - * @return int[] - */ - public int[] getItems() - { - return itemsIndex; - - } // getItems() --------------------------------------------------------- - - - - public int[] getItemsID() - { - return itemsID; - - } // getItemsID() ------------------------------------------------------- - - -} // class AList ============================================================ diff --git a/graphics/AtlantisJava/src/atlantis/list/AListManager.java b/graphics/AtlantisJava/src/atlantis/list/AListManager.java deleted file mode 100755 index 815d922e087..00000000000 --- a/graphics/AtlantisJava/src/atlantis/list/AListManager.java +++ /dev/null @@ -1,1765 +0,0 @@ -package atlantis.list; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Insets; -import java.awt.Point; -import java.awt.dnd.DragSource; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Box; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -import atlantis.canvas.ACanvas; -import atlantis.data.AHelix; -import atlantis.data.ARVxData; -import atlantis.data.ATrackData; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACursorFactory; -import atlantis.graphics.AIcon; -import atlantis.graphics.APickingGraphics2D; -import atlantis.graphics.colormap.AColorMap; -import atlantis.gui.AGUI; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.APar; -import atlantis.utils.A4Vector; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; -import atlantis.utils.AUtilities; - -public class AListManager extends JTree implements MouseListener, MouseMotionListener -{ - private static ALogger logger = ALogger.getLogger(AListManager.class); - private static AEventManager eventManager = AEventManager.instance(); - - // used to display the tree - static private JFrame dialog; // rather than JDialog - // special nodes - static private final DefaultMutableTreeNode root = new DefaultMutableTreeNode("Lists"); - static private final DefaultMutableTreeNode highlight = new DefaultMutableTreeNode("Highlight"); - static private final DefaultMutableTreeNode lastDrawn = new DefaultMutableTreeNode("Last Drawn"); - static private final DefaultMutableTreeNode others = new DefaultMutableTreeNode("Others"); - static private final DefaultMutableTreeNode invisible = new DefaultMutableTreeNode("Invisible"); - static private final DefaultMutableTreeNode mass = new DefaultMutableTreeNode("Calculation"); - // instance - static private final AListManager listManager = new AListManager(); - static private DefaultTreeModel dtm; - static private int numLists = 0; - // source and status of Drag and Drop - static private DefaultMutableTreeNode source = null; - static private boolean draging = false; - static private HashMapSet nodeColors; - - // counters for V0 mass calc - static private int V0vx=0; - static private int V0tracks=0; - static private int V0charge=0; - - // private static final Cursor DROP_VALID = DragSource.DefaultMoveDrop; - private static final Cursor DROP_VALID_COPY = DragSource.DefaultCopyDrop; - // private static final Cursor DROP_INVALID = DragSource.DefaultMoveNoDrop; - - - - private AListManager() - { - super(root, true); - dtm = (DefaultTreeModel) getModel(); - nodeColors = new HashMapSet(); - reset(); - - addMouseListener(this); - addMouseMotionListener(this); - setSelectionRow(1); - setPreferredSize(new Dimension(200, 300)); - setRootVisible(true); - setScrollsOnExpand(true); - setShowsRootHandles(false); - setCellRenderer(new ColorRenderer()); - - if (!AGlobals.isAtlantisHeadless()) { - // set up the visual representation - dialog = new JFrame("List manager"); - AIcon.setIconImage(dialog); - Box b = Box.createHorizontalBox(); - b.add(new JScrollPane(this)); - b.add(new ColorPanel()); - dialog.getContentPane().add(b); - dialog.pack(); - dialog.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - } - - } // AListManager() ----------------------------------------------------- - - - - public static AListManager getInstance() - { - return listManager; - - } // getInstance() ------------------------------------------------------ - - - - public void showLists() - { - Component gui = AGlobals.instance().getGuiFrame(); - if (gui != null) - { - dialog.setLocation(gui.getLocation()); - } - dialog.setVisible(true); - - } // showLists() -------------------------------------------------------- - - - - private boolean isAlreadyInTheList(AList list, - DefaultMutableTreeNode destination) - { - boolean already = false; - for(int i = 0; i < destination.getChildCount(); i++) - { - DefaultMutableTreeNode child = - (DefaultMutableTreeNode) destination.getChildAt(i); - if(!child.getAllowsChildren()) - { - AList a = (AList) child.getUserObject(); - if(a.getSource() == list.getSource()) - { - int[] items = a.getItems(); - int newItem = list.getItems()[0]; - for(int j = 0; j < items.length; ++j) - { - if(items[j] == newItem) - { - already = true; - } - } - } - } - } - - return already; - - } // isAlreadyInTheList() ----------------------------------------------- - - - - public void add(AList list) - { - if(!dialog.isVisible()) - { - dialog.setVisible(true); - } - - // default destination - DefaultMutableTreeNode destination = root; - TreePath tp = getSelectionPath(); - if(tp != null) - { - destination = (DefaultMutableTreeNode) tp.getLastPathComponent(); - } - - if(destination != null && destination.getAllowsChildren()) - { - if(destination == others || destination == lastDrawn || - destination == highlight || destination == invisible || - destination == mass) - { - AOutput.alwaysAppend("Can't add to " + destination, ALogInterface.WARNING); - return; - } - - // check if it's already in the list and if so, don't add - boolean already = this.isAlreadyInTheList(list, destination); - if(already) - { - logger.info(list + " is already in this list, not added"); - } - else - { - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), - destination, destination.getChildCount()); - expandPath(new TreePath(dtm.getPathToRoot(destination))); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - - } // add() ------------------------------------------------------------- - - - - /** - * Adds the selected item to the mass list and outputs the invariant mass in the output window - * Doesn't make the list visible as really only need to see output window - * @param list - */ - public void massCalc(AList list) - { - // default destination - DefaultMutableTreeNode destination = mass; - TreePath tp = getSelectionPath(); - - if(destination != null && destination.getAllowsChildren()) - { - // check if it's already in the list and if so, don't add - boolean already = this.isAlreadyInTheList(list, destination); - if(already) - { - logger.info(list + " is already in this list, not added"); - } - else - { - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), - destination, destination.getChildCount()); - expandPath(new TreePath(dtm.getPathToRoot(destination))); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - - if (tp != null) - { - setSelectionPath(tp); - } - - // added to list, now do summarise - Summarizer summ = new Summarizer(); - AOutput.alwaysAppend(summ.getHeader(), ALogInterface.NORMAL); - - AList[] children = getChildren(mass); - - int chiLength = children.length; - - for(int i = 0; i < chiLength; i++) - { - int num = children[i].getItems().length; - A4Vector v = children[i].getSource().get4Vector(num, - children[i].getItems(),0.14); //assume pion mass - - - if(v != null && num > 0) - { - String info = summ.addAndGetInfo(v, children[i].toString()); - AOutput.alwaysAppend(info, ALogInterface.NORMAL); - } - } - - String msg = summ.getTotalInfo(); - - AOutput.alwaysAppend(msg, ALogInterface.NORMAL_BOLD); // Print default summary (ie, assuming pi mass for all) - - summ = null; - - } // massCalc() ------------------------------------------------------------- - - /** - * Adds the selected item to the mass list and outputs the invariant mass in the output window - * Doesn't make the list visible as really only need to see output window - * This is the massCalc function for V0 decays. Check for up to 2 tracks and display 4 mass scenarios - * @param list - */ - public void massCalcV0(AList list) - { - // default destination - DefaultMutableTreeNode destination = mass; - TreePath tp = getSelectionPath(); - - if(getChildren(mass).length == 0) // if list is empty, make sure counters are reinitialised - { - V0vx=0; - V0tracks=0; - V0charge=0; - } - - if(destination != null && destination.getAllowsChildren()) - { - // check if it's already in the list and if so, don't add - boolean already = this.isAlreadyInTheList(list, destination); - - // check list for tracks and vertices (to a maximum of 2 tracks and 1 vertex) - if(getChildren(mass).length < 3) - { - if(already) - { - logger.info(list + " is already in this list, not added"); - } - else if(!(list.getSource() instanceof ARVxData || list.getSource() instanceof ATrackData)) - { - logger.info("not selected a track or vertex"); - AOutput.alwaysAppend("\n\n Not selected a track or vertex\n\n",ALogInterface.PICK); - return; - } - else if((list.getSource() instanceof ARVxData && V0vx>=1) || (list.getSource() instanceof ATrackData && V0tracks>=2)) - { - logger.info("already a vertex or two tracks selected"); - AOutput.alwaysAppend("\n\n Already a vertex or two tracks selected\n",ALogInterface.PICK); - return; - } - else - { - - // check the charges of the two tracks are opposite - // - if((list.getSource() instanceof ATrackData)) - { - ATrackData track = (ATrackData) list.getSource(); - AHelix h = track.getModifiableHelix(list.getItemsID()[0]); - if((V0charge != 0) && (V0charge * AMath.getSign(h.pT()) > 0)) - { - logger.info("2nd track is same charge as 1st track"); - AOutput.alwaysAppend("\n\nPlease pick an oppositely charged track\n", ALogInterface.PICK); - return; - } - } //end check charge - - // now increment the counters - // all tests passed, now can input into list. - - if(list.getSource() instanceof ATrackData) - { - V0tracks++; - logger.info("Selected a Track"); - } - else if(list.getSource() instanceof ARVxData) - { - V0vx++; - logger.info("Selected a Vertex"); - } - - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), - destination, destination.getChildCount()); - expandPath(new TreePath(dtm.getPathToRoot(destination))); - ACanvas.getCanvas().repaintAllFromScratch(); - } - - } - else - { - logger.info("list full (max 2 tracks + 1 vertex)"); - AOutput.alwaysAppend("\n\n List full (max 2 tracks + 1 vertex)\n",ALogInterface.PICK); - return; - } - } - if (tp != null) - { - setSelectionPath(tp); - } - - - // added to list, now do summarise - Summarizer summK = new Summarizer(); // K -> pi pi - Summarizer summL = new Summarizer(); // Lambda -> pi p - Summarizer summAL = new Summarizer(); // AntiLambda -> pi pbar - Summarizer summG = new Summarizer(); // gamma -> ee - - double[] secVx = new double[3]; // initialisation of secVx x,y,z array, if no vertex selected, use primary - double[] priVx = new double[3]; // primary vertex container (used to calculate decay length) - APar parameterStore = APar.instance(); - priVx[0]=parameterStore.get("Event", "XVtx").getD(); - priVx[1]=parameterStore.get("Event", "YVtx").getD(); - priVx[2]=parameterStore.get("Event", "ZVtx").getD(); - - secVx=priVx; - - AList[] children = getChildren(mass); - - - int chiLength = children.length; - - if(chiLength == 3) - { - boolean V0title = true; - for(int i = 0; i < chiLength; i++) - { - AData source = children[i].getSource(); - //ordering of the list is important. - //if vertex selected second, then the tracks selected before use primary vertex... - //need to get secVx first, THEN calculate tracks... - if(source instanceof ARVxData) - { - ARVxData rvx = (ARVxData) source; - secVx = rvx.getVertex(children[i].getItemsID()[0]); // gets x,y,z of the picked vertex. - } - } - - for(int i = 0; i < chiLength; i++) - { - - AData source = children[i].getSource(); - - if(source instanceof ATrackData) - { - ATrackData track = (ATrackData) source; - - // get helix of picked track - AHelix h = track.getModifiableHelix(children[i].getItemsID()[0]); - - // get charge for charge check - V0charge = (int) (Math.abs(h.pT())/h.pT()); - - int num = children[i].getItems().length; - - // initialise 4 vectors - A4Vector vK = source.get4Vector(num, - children[i].getItems(),0.0); - A4Vector vL = source.get4Vector(num, - children[i].getItems(),0.0); - A4Vector vAL = source.get4Vector(num, - children[i].getItems(),0.0); - A4Vector vG = source.get4Vector(num, - children[i].getItems(),0.0); - - - // now calculate the 4 vector - if(V0vx > 0) - { - double R = parameterStore.get("Event", "Curvature").getD() * Math.abs(h.pT()); - - // +1/-1 for a clockwise/anti-clockwise helix - double S = (int) (Math.abs(h.pT())/h.pT()); - - // Coordinates of the center point for the helix - double xC = (S * h.d0() - R) * Math.cos(Math.toRadians(h.phi0()) + S * Math.PI / 2.); - double yC = (S * h.d0() - R) * Math.sin(Math.toRadians(h.phi0()) + S * Math.PI / 2.); - - // calculate new phi from centre of curvature and secondary vertex - double phiPrime = Math.atan2(yC-secVx[1], xC-secVx[0]) + S*(Math.PI / 2.0); - - double px = Math.abs(h.pT()) * Math.cos(h.phi0()); - double py = Math.abs(h.pT()) * Math.sin(h.phi0()); - double pz = Math.abs(h.pT()) * Math.sinh(h.eta()); - - // recalculate px/py at secondary vertex - double pxPrime = Math.sqrt((px*px) + (py*py))*Math.cos(phiPrime); - double pyPrime = Math.sqrt((px*px) + (py*py))*Math.sin(phiPrime); - - px = pxPrime; - py = pyPrime; - - if(chiLength == 3 && !parameterStore.get("Minerva", "hideV0massoutput").getStatus()) - { - logger.info("recalculating tracks"); - AOutput.alwaysAppend("\n\nRecalculated track values:\n", ALogInterface.PICK); - AOutput.alwaysAppend(source.getNameScreenName()+" index: " + (children[i].getItemsID()[0]) + "\n" - +"PT="+String.format("%.3f",h.pT()) +" GeV\n" - +AMath.ETA+" = "+String.format("%.3f",h.eta())+"\n" - +AMath.PHI+" = "+String.format("%.3f",Math.toDegrees(phiPrime))+AMath.DEGREES+"\n" - +"Px=" + String.format("%.3f",px) +" GeV\n" - +"Py=" + String.format("%.3f",py) +" GeV\n" - +"Pz=" + String.format("%.3f",pz) +" GeV\n" - +"Charge = " + V0charge//Math.abs(V0charge) - ,ALogInterface.PICK); - } - else if(chiLength == 3) - { - if(V0title) - { - V0title = false; - - double decayLength = Math.sqrt(Math.pow(secVx[0]-priVx[0], 2.0)+Math.pow(secVx[1]-priVx[1], 2.0)+Math.pow(secVx[2]-priVx[2], 2.0)); - - AOutput.alwaysAppend("\n Decay length for selected vertex: "+String.format("%.2f",decayLength)+" cm\n\n", ALogInterface.PICK); - - - AOutput.alwaysAppend("\n Momentum for selected tracks: \n\n", ALogInterface.PICK); - } - if(V0charge>0) - AOutput.alwaysAppend("+ve track (px,py,pz): ("+String.format("%.3f",px)+", "+String.format("%.3f",py)+", "+String.format("%.3f",pz)+")\n", ALogInterface.PICK); - else if(V0charge <0) - AOutput.alwaysAppend("-ve track (px,py,pz): ("+String.format("%.3f",px)+", "+String.format("%.3f",py)+", "+String.format("%.3f",pz)+")\n", ALogInterface.PICK); - - } - - - /* now check charges of particles again and add to corresponding 4vectors - * - * scenarios: - * - * (K) Kaon -> pi+ pi- - * (L) Lambda -> proton pi- - * (AL)AntiLambda -> antiproton pi+ - * (G) Gamma -> e+ e- - * - * - * - */ - - // negative charge - if(V0charge < 0) - { - vK.set(px, py, pz, 0.1396); - vL.set(px, py, pz, 0.1396); - vAL.set(px, py, pz, 0.938); - vG.set(px, py, pz, 0.000511); - } - // positive charge - else if(V0charge > 0) - { - vK.set(px, py, pz, 0.1396); - vL.set(px, py, pz, 0.938); - vAL.set(px, py, pz, 0.1396); - vG.set(px, py, pz, 0.000511); - } - - - - // this is to display each track summary. - // currently off as too much summary crowds the output - if(vK != null && vL != null && vAL != null && vG != null && num > 0 && chiLength == 3) - { - String info = summK.addAndGetInfo(vK, children[i].toString()); - //AOutput.alwaysAppend(info, ALogPane.NORMAL); - info = summL.addAndGetInfo(vL, children[i].toString()); - //AOutput.alwaysAppend(info, ALogPane.NORMAL); - info = summAL.addAndGetInfo(vAL, children[i].toString()); - //AOutput.alwaysAppend(info, ALogPane.NORMAL); - info = summG.addAndGetInfo(vG, children[i].toString()); - //AOutput.alwaysAppend(info, ALogPane.NORMAL); - } - } - - } - } - - if(chiLength ==3 && !parameterStore.get("Minerva", "hideV0massoutput").getStatus()) - { - // Config switch to display either mass or px,py,pz. - String msgK = summK.getTotalInfo(); - String msgL = summL.getTotalInfo(); - String msgAL = summAL.getTotalInfo(); - String msgG = summG.getTotalInfo(); - - AOutput.alwaysAppend("\n V0 Decay Scenarios", ALogInterface.NORMAL_BOLD); - - AOutput.alwaysAppend(summK.getHeader(), ALogInterface.NORMAL); - - // print out the resultant mass calculation for each scenario - AOutput.alwaysAppend("K"+AMath.RARROW+AMath.PION+AMath.SUPPLUS+AMath.PION+AMath.SUPMINUS+"\n", ALogInterface.NORMAL); - AOutput.alwaysAppend(msgK, ALogInterface.NORMAL_BOLD); // Print kaon summary - AOutput.alwaysAppend("\n"+AMath.LAMBDACAP+AMath.RARROW+"p"+AMath.PION+AMath.SUPMINUS+"\n", ALogInterface.NORMAL); - AOutput.alwaysAppend(msgL, ALogInterface.NORMAL_BOLD); // Print lambda summary - AOutput.alwaysAppend("\n"+AMath.LAMBDACAP+AMath.OVERLINE+AMath.RARROW+"p"+AMath.OVERLINE+AMath.PION+AMath.SUPPLUS+"\n", ALogInterface.NORMAL); - AOutput.alwaysAppend(msgAL, ALogInterface.NORMAL_BOLD); // Print antilambda summary - AOutput.alwaysAppend("\n"+AMath.GAMMA+AMath.RARROW+"e"+AMath.SUPPLUS+"e"+AMath.SUPMINUS+"\n", ALogInterface.NORMAL); - AOutput.alwaysAppend(msgG, ALogInterface.NORMAL_BOLD); // Print gamma summary - AOutput.alwaysAppend("\n", ALogInterface.NORMAL); - } - } - summK = null; - summL = null; - summAL = null; - summG = null; - - } // massCalcV0() ------------------------------------------------------------- - - /** - * Takes two vectors from a list (added with the pick interaction and P key modifier) - * and prints the delta R and delta Phi of the vectors - * @param list - */ - public void deltaR(AList list) - { - // default destination - DefaultMutableTreeNode destination = mass; - TreePath tp = getSelectionPath(); - - if(destination != null && destination.getAllowsChildren()) - { - // check if it's already in the list and if so, don't add - boolean already = this.isAlreadyInTheList(list, destination); - - if(already) - { - logger.info(list + " is already in this list, not added"); - } - else - { - if(getChildren(mass).length >= 2){ - logger.info(list + " is full, maximum of 2 objects for delta phi calculation " + - "\n Clearing list"); - //AOutput.alwaysAppend("\n\n List full \n Clearing List \n",ALogPane.PICK); - mass.removeAllChildren(); - } - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), - destination, destination.getChildCount()); - expandPath(new TreePath(dtm.getPathToRoot(destination))); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - - if (tp != null) - { - setSelectionPath(tp); - } - - AList[] children = getChildren(mass); - - int chiLength = children.length; - if(chiLength == 2){ - A4Vector v1 = children[0].getSource().get4Vector(children[0].getItems().length, - children[0].getItems(),0.0); - A4Vector v2 = children[1].getSource().get4Vector(children[1].getItems().length, - children[1].getItems(),0.0); - - if(v1 != null && v2 != null) - { - double deltaPhi = Math.abs(v1.getPhi() - v2.getPhi()) > Math.PI ? (2*Math.PI) - Math.abs(v1.getPhi() - v2.getPhi()) : Math.abs(v1.getPhi() - v2.getPhi()); - double deltaEta = Math.abs(v1.getEta() - v2.getEta()); - double deltaR = Math.sqrt(deltaPhi*deltaPhi + deltaEta*deltaEta); - - String info = "\n\n"+AMath.DELTA+AMath.PHI+" = "+String.format("%.1f",Math.toDegrees(deltaPhi))+AMath.DEGREES+" ("+String.format("%.3f",deltaPhi)+")" - + "\n"+AMath.DELTA+"R = "+String.format("%.3f",deltaR)+"\n"; - AOutput.alwaysAppend(info, ALogInterface.NORMAL_BOLD); - } - - } - } - - public void highlight(AList list) - { - highlight.removeAllChildren(); - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), highlight, 0); - dtm.reload(highlight); - expandPath(new TreePath(dtm.getPathToRoot(highlight))); - ACanvas.getCanvas().repaintAllFromScratch(); - - } // highlight() -------------------------------------------------------- - - - - public void addLastDrawn(AList list) - { - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), lastDrawn, 0); - dtm.reload(lastDrawn); - - } // addLastDrawn() ----------------------------------------------------- - - - - public void addInvisible(AList list) - { - if(!dialog.isVisible()) - { - dialog.setVisible(true); - } - - // check if it's already in the list and if so, don't add - boolean already = this.isAlreadyInTheList(list, invisible); - if(already) - { - logger.info(list + " is already in the Invisible list, not added"); - } - else - { - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), - invisible, invisible.getChildCount()); - expandPath(new TreePath(dtm.getPathToRoot(invisible))); - ACanvas.getCanvas().repaintAllFromScratch(); - } - - } // addInvisible() ----------------------------------------------------- - - - /** - * When adding items to the list using rubberband they are grouped by type - * and appear as "InDetTrack (5 items)". This method allows the user to expand - * these items so they can manipulate individual items. - * @param s Collection - * @return Action - */ - private Action expand(final Collection s) - { - // This is called when the user right-clicks, we first determine if this - // item can be expanded or not. - if (s.contains(root) || s.size() != 1) - { - return null; - } - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) s.iterator().next(); - if (node.getUserObject() instanceof AList) - { - AList a = (AList) node.getUserObject(); - if (a.getItems().length < 1) - { - return null; - } - } - else - { - return null; - } - - // It can be expanded, so we add a menu item to the popup with the callback - // function as specified below. - return new AbstractAction("Expand items") - { - public void actionPerformed(ActionEvent e) - { - // We checked these casts before adding the callback - DefaultMutableTreeNode node = (DefaultMutableTreeNode) s.iterator().next(); - AList a = (AList) node.getUserObject(); - DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent(); - int index = parent.getIndex(node); - - // Now go through the list and add the items one by one to the parent. - for (int i=0; i<a.getItems().length; i++) - { - AList list = new AList(a.getSource(), a.getItems()[i]); - dtm.insertNodeInto(new DefaultMutableTreeNode(list, false), parent, index); - } - - // And remove the old list. - dtm.removeNodeFromParent(node); - } - }; - - } // expand() ----------------------------------------------------------- - - - private Action remove(final Collection s) - { - if(s.contains(root)) - { - return null; - } - - return new AbstractAction("Remove") - { - public void actionPerformed(ActionEvent e) - { - for (Iterator i = s.iterator(); i.hasNext();) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) i.next(); - if (node.getUserObject() instanceof AList) - { - AList a = (AList) node.getUserObject(); - a.getSource().remove(a.getItems()); - } - dtm.removeNodeFromParent(node); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - }; - - } // remove() ----------------------------------------------------------- - - - - /** - * This method is called after right-click -> summarize on the list-item in - * the list dialog - * @param s Collection - * @return Action - */ - private Action newSummarize(final Collection s) - { - if(s.contains(root) || s.size() != 1) - { - return null; - } - - return new AbstractAction("Summarize") - { - public void actionPerformed(ActionEvent e) - { - Summarizer summ = new Summarizer(); - AOutput.alwaysAppend(summ.getHeader(), ALogInterface.NORMAL); - - for(Iterator j = s.iterator(); j.hasNext();) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) j.next(); - AList[] children = getChildren(node); - - for(int i = 0; i < children.length; i++) - { - int num = children[i].getItems().length; - AList child = children[i]; - AData source = child.getSource(); - A4Vector v = source.get4Vector(num, child.getItems()); - - if(v != null && num > 0) - { - String info = summ.addAndGetInfo(v, children[i].toString()); - AOutput.alwaysAppend(info, ALogInterface.NORMAL); - } - } - } - - String msg = summ.getTotalInfo(); - AOutput.alwaysAppend(msg, ALogInterface.NORMAL_BOLD); - - summ = null; - - } // actionPerformed() - }; - - } // newSummarize() ----------------------------------------------------- - - - - /** - * This summarize method is called from rubberbanding menu - Summarize - * (from ASelection class) - */ - public void summarize() - { - if(lastDrawn == null) - { - return; - } - - Summarizer summ = new Summarizer(); - - AList[] children = getChildren(lastDrawn); - - AOutput.alwaysAppend(summ.getHeader(), ALogInterface.NORMAL); - - for(int i = 0; i < children.length; i++) - { - int num = children[i].getItems().length; - A4Vector v = children[i].getSource().get4Vector(num, children[i].getItems()); - - if(v != null && num > 0) - { - String msg = summ.addAndGetInfo(v, children[i].toString()); - AOutput.alwaysAppend(msg, ALogInterface.NORMAL); - } - } - - String msg = summ.getTotalInfo(); - AOutput.alwaysAppend(msg, ALogInterface.NORMAL_BOLD); - - summ = null; - - } // summarize() -------------------------------------------------------- - - - - private Action reset(final Collection s) - { - if(s.size() == 1 && s.contains(root)) - { - return new AbstractAction("Reset") - { - public void actionPerformed(ActionEvent e) - { - reset(); - ACanvas.getCanvas().repaintAllFromScratch(); - } - }; - } - else - { - return null; - } - - } // reset() ------------------------------------------------------------ - - - - public void clearHighlight() - { - highlight.removeAllChildren(); - dtm.reload(highlight); - ACanvas.getCanvas().repaintAllFromScratch(); - - } // clearHighlight() --------------------------------------------------- - - - - public void clearHighlightAndMassCalculation() - { - highlight.removeAllChildren(); - dtm.reload(highlight); - mass.removeAllChildren(); - dtm.reload(mass); - ACanvas.getCanvas().repaintAllFromScratch(); - - } // clearHighlightAndMassCalculation() --------------------------------------------------- - - - - public void clearLastDrawn() - { - lastDrawn.removeAllChildren(); - dtm.reload(lastDrawn); - - } // clearLastDrawn() --------------------------------------------------- - - - - /** - * Check if list (list of IDs id) of datatimes (toMask datatype) is present - * in the current event and if so, the items are added into the Invisible - * list, thus masked and igrored. - * - * @param toMask AData - * @param id int[] - * @param index int[] - */ - private boolean checkAndAddIntoInvisible(int[] id, int[] indexCheck, String key) - { - boolean result = false; - - // check if the datatype (key) exists in the new event - AEvent e = eventManager.getCurrentEvent(); - AData toMask = e.get(key); - - if(toMask != null) - { - // iterate over all data items in this list - for(int i = 0; i < id.length; i++) - { - // check if this ID is present in the current event - int index = toMask.getIndexFromId(id[i]); - if(index != -1) - { - // AList expects datatype and its index - AList l = new AList(toMask, index); - addInvisible(l); - AOutput.alwaysAppend(" " + l.toString() + "\n", ALogInterface.NORMAL); - result = true; - - // 2007-08-29: debugging check, remove after some time if the - // problem is not observed (then indexCheck param is not needed) - if(index != indexCheck[i]) - { - logger.warn("AListManager: problem, indices not equal!"); - } - // </debug> - } - } - } - - return result; - - } // checkAndAddIntoInvisible() ----------------------------------------- - - - - /** - * restore Invisible list, cross-event invisible - * @param backup AList[] - */ - private void restoreInvisible(AList[] backup) - { - if(backup.length > 0) - { - AOutput.alwaysAppend("\nPrevious Invisible list not empty, masked items:\n", - ALogInterface.WARNING); - - boolean somethingInvisible = false; - - for(int i = 0; i < backup.length; i++) - { - AData d = backup[i].getSource(); - String sg = d.getStoreGateKey(); - String accessKey = d.getName() + (sg != null ? sg : ""); - - if(backup[i].getItems().length > 1) - { - somethingInvisible = checkAndAddIntoInvisible(backup[i].getItemsID(), - backup[i].getItems(), accessKey); - } - else - { - int id = backup[i].getItemsID()[0]; - int index = backup[i].getItems()[0]; - somethingInvisible = checkAndAddIntoInvisible(new int[] { id }, - new int[] { index }, accessKey); - } - - } // for (overall items in the Invisible list) - - if(!somethingInvisible) - { - AOutput.alwaysAppend(" none\n", ALogInterface.NORMAL); - } - - } // if(backup.length > 0) - - } // restoreInvisible() ------------------------------------------------- - - - - public void resetAndPreserveInvisible() - { - AList[] invisibleBackup = getChildren(invisible); - reset(); - restoreInvisible(invisibleBackup); - - } // resetAndPreserveInvisible() ---------------------------------------- - - - - public void reset() - { - root.removeAllChildren(); - highlight.removeAllChildren(); - lastDrawn.removeAllChildren(); - invisible.removeAllChildren(); - mass.removeAllChildren(); - - root.add(highlight); - root.add(lastDrawn); - root.add(others); - root.add(invisible); - root.add(mass); - - numLists = 0; - root.add(new DefaultMutableTreeNode("List " + numLists++)); - - nodeColors.clear(); - nodeColors.put(highlight, new Integer(AColorMap.WH)); - nodeColors.put(invisible, new Integer(AColorMap.INVISIBLE)); - nodeColors.put(mass, new Integer(AColorMap.WH)); - dtm.reload(); - - } // reset() ------------------------------------------------------------ - - - - private Action rename(Collection s) - { - if(s.size() != 1) - { - return null; - } - - final DefaultMutableTreeNode selected = - (DefaultMutableTreeNode) (s.iterator().next()); - - if(!selected.getAllowsChildren() || selected == root || - selected == others || selected == highlight || - selected == lastDrawn || selected == invisible || - selected == mass) - { - return null; - } - - return new AbstractAction("Rename") - { - public void actionPerformed(ActionEvent h) - { - String name = JOptionPane.showInputDialog(listManager, - "Enter new name"); - selected.setUserObject(name); - } - }; - - } // rename() ----------------------------------------------------------- - - - - private Action newParent(final Collection s) - { - if(s.contains(root)) - { - return null; - } - - Set parents = new HashSet(); - - for(Iterator i = s.iterator(); i.hasNext();) - { - parents.add(((TreeNode) (i.next())).getParent()); - } - - if(parents.size() != 1) - { - return null; - } - - final DefaultMutableTreeNode oldParent = - (DefaultMutableTreeNode) (parents.iterator().next()); - - return new AbstractAction("New Parent") - { - public void actionPerformed(ActionEvent e) - { - DefaultMutableTreeNode newParent = - new DefaultMutableTreeNode("List " + numLists++); - int index = 0; - for(Iterator i = s.iterator(); i.hasNext();) - { - index = Math.min(oldParent.getIndex((TreeNode) (i.next())), - index); - } - - for(Iterator i = s.iterator(); i.hasNext();) - { - dtm.removeNodeFromParent((MutableTreeNode) (i.next())); - } - - dtm.insertNodeInto(newParent, oldParent, index); - - for(Iterator i = s.iterator(); i.hasNext();) - { - dtm.insertNodeInto((MutableTreeNode) (i.next()), newParent, 0); - } - - expandPath(new TreePath(dtm.getPathToRoot(newParent))); - } - }; - - } // newParent() -------------------------------------------------------- - - - - private Action newChild(final Collection s) - { - if(s.size() != 1) - { - return null; - } - - final DefaultMutableTreeNode selected = - (DefaultMutableTreeNode) (s.iterator().next()); - - if(!selected.getAllowsChildren()) - { - return null; - } - - return new AbstractAction("New Child") - { - public void actionPerformed(ActionEvent h) - { - dtm.insertNodeInto(new DefaultMutableTreeNode("List " + numLists++), - selected, 0); - expandPath(new TreePath(dtm.getPathToRoot(selected))); - } - }; - - } // newChild() --------------------------------------------------------- - - - - private DefaultMutableTreeNode getNode(Point m) - { - TreePath p = getPathForLocation(m.x, m.y); - if(p != null) - { - TreeNode tn = (TreeNode) p.getLastPathComponent(); - if(tn instanceof DefaultMutableTreeNode) - { - return (DefaultMutableTreeNode) tn; - } - } - return null; - - } // getNode() ---------------------------------------------------------- - - - - private static class HashMapSet extends HashMap - { - public Object put(Object key, Object value) - { - // don't allow duplicates - if(containsKey(key)) - { - this.remove(key); - } - - if(value != null) - { - return super.put(key, value); - } - - else - { - return null; - } - } - } - - - - class ColorRenderer extends DefaultTreeCellRenderer - { - AColorIcon folderIcon; - AColorIcon leafIcon; - - public ColorRenderer() - { - folderIcon = new AColorIcon(AColorMap.WH, 15, 11); - leafIcon = new AColorIcon(AColorMap.WH, 11, 11); - } - - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) - { - - super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); - - int c = getColor((TreeNode) value); - if (c == AColorMap.NO_COLOR) - setToolTipText("No Color"); - else if (c == AColorMap.INVISIBLE) - setToolTipText("Invisible"); - else - setToolTipText(""); - - if (leaf) - { - leafIcon.setColorIndex(c); - setIcon(leafIcon); - } - else - { - folderIcon.setColorIndex(c); - setIcon(folderIcon); - } - - return this; - } - - } - - private int getColor(TreeNode node) - { - TreeNode[] parents = dtm.getPathToRoot(node); - int color = AColorMap.NO_COLOR; - for (int i = 0; i < parents.length; ++i) - { - Object o = nodeColors.get(parents[i]); - if (o != null) - color = ((Integer) o).intValue(); - } - return color; - } - - private DefaultMutableTreeNode[] getLeafs() - { - java.util.List list = new ArrayList(); - for (int i = 0; i < root.getChildCount(); ++i) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i); - if (node != lastDrawn) - { - if (node.getAllowsChildren()) - { - Enumeration descendents = node.breadthFirstEnumeration(); - while (descendents.hasMoreElements()) - { - DefaultMutableTreeNode descendent = (DefaultMutableTreeNode) (descendents.nextElement()); - if (!descendent.getAllowsChildren()) - list.add(descendent); - } - } - else - { - list.add(node); - } - } - } - return (DefaultMutableTreeNode[]) list.toArray(new DefaultMutableTreeNode[list.size()]); - } - - public int[][] getColorMapping(AData data) - { - DefaultMutableTreeNode[] leafs = getLeafs(); - int num = 0; - for (int i = 0; i < leafs.length; ++i) - if (((AList) (leafs[i].getUserObject())).getSource() == data) - num += ((AList) (leafs[i].getUserObject())).getItems().length; - - int[] index = new int[num]; - int[] color = new int[num]; - num = 0; - for (int i = 0; i < leafs.length; ++i) - { - if (((AList) (leafs[i].getUserObject())).getSource() == data) - { - int[] items = ((AList) (leafs[i].getUserObject())).getItems(); - int c = getColor(leafs[i]); - for (int j = 0; j < items.length; ++j) - { - index[num] = items[j]; - color[num] = c; - num++; - } - } - } - int[][] temp = new int[2][]; - temp[0] = index; - temp[1] = color; - return temp; - } - - public int getColorOfOthers() - { - return getColor(others); - } - - public boolean[] getSelection(AData data) - { - boolean[] selected = new boolean[data.getNumData()]; - - TreePath[] paths = getSelectionPaths(); - if (paths != null) - { - for (int i = 0; i < paths.length; ++i) - { - Enumeration nodes = ((DefaultMutableTreeNode) (paths[i].getLastPathComponent())).breadthFirstEnumeration(); - while (nodes.hasMoreElements()) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) (nodes.nextElement()); - if (!node.getAllowsChildren()) - { - AList a = (AList) (node.getUserObject()); - if (a.getSource() == data) - { - int[] items = a.getItems(); - for (int j = 0; j < items.length; ++j) - selected[items[j]] = true; - } - } - } - } - } - return selected; - } - - public AList[] getChildren(DefaultMutableTreeNode node) - { - java.util.List children = new ArrayList(); - - Object o = node.getUserObject(); - if (o instanceof AList) - { - children.add(o); - } - else - { - // process the child nodes recursively - for (int i = 0; i < node.getChildCount(); ++i) - { - AList[] grandChildren = getChildren((DefaultMutableTreeNode) node.getChildAt(i)); - for (int j = 0; j < grandChildren.length; ++j) - { - children.add(grandChildren[j]); - } - } - } - return (AList[]) (children.toArray(new AList[children.size()])); - } - - public static Collection uniqueExpansion(Collection s) - { - Collection c = new HashSet(); - for (Iterator i = s.iterator(); i.hasNext();) - { - Enumeration en = ((DefaultMutableTreeNode) (i.next())).depthFirstEnumeration(); - while (en.hasMoreElements()) - { - c.add(en.nextElement()); - } - } - return c; - } - - class ColorPanel extends JPanel - { - ColorPanel() - { - Color[] colorMap = AColorMap.getColors(); - ActionListener a = new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - int colorIndex = ((AColorIcon) (((JButton) (e.getSource())).getIcon())).getColorIndex(); - TreePath[] sel = getSelectionPaths(); - if (sel != null) - { - for (int i = 0; i < sel.length; ++i) - nodeColors.put(sel[i].getLastPathComponent(), new Integer(colorIndex)); - } - listManager.repaint(); - ACanvas.getCanvas().repaintAllFromScratch(); - } - }; - Box b = Box.createVerticalBox(); - for (int i = 0; i < colorMap.length; i++) - { - JButton l = new JButton(new AColorIcon(i, 13, 13)); - l.setMargin(new Insets(0, 0, 0, 0)); - l.setBorder(null); - b.add(l); - b.add(Box.createVerticalStrut(3)); - l.addActionListener(a); - } - b.add(Box.createVerticalStrut(6)); - JButton l = new JButton(new AColorIcon(AColorMap.NO_COLOR, 13, 13)); - l.setMargin(new Insets(0, 0, 0, 0)); - l.setBorder(null); - l.setToolTipText("No specified color"); - b.add(l); - b.add(Box.createVerticalStrut(3)); - l.addActionListener(a); - l = new JButton(new AColorIcon(AColorMap.INVISIBLE, 13, 13)); - l.setMargin(new Insets(0, 0, 0, 0)); - l.setBorder(null); - l.setToolTipText("Invisible"); - b.add(l); - l.addActionListener(a); - super.add(b); - } - } - - - - public ArrayList getLastDrawn() - { - ArrayList result = new ArrayList(); - - Enumeration myenum = lastDrawn.children(); - while(myenum.hasMoreElements()) - { - Object o = ((DefaultMutableTreeNode) (myenum.nextElement())).getUserObject(); - if(o instanceof AList) - { - if(((AList) o).getItems().length > 0) - { - result.add(o); - } - } - } - - return result; - } - - - - public void copyLastDrawn() - { - - DefaultMutableTreeNode copy = new DefaultMutableTreeNode("List " + numLists++); - Enumeration myenum = lastDrawn.children(); - while (myenum.hasMoreElements()) - { - Object o = ((DefaultMutableTreeNode) (myenum.nextElement())).getUserObject(); - if (o instanceof AList) - { - if (((AList) o).getItems().length > 0) - copy.add(new DefaultMutableTreeNode(o, false)); - } - } - dtm.insertNodeInto(copy, root, 0); - setSelectionPath(new TreePath(dtm.getPathToRoot(copy))); - // expandPath(getPathForLocation(e.getX(), e.getY())); - } - - public void mouseExited(MouseEvent e) - { - update(e); - } // DnD - - public void mouseClicked(MouseEvent e) - {} - - public void mouseEntered(MouseEvent e) - { - update(e); - } // DnD - - - public void mousePressed(MouseEvent e) - { - // source of DnD - source = getNode(e.getPoint()); - // set picked object to selection if possible - TreePath tp = getPathForLocation(e.getPoint().x, e.getPoint().y); - if (tp != null) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) (tp.getLastPathComponent()); - if (!node.getAllowsChildren()) - { - AList a = (AList) (node.getUserObject()); - if (a.getItems().length == 1) - APickingGraphics2D.setPicked(a.getSource(), a.getItems()[0]); - } - } - // special for right button - if (!AUtilities.isRightMouseButton(e)) - return; - // make right button act on selection just as left button does - if (tp != null) - { - if (e.isControlDown()) - { - addSelectionPath(tp); - } - else - { - setSelectionPath(tp); - } - } - // pop up menu on right click - TreePath[] sel = getSelectionPaths(); - Collection selection = new ArrayList(sel.length); - for (int i = 0; i < sel.length; ++i) - selection.add(sel[i].getLastPathComponent()); - - JPopupMenu popup = new JPopupMenu(); - Action temp; - temp = expand(selection); - if (temp != null) - popup.add(temp); - temp = remove(selection); - if (temp != null) - popup.add(temp); - temp = reset(selection); - if (temp != null) - popup.add(temp); - temp = rename(selection); - if (temp != null) - popup.add(temp); - temp = newParent(selection); - if (temp != null) - popup.add(temp); - temp = newChild(selection); - if (temp != null) - popup.add(temp); - temp = newSummarize(selection); - if (temp != null) - popup.add(temp); - // gary just remove this for now - - AListProcessor[] listProcessors = eventManager.getCurrentEvent().getData(); - - for (int i = 0; i < listProcessors.length; i++) - { - Action[] actions = listProcessors[i].getActions(selection); - for (int j = 0; j < actions.length; ++j) - { - popup.add(actions[j]); - } - } - - popup.show(e.getComponent(), e.getX(), e.getY()); - - } - - public void mouseMoved(MouseEvent e) - {} - - public void mouseDragged(MouseEvent e) - { - // start of drag - if (!draging) - { - if (source != null && isDragSource(source)) - draging = true; - } - update(e); - } - - public void mouseReleased(MouseEvent e) - { - // DnD event - if (draging && source != null) - { - DefaultMutableTreeNode destination = getNode(e.getPoint()); - if (destination != null && source != destination && destination.getAllowsChildren() && isValidDrag(source, destination)) - { - if (!e.isControlDown() && source != lastDrawn) - { - dtm.removeNodeFromParent(source); - } - if (source == lastDrawn) - { - DefaultMutableTreeNode copy = new DefaultMutableTreeNode("List " + numLists++); - Enumeration myenum = source.children(); - while (myenum.hasMoreElements()) - { - Object o = ((DefaultMutableTreeNode) (myenum.nextElement())).getUserObject(); - copy.add(new DefaultMutableTreeNode(o, false)); - } - dtm.insertNodeInto(copy, destination, 0); - } - else - dtm.insertNodeInto(source, destination, 0); - expandPath(getPathForLocation(e.getX(), e.getY())); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - draging = false; - source = null; - setCursor(ACursorFactory.getInstance().getDefaultCursor()); - } - - private boolean isDragSource(DefaultMutableTreeNode source) - { - if (source == null || source == root || source == highlight || source == others || source==mass) - return false; - else - return true; - } - - private boolean isValidDrag(DefaultMutableTreeNode source, DefaultMutableTreeNode destination) - { - if (source == null || destination == null) - return false; - if (source == root || source == highlight || source == others || source == mass) - return false; - if (destination == others) - return false; - if (destination == lastDrawn) - return false; - if (destination == highlight) - { - if (source.getAllowsChildren()) - return false; - if (((AList) (source.getUserObject())).getItems().length != 1) - return false; - if (highlight.getChildCount() != 0) - return false; - } - return true; - } - - private void update(MouseEvent e) - { - if (!draging) - return; - Point point = e.getPoint(); - DefaultMutableTreeNode current = getNode(point); - if (current != null && current.getAllowsChildren() && isValidDrag(source, current)) - { - TreePath p = getPathForLocation(point.x, point.y); - setSelectionPath(p); - if (e.isControlDown()) - { - setCursor(DROP_VALID_COPY); - } - else - { - setCursor(ACursorFactory.getInstance().getDragValidCursor()); - } - } - else - { - setCursor(ACursorFactory.getInstance().getDragInvalidCursor()); - } - } - -} - - -class Summarizer -{ - private A4Vector vector = null; - private double etSum = 0; - - - public Summarizer() - { - vector = new A4Vector(); - - } - - - public String getHeader() - { - StringBuffer sb = new StringBuffer(); - sb.append("\nSummary output:\n"); - sb.append(" "); // 18 spaces - sb.append(" PT "); - sb.append(" ET "); - sb.append(" E "); - sb.append(" M "); - sb.append(" MT "); - sb.append("\n"); - - return sb.toString(); - - } - - - public String addAndGetInfo(A4Vector item, String description) - { - vector.add(item); - etSum += item.getEt(); - StringBuffer sb = new StringBuffer(); - sb.append(description); - sb.append("\n"); - sb.append(" "); // 18 spaces - sb.append(String.format("%7.1f",item.getPt())); - sb.append(String.format("%8.1f",item.getEt())); - sb.append(String.format("%7.1f",item.getE())); - sb.append(String.format("%8.3f",item.getMass())); - sb.append(String.format("%8.1f",item.getMt())); - sb.append("\n"); - - return sb.toString(); - } - - public double getTotalEt() - { - return etSum; - } - - public double getTotalPt() - { - return vector.getPt(); - } - - public double getTotalMt() - { - double et = getTotalEt(); - double pt = getTotalPt(); - return Math.sqrt(et*et - pt*pt); - } - - public String getTotalInfo() - { - StringBuffer sb = new StringBuffer(); - sb.append(String.format("%-18s", "Total")); - sb.append(String.format("%7.1f",getTotalPt())); - sb.append(String.format("%8.1f",getTotalEt())); - sb.append(String.format("%7.1f",vector.getE())); - sb.append(String.format("%8.3f",vector.getMass())); - sb.append(String.format("%8.1f",getTotalMt())); - sb.append("\n"); - - return sb.toString(); - - } - -} - diff --git a/graphics/AtlantisJava/src/atlantis/list/AListProcessor.java b/graphics/AtlantisJava/src/atlantis/list/AListProcessor.java deleted file mode 100755 index 6c58995a4a5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/list/AListProcessor.java +++ /dev/null @@ -1,10 +0,0 @@ -package atlantis.list; - - -import javax.swing.Action; -import java.util.Collection; - - -public interface AListProcessor { - Action[] getActions(Collection nodes); -} diff --git a/graphics/AtlantisJava/src/atlantis/list/package.html b/graphics/AtlantisJava/src/atlantis/list/package.html deleted file mode 100644 index ca84b937bc7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/list/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<html> -<head></head> -<body> -<p>Implementation of lists which are used to store event datatypes.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimInterpolate.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimInterpolate.java deleted file mode 100644 index 90e0284bc68..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimInterpolate.java +++ /dev/null @@ -1,47 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public class ANAnimInterpolate extends ANAnimSegment { - - private ANAnimVar m_var; - private double m_t1; - private double m_t2; - private double m_v1; - private double m_v2; - private int m_interp; - - public ANAnimInterpolate(ANAnimVar var, double t1, double t2, - double v1, double v2, int interp) { - m_var = var; - m_t1 = t1; - m_t2 = t2; - m_v1 = v1; - m_v2 = v2; - m_interp = interp; - } - - public void evaluate(double now) { - if (now < m_t1) { return; } - switch(m_interp) { - case (ANAnimationManager.INTERP_LINEAR): - //System.out.println("now: " + now + " m_t1: " + m_t1 + " m_t2: " + m_t2); - double t = (now - m_t1) / (m_t2 - m_t1); - //System.out.println("t: " + t); - m_var.setValue((t * (m_v2 - m_v1)) + m_v1); - break; - } - } - - @Override - public double getStart() { - return m_t1; - } - - @Override - public double getEnd() { - return m_t2; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimSegment.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimSegment.java deleted file mode 100644 index 6678cade19f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimSegment.java +++ /dev/null @@ -1,13 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public abstract class ANAnimSegment { - - public abstract double getStart(); - public abstract double getEnd(); - - public abstract void evaluate(double now); -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimSetProjection.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimSetProjection.java deleted file mode 100644 index 6ca352555ac..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimSetProjection.java +++ /dev/null @@ -1,38 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public class ANAnimSetProjection extends ANAnimSegment { - private ANFrameManager m_fm; - private ANProjection m_p; - private double m_when; - - public ANAnimSetProjection(ANFrameManager fm, ANProjection p, double when) { - m_fm = fm; - m_p = p; - m_when = when; - } - - @Override - public void evaluate(double now) { - //System.out.println("Evaluate in SetProjection: " + now); - if (now > m_when) { - //System.out.println("CHANGE!"); - m_fm.setCurrentProjection(m_p); - } - } - - @Override - public double getStart() { - return m_when; - } - - @Override - public double getEnd() { - return m_when; - } - - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimThread.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimThread.java deleted file mode 100644 index 97185bb17cd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimThread.java +++ /dev/null @@ -1,67 +0,0 @@ -package atlantis.nge; - -import atlantis.canvas.AWindow; -import atlantis.utils.ALogger; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Adam Davison - */ -public class ANAnimThread implements Runnable { - - private static ALogger logger = ALogger.getLogger(ANAnimThread.class); - private ANAnimationManager m_am; - private Object m_wait = new Object(); - private AWindow m_w; - - public ANAnimThread(ANAnimationManager am, AWindow w) { - m_am = am; - m_w = w; - } - - public void reschedule() { - //System.out.println("Rescheduling"); - synchronized (m_wait) { - m_wait.notifyAll(); - } - //System.out.println("Rescheduled"); - } - - public void run() { - while (true) { - double wait = m_am.timeToWait(); - - //System.out.println("Told to wait: " + wait); - - double mintime = 1.0 / 100.0; - - if (wait == -1.0) { - // wait forever - synchronized (m_wait) { - try { - m_wait.wait(); - } catch (InterruptedException ex) { - logger.error("Interrupted in sleep", ex); - } - } - } else if (wait > mintime) { - // wait until we're supposed to do something - synchronized (m_wait) { - try { - m_wait.wait((long) (wait * 1000)); - } catch (InterruptedException ex) { - logger.error("Interrupted in sleep", ex); - } - } - } else { - // do something now - //System.out.println("Forcing Repaint!"); - m_w.invalidateQuietly(); - //m_w.getView().paintImmediately(0, 0, m_w.getWidth(), m_w.getHeight()); - m_w.repaint(); - } - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimVar.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimVar.java deleted file mode 100644 index 2dd5c9c9b38..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimVar.java +++ /dev/null @@ -1,27 +0,0 @@ -package atlantis.nge; - -/** - * A variable which is animatable, pretty much a wrapper around a double... - * - * @author Adam Davison - */ -public class ANAnimVar { - - private double m_val; - - public ANAnimVar(double val) { - m_val = val; - } - - public ANAnimVar() { - m_val = 0.0; - } - - public double getValue() { - return m_val; - } - - public void setValue(double val) { - m_val = val; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANAnimationManager.java b/graphics/AtlantisJava/src/atlantis/nge/ANAnimationManager.java deleted file mode 100644 index a4d7e3fe0c8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANAnimationManager.java +++ /dev/null @@ -1,92 +0,0 @@ -package atlantis.nge; - -import atlantis.canvas.AWindow; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * - * @author Adam Davison - */ -public class ANAnimationManager { - - public static final int INTERP_LINEAR = 1; - private ArrayList<ANAnimSegment> m_segs; - private double m_now; - - private ANAnimThread m_at; - - public ANAnimationManager(AWindow w) { - m_segs = new ArrayList<ANAnimSegment>(); - updateNow(); - m_at = new ANAnimThread(this, w); - new Thread(m_at).start(); - } - - public void updateNow() { - m_now = ((double) System.currentTimeMillis()) / 1000.0; - } - - public void scheduleAnimationAbsolute(ANAnimVar v, double t1, double t2, double v1, double v2) { - m_segs.add(new ANAnimInterpolate(v, t1, t2, v1, v2, INTERP_LINEAR)); - m_at.reschedule(); - } - - public void scheduleAnimation(ANAnimVar v, double t1, double t2, double v1, double v2) { - updateNow(); - scheduleAnimationAbsolute(v, t1 + m_now, t2 + m_now, v1, v2); - } - - public void scheduleProjectionChange(ANFrameManager fm, ANProjection p, double t) { - updateNow(); - m_segs.add(new ANAnimSetProjection(fm, p, t + m_now)); - m_at.reschedule(); - } - - public void animate() { - updateNow(); - - //System.out.println("Animating at: " + m_now); - - Iterator<ANAnimSegment> it = m_segs.listIterator(); - while (it.hasNext()) { - ANAnimSegment seg = it.next(); - //System.out.println("Seg: " + seg + " start: " + seg.getStart() + " end: " + seg.getEnd()); - if (seg.getStart() < m_now) { - seg.evaluate(m_now); - } - if (seg.getEnd() < m_now) { - it.remove(); - } - } - } - - public double timeToWait() { - double next = -1.0; - updateNow(); - - //System.out.println("Wait testing at: " + m_now); - - Iterator<ANAnimSegment> it = m_segs.listIterator(); - while (it.hasNext()) { - ANAnimSegment seg = it.next(); - //System.out.println("Seg: " + seg + " start: " + seg.getStart() + " end: " + seg.getEnd()); - if (seg.getStart() <= next && seg.getEnd() >= next) { - //System.out.println("In segment, returning 0.0"); - return 0.0; - } else if (seg.getStart() >= next) { - double wait = seg.getStart() - m_now; - if (wait < next || next == -1.0) { - if (wait < 0.0) { - wait = 0.0; - } - next = wait; - } - } - } - - return next; - } -} - - diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANCacheToken.java b/graphics/AtlantisJava/src/atlantis/nge/ANCacheToken.java deleted file mode 100644 index 3ec2fe065ac..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANCacheToken.java +++ /dev/null @@ -1,11 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public class ANCacheToken<T> { - - - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANColor.java b/graphics/AtlantisJava/src/atlantis/nge/ANColor.java deleted file mode 100644 index 87c01543c86..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANColor.java +++ /dev/null @@ -1,87 +0,0 @@ -package atlantis.nge; - -import atlantis.graphics.colormap.AColorMap; - -import java.awt.Color; - -/** - * A floating point colour class that enforces very little - * - * @author Adam Davison, Mark Stockton - */ -public class ANColor { - - public float r; - public float g; - public float b; - public float a; - - public ANColor(Color c) { - r = ((float) c.getRed()) / 255.0f; - g = ((float) c.getGreen()) / 255.0f; - b = ((float) c.getBlue()) / 255.0f; - a = ((float) c.getAlpha()) / 255.0f; - } - - public ANColor(float _r, float _g, float _b, float _a) { - r = _r; - g = _g; - b = _b; - a = _a; - } - - public ANColor(float _r, float _g, float _b) { - r = _r; - g = _g; - b = _b; - a = 1.0f; - } - - public static ANColor getBGColor() { - return getMapColor(AColorMap.BG); - } - - public static ANColor getMapColor(int index) { - Color bg = AColorMap.getColors()[index]; - - float r = ((float) bg.getRed()) / 255.0f; - float g = ((float) bg.getGreen()) / 255.0f; - float b = ((float) bg.getBlue()) / 255.0f; - - return new ANColor(r, g, b); - } - - public static ANColor getMapColor(int index, float trans) { - Color bg = AColorMap.getColors()[index]; - - float r = ((float) bg.getRed()) / 255.0f; - float g = ((float) bg.getGreen()) / 255.0f; - float b = ((float) bg.getBlue()) / 255.0f; - - return new ANColor(r, g, b, trans); - } - - public void mult(float c) { - r *= c; - g *= c; - b *= c; - if (r < 0.0f) { r = 0.0f; } - if (r > 1.0f) { r = 1.0f; } - if (g < 0.0f) { g = 0.0f; } - if (g > 1.0f) { g = 1.0f; } - if (b < 0.0f) { b = 0.0f; } - if (b > 1.0f) { b = 1.0f; } - } - - public void lighten(float c) { - r = 1.0f - ((1.0f - r)*c); - g = 1.0f - ((1.0f - g)*c); - b = 1.0f - ((1.0f - b)*c); - if (r < 0.0f) { r = 0.0f; } - if (r > 1.0f) { r = 1.0f; } - if (g < 0.0f) { g = 0.0f; } - if (g > 1.0f) { g = 1.0f; } - if (b < 0.0f) { b = 0.0f; } - if (b > 1.0f) { b = 1.0f; } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANFrameManager.java b/graphics/AtlantisJava/src/atlantis/nge/ANFrameManager.java deleted file mode 100644 index adb6cb778c0..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANFrameManager.java +++ /dev/null @@ -1,190 +0,0 @@ -package atlantis.nge; - -import atlantis.canvas.AWindow; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import javax.media.opengl.DebugGL; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.glu.GLU; - -/** - * Decides which projection should be onscreen and in what state. - * Handles animation, performance and probably all sorts of other things. - * - * @author Adam Davison, Mark Stockton - */ -public class ANFrameManager { - - // Targ is what we're aiming to display but proj is what we're really - // displaying, could be the same but could also be some transition into - // targ - - private ANProjection m_targ; - private ANProjection m_proj; - - private ANAnimationManager m_am; - - public ANFrameManager(AWindow w) { - // Default, if not told anything else construct 3d projection - m_proj = null; - m_am = new ANAnimationManager(w); - - } - - public ANPickResult pick(GLAutoDrawable drawable, int w, int h, int x, int y) { - - if (m_proj == null) { return null; } - - long before = System.nanoTime(); - - GL gl = drawable.getGL(); - gl.glViewport(0, 0, w, h); - - GLU glu = new GLU(); - int maxsize = 100000; - - ByteBuffer bb = ByteBuffer.allocateDirect(4*maxsize); - bb.order(ByteOrder.nativeOrder()); - // FIXME: Reuse this object for performance - IntBuffer ib = bb.asIntBuffer(); - gl.glSelectBuffer(maxsize, ib); - gl.glRenderMode(GL.GL_SELECT); - gl.glMatrixMode(GL.GL_PROJECTION); - int[] viewport = new int[4]; - gl.glLoadIdentity(); - gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0); - y = h - y; - glu.gluPickMatrix(x - 1, y - 1, 3, 3, viewport, 0); - - ANRenderHints rh = new ANRenderHints(); - rh.setPick(true); - rh.setPickHelper(new ANPickHelper(gl)); - - //gl.glPushName(0); - m_proj.display(drawable, w, h, rh); - //gl.glPopName(); - - int hits = gl.glRenderMode(GL.GL_RENDER); - - System.out.println("HITS: " + hits); - ANSelectionList sl = new ANSelectionList(ib); - //System.out.println("FRONT: " + sl.getFrontID()); - int[] front = sl.getFrontID(); - - ANPickResult ret = null; - - if (front != null) { - int id = front[0]; - System.out.println(id); - int data = front[1]; - System.out.println(data); - ANPickHandler ph = rh.getPickHelper().getPickHandler(id); - System.out.println(ph); - if (ph != null) { - ret = ph.getHitInfo(data); - } - } - - long after = System.nanoTime(); - System.out.println("Pick took: " + (after - before) / 1000); - - System.out.println(ret); - return ret; - } - - public void display(GLAutoDrawable drawable, int w, int h) { - System.out.println("Asked to display!"); - - if (m_proj == null) { return; } - - long before = System.nanoTime(); - - GL gl = new DebugGL(drawable.getGL()); - gl.glViewport(0, 0, w, h); - - m_am.animate(); - - m_proj.display(drawable, w, h, new ANRenderHints()); - - long after = System.nanoTime(); - System.out.println("Frame took: " + (after - before) / 1000); - } - - public double timeToWait() { - return m_am.timeToWait(); - } - - public ANProjection getTargetProjection() { - return m_targ; - } - - public ANProjection getCurrentProjection() { - return m_proj; - } - - public void setCurrentProjection(ANProjection proj) { - m_proj = proj; - } - - public void scheduleTransition(ANProjection p) { - //(new Exception()).printStackTrace(); - - m_targ = p; - - if (m_proj == null || m_proj == p) { m_proj = p; return; } - - //System.out.println(m_proj); - //System.out.println(p); - - if (m_proj instanceof ANLinearProjection && - p instanceof ANLinearProjection) { - - //System.out.println("HERE!"); - - ANLinearTransition trans = new ANLinearTransition( - (ANLinearProjection) m_proj, - (ANLinearProjection) p); - - setCurrentProjection(trans); - - double length = 1.0; - - m_am.scheduleAnimation(trans.getTransformTimeVar(), 0.0, length, 0.0, 1.0); - m_am.scheduleAnimation(trans.getFadeTimeVar(), 0.0, length, 0.0, 1.0); - m_am.scheduleProjectionChange(this, p, length); - - } else { - m_proj = p; - } - } - - public void checkProjectionYX() { - //System.out.println("checkProjectionYX: m_proj: " + m_proj); - if (!(m_targ instanceof ANProjectionYX)) { - //System.out.println("RECREATING"); - scheduleTransition(new ANProjectionYX()); - } - } - - public void checkProjection3D() { - if (!(m_targ instanceof ANProjection3D)) { - scheduleTransition(new ANProjection3D()); - } - } - - public ANProjectionPhysics checkProjectionPhysics() { - if (!(m_targ instanceof ANProjectionPhysics)) { - ANProjectionPhysics pp = new ANProjectionPhysics(); - scheduleTransition(pp); - return pp; - } else { - return (ANProjectionPhysics)(m_targ); - } - } - - public ANAnimationManager getAnimationManager() { - return m_am; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANGlobalFlags.java b/graphics/AtlantisJava/src/atlantis/nge/ANGlobalFlags.java deleted file mode 100644 index 5a96788eafa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANGlobalFlags.java +++ /dev/null @@ -1,17 +0,0 @@ -package atlantis.nge; - -/** - * This class contains some static final boolean flags that can be used to - * control behaviour such as debugging and sanity checking. - * - * The java compiler guarantees that code enclosed in an if(var) where var - * is a final and false boolean is entirely excluded from your class file - * - * This is better than just using logger.debug() here because we don't want - * to do the debug level testing inside the fast rendering path - * - * @author Adam Davison - */ -public class ANGlobalFlags { - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANLinearProjection.java b/graphics/AtlantisJava/src/atlantis/nge/ANLinearProjection.java deleted file mode 100644 index c3cda8cb627..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANLinearProjection.java +++ /dev/null @@ -1,229 +0,0 @@ -package atlantis.nge; - -import atlantis.nge.object.data.ANObjectDataJet; -import atlantis.nge.object.geometry.ANObjectGeomMuon; -import atlantis.nge.object.geometry.ANObjectGeomCalo; -import atlantis.nge.object.data.ANObjectDataCell; -import atlantis.data.ACalorimeterData; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.data.AJetData; -import atlantis.data.ALArData; -import atlantis.geometry.AAtlasDetector; -import atlantis.geometry.ABarrelCalorimeterDetector; -import atlantis.geometry.ABoxDetector; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.geometry.ADetector; -import atlantis.geometry.ADetectors; -import atlantis.geometry.AEndcapCalorimeterDetector; -import atlantis.geometry.AEndcapCryostatDetector; -import atlantis.utils.AMath; - -import java.util.ArrayList; - -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; - -/** - * This class represents projections which are a linear transformation on - * 3d space. These are easy to handle for a variety of reasons - * - * @author Adam Davison, Mark Stockton - */ -public abstract class ANLinearProjection extends ANProjection { - - // DEPRECATED - public ANObjectGeomMuon m_ogm;//muon - public ANObjectGeomCalo m_ogc;//calo barrel - public ANObjectGeomCalo m_ogetp;//extended tile +z - public ANObjectGeomCalo m_ogtsp;//mbts +z - public ANObjectGeomCalo m_ogecp;//endcap +z - public ANObjectGeomCalo m_ogetm;//extended tile -z - public ANObjectGeomCalo m_ogtsm;//mbts -z - public ANObjectGeomCalo m_ogecm;//endcap -z - - public ANObjectDataJet m_jet;//jets - public ANObjectDataCell m_lar;//lar cells - - private static AEventManager eventManager = AEventManager.instance(); - - /** - * The contract of applyLinearTransform is that you can assume - * the matrix stack is in an identity state and you should always apply - * the transformation in a relative manner, ie glTransform, glRotate - * nothing like glLoadMatrix or glLoadIdentity - * - * @param drawable - */ - public abstract void applyLinearTransform(GLAutoDrawable drawable, int w, int h); - - public abstract void drawScene(GLAutoDrawable drawable, ANRenderHints hint); - - // TODO: A lot of this function should probably be broken up into more - // subclasses to allow this functionality to be selected more - // granularly - @Override - public final void display(GLAutoDrawable drawable, int w, int h, ANRenderHints hint) { - GL gl = drawable.getGL(); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadIdentity(); - - gl.glMatrixMode(GL.GL_PROJECTION); - - // This is a bit of a hack maybe... - if (!hint.getPick()) { - gl.glLoadIdentity(); - } - - gl.glEnable(gl.GL_BLEND); - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA); - gl.glEnable(GL.GL_DEPTH_TEST); - - gl.glPolygonOffset(2.0f, 1.0f); - gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); - - applyLinearTransform(drawable, w, h); - - ANColor bg = ANColor.getBGColor(); - - gl.glClearColor(bg.r, bg.g, bg.b, 1.0f); - gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); - - drawScene(drawable, hint); - } // Some function that calls applyLinearTransform and extracts the matrix - // is needed for the transitions but that can come later... - - - // DEPRECATED - to be replaced shortly by ANObjectGenerator - public final void createGeometry(){ - ArrayList<ABoxDetector> m_boxes = new ArrayList<ABoxDetector>(); - ArrayList<ACalorimeterDetector> m_calo = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_extt = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_mbts = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_endc = new ArrayList<ACalorimeterDetector>(); - - ADetectors[] ds = AAtlasDetector.getDetector().getDetectors(); - for (int i = 0; i < ds.length; i++) { - ADetector[] d = ds[i].getDetectors(); - for (int j = 0; j < d.length; j++) { - if (d[j] instanceof ABoxDetector) { - ABoxDetector bd = (ABoxDetector) d[j]; - //TODO temporary code to show cut away detector - //if((bd.getPhi()>1.2 && bd.getPhi()<5.1) || !ACanvas.getCanvas().getPaintingWindow().getProjection().getName().equals("N3D")) - m_boxes.add(bd); - }else if (d[j] instanceof ABarrelCalorimeterDetector) { - ACalorimeterDetector cd = (ACalorimeterDetector) d[j]; - //extended tile only has one end in geom file and not relicated like others - if(d[j].getName().equals("Extended TILE")){ - m_extt.add(cd); - }else{ - m_calo.add(cd); - } - - } else if (d[j] instanceof AEndcapCryostatDetector) { - //adds MBTS but only has one end in geom file - AEndcapCryostatDetector ecd = (AEndcapCryostatDetector) d[j]; - m_mbts.add(ecd); - } else if (d[j] instanceof AEndcapCalorimeterDetector) { - //adds LAr endcap + HEC but only has one end in geom file - AEndcapCalorimeterDetector ecd = (AEndcapCalorimeterDetector) d[j]; - m_endc.add(ecd); - - } - - } - } - - m_ogm = new ANObjectGeomMuon(m_boxes); - m_ogc = new ANObjectGeomCalo(m_calo, 4, false); - m_ogetp = new ANObjectGeomCalo(m_extt, 4, false); - m_ogtsp = new ANObjectGeomCalo(m_mbts, 1, false); - m_ogecp = new ANObjectGeomCalo(m_endc, 1, false); - m_ogetm = new ANObjectGeomCalo(m_extt, 4, true); - m_ogtsm = new ANObjectGeomCalo(m_mbts, 1, true); - m_ogecm = new ANObjectGeomCalo(m_endc, 1, true); - - - } - - // DEPRECATED - to be replaced shortly by ANObjectGenerator - public final void createData(){ - - AEvent ev = eventManager.getCurrentEvent(); - AJetData ajd = ev.getJetData(); - ajd.makeDrawList(); - m_jet = new ANObjectDataJet(ajd); - - ALArData ald = ev.getLArData(); - ald.makeDrawList(); - m_lar = new ANObjectDataCell(ald); - - } - - // DEPRECATED - to be replaced shortly by ANObjectGenerator - public final void createGeometry(float phi, float eta, float dr){ - ArrayList<ABoxDetector> m_boxes = new ArrayList<ABoxDetector>(); - ArrayList<ACalorimeterDetector> m_calo = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_extt = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_mbts = new ArrayList<ACalorimeterDetector>(); - ArrayList<ACalorimeterDetector> m_endc = new ArrayList<ACalorimeterDetector>(); - - - ADetectors[] ds = AAtlasDetector.getDetector().getDetectors(); - for (int i = 0; i < ds.length; i++) { - ADetector[] d = ds[i].getDetectors(); - for (int j = 0; j < d.length; j++) { - if (d[j] instanceof ABoxDetector) { - ABoxDetector bd = (ABoxDetector) d[j]; - //code to show cut away detector - float etabd = (float) AMath.etaAbs(bd.getZMin(), bd.getRMin()); - if(AMath.deltaR(phi,eta,(float)bd.getPhi(),etabd)<dr) - m_boxes.add(bd); - }else if (d[j] instanceof ABarrelCalorimeterDetector) { - ACalorimeterDetector cd = (ACalorimeterDetector) d[j]; - //extended tile only has one end in geom file and not relicated like others - if(d[j].getName().equals("Extended TILE")){ - m_extt.add(cd); - }else{ - m_calo.add(cd); - } - - } else if (d[j] instanceof AEndcapCryostatDetector) { - //adds MBTS but only has one end in geom file - AEndcapCryostatDetector ecd = (AEndcapCryostatDetector) d[j]; - m_mbts.add(ecd); - } else if (d[j] instanceof AEndcapCalorimeterDetector) { - //adds LAr endcap + HEC but only has one end in geom file - AEndcapCalorimeterDetector ecd = (AEndcapCalorimeterDetector) d[j]; - m_endc.add(ecd); - - } - - } - } - - m_ogm = new ANObjectGeomMuon(m_boxes); - m_ogc = new ANObjectGeomCalo(m_calo, 4, false); - m_ogetp = new ANObjectGeomCalo(m_extt, 4, false); - m_ogtsp = new ANObjectGeomCalo(m_mbts, 1, false); - m_ogecp = new ANObjectGeomCalo(m_endc, 1, false); - m_ogetm = new ANObjectGeomCalo(m_extt, 4, true); - m_ogtsm = new ANObjectGeomCalo(m_mbts, 1, true); - m_ogecm = new ANObjectGeomCalo(m_endc, 1, true); - - - } - - public final void createData(float phi, float eta, float dr){ - - AEvent ev = eventManager.getCurrentEvent(); - AJetData ajd = ev.getJetData(); - ajd.makeDrawList(); - m_jet = new ANObjectDataJet(ajd, phi, eta, dr); - - ALArData ald = ev.getLArData(); - ald.makeDrawList(); - m_lar = new ANObjectDataCell((ACalorimeterData)ald, phi, eta, dr); - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANLinearTransition.java b/graphics/AtlantisJava/src/atlantis/nge/ANLinearTransition.java deleted file mode 100644 index 918caf427d8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANLinearTransition.java +++ /dev/null @@ -1,140 +0,0 @@ -package atlantis.nge; - -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; - -/** - * - * @author Adam Davison - */ -public class ANLinearTransition extends ANLinearProjection { - - private ANLinearProjection m_a; - private ANLinearProjection m_b; - private ANAnimVar m_vtttime = new ANAnimVar(); - private ANAnimVar m_fadetime = new ANAnimVar(); - - public ANLinearTransition(ANLinearProjection a, ANLinearProjection b) { - m_a = a; - m_b = b; - } - - public ANAnimVar getTransformTimeVar() { return m_vtttime; } - public ANAnimVar getFadeTimeVar() { return m_fadetime; } - - @Override - public void applyLinearTransform(GLAutoDrawable drawable, int w, int h) { - GL gl = drawable.getGL(); - - double vtttime = m_vtttime.getValue(); - - if (vtttime < 0.0) { vtttime = 0.0; } - - if (vtttime <= 0.0f) { - m_a.applyLinearTransform(drawable, w, h); - } else if (vtttime >= 1.0f) { - m_b.applyLinearTransform(drawable, w, h); - } else { - - float[] ma = new float[16]; - float[] mb = new float[16]; - - // TODO: Make this whole thing better - // Maybe this is ok. If getFloatv is problematic we may have trouble - // but generally this allows us to transform between moving projections! - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - m_a.applyLinearTransform(drawable, w, h); - gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, ma, 0); - gl.glLoadIdentity(); - m_b.applyLinearTransform(drawable, w, h); - gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, mb, 0); - gl.glPopMatrix(); - - float[] matrix = new float[16]; - - // Scaling the matrix linearly means that x/w moves in a highly - // non-linear way, especially where large scale changes in w are - // involved, try to compensate this by using a highly non-linear - // time coordinate - - // Final solution involves inverting the formula for the transformation - // to calculate what time coordinate should be applied to ensure - // linear motion of a test eye coordinate between it's clip - // coordinates under transformation by ma and mb - // Should document the maths at some point for sanity... - - // Operating on normalised time here, length 1 - double[] zerosums = new double[4]; - double[] gradsums = new double[4]; - - for (int y = 0; y < 4; y++) { - zerosums[y] = 0.0f; - gradsums[y] = 0.0f; - for (int x = 0; x < 4; x++) { - zerosums[y] += ma[(4 * x) + y]; - gradsums[y] += mb[(4 * x) + y] - ma[(4 * x) + y]; - } - } - - double w0 = ma[3] + ma[7] + ma[11] + ma[15]; - double wT = mb[3] + mb[7] + mb[11] + mb[15]; - - double[] timeest = new double[3]; - for (int i = 0; i < 3; i++) { - // Target value of coord/w - double c0w = (ma[0 + i] + ma[4 + i] + ma[8 + i] + ma[12 + i]) / w0; - double cTw = (mb[0 + i] + mb[4 + i] + mb[8 + i] + mb[12 + i]) / wT; - // Beta is the target value for this component, this could be - // a non-linear function for smoother transitions - // i.e. something with 0 first derivative at times 0 and 1 - double beta = (c0w + ((cTw - c0w) * vtttime)); - timeest[i] = (zerosums[i] - zerosums[3] * beta) / (gradsums[3] * beta - gradsums[i]); - } - - // They seem to tend to scale similarly at the moment but this - // may fall apart for some really wierd transformation matrix... - // ... just take the mean for now and look out for problems - double meantime = (timeest[0] + timeest[1] + timeest[2]) / 3.0; - - for (int i = 0; i < 16; i++) { - matrix[i] = (float) (ma[i] + ((mb[i] - ma[i]) * meantime)); - } - - gl.glMultMatrixf(matrix, 0); - } - } - - @Override - public void drawScene(GLAutoDrawable drawable, ANRenderHints hint) { - GL gl = drawable.getGL(); - - - - if (m_fadetime.getValue() > 0.0) { - m_a.drawScene(drawable, hint); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); - ANColor bgc = ANColor.getBGColor(); - gl.glColor4f(bgc.r, bgc.g, bgc.b, (float)(m_fadetime.getValue())); - gl.glDisable(GL.GL_DEPTH_TEST); - gl.glBegin(GL.GL_QUADS); - gl.glVertex3f(-1.0f, -1.0f, 0.0f); - gl.glVertex3f(1.0f, -1.0f, 0.0f); - gl.glVertex3f(1.0f, 1.0f, 0.0f); - gl.glVertex3f(-1.0f, 1.0f, 0.0f); - gl.glEnd(); - // FIXME: Don't always want this back on here potentially - gl.glEnable(GL.GL_DEPTH_TEST); - gl.glPopMatrix(); - gl.glClear(GL.GL_DEPTH_BUFFER_BIT); - } - - m_b.drawScene(drawable, hint); - - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANManager.java b/graphics/AtlantisJava/src/atlantis/nge/ANManager.java deleted file mode 100644 index 0b7350c29e4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANManager.java +++ /dev/null @@ -1,122 +0,0 @@ -package atlantis.nge; - -import atlantis.canvas.AWindow; -import atlantis.utils.ALogger; -import java.util.Hashtable; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLPbuffer; - -/** - * This class keeps handy resources for you... - * - * @author Adam Davison - */ -public class ANManager implements GLEventListener { - - private static ALogger logger = ALogger.getLogger(ANManager.class); - private static ANManager manager = new ANManager(); - - public static ANManager getManager() { - return manager; - } - private Hashtable<AWindow, ANFrameManager> m_fms = null; - private GLPbuffer m_buf = null; - private GLEventListener m_gll; - - public ANManager() { - m_fms = new Hashtable<AWindow, ANFrameManager>(); - } - - public ANFrameManager getFrameManager(AWindow w) { - if (w == null) { - return null; - } - ANFrameManager fm = m_fms.get(w); - if (fm == null) { - fm = new ANFrameManager(w); - m_fms.put(w, fm); - } - return fm; - } - - public static int getNextPower2(int v) { - int p = 1; - for (int i = 0; i < 16; i++) { - p *= 2; - if (p >= v) { - return p; - } - } - - logger.warn("Returning non power of 2 buffer size!"); - return v; - } - - public void requestBufferDraw(int w, int h, GLEventListener gll) { - - if (m_buf != null && m_buf.getWidth() >= w && m_buf.getHeight() >= h) { - //System.out.println("BUFFER OK"); - // Do nothing - } else { - //System.out.println("BUFFER CREATE/REPLACE"); - if (m_buf != null) { - m_buf.destroy(); - } - - GLCapabilities pbcap = new GLCapabilities(); - pbcap.setHardwareAccelerated(true); - pbcap.setSampleBuffers(true); - pbcap.setNumSamples(4); - //pbcap.setPbufferRenderToTexture(true); - //pbcap.setDoubleBuffered(false); - - //logger.info("w: " + m_w + " 2: " + getNextPower2(m_w)); - - m_buf = GLDrawableFactory.getFactory().createGLPbuffer(pbcap, null, - getNextPower2(w), getNextPower2(h), null); - - if (m_buf == null) { - logger.error("Got null when trying to create pbuffer!"); - return; - } - - m_buf.addGLEventListener(this); - - logger.info("Created pbuffer w: " + m_buf.getWidth() + " h: " + m_buf.getHeight()); - - if (m_buf.getChosenGLCapabilities() == null) { - logger.warn("Your implementation returns null for pbuffer capabilities..."); - } else { - logger.info("Pbuffer hardware accelleration: " + m_buf.getChosenGLCapabilities().getHardwareAccelerated()); - } - } - - // Set up events to go back to the projection - m_gll = gll; - - //System.out.println("CALLING DISPLAY"); - m_buf.display(); - } - - public void init(GLAutoDrawable arg0) { - m_gll.init(arg0); - } - - public void display(GLAutoDrawable arg0) { - //System.out.println("HIT DISPLAY CALLBACK"); - m_gll.display(arg0); - } - - public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { - m_gll.reshape(arg0, arg1, arg2, arg3, arg4); - } - - public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { - m_gll.displayChanged(arg0, arg1, arg2); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANObjectGenerator.java b/graphics/AtlantisJava/src/atlantis/nge/ANObjectGenerator.java deleted file mode 100644 index 260518afd22..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANObjectGenerator.java +++ /dev/null @@ -1,151 +0,0 @@ -package atlantis.nge; - -import atlantis.event.AEventManager; -import atlantis.data.ACalorimeterData; -import atlantis.event.AEvent; -import atlantis.data.AJetData; -import atlantis.data.ATrackData; -import atlantis.geometry.ABoxDetector; -import atlantis.nge.object.ANObject; -import atlantis.nge.object.ANObjectList; -import atlantis.nge.object.data.ANObjectPointing; -import atlantis.nge.object.data.ANObjectTracks; -import atlantis.nge.object.geometry.ANObjectGeomMuon; -import atlantis.utils.ALogger; -import atlantis.utils.AMath; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.List; - -/** - * These things get arrays of ANObjects out of the Atlantis data store - * - * The general idea is to separate the selection of objects from the way - * they're represented in the projection. But I suspect that'll break down - * - * For now it's a static object but if we ever want to unstatic it then it's - * only accessible via getGenerator() so it should be easy to refactor - * - * A lot of the functionality should one day be pushed back into the detector - * objects themselves - * - * @author Adam Davison - */ -public class ANObjectGenerator { - - private static ALogger logger = ALogger.getLogger(ANObjectGenerator.class); - private static AEventManager eventManager = AEventManager.instance(); - - private static ANObjectGenerator thegenerator = new ANObjectGenerator(); - - private ANObjectGenerator() { - } - - public static ANObjectGenerator getGenerator() { - return thegenerator; - } - - public ANObject getGeometryMuon() { - return new ANObjectGeomMuon(ANTerribleHacks.getMuonDetectors()); - } - - // Ideally change layout of detector stuff so this can be more generic - // not like one search per type, since basically everything has eta/phi - public ANObject getGeometryMuon(float phi, float eta, float dr) { - ArrayList<ABoxDetector> boxes = ANTerribleHacks.getMuonDetectors(); - ArrayList<ABoxDetector> hits = new ArrayList<ABoxDetector>(); - - for (int i = 0; i < boxes.size(); i++) { - ABoxDetector bd = boxes.get(i); - // TODO - This formula is wrong, it's only checking one corner - float etabd = (float) AMath.etaAbs(bd.getZMin(), bd.getRMin()); - if (AMath.deltaR(phi, eta, (float) bd.getPhi(), etabd) < dr) { - hits.add(bd); - } - } - - return new ANObjectGeomMuon(hits); - } - - public ANObject getDataCaloForJet(int j, String key) { - - ANObjectList ol = new ANObjectList(); - - AEvent ev = eventManager.getCurrentEvent(); - AJetData jd = ev.getJetData(); - String assockey = jd.getFullName(); - int[][] assoc = ev.getAssociationManager().get(assockey, key); - if (assoc == null) { return ol; } - if (assoc[j] == null) { return ol; } - int[] dl = new int[assoc[j].length]; - List calolist = ev.getCalorimeters(); - ACalorimeterData calo = null; - for (int i = 0; i < calolist.size(); i++) { - ACalorimeterData tc = (ACalorimeterData)(calolist.get(i)); - if (tc.getName().equals(key)) { - calo = tc; - } - } - if (calo == null) { - logger.error("Requested unavailable calo key!"); - return ol; - } - - calo.makeDrawList(); - int[] calodl = calo.getDrawList(); - - IntBuffer ib = IntBuffer.allocate(assoc[j].length); - for (int i = 0; i < assoc[j].length; i++) { - int id = assoc[j][i]; - int index = calo.getIndexFromId(id); - boolean found = false; - for (int d = 0; d < calo.getNumDraw(); d++) { - if (calodl[d] == index) { - found = true; - } - } - if (found) { - ib.put(index); - } - } - - ol.addObject(new ANObjectPointing(calo, ib.array(), ib.position(), true)); - ol.addObject(new ANObjectPointing(calo, ib.array(), ib.position(), false)); - - return ol; - } - - public ANObject getInDetTracksForJet(int j) { - AEvent ev = eventManager.getCurrentEvent(); - AJetData jd = ev.getJetData(); - int jetid = jd.getIdFromIndex(j); - ATrackData tracks = ev.getTrackData("InDetTrack"); - int[] trackdl = tracks.getDrawList(); - String jetassockey = jd.getFullName(); - String trackassockey = tracks.getName() + tracks.getStoreGateKey(); - int[][] assoc = ev.getAssociationManager().get(trackassockey, jetassockey); - - IntBuffer ib = IntBuffer.allocate(assoc.length); - for (int i = 0; i < assoc.length; i++) { - for (int s = 0; s < assoc[i].length; s++) { - if (assoc[i][s] == jetid) { - boolean display = false; - for (int d = 0; d < trackdl.length; d++) { - if (trackdl[d] == i) { - display = true; - } - } - if (display) {ib.put(i);} - } - } - } - - return new ANObjectTracks(tracks, ib.array()); - } - - public ANObject getInDetTracks() { - AEvent ev = eventManager.getCurrentEvent(); - ATrackData td = ev.getTrackData("InDetTrack"); - return new ANObjectTracks(td); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickDrawer.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickDrawer.java deleted file mode 100644 index 938f0a4f370..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickDrawer.java +++ /dev/null @@ -1,59 +0,0 @@ -package atlantis.nge; - -import atlantis.canvas.AWindow; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLEventListener; - -/** - * - * @author Adam Davison - */ -public class ANPickDrawer implements GLEventListener { - - private AWindow m_window; - private int m_w; - private int m_h; - private int m_x; - private int m_y; - - private ANPickResult m_pr; - private boolean m_pickdone; - - private ANPickListener m_pl; - - public ANPickDrawer(AWindow window, int w, int h, int x, int y, ANPickListener pl) { - m_window = window; - m_w = w; - m_h = h; - m_x = x; - m_y = y; - m_pickdone = false; - m_pl = pl; - } - - public void doPick() { - ANManager.getManager().requestBufferDraw(m_w, m_h, this); - } - - public void init(GLAutoDrawable arg0) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void display(GLAutoDrawable arg0) { - m_pr = ANManager.getManager().getFrameManager(m_window).pick(arg0, m_w, m_h, m_x, m_y); - m_pickdone = true; - - if (m_pl != null) { - m_pl.pickCompleted(m_pr); - } - } - - public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { - //throw new UnsupportedOperationException("Not supported yet."); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickHandler.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickHandler.java deleted file mode 100644 index baaeb581efe..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public interface ANPickHandler { - - // Turn your 32 bits of data into a result somehow - public ANPickResult getHitInfo(int data); -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickHandlerSimple.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickHandlerSimple.java deleted file mode 100644 index 7b1f713e79e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickHandlerSimple.java +++ /dev/null @@ -1,19 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public class ANPickHandlerSimple implements ANPickHandler { - - private String m_name; - - public ANPickHandlerSimple(String name) { - m_name = name; - } - - public ANPickResult getHitInfo(int data) { - return new ANPickResult(m_name); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickHelper.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickHelper.java deleted file mode 100644 index e8912acfdf9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -package atlantis.nge; - -import atlantis.nge.object.ANObject; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import javax.media.opengl.GL; - -/** - * - * @author Adam Davison - */ -public class ANPickHelper { - - private ArrayList<ANObject> m_all = new ArrayList<ANObject>(); - private GL m_gl; - - public ANPickHelper(GL gl) { - m_gl = gl; - } - - public ANPickHandler getPickHandler(int id) { - System.out.println(m_all.get(id)); - return m_all.get(id).getPickHandler(); - } - - public int getIndex(ANObject p) { - int id = m_all.indexOf(p); - - if (id == -1) { - m_all.add(p); - id = m_all.indexOf(p); - } - - return id; - } - - // Worry about it being fast much later... - public void startPick(ANObject p, int data) { - startPick(getIndex(p), data); - } - - public void startPick(int pickid, int data) { - m_gl.glPushName(pickid); - m_gl.glPushName(data); - } - - public void endPick() { - m_gl.glPopName(); - m_gl.glPopName(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickListener.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickListener.java deleted file mode 100644 index f7a118143fa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickListener.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package atlantis.nge; - -/** - * - * @author Adam - */ -public interface ANPickListener { - - public void pickCompleted(ANPickResult pr); -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickResult.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickResult.java deleted file mode 100644 index d1d05d7efcf..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickResult.java +++ /dev/null @@ -1,21 +0,0 @@ -package atlantis.nge; - -/** - * This class encapsulates all the information you might want to get out of a - * pick interaction and back into Atlantis - * - * @author Adam Davison - */ -public class ANPickResult { - - private String m_result; - - public ANPickResult(String result) { - m_result = result; - } - - public String getResult() { - return m_result; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANPickResultPrinter.java b/graphics/AtlantisJava/src/atlantis/nge/ANPickResultPrinter.java deleted file mode 100644 index 1b28bd2a45e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANPickResultPrinter.java +++ /dev/null @@ -1,17 +0,0 @@ -package atlantis.nge; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; - -/** - * - * @author Adam Davison - */ -public class ANPickResultPrinter implements ANPickListener { - - public void pickCompleted(ANPickResult pr) { - if (pr != null) { - AOutput.append("Picked: " + pr.getResult() + "\n\n", ALogInterface.PICK); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANProjection.java b/graphics/AtlantisJava/src/atlantis/nge/ANProjection.java deleted file mode 100644 index f49fb76086b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANProjection.java +++ /dev/null @@ -1,20 +0,0 @@ -package atlantis.nge; - -import javax.media.opengl.GLAutoDrawable; - -/** - * So this class represents a projection, which in this model is the class - * that decides what objects to draw and how to draw them - * - * It is controlled by the ANFrameManager which tells it what to do. - * - * It shouldn't touch the Atlantis core at all. It gets ANObjects from an - * ANObjectGenerator which is can then render in any order it chooses into a - * renderer it can configure in any way it likes. - * - * @author Adam Davison - */ -public abstract class ANProjection { - - public abstract void display(GLAutoDrawable drawable, int w, int h, ANRenderHints hint); -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANProjection3D.java b/graphics/AtlantisJava/src/atlantis/nge/ANProjection3D.java deleted file mode 100644 index 954f0ead445..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANProjection3D.java +++ /dev/null @@ -1,90 +0,0 @@ -package atlantis.nge; - -import atlantis.nge.object.ANObjectTestAxes; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; - -import atlantis.parameters.APar; - -/** - * The plain 3d projection, simple for debugging - * - * @author Adam Davison, Mark Stockton - */ -public class ANProjection3D extends ANLinearProjection { - - - private float m_phi; - private float m_elev; - private float m_distance; - private float m_tx, m_ty, m_tz; - - public ANProjection3D() { - - m_phi = -45.0f; - m_elev = 20.0f; - m_distance = 3000.0f; - m_tx = 0.0f; - m_ty = 0.0f; - m_tz = 0.0f; - - // create the object generator here - } - - @Override - public void applyLinearTransform(GLAutoDrawable drawable, int width, int height) { - GL gl = drawable.getGL(); - - float w = 1000.0f; - float h = (w * drawable.getHeight()) / drawable.getWidth(); - - gl.glFrustum(-w, w, -h, h, 1000.0f, 10000.0f); - - // Remember, these are in reverse so essentially: - // 0. GL default, start at 0,0,-1 looking at 0,0,0 - // 1. Spin around y axis to give phi - // 2. Spin around x axis to give elevation - // 3. Pull back to give distance - gl.glTranslatef(0.0f, 0.0f, -m_distance); - gl.glRotatef(m_elev, 1.0f, 0.0f, 0.0f); - gl.glRotatef(m_phi, 0.0f, 1.0f, 0.0f); - gl.glTranslatef(-m_tx, -m_ty, -m_tz); - } - - @Override - public void drawScene(GLAutoDrawable drawable, ANRenderHints hint) { - ANRenderer r = new ANRendererBasic(drawable); - if(APar.instance().get("N3D","Axis").getStatus()){ - ANObjectTestAxes ota = new ANObjectTestAxes(); - ota.render(r, hint); - } - - if (m_ogm == null) { - //m_ogm = new ANObjectGeom(); - createGeometry(); - } - - m_ogm.render(r, hint); - m_ogc.render(r, hint); - m_ogetp.render(r, hint); - m_ogecp.render(r, hint); - m_ogtsp.render(r, hint); - m_ogetm.render(r, hint); - m_ogecm.render(r, hint); - m_ogtsm.render(r, hint); - - createData(); - m_jet.render(r, hint); - - } - - public void dPhi(float phi) { - m_phi += phi; - } - - public void dElev(float elev) { - m_elev += elev; - if (m_elev < -90.0f) { m_elev = -90.0f; } - if (m_elev > 90.0f) { m_elev = 90.0f; } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANProjectionPhysics.java b/graphics/AtlantisJava/src/atlantis/nge/ANProjectionPhysics.java deleted file mode 100644 index 47e95f65d9f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANProjectionPhysics.java +++ /dev/null @@ -1,181 +0,0 @@ -package atlantis.nge; - -import atlantis.event.AData; -import atlantis.data.AJetData; -import atlantis.nge.object.ANObjectTestAxes; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; - -import atlantis.parameters.APar; -import atlantis.utils.A3Vector; -import atlantis.utils.AMath; -import javax.media.opengl.glu.GLU; - -/** - * The plain 3d projection, simple for debugging - * - * @author Adam Davison, Mark Stockton - */ -public class ANProjectionPhysics extends ANLinearProjection { - - private float m_focus_phi; - private float m_focus_eta; - private ANAnimVar m_phi; - private ANAnimVar m_elev; - private float m_distance; - private float m_tx, m_ty, m_tz; - private AData m_data; - private int m_data_index; - - public ANProjectionPhysics() { - - m_focus_phi = 0; - m_focus_eta = 0; - m_phi = new ANAnimVar(-45.0); - m_elev = new ANAnimVar(20.0); - m_distance = 2000.0f; - m_tx = 0.0f; - m_ty = 0.0f; - m_tz = 0.0f; - - - // create the object generator here - } - - @Override - public void applyLinearTransform(GLAutoDrawable drawable, int w, int h) { - GL gl = drawable.getGL(); - - //float w = 1000.0f; - //float h = (w * drawable.getHeight()) / drawable.getWidth(); - - //gl.glFrustum(-w, w, -h, h, 1000.0f, 10000.0f); - GLU glu = new GLU(); - glu.gluPerspective(7.0f, w / h, 200.0f, 10000.0f); - - /*gl.glTranslatef(0.0f, 0.0f, -2000.0f); - gl.glRotatef(m_elev, 1.0f, 0.0f, 0.0f); - gl.glRotatef(m_phi, 0.0f, 1.0f, 0.0f); - gl.glRotatef(m_focus_phi, 0.0f, 0.0f, 1.0f); - gl.glRotatef(-theta, 0.0f, 1.0f, 0.0f); - gl.glTranslatef(0.0f, 0.0f, 500.0f); - gl.glRotatef(theta, 0.0f, 1.0f, 0.0f); - gl.glRotatef(-m_focus_phi, 0.0f, 0.0f, 1.0f);*/ - // Remember, these are in reverse so essentially: - // 0. GL default, start at 0,0,-1 looking at 0,0,0 - // 1. Spin around y axis to give phi - // 2. Spin around x axis to give elevation - // 3. Pull back to give distance - gl.glTranslatef(0.0f, 0.0f, -m_distance); - gl.glRotatef((float) m_elev.getValue(), 1.0f, 0.0f, 0.0f); - gl.glRotatef((float) m_phi.getValue(), 0.0f, 1.0f, 0.0f); - gl.glTranslatef(-m_tx, -m_ty, -m_tz); - - - } - - @Override - public void drawScene(GLAutoDrawable drawable, ANRenderHints hint) { - ANRenderer r = new ANRendererBasic(drawable); - - GL gl = drawable.getGL(); - gl.glColor3f(1.0f, 0.0f, 0.0f); - gl.glPointSize(2.0f); - gl.glBegin(GL.GL_POINTS); - gl.glVertex3f(m_tx, m_ty, m_tz); - gl.glEnd(); - - if (APar.instance().get("NPhysics", "Axis").getStatus()) { - ANObjectTestAxes ota = new ANObjectTestAxes(); - ota.render(r, hint); - } - - //ANObjectGenerator.getGenerator() - // .getGeometryMuon(m_focus_phi, m_focus_eta, 1.0f).render(r, pick); - //.getGeometryMuon().render(r, pick); - - ANObjectGenerator.getGenerator().getDataCaloForJet(m_data_index, "LAr").render(r, hint); - ANObjectGenerator.getGenerator().getDataCaloForJet(m_data_index, "TILE").render(r, hint); - ANObjectGenerator.getGenerator().getDataCaloForJet(m_data_index, "HEC").render(r, hint); - //ANObjectGenerator.getGenerator().getDataCaloForJet(m_data_index, "FCAL").render(r, pick); - ANObjectGenerator.getGenerator().getInDetTracksForJet(m_data_index).render(r, hint); - - //createGeometry(m_focus_phi, m_focus_eta, 1.0f); - //m_ogm.render(r, pick); - /*m_ogc.render(r); - m_ogetp.render(r); - m_ogecp.render(r); - m_ogtsp.render(r); - m_ogetm.render(r); - m_ogecm.render(r); - m_ogtsm.render(r);*/ - - //createData(m_focus_phi, m_focus_eta, 2.0f); - //m_jet.render(r, pick); - //m_lar.render(r, pick); - - } - - public void dPhi(float phi) { - m_phi.setValue(m_phi.getValue() + phi); - } - - public void dElev(float elev) { - m_elev.setValue(m_elev.getValue() + elev); - if (m_elev.getValue() < -90.0) { - m_elev.setValue(-90.0); - } - if (m_elev.getValue() > 90.0) { - m_elev.setValue(90.0); - } - } - - public void lookAt(AJetData jd, int jet_index) { - - m_data = jd; - m_data_index = jet_index; - - A3Vector centre = ANTerribleHacks.getCellCentreLArForJet(jet_index); - m_tx = (float) centre.x; - m_ty = (float) centre.y; - m_tz = (float) centre.z; - - float phi = jd.getPhi(jet_index); - float eta = jd.getEta(jet_index); - - m_focus_phi = phi; - m_focus_eta = eta; - - // m_elev is Spin around y axis to give phi - // m_phi is Spin around x axis to give elevation - float theta = (float) (2.0f * Math.atan(Math.exp(eta))); - theta = (float) Math.toDegrees(theta); - phi = (float) Math.toDegrees(phi); - - //produce coords to try to look perpendicular to jet - //needs improving - if (eta < 0) { - eta = -1; - } else { - eta = 1; - } - float x = (float) (m_distance * Math.cos(phi) * Math.sin(theta)); - float z = (float) (m_distance * Math.cos(theta)); - - float rot = (float) Math.toDegrees(Math.atan(z / x)); - - if (theta < 90) { - m_elev.setValue(eta * -theta); - m_phi.setValue(rot); - } else { - m_elev.setValue(eta * (180. - theta)); - m_phi.setValue(rot - 45.); - } - //actually dont need to set melev - m_elev.setValue(0); - - } - - public ANAnimVar getElevVar() { return m_elev; } - public ANAnimVar getPhiVar() { return m_phi; } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANProjectionYX.java b/graphics/AtlantisJava/src/atlantis/nge/ANProjectionYX.java deleted file mode 100644 index 6ca68b65f10..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANProjectionYX.java +++ /dev/null @@ -1,46 +0,0 @@ -package atlantis.nge; - -import atlantis.nge.object.ANObjectTestAxes; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; - -import atlantis.parameters.APar; - -/** - * - * @author Adam Davison, Mark Stockton - */ -public class ANProjectionYX extends ANLinearProjection { - - - @Override - public void applyLinearTransform(GLAutoDrawable drawable, int w, int h) { - GL gl = drawable.getGL(); - - gl.glMatrixMode(GL.GL_PROJECTION); - float scale = ((float) drawable.getHeight()) / ((float) drawable.getWidth()); - gl.glOrtho(-1500.0f, 1500.0f, -1500.0f * scale, 1500.0f * scale, -100000.0f, 100000.0f); - } - - @Override - public void drawScene(GLAutoDrawable drawable, ANRenderHints hint) { - ANRenderer r = new ANRendererBasic(drawable); - if(APar.instance().get("NYX","Axis").getStatus()){ - ANObjectTestAxes ota = new ANObjectTestAxes(); - ota.render(r, hint); - } - - if (m_ogm == null) { - //m_ogm = new ANObjectGeomMuon(); - createGeometry(); - } - - m_ogm.render(r, hint); - - m_ogc.render(r, hint); - - createData(); - m_jet.render(r, hint); - m_lar.render(r, hint); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANRenderHints.java b/graphics/AtlantisJava/src/atlantis/nge/ANRenderHints.java deleted file mode 100644 index c370fdf3a98..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANRenderHints.java +++ /dev/null @@ -1,33 +0,0 @@ -package atlantis.nge; - -/** - * - * @author Adam Davison - */ -public class ANRenderHints { - - private boolean pick; - private ANPickHelper pickHelper; - - public ANRenderHints() { - pick = false; - pickHelper = null; - } - - public ANPickHelper getPickHelper() { - return pickHelper; - } - - public void setPickHelper(ANPickHelper pickHelper) { - this.pickHelper = pickHelper; - } - - public boolean getPick() { - return pick; - } - - public void setPick(boolean pick) { - this.pick = pick; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANRenderer.java b/graphics/AtlantisJava/src/atlantis/nge/ANRenderer.java deleted file mode 100644 index 91817987407..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANRenderer.java +++ /dev/null @@ -1,22 +0,0 @@ -package atlantis.nge; - -/** - * This class provides an interface for drawing into a context of some kind - * essentially it's a drawing API, much like java.awt.Graphics but rather - * tuned towards drawing 3-d objects via OpenGL - * - * @author Adam Davison - */ -public abstract class ANRenderer { - - public abstract void begin(int type); - public abstract void end(); - - public abstract void vertex3f(float x, float y, float z); - public abstract void color3f(float r, float g, float b); - public abstract void color4f(float r, float g, float b, float a); - public abstract void lineWidth(float w); - - public abstract void drawVertices(float[] vert); - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANRendererBasic.java b/graphics/AtlantisJava/src/atlantis/nge/ANRendererBasic.java deleted file mode 100644 index c0895accf38..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANRendererBasic.java +++ /dev/null @@ -1,88 +0,0 @@ -package atlantis.nge; - -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.glu.GLU; - -/** - * - * @author Adam Davison - */ -public class ANRendererBasic extends ANRenderer { - - private GLAutoDrawable m_drawable; - private GL m_gl; - - public ANRendererBasic(GLAutoDrawable drawable) { - m_drawable = drawable; - m_gl = drawable.getGL(); - } - - @Override - public void begin(int type) { - m_gl.glBegin(type); - } - - @Override - public void end() { - m_gl.glEnd(); - } - - @Override - public void drawVertices(float[] vert) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void vertex3f(float x, float y, float z) { - // if (m_btesting) { - // doBoundTest(x, y, z); - // } - - m_gl.glVertex3f(x, y, z); - } - - @Override - public void color3f(float r, float g, float b) { - m_gl.glColor3f(r, g, b); - } - - @Override - public void lineWidth(float w) { - m_gl.glLineWidth(w); - } - - @Override - public void color4f(float r, float g, float b, float a) { - m_gl.glColor4f(r, g, b, a); - } - -/* private float[] m_tmat = new float[16]; - private float m_minx; - private float m_maxx; - private float m_miny; - private float m_maxy; - - private boolean m_btesting = false; - - public void beginBoundsTest() { - // This function assumes no new transformations take place - // So bear that in mind... - - m_gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, m_tmat, 0); - m_minx = Float.MAX_VALUE; - m_maxx = Float.MIN_VALUE; - m_miny = Float.MAX_VALUE; - m_maxy = Float.MIN_VALUE; - - m_btesting = true; - } - - public void stopBoundsTest() { - m_btesting = false; - } - - private void doBoundTest(float x, float y, float z) { - - }*/ -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANSelectionList.java b/graphics/AtlantisJava/src/atlantis/nge/ANSelectionList.java deleted file mode 100644 index 52e404eda2a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANSelectionList.java +++ /dev/null @@ -1,81 +0,0 @@ -package atlantis.nge; - -import java.nio.IntBuffer; - -/** - * - * @author Adam Davison - */ -public class ANSelectionList { - - private long[] m_zmax; - private long[] m_zmin; - private int[][] m_names; - private int m_ent; - - public ANSelectionList(IntBuffer ib) { - int s = ib.limit(); - // Shortest possible entry is 4 ints long, could two pass to get - // memory requirements right but better to just spend a few bytes - int maxent = s/4; - m_zmax = new long[maxent]; - m_zmin = new long[maxent]; - m_names = new int[maxent][]; - - /*for (int i = 0; i < 20; i++) { - System.out.print(":" + ib.get(i)); - } - System.out.println();*/ - - m_ent = 0; - int pos = 0; - while((pos = processEntry(ib, pos, m_ent)) != -1) { - m_ent++; - } - //System.out.println("Got " + m_ent + " entries in selection list"); - } - - private int processEntry(IntBuffer ib, int pos, int ent) { - //System.out.println("Processing at " + pos + " entry " + ent); - int nn = ib.get(pos); - //System.out.println("nn: " + nn); - if (nn == 0) { - // At the end - return -1; - } - m_zmin[ent] = getUnsigned(ib.get(pos+1)); - m_zmax[ent] = getUnsigned(ib.get(pos+2)); - m_names[ent] = new int[nn]; - for (int i = 0; i < nn; i++) { - m_names[ent][i] = ib.get(pos+3+i); - //System.out.println("Name " + i + " is " + m_names[ent][i]); - } - pos += 3 + nn; - return pos; - } - - public long getUnsigned(int a) { - long b = a; - if (b < 0) { b -= 2L*(long)Integer.MIN_VALUE; } - return b; - } - - public int[] getFrontID() { - int found = -1; - long max = Long.MIN_VALUE; - for (int i = 0; i < m_ent; i++) { - System.out.println(m_zmax[i] + ":" + max); - if (m_zmax[i] > max) { - max = m_zmax[i]; - found = i; - } - } - - System.out.println(found); - if (found == -1) { - return null; - } else { - return m_names[found]; - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANTerribleHacks.java b/graphics/AtlantisJava/src/atlantis/nge/ANTerribleHacks.java deleted file mode 100644 index 1fd1b1c106a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANTerribleHacks.java +++ /dev/null @@ -1,119 +0,0 @@ -package atlantis.nge; - -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.data.AJetData; -import atlantis.data.ALArData; -import atlantis.geometry.AAtlasDetector; -import atlantis.geometry.ABarrelCalorimeterDetector; -import atlantis.geometry.ABoxDetector; -import atlantis.geometry.ACalorimeterDetector; -import atlantis.geometry.ADetector; -import atlantis.geometry.ADetectors; -import atlantis.geometry.AEndcapCalorimeterDetector; -import atlantis.geometry.AEndcapCryostatDetector; -import atlantis.utils.A3Vector; -import java.util.ArrayList; - -/** - * This class encapsulates everything that we shouldn't have to do in one place - * - * Mainly it relates to the fact that there's no way to ask the detector - * store for something like the muon geometry only at the moment - * - * One day if we really use this code then we need to add sensible access - * methods like that to the detector store - * - * This class should definitely be deleted one day - * - * @author Adam Davison - */ -public class ANTerribleHacks { - - private static ArrayList<ABoxDetector> m_boxes = null; - private static ArrayList<ACalorimeterDetector> m_calo = null; - private static ArrayList<ACalorimeterDetector> m_extt = null; - private static ArrayList<ACalorimeterDetector> m_mbts = null; - private static ArrayList<ACalorimeterDetector> m_endc = null; - - public static ArrayList<ABoxDetector> getMuonDetectors() { - if (m_boxes == null) { - fillArrays(); - } - return m_boxes; - } - - private static void fillArrays() { - m_boxes = new ArrayList<ABoxDetector>(); - m_calo = new ArrayList<ACalorimeterDetector>(); - m_extt = new ArrayList<ACalorimeterDetector>(); - m_mbts = new ArrayList<ACalorimeterDetector>(); - m_endc = new ArrayList<ACalorimeterDetector>(); - - ADetectors[] ds = AAtlasDetector.getDetector().getDetectors(); - for (int i = 0; i < ds.length; i++) { - ADetector[] d = ds[i].getDetectors(); - for (int j = 0; j < d.length; j++) { - if (d[j] instanceof ABoxDetector) { - ABoxDetector bd = (ABoxDetector) d[j]; - //TODO temporary code to show cut away detector - //if((bd.getPhi()>1.2 && bd.getPhi()<5.1) || !ACanvas.getCanvas().getPaintingWindow().getProjection().getName().equals("N3D")) - m_boxes.add(bd); - } else if (d[j] instanceof ABarrelCalorimeterDetector) { - ACalorimeterDetector cd = (ACalorimeterDetector) d[j]; - //extended tile only has one end in geom file and not relicated like others - if (d[j].getName().equals("Extended TILE")) { - m_extt.add(cd); - } else { - m_calo.add(cd); - } - - } else if (d[j] instanceof AEndcapCryostatDetector) { - //adds MBTS but only has one end in geom file - AEndcapCryostatDetector ecd = (AEndcapCryostatDetector) d[j]; - m_mbts.add(ecd); - } else if (d[j] instanceof AEndcapCalorimeterDetector) { - //adds LAr endcap + HEC but only has one end in geom file - AEndcapCalorimeterDetector ecd = (AEndcapCalorimeterDetector) d[j]; - m_endc.add(ecd); - - } - - } - } - } - - public static A3Vector getCellCentreLArForJet(int j) { - float xsum = 0.0f; - float ysum = 0.0f; - float zsum = 0.0f; - int count = 0; - AEvent ev = AEventManager.instance().getCurrentEvent(); - AJetData jd = ev.getJetData(); - String assockey = jd.getFullName(); - int[][] assoc = ev.getAssociationManager().get(assockey, "LAr"); - int[] dl = new int[assoc[j].length]; - ALArData calo = ev.getLArData(); - for (int i = 0; i < assoc[j].length; i++) { - int index = calo.getIndexFromId(assoc[j][i]); - float eta = (float) (calo.getEta(index)); - - float theta = (float) (2.0f * Math.atan(Math.exp(-eta))); - - float phi = (float) (calo.getPhi(index)); - - float rmin = (float) calo.getDetector(index).getRMin(); - float rmax = (float) calo.getDetector(index).getRMax(); - float r = 0.5f * (rmin + rmax); - - xsum += (float) (r * Math.cos(phi)); - ysum += (float) (r * Math.sin(phi)); - zsum += (float) (r / Math.tan(theta)); - count++; - } - - - - return new A3Vector(xsum / count, ysum / count, zsum / count); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/ANTestWindow.java b/graphics/AtlantisJava/src/atlantis/nge/ANTestWindow.java deleted file mode 100644 index f4340ca844e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/ANTestWindow.java +++ /dev/null @@ -1,119 +0,0 @@ -package atlantis.nge; - -import com.sun.opengl.util.Screenshot; -import java.awt.Graphics; -import java.awt.image.BufferedImage; -import java.util.Random; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLPbuffer; -import javax.swing.JComponent; -import javax.swing.JFrame; - -/** - * The ubiquitous test window class... - * - * @author Adam Davison - */ -public class ANTestWindow implements GLEventListener { - - private Random m_r = new Random(); - - private int m_h = 400; - private int m_w = 400; - - private JFrame m_f; - private BufferedImage m_img; - - private ANFrameManager m_fm; - - private GLPbuffer m_context; - - public ANTestWindow() { - m_f = new JFrame("Happy Time!"); - m_f.setBounds(100, 100, m_w, m_h); - - TestComponent tc = new TestComponent(this); - - m_f.add(tc); - - GLCapabilities pbcap = new GLCapabilities(); - pbcap.setSampleBuffers(true); - pbcap.setNumSamples(4); - //pbcap.setPbufferRenderToTexture(true); - //pbcap.setDoubleBuffered(false); - m_context = GLDrawableFactory.getFactory().createGLPbuffer(pbcap, null, m_w, m_h, null); - m_context.addGLEventListener(this); - - m_fm = new ANFrameManager(null); - - m_f.setVisible(true); - - //(new Thread(new TimingThread(tc))).start(); - } - - public void causeRepaint(Graphics g) { - m_context.display(); - g.drawImage(m_img, 0, 0, null); - } - - public void init(GLAutoDrawable arg0) { - } - - public void display(GLAutoDrawable arg0) { - //m_fm.display(arg0); - m_img = Screenshot.readToBufferedImage(m_w, m_h); - } - - public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { - } - - public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { - throw new UnsupportedOperationException("Not supported yet."); - } - -} - -class TestComponent extends JComponent { - private ANTestWindow m_parent; - - public TestComponent(ANTestWindow parent) { - m_parent = parent; - } - - @Override - protected void paintComponent(Graphics g) { - m_parent.causeRepaint(g); - } - -} - -class TimingThread implements Runnable { - private JComponent m_parent; - - private long m_sum; - private int m_count; - - public TimingThread(JComponent parent) { - m_parent = parent; - } - - public void run() { - m_sum = 0; - m_count = 0; - try { - Thread.sleep(5000); - } catch (Exception e) {} - for (int i = 0; i < 100; i++) { - long before = System.nanoTime(); - m_parent.paintImmediately(0, 0, m_parent.getWidth(), m_parent.getHeight()); - long after = System.nanoTime(); - m_sum += after - before; - m_count++; - } - System.out.println("Mean time: " + m_sum/m_count + "ns"); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/ANObject.java b/graphics/AtlantisJava/src/atlantis/nge/object/ANObject.java deleted file mode 100644 index 944c3c461b9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/ANObject.java +++ /dev/null @@ -1,27 +0,0 @@ -package atlantis.nge.object; - -import atlantis.nge.*; - -/** - * An ANObject is the superclass of anything which knows how to draw itself - * using an ANRenderer - * - * Specifically these will tend to represent some kind of visual onscreen - * element and will contain all the information required to draw the - * representation - * - * @author Adam Davison - */ -public abstract class ANObject { - - public abstract void render(ANRenderer r, ANRenderHints hint); - - private ANPickHandler m_ph = null; - protected void setPickHandler(ANPickHandler ph) { - m_ph = ph; - } - - public ANPickHandler getPickHandler() { - return m_ph; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectList.java b/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectList.java deleted file mode 100644 index 7e79f7f10e5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectList.java +++ /dev/null @@ -1,30 +0,0 @@ -package atlantis.nge.object; - -import atlantis.nge.ANRenderHints; -import atlantis.nge.ANRenderer; -import java.util.ArrayList; - -/** - * A composite object, of course these can be nested to make trees of objects - * - * @author Adam Davison - */ -public class ANObjectList extends ANObject { - - private ArrayList<ANObject> m_list; - - public ANObjectList() { - m_list = new ArrayList<ANObject>(); - } - - public void addObject(ANObject o) { - m_list.add(o); - } - - public void render(ANRenderer r, ANRenderHints hint) { - for (int i = 0; i < m_list.size(); i++) { - m_list.get(i).render(r, hint); - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectTestAxes.java b/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectTestAxes.java deleted file mode 100644 index c32ad4e2fec..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectTestAxes.java +++ /dev/null @@ -1,44 +0,0 @@ -package atlantis.nge.object; - -import atlantis.nge.*; -import javax.media.opengl.GL; - -/** - * A simple test object - * - * @author Adam Davison, Mark Stockton - */ -public class ANObjectTestAxes extends ANObject { - - public ANObjectTestAxes() { - - } - - @Override - public void render(ANRenderer r, ANRenderHints hint) { - - r.lineWidth(2.0f); - - // x - r.color3f(1.0f, 0.0f, 0.0f); - r.begin(GL.GL_LINES); - r.vertex3f(0.0f, 0.0f, 0.0f); - r.vertex3f(1500.0f, 0.0f, 0.0f); - r.end(); - - // y - r.color3f(0.0f, 1.0f, 0.0f); - r.begin(GL.GL_LINES); - r.vertex3f(0.0f, 0.0f, 0.0f); - r.vertex3f(0.0f, 1500.0f, 0.0f); - r.end(); - - // z - r.color3f(0.0f, 0.0f, 1.0f); - r.begin(GL.GL_LINES); - r.vertex3f(0.0f, 0.0f, 0.0f); - r.vertex3f(0.0f, 0.0f, 1500.0f); - r.end(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectVL.java b/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectVL.java deleted file mode 100644 index 091ac5ffb58..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/ANObjectVL.java +++ /dev/null @@ -1,66 +0,0 @@ -package atlantis.nge.object; - -import atlantis.nge.*; - -/** - * An object which draws from a vertex list - * - * @author Adam Davison - */ -public abstract class ANObjectVL extends ANObject { - - public abstract float[][] getVertices(); - - public abstract int[] getPrimTypes(); - - // What the hell is this? - public final int DRAW_LINE=-9; - - public ANColor getColor(int i) { - return new ANColor(1.0f, 0.0f, 0.0f, 1.0f); - } - - /** - * This function is like the software equivalent of just dumping a block - * of vertex information in GL 3.1... - * @param r - * @param hint - */ - @Override - public void render(ANRenderer r, ANRenderHints hint) { - r.lineWidth(1.5f); - - int pid = -1; - ANPickHelper ph = null; - if (hint.getPick()) { - ph = hint.getPickHelper(); - pid = ph.getIndex(this); - } - - int[] pt = getPrimTypes(); - float[][] v = getVertices(); - - if (pt == null) { - return; - } - - for (int i = 0; i < pt.length; i++) { - if (hint.getPick()) { - ph.startPick(pid, i); - } - - ANColor c = getColor(i); - r.color4f(c.r, c.g, c.b, c.a); - r.begin(pt[i]); - for (int j = 0; j < v[i].length; j+=3) { - r.vertex3f(v[i][j], v[i][j+1], v[i][j+2]); - } - r.end(); - - if (hint.getPick()) { - ph.endPick(); - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataCell.java b/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataCell.java deleted file mode 100644 index 410ea527370..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataCell.java +++ /dev/null @@ -1,170 +0,0 @@ -package atlantis.nge.object.data; - -import atlantis.nge.object.*; -import atlantis.nge.*; -import atlantis.data.ACalorimeterData; -import atlantis.geometry.AEndcapCalorimeterDetector; -import atlantis.utils.AMath; - -import javax.media.opengl.GL; - -/** - * Object that draws cells - * - * @author Adam Davison, Mark Stockton - */ -public class ANObjectDataCell extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - private int[] m_color; - - public ANObjectDataCell() { - } - - public ANObjectDataCell(ACalorimeterData ald) { - - m_pt = new int[ald.getNumDraw()]; - m_v = new float[ald.getNumDraw()][]; - m_color = new int[ald.getNumDraw()]; - - for (int j = 0; j < ald.getNumDraw(); j++) { - int i = ald.getDrawIndex(j); - - m_pt[j] = GL.GL_TRIANGLE_STRIP; - m_color[j] = ald.getColor(i); - m_v[j] = getVert(ald, i); - - } - } - - public ANObjectDataCell(ACalorimeterData ald, int dl[]) { - - m_pt = new int[dl.length]; - m_v = new float[dl.length][]; - m_color = new int[dl.length]; - - for (int j = 0; j < dl.length; j++) { - int i = dl[j]; - - m_pt[j] = GL.GL_TRIANGLE_STRIP; - m_color[j] = ald.getColor(i); - m_v[j] = getVert(ald, i); - - } - } - - // This logic should be in ANObjectGenerator - public ANObjectDataCell(ACalorimeterData ald, float phi, float eta, float dr) { - - int num = 0; - for (int j = 0; j < ald.getNumDraw(); j++) { - int i = ald.getDrawIndex(j); - if (AMath.deltaR(phi, eta, (float) ald.getPhi(i), (float) ald.getEta(i)) < dr) { - num++; - } - } - - m_pt = new int[num]; - m_v = new float[num][]; - m_color = new int[num]; - num = 0; - for (int j = 0; j < ald.getNumDraw(); j++) { - int i = ald.getDrawIndex(j); - if (AMath.deltaR(phi, eta, (float) ald.getPhi(i), (float) ald.getEta(i)) > dr) { - continue; - } - m_pt[num] = GL.GL_TRIANGLE_STRIP; - m_color[num] = ald.getColor(i); - m_v[num] = getVert(ald, i); - num++; - - } - } - - private float[] getVert(ACalorimeterData ald, int index) { - - float etamin = (float) (ald.getEta(index) - ald.getdEta(index)); - float etamax = (float) (ald.getEta(index) + ald.getdEta(index)); - - float thetamin = (float) (2.0f * Math.atan(Math.exp(-etamin))); - float thetamax = (float) (2.0f * Math.atan(Math.exp(-etamax))); - - float phimin = (float) (ald.getPhi(index) - ald.getdPhi(index)); - float phimax = (float) (ald.getPhi(index) + ald.getdPhi(index)); - - float rmin = (float) ald.getDetector(index).getRMin(); - float rmax = (float) ald.getDetector(index).getRMax(); - - // TODO: Push this up to the getZ??? functions in this detector - // class. - if (ald.getDetector(index) instanceof AEndcapCalorimeterDetector) { - //correction taken from AEndcapCalorimeterDetector - String name = ald.getDetector(index).getName(); - float zmin = (float) (ald.getDetector(index).getZMin()); - //This shouldn't be 0, but just to be on the safe side. - int side = ald.getSide(index); - if (side != 0) { - side /= Math.abs(side); - } - zmin *= side; - if (name.indexOf("Inner") >= 0 || name.indexOf("Outer") >= 0 || name.indexOf("Presampler") >= 0) { - rmax = (float) (zmin / Math.sinh(etamin)); - } - rmin = (float) (zmin / Math.sinh(etamax)); - } - - float[][] v = new float[8][3]; - - fillVert(v[0], rmin, thetamin, phimin); - fillVert(v[1], rmin, thetamax, phimin); - fillVert(v[2], rmax, thetamax, phimin); - fillVert(v[3], rmax, thetamin, phimin); - fillVert(v[4], rmin, thetamin, phimax); - fillVert(v[5], rmin, thetamax, phimax); - fillVert(v[6], rmax, thetamax, phimax); - fillVert(v[7], rmax, thetamin, phimax); - - float[] vert = new float[3 * 14]; - int[] wind = {6, 5, 7, 4, 0, 5, 1, 2, 0, 3, 7, 2, 6, 5}; - for (int i = 0; i < 14; i++) { - copyVert(v[wind[i]], vert, i); - } - - return vert; - } - - private void copyVert(float[] v, float[] t, int ti) { - t[(ti * 3) + 0] = v[0]; - t[(ti * 3) + 1] = v[1]; - t[(ti * 3) + 2] = v[2]; - - } - - private void fillVert(float[] v, float r, float theta, float phi) { - - v[0] = (float) (r * Math.cos(phi)); - v[1] = (float) (r * Math.sin(phi)); - v[2] = (float) (r / Math.tan(theta)); - } - - @Override - public float[][] getVertices() { - return m_v; - } - - @Override - public int[] getPrimTypes() { - return m_pt; - } - - @Override - public ANColor getColor(int i) { - - if (m_color[i] == DRAW_LINE) { - return new ANColor(0.0f, 0.0f, 0.0f, 1.0f); - } else { - return ANColor.getMapColor(m_color[i]); - } - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataJet.java b/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataJet.java deleted file mode 100644 index f97774fe95f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectDataJet.java +++ /dev/null @@ -1,146 +0,0 @@ -package atlantis.nge.object.data; - -import atlantis.nge.object.*; -import atlantis.nge.*; -import atlantis.data.AJetData; -import atlantis.utils.AMath; - -import javax.media.opengl.GL; - -/** - * Object that draws geometry of the muon system - * - * @author Adam Davison, Mark Stockton - */ -public class ANObjectDataJet extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - private int[] m_color; - - public ANObjectDataJet() { - - } - -public ANObjectDataJet(AJetData ajd) { - - - m_pt = new int[2*ajd.getNumDraw()]; - m_v = new float[2*ajd.getNumDraw()][]; - m_color = new int[2*ajd.getNumDraw()]; - - for (int j = 0; j < ajd.getNumDraw(); j++) { - int i= ajd.getDrawIndex(j); - float theta = (float) (2.0f * Math.atan(Math.exp(-ajd.getEta(i)))); - - m_pt[2*j] = GL.GL_TRIANGLE_FAN; - //m_v[2*j] = getCone(ajd.getET(i), ajd.getPhi(i), theta); - m_v[2*j] = getCone(1300.0f, ajd.getPhi(i), theta); - m_color[2*j]=ajd.getColor(i); - m_pt[2*j+1] = GL.GL_LINES; - //m_v[2*i+1] = getCore(ajd.getET(i), ajd.getPhi(i), theta); - m_v[2*j+1] = getCore(1300.0f, ajd.getPhi(i), theta); - m_color[2*j+1]=DRAW_LINE; - } - } - - public ANObjectDataJet(AJetData ajd, float phi, float eta, float dr) { - - int num=0; - for (int j = 0; j < ajd.getNumDraw(); j++) { - int i= ajd.getDrawIndex(j); - if(AMath.deltaR(phi,eta,(float)ajd.getPhi(i),(float)ajd.getEta(i))<dr){ - num++; - } - } - - m_pt = new int[2*num]; - m_v = new float[2*num][]; - m_color = new int[2*num]; - num=0; - for (int j = 0; j < ajd.getNumDraw(); j++) { - int i= ajd.getDrawIndex(j); - if(AMath.deltaR(phi,eta,(float)ajd.getPhi(i),(float)ajd.getEta(i))>dr) - continue; - float theta = (float) (2.0f * Math.atan(Math.exp(-ajd.getEta(i)))); - - m_pt[2*num] = GL.GL_TRIANGLE_FAN; - //m_v[2*num] = getCone(ajd.getET(i), ajd.getPhi(i), theta); - m_v[2*num] = getCone(1300.0f, ajd.getPhi(i), theta); - m_color[2*num]=ajd.getColor(i); - m_pt[2*num+1] = GL.GL_LINES; - //m_v[2*num+1] = getCore(ajd.getET(i), ajd.getPhi(i), theta); - m_v[2*num+1] = getCore(1300.0f, ajd.getPhi(i), theta); - m_color[2*num+1]=DRAW_LINE; - num++; - } - } - - - - private float[] getCore(float len, float phi, float theta){ - - // Jets are in detector eta so primary vertex set to 0 is sensible for now - float[] core = {0.0f, 0.0f, 0.0f, - (float) (len * Math.cos(phi) * Math.sin(theta)), - (float) (len * Math.sin(phi) * Math.sin(theta)), - (float) (len * Math.cos(theta)) - }; - return core; - } - - private float[] getCone(float len, float phi, float theta){ - int segs = 8; - - float[] cone = new float[3 * (2 + segs)]; - cone[0] = 0.0f; - cone[1] = 0.0f; - cone[2] = 0.0f; - - //temporary jet radius - float jetr = 100.0f; - - for (int i = 0; i < segs; i++) { - float lphi = (float) (i * 2.0f * Math.PI / segs); - float ax = (float) (jetr * Math.cos(lphi)); - float ay = (float) (jetr * Math.sin(lphi)); - float az = len; - - float bx = (float) (ax * Math.cos(phi) * Math.cos(theta) + - az * Math.sin(theta) * Math.cos(phi) - ay * Math.sin(phi)); - float by = (float) (ax * Math.cos(theta) * Math.sin(phi) + - az * Math.sin(theta) * Math.sin(phi) + ay * Math.cos(phi)); - float bz = (float) (-ax * Math.sin(theta) + az * Math.cos(theta)); - - cone[i*3+3] = bx; - cone[i*3+4] = by; - cone[i*3+5] = bz; - } - - cone[(3*(2+segs)) - 3] = cone[3]; - cone[(3*(2+segs)) - 2] = cone[4]; - cone[(3*(2+segs)) - 1] = cone[5]; - - return cone; - } - - @Override - public float[][] getVertices() { - return m_v; - } - - @Override - public int[] getPrimTypes() { - return m_pt; - } - - @Override - public ANColor getColor(int i) { - - if(m_color[i]==DRAW_LINE) - return new ANColor(0.0f, 0.0f, 0.0f, 1.0f); - else - return ANColor.getMapColor(m_color[i], 0.5f); - - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectPointing.java b/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectPointing.java deleted file mode 100644 index 2fddcee1d37..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectPointing.java +++ /dev/null @@ -1,147 +0,0 @@ -package atlantis.nge.object.data; - -import atlantis.data.ACalorimeterData; -import atlantis.data.ATILEData; -import atlantis.geometry.AEndcapCalorimeterDetector; -import atlantis.nge.ANColor; -import atlantis.nge.object.ANObjectVL; -import atlantis.utils.AMath; -import javax.media.opengl.GL; - -/** - * - * @author Adam Davison - */ -public class ANObjectPointing extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - private ANColor[] m_c; - - public ANObjectPointing(ACalorimeterData ald, int dl[], int dllen, boolean outline) { - m_pt = new int[dllen]; - m_v = new float[dllen][]; - m_c = new ANColor[dllen]; - - double[] area = new double[dl.length]; - for (int i = 0; i < dllen; i++) { - area[i] = 1.0; - } - - ald.calibrateLocalDensity(dl, area); - double[] scale = ald.getScaleFactors(dl, area); - - if (outline) { - for (int j = 0; j < dllen; j++) { - int i = dl[j]; - m_pt[j] = GL.GL_LINES; - m_c[j] = ANColor.getMapColor(ald.getColor(i)); - m_c[j].mult(0.5f); - m_v[j] = getVert(ald, i, (float)scale[j], true); - //m_v[j] = getVert(ald, i, 1.0f, true); - } - } else { - - for (int j = 0; j < dllen; j++) { - int i = dl[j]; - m_pt[j] = GL.GL_TRIANGLE_STRIP; - m_c[j] = ANColor.getMapColor(ald.getColor(i)); - m_v[j] = getVert(ald, i, (float)scale[j], false); - } - } - - } - - @Override - public float[][] getVertices() { - return m_v; - } - - @Override - public int[] getPrimTypes() { - return m_pt; - } - - @Override - public ANColor getColor(int i) { - return m_c[i]; - } - - private float[] getVert(ACalorimeterData ald, int index, float scale, boolean outline) { - - // Possibly should apply scale to theta not eta? - float etamin = (float) (ald.getEta(index) - 0.5f*scale*ald.getdEta(index)); - float etamax = (float) (ald.getEta(index) + 0.5f*scale*ald.getdEta(index)); - - float thetamin = (float) (2.0f * Math.atan(Math.exp(-etamin))); - float thetamax = (float) (2.0f * Math.atan(Math.exp(-etamax))); - - float phimin = (float) (ald.getPhi(index) - 0.5f*scale*ald.getdPhi(index)); - float phimax = (float) (ald.getPhi(index) + 0.5f*scale*ald.getdPhi(index)); - - float rmin = (float) ald.getDetector(index).getRMin(); - float rmax = (float) ald.getDetector(index).getRMax(); - float dr = 0.5f*(rmax - rmin); - rmin += (1.0f - scale)*dr; - rmax -= (1.0f - scale)*dr; - - // TODO: Push this up to the getZ??? functions in this detector - // class. - if (ald.getDetector(index) instanceof AEndcapCalorimeterDetector) { - //correction taken from AEndcapCalorimeterDetector - String name = ald.getDetector(index).getName(); - float zmin = (float) (ald.getDetector(index).getZMin()); - //This shouldn't be 0, but just to be on the safe side. - int side = ald.getSide(index); - if (side != 0) { - side /= Math.abs(side); - } - zmin *= side; - if (name.indexOf("Inner") >= 0 || name.indexOf("Outer") >= 0 || name.indexOf("Presampler") >= 0) { - rmax = (float) (zmin / Math.sinh(etamin)); - } - rmin = (float) (zmin / Math.sinh(etamax)); - } - - float[][] v = new float[8][3]; - - fillVert(v[0], rmin, thetamin, phimin); - fillVert(v[1], rmin, thetamax, phimin); - fillVert(v[2], rmax, thetamax, phimin); - fillVert(v[3], rmax, thetamin, phimin); - fillVert(v[4], rmin, thetamin, phimax); - fillVert(v[5], rmin, thetamax, phimax); - fillVert(v[6], rmax, thetamax, phimax); - fillVert(v[7], rmax, thetamin, phimax); - - int[] wind = null; - if (!outline) { - int[] inwind = {6, 5, 7, 4, 0, 5, 1, 2, 0, 3, 7, 2, 6, 5}; - wind = inwind; - } else { - int[] outwind = {0, 3, 0, 1, 0, 4, 2, 1, 2, 3, 2, 6, - 7, 4, 7, 6, 7, 3, 5, 6, 5, 4, 5, 1}; - wind = outwind; - } - float[] vert = new float[3 * wind.length]; - for (int i = 0; i < wind.length; i++) { - copyVert(v[wind[i]], vert, i); - } - - return vert; - } - - private void copyVert(float[] v, float[] t, int ti) { - t[(ti * 3) + 0] = v[0]; - t[(ti * 3) + 1] = v[1]; - t[(ti * 3) + 2] = v[2]; - - } - - private void fillVert(float[] v, float r, float theta, float phi) { - - v[0] = (float) (r * Math.cos(phi)); - v[1] = (float) (r * Math.sin(phi)); - v[2] = (float) (r / Math.tan(theta)); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectTracks.java b/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectTracks.java deleted file mode 100644 index f8599c1f12a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/data/ANObjectTracks.java +++ /dev/null @@ -1,82 +0,0 @@ -package atlantis.nge.object.data; - -import atlantis.data.ALArData; -import atlantis.data.ATrackData; -import atlantis.nge.ANColor; -import atlantis.nge.object.ANObjectVL; -import javax.media.opengl.GL; - -/** - * - * @author Adam Davison - */ -public class ANObjectTracks extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - private int[] m_color; - - public ANObjectTracks(ATrackData td) { - float[][] x = td.getX(); - float[][] y = td.getY(); - float[][] z = td.getZ(); - - m_pt = new int[x.length]; - m_v = new float[x.length][]; - m_color = new int[x.length]; - - for (int i = 0; i < x.length; i++) { - m_pt[i] = GL.GL_LINE_STRIP; - m_v[i] = new float[x[i].length * 3]; - m_color[i] = td.getColor(i); - for (int p = 0; p < x[i].length; p++) { - m_v[i][p * 3] = x[i][p]; - m_v[i][p * 3 + 1] = y[i][p]; - m_v[i][p * 3 + 2] = z[i][p]; - } - } - } - - public ANObjectTracks(ATrackData td, int[] dl) { - float[][] x = td.getX(); - if (x == null) { - System.out.println("ARGH!!"); - m_pt = null; - m_v = null; - m_color = null; - return; - } - float[][] y = td.getY(); - float[][] z = td.getZ(); - - m_pt = new int[dl.length]; - m_v = new float[dl.length][]; - m_color = new int[dl.length]; - - for (int i = 0; i < dl.length; i++) { - m_pt[i] = GL.GL_LINE_STRIP; - int index = td.getIndexFromId(dl[i]); - m_v[i] = new float[x[index].length * 3]; - m_color[i] = td.getColor(index); - for (int p = 0; p < x[index].length; p++) { - m_v[i][p * 3] = x[index][p]; - m_v[i][p * 3 + 1] = y[index][p]; - m_v[i][p * 3 + 2] = z[index][p]; - } - } - } - - @Override - public float[][] getVertices() { - return m_v; - } - - @Override - public int[] getPrimTypes() { - return m_pt; - } - - public ANColor getColor(int i) { - return ANColor.getMapColor(m_color[i]); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectBeamLine.java b/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectBeamLine.java deleted file mode 100644 index ad9d7da77b4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectBeamLine.java +++ /dev/null @@ -1,21 +0,0 @@ -package atlantis.nge.object.geometry; - -import atlantis.nge.object.ANObjectVL; - -/** - * - * @author Adam Davison - */ -public class ANObjectBeamLine extends ANObjectVL { - - @Override - public float[][] getVertices() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int[] getPrimTypes() { - throw new UnsupportedOperationException("Not supported yet."); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomCalo.java b/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomCalo.java deleted file mode 100644 index 5705182ecc6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomCalo.java +++ /dev/null @@ -1,159 +0,0 @@ -package atlantis.nge.object.geometry; - -import atlantis.nge.object.*; -import atlantis.nge.*; -import atlantis.geometry.ACalorimeterDetector; - -import java.util.ArrayList; -import javax.media.opengl.GL; - -/** - * Object that draws geometry of the muon system - * - * @author Adam Davison, Mark Stockton - */ -public class ANObjectGeomCalo extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - - private int[] m_color; - - public ANObjectGeomCalo(ArrayList<ACalorimeterDetector> m_calo, int nv_scale, boolean duplicate) { - - m_pt = new int[7*m_calo.size()]; - m_v = new float[7*m_calo.size()][]; - m_color = new int[7*m_calo.size()]; - - //all endcaps and extended tile only has one end in geom file and not relicated like others - for (int j = 0; j < m_calo.size(); j++) { - int i=7*j; - ACalorimeterDetector cd = m_calo.get(j); - m_pt[i]=GL.GL_TRIANGLE_STRIP; - m_pt[i+1]=GL.GL_TRIANGLE_STRIP; - m_pt[i+2]=GL.GL_TRIANGLE_STRIP; - m_pt[i+3]=GL.GL_LINE_LOOP; - m_pt[i+4]=GL.GL_LINE_LOOP; - m_pt[i+5]=GL.GL_LINE_LOOP; - m_pt[i+6]=GL.GL_LINE_LOOP; - m_color[i]=cd.getFillColor(); - m_color[i+1]=cd.getFillColor(); - m_color[i+2]=cd.getFillColor(); - m_color[i+3]=DRAW_LINE; - m_color[i+4]=DRAW_LINE; - m_color[i+5]=DRAW_LINE; - m_color[i+6]=DRAW_LINE; - - float zMin=(float) cd.getZMin(); - float zMax=(float) cd.getZMax(); - if(duplicate){ - zMin*=-1.; - zMax*=-1.; - } - m_v[i] = getEndTris(zMin, (float) cd.getRMin(), (float) cd.getRMax(), cd.getNumPhi() / nv_scale); - m_v[i+1] = getEndTris(zMax, (float) cd.getRMin(), (float) cd.getRMax(), cd.getNumPhi() / nv_scale); - m_v[i+2] = getBarrelTris(zMin, zMax, (float) cd.getRMin(), (float) cd.getRMax(), cd.getNumPhi() / nv_scale); - m_v[i+3] = getEdges(zMin, (float) cd.getRMin(), cd.getNumPhi() / nv_scale, true); - m_v[i+4] = getEdges(zMax, (float) cd.getRMin(), cd.getNumPhi() / nv_scale, true); - m_v[i+5] = getEdges(zMin, (float) cd.getRMax(), cd.getNumPhi() / nv_scale, false); - m_v[i+6] = getEdges(zMax, (float) cd.getRMax(), cd.getNumPhi() / nv_scale, false); - } - } - - - private float[] getEdges(float z, float r, int nv, boolean inner) { - float[] v = new float[3 * nv]; - - float dphi = (2 * (float) Math.PI) / nv; - float hdphi = 0.5f * dphi; - //if (inner) { hdphi = 0.0f; } - - for (int i = 0; i < nv; i++) { - int ie = i * 3; - v[ie] = r * (float) Math.cos(i * dphi + hdphi); - v[ie + 1] = r * (float) Math.sin(i * dphi + hdphi); - v[ie + 2] = (float) z; - } - - return v; - } - - private float[] getBarrelTris(float zmin, float zmax, float rmin, float rmax, int nv) { - float[] v = new float[3 * (nv * 2 + 2)]; - - float dphi = (2 * (float) Math.PI) / nv; - float hdphi = 0.5f * dphi; - - float r = (float) rmax; - - for (int i = 0; i < nv; i++) { - int ie = i * 2 * 3; - int oe = (i * 2 + 1) * 3; - v[ie] = r * (float) Math.cos(i * dphi + hdphi); - v[ie + 1] = r * (float) Math.sin(i * dphi + hdphi); - v[ie + 2] = (float) zmin; - v[oe] = r * (float) Math.cos(i * dphi + hdphi); - v[oe + 1] = r * (float) Math.sin(i * dphi + hdphi); - v[oe + 2] = (float) zmax; - } - - // Close the strip - for (int i = 0; i < 6; i++) { - v[i + v.length - 6] = v[i]; - } - - return v; - } - - private float[] getEndTris(float z, float rmin, float rmax, int nv) { - float[] v = new float[3 * (nv * 2 + 2)]; - - float dphi = (2 * (float) Math.PI) / nv; - float hdphi = 0.5f * dphi; - - for (int i = 0; i < nv; i++) { - int ie = i * 2 * 3; - int oe = (i * 2 + 1) * 3; - v[ie] = (float) rmin * (float) Math.cos(i * dphi); - v[ie + 1] = (float) rmin * (float) Math.sin(i * dphi); - v[ie + 2] = z; - v[oe] = (float) rmax * (float) Math.cos(i * dphi + hdphi); - v[oe + 1] = (float) rmax * (float) Math.sin(i * dphi + hdphi); - v[oe + 2] = z; - } - - // Close the strip - for (int i = 0; i < 6; i++) { - v[i + v.length - 6] = v[i]; - } - - return v; - } - - - - public ANObjectGeomCalo() { - - } - - @Override - public int[] getPrimTypes() - { - return m_pt; - } - - @Override - public float[][] getVertices() - { - return m_v; - } - - @Override - public ANColor getColor(int i) { - - if(m_color[i]==DRAW_LINE) - return new ANColor(0.0f, 0.0f, 0.0f, 1.0f); - else - return ANColor.getMapColor(m_color[i], 1.0f); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomMuon.java b/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomMuon.java deleted file mode 100644 index dd115cb360a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/nge/object/geometry/ANObjectGeomMuon.java +++ /dev/null @@ -1,229 +0,0 @@ -package atlantis.nge.object.geometry; - -import atlantis.nge.object.*; -import atlantis.nge.*; -import atlantis.geometry.ABoxDetector; -import java.util.ArrayList; -import javax.media.opengl.GL; - -/** - * Object that draws geometry of the muon system - * - * @author Adam Davison, Mark Stockton - */ -public class ANObjectGeomMuon extends ANObjectVL { - - private float[][] m_v; - private int[] m_pt; - private int[] m_color; - - public ANObjectGeomMuon() { - setPickHandler(new ANPickHandlerSimple("Muon Spectrometer")); - } - - public ANObjectGeomMuon(ArrayList<ABoxDetector> m_boxes) { - setPickHandler(new ANPickHandlerSimple("Muon Spectrometer")); - - m_pt = new int[2*m_boxes.size()]; - m_v = new float[2*m_boxes.size()][]; - m_color = new int[2*m_boxes.size()]; - - for (int i = 0; i < m_boxes.size(); i++) { - ABoxDetector b = m_boxes.get(i); - m_pt[2*i] = GL.GL_TRIANGLE_STRIP; - m_v[2*i] = getBoxFaces((float)b.getZMin(), (float)b.getZMax(), - (float)b.getRMin(), (float)b.getRMax(), (float)b.getPhi(), - (float)b.getSize()); - m_color[2*i]=b.getFillColor(); - m_pt[2*i+1] = GL.GL_LINES; - m_v[2*i+1] = getBoxEdges((float)b.getZMin(), (float)b.getZMax(), - (float)b.getRMin(), (float)b.getRMax(), (float)b.getPhi(), - (float)b.getSize()); - m_color[2*i+1]=DRAW_LINE; - } - } - - // This code answers the question, how do you wrap a strip of 14 triangles - // to form a cube? - private float[] getBoxFaces(float zmin, float zmax, float rmin, float rmax, float phi, float w) { - float[] v = new float[3*14]; - - float sinPhi = (float)Math.sin(phi); - float cosPhi = (float)Math.cos(phi); - - float xmi = rmin*cosPhi; - float ymi = rmin*sinPhi; - float xmo = rmax*cosPhi; - float ymo = rmax*sinPhi; - float dx = -sinPhi*w/2.0f; - float dy = cosPhi*w/2.0f; - - v[0] = xmi + dx; - v[1] = ymi + dy; - v[2] = zmax; - - v[3] = xmi - dx; - v[4] = ymi - dy; - v[5] = zmax; - - v[6] = xmo + dx; - v[7] = ymo + dy; - v[8] = zmax; - - v[9] = xmo - dx; - v[10] = ymo - dy; - v[11] = zmax; - - v[12] = v[9]; - v[13] = v[10]; - v[14] = zmin; - - v[15] = v[3]; - v[16] = v[4]; - v[17] = v[5]; - - v[18] = v[3]; - v[19] = v[4]; - v[20] = zmin; - - v[21] = v[0]; - v[22] = v[1]; - v[23] = zmin; - - v[24] = v[12]; - v[25] = v[13]; - v[26] = v[14]; - - v[27] = v[6]; - v[28] = v[7]; - v[29] = zmin; - - v[30] = v[6]; - v[31] = v[7]; - v[32] = v[8]; - - v[33] = v[21]; - v[34] = v[22]; - v[35] = v[23]; - - v[36] = v[0]; - v[37] = v[1]; - v[38] = v[2]; - - v[39] = v[3]; - v[40] = v[4]; - v[41] = v[5]; - - return v; - } - - private float[] getBoxEdges(float zmin, float zmax, float rmin, float rmax, float phi, float w) { - float[] v = new float[3*12*2]; // 3d*12edges*2ends - - float sinPhi = (float)Math.sin(phi); - float cosPhi = (float)Math.cos(phi); - - float xmi = rmin*cosPhi; - float ymi = rmin*sinPhi; - float xmo = rmax*cosPhi; - float ymo = rmax*sinPhi; - float dx = -sinPhi*w/2.0f; - float dy = cosPhi*w/2.0f; - - v[0] = xmi + dx; - v[1] = ymi + dy; - v[2] = zmin; - - v[3] = xmi - dx; - v[4] = ymi - dy; - v[5] = zmin; - - v[6] = v[3]; - v[7] = v[4]; - v[8] = v[5]; - - v[9] = xmo - dx; - v[10] = ymo - dy; - v[11] = zmin; - - v[12] = v[9]; - v[13] = v[10]; - v[14] = v[11]; - - v[15] = xmo + dx; - v[16] = ymo + dy; - v[17] = zmin; - - v[18] = v[15]; - v[19] = v[16]; - v[20] = v[17]; - - v[21] = v[0]; - v[22] = v[1]; - v[23] = v[2]; - - for (int i = 24; i < 48; i++) { - if (i % 3 == 2) { - v[i] = zmax; - } else { - v[i] = v[i - 24]; - } - - } - - v[48] = v[0]; - v[49] = v[1]; - v[50] = v[2]; - - v[51] = v[0]; - v[52] = v[1]; - v[53] = zmax; - - v[54] = v[3]; - v[55] = v[4]; - v[56] = v[5]; - - v[57] = v[3]; - v[58] = v[4]; - v[59] = zmax; - - v[60] = v[9]; - v[61] = v[10]; - v[62] = v[11]; - - v[63] = v[9]; - v[64] = v[10]; - v[65] = zmax; - - v[66] = v[15]; - v[67] = v[16]; - v[68] = v[17]; - - v[69] = v[15]; - v[70] = v[16]; - v[71] = zmax; - - return v; - } - - @Override - public float[][] getVertices() { - return m_v; - } - - @Override - public int[] getPrimTypes() { - return m_pt; - } - - @Override - public ANColor getColor(int i) { - - if(m_color[i]==DRAW_LINE) - return new ANColor(0.0f, 0.0f, 0.0f, 1.0f); - else - return ANColor.getMapColor(m_color[i], 1.0f); - - } - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/output/AExceptionHandler.java b/graphics/AtlantisJava/src/atlantis/output/AExceptionHandler.java deleted file mode 100755 index 7be2501d9e7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/output/AExceptionHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package atlantis.output; - -import javax.swing.JOptionPane; - -import atlantis.globals.AGlobals; - -/** - * Handles an exception thrown in the AWT event-dispatch thread. If the system - * property "sun.awt.exception.handler" is defined then when an exception occurs - * in the AWT event-dispatch thread, the thread wii do the following: 1) Load - * the class named by the value of that property, using the current thread's - * context class loader, 2) Instantiate that class using its zero-argument - * constructor, 3) Find the resulting handler object's "public void handle" - * method, which should take a single argument of type "Throwable", and 4) - * Invoke the handler's "handle" method, passing it the exception as an - * argument. - * - * Note: The magic "sun.awt.exception.handler" property will be - * removed in a future release. - * - * Comment: No wonder - centrally handling all exceptions is not a good idea - * in the first place (S.B.) - */ - -public class AExceptionHandler { - private static final AGlobals globals = AGlobals.instance(); - - public void handle(Throwable exception) - { - processException("AWT Event Dispatch Thread Exception:", exception); - } - - public static void processException(String message, Throwable exception) - { - exception.printStackTrace(); - showMessageDialog(message); - } - - public static void processException(String type, String message) - { - - if (type.equals("fatal")){ - showMessageDialog(type + ": " + message + "\n"); - System.exit(1); - } - AOutput.append(type + ": " + message + "\n", ALogInterface.BAD_COMMAND); - } - - private static void showMessageDialog(String message) - { - //Do not show messages in headless mode - if(AGlobals.isAtlantisHeadless()) return; - - //Do not show messages in demo mode - if (AGlobals.instance().isDemoMode()) return; - - //Else show a message box with the exception - JOptionPane.showMessageDialog(globals.getGuiFrame(), message, "Atlantis", JOptionPane.ERROR_MESSAGE); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/output/ALogInterface.java b/graphics/AtlantisJava/src/atlantis/output/ALogInterface.java deleted file mode 100644 index 3a3f416a71f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/output/ALogInterface.java +++ /dev/null @@ -1,25 +0,0 @@ -package atlantis.output; - -/** - * Non-GUI-dependent interface for ALogPane. - * - * @author waugh - * - */ -public interface ALogInterface { - - public static final String TITLE = "TITLE"; - public static final String NORMAL = "NORMAL"; - public static final String NORMAL_BOLD = "NORMAL_BOLD"; - public static final String COMMAND = "COMMAND"; - public static final String BAD_COMMAND = "BAD_COMMAND"; - public static final String PICK = "PICK"; - public static final String WARNING = "WARNING"; - - void append(String s); - - void append(String s, String style); - - void clear(); - -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/output/AOutput.java b/graphics/AtlantisJava/src/atlantis/output/AOutput.java deleted file mode 100755 index 4f5285cb5a5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/output/AOutput.java +++ /dev/null @@ -1,54 +0,0 @@ -package atlantis.output; - -import atlantis.globals.AGlobals; -import atlantis.utils.ALogger; - -/** - * AOutput provides access to the specific static instance of AMainLogPane which - * is used for displaying general information within Atlantis - * @author Adam Davison - */ -public class AOutput -{ - //Handle to the main log pane - private static ALogInterface outputPane; - - /** Logger for when not outputting to the GUI (Minerva). */ - private final static ALogger logger = ALogger.getLogger(AOutput.class); - - /** Append text to output pane/logger depending on output level. */ - public static void append(String s, String style) { - if (outputPane==null) return; // in case not set yet, or no GUI - if(AGlobals.instance().getSimpleOutput()>0){ - if (style.equals(ALogInterface.BAD_COMMAND) || style.equals(ALogInterface.WARNING)) { - logger.warn(s); - }else{ - logger.info(s); - } - }else{ - outputPane.append(s, style); - } - } - - /** Append text to output pane - only for pick info (and select event/debug info). */ - public static void alwaysAppend(String s, String style) { - if (outputPane==null) return; // in case not set yet, or no GUI - outputPane.append(s, style); - } - - /** - * Provide interface to the log pane in the GUI. - * @param outputDisplay the log pane - */ - public static void setOutput(ALogInterface outputDisplay) { - AOutput.outputPane = outputDisplay; - } - - /** - * Get interface to the log pane in the GUI, if any. - * @param outputDisplay the log pane - */ - public static ALogInterface getOutput() { - return outputPane; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/package.html b/graphics/AtlantisJava/src/atlantis/package.html deleted file mode 100644 index 9d160b36ad3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head></head> -<body> - Root package of the Atlantis application. - Contains main class Atlantis, whose purpose is to parse the command line, - initialise the application's main components and provide access to them. -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AAbstractParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AAbstractParameter.java deleted file mode 100755 index 74401090c6e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AAbstractParameter.java +++ /dev/null @@ -1,913 +0,0 @@ -package atlantis.parameters; - -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPopupMenu; -import javax.swing.LookAndFeel; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.gui.ACheckBox; -import atlantis.gui.AParametersTable; -import atlantis.output.AExceptionHandler; -import atlantis.utils.AUtilities; - -/** - * The class is used as a default implementation of the AParameter interface. - * All parameters extend this class except ALinkParameter which implements - * AParameter directly. - */ -abstract class AAbstractParameter implements AParameter -{ - // range constants - protected final static int MIN = 0; - protected final static int MAX = 1; - protected final static int SVAL = 2; - - // unitsOf constants - protected final static int NOTHING = 0; - protected final static int LENGTH = 1; - protected final static int ENERGY = 2; - protected final static int ENERGYMEV = 3; - - /** - * List of listeners/observers to be informed of changes to parameters. - * Currently this is just the GUI, which repaints its tables when a parameter - * changes. - */ - private List<AParameterChangeListener> parameterChangeListeners = new ArrayList<AParameterChangeListener>(); - - /** The internal name of the parameter. */ - protected String name; - /** The name which is displayed in the user interface. */ - protected String screenName; - /** Tool tip, i.e. text that appears when mouse hovers over control. */ - protected String toolTip; - - protected boolean hasStatus; - protected int valueType; - protected int scope; - protected int defaultScope; - protected boolean isModulus; - protected int userLevel; - protected int unitsOf; - protected String[] operators; - /** Allowed values for this parameter: - * range[MIN][i] and range[MAX][i] are the limits of the i'th range; - * range[SVAL][j] is the j'th allowed single value. */ - protected double[][] range; - - private ACheckBox nameLabel; - private JLabel label; - private boolean isInitialized = false; - - /** The number of windows in the canvas. */ - protected int wCount = 0; // initialised later in constructor - - /** Contains the values for each window. */ - protected AParameterData data; - - @Override - public void addParameterChangeListener(AParameterChangeListener listener) { - parameterChangeListeners.add(listener); - } - - public AAbstractParameter(String name, String screenName, String toolTip, - int valueType, double value, String op, String dop, - boolean haseStatus, boolean status, boolean isMod, int userLevel, - int scope, int unitsOf) - { - // initialising wCount - // for running without Canvas (e.g. calling geometry methods from GraXML), - // this may run without Canvas initialised - // check if Canvas actually exists - // dependency of AAbstractParameter on ACanvas should be revised, this - // current solution is not very elegant - ACanvas canvas = ACanvas.getCanvas(); - this.wCount = canvas == null ? 0 : canvas.getWindowsCount(); - - this.isModulus = isMod; - this.unitsOf = unitsOf; - - if (!screenName.trim().equals("")) - this.screenName = screenName; - else - this.screenName = name; - - if (isMod) - this.screenName = "|" + this.screenName + "|"; - - // removing spaces from the parameter name - StringBuffer strBuffer = new StringBuffer(name); - int i = 0; - - while (i < strBuffer.length()) - { - if (Character.isWhitespace(strBuffer.charAt(i))) - strBuffer.deleteCharAt(i); - else - i++; - } - this.name = strBuffer.toString(); - - if ((toolTip == null) || (toolTip.trim().length() == 0)) - this.toolTip = this.screenName; - else - this.toolTip = toolTip; - - this.hasStatus = haseStatus; - this.valueType = valueType; - - // set up the local window copies - this.data = new AParameterData(wCount); - - for (i = 0; i < wCount; i++) - { - this.data.setValue(i, value); - this.data.setStatus(i, status); - } - - // decompose supportedOperators - if ((op == null) || (op.trim().equals(""))) - { - this.operators = new String[1]; - operators[0] = "="; - } - else - { - String[] tempOperators = new String[10]; - - int operatorsCount = 0; - StringTokenizer st = new StringTokenizer(op, ","); - - while (st.hasMoreTokens()) - { - String oper = st.nextToken().trim(); - - if (isKnownOperator(oper)) - { - tempOperators[operatorsCount] = oper; - operatorsCount++; - } - else - throw new Error("Unknown operator: " + oper); - } - - this.operators = new String[operatorsCount]; - for (i = 0; i < operatorsCount; i++) - this.operators[i] = tempOperators[i]; - } - - if ((dop == null) || (dop.trim().equals(""))) - for (i = 0; i < wCount; i++) - this.data.setOperator(i, operators[0]); - else - for (i = 0; i < wCount; i++) - this.data.setOperator(i, dop); - - this.userLevel = userLevel; - setScope(scope); - saveDefaults(); - } - - public void saveDefaults() - { - this.data.saveDefaults(); - this.defaultScope = this.scope; - } - - public void restoreDefaults() - { - this.data.restoreDefaults(); - changeScope(this.defaultScope); - } - - /** - * This method is called to apply the change in the value of the parameter - */ - public void apply() - { - if (getScope() == LOCAL) - ACommandProcessor.receive("DO"); - else - ACanvas.getCanvas().repaintAllFromScratch(); - } - - /** - * Called by the User Interface in order to initialize the graphics of the - * parameter (if it will be displayed in the UI). - */ - public void initialize() - { - if (hasStatus) - { - nameLabel = new ACheckBox(screenName); - nameLabel.setSelected(getStatus()); - nameLabel.setBackground(new Color(204, 204, 204)); - if (getScope() == LOCAL) - setForeground(Color.black); - else - setForeground(Color.blue); - - nameLabel.setToolTipText(toolTip); - nameLabel.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - ACommandProcessor.receive(name); - apply(); - } - }); - - // after the first left click at the table in the parameter tabbed - // pane, all the followingmouse mouse event will be catched by the - // mouselisteners of those components inside the table cells, not - // the table itself, so in order for the local/global - // switch (right click to change) to always work, have to add mouse - // listeners to these components as well. - nameLabel.addMouseListener(new MouseAdapter() - { - public void mousePressed(MouseEvent e) - { - if (AUtilities.isRightMouseButton(e)) - { - JPopupMenu popupMenu = new JPopupMenu(); - if (getScope() == AParameter.LOCAL) - { - popupMenu.add(AParametersTable.SET_GLOBAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeScope(AParameter.GLOBAL); - refresh(); - } - }); - } - else - { - popupMenu.add(AParametersTable.SET_LOCAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeScope(AParameter.LOCAL); - refresh(); - } - }); - } - popupMenu.show(nameLabel, e.getX(), e.getY()); - } - } - }); - } - else - { - label = new JLabel(screenName); - if (getScope() == LOCAL) - setForeground(Color.black); - else - setForeground(Color.blue); - - // after the first left click at the table in the parameter tabbed - // pane, all the followingmouse mouse event will be catched by the - // mouselisteners of those components inside the table cells, not - // the table itself, so in order for the local/global - // switch (right click to change) to always work, have to add mouse - // listeners to these components as well. - label.addMouseListener(new MouseAdapter() - { - public void mousePressed(MouseEvent e) - { - if (AUtilities.isRightMouseButton(e)) - { - JPopupMenu popupMenu = new JPopupMenu(); - if (getScope() == AParameter.LOCAL) - { - popupMenu.add(AParametersTable.SET_GLOBAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeScope(AParameter.GLOBAL); - refresh(); - } - }); - } - else - { - popupMenu.add(AParametersTable.SET_LOCAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeScope(AParameter.LOCAL); - refresh(); - } - }); - } - popupMenu.show(label, e.getX(), e.getY()); - } - } - }); - label.setOpaque(true); - label.setToolTipText(toolTip); - LookAndFeel.installColorsAndFont(label, "CheckBox.background", "CheckBox.foreground", "CheckBox.font"); - } - - isInitialized = true; - } - - public boolean isInitialized() - { - return this.isInitialized; - } - - /** - * Copies from one window to another the value of the parameter - */ - public void copy(int from, int to) - { - data.copy(from,to); - } - - /** - * This function is called for GLOBAL parameters to apply the value in all - * windows. - */ - public void globalize(int window) - { - data.globalize(window); - } - - public void setScope(int scope) - { - this.scope = scope; - if (scope == LOCAL) - setForeground(Color.black); - else - setForeground(Color.blue); - } - - public void changeScope(int scope) - { - if (scope != this.scope) - { - this.scope = scope; - if (scope == LOCAL) - setForeground(Color.black); - else - { - setForeground(Color.blue); - data.globalize(); - ACanvas.getCanvas().repaintAllFromScratch(); - } - } - } - - public int getScope() - { - return scope; - } - - public String getName() - { - return name; - } - - public String getScreenName() - { - return screenName; - } - - public String getToolTip() - { - return toolTip; - } - - // public String getOperator() { return operator; } - public boolean isModulus() - { - return isModulus; - } - - public int getValueType() - { - return valueType; - } - - public String getOperator() - { - return data.getOperator(); - } - - protected void _setOperator(String oper) - { - // if (!validateValue(v)) - // throw new Error("Value " + v + " for parameter " + screenName + " is - // out of range "); - data.setOperator(oper); - if (scope == GLOBAL) data.globalize(); - } - - protected void _setOperator(String windowName, String oper) - { - if (scope == GLOBAL || windowName.equals("*")) { - data.setOperator(oper); - data.globalize(); - } else { - data.setOperator(ACanvas.getCanvas().getWindow(windowName).getIndex(), oper); - } - } - - protected void _setValue(String windowName, double val) - { - if (scope == GLOBAL || windowName.equals("*")) { - data.setValue(val); - data.globalize(); - } else { - data.setValue(ACanvas.getCanvas().getWindow(windowName).getIndex(), val); - } - } - - protected void _setStatus(String windowName, boolean stat) - { - if (scope == GLOBAL || windowName.equals("*")) { - data.setStatus(stat); - data.globalize(); - } else { - data.setStatus(ACanvas.getCanvas().getWindow(windowName).getIndex(), stat); - } - } - - /** - * _setD and _setI are used by subclasses when changing the values of - * parameters. - */ - protected void _setD(double v) - { - if (!validateValue(v)) - throw new Error("Value " + v + " for parameter " + screenName + " is out of range "); - data.setValue(v); - if (scope == GLOBAL) data.globalize(); - } - - protected void _setI(int v) - { - if (!validateValue(v)) - throw new Error("Value " + v + " for parameter " + screenName + " is out of range "); - data.setValue(v); - if (scope == GLOBAL) data.globalize(); - } - - public double getD() - { - if (valueType != FLOAT) - throw new Error("getD acces on not FLOAT parameter"); - return data.getValue(); - } - - public int getI() - { - if (valueType != INT) - throw new Error("getI acces on not INT parameter"); - return (int) data.getValue(); - } - - public String getValue() - { - if (valueType == FLOAT) - return Double.toString(data.getValue()); - else - return Integer.toString((int) data.getValue()); - } - - public void setStatus(boolean st) - { - if (!hasStatus) - throw new Error("Parameter has no status"); - data.setStatus(st); - if (scope == GLOBAL) data.globalize(); - - refresh(); - fireParameterChanged(); - } - - public boolean getStatus() - { - if (!hasStatus) - throw new Error("Parameter hase no status"); - - return data.getStatus(); - } - - public JComponent getNameComponent() - { - if (hasStatus) - return nameLabel; - else - return label; - } - - public JComponent getValueComponent() - { - return new JLabel("error"); - } - - protected void _refresh() - { - if (hasStatus) - if (nameLabel != null) - nameLabel.setSelected(getStatus()); - } - - /** - * Parses the PossibleValues string and returns the double[][] containing - * the range of this parameter. - */ - protected static double[][] resolvePossibleValues(String possibleValues, int type) - { - double[][] range = new double[3][100]; - int valCount = 0; - int rangeCount = 0; - StringTokenizer st = new StringTokenizer(possibleValues, ","); - String sval; - double val = 0; - - while (st.hasMoreTokens()) - { - String token = st.nextToken().trim(); - StringTokenizer st1 = new StringTokenizer(token, ":"); - - switch (st1.countTokens()) - { - case 1: - sval = st1.nextToken().trim(); - try - { - if (type == FLOAT) - val = Double.parseDouble(sval); - else if (type == INT) - val = Integer.parseInt(sval); - range[SVAL][valCount] = val; - valCount++; - } - catch (NumberFormatException nfe) - { - AExceptionHandler.processException("Corrupt Possible Value: " + sval, nfe); - } - break; - - case 2: - for (int i = 0; i < 2; i++) - { - sval = st1.nextToken().trim(); - try - { - if (type == FLOAT) - val = Double.parseDouble(sval); - else if (type == INT) - val = Integer.parseInt(sval); - } - catch (NumberFormatException nfe) - { - if (sval.equals("inf")) - val = Double.POSITIVE_INFINITY; - else if (sval.equals("-inf")) - val = Double.NEGATIVE_INFINITY; - else - AExceptionHandler.processException("Corrupt Possible Range: (" + token + ")", nfe); - } - range[i][rangeCount] = val; - } - rangeCount++; - break; - - default: - AExceptionHandler.processException("fatal", "Corrupt \"pv\" definition: \"" + possibleValues + "\""); - break; - } - } - - double[] min = new double[rangeCount]; - double[] max = new double[rangeCount]; - - for (int i = 0; i < rangeCount; i++) - if (range[MIN][i] <= range[MAX][i]) - { - min[i] = range[MIN][i]; - max[i] = range[MAX][i]; - } - else - throw new Error("Bad range definiton: (" + range[0][i] + ":" + range[1][i] + ")"); - - double[] v = new double[valCount]; - - for (int i = 0; i < valCount; i++) - v[i] = range[SVAL][i]; - - range[MIN] = min; - range[MAX] = max; - range[SVAL] = v; - return range; - } - - protected static int[] getValues(String possibleValues) - { - int[] pVal = new int[100]; - int[] range = new int[2]; - int i, valCount = 0; - String token; - StringTokenizer st, st1; - - st = new StringTokenizer(possibleValues, ","); - while (st.hasMoreTokens()) - { - token = st.nextToken().trim(); - st1 = new StringTokenizer(token, ":"); - switch (st1.countTokens()) - { - case 1: - try - { - pVal[valCount++] = Integer.parseInt(st1.nextToken().trim()); - } - catch (NumberFormatException nfe) - { - AExceptionHandler.processException("Corrupt Possible Value", nfe); - } - break; - - case 2: - for (i = 0; i < 2; i++) - try - { - range[i] = Integer.parseInt(st1.nextToken().trim()); - } - catch (NumberFormatException nfe) - { - AExceptionHandler.processException("fatal", "error in range definition"); - } - - if (range[0] <= range[1]) - for (i = range[0]; i <= range[1]; i++) - pVal[valCount++] = i; - break; - - default: - AExceptionHandler.processException("fatal", "Corrupt range definition: \"" + possibleValues + "\""); - } - } - - int[] pValFinal = new int[valCount]; - - for (i = 0; i < valCount; i++) - pValFinal[i] = pVal[i]; - - return pValFinal; - } - - public boolean processCommand(String oper, double v) - { - // first I validate the operator and the value - if (!validateOperator(oper)) - return false; - if (!validateValue(v)) - return false; - - if (valueType == FLOAT) - _setD(v); - else - _setI((int) v); - - _setOperator(oper); - - refresh(); - fireParameterChanged(); - - return true; - } - - public boolean validateValue(double v) - { - if (range[SVAL] != null) - for (int i = 0; i < range[SVAL].length; i++) - if (v == range[SVAL][i]) - return true; - - if (range[MIN] != null) - for (int i = 0; i < range[MIN].length; i++) - if ((v >= range[MIN][i]) && (v <= range[MAX][i])) - return true; - - return false; - } - - public boolean validateOperator(String oper) - { - for (int i = 0; i < operators.length; i++) - if (oper.equals(operators[i])) - return true; - - return false; - } - - public int getUserLevel() - { - return userLevel; - } - - - public String toString() - { - StringBuilder s = new StringBuilder(screenName + ": "); - - if (scope == GLOBAL) - s.append("GLOBAL"); - else if (scope == LOCAL) - s.append("LOCAL"); - - s.append("["); - - // for running without Canvas (e.g. calling geometry methods from GraXML), - // this may run without Canvas initialised - // check if Canvas actually exists - // dependency of AAbstractParameter on ACanvas should be revised, this - // current solution is not very elegant - ACanvas canvas = ACanvas.getCanvas(); - String[] wName = canvas == null ? new String[0] : canvas.getKnownWindowNames(); - - for (int i = 0; i < wName.length; i++) - { - AWindow w = ACanvas.getCanvas().getWindow(wName[i]); - - s.append(wName[i] + ": " + data.getValue(w.getIndex()) + ": "); - } - - return s.toString() + "]" + " :" + toolTip + ":"; - } - - - private final void setForeground(Color color) - { - if (getNameComponent() != null) - getNameComponent().setForeground(color); - } - - public String getDifferences(String groupName) - { - StringBuffer b = new StringBuffer(); - String[] windowNames = ACanvas.getCanvas().getKnownWindowNames(); - int[] inverse = new int[windowNames.length]; - for (int i = 0; i < windowNames.length; i++) - inverse[ACanvas.getCanvas().getWindow(windowNames[i]).getIndex()] = i; - - for (int i = 0; i < wCount; ++i) - { - if (data.getStatus() != data.getStatus(i) || !data.getOperator().equals(data.getOperator(i)) || data.getValue() != data.getValue(i)) - { - - b.append("\t\t<DIFFERENCE group=\"" + groupName + "\" name=\"" + getName() + "\" windowName=\"" + windowNames[inverse[i]] + "\""); - - if (data.getValue() != data.getValue(i)) - b.append(" va=\"" + data.getValue(i) + "\""); - if (data.getStatus() != data.getStatus(i)) - { - if (data.getStatus(i)) - b.append(" st=\"ON\""); - else - b.append(" st=\"OFF\""); - } - if (!data.getOperator().equals(data.getOperator(i))) - b.append(" op=\"" + data.getOperator(i) + "\""); - b.append("/>\n"); - } - } - return b.toString(); - } - - protected double parseUnitsDouble(String text) - { - // units shown are cm - if (unitsOf == LENGTH) - { - if (text.endsWith("MM") || text.endsWith("mm")) - return 0.1 * Double.parseDouble(text.substring(0, text.length() - 2)); - if (text.endsWith("CM") || text.endsWith("cm")) - return Double.parseDouble(text.substring(0, text.length() - 2)); - if (text.endsWith("UM") || text.endsWith("um")) - return 0.0001 * Double.parseDouble(text.substring(0, text.length() - 2)); - else if (text.endsWith("M") || text.endsWith("m")) - return 100. * Double.parseDouble(text.substring(0, text.length() - 1)); - else - return Double.parseDouble(text.substring(0, text.length())); - } - else if (unitsOf == ENERGY) - { - if (text.endsWith("GeV") || text.endsWith("gev") || text.endsWith("GEV")) - return Double.parseDouble(text.substring(0, text.length() - 3)); - else if (text.endsWith("MeV") || text.endsWith("mev") || text.endsWith("MEV")) - return .001 * Double.parseDouble(text.substring(0, text.length() - 3)); - else - return Double.parseDouble(text); - } - else if (unitsOf == ENERGYMEV) - { - if (text.endsWith("MeV") || text.endsWith("mev") || text.endsWith("MEV")) - return Double.parseDouble(text.substring(0, text.length() - 3)); - else if (text.endsWith("KeV") || text.endsWith("kev") || text.endsWith("KEV")) - return .001 * Double.parseDouble(text.substring(0, text.length() - 3)); - else if (text.endsWith(" eV") || text.endsWith(" ev") || text.endsWith(" EV")) - return .000001 * Double.parseDouble(text.substring(0, text.length() - 3)); - else - return Double.parseDouble(text); - } - else - { - return Double.parseDouble(text); - } - } - - protected String parseUnits(double d) - { - // units shown are cm - double abs = Math.abs(d); - if (unitsOf == LENGTH) - { - if (abs >= 100.) - return "" + trim(d, 100.) + " m"; - else if (abs >= 1.) - return "" + trim(d, 1.) + " cm"; - else if (abs >= 0.1) - return "" + trim(d, 0.1) + " mm"; - else - return "" + trim(d, 0.0001) + " um"; - } - else if (unitsOf == ENERGY) - { - if (abs >= 1.) - return "" + trim(d, 1.) + " GeV"; - else - return "" + trim(d, 0.001) + " MeV"; - } - else if (unitsOf == ENERGYMEV) - { - if (abs >= 1.) - return "" + trim(d, 1.) + " MeV"; - else if(abs >=0.001) - return "" + trim(d, 0.001) + " KeV"; - else - return "" + trim(d, 0.000001) + " eV"; - } - else - { - return "" + trim(d, 1.); - } - } - - private String trim(double d, double factor) - { - // only display with 3 significant digits - if (unitsOf == LENGTH && Math.abs(d) < .1) - return "" + Math.rint(d / factor); - else if (unitsOf == ENERGY && Math.abs(d) < 1.) - return "" + Math.rint(d / factor); - else if (unitsOf == ENERGYMEV && Math.abs(d) < 1.) - return "" + Math.rint(d / factor); - else - return "" + Math.rint(1000. * d / factor) / 1000.; - } - - public ACheckBox getCheckBox() - { - return this.nameLabel; - } - - /** - * Check if a given operator is one of the allowed supportedOperators. - * @param oper the operator to check - * @return true if this is a known operator - */ - protected static boolean isKnownOperator(String oper) - { - for(int i=0; i<AParameter.supportedOperators.length; i++) - if(oper.equals(AParameter.supportedOperators[i])) - return true; - - return false; - } - - /** - * Tell the listeners that a parameter has changed. - */ - protected void fireParameterChanged() { - for (AParameterChangeListener listener : parameterChangeListeners) { - listener.parameterChanged(this); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AColorParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AColorParameter.java deleted file mode 100755 index 34972e6e189..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AColorParameter.java +++ /dev/null @@ -1,92 +0,0 @@ -package atlantis.parameters; - -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import javax.swing.JComponent; - -import atlantis.gui.AColorComboBoxRenderer; -import atlantis.gui.AComboBox; - -/** - * A parameter representing a selectable colour. - */ -public class AColorParameter extends AAbstractParameter { - private AComboBox colorComboBox; - - public AColorParameter( - String name, String screenName, String toolTip, String pv, double value, - boolean haseStatus, boolean status, int userLevel, int scope) { - - super(name, screenName, toolTip, INT, value, null, null, haseStatus, status, false, userLevel, - scope, NOTHING); - - range=resolvePossibleValues(pv, INT); - if((range[SVAL]==null)&&(range[MIN]==null)) { - range[MIN]=new double[] {0}; - range[MAX]=new double[] {29}; - } - - } - - public void setD(double v) { - throw new IllegalArgumentException("is not allowed to use setD on ColorParameter"); - } - - public void setI(int v) { - if(colorComboBox!=null) - colorComboBox.setGUISelectedItem(new Integer(v)); - - _setI(v); - refresh(); - fireParameterChanged(); - } - - public void initialize() { - super.initialize(); - colorComboBox=new AComboBox(); - colorComboBox.setRenderer(new AColorComboBoxRenderer()); - colorComboBox.setToolTipText(toolTip); - - int i, j; - - for(i=0; i<range[SVAL].length; i++) { - int color=(int)range[SVAL][i]; - - if((color>=0)&&(color<=29)) - colorComboBox.addItem(new Integer(color)); - } - - for(i=0; i<range[MIN].length; i++) { - int color1=(int)range[MIN][i]; - int color2=(int)range[MAX][i]; - - if((color1>=0)&&(color1<=29)&&(color2>=0)&&(color2<=29)) - for(j=color1; j<=color2; j++) - colorComboBox.addItem(new Integer(j)); - } - - colorComboBox.setGUIItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if(e.getStateChange()==ItemEvent.SELECTED) { - int color=((Integer)colorComboBox.getSelectedItem()).intValue(); - - ACommandProcessor.receive(name+"="+color); - apply(); - } - } - }); - - colorComboBox.setGUISelectedItem(new Integer(getI())); - } - - public JComponent getValueComponent() { - return colorComboBox; - } - - public void refresh() { - _refresh(); - if(colorComboBox!=null) - colorComboBox.setGUISelectedItem(new Integer(getI())); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/ACommand.java b/graphics/AtlantisJava/src/atlantis/parameters/ACommand.java deleted file mode 100755 index 1ae57ad8ffc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/ACommand.java +++ /dev/null @@ -1,31 +0,0 @@ -package atlantis.parameters; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JButton; - -/** - * This class is a GUI representation of a command button. - * It just generates the corresponding command when pressed. - */ -public class ACommand extends JButton { - private String command; - - ACommand(String name, String _command, String toolTip) { - super(name); - - this.command=_command; - - setToolTipText(toolTip); - addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - ACommandProcessor.receive(command); - } - }); - } - - public String getName() { - return getText(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/ACommandProcessor.java b/graphics/AtlantisJava/src/atlantis/parameters/ACommandProcessor.java deleted file mode 100755 index 9c023708c66..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/ACommandProcessor.java +++ /dev/null @@ -1,451 +0,0 @@ -package atlantis.parameters; - -import java.util.Vector; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.event.AEventManager; -import atlantis.event.AFilter; -import atlantis.data.AS3DData; -import atlantis.data.ATrackData; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.projection.AProjection; -import atlantis.utils.ALogger; - -/** - * (almost?) All actions on the GUI generate a command (which is basically a - * text string) which is passed to the command processor which performs the - * actions associated with that command. This should allow a simple - * implementation of scripting and logging - * - * NOTE: This design has been dramatically neglected in the past and should - * probably be revised (Sebastian Boeser, 06.10.09) - */ - -public class ACommandProcessor -{ - private static ALogger logger = ALogger.getLogger(ACommandProcessor.class); - private static AEventManager eventManager = AEventManager.instance(); - - private static String legoLayoutName =""; - private static String[] legoWindowNames = {"current", "W", "1", "2", "3", "4"}; - private final static String[] legoStatusParameterNames = {"DrawPlot", "MainLegend", "L1EtLegend", "L1Items", "L2Items", "EFItems"}; - private final static String[] legoIntParameterNames = {"Mode", "nphicells", "netacells"}; - private final static String[] legoCaloParameterNames = {"LAr", "TILE", "FCAL", "MBTS"}; - private static boolean[][] legoStatusParameter = new boolean[6][6]; - private static int[][] legoIntParameter = new int[6][3]; - private static boolean[][] legoCaloParameter = new boolean[2][4]; - - private static APar parameterStore = APar.instance(); - - /** - * While this is called receive, it is actually just a small wrapper to - * processes a command and at the same time log it - * @param command the command to process - */ - public synchronized static void receive(String command) - { - //In debug mode show the command - logger.debug("ACommandProcessor.receive(): " + command); - //In trace mode show also who called this - logger.trace("Calling hierarchy",new Exception()); - - //Now process the command - boolean status = process(command); - - //And log the result - logger.debug( ((status)?" success: ":" bad command:") + command); - - } - - - - private synchronized static boolean process(String c) - { - - if (processGlobal(c)) - { - return true; - } - - AProjection p = ACanvas.getCanvas().getCurrentWindow().getProjection(); - // projection dependent command could be processed here - if (p.processLocalCommand(c)) - { - return true; - } - - if (parameterStore.processParameterChangeCommand(c)) - { - return true; - } - - return false; - } - - // used for checking all command are implemented - private synchronized static boolean found(int mode, String name, String command) - { - if (mode != 0) - { - logger.warn("Command not found: " + command); - return false; - } - if (name.equals(command)) - return true; - return false; - } - - private synchronized static boolean foundWindow(int mode, String name, String command) - { - if (mode != 0) - { - String[] windowNames = ACanvas.getCanvas().getKnownWindowNames(); - - for (int i = 0; i < windowNames.length; ++i) - logger.debug(command + windowNames[i]); - return false; - } - - if (name.substring(0, name.length() - 1).equals(command)) - if (ACanvas.getCanvas().isValidWindowName(name.substring(name.length() - 1))) - if (ACanvas.getCanvas().getWindow(name.substring(name.length() - 1)) != null) - return true; - return false; - } - - private synchronized static boolean processGlobal(String c) - { - return processGlobal(c, 0); - } - - private static void getGlobalCommands() - { - processGlobal("GARY", 1); - } - - private static boolean processZoomTrack(String name, int mode) - { - ATrackData tr = null; - - // check if STr (Simulated Track) Zoom Next Track was pressed - if(found(mode, name, "ZOOMNEXTSTR")) - { - tr = eventManager.getCurrentEvent().getSTrData(); - } - // check if Track (InDetTrack) Zoom Next Track was pressed - else if(found(mode, name, "ZOOMNEXTTRACK")) - { - AEnumeratorParameter listBox = null; - listBox = (AEnumeratorParameter) parameterStore.get("InDetTrack", "InDetTrackCollections"); - String col = listBox.getCurrentText(); - if("All".equals(col)) - { - String msg = "Choose a particular Track collection, " + - "can't zoom next track when 'All' is selected.\n"; - AOutput.alwaysAppend(msg, ALogInterface.WARNING); - return false; - } - else - { - tr = eventManager.getCurrentEvent().getTrackData("InDetTrack", col); - } - } - - if(tr == null) - { - // STr or Track of requested collection doesn't exits in this event - return false; - } - - // check if the datatype where Zoom Next Track was pressed is actually - // turned on and thus visible - if(! parameterStore.get("Data", tr.getName()).getStatus()) - { - AOutput.alwaysAppend("Can't zoom next track, " + tr.getNameScreenName() + - " is turned off.\n", ALogInterface.WARNING); - return false; - } - - AParameter nextTrPar = parameterStore.get(tr.getName(), "NextTrack"); - nextTrPar.setStatus(true); - nextTrPar.setI(nextTrPar.getI() + 1); - tr.zoomAroundTracks(); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - - AOutput.alwaysAppend(tr.getNameScreenName() + " -> Next Track cut active now.\n", - ALogInterface.WARNING); - - return true; - - } // processZoomTrack() - // --------------------------------------------------- - - private synchronized static boolean processGlobal(String name, int mode) - { - // is this a group in the parameter file ? - Vector<String> groups = parameterStore.getUIGroupNames(); - for (int i = 0; i < groups.size(); ++i) - { - String groupName = groups.elementAt(i); - if (found(mode, name, groupName + ".")) - { - ACanvas.getCanvas().getCurrentWindow().setGroup(groupName); - return true; - } - } - - if(found(mode, name, "SETORIGINALPRIMARYVERTEX")) - { - eventManager.getCurrentEvent().setPrimaryVertex(); - ACanvas.getCanvas().repaintAllFromScratch(); - } - - - if (found(mode, name, "LEGOTRIGGER")) - { - processLegoTrigger(); - return true; - } - - if (found(mode, name, "RETURNLEGOTRIGGER")) - { - if(legoLayoutName.equals("")) - { - AOutput.append("No trigger debugging to return from\n", ALogInterface.NORMAL); - return true; - } - - returnLegoTrigger(); - return true; - } - - if (found(mode, name, "PREVSECTOR")) - { - AParameter phi = parameterStore.get("YZ", "Phi"); - phi.setD(((Math.round(phi.getD()/22.5) + 15) % 16) * 22.5); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - return true; - } - - if (found(mode, name, "NEXTSECTOR")) - { - AParameter phi = parameterStore.get("YZ", "Phi"); - phi.setD(((Math.round(phi.getD()/22.5) + 1) % 16) * 22.5); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - return true; - } - - if (found(mode, name, "ZOOMNEXTSTR") || found(mode, name, "ZOOMNEXTTRACK")) - { - return processZoomTrack(name, mode); - } - - if (found(mode, name, "PC")) - { - getGlobalCommands(); - return true; - } - if (found(mode, name, "DO")) - { - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - return true; - } - - // turning all datatypes on/off command: - see code which was - // commented out in AtlantisJava-09-05-71 and before - - // Toggle: PT,D0,Z0,NU off:NG,NB,NS,NR,SH - if (found(mode, name, "CC")) - { - if (parameterStore.get("CutsInDet", "z0-zVtx").getStatus()) - { - parameterStore.get("CutsInDet", "z0-zVtx").setStatus(false); - parameterStore.get("CutsInDet", "d0").setStatus(false); - parameterStore.get("CutsInDet", "Pt").setStatus(false); - parameterStore.get("CutsInDet", "NumS3D").setStatus(false); - } - else - { - parameterStore.get("CutsInDet", "z0-zVtx").setStatus(true); - parameterStore.get("CutsInDet", "d0").setStatus(true); - parameterStore.get("CutsInDet", "Pt").setStatus(true); - parameterStore.get("CutsInDet", "NumS3D").setStatus(true); - } - parameterStore.get("CutsInDet", "RTrIndex").setStatus(false); - parameterStore.get("CutsInDet", "STr").setStatus(false); - parameterStore.get("CutsInDet", "Group").setStatus(false); - parameterStore.get("CutsATLAS", "Index").setStatus(false); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - return true; - } - if (found(mode, name, "FH")) - { - //Try to get SpacePoints - AS3DData spacePoints = (AS3DData) eventManager.getCurrentEvent().get("S3D"); - //Apply Hans Drevermanns hit filter - if (spacePoints != null){ - AFilter.filter(spacePoints); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - return true; - } - if (foundWindow(mode, name, "W")) - { - ACanvas.getCanvas().setCurrentWindow(name.substring(1, 2)); - return true; - } - if (foundWindow(mode, name, "C")) - { - return true; - } - if (foundWindow(mode, name, "Z")) - { - return true; - } - return false; - } // processGlobal() ------------------------------------------------------ - - private synchronized static void processLegoTrigger() - { - String currentWindowName = ACanvas.getCanvas().getCurrentWindowName(); - String currentLayoutName = ACanvas.getCanvas().getCurrentLayout().getName(); - - //save status of windows on first time button pressed - if(legoLayoutName.equals("")) - { - //output message to the user - AOutput.append("\nWindows changed to:\n",ALogInterface.TITLE); - AOutput.append("Window 1: LegoPlot with Calo View\n", ALogInterface.NORMAL); - AOutput.append("Window 2: LegoPlot with Trigger Tower View\n", ALogInterface.NORMAL); - AOutput.append("Window 3: LegoPlot with Jet Element View\n", ALogInterface.NORMAL); - AOutput.append("Window 4: LegoPlot Legend (may not be displayed if window too small)\n", ALogInterface.NORMAL); - //save current window name and layout to then parameters to restore later - legoWindowNames[0]=currentWindowName; - legoLayoutName=currentLayoutName; - for(int i=0; i<legoWindowNames.length; i++) - { - parameterStore.selectWindowParameters(legoWindowNames[i]); - if (ACanvas.getCanvas().getWindow(legoWindowNames[i]) != null) - { - //save lego status parameters - for(int j=0; j<legoStatusParameterNames.length; j++){ - legoStatusParameter[i][j]=parameterStore.get("LegoPlot", legoStatusParameterNames[j]).getStatus(); - } - //save lego int parameters - for(int j=0; j<legoIntParameterNames.length; j++){ - legoIntParameter[i][j]=parameterStore.get("LegoPlot", legoIntParameterNames[j]).getI(); - } - //save data parameters for windows 1 and 4 - if(legoWindowNames[i].equals("1")){ - for(int j=0; j<legoCaloParameterNames.length; j++){ - legoCaloParameter[0][j]=parameterStore.get("Data", legoCaloParameterNames[j]).getStatus(); - } - }else if(legoWindowNames[i].equals("4")){ - for(int j=0; j<legoCaloParameterNames.length; j++){ - legoCaloParameter[1][j]=parameterStore.get("Data", legoCaloParameterNames[j]).getStatus(); - } - } - } - parameterStore.restoreWindowParameters(); - } - } - //copy to W to make sure can switch layout to 4 squares - ACanvas.getCanvas().copyWindowSettings(currentWindowName, "W"); - if(!currentLayoutName.equals("FOUR SQUARES")) - ACanvas.getCanvas().setCurrentLayout("FOUR SQUARES"); - //for cell sizing take defaults values and then roughly scaled for different views - int nphicells = 128; - int netacells = 200; - //now copy to each window and set the display correctly - for (int i = 0; i < 4; i++) - { - String wName = Integer.toString(i + 1); - AWindow w = ACanvas.getCanvas().getWindow(wName); - parameterStore.selectWindowParameters(wName); - if (w != null) - { - ACanvas.getCanvas().copyWindowSettings("W", wName); - //first 3 windows show data items (calo, trigger towers, jet elements) - if(i<3) - { - parameterStore.get("LegoPlot", "Mode").setI(i); - parameterStore.get("LegoPlot", "DrawPlot").setStatus(true); - parameterStore.get("LegoPlot", "MainLegend").setStatus(false); - parameterStore.get("LegoPlot", "L1EtLegend").setStatus(false); - parameterStore.get("LegoPlot", "L1Items").setStatus(false); - parameterStore.get("LegoPlot", "L2Items").setStatus(false); - parameterStore.get("LegoPlot", "EFItems").setStatus(false); - parameterStore.get("LegoPlot", "nphicells").setI(nphicells/((int) Math.pow(2.0, i))); - parameterStore.get("LegoPlot", "netacells").setI(netacells/((int) Math.pow(2.0, i))); - } - else - { - //last window shows legend - parameterStore.get("LegoPlot", "DrawPlot").setStatus(false); - parameterStore.get("LegoPlot", "MainLegend").setStatus(true); - parameterStore.get("LegoPlot", "L1EtLegend").setStatus(true); - parameterStore.get("LegoPlot", "L1Items").setStatus(true); - parameterStore.get("LegoPlot", "L2Items").setStatus(true); - parameterStore.get("LegoPlot", "EFItems").setStatus(true); - } - //if first or last window it needs the data items turned on - if(i==0 || i==3) - { - for(int j=0; j<legoCaloParameterNames.length; j++){ - parameterStore.get("Data", legoCaloParameterNames[j]).setStatus(true); - } - } - } - parameterStore.restoreWindowParameters(); - ACanvas.getCanvas().moveToFrontWindow(w.getName()); - w.repaintFromScratch(); - - } - } - - private synchronized static void returnLegoTrigger() - { - //now will reset the parameters explictly set by trigger debug mode - //others may be changed as on doing trigger debug others might get changed - //when the current window is copied to W but these have been changed by the - //user so not so important to reset - - //loop backwards so can reset each window before reverting to previous layout - for(int i=legoWindowNames.length-1; i>=0; i--) - { - //reset the lego status parameters - parameterStore.selectWindowParameters(legoWindowNames[i]); - for(int j=0; j<legoStatusParameterNames.length; j++){ - parameterStore.get("LegoPlot", legoStatusParameterNames[j]).setStatus(legoStatusParameter[i][j]); - } - //reset the lego int parameters - for(int j=0; j<legoIntParameterNames.length; j++){ - parameterStore.get("LegoPlot", legoIntParameterNames[j]).setI(legoIntParameter[i][j]); - } - //reset the data ites for windows 1 and 4 - if(legoWindowNames[i].equals("1")){ - for(int j=0; j<legoCaloParameterNames.length; j++){ - parameterStore.get("Data", legoCaloParameterNames[j]).setStatus(legoCaloParameter[0][j]); - } - }else if(legoWindowNames[i].equals("4")){ - for(int j=0; j<legoCaloParameterNames.length; j++){ - parameterStore.get("Data", legoCaloParameterNames[j]).setStatus(legoCaloParameter[1][j]); - } - } - parameterStore.restoreWindowParameters(); - //finished altering window so repaint - ACanvas.getCanvas().getWindow(legoWindowNames[i]).repaintFromScratch(); - //have just finished W window so now can reset the layout - if(i==1){ - ACanvas.getCanvas().setCurrentLayout(legoLayoutName); - legoLayoutName=""; - } - } - //everything reset now make the original window where trigger debug - //was started the current window - ACanvas.getCanvas().setCurrentWindow(legoWindowNames[0]); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/ACutParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/ACutParameter.java deleted file mode 100755 index 490114e3e65..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/ACutParameter.java +++ /dev/null @@ -1,171 +0,0 @@ -package atlantis.parameters; - -import java.awt.Color; -import java.awt.event.*; -import javax.swing.*; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.AUtilities; -import atlantis.gui.AMutableCheckBox; -import atlantis.gui.AParametersTable; -import atlantis.gui.ATextField; - -/** - * A parameter representing a cut on a variable. - */ -public class ACutParameter extends AAbstractParameter { - // name component - private AMutableCheckBox checkBox; - - // value component - private ATextField textField; - - private ActionListener statusActionListener, valueActionListener; - - public ACutParameter( - String name, String screenName, String toolTip, String pv, int valueType, double value, - String operators, String defOperator, boolean haseStatus, boolean status, boolean isMod, - int userLevel, int scope, int unitsOf) { - - super(name, screenName, toolTip, valueType, value, operators, defOperator, haseStatus, status, - isMod, userLevel, scope, unitsOf); - - range=resolvePossibleValues(pv, valueType); - } - - public void setD(double v) { - if(valueType!=FLOAT) throw new IllegalArgumentException("setD acces on not FLOAT parameter"); - - if(textField!=null) textField.setText(""+v); - _setD(v); - - refresh(); - } - - public void setI(int v) { - if(valueType!=INT) throw new IllegalArgumentException("setI acces on not INT parameter"); - - if(textField!=null) textField.setText(""+v); - _setI(v); - - refresh(); - } - - public void initialize() { - checkBox=new AMutableCheckBox(screenName); - checkBox.setToolTipText(toolTip); - if(getScope()==LOCAL) - checkBox.setForeground(Color.black); - else - checkBox.setForeground(Color.blue); - - for(int i=0; i<operators.length; i++) - checkBox.addItem(operators[i]); - - checkBox.finalizeConstruction(); - checkBox.setSelectedText(getOperator()); - - statusActionListener=new ActionListener() { - public void actionPerformed(ActionEvent e) { - ACommandProcessor.receive(name); - apply(); - } - }; - - valueActionListener=new ActionListener() { - public void actionPerformed(ActionEvent e) { - applyInput(); - } - }; - - checkBox.addStatusActionListener(statusActionListener); - checkBox.addTextActionListener(valueActionListener); - - // after the first left click at the table in the parameter tabbed pane, - // all the followingmouse mouse event will be catched by the mouselisteners of those - // components inside the table cells, not the table itself, so in order for the local/global - // switch (right click to change) to always work, have to add mouse listeners to these components - // as well. - checkBox.getCheckBox().addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - if(AUtilities.isRightMouseButton(e)) { - JPopupMenu popupMenu=new JPopupMenu(); - if(getScope()==AParameter.LOCAL) { - popupMenu.add(AParametersTable.SET_GLOBAL).addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - changeScope(AParameter.GLOBAL); - refresh(); - } - }); - } else { - popupMenu.add(AParametersTable.SET_LOCAL).addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - changeScope(AParameter.LOCAL); - refresh(); - } - }); - } - popupMenu.show(checkBox.getCheckBox(), e.getX(), e.getY()); - } - } - }); - - textField=new ATextField(); - textField.setToolTipText(toolTip); - - if(valueType==FLOAT) - textField.setText(""+getD()); - else - textField.setText(""+getI()); - - textField.addActionListener(valueActionListener); - - /* - textField.addFocusListener(new FocusAdapter() { - public void focusLost(FocusEvent e) { - applyInput(); - } - }); - */ - } - - private void applyInput() { - try { - if(valueType==FLOAT) { - double v=parseUnitsDouble(textField.getText()); - - ACommandProcessor.receive(name+checkBox.getSelectedText()+v); - apply(); - } else { - int v=Integer.parseInt(textField.getText()); - - ACommandProcessor.receive(name+checkBox.getSelectedText()+v); - apply(); - } - } catch(NumberFormatException nfe) { - AOutput.append("value: "+textField.getText()+", is not correct!", ALogInterface.BAD_COMMAND); - } - } - - public JComponent getValueComponent() { - return textField; - } - - public JComponent getNameComponent() { - return checkBox; - } - - public void refresh() { - if(textField!=null) { - if(valueType==FLOAT) - textField.setText(parseUnits(getD())); - else - textField.setText(""+getI()); - } - if(checkBox!=null) checkBox.setStatus(getStatus()); - if(checkBox!=null) checkBox.setSelectedText(getOperator()); - fireParameterChanged(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AEnumeratorParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AEnumeratorParameter.java deleted file mode 100755 index 92cdc8019c7..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AEnumeratorParameter.java +++ /dev/null @@ -1,278 +0,0 @@ -package atlantis.parameters; - -import java.util.StringTokenizer; -import java.util.Hashtable; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import javax.swing.JComponent; - -import atlantis.output.AExceptionHandler; -import atlantis.gui.AComboBox; - - -/** - * A parameter that displays a finite list of possible values. - * Used to contain items in pTexts String[], reimplemented to contain items - * in Hash in order to be able to change the contents from event to event - * (because of the multiple collections cuts). - */ -public class AEnumeratorParameter extends AAbstractParameter -{ - private AComboBox comboBox; - private Hashtable<Integer, String> pTexts; - - - - public AEnumeratorParameter(String name, String screenName, String toolTip, - String possibleValues, double value, - boolean haseStatus, boolean status, - int userLevel, int scope) - { - super(name, screenName, toolTip, INT, value, null, null, haseStatus, - status, false, userLevel, scope, NOTHING); - - StringTokenizer st, tokenSt; - st = new StringTokenizer(possibleValues, ","); - int num = st.countTokens(); - if(num <= 0) - { - throw new Error("Empty \"pv\" attribute for ENUM: " + name); - } - pTexts = new Hashtable<Integer, String>(); - comboBox = new AComboBox(); - comboBox.setName(screenName); - - range = new double[3][]; - range[MIN] = null; - range[MAX] = null; - range[SVAL] = new double[num]; - - for(int i = 0; i < num; i++) - { - tokenSt = new StringTokenizer(st.nextToken(), "="); - if(tokenSt.countTokens() != 2) - { - throw new Error("Incomplete \"text = value\" declaration " + - "for ENUM: " + name); - } - pTexts.put(new Integer(i), tokenSt.nextToken().trim()); - - try - { - if(valueType == FLOAT) - { - range[SVAL][i] = - Double.parseDouble(tokenSt.nextToken().trim()); - } - else if(valueType == INT) - { - range[SVAL][i] = - Integer.parseInt(tokenSt.nextToken().trim()); - } - } - catch(NumberFormatException nfe) - { - String msg = "Number error for ENUM: " + name + possibleValues; - AExceptionHandler.processException(msg, nfe); - } - } - - } // AEnumeratorParameter() --------------------------------------------- - - - - public void setD(double v) - { - if(valueType != FLOAT) - { - throw new Error("setD access on not FLOAT parameter"); - } - if(comboBox != null) - { - comboBox.setGUISelectedItem(getText(v)); - } - _setD(v); - refresh(); - - } // setD() ------------------------------------------------------------- - - - - public void setI(int v) - { - if(valueType != INT) - { - throw new Error("setI access on not INT parameter"); - } - if(comboBox != null) - { - comboBox.setGUISelectedItem(getText(v)); - } - _setI(v); - refresh(); - - } // setI() ------------------------------------------------------------- - - - - public String getCurrentText() - { - return getText(getI()); - - } // getCurrentText() --------------------------------------------------- - - - - public void clear() - { - pTexts.clear(); - - } // clear() ------------------------------------------------------------ - - - - public Hashtable<Integer, String> getValuesHashtable() - { - return pTexts; - - } // getValuesHashtable() ----------------------------------------------- - - - - public int size() - { - return pTexts.size(); - - } // size() ------------------------------------------------------------- - - - - public String getText(double v) - { - for(int i = 0; i < pTexts.size(); i++) - { - if(range[SVAL][i] == v) - { - return pTexts.get(new Integer(i)); - } - } - return null; - - } // getText() ---------------------------------------------------------- - - - - public double getValue(String text) - { - for(int i = 0; i < pTexts.size(); i++) - { - if(text.equals(pTexts.get(new Integer(i)))) - { - return range[SVAL][i]; - } - } - return 0; - - } // getValue() --------------------------------------------------------- - - - - public void addItem(int key, String item) - { - pTexts.put(new Integer(key), item); - range[SVAL] = new double[pTexts.size()]; - for(int i = 0; i < pTexts.size(); i++) - { - range[SVAL][i] = i; - } - - } // addItem() ---------------------------------------------------------- - - - public void removeItem(String itemToRemove) - { - Hashtable<Integer, String> pTextsNew = new Hashtable<Integer, String>(); - for(int i = 0; i < pTexts.size(); i++) - { - String item = pTexts.get(new Integer(i)); - if(itemToRemove.equals(item)) - { - continue; - } - else - { - pTextsNew.put(new Integer(pTextsNew.size()), item); - } - } - pTexts = pTextsNew; - - range[SVAL] = new double[pTexts.size()]; - for(int i = 0; i < pTexts.size(); i++) - { - range[SVAL][i] = i; - } - - } // removeItem() ------------------------------------------------------- - - - - /** - * Initialize the contained AComboBox with the list of items stored in this AEnumeratorParameter. - * Also sets a listener to send the appropriate command when an item is selected. - */ - public void initialize() - { - super.initialize(); - // remove all existing items from, in the constructor created, comboBox - // rather than create a new instance here, because after the first - // call of this initialize() method is not possible to update items - // in the comboBox - comboBox.removeAllItems(); - comboBox.setToolTipText(toolTip); - for(int i = 0; i < pTexts.size(); i++) - { - String item = pTexts.get(new Integer(i)); - comboBox.addItem(item); - } - comboBox.setGUISelectedItem(getText(getI())); - if (!comboBox.hasGUIItemListener()) { - comboBox.setGUIItemListener(new ItemListener() - { - public void itemStateChanged(ItemEvent e) - { - if(e.getStateChange() == ItemEvent.SELECTED) - { - int index = comboBox.getSelectedIndex(); - String command = name + "=" + range[SVAL][index]; - ACommandProcessor.receive(command); - apply(); - } - } - }); - } - refresh(); - } // initialize() ------------------------------------------------------- - - - - public JComponent getValueComponent() - { - return comboBox; - - } // getValueComponent() ------------------------------------------------ - - - - public void refresh() - { - _refresh(); - if(comboBox != null) - { - comboBox.setGUISelectedItem(getText(getI())); - } - fireParameterChanged(); - } // refresh() ---------------------------------------------------------- - - - -} // class AEnumeratorParameter ============================================= diff --git a/graphics/AtlantisJava/src/atlantis/parameters/ALinkParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/ALinkParameter.java deleted file mode 100755 index c1c732e42e6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/ALinkParameter.java +++ /dev/null @@ -1,151 +0,0 @@ -package atlantis.parameters; - - -import java.util.StringTokenizer; -import javax.swing.JComponent; - - -/** - * A parameter which represents a link to another parameter. - */ -public class ALinkParameter implements AParameter { - private String groupName, parameterName; - private AParameter parameter=null; - - public ALinkParameter(String linkTo) { - StringTokenizer st=new StringTokenizer(linkTo.trim(), "."); - - groupName=st.nextToken().trim(); - parameterName=st.nextToken().trim(); - } - - public void solveLink() { - parameter=APar.instance().get(groupName, parameterName); - } - - public void initialize() { - parameter.initialize(); - } - - public boolean isInitialized() { - return parameter.isInitialized(); - } - - public void copy(int from, int to) { - parameter.copy(from, to); - } - - public void globalize(int window) { - parameter.globalize(window); - } - - public boolean isModulus() { - return parameter.isModulus(); - } - - public int getValueType() { - return parameter.getValueType(); - } - - public void setScope(int scope) {} - - public void changeScope(int scope) { - parameter.changeScope(scope); - } - - public int getScope() { - return parameter.getScope(); - } - - public String getName() { - return parameter.getName(); - } - - public String getScreenName() { - return parameter.getScreenName(); - } - - public String getToolTip() { - return parameter.getToolTip(); - } - - public boolean validateOperator(String oper) { - return parameter.validateOperator(oper); - } - - public boolean validateValue(double v) { - return parameter.validateValue(v); - } - - public void setD(double v) { - parameter.setD(v); - } - - public void setI(int v) { - parameter.setI(v); - } - - public double getD() { - return parameter.getD(); - } - - public int getI() { - return parameter.getI(); - } - - public String getValue() { - return parameter.getValue(); - } - - public String getCurrentText(){ - if(parameter instanceof AEnumeratorParameter) - return ((AEnumeratorParameter) parameter).getCurrentText(); - else - return null; - } - - public void setStatus(boolean status) { - parameter.setStatus(status); - } - - public boolean getStatus() { - return parameter.getStatus(); - } - - public String toString() { - return parameter.toString(); - } - - public String getOperator() { - return parameter.getOperator(); - } - - public boolean processCommand(String oper, double value) { - return parameter.processCommand(oper, value); - } - - public JComponent getValueComponent() { - return parameter.getValueComponent(); - } - - public JComponent getNameComponent() { - return parameter.getNameComponent(); - } - - public void refresh() { - parameter.refresh(); - } - - public int getUserLevel() { - return parameter.getUserLevel(); - } - - public String getDifferences(String groupName) { - return ""; - } - - @Override - public void addParameterChangeListener(AParameterChangeListener listener) { - if (parameter!=null) parameter.addParameterChangeListener(listener); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AListIntegerParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AListIntegerParameter.java deleted file mode 100755 index 0f26c158813..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AListIntegerParameter.java +++ /dev/null @@ -1,98 +0,0 @@ -package atlantis.parameters; - -import atlantis.utils.*; -import atlantis.gui.AComboBox; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import javax.swing.JComponent; - -/** - * A parameter which shows a list of possible integer values. - */ -public class AListIntegerParameter extends AAbstractParameter { - - private static ALogger logger = ALogger.getLogger(AListIntegerParameter.class); - - private AComboBox comboBox; - int[] displayableValues; - - public AListIntegerParameter( - String name, String screenName, String toolTip, String pv, int value, - boolean haseStatus, boolean status, int userLevel, int scope) { - - super(name, screenName, toolTip, INT, value, null, null, haseStatus, status, false, userLevel, - scope, NOTHING); - - range=resolvePossibleValues(pv, INT); - displayableValues=getValues(pv); - } - - public void setD(double v) { - throw new IllegalArgumentException("is not allowed to use setD on AListIntegerParameter"); - } - - public void setI(int v) { - if(comboBox!=null) comboBox.setGUISelectedItem(""+v); - _setI(v); - refresh(); - } - - public void initialize() { - super.initialize(); - comboBox=new AComboBox(); - comboBox.setEditable(true); - comboBox.setToolTipText(toolTip); - - for(int i=0; i<displayableValues.length; i++) - if(validateValue(displayableValues[i])) - comboBox.addItem(""+displayableValues[i]); - else throw new Error("Displayable Value: "+displayableValues[i]+" cannot be validated" - +toString()); - - comboBox.setGUISelectedItem(""+getI()); - - comboBox.setGUIItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if(e.getStateChange()==ItemEvent.SELECTED) - applyInput(); - } - }); - - /* - comboBox.addFocusListener(new FocusAdapter() { - public void focusLost(FocusEvent e) { - applyInput(); - } - }); - */ - } - - private void applyInput() { - boolean error=false; - - try { - int val=Integer.parseInt((String)comboBox.getSelectedItem()); - - if(validateValue(val)) { - ACommandProcessor.receive(name+"="+val); - apply(); - } else - error=true; - } catch(NumberFormatException nfe) { - error=true; - } - if(error) - logger.error("value: "+comboBox.getSelectedItem()+", is not correct!"); - } - - public JComponent getValueComponent() { - return comboBox; - } - - public void refresh() { - _refresh(); - if(comboBox!=null) comboBox.setGUISelectedItem(""+getI()); - fireParameterChanged(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/ANumberParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/ANumberParameter.java deleted file mode 100755 index 403285e8648..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/ANumberParameter.java +++ /dev/null @@ -1,104 +0,0 @@ -package atlantis.parameters; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JComponent; - -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.gui.ATextField; - -public class ANumberParameter extends AAbstractParameter { - private ATextField textField; - - public ANumberParameter( - String name, String screenName, String toolTip, String pv, int valueType, double value, - boolean haseStatus, boolean status, boolean isMod, int userLevel, int scope, int unitsOf) { - - super(name, screenName, toolTip, valueType, value, null, null, haseStatus, status, isMod, - userLevel, scope, unitsOf); - range=resolvePossibleValues(pv, valueType); - } - - public void setD(double v) { - if(valueType!=FLOAT) - throw new IllegalArgumentException("setD acces on not FLOAT parameter"); - - _setD(v); - refresh(); - } - - public void setI(int v) { - if(valueType!=INT) - throw new IllegalArgumentException("setI acces on not INT parameter"); - - if(textField!=null) textField.setText(""+v); - _setI(v); - } - - public void initialize() { - super.initialize(); - - textField=new ATextField(); - textField.setEditable(true); - textField.setToolTipText(toolTip); - - if(valueType==FLOAT) - textField.setText(""+getD()); - else - textField.setText(""+getI()); - - textField.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - applyInput(); - } - }); - - /* - textField.addFocusListener(new FocusAdapter() { - public void focusLost(FocusEvent e) { - applyInput(); - } - }); - */ - } - - private void applyInput() { - boolean error=false; - - try { - double val=parseUnitsDouble(textField.getText()); - - if(validateValue(val)) { - if(valueType==FLOAT) { - ACommandProcessor.receive(name+getOperator()+val); - apply(); - } else { - ACommandProcessor.receive(name+getOperator()+(int)val); - apply(); - } - } else - error=true; - } catch(NumberFormatException nfe) { - error=true; - } - if(error) - AOutput.append("value: "+textField.getText()+", is not correct!", ALogInterface.BAD_COMMAND); - } - - public JComponent getValueComponent() { - return textField; - } - - public void refresh() { - _refresh(); - if(textField!=null) { - if(valueType==FLOAT) - textField.setText(parseUnits(getD())); - else - textField.setText(""+getI()); - } - fireParameterChanged(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/APar.java b/graphics/AtlantisJava/src/atlantis/parameters/APar.java deleted file mode 100644 index 1aefa78f03b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/APar.java +++ /dev/null @@ -1,657 +0,0 @@ -package atlantis.parameters; - -import java.util.ArrayList; - -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import java.util.Set; -import java.util.Vector; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.AJetData; -import atlantis.event.AEvent; -import atlantis.event.AEventManager; -import atlantis.event.ANewEventListener; -import atlantis.utils.ALogger; -import atlantis.utils.xml.AXMLUtils; - -/** - * The Atlantis parameters store. Contains a list of AParametersGroup - * groups of parameters. - * - * The class keeps a reference to a singleton instance, but this must initially be created using - * the method {@link #construct(Node)}. Attempting to access the instance before initialization will - * cause an Error to be thrown. - * - * Ideally the APar instance would be passed to the classes that need it when the application is - * initalized, but currently the instance is fetched where it is needed, in many different parts of - * the code. - */ -public final class APar implements ANewEventListener, AParameterChangeListener -{ - private static ALogger logger = ALogger.getLogger(APar.class); - - private final List<AParameterSuperGroup> superGroups = new ArrayList<AParameterSuperGroup>(); - - /** Index of the currently selected window */ - private int currentWindowIndex; - /** Index of the previously selected window. - * Used for obtaining temporary access to parameters of some window! - */ - private int previousIndex; - - /** Parameter change listeners: just the GUI for now. */ - private List<AParameterChangeListener> parameterChangeListeners = new ArrayList<AParameterChangeListener>(); - - /** The user level of the program */ - private int userLevel; - - /** The singleton instance */ - private static APar instance; - - /** - * Create and return the singleton instance. - * @param parameters - */ - public synchronized static APar construct(Node parameters) { - instance = new APar(); - instance.initialize(parameters); - return instance; - } - - /** - * Get the singleton instance. - * @return - */ - public synchronized static APar instance() { - if (instance==null) throw new Error("Attempted to access APar instance before initialization."); - return instance; - } - - /** - * For testing only: create instance without initializing. - * @return - */ - public static synchronized APar constructDummyForTesting() { - instance = new APar(); - return instance; - } - - /** - * Constructs dummy singleton instance for testing. - */ - private APar() {} - - /** - * Constructs the singleton instance by reading the config file. - */ - private void initialize(Node parameters) - { - String ul=parameters.getAttributes().getNamedItem("userLevel").getNodeValue(); - userLevel=Integer.parseInt(ul); - - NodeList superGroupNodes=parameters.getChildNodes(); - for(int s=0; s<superGroupNodes.getLength(); s++) - { - Node superGroupNode = superGroupNodes.item(s); - if (superGroupNode.getNodeType() == Node.ELEMENT_NODE) - { - // here we have a <SuperGroup> element - AParameterSuperGroup superGroup = AParameterSuperGroup.readSuperGroup(superGroupNode,userLevel); - superGroup.addParameterChangeListener(this); - - this.superGroups.add(superGroup); - } - } - // Can't resolve link parameters until all parameters configured. - for (AParameterSuperGroup superGroup : superGroups) { - superGroup.resolveLinkParameters(); - } - - previousIndex=-1; - } - - /** Used to take into account differences in local parameters. */ - public void update(Node differences) - { - if(differences==null) return; - NodeList children=differences.getChildNodes(); - int childrenCount=children.getLength(); - for(int i=0; i<childrenCount; i++) - { - Node diff=children.item(i); - if(diff.getNodeType()==Node.ELEMENT_NODE) - { - NamedNodeMap attributes=diff.getAttributes(); - String group=AXMLUtils.tryAttribut(attributes, "group"); - String name=AXMLUtils.tryAttribut(attributes, "name"); - String windowName=AXMLUtils.tryAttribut(attributes, "windowName"); - String va=AXMLUtils.tryAttribut(attributes, "va"); - String st=AXMLUtils.tryAttribut(attributes, "st"); - String op=AXMLUtils.tryAttribut(attributes, "op"); - AParameter p=get(group, name); - if(p instanceof AAbstractParameter) - { - // When setting a global variable for just one window, make it local first - if (((AAbstractParameter)p).getScope() == AAbstractParameter.GLOBAL && !windowName.equals("*")) { - System.out.println("Setting scope to local for "+p.getName()); - ((AAbstractParameter)p).setScope(AAbstractParameter.LOCAL); - } - if(va!=null&&!va.equals("")) - { - ((AAbstractParameter)p)._setValue(windowName, Double.parseDouble(va)); - } - if(st!=null&&!st.equals("")) - { - if(st.equals("ON")) - ((AAbstractParameter)p)._setStatus(windowName, true); - else if(st.equals("OFF")) - ((AAbstractParameter)p)._setStatus(windowName, false); - } - if(op!=null&&!op.equals("")) - { - ((AAbstractParameter)p)._setOperator(windowName, op); - } - ((AAbstractParameter)p).saveDefaults(); - } - } - } - } - - /** Restore default settings of all parameters. */ - public void restoreDefaults() - { - for (AParameterSuperGroup superGroup : superGroups) { - superGroup.restoreDefaults(); - } - } - - /** - * Get parameter supergroups corresponding to current user level. - * i.e. Those with a user level less than or equal to the current level. - * @return supergroups corresponding to current user level - */ - public List<AParameterSuperGroup> getUISuperGroups() { - List<AParameterSuperGroup> uiSuperGroups = new ArrayList<AParameterSuperGroup>(); - for (AParameterSuperGroup superGroup : superGroups) { - if (superGroup.getUserLevel()<=this.userLevel) uiSuperGroups.add(superGroup); - } - return uiSuperGroups; - } - - /** - * Get all the parameter groups used by the GUI, according to the user level. - * @return the parameter groups - */ - public AParametersGroup[][] getUIGroups() - { - List<AParametersGroup[]> uiSuperGroups = new ArrayList<AParametersGroup[]>(); - for (AParameterSuperGroup superGroup : superGroups) { - List<AParametersGroup> uiGroups = superGroup.getUIGroups(); - AParametersGroup[] uiGroupsArray = uiGroups.toArray(new AParametersGroup[uiGroups.size()]); - uiSuperGroups.add(uiGroupsArray); - } - AParametersGroup[][] groups = - uiSuperGroups.toArray(new AParametersGroup[uiSuperGroups.size()][]); - return groups; - } - - /** - * Get names of groups of given usage type to display in GUI. - * @param uiUsage UI usage type to select - * @return the group names - */ - public Vector<String> getUIGroupNames(int uiUsage) {return getUIGroupNames(false,uiUsage);} - - /** - * Get names of groups to display in GUI. - * @return the group names - */ - public Vector<String> getUIGroupNames() {return getUIGroupNames(true,0);} - - /** - * Get names of groups to display in GUI. - * @param selectAll true to select all regardless of UI usage - * @param uiUsage ignored if selectAll is true - * @return the group names - */ - private Vector<String> getUIGroupNames(boolean selectAll, int uiUsage) { - Vector<String> v=new Vector<String>(); - AParametersGroup[][] g=getUIGroups(); - for(int i=0;i<g.length;++i) - for(int j=0;j<g[i].length;++j) - if(selectAll || (g[i][j].getUIUsage()==uiUsage)) - v.addElement(g[i][j].getGroupName()); - return v; - } - - /** - * Find parameter group with given name. - * @param groupName name to look for - * @return the group, or null if not found - */ - public AParametersGroup getGroup(String groupName) - { - for (AParameterSuperGroup superGroup : superGroups) { - AParametersGroup group = superGroup.getGroup(groupName); - if (group!=null) return group; - } - return null; - } - - public int getUserLevel() - { - return userLevel; - } - - public AParameter get(String group, String name) - { - AParametersGroup g = getGroup(group); - if(g == null) - { - logger.debug("No group named \"" + group + "\""); - return null; - } - - AParameter p = g.getParameter(name); - if(p == null) - { - logger.debug("No parameter named \"" + group + ":" + name + "\""); - } - - return p; - } - - public AParameter getUnknown(String group, String name) - { - AParametersGroup grp = getGroup(group); - if(grp==null) - return null; - else - return grp.getParameter(name); - } - - /** - * Returns the values of an array of parameters - * (can be ANY order: C1, C2, C3 ...) - */ - public int[] getArray(String groupName, String name, int numEntries) - { - int[] array=new int[numEntries]; - - String baseName=name.substring(0, name.length()-1); - int baseNumber=Integer.parseInt(name.substring(name.length()-1, name.length())); - - for(int i=0; i<numEntries; i++) - array[i]=this.get(groupName, baseName+(baseNumber+i)).getI(); - - return array; - } - - boolean processParameterChangeCommand(String parameterChangeCommand) - { - String parameterName, sValue; - double value; - AParameter parameter=null; - String groupName = ACanvas.getCanvas().getCurrentWindow().getGroupName(); - - for(int i=0; i<AParameter.supportedOperators.length; i++) - { - int index=parameterChangeCommand.indexOf(AParameter.supportedOperators[i]); - - if(index!=-1) - { - parameterName=parameterChangeCommand.substring(0, index).trim(); - AParametersGroup pg = getGroup(groupName); - - parameter=pg.getParameter(parameterName); - - /* AEvent calls listbox initialize in order to change its values from - event to event basis - AEnumeratorParameter.initialize() -> - ACommandProcessor.receive() -> .process() -> - APar.processParameterChangeCommand() - - In case of ETMis - warning 'ETMisCollections=0.0 bad command' when - ATLAS->ETMis group wasn't the active one for a current window. - Following statement however continues if the group tab (ETMis) is - active, so it's not a bad command. - This will have to be dealt with when implementing the keyboard - commands mode of driving Atlantis, it would have to be possible to - change values, etc of group tabs which are not active. It should be - easy as local commands (like ETMisCollections) would say name of - parameter group they belong to. Proper groupName would the only problem. - */ - if(parameter==null) - { - logger.debug("APar: warning: parameter " + parameterName + - " doesn't exist " + "in active group tab " + groupName); - return true; // prevent printing warning 'bad command ...' - - // return false; - used to, hence raising 'bad command ... ' in - // ACommandProcessor.receive(). the same effect. - } - - sValue=parameterChangeCommand.substring(index+AParameter.supportedOperators[i].length(), parameterChangeCommand.length()).trim(); - - if(sValue.equals("")) break; - - try - { - value=Double.parseDouble(sValue); - } - catch(NumberFormatException e) - { - return false; - } - - return parameter.processCommand(AParameter.supportedOperators[i], value); - } - } - - AParametersGroup pg = getGroup(groupName); - - parameterName=parameterChangeCommand.trim(); - parameter=pg.getParameter(parameterName); - if(parameter!=null) - { - if(parameter.getStatus()==true) - parameter.setStatus(false); - else - parameter.setStatus(true); - return true; - } - else - return false; - } - - /** - * Copy parameters from one window to another. - * @param sourceName name of source window - * @param destName name of destination window - */ - public void copyParameters(String sourceName, String destName) - { - for (AParameterSuperGroup superGroup : superGroups) { - superGroup.copyParameters(sourceName, destName); - } - } - - public void copyCurrentGroupLocalsTo(String destinationWindow) - { - if(ACanvas.getCanvas().isValidWindowName(destinationWindow)) - { - AWindow w=ACanvas.getCanvas().getCurrentWindow(); - Vector<AParameter> params=(getGroup(w.getGroupName())).getParameters(userLevel); - - int from=w.getIndex(); - int to=ACanvas.getCanvas().getWindow(destinationWindow).getIndex(); - - for(int i=0; i<params.size(); i++) - { - AParameter p=(AParameter)params.elementAt(i); - - if(p.getScope()==AParameter.LOCAL) - p.copy(from, to); - } - } - else - throw new Error("copyCurrentGroupLocalsTo, unknown: "+destinationWindow); - } - - /** - * selectWindowParameters/restoreWindowParameters methods are used for - * obtaining temporary access to parameters of some window - */ - public void selectWindowParameters(String newWindow) - { - //ACH - this was getting thrown sometimes, and I don't know why... - //if(previousIndex!=-1) - //throw new Error("selectWindowParameters, Try to select twice !?"); - - if(ACanvas.getCanvas().isValidWindowName(newWindow)) - { - previousIndex=getCurrentWindowIndex(); - setCurrentWindowIndex(ACanvas.getCanvas().getWindow(newWindow).getIndex()); - } - else - throw new Error("selectWindowParameters, window: "+newWindow+" , doesn't exist !?"); - } - - /** - * selectWindowParameters/restoreWindowParameters methods are used for - * obtaining temporary access to parameters of some window - */ - public void restoreWindowParameters() - { - if(previousIndex!=-1) - { - setCurrentWindowIndex(previousIndex); - previousIndex=-1; - } - else - throw new Error("restoreWindowParameters: you have nothing to restore !?"); - } - - /** - * @param currentWindowIndex the currentWindowIndex to set - */ - public void setCurrentWindowIndex(int currentWindowIndex) { - this.currentWindowIndex = currentWindowIndex; - } - - /** - * @return the currentWindowIndex - */ - public int getCurrentWindowIndex() { - return currentWindowIndex; - } - - /** - * Add a listener to be informed of parameter changes. - * - * @param listener - */ - public void addParameterChangeListener(AParameterChangeListener listener) { - parameterChangeListeners.add(listener); - } - - /** - * Tell the listeners that a parameter has changed. - */ - @Override - public void parameterChanged(AParameter parameter) { - if(parameter.getName().equals("JetBTagger")){ - this.setDefaultBTaggerValue(parameter); - } - for (AParameterChangeListener listener : parameterChangeListeners) { - listener.parameterChanged(parameter); - } - } - - @Override - public void newEvent(AEvent event) { - // update collection cut listboxes for collection-aware datatypes - updateCollectionsListBoxes(event); - updateBTaggerListBox(event); - } - - /** - * Update collection cut listboxes for collection-aware datatypes. - */ - private void updateCollectionsListBoxes(AEvent event) - { - Hashtable<String,Vector<String>> collections = event.getCollections(); - String listBoxName = null; - Hashtable<Integer, String> listBoxPreviousContents = null; - Vector<String> keys = null; - String[] keysArray = null; - boolean contentsChanged = false; // contents of listbox change watchdog - Set<AEnumeratorParameter> updatedEnumeratorParameters = new HashSet<AEnumeratorParameter>(); - - // note - listBox.initialize() - // if tab containing this particular listbox was active, it didn't - // take effect to set different value by .setI() as default value - // was in this case always the first one added - .initialize() called - // automatically when tabpane is active - // if tabpane wasn't active it worked fine - for (String dataTypeName : collections.keySet()) - { - contentsChanged = false; - listBoxName = dataTypeName + "Collections"; - keys = collections.get(dataTypeName); - AEnumeratorParameter listBox = (AEnumeratorParameter) this.get(dataTypeName, listBoxName); - keysArray = keys.toArray(new String[keys.size()]); - - listBoxPreviousContents = listBox.getValuesHashtable(); - - for(int i = 0; i < listBoxPreviousContents.size(); i++) - { - String item = (String) listBoxPreviousContents.get(new Integer(i)); - if(keys.contains(item) || "All".equals(item)) - { - continue; - } - else - { - contentsChanged = true; - listBox.removeItem(item); - } - } - - for(int i = 0; i < keysArray.length; i++) - { - if(listBoxPreviousContents.containsValue(keysArray[i])) - { - continue; - } - else - { - contentsChanged = true; - listBox.addItem(listBox.size(), keysArray[i]); - } - } - - // if the previous event had completely different collections than - // the current one, 'all' item will be the only one which remained - // after removal (the first loop). then the current (new) collections - // were added in the secold loop and 'all' item was in this case the - // fist, hence the default one - not desired - // solution: if any changes were performed in these two loops - // (contentsChanged variable set to true), the listbox will - // get re-initialised anyway. by removing 'all' and subsequent - // adding it the first collection from the event will be the default - // one and 'all' would be the last item - as desired - if(contentsChanged && !dataTypeName.endsWith("Segment")) - { - listBox.removeItem("All"); - listBox.addItem(listBox.size(), "All"); - listBox.initialize(); - } - updatedEnumeratorParameters.add(listBox); - } // while - // Get the enumerator parameters so we can tell them about the new event. - List<AEnumeratorParameter> collectionParameters = new ArrayList<AEnumeratorParameter>(); - for (AParameterSuperGroup superGroup : superGroups) { - collectionParameters.addAll(superGroup.getCollectionParameters()); - } - for (AEnumeratorParameter listBox : collectionParameters) { - if (!updatedEnumeratorParameters.contains(listBox)) { - listBox.clear(); - listBox.addItem(0, "None"); - listBox.initialize(); - } - } - } // updateCollectionsCutListBoxes() ------------------------------------ - - /** - * Update btagging cut listboxes for available btaggers. - * - * @param event The current event - * - * TODO: Make this independent of context (ie. pass it the name of the listBox to update, plus the values it should use) ? - Tom - */ - private void updateBTaggerListBox(AEvent event) - { - AJetData currentjets = event.getJetData(); - if (currentjets==null) return; - List<String> taggers = currentjets.getBTaggers(); - Set<AEnumeratorParameter> updatedEnumeratorParameters = new HashSet<AEnumeratorParameter>(); - AEnumeratorParameter listBox = (AEnumeratorParameter) this.get("CutsObjects", "JetBTagger"); - - if(taggers.size() == 0) { - listBox.clear(); - listBox.addItem(0, "None"); - } - - for(int i=0; i<taggers.size(); i++) { - listBox.addItem(i, taggers.get(i)); - } - - listBox.initialize(); - updatedEnumeratorParameters.add(listBox); - - } // updateBTaggerListBox() ------------------------------------ - - /** - * Keep a list of popular 'default' values for various b-taggers - * If we don't know about the b-tagger, use a fallback default of 1.0 - * - * @param parameter The current BTagger parameter - */ - public void setDefaultBTaggerValue(AParameter parameter) { - AEventManager eventManager = AEventManager.instance(); - - //Necessary code to stop B-tagging listener when having no-jet-info xml file - AJetData Jetss = eventManager.getCurrentEvent().getJetData(); - if(Jetss == null) - return; - - // Grab the b-taggers from the current Jet Collection - List<String> taggers = eventManager.getCurrentEvent().getJetData().getBTaggers(); - if(taggers.size() == 0) - return; - - // Get the BTagName corresponding to the current selection (ordering!) - // String newTagger = taggers.get(parameter.getI()); - String newTagger = taggers.get(parameter.getI()); - - - if(newTagger.equals(new String("SV0"))){ - get("CutsObjects", "JetBTagweight").setD(5.25); - } - else if(newTagger.equals(new String("SV1"))){ - get("CutsObjects", "JetBTagweight").setD(1.00); - } - else if(newTagger.equals(new String("JetFitterCOMBNN"))){ - get("CutsObjects", "JetBTagweight").setD(2.4); - } - else if(newTagger.equals(new String("IP3D+SV1")) || newTagger.equals(new String("IP3DSV1"))){ - get("CutsObjects", "JetBTagweight").setD(1.55); - } - else if(newTagger.equals(new String("JetFitterTagNN"))){ - get("CutsObjects", "JetBTagweight").setD(1.55); - } - else if(newTagger.equals(new String("IP2D"))){ - get("CutsObjects", "JetBTagweight").setD(1.00); - } - else if(newTagger.equals(new String("IP3D"))){ - get("CutsObjects", "JetBTagweight").setD(1.00); - } - else if(newTagger.equals(new String("SV2"))){ - get("CutsObjects", "JetBTagweight").setD(1.00); - } - else if(newTagger.equals(new String("MV1"))){ - get("CutsObjects", "JetBTagweight").setD(0.601713); - } - else { - get("CutsObjects", "JetBTagweight").setD(1.00); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameter.java deleted file mode 100755 index 31b3ce329c6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameter.java +++ /dev/null @@ -1,107 +0,0 @@ -package atlantis.parameters; - - -import javax.swing.JComponent; - - -/** - * This interface defines all the methods a parameter should have. - */ -public interface AParameter { - // scope constants - int LOCAL=1; - int GLOBAL=2; - - // value type constants - int NO_VALUE=0; - int INT=1; - int FLOAT=2; - - /** All supported supportedOperators */ - static final String[] supportedOperators= {"!=", ">=", ">", "<=", "<", "="}; - - /** Initializes graphics for this parameter. */ - void initialize(); - - /** Checks if the parameters graphics is initialized. */ - boolean isInitialized(); - - /** Copies the value and status from one window to the other. */ - void copy(int from, int to); - - /** Copies the value and status from "window" in all the others. */ - void globalize(int window); - - /** Returns true if parameter is modulus, i.e. sign is irrelevant. */ - boolean isModulus(); - - /** Return NO_VALUE, INT or FLOAT. */ - int getValueType(); - - /** sets the scope to LOCAL or GLOBAL. */ - void setScope(int scope); - - /** Returns the scope of the parameter. */ - int getScope(); - - /** Changes scope after it has originally been set. */ - void changeScope(int scope); - - /** Returns the name of the parameter. */ - String getName(); - - /** returns the screen name of the parameter. */ - String getScreenName(); - - /** Returns the tooltip text. */ - String getToolTip(); - - /** Returns the current operator assigned to parameter. */ - String getOperator(); - - /** Sets the double value for parameter. */ - void setD(double v); - void setI(int v); - - /** Returns the value of the parameter. */ - double getD(); - /** Returns the value of the parameter. */ - int getI(); - /** Returns the value of the parameter. */ - String getValue(); - - /** Sets the parameter's status. */ - void setStatus(boolean status); - - /** Returns the current status. */ - boolean getStatus(); - - /** Returns the graphical component used to display the Name and Status of this parameter. */ - JComponent getNameComponent(); - - /** Returns the graphical component used to display the value of this parameter. */ - JComponent getValueComponent(); - - /** Make synchronisation between the value and status and graphical components. */ - void refresh(); - - /** Returns true if "oper" represents an valid operator for this parameter. */ - boolean validateOperator(String oper); - - /** Returns true if "v" represents a valid value for this parameter. */ - boolean validateValue(double v); - - String getDifferences(String groupName); - - /** Validates and updates the current operator and value. */ - boolean processCommand(String oper, double v); - - /** Returns the user level associated with the parameter. */ - int getUserLevel(); - - /** Returns a String representation of the parameter. */ - String toString(); - - /** Add a parameter change listener. */ - void addParameterChangeListener(AParameterChangeListener listener); -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterChangeListener.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterChangeListener.java deleted file mode 100644 index b65e530b826..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterChangeListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package atlantis.parameters; - -/** - * Used by GUI to listen for changed parameters. - * - * @author waugh - * - */ -public interface AParameterChangeListener { - void parameterChanged(AParameter parameter); -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterConfigReader.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterConfigReader.java deleted file mode 100644 index 8a2a88e9eae..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterConfigReader.java +++ /dev/null @@ -1,114 +0,0 @@ -package atlantis.parameters; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import atlantis.utils.xml.AXMLUtils; - -/** - * Construct AParameter objects from the XML configuration file. - * - * @author waugh - * - */ -public class AParameterConfigReader { - /** - * This function reads any type of parameters. - * @param parameter The Node containing the definition of the parameter. - * @return An AParameter object. - */ - static AParameter readParameter(Node parameter, int groupScope) - { - AParameter par=null; - - // the node name of the parameter decides its type - String type=parameter.getNodeName(); - - // read all the parameter atributes - NamedNodeMap attributes=parameter.getAttributes(); - String fn=AXMLUtils.tryAttribut(attributes, "fn"); - String sn=AXMLUtils.tryAttribut(attributes, "sn"); - String sst=AXMLUtils.tryAttribut(attributes, "st"); - String sisMod=AXMLUtils.tryAttribut(attributes, "isMod"); - String sva=AXMLUtils.tryAttribut(attributes, "va"); - String op=AXMLUtils.tryAttribut(attributes, "op"); - String dop=AXMLUtils.tryAttribut(attributes, "dop"); - String to=AXMLUtils.tryAttribut(attributes, "to"); - String pv=AXMLUtils.tryAttribut(attributes, "pv"); - String tip=AXMLUtils.tryAttribut(attributes, "tip"); - String scopeAtt=AXMLUtils.tryAttribut(attributes, "scope"); - String unitsOfAtt=AXMLUtils.tryAttribut(attributes, "u"); - - // set scope value for this parameter - int scope=groupScope; - if(scopeAtt!=null) - { - if(scopeAtt.equals("LOCAL")) - scope=AParameter.LOCAL; - else if(scopeAtt.equals("GLOBAL")) - scope=AParameter.GLOBAL; - } - - // set user level for this parameter - int ul=-1; - if(!type.equals("LINK")) - ul=Integer.parseInt(AXMLUtils.tryAttribut(attributes, "ul")); - - double va=0; - if(sva!=null) va=Double.parseDouble(sva); - - // set initial status of this parameter - boolean st=false; - if(sst!=null) - if(sst.equals("ON")) - st=true; - - boolean isMod=false; - if(sisMod!=null) - if(sisMod.equals("YES")) - isMod=true; - - int unitsOf=0; - if(unitsOfAtt!=null) - unitsOf=Integer.parseInt(unitsOfAtt); - - // create an AParameter object based on its type - if(type.equals("LINK")) - par=new ALinkParameter(to); - else if(type.equals("COLOR")) - par=new AColorParameter(fn, sn, tip, pv, va, false, st, ul, scope); - else if(type.equals("SCOLOR")) - par=new AColorParameter(fn, sn, tip, pv, va, true, st, ul, scope); - else if(type.equals("ENUM")) - par=new AEnumeratorParameter(fn, sn, tip, pv, va, false, st, ul, scope); - else if(type.equals("SENUM")) - par=new AEnumeratorParameter(fn, sn, tip, pv, va, true, st, ul, scope); - else if(type.equals("ICUT")) - par=new ACutParameter(fn, sn, tip, pv, AParameter.INT, va, op, dop, false, st, isMod, ul, scope, unitsOf); - else if(type.equals("SICUT")) - par=new ACutParameter(fn, sn, tip, pv, AParameter.INT, va, op, dop, true, st, isMod, ul, scope, unitsOf); - else if(type.equals("FCUT")) - par=new ACutParameter(fn, sn, tip, pv, AParameter.FLOAT, va, op, dop, false, st, isMod, ul, scope, unitsOf); - else if(type.equals("SFCUT")) - par=new ACutParameter(fn, sn, tip, pv, AParameter.FLOAT, va, op, dop, true, st, isMod, ul, scope, unitsOf); - else if(type.equals("FLOAT")) - par=new ANumberParameter(fn, sn, tip, pv, AParameter.FLOAT, va, false, st, isMod, ul, scope, unitsOf); - else if(type.equals("SFLOAT")) - par=new ANumberParameter(fn, sn, tip, pv, AParameter.FLOAT, va, true, st, isMod, ul, scope, unitsOf); - else if(type.equals("INT")) - par=new ANumberParameter(fn, sn, tip, pv, AParameter.INT, (int)va, false, st, isMod, ul, scope, unitsOf); - else if(type.equals("SINT")) - par=new ANumberParameter(fn, sn, tip, pv, AParameter.INT, (int)va, true, st, isMod, ul, scope, unitsOf); - else if(type.equals("LINT")) - par=new AListIntegerParameter(fn, sn, tip, pv, (int)va, false, st, ul, scope); - else if(type.equals("SLINT")) - par=new AListIntegerParameter(fn, sn, tip, pv, (int)va, true, st, ul, scope); - else if(type.equals("STATUS")) - par=new AStatusParameter(fn, sn, tip, st, ul, scope); - else if(type.equals("StatusRoot")) - par = new AStatusRootParameter(parameter, fn, sn, tip, ul, scope); - else if(type.equals("StatusGroup")) - par = new AStatusGroupParameter(parameter, fn, sn, tip, ul, scope); - return par; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterData.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterData.java deleted file mode 100644 index 0abcdf85799..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterData.java +++ /dev/null @@ -1,202 +0,0 @@ -package atlantis.parameters; - -/** - * Encapsulates the per-window data belonging to a parameter. - * - * @author waugh - * - */ -public class AParameterData { - private AParameterState[] state; - private AParameterState[] defaultState; - - protected final APar parameterStore = APar.instance(); - - /** - * Create AParameterData for given number of windows. - * @param numWindows number of windows in the canvas - */ - AParameterData(int numWindows) { - state = new AParameterState[numWindows]; - defaultState = new AParameterState[numWindows]; - initializeParameterState(state); - initializeParameterState(defaultState); - } - - /** - * Initialize arrays of AParameterState objects. - * @param state - */ - private static void initializeParameterState(AParameterState[] state) { - for (int i=0; i<state.length; ++i) { - state[i] = new AParameterState(); - } - } - - /** - * Return the state of this parameter for a given window. - * @param windowIndex index of window - * @return the state - */ - AParameterState getState(int windowIndex) { - return state[windowIndex]; - } - - /** - * Get value of parameter for current window. - * @return value - */ - public double getValue() { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - return getValue(currentWindowIndex); - } - - /** - * Get value of parameter for given window. - * @param windowIndex index of window - * @return value - */ - public double getValue(int windowIndex) { - return state[windowIndex].value; - } - - /** - * Set value of parameter for current window. - * @param value - */ - public void setValue(double value) { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - setValue(currentWindowIndex,value); - } - - /** - * Set value of parameter for given window. - * @param windowIndex index of window - * @param value - */ - public void setValue(int windowIndex, double value) { - this.state[windowIndex].value = value; - } - - /** - * Get status (whether parameter is enabled) for current window. - * @return true if enabled - */ - public boolean getStatus() { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - return getStatus(currentWindowIndex); - } - - /** - * Get status (whether parameter is enabled) for given window. - * @param windowIndex index of window - * @return true if enabled - */ - public boolean getStatus(int windowIndex) { - return state[windowIndex].status; - } - - /** - * Set status (whether parameter is enabled) for current window. - * @param status true to enable - */ - public void setStatus(boolean status) { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - setStatus(currentWindowIndex,status); - } - - /** - * Set status (whether parameter is enabled) for given window). - * @param windowIndex index of window - * @param status true to enable - */ - public void setStatus(int windowIndex, boolean status) { - this.state[windowIndex].status = status; - } - - /** - * Get operator for current window. - * @return operator - */ - public String getOperator() { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - return getOperator(currentWindowIndex); - } - - /** - * Get operator for given window. - * @param windowIndex index of window - * @return operator - */ - public String getOperator(int windowIndex) { - return state[windowIndex].operator; - } - - /** - * Set operator for current window. - * @param operator - */ - public void setOperator(String operator) { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - setOperator(currentWindowIndex,operator); - } - - /** - * Set operator for given window. - * @param windowIndex index of window - * @param operator - */ - public void setOperator(int windowIndex, String operator) { - this.state[windowIndex].operator = operator; - } - - /** - * Copy values from one window to another. - * @param from index of source window - * @param to index of destination window - */ - public void copy(int from, int to) { - if (to!=from) state[to] = state[from].copy(); - } - - /** - * Save current values for each window to be restored later. - */ - public void saveDefaults() { - int numWindows = state.length; - for (int iWindow = 0; iWindow<numWindows; ++iWindow) { - defaultState[iWindow] = state[iWindow].copy(); - } - } - - /** - * Restore values for each window from saved values. - */ - public void restoreDefaults() { - int numWindows = state.length; - for (int iWindow = 0; iWindow<numWindows; ++iWindow) { - state[iWindow] = defaultState[iWindow].copy(); - } - } - - /** - * This function is called for GLOBAL parameters to apply the value in all - * windows. - */ - public void globalize() - { - int currentWindowIndex = parameterStore.getCurrentWindowIndex(); - globalize(currentWindowIndex); - } - - /** - * This function is called for GLOBAL parameters to apply the value in all - * windows. - */ - public void globalize(int window) - { - int numWindows = state.length; - for (int i = 0; i < numWindows; i++) - copy(window, i); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterState.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterState.java deleted file mode 100644 index 0c93ee31a72..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterState.java +++ /dev/null @@ -1,38 +0,0 @@ -package atlantis.parameters; - -/** - * Encapsulate the state (value, status, operator) of a given parameter for a - * single window. - * - * @author waugh - * - */ -public class AParameterState implements Cloneable { - double value; - boolean status; - String operator = ""; - - /** - * Make a new AParameterState with default values. - */ - AParameterState() {} - - /** - * Make a new AParameterState that is a copy of another. - * Other classes should use the public copy() method. - * @param from the object to copy - */ - private AParameterState(AParameterState from) { - this.value = from.value; - this.status = from.status; - this.operator = from.operator; - } - - /** - * Make a new AParameterState that is a copy of this one. - * @return copy - */ - public AParameterState copy() { - return new AParameterState(this); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterSuperGroup.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterSuperGroup.java deleted file mode 100644 index fe01d3b3d7b..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterSuperGroup.java +++ /dev/null @@ -1,241 +0,0 @@ -package atlantis.parameters; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * A supergroup of parameters, i.e. a group of groups, corresponding to one of the - * top-level tabs in the GUI, e.g. "Projections" or "Data". - * - * @author waugh - * - */ -public class AParameterSuperGroup implements AParameterChangeListener { - private String name; - private String toolTip; - private int userLevel; - - private Map<String,AParametersGroup> parameterGroups = new HashMap<String,AParametersGroup>(); - private List<AParametersGroup> uiGroups = new ArrayList<AParametersGroup>(); - /** Keep track of enumerator parameters so we can tell them about new events. */ - private final List<AEnumeratorParameter> collectionParameters = new ArrayList<AEnumeratorParameter>(); - - private List<AParameterChangeListener> parameterChangeListeners = new ArrayList<AParameterChangeListener>(); - - private AParameterSuperGroup() {} - - static AParameterSuperGroup readSuperGroup(Node node, int applicationUserLevel) { - AParameterSuperGroup superGroup = new AParameterSuperGroup(); - superGroup.name = node.getAttributes().getNamedItem("name").getNodeValue(); - superGroup.toolTip = node.getAttributes().getNamedItem("toolTip").getNodeValue(); - String sUserLevel = node.getAttributes().getNamedItem("userLevel").getNodeValue(); - superGroup.userLevel = Integer.parseInt(sUserLevel); - superGroup.readGroups(node,applicationUserLevel); - return superGroup; - } - - /** - * Populate the lists of parameter groups and UI groups. - * @param superGroupNode - */ - private void readGroups(Node superGroupNode, int applicationUserLevel) { - NodeList groups = superGroupNode.getChildNodes(); - for (int i = 0; i < groups.getLength(); i++) - { - Node group = groups.item(i); - if (group.getNodeType() == Node.ELEMENT_NODE) - { - // here we have a <Group> element and create an AParametersGroup object from it - AParametersGroup g = readGroup(group); - - String gName = g.getGroupName(); - if (parameterGroups.containsKey(gName)) - throw new Error("Duplicate definition of group " + gName); - parameterGroups.put(gName, g); - int guiUsage = g.getUIUsage(); - - if ( ( (guiUsage == AParametersGroup.TABLE) || - (guiUsage == AParametersGroup.PROJECTION) - || (guiUsage == AParametersGroup.BRAIN_TEST) - ) && (g.getUserLevel() <= userLevel)) - uiGroups.add(g); - } - } - - } - - private AParametersGroup readGroup(Node group) - { - // first we read all the attributes - NamedNodeMap attributes=group.getAttributes(); - String groupName=attributes.getNamedItem("name").getNodeValue(); - String screenName=attributes.getNamedItem("sname").getNodeValue(); - String guiUsageAttribut=attributes.getNamedItem("guiUsage").getNodeValue(); - String scopeAttribut=attributes.getNamedItem("scope").getNodeValue(); - int ul=Integer.parseInt(attributes.getNamedItem("userLevel").getNodeValue()); - String groupToolTip=attributes.getNamedItem("toolTip").getNodeValue(); - - // set guiUsage value for this group - int guiUsage; - if(guiUsageAttribut.equals("TABLE")) - guiUsage=AParametersGroup.TABLE; - else if(guiUsageAttribut.equals("PROJECTION")) - guiUsage=AParametersGroup.PROJECTION; - else if(guiUsageAttribut.equals("BRAIN_TEST")) - guiUsage=AParametersGroup.BRAIN_TEST; - else - guiUsage=AParametersGroup.NO_USE; - - // set scope value for this group - int scope; - if(scopeAttribut.equals("LOCAL")) - scope=AParameter.LOCAL; - else if(scopeAttribut.equals("GLOBAL")) - scope=AParameter.GLOBAL; - else - scope=AParameter.GLOBAL; - - // create an AParametersGroup object based on the attributes - AParametersGroup thisGroup=new AParametersGroup(groupName, screenName, guiUsage, scope, ul, groupToolTip); - - // report error if no parameters in this group - NodeList childrens=group.getChildNodes(); - if(childrens==null) throw new Error("this group contains no parameters"); - int childrensCount=childrens.getLength(); - if(childrensCount==0) throw new Error("this group contains no parameters"); - - // read all the parameters of this group recursively - for(int i=0; i<childrensCount; i++) - { - Node child=childrens.item(i); - if(child.getNodeType()==Node.ELEMENT_NODE) - { - // for each parameter, create an object (either ACommnad or AParameter) - // and add it into the to be returned AParametersGroup object - String childName=child.getNodeName(); - if(childName.equals("Command")) { - ACommand c=readCommand(child); - if(c!=null) thisGroup.add(c); - } - else { - AParameter parameter = AParameterConfigReader.readParameter(child, scope); - parameter.addParameterChangeListener(this); - thisGroup.add(parameter); - if (parameter instanceof AEnumeratorParameter && - parameter.getScreenName().endsWith("Collections")) { - collectionParameters.add((AEnumeratorParameter)parameter); - } - } - } - } - - return thisGroup; - } - - - - private ACommand readCommand(Node commandNode) - { - NamedNodeMap attributes=commandNode.getAttributes(); - - String name=attributes.getNamedItem("name").getNodeValue(); - String command=attributes.getNamedItem("command").getNodeValue(); - String toolTip=attributes.getNamedItem("toolTip").getNodeValue(); - String userLevel=attributes.getNamedItem("ul").getNodeValue(); - if(Integer.parseInt(userLevel)<=this.userLevel) - return new ACommand(name, command, toolTip); - else - return null; - } - - /** - * Get the name of the supergroup. - * @return the name - */ - public String getName() {return name;} - - /** - * Get the tool tip for this supergroup. - * @return the tool tip - */ - public String getToolTip() {return toolTip;} - - /** - * Get the user level of this supergroup. - * @return the user level - */ - public int getUserLevel() {return userLevel;} - - /** - * Get parameter group with given name. - * @param name name of group - * @return parameter group - */ - public AParametersGroup getGroup(String name) {return parameterGroups.get(name);} - - /** - * Get the parameter groups that are displayed in the UI in the current user level. - * @return list of parameter groups - */ - public List<AParametersGroup> getUIGroups() {return uiGroups;} - - /** - * Tell the listeners that a parameter has changed. - */ - @Override - public void parameterChanged(AParameter parameter) { - for (AParameterChangeListener listener : parameterChangeListeners) { - listener.parameterChanged(parameter); - } - } - - public Map<? extends String, ? extends AParametersGroup> getParameterGroups() { - return parameterGroups; - } - - public Collection<? extends AEnumeratorParameter> getCollectionParameters() { - return collectionParameters; - } - - /** - * Add a listener to be informed of parameter changes. - * - * @param listener - */ - public void addParameterChangeListener(AParameterChangeListener listener) { - this.parameterChangeListeners.add(listener); - } - - /** - * Restore all groups in supergroup to defaults. - */ - public void restoreDefaults() { - for (AParametersGroup group : parameterGroups.values()) { - group.restoreDefaults(); - } - } - - /** - * Copy parameters from one window to another. - * @param sourceName name of source window - * @param destName name of destination window - */ - public void copyParameters(String sourceName, String destName) { - for (AParametersGroup group : parameterGroups.values()) { - group.copyParameters(sourceName, destName); - } - } - - public void resolveLinkParameters() { - for (AParametersGroup group : parameterGroups.values()) { - group.resolveLinkParameters(); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParameterUtilities.java b/graphics/AtlantisJava/src/atlantis/parameters/AParameterUtilities.java deleted file mode 100644 index 7dada86fe69..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParameterUtilities.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * - */ -package atlantis.parameters; - -import atlantis.utils.AMath; - -/** - * Mathematical utility methods that act on Parameters. - * Moved from atlantis.utils.AMath to reduce dependencies of utils on other packages. - * - * @author waugh - * - */ -public class AParameterUtilities { - - private final static APar parameterStore = APar.instance(); - private final static AParameter xVertexPar = parameterStore.get("Event", "XVtx"); - private final static AParameter yVertexPar = parameterStore.get("Event", "YVtx"); - private final static AParameter zVertexPar = parameterStore.get("Event", "ZVtx"); - - /** - * Get coordinates of event vertex. - * - * @return (x,y,z) of vertex - */ - public static double[] getPrimaryVertex() - { - double[] primaryVertex = new double[3]; - primaryVertex[0] = parameterStore.get("Event", "XVtx").getD(); - primaryVertex[1] = parameterStore.get("Event", "YVtx").getD(); - primaryVertex[2] = parameterStore.get("Event", "ZVtx").getD(); - return primaryVertex; - } - - /** - * Returns phi with respect to the primary vertex. - * @param x double x coordinate - * @param y double y coordinate - * @return double phi - */ - public static double phi(double x, double y) { - double phi = Math.atan2(y-yVertexPar.getD(), x-xVertexPar.getD()); - if (phi < 0) phi += 2.*Math.PI; - return Math.toDegrees(phi); - } - - /** - * Returns eta with respect to the primary vertex. - * @param z double z coordinate - * @param rho double rho coordinate - * @return double eta - */ - public static double eta(double z, double rho) - { - return AMath.etaAbs(z - zVertexPar.getD(), rho); - } - - public static double getPhiStereo(double rho, double phi, double z) - { - AParameter stereoAnglePar = parameterStore.get("SiCluster", "Stereo"); - if(!stereoAnglePar.getStatus()) - { - return phi; - } - double stereoAngle = stereoAnglePar.getI() * 0.04; - return phi + stereoAngle * (z-parameterStore.get("Event", "ZVtx").getD()) / rho; - } - - /** - * Get the sign of the rho coordinate based on the x and y coordinates and - * the phi value set by the user. - * @param x double x coordinate - * @param y double y coordinate - * @return int sign of rho (-1 or +1) - */ - public static int getRhoSign(double x, double y) { - return getRhoSign(Math.atan2(y, x)); - } - - /** - * Get the sign of the rho coordinate based on the phi coordinate and - * the phi value set by the user. - * @param phi double phi coordinate - * @return int sign of rho (-1 or +1) - */ - private static int getRhoSign(double phi) { - int sign; - if (phi < 0.) phi += 2.*Math.PI; - - double phiMid = Math.toRadians(parameterStore.get("RZ", "Phi").getD()); - double phiDiff = Math.abs(phi-phiMid); - - if(phiDiff <= Math.PI/2.|| phiDiff > 3*Math.PI/2.) { - sign = 1; - } else { - sign = -1; - } - return sign; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AParametersGroup.java b/graphics/AtlantisJava/src/atlantis/parameters/AParametersGroup.java deleted file mode 100755 index eeadb9d3183..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AParametersGroup.java +++ /dev/null @@ -1,157 +0,0 @@ -package atlantis.parameters; - -import atlantis.canvas.ACanvas; -import java.util.*; - -/** - * This class is used to store a set of parameters. Provides functions for - * fast searching of a parameter by its name. - */ -public class AParametersGroup { - public static final int NO_USE=0; - public static final int TABLE=1; - public static final int PROJECTION=2; - public static final int BRAIN_TEST=3; - - private String name; - private String screenName; - private String toolTip; - private int scope; - private int guiUsage; - private int userLevel; - - private Vector<AParameter> parametersVector = new Vector<AParameter>(); - private HashMap<String, AParameter> parametersMap = new HashMap<String, AParameter>(); - private Vector<ACommand> commandsVector = new Vector<ACommand>(); - - public AParametersGroup(String name, String screenName, int guiUsage, - int scope, int userLevel, String toolTip) { - - this.name=name; - - if(!screenName.trim().equals("")) - this.screenName=screenName; - else - this.screenName=name; - - this.guiUsage=guiUsage; - this.scope=scope; - this.userLevel=userLevel; - this.toolTip=toolTip; - } - - public void restoreDefaults() { - Enumeration<AParameter> parameters = parametersVector.elements(); - while(parameters.hasMoreElements()) { - AParameter p = parameters.nextElement(); - if(p instanceof AAbstractParameter) - ((AAbstractParameter)p).restoreDefaults(); - } - } - - - private void addToMap(AParameter p) { - if(parametersMap.containsKey(p.getName())) - throw new Error("Duplicate definition of parameter full name "+p.getName()); - - parametersMap.put(p.getName(), p); - } - - public void add(AParameter p) { - parametersVector.addElement(p); - if(!(p instanceof ALinkParameter)) - addToMap(p); - } - - public void add(ACommand c) { - for(int i=0; i<commandsVector.size(); i++) { - ACommand command = commandsVector.elementAt(i); - if(command.getName().equals(c.getName())) - throw new Error("Duplicate definition of command "+c.getName()); - } - commandsVector.addElement(c); - } - - public int getScope() { - return scope; - } - - public String getGroupName() { - return name; - } - - public String getScreenName() { - return screenName; - } - - public String getToolTip() { - return toolTip; - } - - public int getUIUsage() { - return guiUsage; - } - - public int getUserLevel() { - return userLevel; - } - - public ACommand[] getCommands() { - ACommand[] commands=new ACommand[commandsVector.size()]; - - for(int i=0; i<commands.length; i++) - commands[i]=commandsVector.elementAt(i); - - return commands; - } - - public Vector<AParameter> getParameters(int userLevel) { - Vector<AParameter> v=new Vector<AParameter>(parametersVector.size()); - - for(int i=0; i<parametersVector.size(); i++) { - AParameter p = parametersVector.elementAt(i); - if(p.getUserLevel()<=userLevel) - v.addElement(p); - } - - return v; - } - - public AParameter getParameter(String name) { - if(parametersMap.get(name)!=null) - return parametersMap.get(name); - // if under group "Data", should find the parameter in the whole tree - else if(parametersMap.get("Status")!=null){ - return ((AStatusRootParameter)parametersMap.get("Status")).getParameter(name); - } - else - return null; - } - - /** - * Copy parameters from one window to another. - * @param sourceName name of source window - * @param destName name of destination window - */ - public void copyParameters(String sourceName, String destName) { - int source=ACanvas.getCanvas().getWindow(sourceName).getIndex(); - int dest=ACanvas.getCanvas().getWindow(destName).getIndex(); - - for(int i=0; i<parametersVector.size(); i++) { - AParameter p = parametersVector.elementAt(i); - if(p.getScope()==AParameter.LOCAL) - p.copy(source, dest); - } - } - - public void resolveLinkParameters() { - for(int i=0; i<parametersVector.size(); i++) { - AParameter p = parametersVector.elementAt(i); - if(p instanceof ALinkParameter) { - ((ALinkParameter)p).solveLink(); - addToMap(p); - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AStatusGroupParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AStatusGroupParameter.java deleted file mode 100755 index 59bc40f1fc2..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AStatusGroupParameter.java +++ /dev/null @@ -1,213 +0,0 @@ -package atlantis.parameters; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import javax.swing.JComponent; -import java.util.ArrayList; -import java.awt.Color; -import hep.wired.util.TristateCheckBox; - -import atlantis.gui.ACheckNode; -import atlantis.gui.ACheckBox; - -/** - * Created on 16 March 2005, 16:15 - * - * @author Qiang Lu - */ -public class AStatusGroupParameter extends AAbstractParameter -{ - private ArrayList<AParameter> parameterNodeList; - - private ACheckNode statusGroupNode; - - /** Creates a new instance of AStatusGroupParameter */ - AStatusGroupParameter(Node statusGroup, String name, String screenName, String toolTip, int userLevel, int scope) - { - super(name, screenName, toolTip, AParameter.NO_VALUE, 0, null, null, false, false, - false, userLevel, scope, AAbstractParameter.NOTHING); - - // get child element of statusGroup - NodeList childrens = statusGroup.getChildNodes(); - // report error if no parameters - if (childrens == null) - throw new Error("StatusGroup element contains no parameters"); - int childrensCount = childrens.getLength(); - if (childrensCount == 0) - throw new Error("StatusGroup element contains no parameters"); - - // create an AParameter object for each node under statusGroup - // and add them into parameterNodeList - parameterNodeList = new ArrayList<AParameter>(); - for (int i = 0; i < childrensCount; i++) - { - Node child = childrens.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) - { - // here we have a <StatusGroup> or <Status> element - parameterNodeList.add(AParameterConfigReader.readParameter(child, scope)); - } - } - } - - public void initialize() - { - super.initialize(); - - // create the tree node using the <StatusGroup> element - TristateCheckBox groupCheckBox = new TristateCheckBox(screenName); - groupCheckBox.setBackground(new Color(204, 204, 204)); - if (getScope() == LOCAL) - groupCheckBox.setForeground(Color.black); - else - groupCheckBox.setForeground(Color.blue); - - groupCheckBox.setToolTipText(toolTip); - statusGroupNode = new ACheckNode(groupCheckBox, false, ACheckNode.MULTI_SELECTION, this); - - for (AParameter aNodeParameter : parameterNodeList) - { - aNodeParameter.initialize(); - if (aNodeParameter instanceof AStatusParameter) - { - if (aNodeParameter.getUserLevel() <= APar.instance().getUserLevel()) - { - ACheckBox statusCheckBox = ((AStatusParameter) aNodeParameter).getCheckBox(); - ACheckNode aNode = new ACheckNode(statusCheckBox, statusCheckBox.isSelected(), ACheckNode.SINGLE_SELECTION, aNodeParameter); - statusGroupNode.add(aNode); - } - } - else if (aNodeParameter instanceof AStatusGroupParameter) - { - statusGroupNode.add(((AStatusGroupParameter) aNodeParameter).getCheckNode()); - } - } - } - - public JComponent getValueComponent() - { - return null; - } - - public ACheckNode getCheckNode() - { - return statusGroupNode; - } - - ArrayList<AParameter> getParameterList() - { - return parameterNodeList; - } - - public AParameter getParameter(String name) - { - for (AParameter aNodeParameter : parameterNodeList) - { - if (aNodeParameter instanceof AStatusParameter) - { - if (aNodeParameter.getName().equals(name)) - return aNodeParameter; - } - else if (((AStatusGroupParameter) aNodeParameter).getParameter(name) != null) - { - return ((AStatusGroupParameter) aNodeParameter).getParameter(name); - } - } - return null; - } - - public AParameter getGroupParameter(String name) - { - if(getName().equals(name)) - return this; - for (AParameter aNodeParameter : parameterNodeList) - { - if (aNodeParameter instanceof AStatusGroupParameter) - { - if (((AStatusGroupParameter) aNodeParameter).getGroupParameter(name) != null) - { - return ((AStatusGroupParameter) aNodeParameter).getGroupParameter(name); - } - } - } - return null; - } - - public boolean getStatus() - { - return statusGroupNode.isSelected(); - } - - public void setStatus(boolean status) - { - for (AParameter aNodeParameter : parameterNodeList) - { - aNodeParameter.setStatus(status); - } - } - - public void refresh() - { - _refresh(); - fireParameterChanged(); - } - - public void setD(double v) - { - throw new IllegalArgumentException("StatusGroupParameter hase no value"); - } - - public void setI(int v) - { - throw new IllegalArgumentException("StatusGroupParameter hase no value"); - } - - public void saveChildrenDefaults() - { - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - if(aNodeAbstractParameter instanceof AStatusGroupParameter) - ((AStatusGroupParameter)aNodeAbstractParameter).saveChildrenDefaults(); - else - ((AStatusParameter)aNodeAbstractParameter).saveDefaults(); - } - } - - public void restoreDefaults() - { - super.restoreDefaults(); - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - aNodeAbstractParameter.restoreDefaults(); - } - } - - public void copy(int from, int to) - { - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - aNodeAbstractParameter.copy(from, to); - } - } - - public String getDifferences(String groupName) - { - StringBuffer ret = new StringBuffer(); - - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - if(aNodeAbstractParameter instanceof AStatusGroupParameter) - ret.append(((AStatusGroupParameter)aNodeAbstractParameter).getDifferences(groupName)); - else - ret.append(aNodeAbstractParameter.getDifferences(groupName)); - } - - return ret.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AStatusParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AStatusParameter.java deleted file mode 100755 index ad42a168db9..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AStatusParameter.java +++ /dev/null @@ -1,58 +0,0 @@ -package atlantis.parameters; - -import javax.swing.JLabel; -import javax.swing.LookAndFeel; -import javax.swing.JComponent; - -/** - * A parameter representing an on/off value. Corresponds to an ACheckBox in the GUI. - */ -public class AStatusParameter extends AAbstractParameter -{ - private JLabel valueLabel; - - public AStatusParameter(String name, String screenName, String toolTip, - boolean status, int userLevel, int scope) - { - super(name, screenName, toolTip, NO_VALUE, 0, null, null, true, - status, false, userLevel, scope, NOTHING); - } - - - public void setD(double v) - { - throw new IllegalArgumentException("StatusParameter has no value"); - } - - - public void setI(int v) - { - throw new IllegalArgumentException("StatusParameter has no value"); - } - - - public void initialize() - { - super.initialize(); - valueLabel = new JLabel(); - valueLabel.setOpaque(true); - valueLabel.setToolTipText(toolTip); - LookAndFeel.installColorsAndFont(valueLabel, "CheckBox.background", - "CheckBox.foreground", - "CheckBox.font"); - } - - - public JComponent getValueComponent() - { - return valueLabel; - } - - - public void refresh() - { - _refresh(); - fireParameterChanged(); - } - -} // class AStatusParameter ================================================= diff --git a/graphics/AtlantisJava/src/atlantis/parameters/AStatusRootParameter.java b/graphics/AtlantisJava/src/atlantis/parameters/AStatusRootParameter.java deleted file mode 100755 index fbbf4f40448..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/AStatusRootParameter.java +++ /dev/null @@ -1,435 +0,0 @@ -package atlantis.parameters; - -import hep.wired.util.TristateCheckBox; - -import java.awt.Color; -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Iterator; - -import javax.swing.JComponent; -import javax.swing.JPopupMenu; -import javax.swing.JTree; -import javax.swing.ToolTipManager; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import atlantis.utils.AUtilities; -import atlantis.gui.ACheckBox; -import atlantis.gui.ACheckNode; -import atlantis.gui.AParametersTable; -import atlantis.gui.ATreeCellRenderer; - -/** - * AStatusRootParameter.java - * - * Created on 14 March 2005, 17:49 - * - * @author Qiang Lu - */ -public class AStatusRootParameter extends AAbstractParameter -{ - private ArrayList<AParameter> parameterNodeList; - - private JTree statusTree; - - private ACheckNode statusRootNode; - - /** Creates a new instance of AStatusGroupParameter */ - AStatusRootParameter(Node statusRoot, String name, String screenName, String toolTip, int userLevel, int scope) - { - super(name, screenName, toolTip, AParameter.NO_VALUE, 0, null, null, false, false, - false, userLevel, scope, AAbstractParameter.NOTHING); - // get child element of statusRoot - NodeList childrens = statusRoot.getChildNodes(); - // report error if no parameters - if (childrens == null) - throw new Error("this group contains no parameters"); - int childrensCount = childrens.getLength(); - if (childrensCount == 0) - throw new Error("this group contains no parameters"); - - // create an AParameter object for each node under statusRoot - // and add them into parameterNodeList - parameterNodeList = new ArrayList<AParameter>(); - for (int i = 0; i < childrensCount; i++) - { - Node child = childrens.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) - { - // here we have a <StatusGroup> or <Status> element - parameterNodeList.add(AParameterConfigReader.readParameter(child, scope)); - } - } - } - - public void initialize() - { - super.initialize(); - - // create the root node of the tree using the <StatusRoot> element - TristateCheckBox rootCheckBox = new TristateCheckBox(screenName); - rootCheckBox.setBackground(new Color(204, 204, 204)); - if (getScope() == LOCAL) - rootCheckBox.setForeground(Color.black); - else - rootCheckBox.setForeground(Color.blue); - - rootCheckBox.setToolTipText(toolTip); - statusRootNode = new ACheckNode(rootCheckBox, false, ACheckNode.MULTI_SELECTION, this); - for (AParameter aNodeParameter : parameterNodeList) - { - aNodeParameter.initialize(); - if (aNodeParameter instanceof AStatusParameter) - { - if (aNodeParameter.getUserLevel() <= APar.instance().getUserLevel()) - { - ACheckBox statusCheckBox = ((AStatusParameter) aNodeParameter).getCheckBox(); - ACheckNode aNode = new ACheckNode(statusCheckBox, statusCheckBox.isSelected(), ACheckNode.SINGLE_SELECTION, aNodeParameter); - statusRootNode.add(aNode); - } - } - else if (aNodeParameter instanceof AStatusGroupParameter) - { - statusRootNode.add(((AStatusGroupParameter) aNodeParameter).getCheckNode()); - } - } - - statusTree = new JTree(statusRootNode); - statusTree.setBackground(new Color(204, 204, 204)); - statusTree.setCellRenderer(new ATreeCellRenderer()); - statusTree.addMouseListener(new NodeSelectionListener(statusTree)); - ToolTipManager.sharedInstance().registerComponent(statusTree); - } - - public JComponent getValueComponent() - { - return null; - } - - public JComponent getNameComponent() - { - return statusTree; - } - - ArrayList<AParameter> getParameterList() - { - return parameterNodeList; - } - - public AParameter getParameter(String name) - { - for (AParameter aNodeParameter : parameterNodeList) - { - if (aNodeParameter instanceof AStatusParameter) - { - if (aNodeParameter.getName().equals(name)) - return aNodeParameter; - } - else if (((AStatusGroupParameter) aNodeParameter).getParameter(name) != null) - { - return ((AStatusGroupParameter) aNodeParameter).getParameter(name); - } - } - return null; - } - - public AParameter getGroupParameter(String name) - { - if(!isInitialized()) - initialize(); - - if(getName().equals(name)) - return this; - for (AParameter aNodeParameter : parameterNodeList) - { - if (aNodeParameter instanceof AStatusGroupParameter) - { - if (((AStatusGroupParameter) aNodeParameter).getGroupParameter(name) != null) - { - return ((AStatusGroupParameter) aNodeParameter).getGroupParameter(name); - } - } - } - return null; - } - - public boolean getStatus() - { - return statusRootNode.isSelected(); - } - - public void setStatus(boolean status) - { - for (AParameter aNodeParameter : parameterNodeList) - { - aNodeParameter.setStatus(status); - } - } - - public void refresh() - { - _refresh(); - fireParameterChanged(); - } - - public void setD(double v) - { - throw new IllegalArgumentException("StatusRootParameter hase no value"); - } - - public void setI(int v) - { - throw new IllegalArgumentException("StatusRootParameter hase no value"); - } - - public void saveChildrenDefaults() - { - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - if(aNodeAbstractParameter instanceof AStatusGroupParameter) - ((AStatusGroupParameter)aNodeAbstractParameter).saveChildrenDefaults(); - else - ((AStatusParameter)aNodeAbstractParameter).saveDefaults(); - } - } - - public void restoreDefaults() - { - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - aNodeAbstractParameter.restoreDefaults(); - } - if(statusTree != null) - { - for (int i = 1; i < statusTree.getRowCount(); i++) - statusTree.collapseRow(i); - } - } - - public void copy(int from, int to) - { - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - aNodeAbstractParameter.copy(from, to); - } - } - - public String getDifferences(String groupName) - { - StringBuffer ret = new StringBuffer(); - - for (AParameter aNodeParameter : parameterNodeList) - { - AAbstractParameter aNodeAbstractParameter = (AAbstractParameter) aNodeParameter; - if(aNodeAbstractParameter instanceof AStatusGroupParameter) - ret.append(((AStatusGroupParameter)aNodeAbstractParameter).getDifferences(groupName)); - else - ret.append(((AStatusParameter)aNodeAbstractParameter).getDifferences(groupName)); - } - - return ret.toString(); - } - - public class NodeSelectionListener extends MouseAdapter - { - private JTree tree; - - private int offsetX; - private int offsetY; - - NodeSelectionListener(JTree tree) - { - this.tree = tree; - offsetX = 0; - offsetY = 0; - } - - public void setOffset(int x, int y) - { - offsetX = x; - offsetY = y; - } - - public int getOffsetX() - { - return offsetX; - } - - public int getOffsetY() - { - return offsetY; - } - - public void mousePressed(MouseEvent e) - { - if (AUtilities.isRightMouseButton(e)) - { - AParameter clickedPar = null; - int x = e.getX(); - int y = e.getY(); - int row = tree.getRowForLocation(x, y); - TreePath path = tree.getPathForRow(row); - if (path != null) - { - Object clickedNode = path.getLastPathComponent(); - if (clickedNode instanceof ACheckNode) - { - ACheckNode node = (ACheckNode) clickedNode; - clickedPar = node.getParameter(); - } - - final AParameter effectPar = clickedPar; - if(effectPar instanceof AStatusParameter) - { - JPopupMenu popupMenu = new JPopupMenu(); - if (effectPar.getScope() == AParameter.LOCAL) - { - popupMenu.add(AParametersTable.SET_GLOBAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - effectPar.changeScope(AParameter.GLOBAL); - refresh(); - } - }); - } - else - { - popupMenu.add(AParametersTable.SET_LOCAL).addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - effectPar.changeScope(AParameter.LOCAL); - refresh(); - } - }); - } - if (tree.isShowing()) - popupMenu.show(tree, e.getX(), e.getY()); - else - // when e.getSource() is the table - popupMenu.show((Component) e.getSource(), e.getX() + getOffsetX(), e.getY() + getOffsetY()); - } - else - { - popupGroupScopeMenu(effectPar, e); - } - } - } - } - - // groupPar is either AStatusRootParameter or AStatusGroupParameter - private final void changeGroupScopes(AParameter groupPar, int scope) - { - Iterator<AParameter> it; - if(groupPar instanceof AStatusRootParameter) - it = ((AStatusRootParameter) groupPar).getParameterList().iterator(); - else - it = ((AStatusGroupParameter) groupPar).getParameterList().iterator(); - while (it.hasNext()) - { - AParameter aPar = it.next(); - // aPar is either AStatusGroupParameter or AStatusParameter - if(aPar instanceof AStatusGroupParameter) - changeGroupScopes(aPar, scope); - else - aPar.changeScope(scope); - } - } - - // groupPar is either AStatusRootParameter or AStatusGroupParameter - private void popupGroupScopeMenu(AParameter groupPar, MouseEvent e) - { - final AParameter tmpPar = groupPar; - JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.add(AParametersTable.SET_ALL_LOCAL).addActionListener( - new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeGroupScopes(tmpPar, AParameter.LOCAL); - refresh(); - } - }); - popupMenu.add(AParametersTable.SET_ALL_GLOBAL).addActionListener( - new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - changeGroupScopes(tmpPar, AParameter.GLOBAL); - refresh(); - } - }); - if (tree.isShowing()) - popupMenu.show(tree, e.getX(), e.getY()); - else - // when e.getSource() is the table - popupMenu.show((Component) e.getSource(), e.getX() + getOffsetX(), e.getY() + getOffsetY()); - } - - public void mouseClicked(MouseEvent e) - { - if (AUtilities.isRightMouseButton(e)) - { - return; - } - int x = e.getX(); - int y = e.getY(); - int row = tree.getRowForLocation(x, y); - TreePath path = tree.getPathForRow(row); - if (path != null) - { - Object clickedNode = path.getLastPathComponent(); - if (clickedNode instanceof ACheckNode) - { - ACheckNode node = (ACheckNode) clickedNode; - boolean newSelectionFlag; - if (node.getParameter() instanceof AStatusParameter) - newSelectionFlag = !node.isSelected(); - else - { - TristateCheckBox.State currentState = ((TristateCheckBox) node.getUserObject()).getState(); - if (currentState == TristateCheckBox.NOT_SELECTED) - newSelectionFlag = true; - else - newSelectionFlag = false; - } - node.getClicked(newSelectionFlag, true); - - if ((node.getSelectionMode() == ACheckNode.MULTI_SELECTION)) - { - if (node.isSelected()) - { - tree.expandPath(path); - } - else - { - if (row != 0) - tree.collapsePath(path); - } - } - ((DefaultTreeModel) tree.getModel()).nodeChanged(node); - // I need revalidate if node is root. but why? - if (row == 0) - { - tree.revalidate(); - tree.repaint(); - } - } - } - } - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/parameters/package.html b/graphics/AtlantisJava/src/atlantis/parameters/package.html deleted file mode 100644 index 8572821c5f1..00000000000 --- a/graphics/AtlantisJava/src/atlantis/parameters/package.html +++ /dev/null @@ -1,7 +0,0 @@ -<html> -<head></head> -<body> -<p>Application parameter store where APar and AParameter are the main - classes.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjection.java b/graphics/AtlantisJava/src/atlantis/projection/AProjection.java deleted file mode 100755 index 2cd72969cf8..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjection.java +++ /dev/null @@ -1,32 +0,0 @@ -package atlantis.projection; - - -import java.awt.event.ActionListener; -import atlantis.canvas.AWindow; -import atlantis.event.AEventManager; -import atlantis.parameters.APar; - -import javax.swing.*; -import java.awt.*; - - -public abstract class AProjection implements ActionListener { - - protected static APar parameterStore = APar.instance(); - protected static AEventManager eventManager = AEventManager.instance(); - - public abstract String getName(); - public abstract String getScreenName(); - public abstract void paint(AWindow window, Graphics g); - - public abstract JMenuItem[] getPopupItems(); - - // next 4/5 needed for normal 2d projections, not for others e.g. Braintests - // should be changed at some point..... - public abstract String getXLabel(); - public abstract String getYLabel(); - public abstract String getXUnits(); - public abstract String getYUnits(); - public abstract void setScales(); - public abstract boolean processLocalCommand(String name); -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjection2D.java b/graphics/AtlantisJava/src/atlantis/projection/AProjection2D.java deleted file mode 100755 index d7a12dd4ead..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjection2D.java +++ /dev/null @@ -1,348 +0,0 @@ -package atlantis.projection; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import java.util.List; -import java.util.ArrayList; - -import javax.swing.JMenuItem; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.ACalorimeterData; -import atlantis.data.ADHelix; -import atlantis.event.AData; -import atlantis.event.AEvent; -import atlantis.geometry.AAtlasDetector; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.parameters.AParameter; -import atlantis.utils.APolygon; -import atlantis.utils.AVector; - -/** - * Base class of Standard 2D projections handles the painting of a projection - * Handles non-linear transforms (linear transforms in AWindow) - */ -public abstract class AProjection2D extends AProjection -{ - private boolean debug = false; - protected ArrayList<JMenuItem> popupItems; - protected final static String ASPECT_RATIO_1 = "Aspect Ratio 1"; - - public AProjection2D() - { - popupItems = new ArrayList<JMenuItem>(); - } - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - - if (action.equals(ASPECT_RATIO_1)) - setAspectRatio1(ACanvas.getCanvas().getCurrentWindow()); - } - - public void setAspectRatio1(AWindow window) - { - //Get the extend of the shown projection (i.e. the corners in user coordinates) - Point2D.Double[] corners = window.getUserCorners(); - AVector v01 = new AVector(corners[0], corners[1]); - AVector v12 = new AVector(corners[1], corners[2]); - //Get the actual size of this window on the screen - Rectangle wSize = window.getBounds(); - - //Calculate new corner positions - //This seems a bit longish to me... CLEANUP - S.B. - - //Calculate stretch factor f such that we keep the larger one of the two extends in user coordinates - //"modulus" just means length of vector! - double f = Math.min(wSize.width / v01.modulus(), wSize.height / v12.modulus()); - - //Rescale new width and height - double w = wSize.width / f; - double h = wSize.height / f; - - //All this just to calculate the center and the new scale - //Maybe easier to split with an if-statement rather than using "Math.min" above - AVector down = v12.getUnitary().scale(h / 2); - AVector up = v12.getUnitary().invert().scale(h / 2); - - AVector v0 = v01.getUnitary().invert().scale(w / 2).add(up); - AVector v1 = v01.getUnitary().scale(w / 2).add(up); - AVector v2 = v01.getUnitary().scale(w / 2).add(down); - - AVector v02 = new AVector(corners[0], corners[2]).scale(0.5); - Point2D.Double center = new Point2D.Double(corners[0].x + v02.dx, corners[0].y + v02.dy); - - //Set the new corner positions - corners[0].setLocation(center.x + v0.dx, center.y + v0.dy); - corners[1].setLocation(center.x + v1.dx, center.y + v1.dy); - corners[2].setLocation(center.x + v2.dx, center.y + v2.dy); - - //Apply new user coordinates - window.setUserCorners(corners); - } - - public boolean processLocalCommand(String name) - { - return false; - } - - public abstract String getName(); - - public String getScreenName() - { - return getName(); - } - - protected Color getBackgroundFillColor(Color[] colorMap) - { - return colorMap[parameterStore.get("Color", "BkgFill").getI()]; - } - - // min rho for tracks - public double getMinRho() - { - return 0.; - } - - public void paint(AWindow window, Graphics g) - { - - AEvent event = null; - List hitsAndTracks = null; - AGraphics ag = AGraphics.makeAGraphics(g); - long time = 0; - - if (debug) - { - time = System.currentTimeMillis(); - } - fillBackground(window, ag); - if (debug) - { - System.out.println("fill " + (System.currentTimeMillis() - time)); - time = System.currentTimeMillis(); - } - - // draw detector geometry - AAtlasDetector.getDetector().draw(window, ag, this); - if (debug) - { - System.out.println("det " + (System.currentTimeMillis() - time)); - time = System.currentTimeMillis(); - } - - // is true when F key is pressed during ZMR operations (detector is - // zoomed for instance, but data are not drawn during the operation) - boolean fastZooming = parameterStore.get("Projection", "SkipData").getStatus(); - if (fastZooming) - { - return; - } - - // draw the current event - event = eventManager.getCurrentEvent(); - - //If there is no current event do nothing - if (event == null) return; - - ACalorimeterData.drawCalorimeters(window, ag, this, event); - - hitsAndTracks = event.getHitsAndTracks(this); - if (debug) - { - System.out.println("calo " + (System.currentTimeMillis() - time)); - time = System.currentTimeMillis(); - } - for (int h = 0; h < hitsAndTracks.size(); h++) - { - ((AData) hitsAndTracks.get(h)).draw(window, ag, this); - if (debug) - { - long delta = (System.currentTimeMillis() - time); - if (delta > 0) - { - System.out.println(((AData) hitsAndTracks.get(h)).getName() + " " + delta); - } - time = System.currentTimeMillis(); - } - } // for - - } // paint() - - protected void fillBackground(AWindow window, AGraphics ag) - { - ag.setColor(getBackgroundFillColor(AColorMap.getColors())); - ag.fillRect(0, 0, window.getWidth(), window.getHeight()); - } - - // this is here to make drawing of tracks fast enough - public abstract ACoord getUserPoint(ADHelix dH, double s); - - public ACoord nonLinearTransform(ACoord user) - { - return user; - } - - public ACoord[] nonLinearTransform(ACoord[] user) - { - if (user != null) - for (int i = 0; i < user.length; i++) - user[i] = nonLinearTransform(user[i]); - return user; - } - - public Point2D.Double nonLinearTransform(double x, double y) - { - ACoord c = nonLinearTransform(new ACoord(x, y)); - return new Point2D.Double(c.hv[0][0][0], c.hv[1][0][0]); - } - - public Point2D.Double nonLinearTransform(Point2D.Double user) - { - return nonLinearTransform(user.x, user.y); - } - - public ACoord inverseNonLinearTransform(ACoord user) - { - return user; - } - - public Point2D.Double inverseNonLinearTransform(double x, double y) - { - ACoord c = inverseNonLinearTransform(new ACoord(x, y)); - - return new Point2D.Double(c.hv[0][0][0], c.hv[1][0][0]); - } - - public Point2D.Double inverseNonLinearTransform(Point2D.Double user) - { - return inverseNonLinearTransform(user.x, user.y); - } - - protected static ACoord nonLinearTransform2D(ACoord user, String projectionName) - { - AParameter fishEyePar = parameterStore.get(projectionName, "FishEye"); - - if (fishEyePar.getStatus()) - { - double[] z, r; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(projectionName, "rTo").getD(); - double zTo = parameterStore.get(projectionName, "zTo").getD(); - - for (int j = 0; j < user.hv[0].length; ++j) - { - z = user.hv[0][j]; - r = user.hv[1][j]; - for (int i = 0; i < z.length; ++i) - { - z[i] *= (1 + fishEye * zTo) / (1 + fishEye * Math.abs(z[i])); - r[i] *= (1 + fishEye * rTo) / (1 + fishEye * Math.abs(r[i])); - } - } - } - return user; - } - - protected static ACoord inverseNonLinearTransform2D(ACoord user, String projectionName) - { - AParameter fishEyePar = parameterStore.get(projectionName, "FishEye"); - - if (fishEyePar.getStatus()) - { - double[] z, r; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(projectionName, "rTo").getD(); - double zTo = parameterStore.get(projectionName, "zTo").getD(); - - for (int j = 0; j < user.hv[0].length; ++j) - { - z = user.hv[0][j]; - r = user.hv[1][j]; - for (int i = 0; i < z.length; ++i) - { - z[i] *= 1 / (1 + fishEye * (zTo - Math.abs(z[i]))); - r[i] *= 1 / (1 + fishEye * (rTo - Math.abs(r[i]))); - } - } - } - return user; - } - - protected static Point2D.Double[] aspectRatioLayout(double width, double height, Dimension wSize) - { - double f = Math.min(wSize.width / width, wSize.height / height); - - width = wSize.width / f; - height = wSize.height / f; - - Point2D.Double[] corners = new Point2D.Double[3]; - - corners[0] = new Point2D.Double(-width, +height); - corners[1] = new Point2D.Double(+width, +height); - corners[2] = new Point2D.Double(+width, -height); - return corners; - } - - public void setScales() - {} - - public abstract Point2D.Double[] calculateNoZoomCorners(Dimension wSize); - - public abstract Point2D.Double getCenter(); - - public Point2D.Double[] validateCorners(Point2D.Double[] corners) - { - APolygon p = new APolygon(); - - for (int i = 0; i < corners.length; i++) - p.addPoint(corners[i].x, corners[i].y); - - if (p.getArea() == 0) - return null; - else - return corners; - } - - /** - * This function is called when the ACanvas configuration was written on - * a screen with one aspect ratio but the current screen has a different - * aspect ratio. Subclasses may re-implement this to behave however they - * like. At present (when this was written) only YX does anything. - * - * -- Adam Davison - * - * @param w AWindow object containing this - * @param oldaspect Aspect ratio of screen where current window corners were chosen - * @param newaspect Aspect ratio of screen now - */ - - public void aspectRatioChange(AWindow w, double oldaspect, double newaspect) { - // Do nothing by default - } - - public JMenuItem[] getPopupItems() - { - // Can't cast arrays very easily... - JMenuItem[] ret = new JMenuItem[popupItems.size()]; - for (int i = 0; i < popupItems.size(); i++) { - ret[i] = (JMenuItem)popupItems.get(i); - } - return ret; - } - - protected void addPopupItem(String str) { - JMenuItem it = new JMenuItem(str); - popupItems.add(it); - it.addActionListener(this); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjection3D.java b/graphics/AtlantisJava/src/atlantis/projection/AProjection3D.java deleted file mode 100755 index 28bf192814c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjection3D.java +++ /dev/null @@ -1,167 +0,0 @@ -package atlantis.projection; - -import atlantis.data.ADHelix; -import atlantis.graphics.*; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import atlantis.event.*; -import java.awt.*; -import java.awt.geom.*; -import javax.swing.JMenuItem; - -public class AProjection3D extends AProjection2D { - - // axis about which the rotations take place - static private double phi; - static private double sinPhi, cosPhi; - // center of rotation in xyz frame - static private double rx, ry, rz; - // three axis abc in the xyz frame - static private double ax, ay, az; - static private double bx, by, bz; - static private double cx, cy, cz; - - static private double[][] abc=new double[3][3]; - - public AProjection3D() { - JMenuItem asp = new JMenuItem(ASPECT_RATIO_1); - asp.addActionListener(this); - popupItems.add(asp); - } - - public String getName() { - return "3D"; - } - - public String getXLabel() { - return "V"; - } - - public String getYLabel() { - return "H"; - } - - public String getXUnits() { - return "(cm)"; - } - - public String getYUnits() { - return "(cm)"; - } - - public Point2D.Double getCenter() { - return new Point2D.Double(0, 0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - double radius=parameterStore.get("Projection", "TrackingRadius").getD(); - double length=parameterStore.get("Projection", "TrackingLength").getD(); - return aspectRatioLayout(length, radius, wSize); - } - - public static double getPhi() { - return parameterStore.get("3D", "Phi").getD(); - } - - public static void updateParameters() { - phi=Math.toRadians(getPhi()); - sinPhi=Math.sin(phi); - cosPhi=Math.cos(phi); - ax=parameterStore.get("3D", "xAxis").getD(); - ay=parameterStore.get("3D", "yAxis").getD(); - az=parameterStore.get("3D", "zAxis").getD(); - rx=parameterStore.get("Event", "XVtx").getD(); - ry=parameterStore.get("Event", "YVtx").getD(); - rz=parameterStore.get("Event", "ZVtx").getD(); - double dx; - double dy; - double dz; - - if(ax==0.&&ay==0) { - // d is the y-axis - dx=0.; - dy=-1.; - dz=0.; - } else { - // d is the z-axis - dx=0.; - dy=0.; - dz=1.; - } - - bx=+ay*dz-az*dy; - by=-ax*dz+az*dx; - bz=+ax*dy-ay*dx; - - cx=+ay*bz-az*by; - cy=-ax*bz+az*bx; - cz=+ax*by-ay*bx; - } - - public static double[][] getRotationMatrix() { - updateParameters(); - abc[0][0]=ax; - abc[0][1]=ay; - abc[0][2]=az; - abc[1][0]=bx; - abc[1][1]=by; - abc[1][2]=bz; - abc[2][0]=cx; - abc[2][1]=cy; - abc[2][2]=cz; - return abc; - } - - public static double[] getRotated(double[] p) { - updateParameters(); - double x=p[0]-rx; - double y=p[1]-ry; - double z=p[2]-rz; - - double u=x*ax+y*ay+z*az; - double v=x*bx+y*by+z*bz; - double w=x*cx+y*cy+z*cz; - - p[0]=u; - p[1]=v*cosPhi-w*sinPhi; - p[2]=v*sinPhi+w*cosPhi; - return p; - } - - public static double[][] getRotated(int numDraw, int[] listdl, float[] x, float[] y, float[] z) { - updateParameters(); - - double[][] uvw=new double[3][numDraw]; - - for(int i=0; i<numDraw; i++) { - int list=listdl[i]; - double xx=x[list]-rx; - double yy=y[list]-ry; - double zz=z[list]-rz; - double u=xx*ax+yy*ay+zz*az; - double v=xx*bx+yy*by+zz*bz; - double w=xx*cx+yy*cy+zz*cz; - uvw[0][i]=u; - uvw[1][i]=v*cosPhi-w*sinPhi; - uvw[2][i]=v*sinPhi+w*cosPhi; - } - return uvw; - } - - public static int[] getAxisMapping() { - return new int[] {0, 1, 2}; - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return nonLinearTransform(dH.get3DPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) { - return nonLinearTransform2D(user, getName()); - } - - public ACoord inverseNonLinearTransform(ACoord user) { - return inverseNonLinearTransform2D(user, getName()); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjection3DBox.java b/graphics/AtlantisJava/src/atlantis/projection/AProjection3DBox.java deleted file mode 100755 index 62ae22b6913..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjection3DBox.java +++ /dev/null @@ -1,569 +0,0 @@ -package atlantis.projection; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import java.util.LinkedList; - -import javax.swing.JMenuItem; - -import Jama.Matrix; -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.A3DPointData; -import atlantis.data.ADHelix; -import atlantis.event.AEvent; -import atlantis.data.ATrackData; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.ADrawable; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; - -public class AProjection3DBox extends AProjection -{ - // angle of the rotation about the axis - static private double phi; - static private double sinPhi; - static private double cosPhi; - - static private double scale; - static private double zP; - static private double xz; - static private double yz; - - static private AVec3D centerDisplay; - static private AVec3D sizeDisplay; - - static private AVec3D sizeUser = new AVec3D(1.1, .5, .5); - - static final String RESTORE_DEFAULTS = "Default Box Volume"; - - static private LinkedList<AVec3D[]> planes = new LinkedList<AVec3D[]>(); - - static private JMenuItem[] popupItems; - - public AProjection3DBox() - { - popupItems = new JMenuItem[1]; - popupItems[0] = new JMenuItem(RESTORE_DEFAULTS); - popupItems[0].addActionListener(this); - } - - public String getName() - { - return "3DBox"; - } - - public String getScreenName() - { - return "3DBox"; - } - - public String getXLabel() - { - return "V"; - } - - public String getYLabel() - { - return "H"; - } - - public String getXUnits() - { - return "(cm)"; - } - - public String getYUnits() - { - return "(cm)"; - } - - public void setScales() - {} - - public boolean processLocalCommand(String name) - { - return false; - } - - public Point2D.Double getCenter(AWindow window) - { - updateParameters(window); - return new Point2D.Double(centerDisplay.x, centerDisplay.y); - } - - public void zoom(double factor) - { - if (factor != 0.) - { - sizeUser = sizeUser.scale(factor); - updateScale(); - } - } - - public static void setSizeUser(double size) - { - if (size != 0.) - { - sizeUser.x = size; - // updateScale(); - // ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - } - - public void zoomHorizontal(double factor) - { - if (factor != 0.) - { - sizeUser.x *= factor; - updateScale(); - } - } - - public void zoomVertical(double factor) - { - if (factor != 0. && !Double.isInfinite(factor)) - { - sizeUser.y *= factor; - sizeUser.z *= factor; - updateScale(); - } - } - - public static void updateScale() - { - scale = parameterStore.get("3DBox", "Scale").getD(); - ACanvas.getCanvas().getCurrentWindow().setUserCorners(0, 2. * sizeUser.x / scale, -sizeUser.y / scale, sizeUser.y / scale); - } - - public static void updateScale(AWindow window) - { - scale = parameterStore.get("3DBox", "Scale").getD(); - window.setUserCorners(0, 2. * sizeUser.x / scale, -sizeUser.y / scale, sizeUser.y / scale); - } - - public static double getPhi() - { - return parameterStore.get("3DBox", "Phi").getD(); - } - - public static void updateParameters(AWindow window) - { - phi = Math.toRadians(getPhi()); - sinPhi = Math.sin(phi); - cosPhi = Math.cos(phi); - scale = parameterStore.get("3DBox", "Scale").getD(); - zP = parameterStore.get("3DBox", "ZP").getD(); - xz = parameterStore.get("3DBox", "xz").getD(); - yz = parameterStore.get("3DBox", "yz").getD(); - - Rectangle bounds = window.getCurrDisp(); - centerDisplay = new AVec3D(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, 0.); - sizeDisplay = new AVec3D(0.5 * bounds.width * scale, 0.5 * bounds.height * scale, 0.5 * bounds.height * scale); - centerDisplay.x -= sizeDisplay.x; - updateScale(window); - } - - protected void drawBox(AGraphics ag) - { - double x = sizeDisplay.x; - double y = sizeDisplay.y; - double z = sizeDisplay.z; - - AVec3D[] firstPlane = new AVec3D[] { new AVec3D(0, y, z), new AVec3D(0, y, -z), new AVec3D(0, -y, -z), new AVec3D(0, -y, z) }; - AVec3D[] middlePlane = new AVec3D[] { new AVec3D(x, y, z), new AVec3D(x, y, -z), new AVec3D(x, -y, -z), new AVec3D(x, -y, z) }; - AVec3D[] lastPlane = new AVec3D[] { new AVec3D(2 * x, y, z), new AVec3D(2 * x, y, -z), new AVec3D(2 * x, -y, -z), new AVec3D(2 * x, -y, z) }; - - planes = new LinkedList<AVec3D[]>(); - - planes.add(firstPlane); - planes.add(middlePlane); - planes.add(lastPlane); - - for (int i = 0; i < planes.size(); i++) - { - AVec3D[] plane = (AVec3D[]) (planes.get(i)); - for (int j = 0; j < plane.length; ++j) - plane[j] = applyViewPoint(plane[j]); - } - - double[] h = new double[4]; - double[] v = new double[4]; - - // back - AVec3D[] back = new AVec3D[] { firstPlane[3], firstPlane[1], lastPlane[1], lastPlane[3] }; - for (int j = 0; j < back.length; ++j) - { - h[j] = back[j].x; - v[j] = back[j].y; - } - - ag.updateDrawParameters(new ADrawParameters(true, 0, 0, 1, 0, 0)); - ag.setColor(Color.gray); - ag.fillPolygon(h, v, 4); - ag.setColor(Color.white); - ag.drawPolygon(h, v, 4); - // base - AVec3D[] base = new AVec3D[] { firstPlane[0], firstPlane[1], lastPlane[1], lastPlane[0] }; - for (int j = 0; j < base.length; ++j) - { - h[j] = base[j].x; - v[j] = base[j].y; - } - ag.setColor(Color.black); - ag.fillPolygon(h, v, 4); - ag.setColor(Color.white); - ag.drawPolygon(h, v, 4); - - for (int i = 0; i < planes.size(); i++) - { - AVec3D[] plane = (AVec3D[]) (planes.get(i)); - for (int j = 0; j < plane.length; ++j) - { - h[j] = plane[j].x; - v[j] = plane[j].y; - } - ag.setColor(Color.black); - ag.fillPolygon(h, v, 4); - ag.setColor(Color.white); - ag.drawPolygon(h, v, 4); - } - - // top - AVec3D[] top = new AVec3D[] { firstPlane[3], firstPlane[2], lastPlane[2], lastPlane[3] }; - for (int j = 0; j < top.length; ++j) - { - h[j] = top[j].x; - v[j] = top[j].y; - } - ag.setColor(Color.white); - ag.drawPolygon(h, v, 4); - } - - protected void touchupBox(AGraphics ag) - { - ag.updateDrawParameters(new ADrawParameters(true, 0, 0, 1, 0, 0)); - ag.setColor(Color.white); - for (int i = 0; i < planes.size(); i++) - { - AVec3D[] plane = (AVec3D[]) (planes.get(i)); - ag.drawLine(plane[1].x, plane[1].y, plane[2].x, plane[2].y); - } - } - - AVec3D scale(AVec3D v) - { - return v.mult(sizeDisplay).divide(sizeUser); - } - - AVec3D rotate(AVec3D v) - { - return new AVec3D(v.x, v.y * cosPhi - v.z * sinPhi, v.y * sinPhi + v.z * cosPhi); - } - - static AVec3D applyViewPoint(AVec3D v) - { - return new AVec3D((v.x + xz * v.z) * (1 - v.z * zP) + centerDisplay.x, (v.y + yz * v.z) * (1 - v.z * zP) + centerDisplay.y, v.z); - } - - public void paint(AWindow window, Graphics g) - { - updateParameters(window); - AGraphics ag = AGraphics.makeAGraphics(g); - fillBackground(window, ag); - drawBox(ag); - AEvent event = eventManager.getCurrentEvent(); - if (event == null) - return; - - java.util.List hitsAndTracks = event.getHitsAndTracks(this); - - for (int h = 0; h < hitsAndTracks.size(); h++) - { - Object o = hitsAndTracks.get(h); - if (o instanceof ATrackData) - drawTracks((ATrackData) o, window, ag); - else if (o instanceof A3DPointData) - drawPoints((A3DPointData) o, window, ag); - } - touchupBox(ag); - } - - protected void drawPoints(A3DPointData pointData, AWindow window, AGraphics ag) - { - double[][] points = pointData.get3DPoints(); - int[] index = pointData.get3DPointsIndex(); - - double[][][] hv = new double[2][1][index.length]; - - for (int i = 0; i < points.length; ++i) - { - AVec3D point = rotate(new AVec3D(AProjection3D.getRotated(points[i]))); - - if (point.x > 0 && point.x < 2 * sizeUser.x && point.y > -sizeUser.y && point.y < sizeUser.y && point.z > -sizeUser.z && point.z < sizeUser.z) - { - point = applyViewPoint(scale(point)); - hv[0][0][i] = point.x; - hv[1][0][i] = point.y; - } - else - { - // aaargh allow this to be clipped from picture for now - hv[0][0][i] = -1000.; - hv[1][0][i] = -1000.; - } - } - - ag.draw(new ACoord(hv, index, pointData, ACoord.SYMBOLS)); - } - - protected void drawTracks(ATrackData tracks, AWindow window, AGraphics ag) - { - ADHelix[] dhelix = tracks.getHelices(); - - int numPlanes = planes.size(); - int numSegments = numPlanes + 4; - AVec3D[][] intersection = new AVec3D[dhelix.length][numPlanes]; - - double[][][] hv = new double[2][dhelix.length * numSegments][0]; - int[] index = new int[dhelix.length * numSegments]; - int[] indexTemp = tracks.getDrawList(); - for (int i = 0; i < indexTemp.length; ++i) - for (int j = 0; j < numSegments; ++j) - index[i * numSegments + j] = indexTemp[i]; - - int numPointsOnEllipse = 24; - AVec3D[] ellipse = new AVec3D[numPointsOnEllipse + 1]; - double radius = 0.005; - for (int i = 0; i < ellipse.length; i++) - { - double phi = 2. * Math.PI * i / numPointsOnEllipse; - ellipse[i] = new AVec3D(0., radius * Math.sin(phi), radius * Math.cos(phi)); - } - - for (int j = 0; j < dhelix.length; ++j) - if (dhelix[j] != null) - { - // s always 0? I don't know why that is... - double s = 0.; - AVec3D start = new AVec3D(dhelix[j].get3DPointAsArray(s)); - AVec3D end = new AVec3D(dhelix[j].get3DPointAsArray(s + 0.01)); - - boolean backwards = false; - - // calculate intersections - for (int p = 0; p < planes.size(); ++p) - { - // position of plane - double xInt = p * sizeUser.x; - double m = (xInt - start.x) / (end.x - start.x); - - // While we're in here, can check if we're pointing in the right direction - if (p == 1 && m < 0.0) { backwards = true; } - - double yInt = start.y + m * (end.y - start.y); - double zInt = start.z + m * (end.z - start.z); - intersection[j][p] = new AVec3D(xInt, yInt, zInt); - } - - // Throw out anything that isn't pointing in the right direction... - if (backwards) { continue; } - - AVec3D first = rotate(intersection[j][0]); - AVec3D middle = rotate(intersection[j][1]); - AVec3D last = rotate(intersection[j][numPlanes - 1]); - - if (first.y > -sizeUser.y && first.y < sizeUser.y && first.z > -sizeUser.z && first.z < sizeUser.z && last.y > -sizeUser.y && last.y < sizeUser.y && last.z > -sizeUser.z && last.z < sizeUser.z) - { - - double[][] cov = dhelix[j].helix.getCovariance(); - if (cov != null) - { - double[][] c = new double[2][2]; - c[0][0] = cov[0][0]; - c[0][1] = cov[0][1]; - c[1][0] = cov[1][0]; - c[1][1] = cov[1][1]; - Matrix covM = new Matrix(c); - Matrix errM = covM.inverse(); - - double b1 = errM.get(0, 0); - double b2 = errM.get(1, 1); - - double b3 = 2. * errM.get(0, 1); - if (parameterStore.get("3DBox", "ellipses").getStatus()) - { - ellipse = new AVec3D[180]; - - for (int i = 0; i < 360; i += 2) - { - double thetat = Math.toRadians(i); - double tt = Math.tan(thetat); - double xx = Math.sqrt(1. / (b1 + b2 * tt * tt + b3 * tt)); - if (i > 90 && i <= 270) - xx *= -1.; - ellipse[i / 2] = new AVec3D(0., xx, xx * tt); - } - } - // add intersections to draw list - for (int p = 0; p < planes.size(); ++p) - { - double[] h = new double[ellipse.length]; - double[] v = new double[ellipse.length]; - - for (int i = 0; i < ellipse.length; i++) - { - AVec3D point = applyViewPoint(scale(rotate(intersection[j][p].add(ellipse[i])))); - h[i] = point.x; - v[i] = point.y; - } - - hv[0][numSegments * j + p] = h; - hv[1][numSegments * j + p] = v; - } - } - first = applyViewPoint(scale(first)); - middle = applyViewPoint(scale(middle)); - last = applyViewPoint(scale(last)); - - double[][] edge = new double[planes.size()][2]; - for (int i = 0; i < planes.size(); i++) - { - AVec3D[] plane = (AVec3D[]) (planes.get(i)); - double xInt = plane[1].x; - double m = (xInt - first.x) / (last.x - first.x); - double yInt = first.y + m * (last.y - first.y); - edge[i] = new double[] { xInt, yInt }; - } - - hv[0][numSegments * j + 3] = new double[] { first.x, edge[1][0] }; - hv[1][numSegments * j + 3] = new double[] { first.y, edge[1][1] }; - hv[0][numSegments * j + 4] = new double[] { middle.x, edge[2][0] }; - hv[1][numSegments * j + 4] = new double[] { middle.y, edge[2][1] }; - - drawDashed(ag, tracks, indexTemp[j], edge[1][0], edge[1][1], middle.x, middle.y); - drawDashed(ag, tracks, indexTemp[j], edge[2][0], edge[2][1], last.x, last.y); - } - } - ag.draw(new ACoord(hv, index, tracks, ACoord.POLYLINES)); - } - - protected void drawDashed(AGraphics ag, ADrawable source, int ind, double h0, double v0, double h1, double v1) - { - double dH = h1 - h0; - double dV = v1 - v0; - double dist = Math.sqrt(dH * dH + dV * dV); - double dashSize = 4; - int num = (int) (dist / dashSize); - int[] index = new int[num / 2 + 1]; - double[][][] hv = new double[2][num / 2 + 1][2]; - - for (int i = 0; i < num; ++i) - { - if (i % 2 == 1) - { - int n = i / 2; - index[n] = ind; - hv[0][n][0] = h0 + dH * i / num; - hv[0][n][1] = h0 + dH * (i + 1) / num; - hv[1][n][0] = v0 + dV * i / num; - hv[1][n][1] = v0 + dV * (i + 1) / num; - if (i >= num - 2) - { - hv[0][n][1] = h1; - hv[1][n][1] = v1; - } - } - } - ag.draw(new ACoord(hv, index, source, ACoord.POLYLINES)); - } - -protected void fillBackground(AWindow window, AGraphics ag) - { - Color[] colorMap = AColorMap.getColors(); - ag.setColor(colorMap[getBackgroundFillColor()]); - ag.fillRect(0, 0, window.getWidth(), window.getHeight()); - } - - protected int getBackgroundFillColor() - { - return parameterStore.get("Color", "BkgFill").getI(); - } - - public JMenuItem[] getPopupItems() - { - return popupItems; - } - - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - if (action.equals(RESTORE_DEFAULTS)) - { - sizeUser.x = 2.; - sizeUser.y = .1; - sizeUser.z = .1; - updateScale(); - ACanvas.getCanvas().getCurrentWindow().repaintFromScratch(); - } - } - -} - -class AVec3D -{ - double x, y, z; - - AVec3D(double x, double y, double z) - { - this.x = x; - this.y = y; - this.z = z; - } - - AVec3D(double[] v) - { - this.x = v[0]; - this.y = v[1]; - this.z = v[2]; - } - - AVec3D cross(AVec3D d) - { - return new AVec3D(+this.y * d.z - this.z * d.y, -this.x * d.z + this.z * d.x, +this.x * d.y - this.y * d.x); - } - - AVec3D add(AVec3D d) - { - return new AVec3D(x + d.x, y + d.y, z + d.z); - } - - AVec3D mult(AVec3D d) - { - return new AVec3D(x * d.x, y * d.y, z * d.z); - } - - AVec3D divide(AVec3D d) - { - return new AVec3D(x / d.x, y / d.y, z / d.z); - } - - AVec3D scale(double s) - { - return new AVec3D(s * x, s * y, s * z); - } - - public String toString() - { - return x + " " + y + " " + z; - } - - public double mag2() { - return x*x + y*y + z*z; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionEventInfo.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionEventInfo.java deleted file mode 100644 index 1735ec2a666..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionEventInfo.java +++ /dev/null @@ -1,197 +0,0 @@ -package atlantis.projection; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import javax.swing.ImageIcon; -import javax.swing.JMenuItem; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.ADHelix; -import atlantis.event.AEvent; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.utils.AUtilities; - -/** Class used to display the ATLAS Experiment logo, along with - * Event Number, Run Number, and Date/Time - * - * @author Tom McLaughlan - */ -public class AProjectionEventInfo extends AProjectionInfo { - - private static long EventNumber; - private static long RunNumber; - private static String DateTime; - private static String Source; - private static Color textColor = Color.white, - backgroundColor = Color.black; - - public String getName() { - return "EventInfo"; - } - - public void paint(AWindow window, Graphics g) { - - AEvent event = eventManager.getCurrentEvent(); - - if (event != null) { - RunNumber = event.getRunNumber(); - EventNumber = event.getEventNumber(); - DateTime = event.getDateTime(); - Source = event.getSourceName(); - } - - // Begin drawing - AGraphics ag = AGraphics.makeAGraphics(g); - // Fill the background - ag.setColor(backgroundColor); - ag.fillRect(0, 0, window.getWidth(), window.getHeight()); - - String iconPath = AGlobals.instance().getHomeDirectory() + "img" + System.getProperty("file.separator"); - - ImageIcon i = AUtilities.getFileAsImageIcon(iconPath + "atlas_logo_shadow.png"); - - - // Determine height and width of current window, and width of ATLAS logo - // These are then used to determine a scaling factor which is used in the - // scale function. - // - int height = window.getSize().height; - int width = window.getSize().width; - int iwidth = i.getIconWidth(); - double factor = (double) width / (double) iwidth; - - // Call scale function to scale image to window size - ImageIcon iscale = AUtilities.scale(i.getImage(), factor, parameterStore.get("Prefs", "AntiAlias").getStatus()); - // x, y calculated to position image exactly centred - int x = (width / 2) - (iscale.getIconWidth() / 2); - int y = (height / 2) - ((3 * iscale.getIconHeight()) / 4); - - // get screen dpi for resolution independent scaling - // commented out 27/3 -- EJ - // without a screen you obviously do not have a screen resolution - int dpi = 72; //Toolkit.getDefaultToolkit().getScreenResolution(); - - // Set a scaling font size with window width - int fontSize = (int) Math.round(3.0 * width / (double) dpi); - - Font f = new Font("SansSerif", Font.PLAIN, fontSize); - - ag.drawImage(iscale.getImage(), x, y); - - ag.setColor(textColor); // Set colour for text - ag.updateColor(); // Update current colour for drawing - - String DateString = "", RunEventString = ""; - String DisclaimerString1 = "", DisclaimerString2 = ""; - if (event != null) { - DateString = "Date: " + DateTime; - RunEventString = "Run Number: " + RunNumber + ", Event Number: " + EventNumber; - DisclaimerString1 = "Snapshot of a proton collision"; - DisclaimerString2 = "directly from the ATLAS experiment"; - } else { - RunEventString = "No event data available"; - } - - FontMetrics fm = g.getFontMetrics(f); - int DateWidth = fm.stringWidth(DateString); - int RunEventWidth = fm.stringWidth(RunEventString); - int Disclaimer1Width = fm.stringWidth(DisclaimerString1); - int Disclaimer2Width = fm.stringWidth(DisclaimerString2); - - // This may need changing to be a bit more elegant - // -- currently under investigation by Tom - - // Check if font is wider than the window and scale down til it fits. - while ((RunEventWidth > width - 20) || (DateWidth > width - 20)) - { - - fontSize = fontSize - 1; - f = new Font("SansSerif", Font.PLAIN, fontSize); - fm = g.getFontMetrics(f); - RunEventWidth = fm.stringWidth(RunEventString); - DateWidth = fm.stringWidth(DateString); - Disclaimer1Width = fm.stringWidth(DisclaimerString1); - Disclaimer2Width = fm.stringWidth(DisclaimerString2); - } - - ag.setFont(f); // set font as defined above - - // For the streams at P1, we include a disclaimer - // Anything without .xml is considered a stream for now - if (Source != null && !Source.endsWith(".xml")) { - ag.drawString(DisclaimerString1, - (width / 2) - Disclaimer1Width / 2, 0.89 * height); - ag.drawString(DisclaimerString2, - (width / 2) - Disclaimer2Width / 2, 0.95 * height); - } - - if (event != null && !DateTime.equals("") && !DateTime.equals("n/a")) { - // If event contains Date/Time data, draw Run Number, Event Number and Date/Time - // and position text in centre of window - ag.drawString(RunEventString, - (width / 2) - RunEventWidth / 2, y + (1.1 * iscale.getIconHeight())); - - ag.drawString(DateString, - (width / 2) - DateWidth / 2, y + (1.3 * iscale.getIconHeight())); - } else { - // Draw text (No Date/Time, for MC events, etc) - ag.drawString(RunEventString, - (width / 2) - RunEventWidth / 2, y + (1.1 * iscale.getIconHeight())); - - } - - } - - public JMenuItem[] getPopupItems() { - return null; - } - - public String getXLabel() { - return ""; - } - - public String getXUnits() { - return ""; - } - - public String getYLabel() { - return ""; - } - - public String getYUnits() { - return ""; - } - - @Override - public void actionPerformed(ActionEvent e) { - assert false : "Did not expect AProjectionEventInfo to be used as ActionListener"; - } - - public void setScales() { - } - - public Point2D.Double getCenter() { - return new Point2D.Double(0.0, 0.0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - Point2D.Double[] corners = new Point2D.Double[3]; - - corners[0] = new Point2D.Double(0., 2.); - corners[1] = new Point2D.Double(100., 2.); - corners[2] = new Point2D.Double(100., -2.); - return corners; - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return ACoord.NO_DATA; - } -}//end of EventInfoProjection class diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionFR.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionFR.java deleted file mode 100755 index ddc52bdb54c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionFR.java +++ /dev/null @@ -1,127 +0,0 @@ -package atlantis.projection; - -import java.awt.Dimension; -import java.awt.geom.Point2D; - -import atlantis.canvas.ACanvas; -import atlantis.data.ADHelix; -import atlantis.graphics.ACoord; -import atlantis.interactions.AZMRInteraction; -import atlantis.parameters.APar; -import atlantis.parameters.AParameter; -import atlantis.utils.AMath; - -public class AProjectionFR extends AProjectionPhi -{ - public String getName() - { - return "FR"; - } - - public String getXLabel() - { - return AMath.RHO; - } - - public String getXUnits() - { - return "(cm)"; - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) - { - Point2D.Double[] corners = new Point2D.Double[3]; - int phiWrap = parameterStore.get(getName(), "PhiWrap").getI(); - - double radius = parameterStore.get("Projection", "Radius").getD(); - corners[0] = new Point2D.Double(0, 360 + phiWrap); - corners[1] = new Point2D.Double(radius, 360 + phiWrap); - corners[2] = new Point2D.Double(radius, 0); - return corners; - } - - public ACoord getUserPoint(ADHelix dH, double s) - { - return nonLinearTransform(dH.getFRPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) - { - AParameter fishEyePar = parameterStore.get(getName(), "FishEye"); - - // Fisheye of projection FR should not change phi - if (fishEyePar.getStatus()) - { - double[] r; - //double[] phi; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(getName(), "rTo").getD(); - //Point2D.Double[] corners = ACanvas.getCanvas().getCurrentWindow().getUserCorners(); - //double phiMid = (corners[0].getY() + corners[2].getY()) / 2.; - - for (int j = 0; j < user.hv[0].length; ++j) - { - r = user.hv[0][j]; - //phi = user.hv[1][j]; - for (int i = 0; i < r.length; ++i) - { - double fact = (1 + fishEye * rTo) / (1 + fishEye * r[i]); - - //phi[i] = phiMid + (phi[i] - phiMid) * fact; - r[i] *= fact; - } - } - } - - // Horizontal Zoom is applied in ZMR interaction - - // don't know what this has to do here? - // CLEANUP - S.B. - /* AParameter horZoomPar = APar.get(getName(), "HorizontalZoom"); - - if (horZoomPar.getStatus()) - { - // performe initial horizontal zoom - double hzf = APar.get("FR", "HorizontalZoom").getD(); - Point2D.Double[] corners = ACanvas.getCanvas().getCurrentWindow().getUserCorners(); - double centerRho = corners[0].getX(); - double centerPhi = (corners[0].getY() + corners[2].getY()) / 2.; - Point2D.Double center = new Point2D.Double(centerRho, centerPhi); - AZMRInteraction.performHorizontalZoom(center, hzf, ACanvas.getCanvas().getPaintingWindow()); - - horZoomPar.setStatus(false); - } - */ - return user; - } - - public ACoord inverseNonLinearTransform(ACoord user) - { - AParameter fishEyePar = parameterStore.get(getName(), "FishEye"); - - if (fishEyePar.getStatus()) - { - double[] r; - //double[] phi; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(getName(), "rTo").getD(); - //Point2D.Double[] corners = ACanvas.getCanvas().getCurrentWindow().getUserCorners(); - //double phiMid = (corners[0].getY() + corners[2].getY()) / 2.; - - for (int j = 0; j < user.hv[0].length; ++j) - { - r = user.hv[0][j]; - //phi = user.hv[1][j]; - for (int i = 0; i < r.length; ++i) - { - double fact = 1 / (1 + fishEye * (rTo - r[i])); - - //phi[i] = phiMid + (phi[i] - phiMid) * fact; - r[i] *= fact; - } - } - } - - return user; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionFZ.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionFZ.java deleted file mode 100755 index 32c092064bd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionFZ.java +++ /dev/null @@ -1,76 +0,0 @@ -package atlantis.projection; - - -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import java.awt.geom.*; -import java.awt.*; -import atlantis.graphics.ACoord; -import atlantis.data.ADHelix; - - -public class AProjectionFZ extends AProjectionPhi { - - public String getName() { - return "FZ"; - } - - public String getXLabel() { - return "Z"; - } - - public String getXUnits() { - return "(cm)"; - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - Point2D.Double[] corners=new Point2D.Double[3]; - int phiWrap=parameterStore.get(getName(), "PhiWrap").getI(); - - double length=parameterStore.get("Projection", "Length").getD(); - - corners[0]=new Point2D.Double(-length, 360+phiWrap); - corners[1]=new Point2D.Double(length, 360+phiWrap); - corners[2]=new Point2D.Double(length, 0); - return corners; - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return nonLinearTransform(dH.getFZPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) { - AParameter fishEyePar=parameterStore.get(getName(), "FishEye"); - - if(fishEyePar.getStatus()) { - double[] z; - double fishEye=0.001*fishEyePar.getD(); - double zTo=parameterStore.get(getName(), "zTo").getD(); - - for(int j=0; j<user.hv[0].length; ++j) { - z=user.hv[0][j]; - for(int i=0; i<z.length; ++i) - z[i]*=(1+fishEye*zTo)/(1+fishEye*Math.abs(z[i])); - } - } - return user; - } - - public ACoord inverseNonLinearTransform(ACoord user) { - AParameter fishEyePar=parameterStore.get(getName(), "FishEye"); - - if(fishEyePar.getStatus()) { - double[] z; - double fishEye=0.001*fishEyePar.getD(); - double zTo=parameterStore.get(getName(), "zTo").getD(); - - for(int j=0; j<user.hv[0].length; ++j) { - z=user.hv[0][j]; - for(int i=0; i<z.length; ++i) - z[i]*=1/(1+fishEye*(zTo-Math.abs(z[i]))); - } - } - return user; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionInfo.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionInfo.java deleted file mode 100644 index b7428f17751..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionInfo.java +++ /dev/null @@ -1,102 +0,0 @@ -package atlantis.projection; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.RenderingHints; -import java.awt.geom.Point2D; -import java.awt.image.BufferedImage; - -import javax.swing.ImageIcon; - -import atlantis.canvas.AWindow; -import atlantis.event.AEvent; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; - -/** - * Stripped down clone of the 2D Projection class - * Used simply to display event data (as text) in a window - * with the ATLAS experiment logo, for publications and presentation purposes - * - * Also contains rudimentary image scaling code used to scale the ATLAS logo depending - * on window size - * - * @author Tom McLaughlan - */ -public abstract class AProjectionInfo extends AProjection -{ - private boolean debug = false; - - protected final static String ASPECT_RATIO_1 = "Aspect Ratio 1"; - - public AProjectionInfo() - {} - - public boolean processLocalCommand(String name) - { - return false; - } - - public abstract String getName(); - - public String getScreenName() - { - return getName(); - } - - protected Color getBackgroundFillColor(Color[] colorMap) - { - return colorMap[parameterStore.get("Color", "BkgFill").getI()]; - } - - public void paint(AWindow window, Graphics g) - { - - AEvent event = null; - AGraphics ag = AGraphics.makeAGraphics(g); - long time = 0; - - if (debug) - { - time = System.currentTimeMillis(); - } - fillBackground(window, ag); - if (debug) - { - System.out.println("fill " + (System.currentTimeMillis() - time)); - time = System.currentTimeMillis(); - } - - - // draw the current event - event = eventManager.getCurrentEvent(); - - //If there is no current event do nothing - if (event == null) return; - - } // paint() - - protected void fillBackground(AWindow window, AGraphics ag) - { - ag.setColor(getBackgroundFillColor(AColorMap.getColors())); - ag.fillRect(0, 0, window.getWidth(), window.getHeight()); - } - - protected static Point2D.Double[] aspectRatioLayout(double width, double height, Dimension wSize) - { - double f = Math.min(wSize.width / width, wSize.height / height); - - width = wSize.width / f; - height = wSize.height / f; - - Point2D.Double[] corners = new Point2D.Double[3]; - - corners[0] = new Point2D.Double(-width, +height); - corners[1] = new Point2D.Double(+width, +height); - corners[2] = new Point2D.Double(+width, -height); - return corners; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionLegoPlot.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionLegoPlot.java deleted file mode 100755 index 2179a2d7f2e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionLegoPlot.java +++ /dev/null @@ -1,402 +0,0 @@ -package atlantis.projection; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.event.ActionEvent; -import java.awt.geom.Point2D; -import java.util.HashSet; -import java.util.Set; - -import atlantis.canvas.ACanvas; -import atlantis.canvas.AWindow; -import atlantis.data.ACalorimeterData; -import atlantis.data.ADHelix; -import atlantis.event.AEvent; -import atlantis.data.ALegoData; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.graphics.ALegoDraw; -import atlantis.graphics.colormap.AColorMap; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.utils.AMath; - -public class AProjectionLegoPlot extends AProjection2D -{ - public static byte nLayers = 29;//also used in ALegoData - //xz and yz are used to define the angle of the eta axis (altered in rotate interaction) - private static double[] xz; - private static double[] yz; - //Variables needed by ALegoDraw and ALegoData that are updated here from changes to the gui value - public static int defaultScale = parameterStore.get("LegoPlot", "Scale").getI();//set the axis scale (standard, log or sqrt) - public static int nPhiCells = parameterStore.get("LegoPlot", "nphicells").getI(); - public static int nEtaCells = parameterStore.get("LegoPlot", "netacells").getI(); - public static Color[] defaultColorMap = AColorMap.getColors(); - public static Color[] caloColorMap = AColorMap.getColors();//to allow colouring by energy - public static boolean reverse = false;//also used by ASynchroCursorsInteraction - public static int mode = parameterStore.get("LegoPlot", "Mode").getI(); - public static int colorEM, colorHad; - public static Set colorset = new HashSet();//not updated here - public static final int minimumofLogScale=(int) Math.round(Math.log10(0.01));// we set 10MeV to lego height 0 on log scale - protected final static String VIEW_DEFAULT = "View normal"; - protected final static String VIEW_FROM_ABOVE = "View from above"; - protected final static String VIEW_ET_ETA = "View Et v " + AMath.ETA; - protected final static String VIEW_ET_PHI = "View Et v " + AMath.PHI; - - //to select th right drawing options for AOD object towers - public final static int DRAW_MET = -21; - public final static int DRAW_MUON = -2; - public final static int DRAW_ELECTRON = -3; - public final static int DRAW_PHOTON = -4; - public final static int DRAW_CLUSTER = -5; - public final static int DRAW_COMPOSITEPARTICLE = -6; - public final static int DRAW_BJET = -7; - public final static int DRAW_TAUJET = -8; - public final static int DRAW_JET = -9; - - public AProjectionLegoPlot() { - addPopupItem(VIEW_DEFAULT); - addPopupItem(VIEW_FROM_ABOVE); - addPopupItem(VIEW_ET_ETA); - addPopupItem(VIEW_ET_PHI); - } - - @Override - public void actionPerformed(ActionEvent e) - { - String action = e.getActionCommand(); - int index=0; - AWindow currentWindow = ACanvas.getCanvas().getCurrentWindow(); - index=currentWindow.getIndex(); - Point2D.Double[] corners = currentWindow.getUserCorners(); - double dPhi=0,dEta=0,currentxz=xz[index],currentyz=yz[index]; - - if (action.equals(VIEW_DEFAULT)) - { - xz[index]=0.6; - yz[index]=0.5; - } - else if (action.equals(VIEW_FROM_ABOVE)) - { - xz[index]=0.8; - yz[index]=0.9; - } - else if (action.equals(VIEW_ET_PHI)) - { - xz[index]=0.0; - yz[index]=-50; - } - else if (action.equals(VIEW_ET_ETA)) - { - xz[index]=360.0; - yz[index]=-75; - } - dPhi=360*(xz[index]-currentxz); - dEta=50*(currentyz-yz[index]); - corners[0].x -= (dPhi); - corners[0].y -= (dEta); - corners[1].y -= (dEta); - currentWindow.setUserCorners(corners); - //reset the center of detector dot on ZMR - // TODO: Check if this really is superfluous. I can't find any situation where it - // sets the interaction group to anything other than its old value. - Ben Waugh 2011-11-09 -// currentWindow.getInteractionManager().setContext(currentWindow.getInteractionToolBar().getSelectedGroup()); - } - - @Override - public void setAspectRatio1(AWindow window) - { - AOutput.append("\nNot implemented for this projection\n", ALogInterface.WARNING); - } - - public String getName() - { - return "LegoPlot"; - } - - public String getXLabel() - { - return AMath.PHI; - } - - public String getYLabel() - { - return AMath.ETA; - } - - public String getXUnits() - { - return AMath.DEGREES; - } - - public String getYUnits() - { - return ""; - } - - public Point2D.Double getCenter() - { - /*in the lego plot the center changes if there is rotation - however the getCenter is also needed in initialization - which is before windows are indexed*/ - int index=0; - double temp=0; - //check to see if the windows are indexed - try - { - index=ACanvas.getCanvas().getCurrentWindow().getIndex(); - } - catch(Throwable t) - { - temp=0.6;//hasn't indexed windows yet - } - if(temp==0) - temp=xz[index]; - return new Point2D.Double(-360.0*temp,-5.0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) - { - if(xz==null) - { - xz=new double[ACanvas.getCanvas().getWindowsCount()]; - for(int i=0; i<ACanvas.getCanvas().getWindowsCount(); i++) - { - xz[i]=0.6; - } - } - if(yz==null) - { - yz=new double[ACanvas.getCanvas().getWindowsCount()]; - for(int i=0; i<ACanvas.getCanvas().getWindowsCount(); i++) - { - yz[i]=0.5; - } - } - if(ACanvas.getCanvas().getCurrentWindow()!=null) - { - int currentIndex =ACanvas.getCanvas().getCurrentWindow().getIndex(); - xz[currentIndex]=0.6; - yz[currentIndex]=0.5; - } - //called before have windows so xz=0.6 and yz=0.5 - Point2D.Double[] corners = new Point2D.Double[3]; - corners[0]=new Point2D.Double(-360.0*0.6,-5-0.5*50); - corners[1]=new Point2D.Double(360.0, -5-0.5*50); - corners[2]=new Point2D.Double(360.0, 5); - //add on an offset - corners[0].x-=25.0; - corners[1].x+=25.0; - corners[2].x+=25.0; - corners[2].y+=3.0; - return corners; - } - - public ACoord getUserPoint(ADHelix dH, double s) - { - return nonLinearTransform(dH.getLEGOPoint(s)); - } - - @Override - public void paint(AWindow window, Graphics g) - { - // update parameters - update(); - // Load the event - AEvent event = eventManager.getCurrentEvent(); - if (event == null) - return; - // Create and fill histograms - double[][][] lego = new double[nPhiCells][nEtaCells][nLayers]; - ALegoData.fillHistograms(event, lego); - // Find the maximum energy - double maxEt = 0.0, AODmaxEt = 0.0, LEGOmaxEt = 0.0; - // loop over histogram data to scale towers and find maxEt - LEGOmaxEt = ALegoData.findMaxEt(lego); - maxEt=LEGOmaxEt; - // loop over AOD data - AODmaxEt = ALegoData.findAODMaxEt(event); - //check if user wants to scale to AOD objects rather than cells - //but only if the AOD max is greater than 0 - if(AODmaxEt==0) - { - if(!parameterStore.get("LegoPlot", "ScaleToAOD").isInitialized()) - parameterStore.get("LegoPlot", "ScaleToAOD").initialize(); - parameterStore.get("LegoPlot", "ScaleToAOD").getNameComponent().setEnabled(false); - } - else - { - if(!parameterStore.get("LegoPlot", "ScaleToAOD").isInitialized()) - parameterStore.get("LegoPlot", "ScaleToAOD").initialize(); - parameterStore.get("LegoPlot", "ScaleToAOD").getNameComponent().setEnabled(true); - } - if(AODmaxEt>0 && parameterStore.get("LegoPlot", "ScaleToAOD").getStatus()) - { - maxEt=AODmaxEt; - //user can no longer set the scale manually - if(!parameterStore.get("LegoPlot", "ETAxisHeight").isInitialized()) - parameterStore.get("LegoPlot", "ETAxisHeight").initialize(); - parameterStore.get("LegoPlot", "ETAxisHeight").getNameComponent().setEnabled(false); - parameterStore.get("LegoPlot", "ETAxisHeight").getValueComponent().setEnabled(false); - } - else - { - //user can now set the scale maually - if(!parameterStore.get("LegoPlot", "ETAxisHeight").isInitialized()) - parameterStore.get("LegoPlot", "ETAxisHeight").initialize(); - parameterStore.get("LegoPlot", "ETAxisHeight").getNameComponent().setEnabled(true); - parameterStore.get("LegoPlot", "ETAxisHeight").getValueComponent().setEnabled(true); - //check if user has defined a scale - if (parameterStore.get("LegoPlot", "ETAxisHeight").getD() > 0.0) - { - // use the user defined scale - maxEt = parameterStore.get("LegoPlot", "ETAxisHeight").getD(); - } - } - // Find the missing ET - double met = ALegoData.findMissingEt(window,lego,event); - // Begin drawing - AGraphics ag = AGraphics.makeAGraphics(g); - // Fill the background - ALegoDraw.fillBackground(window, ag); - // Draw the legend - boolean drawLegend=false; - if(!drawLegend && parameterStore.get("LegoPlot", "MainLegend").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "L1EtLegend").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "L1Items").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "L2Items").getStatus())drawLegend=true; - if(!drawLegend && parameterStore.get("LegoPlot", "EFItems").getStatus())drawLegend=true; - if(drawLegend)ALegoDraw.drawLegend(window,ag,event,met,maxEt,AODmaxEt); - - // Scale the values for the axis type - maxEt=scaleMaxET(maxEt,AODmaxEt); - AODmaxEt=ALegoData.scaleValue(AODmaxEt); - met=ALegoData.scaleValue(met); - if(parameterStore.get("LegoPlot","DrawPlot").getStatus()) - { - // Draw the grid - //System.out.println("maxEt = "+maxEt+" and LEGOmaxEt = "+LEGOmaxEt); - ALegoDraw.drawGrid(window, ag, maxEt); - // Draw the histograms - ALegoData.drawHistograms(window, ag, event, lego, maxEt, met, AODmaxEt); - } - } // paintLego() - - /** - * MaxEt is rounded to get the axis height as well as being scaled - */ - private static double scaleMaxET(double maxEt, double AODmaxEt) - { - //for drawing if maxEt is 0 use AODmaxEt for scaling - if (maxEt == 0) - maxEt = AODmaxEt; - maxEt=ALegoData.scaleValue(maxEt); - //now round to get axis height - if (defaultScale ==1 ) - { - maxEt = Math.ceil(maxEt); - } - else if (maxEt > 10.0) - { - //set maximum to nearest 5 above maxEt - maxEt = 5 * (Math.ceil(maxEt / 5.0)); - } - else if (maxEt < 10.0) - { - maxEt = Math.ceil(maxEt); - } - return maxEt; - } - - /** Shifts the real value of phi to the screen coord to account for the slope of the eta axis. - * For reverse of operation use -adjustPhi(window,-phi,eta) - */ - public static double adjustPhi(AWindow window, double phi, double eta) - { - int index=window.getIndex(); - eta+=5;//scale to between 0 and 10 - eta/=10.0;//scale to between 0 and 1 - eta-=1;//scale to between -1 and 0 - eta*=(xz[index]*360.0);//fraction of full offset to take off - phi+=eta;//take off the fraction - return phi;//now adjusted from slant of eta axis - } - - public static double getxz(int index) - { - return xz[index]; - } - - public static double getyz(int index) - { - return yz[index]; - } - - public static void setxz(int index, double xznew) - { - xz[index]=xznew; - } - - public static void setyz(int index, double yznew) - { - yz[index]=yznew; - } - - /**check if colouring by EM/HAD - * - * @return boolean drawEMHAD - */ - public static boolean getDrawEMHAD() - { - boolean drawEMHAD=false; - if (mode == 0 && parameterStore.get("LAr", "ColorFunction").getI()==6) - { - //Calorimeter Lego - drawEMHAD=true; - } - else if (mode == 1 && parameterStore.get("LVL1TriggerTower", "ColorFunction").getI()==1) - { - //Trigger Tower Lego - drawEMHAD=true; - } - return drawEMHAD; - } - - public static void update() - { - defaultScale = parameterStore.get("LegoPlot", "Scale").getI(); - nPhiCells = parameterStore.get("LegoPlot", "nphicells").getI(); - nEtaCells = parameterStore.get("LegoPlot", "netacells").getI(); - defaultColorMap = AColorMap.getColors(); - caloColorMap = AColorMap.getColors(); - if (parameterStore.get("LAr", "ColorFunction").getI() == ACalorimeterData.COLOR_FUNC_ENERGY) - { - switch (AColorMap.getColorMap()) - { - case AColorMap.COLOR_MAP_DEFAULT1: - case AColorMap.COLOR_MAP_DEFAULT2: - case AColorMap.COLOR_MAP_M4M5: - case AColorMap.COLOR_MAP_GRAYDET: - case AColorMap.COLOR_MAP_ORIGINAL: - // Use colors. - caloColorMap = AColorMap.getColors(AColorMap.COLOR_MAP_HITCOL); - break; - case AColorMap.COLOR_MAP_GRAY: - case AColorMap.COLOR_MAP_BW: - // Use grayscale. - caloColorMap = AColorMap.getColors(AColorMap.COLOR_MAP_GRAY_HITCOL); - break; - } - } - else if (parameterStore.get("LAr", "ColorFunction").getI() == ACalorimeterData.COLOR_FUNC_TIME) - { - caloColorMap = AColorMap.getShades(nLayers+1); - } - reverse = parameterStore.get("LegoPlot", "Reverse").getStatus(); - mode = parameterStore.get("LegoPlot", "Mode").getI(); - //Use detector color but add on 12 to get different shade of same color - colorEM = parameterStore.get("Det", "ECAL" + "Fill").getI() + 12; - colorHad = parameterStore.get("Det", "HCAL" + "Fill").getI() + 12; - } -}//end of LegoProjection class diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionN3D.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionN3D.java deleted file mode 100644 index 1c57d9e8a71..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionN3D.java +++ /dev/null @@ -1,66 +0,0 @@ -package atlantis.projection; - -import atlantis.nge.ANFrameManager; -import java.awt.event.ActionEvent; -import javax.swing.JMenuItem; - -/** - * - * @author Adam Davison - */ -public class AProjectionN3D extends AProjectionNGE { - - @Override - public void configureFrame(ANFrameManager fm) { - fm.checkProjection3D(); - } - - @Override - public String getName() { - return "N3D"; - } - - @Override - public String getScreenName() { - return "N3D"; - } - - @Override - public JMenuItem[] getPopupItems() { - return null; - } - - @Override - public String getXLabel() { - return "X"; - } - - @Override - public String getYLabel() { - return "Y"; - } - - @Override - public String getXUnits() { - return "m"; - } - - @Override - public String getYUnits() { - return "m"; - } - - @Override - public void setScales() { - - } - - @Override - public boolean processLocalCommand(String name) { - return false; - } - - public void actionPerformed(ActionEvent e) { - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNGE.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionNGE.java deleted file mode 100644 index 3f9294ff858..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNGE.java +++ /dev/null @@ -1,143 +0,0 @@ -package atlantis.projection; - -import atlantis.canvas.AWindow; -import atlantis.nge.ANFrameManager; -import atlantis.nge.ANManager; -import atlantis.utils.ALogger; -import com.sun.opengl.util.Screenshot; -import java.awt.Graphics; -import java.awt.image.BufferedImage; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLEventListener; - -/** - * This projection bridges between the traditional canvas and the new graphics - * engine code. Essentially it looks like an old style projection but when - * asked to paint it calls the new code and returns an image - * - * @author Adam Davison - */ -public abstract class AProjectionNGE extends AProjection implements GLEventListener { - - private static ALogger logger = ALogger.getLogger(AProjectionNGE.class); - - //private GLPbuffer m_buf = null; - private BufferedImage m_img = null; - private int m_h = 0; - private int m_w = 0; - - private AWindow m_currentWindow; - - public AProjectionNGE() { - - } - -/* @Override - public String getName() { - return "NGE"; - } - - @Override - public String getScreenName() { - return "NGE"; - }*/ - - public abstract void configureFrame(ANFrameManager fm); - - @Override - public void paint(AWindow window, Graphics g) { - - m_currentWindow = window; - - long before = System.nanoTime(); - - m_w = window.getWidth(); - m_h = window.getHeight(); - - //logger.info("Window w: " + m_w + " h: " + m_h); - - //System.out.println("TAG A"); - - configureFrame(ANManager.getManager().getFrameManager(window)); - - //System.out.println("TAG B"); - - ANManager.getManager().requestBufferDraw(m_w, m_h, this); - - //System.out.println("TAG C"); - - // TODO: Check m_img isn't null - //g.drawImage(m_img, 0, 0, m_w, m_h, null); - g.drawImage(m_img, 0, 0, m_w, m_h, 0, m_img.getHeight()-m_h, m_w, m_img.getHeight(), null); - - //System.out.println("TAG D copyback done"); - - long after = System.nanoTime(); - //System.out.println("Draw took: " + (after - before)/1000); - - //ANManager.getManager().requestReschedule(window); - } - -/* @Override - public JMenuItem[] getPopupItems() { - return null; - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public String getXLabel() { - return "XLABEL"; - } - - @Override - public String getYLabel() { - return "YLABEL"; - } - - @Override - public String getXUnits() { - return ""; - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public String getYUnits() { - return ""; - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void setScales() { - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean processLocalCommand(String name) { - return false; - //throw new UnsupportedOperationException("Not supported yet."); - } - - public void actionPerformed(ActionEvent e) { - System.out.println(e.toString()); - //throw new UnsupportedOperationException("Not supported yet."); - }*/ - - public void init(GLAutoDrawable arg0) { - } - - public void display(GLAutoDrawable arg0) { - - //System.out.println("DISPLAY IN NGE"); - ANManager.getManager().getFrameManager(m_currentWindow).display(arg0, m_w, m_h); - //System.out.println("PAINT DONE"); - m_img = Screenshot.readToBufferedImage(ANManager.getNextPower2(m_w), - ANManager.getNextPower2(m_h)); - //System.out.println("COPIED BACK"); - } - - public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { - } - - public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { - } -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNPhysics.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionNPhysics.java deleted file mode 100644 index e608bd9e51c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNPhysics.java +++ /dev/null @@ -1,95 +0,0 @@ -package atlantis.projection; - -import atlantis.nge.ANAnimVar; -import atlantis.nge.ANFrameManager; -import atlantis.nge.ANProjectionPhysics; -import atlantis.utils.AMath; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JMenuItem; - -/** - * - * @author Adam Davison, Mark Stockton - */ -public class AProjectionNPhysics extends AProjectionNGE { - - private ANProjectionPhysics m_p = null; - private ANFrameManager m_fm = null; - - @Override - public void configureFrame(ANFrameManager fm) { - m_fm = fm; - m_p = fm.checkProjectionPhysics(); - } - - @Override - public String getName() { - return "NPhysics"; - } - - @Override - public String getScreenName() { - return "NPhysics"; - } - - @Override - public JMenuItem[] getPopupItems() { - - JMenuItem phi = new JMenuItem(AMath.ETA + " view"); - phi.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - phiView(); - } - }); - - JMenuItem[] i = { - phi - }; - return i; - } - - @Override - public String getXLabel() { - return "X"; - } - - @Override - public String getYLabel() { - return "Y"; - } - - @Override - public String getXUnits() { - return "m"; - } - - @Override - public String getYUnits() { - return "m"; - } - - @Override - public void setScales() { - - } - - @Override - public boolean processLocalCommand(String name) { - return false; - } - - public void actionPerformed(ActionEvent e) { - } - - public void phiView() { - - ANAnimVar pelev = m_p.getElevVar(); - ANAnimVar pphi = m_p.getPhiVar(); - - m_fm.getAnimationManager().scheduleAnimation(pelev, 0.0, 1.0, pelev.getValue(), -90.0); - m_fm.getAnimationManager().scheduleAnimation(pphi, 0.0, 1.0, pphi.getValue(), 0.0); - - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNYX.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionNYX.java deleted file mode 100644 index fb95d8ff95a..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionNYX.java +++ /dev/null @@ -1,71 +0,0 @@ -package atlantis.projection; - -import atlantis.nge.ANFrameManager; -import java.awt.event.ActionEvent; -import javax.swing.JMenuItem; - -/** - * - * @author Adam Davison - */ -public class AProjectionNYX extends AProjectionNGE { - - public AProjectionNYX() { - - } - - @Override - public void configureFrame(ANFrameManager fm) { - fm.checkProjectionYX(); - } - - @Override - public String getName() { - return "NYX"; - } - - @Override - public String getScreenName() { - return "NYX"; - } - - @Override - public JMenuItem[] getPopupItems() { - return null; - } - - @Override - public String getXLabel() { - return "X"; - } - - @Override - public String getYLabel() { - return "Y"; - } - - @Override - public String getXUnits() { - return "m"; - } - - @Override - public String getYUnits() { - return "m"; - } - - @Override - public void setScales() { - - } - - @Override - public boolean processLocalCommand(String name) { - return false; - } - - public void actionPerformed(ActionEvent e) { - // - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionPhi.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionPhi.java deleted file mode 100755 index 92785454bb5..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionPhi.java +++ /dev/null @@ -1,73 +0,0 @@ -package atlantis.projection; - -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import atlantis.utils.AVector; -import java.awt.geom.*; - -/** - * Base class of all phi projections - */ - -public abstract class AProjectionPhi extends AProjection2D { - - public String getScreenName() - { - return AMath.PHI+ getXLabel(); - } - - public String getYLabel() { - return AMath.PHI; - } - - public String getYUnits() { - return AMath.DEGREES; - } - - public double getMinRho() { - return 2.; - } - - public Point2D.Double getCenter() { - int phiWrap=parameterStore.get(getName(), "PhiWrap").getI(); - - return new Point2D.Double(0, (360+phiWrap)/2); - } - - public Point2D.Double[] validateCorners(Point2D.Double[] corners) { - if(super.validateCorners(corners)==null) - return null; - int phiWrap=parameterStore.get(getName(), "PhiWrap").getI(); - AParameter initialFramePar=parameterStore.get(getName(), "InitialFrame"); - - if(Math.abs(getMaxPhi(corners)-getMinPhi(corners))>(360+phiWrap)) - return null; - if(getMaxPhi(corners)>(initialFramePar.getI()*360+2*360-90)) - initialFramePar.setI(initialFramePar.getI()+1); - if(getMinPhi(corners)<(initialFramePar.getI()*360+90)) - initialFramePar.setI(initialFramePar.getI()-1); - return corners; - } - - private static double getMinPhi(Point2D.Double[] corners) { - double phiMin=corners[0].y; - - for(int i=0; i<corners.length; i++) - if(corners[i].y<phiMin) phiMin=corners[i].y; - AVector v12=new AVector(corners[1], corners[2]); - - return Math.min(phiMin, corners[0].y+v12.dy); - } - - private static double getMaxPhi(Point2D.Double[] corners) { - double phiMax=corners[0].y; - - for(int i=0; i<corners.length; i++) - if(corners[i].y>phiMax) phiMax=corners[i].y; - AVector v12=new AVector(corners[1], corners[2]); - - return Math.max(phiMax, corners[0].y+v12.dy); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionRZ.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionRZ.java deleted file mode 100755 index a47d1e0f05f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionRZ.java +++ /dev/null @@ -1,68 +0,0 @@ -package atlantis.projection; - -import atlantis.data.ADHelix; -import atlantis.graphics.ACoord; -import atlantis.utils.AMath; -import java.awt.*; -import java.awt.geom.*; -import atlantis.event.*; -import atlantis.parameters.*; - -public class AProjectionRZ extends AProjection2D { - - public AProjectionRZ() { - addPopupItem(ASPECT_RATIO_1); - } - - public String getName() { - return "RZ"; - } - - public String getScreenName() - { - return AMath.RHO + "Z"; - } - - public String getXLabel() { - return "Z"; - } - - public String getYLabel() { - return AMath.RHO; - } - - public String getXUnits() { - return "(cm)"; - } - - public String getYUnits() { - return "(cm)"; - } - - public Point2D.Double getCenter() { - return new Point2D.Double(0, 0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - double radius=parameterStore.get("Projection", "Radius").getD(); - double length=parameterStore.get("Projection", "Length").getD(); - return aspectRatioLayout(length, radius, wSize); - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return nonLinearTransform(dH.getRZPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) { - return nonLinearTransform2D(user, getName()); - } - - public ACoord inverseNonLinearTransform(ACoord user) { - return inverseNonLinearTransform2D(user, getName()); - } - - public static int[] getAxisMapping() { - return new int[] {2, 1, 0}; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionTrackResidual.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionTrackResidual.java deleted file mode 100644 index fc07eddcbea..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionTrackResidual.java +++ /dev/null @@ -1,167 +0,0 @@ -package atlantis.projection; - -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.geom.Point2D; - -import atlantis.canvas.AWindow; -import atlantis.data.ADHelix; -import atlantis.data.ATrackResidualData; -import atlantis.graphics.ACoord; -import atlantis.graphics.AGraphics; -import atlantis.parameters.APar; -import atlantis.utils.AMath; - -public class AProjectionTrackResidual extends AProjection2D -{ - private ATrackResidualData residual; - private String residualType; - private double xLength; - private double yLength = 1.0; - - /** - * @param residual The residual to set. - */ - public void setResidual(ATrackResidualData residual) - { - this.residual = residual; - } - - public ATrackResidualData getResidual() - { - return residual; - } - - public void setResidualType(String type) - { - residualType = type; - } - - public String getResidualType() - { - return residualType; - } - - public String getName() - { - return "TrackResidual"; - } - - public String getXLabel() - { - return "Index"; - } - - public String getYLabel() - { - return "Res"; - } - - public String getXUnits() - { - return ""; - } - - public String getYUnits() - { - return "(mm)"; - } - - public double getXLength() - { - return xLength; - } - - public double getYLength() - { - return yLength; - } - - public Point2D.Double getCenter() - { - return new Point2D.Double(0.0, 0.0); - } - - // not useful for this projection, only put here to be compatible with - // other code - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) - { - Point2D.Double[] corners=new Point2D.Double[3]; - - corners[0]=new Point2D.Double(0., 2.); - corners[1]=new Point2D.Double(100., 2.); - corners[2]=new Point2D.Double(100., -2.); - return corners; - } - - public Point2D.Double[] calculateNoZoomCorners() - { - float[] dataArray; - if(residualType.equals(ATrackResidualData.RESIDUAL_X)) - dataArray = residual.getResLoc1(); - else - dataArray = residual.getPullLoc1(); - - xLength = dataArray.length; - if(parameterStore.get(getName(), "Scale").getI() == 0) // linear - { - yLength = (AMath.maxAbsInArray(dataArray) + 0.1) * 2; - } - else // logarithmic - { - float[] dataArrayCopy = new float[dataArray.length]; - for(int i=0; i<dataArrayCopy.length; ++i) - { - if(dataArray[i] == -99.0f) - dataArrayCopy[i] = 0.0f; - else - dataArrayCopy[i] = dataArray[i]; - } - double minValue = (double) AMath.minAbsInArray(dataArrayCopy); - double maxValue = (double) AMath.maxAbsInArray(dataArrayCopy); - double magnitude; - - // all data is either invalid or 0 - if(maxValue == 0.0 && minValue == 0.0) - { - magnitude = 1; - residual.setLogMagnitudeMin(-1.0); - } - else if (minValue == 0.0) - { - double minNonZeroValue = (double) AMath.minNonZeroAbsInArray(dataArrayCopy); - magnitude = Math.floor(Math.log10(maxValue)) - - Math.floor(Math.log10(minNonZeroValue))+ 1.0; - residual.setLogMagnitudeMin(Math.floor(Math.log10(minNonZeroValue))); - } - else - { - magnitude = Math.floor(Math.log10(maxValue)) - - Math.floor(Math.log10(minValue))+ 1.0; - residual.setLogMagnitudeMin(Math.floor(Math.log10(minValue))); - } - yLength = magnitude * 2; - } - Point2D.Double[] corners = new Point2D.Double[3]; - - corners[0] = new Point2D.Double(0., yLength/2); - corners[1] = new Point2D.Double(xLength, yLength/2); - corners[2] = new Point2D.Double(xLength, -yLength/2); - return corners; - } - - public ACoord getUserPoint(ADHelix dH, double s) - { - return ACoord.NO_DATA; - } - - public void paint(AWindow window, Graphics g) - { - AGraphics ag = AGraphics.makeAGraphics(g); - - fillBackground(window, ag); - if(residual != null) - residual.draw(window, ag, this); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionVP.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionVP.java deleted file mode 100755 index 210d848d447..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionVP.java +++ /dev/null @@ -1,169 +0,0 @@ -package atlantis.projection; - -import atlantis.graphics.ACoord; -import atlantis.graphics.colormap.AColorMap; -import atlantis.output.ALogInterface; -import atlantis.output.AOutput; -import atlantis.parameters.AParameter; -import atlantis.parameters.APar; -import atlantis.utils.AMath; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.geom.Point2D; - -import atlantis.canvas.AWindow; -import atlantis.data.ADHelix; - -public class AProjectionVP extends AProjectionPhi { - - // this should be moved ugly - // sign is which arm of the v is being drawn at this point in time - public static int sign; - - private static double qcp=0.00035936; - - // Display modes as defined in the configuration file. - public static final int MODE_STANDARD = 0; - public static final int MODE_SPACEPOINT = 1; - public static final int MODE_TRT_DRIFT_CIRCLE = 2; - public static final int MODE_ECAL_LAYER_0 = 3; - public static final int MODE_ECAL_LAYER_1 = 4; - public static final int MODE_ECAL_LAYER_2 = 5; - public static final int MODE_ECAL_LAYER_3 = 6; - public static final int MODE_HCAL_LAYER_0 = 7; - public static final int MODE_HCAL_LAYER_1 = 8; - public static final int MODE_HCAL_LAYER_2 = 9; - public static final int MODE_HCAL_LAYER_3 = 10; - - public static final double MAX_ETA = 5.; - - private static boolean first=true; - // draw V apex at this rho or Z - private static double[] rhoMode=new double[] - { 55., 55., 108., 138., 154., 173., 193., 244., 306., 368., 368.}; - private static double[] zMode=new double[] - {277., 277., 338., 360., 374., 394., 414., 441., 482., 561., 561.}; - // zoom in another projection to this rho and Z - private static double[] rhoZoomMode=new double[] - { 56., 56., 110., 200., 200., 200., 200., 400., 400., 400., 400.}; - private static double[] zZoomMode=new double[] - {280., 280., 340., 440., 440., 440., 440., 374., 374., 374., 374.}; - - private static AParameter modePar; - private static AParameter rMaxPar; - private static AParameter zMaxPar; - private static AParameter gradientPar; - private static AParameter zVtxPar; - - public AProjectionVP() {} - - public String getName() { - return "VP"; - } - - public String getXLabel() { - return AMath.ETA; - } - - public String getXUnits() { - return ""; - } - - public void setAspectRatio1(AWindow window) - { - AOutput.append("\nNot implemented for this projection\n", ALogInterface.WARNING); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - Point2D.Double[] corners=new Point2D.Double[3]; - - corners[0]=new Point2D.Double(-5.0, 360); - corners[1]=new Point2D.Double(5.0, 360); - corners[2]=new Point2D.Double(5.0, 0); - return corners; - } - - protected Color getBackgroundFillColor(Color[] colorMap) { - int mode=parameterStore.get("VP", "Mode").getI(); - - switch(mode) { - case MODE_SPACEPOINT: - return colorMap[parameterStore.get("Det", "SIL"+"Fill").getI()]; - case MODE_TRT_DRIFT_CIRCLE: - return colorMap[parameterStore.get("Det", "TRT"+"Fill").getI()]; - case MODE_ECAL_LAYER_0: - case MODE_ECAL_LAYER_1: - case MODE_ECAL_LAYER_2: - case MODE_ECAL_LAYER_3: - return colorMap[parameterStore.get("Det", "ECAL"+"Fill").getI()]; - case MODE_HCAL_LAYER_0: - case MODE_HCAL_LAYER_1: - case MODE_HCAL_LAYER_2: - case MODE_HCAL_LAYER_3: - return colorMap[parameterStore.get("Det", "HCAL"+"Fill").getI()]; - default: - return colorMap[parameterStore.get("Color", "Bkg"+"Fill").getI()]; - } - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return dH.getVPPoint(s, this.sign); - } - - public static double getDeltaEta(double rho, double z) { - if(first) { - modePar=parameterStore.get("VP", "Mode"); - rMaxPar=parameterStore.get("VP", "RMax"); - zMaxPar=parameterStore.get("VP", "ZMax"); - gradientPar=parameterStore.get("VP", "Gradient"); - zVtxPar=parameterStore.get("VP", "ZVtx"); - first=false; - } - double fact=qcp*gradientPar.getD(); - int mode=modePar.getI(); - double zLayer=zMode[mode]; - - if(zMaxPar.getStatus()) - zLayer=Math.min(zLayer, zMaxPar.getD()); - double rhoLayer=rhoMode[mode]; - - if(rMaxPar.getStatus()) - rhoLayer=Math.min(rhoLayer, rMaxPar.getD()); - double zVtx=zVtxPar.getD(); - double zsign=1.; - - if(z<0.) zsign=-1.; - if(Math.abs((z-zVtx)/rho)<(zLayer-zVtx)/rhoLayer) - return fact*(rhoLayer-rho); - else - return fact*rho*(zsign*zLayer-z)/(z-zVtx); - } - - public static double getRhoVPlot() { - double rhoLayer=rhoMode[parameterStore.get("VP", "Mode").getI()]; - AParameter rMaxPar=parameterStore.get("VP", "RMax"); - - if(rMaxPar.getStatus()) - rhoLayer=Math.min(rhoLayer, rMaxPar.getD()); - return rhoLayer; - } - - public static double getZVPlot() { - double zLayer=zMode[parameterStore.get("VP", "Mode").getI()]; - AParameter zMaxPar=parameterStore.get("VP", "ZMax"); - - if(zMaxPar.getStatus()) - zLayer=Math.min(zLayer, zMaxPar.getD()); - return zLayer; - } - - public static double getRhoZoomVPlot() { - return rhoZoomMode[parameterStore.get("VP", "Mode").getI()]; - } - - public static double getZZoomVPlot() { - return zZoomMode[parameterStore.get("VP", "Mode").getI()]; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionXZ.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionXZ.java deleted file mode 100755 index 24f2d9b17cc..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionXZ.java +++ /dev/null @@ -1,81 +0,0 @@ -package atlantis.projection; - -import atlantis.data.ADHelix; -import atlantis.graphics.ACoord; -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import atlantis.event.*; -import java.awt.*; -import java.awt.geom.*; - -public class AProjectionXZ extends AProjection2D { - - public AProjectionXZ() { - addPopupItem(ASPECT_RATIO_1); - } - - public String getName() { - return "XZ"; - } - - public String getXLabel() { - return "Z"; - } - - public String getYLabel() { - return "X"+AMath.PRIME; - } - - public String getXUnits() { - return "(cm)"; - } - - public String getYUnits() { - return "(cm)"; - } - - public Point2D.Double getCenter() { - return new Point2D.Double(0, 0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - double radius=parameterStore.get("Projection", "TrackingRadius").getD(); - double length=parameterStore.get("Projection", "TrackingLength").getD(); - return aspectRatioLayout(length, radius, wSize); - } - - public static double getPhi() { - return parameterStore.get("XZ", "Phi").getD(); - } - - public static double[][] getRotationMatrix() { - double phi=Math.toRadians(getPhi()); - double cos=Math.cos(phi); - double sin=Math.sin(phi); - double[][] r=new double[3][3]; - - r[0][0]=cos; - r[1][1]=cos; - r[2][2]=1.; - r[0][1]=sin; - r[1][0]=-sin; - return r; - } - - public static int[] getAxisMapping() { - return new int[] {2, 0, 1}; - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return nonLinearTransform(dH.getXZPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) { - return nonLinearTransform2D(user, getName()); - } - - public ACoord inverseNonLinearTransform(ACoord user) { - return inverseNonLinearTransform2D(user, getName()); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionYX.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionYX.java deleted file mode 100755 index ef2a7d28db6..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionYX.java +++ /dev/null @@ -1,307 +0,0 @@ -package atlantis.projection; - -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; - -import javax.swing.ImageIcon; - -import atlantis.canvas.AWindow; -import atlantis.data.ADHelix; -import atlantis.globals.AGlobals; -import atlantis.graphics.ACoord; -import atlantis.graphics.ADrawParameters; -import atlantis.graphics.AGraphics; -import atlantis.graphics.colormap.AColorMap; -import atlantis.interactions.AZMRInteraction; -import atlantis.parameters.AParameter; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; - -public class AProjectionYX extends AProjection2D -{ - private static ALogger logger = ALogger.getLogger(AProjectionYX.class); - - // Different display modes, as defined in the configuration file. - public static final int MODE_STANDARD = 0; - public static final int MODE_TGC_INNER = 1; - public static final int MODE_TGC_MIDDLE_1 = 2; - public static final int MODE_TGC_MIDDLE_2 = 3; - public static final int MODE_TGC_MIDDLE_3 = 4; - public static final int MODE_MDT_INNER = 5; - public static final int MODE_MDT_EXTENSION = 6; - public static final int MODE_MDT_MIDDLE = 7; - public static final int MODE_MDT_OUTER = 8; - public static final int MODE_FCAL_EM = 9; - public static final int MODE_FCAL_HAD_1 = 10; - public static final int MODE_FCAL_HAD_2 = 11; - public static final int MODE_LAR_ENDCAP_PRESAMPLER = 12; - public static final int MODE_LAR_ENDCAP_1 = 13; - public static final int MODE_LAR_ENDCAP_2 = 14; - public static final int MODE_LAR_ENDCAP_3 = 15; - public static final int MODE_HEC_1 = 16; - public static final int MODE_HEC_2 = 17; - public static final int MODE_HEC_3 = 18; - public static final int MODE_HEC_4 = 19; - public static final int MODE_LAR_ENDCAP_SUMMED = 20; - public static final int MODE_HEC_SUMMED = 21; - public static final int MODE_MBTS = 22; - - public AProjectionYX() - { - addPopupItem(ASPECT_RATIO_1); - } - - public String getName() - { - return "YX"; - } - - public String getXLabel() - { - return "X"; - } - - public String getYLabel() - { - return "Y"; - } - - public String getXUnits() - { - return "(cm)"; - } - - public String getYUnits() - { - return "(cm)"; - } - - public Point2D.Double getCenter() - { - return new Point2D.Double(0, 0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) - { - // should not be here - parameterStore.get(getName(), "Phi").setD(0.); - double radius = parameterStore.get("Projection", "Radius").getD(); - return aspectRatioLayout(radius, radius, wSize); - } - - public static double[][] getRotationMatrix() - { - double[][] r = new double[3][3]; - - r[0][0] = 1.; - r[1][1] = 1.; - r[2][2] = 1.; - return r; - } - - public static int[] getAxisMapping() - { - return new int[] { 0, 1, 2 }; - } - - public ACoord getUserPoint(ADHelix dH, double s) - { - return nonLinearTransform(dH.getYXPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) - { - AParameter fishEyePar = parameterStore.get(getName(), "FishEye"); - - if (fishEyePar.getStatus()) - { - double[] x, y; - double r, fact; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(getName(), "rTo").getD(); - - for (int j = 0; j < user.hv[0].length; ++j) - { - x = user.hv[0][j]; - y = user.hv[1][j]; - for (int i = 0; i < x.length; ++i) - { - r = Math.sqrt(x[i] * x[i] + y[i] * y[i]); - fact = (1 + fishEye * rTo) / (1 + fishEye * r); - x[i] *= fact; - y[i] *= fact; - } - } - } - AParameter clockPar = parameterStore.get(getName(), "Clock"); - - if (clockPar.getStatus()) - { - double clock = Math.PI / clockPar.getD(); - double phiClock = Math.toRadians(parameterStore.get(getName(), "Phi").getD()); - - for (int j = 0; j < user.hv[0].length; ++j) - { - double[] x = user.hv[0][j]; - double[] y = user.hv[1][j]; - - for (int i = 0; i < x.length; ++i) - { - double phi = Math.atan2(y[i], x[i]); - - if (phi < 0.) - phi += 2 * Math.PI; - double rho = Math.sqrt(x[i] * x[i] + y[i] * y[i]); - double dPhi = phi - phiClock; - - if (dPhi > Math.PI) - dPhi -= 2 * Math.PI; - else if (dPhi <= -Math.PI) - dPhi += 2 * Math.PI; - double fact = (clock + Math.PI) / (clock + Math.abs(dPhi)); - - phi = phiClock + fact * dPhi; - x[i] = rho * Math.cos(phi); - y[i] = rho * Math.sin(phi); - } - } - } - - return user; - } - - public ACoord inverseNonLinearTransform(ACoord user) - { - AParameter fishEyePar = parameterStore.get(getName(), "FishEye"); - - if (fishEyePar.getStatus()) - { - double[] x, y; - double r, fact; - double fishEye = 0.001 * fishEyePar.getD(); - double rTo = parameterStore.get(getName(), "rTo").getD(); - - for (int j = 0; j < user.hv[0].length; ++j) - { - x = user.hv[0][j]; - y = user.hv[1][j]; - for (int i = 0; i < x.length; ++i) - { - r = Math.sqrt(x[i] * x[i] + y[i] * y[i]); - fact = 1 / (1 + fishEye * (rTo - r)); - x[i] *= fact; - y[i] *= fact; - } - } - } - AParameter clockPar = parameterStore.get(getName(), "Clock"); - - if (clockPar.getStatus()) - { - double clock = Math.PI / clockPar.getD(); - double phiClock = Math.toRadians(parameterStore.get(getName(), "Phi").getD()); - - for (int j = 0; j < user.hv[0].length; ++j) - { - double[] x = user.hv[0][j]; - double[] y = user.hv[1][j]; - - for (int i = 0; i < x.length; ++i) - { - double phi = Math.atan2(y[i], x[i]); - - if (phi < 0.) - phi += 2 * Math.PI; - double dPhi = phi - phiClock; - - if (dPhi > Math.PI) - dPhi -= 2 * Math.PI; - else if (dPhi <= -Math.PI) - dPhi += 2 * Math.PI; - - double dPhiPrime = (clock * dPhi) / (clock + Math.PI - Math.abs(dPhi)); - - phi = phiClock + dPhiPrime; - - double rho = Math.sqrt(x[i] * x[i] + y[i] * y[i]); - - x[i] = rho * Math.cos(phi); - y[i] = rho * Math.sin(phi); - } - } - } - return user; - } - - public void paint(AWindow window, Graphics g) - { - super.paint(window, g); - - // draw RZ cutting plane - if (parameterStore.get("YX", "RZCuttingPlane").getStatus()) - { - AGraphics ag = AGraphics.makeAGraphics(g); - final ADrawParameters drawParameters = - new ADrawParameters(true, AColorMap.WH, 4, 1, 0, AGraphics.SYMBOL_FILLED_BOX); - ag.updateDrawParameters(drawParameters); - final double RHO_MAX = 3000.0; - - double phi = Math.toRadians(parameterStore.get("RZ", "Phi").getD()) - Math.PI / 2; - double cosPhi = Math.cos(phi); - double sinPhi = Math.sin(phi); - String iconPath = AGlobals.instance().getHomeDirectory() + "img" + System.getProperty("file.separator"); - - // draw the cutting plane - Point2D.Double p1 = window.calculateDisplay(nonLinearTransform(RHO_MAX * cosPhi, RHO_MAX * sinPhi)); - Point2D.Double p2 = window.calculateDisplay(nonLinearTransform(-RHO_MAX * cosPhi, -RHO_MAX * sinPhi)); - - ag.drawLine(p1.x, p1.y, p2.x, p2.y); - - // draw the arrows - Point2D.Double p3 = window.calculateDisplay(nonLinearTransform(1500 * Math.cos(phi+.07), 1500 * Math.sin(phi+.07))); - Point2D.Double p4 = window.calculateDisplay(nonLinearTransform(1500 * Math.cos(phi+3.21), 1500 * Math.sin(phi+3.21))); - - ImageIcon upArrow = AUtilities.getFileAsImageIcon(iconPath+"uparrow.png"); - ImageIcon downArrow = AUtilities.getFileAsImageIcon(iconPath+"downarrow.png"); - - Graphics2D g2d = (Graphics2D) g; - - g2d.drawImage(upArrow.getImage(),(int) p3.x,(int) p3.y,null); - g2d.drawImage(downArrow.getImage(),(int) p4.x,(int) p4.y,null); - - } - } - - /** This function ensures that when the aspect ratio of the display changes - * the aspect ratio of the contents of a YX projection remain at the same - * aspect ratio. - * - * It uses the (thankfully) static methods of AZMRInteraction to do the - * actual zooming, which can involve some non-trivial mathematics... - * -- Adam Davison - */ - @Override - public void aspectRatioChange(AWindow w, double oldaspect, double newaspect) { - logger.debug("ProjectionYX informed of aspect ratio change from " + oldaspect + " to " + newaspect); - - Point2D.Double[] corners = w.getUserCorners(); - - // Get center - Point2D.Double center = new Point2D.Double( - 0.5*(corners[0].x+corners[2].x), - 0.5*(corners[0].y+corners[2].y)); - - // If > 1, the new view is taller if < 1 it's wider - double fracchange = newaspect/oldaspect; - - if (fracchange > 1) { - // Need to vzoom "away" to restore aspect ratio - AZMRInteraction.performVerticalZoom(center, fracchange, w); - } else { - // Need to hzoom - AZMRInteraction.performHorizontalZoom(center, 1.0/fracchange, w); - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionYZ.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionYZ.java deleted file mode 100755 index 490afb72dfd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionYZ.java +++ /dev/null @@ -1,72 +0,0 @@ -package atlantis.projection; - - -import atlantis.graphics.ACoord; -import atlantis.utils.AMath; -import java.awt.*; -import java.awt.geom.*; -import atlantis.data.ADHelix; -import atlantis.parameters.*; - - -public class AProjectionYZ extends AProjection2D { - - public AProjectionYZ() { - addPopupItem(ASPECT_RATIO_1); - } - - public String getName() { - return "YZ"; - } - - public String getXLabel() { - return "Z"; - } - - public String getYLabel() { - return "Y"+AMath.PRIME; - } - - public String getXUnits() { - return "(cm)"; - } - - public String getYUnits() { - return "(cm)"; - } - - public Point2D.Double getCenter() { - return new Point2D.Double(0, 0); - } - - public Point2D.Double[] calculateNoZoomCorners(Dimension wSize) { - double radius=parameterStore.get("Projection", "TrackingRadius").getD(); - double length=parameterStore.get("Projection", "TrackingLength").getD(); - return aspectRatioLayout(length, radius, wSize); - } - - public static double getPhi() { - return AProjectionXZ.getPhi(); - } - - public static double[][] getRotationMatrix() { - return AProjectionXZ.getRotationMatrix(); - } - - public static int[] getAxisMapping() { - return new int[] {2, 1, 0}; - } - - public ACoord getUserPoint(ADHelix dH, double s) { - return nonLinearTransform(dH.getYZPoint(s)); - } - - public ACoord nonLinearTransform(ACoord user) { - return nonLinearTransform2D(user, getName()); - } - - public ACoord inverseNonLinearTransform(ACoord user) { - return inverseNonLinearTransform2D(user, getName()); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/AProjectionsManager.java b/graphics/AtlantisJava/src/atlantis/projection/AProjectionsManager.java deleted file mode 100755 index e9886ac1fef..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/AProjectionsManager.java +++ /dev/null @@ -1,110 +0,0 @@ -package atlantis.projection; - -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Set; -import java.util.Vector; - -import atlantis.output.AExceptionHandler; -import atlantis.parameters.APar; -import atlantis.parameters.AParametersGroup; - -/** - * This manager keeps references to all projections. - * - * The code keeping track of the list and states of interactions associated with each - * projection in each window, and creating the corresponding pop-up menus, has been - * moved to atlantis.gui.AInteractionToolBar and atlantis.interactions.AInteractionsByProjection. - */ -public class AProjectionsManager { - - // the set of projections (name : AProjection) - private static Hashtable<String,AProjection> projections = new Hashtable<String, AProjection>(); - private static Set<String> projectionsAvailableInDemoMode = new HashSet<String>(); - private static Set<String> defaultProjectionsInDemoMode = new HashSet<String>(); - - /** - * Creates projections using information from APar. - */ - public static void initialise() { - Vector<String> projVector=APar.instance().getUIGroupNames(AParametersGroup.PROJECTION); - - for (String projName : projVector) { - createProjection(projName); - } - } - - /** - * Used to request the projection with the given name - * @param projectionName The name of the projection - * @return The AProjection corespoinding to the projection name. - */ - public static AProjection getProjection(String projectionName) { - return projections.get(projectionName); - } - - /** - * Checks whether the given name is a valid projection name. - * @param name The name to be checked - * @return True/False - */ - public static boolean isValidProjection(String name) { - return projections.containsKey(name); - } - - /** - * Returns an array containing the names of all known projections - * @return The name array - */ - public static String[] getKnownProjectionNames() { - String[] names=new String[projections.size()]; - - Enumeration<String> myenum=projections.keys(); - - for(int i=0; i<projections.size(); i++) - names[i]=myenum.nextElement(); - - return names; - } - - /** - * Check whether the projection should be used in the demo dialog - * @return false if the projection should not be used or does not exist - */ - public static boolean useProjectionInDemoMode(String name){ - return projectionsAvailableInDemoMode.contains(name); - } - - /** - * @return true if the projection should be selected by default in the demo dialog - */ - public static boolean defaultProjectionInDemoMode(String name){ - return defaultProjectionsInDemoMode.contains(name); - } - - /** - * Creates an instance of a given projection and pushes it into the - * <code>projections</code> Hashtable. The name shold be for example: YX if you - * want to create a instance of AProjectionYX.java class. - * @param name The name of the projection. - */ - private static void createProjection(String name) { - try { - - AProjection p=(AProjection)Class.forName("atlantis.projection.AProjection"+name).newInstance(); - - projections.put(name, p); - } catch(Exception e) { - AExceptionHandler.processException("Cannot create AProjection"+name, e); - } - } - - public static void makeProjectionAvailableInDemoMode(String projection) { - projectionsAvailableInDemoMode.add(projection); - } - - public static void makeProjectionDefaultInDemoMode(String name) { - defaultProjectionsInDemoMode.add(name); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/projection/package.html b/graphics/AtlantisJava/src/atlantis/projection/package.html deleted file mode 100644 index 471774c48ca..00000000000 --- a/graphics/AtlantisJava/src/atlantis/projection/package.html +++ /dev/null @@ -1,9 +0,0 @@ -<html> -<head></head> -<body> -<p>Implementation of projections (XY, Rho Z, V plot, etc). Class - AProjectionManager changes the current projection and informs the - AEvent class instance of how to draw itself, e.g. in the XY - projection.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/utils/A3Vector.java b/graphics/AtlantisJava/src/atlantis/utils/A3Vector.java deleted file mode 100755 index 649a18dd317..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/A3Vector.java +++ /dev/null @@ -1,98 +0,0 @@ -package atlantis.utils; - - -/** - * Provides basic 3D vector operations. - */ - -public class A3Vector { - - public double x, y, z; - - /** - * Construct zero 3-vector. - */ - public A3Vector() {} - - /** - * Construct 3-vector from Cartesian coordinates. - * @param dx - * @param dy - * @param dz - */ - public A3Vector(double x, double y, double z) { - this.x=x; - this.y=y; - this.z=z; - } - - /** - * Create 3-vector from eta, phi and magnitude. - * @param eta pseudorapidity along z direction - * @param phi azimuthal angle [radians] - * @param r magnitude of vector - * @return new A3Vector - */ - public static A3Vector fromEtaPhiR(double eta, double phi, double r) { - double theta = 2.0 * Math.atan(Math.exp(-eta)); - return new A3Vector(r * Math.sin(theta) * Math.cos(phi), - r * Math.sin(theta) * Math.sin(phi), - r * Math.cos(theta)); - } - - /** - * Create 3-vector from cylindrical coordinates rho, phi, z. - * @param rho component perpendicular to z axis - * @param phi azimuthal angle [radians] - * @param z - * @return - */ - public static A3Vector fromRhoPhiZ(double rho, double phi, double z) { - double x=rho*Math.cos(phi); - double y=rho*Math.sin(phi); - return new A3Vector(x,y,z); - } - - public A3Vector getNormalized() { - double r=Math.sqrt(x*x+y*y+z*z); - return new A3Vector(x/r, y/r, z/r); - } - - public A3Vector normalize() { - double r=magnitude(); - x/=r; - y/=r; - z/=r; - return this; - } - - public double magnitude() { - return Math.sqrt(x*x+y*y+z*z); - } - - public A3Vector scale(double a) { - x*=a; - y*=a; - z*=a; - return this; - } - - public A3Vector add(A3Vector v) { - x+=v.x; - y+=v.y; - z+=v.z; - return this; - } - - public A3Vector subtract(A3Vector v) { - x-=v.x; - y-=v.y; - z-=v.z; - return this; - } - - public String toString() { - return "A3Vector[x="+x+", y="+y+", z="+z+"]"; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/A4Vector.java b/graphics/AtlantisJava/src/atlantis/utils/A4Vector.java deleted file mode 100755 index 5032250f170..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/A4Vector.java +++ /dev/null @@ -1,127 +0,0 @@ -package atlantis.utils; - -/** - * Provides basic 4D vector operations. - */ -public class A4Vector -{ - public double px, py, pz, e; - - public A4Vector() - {} - - public A4Vector(double dx, double dy, double dz, double m) - { - set(dx, dy, dz, m); - } - - public A4Vector(A3Vector v, double m) - { - set(v.x, v.y, v.z, m); - } - - public void set(double dx, double dy, double dz, double m) - { - px = dx; - py = dy; - pz = dz; - e = Math.sqrt(px * px + py * py + pz * pz + m * m); - } - - public void setPtEtaPhiM(double pT, double eta, double phi, double mass) - { - double ptAbs = Math.abs(pT); - px = ptAbs*Math.cos(phi); - py = ptAbs*Math.sin(phi); - pz = ptAbs*Math.sinh(eta); - e = Math.sqrt(px * px + py * py + pz * pz + mass * mass); - } - - public double getP() - { - return Math.sqrt(px * px + py * py + pz * pz); - } - - public double getPt() - { - return Math.sqrt(px * px + py * py); - } - - public double getE() - { - return e; - } - - /** - * getEt() returns the transverse energy. - * The formula used to calculate it is: - * Et^2 = E^2 * Pt^2 / P^2. - */ - public double getEt() - { - double pt2 = px * px + py * py; - double p2 = pt2 + pz * pz; - return Math.sqrt(e * e * pt2/p2); - } - - public double getMass() - { - return Math.sqrt(e * e - px * px - py * py - pz * pz); - } - - /** - * getMt() returns the transverse mass. - * The formula used to calculate it is: - * Mt^2 = Et^2 - Pt^2. - * - * This is from the Particle Data Group (http://pdg.lbl.gov/) - * - * Note this is different to another definition in the PDG: - * Mt^2 = E^2 - Pz^2 = m^2 + Pt^2 - * - * [J. Beringer et al. (Particle Data Group), Phys. Rev. D86, 010001 (2012). - * (Kinematics, 43.6.1 and 43.5.2)] - */ - public double getMt() - { - double pt2 = px * px + py * py; - double Et = getEt(); - return Math.sqrt(Et * Et - pt2); - } - - public double getPhi() - { - return px == 0.0 && py == 0.0 ? 0.0 : Math.atan2(py,px); - } - - public double getEta() - { - double ptot = getP(); - double cosTheta = ptot == 0.0 ? 1.0 : pz/ptot; - if (cosTheta*cosTheta < 1) return -0.5* Math.log( (1.0-cosTheta)/(1.0+cosTheta) ); - if (pz > 0) return 10e10; - else return -10e10; - } - - public void add(double dx, double dy, double dz, double m) - { - px += dx; - py += dy; - pz += dz; - e += Math.sqrt(dx * dx + dy * dy + dz * dz + m * m); - } - - public void add(A4Vector v) - { - px += v.px; - py += v.py; - pz += v.pz; - e += v.e; - } - - public String toString() - { - return "A4Vector[px=" + px + ", py=" + py + ", pz=" + pz + ", E=" + e + ", m=" + getMass() + "]"; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AAtlantisException.java b/graphics/AtlantisJava/src/atlantis/utils/AAtlantisException.java deleted file mode 100755 index d8a4edc6d38..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AAtlantisException.java +++ /dev/null @@ -1,41 +0,0 @@ -package atlantis.utils; - -/** - * - * @author Zdenek Maxa - */ -public class AAtlantisException extends Exception -{ - private boolean isFatal = true; - - // private static ALogger logger = ALogger.getLogger(AAtlantisException.class); - - - public AAtlantisException(String msg) - { - super(msg); - // logger.debug(msg, this); - this.isFatal = true; - - } // AAtlantisException() ----------------------------------------------- - - - - public AAtlantisException(String msg, boolean isFatal) - { - super(msg); - // logger.debug(msg, this); - this.isFatal = isFatal; - - } // AAtlantisException() ----------------------------------------------- - - - - public boolean isFatal() - { - return this.isFatal; - - } // isFatal() ---------------------------------------------------------- - - -} // class AAtlantisException =============================================== diff --git a/graphics/AtlantisJava/src/atlantis/utils/AClipPolygon.java b/graphics/AtlantisJava/src/atlantis/utils/AClipPolygon.java deleted file mode 100755 index ad73aac1bfd..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AClipPolygon.java +++ /dev/null @@ -1,98 +0,0 @@ -package atlantis.utils; - -/** - * This class is used when clipping polygons. - */ -public class AClipPolygon extends APolygon { - - public AClipPolygon(double[] x, double[] y) { - super(x, y); - calc_hesse(); - } - - private double[][] normalized; - private double[] distances; - - public double[] get_normalized(int index) { - if(index>=0&&index<normalized.length&&normalized[index].length==3) - return normalized[index]; - else - return null; - } - - public double get_distance(int index) { - if(index>=0&&index<distances.length) - return distances[index]; - else - return Double.NaN; - } - - public void calc_hesse() { - int degree=nodes.size(); - - // Check if fields are already allocated - if(distances==null||distances.length!=degree) - distances=new double[nodes.size()]; // Generate array for distances - - if(normalized==null||normalized.length!=degree) - normalized=new double[nodes.size()][]; // array for normal vectors - - // Loop over all components and determine the normal vectors - for(int i=0; i<degree; i++) { - APoint r, next=null, current=null; - - if(nodes.elementAt(i) instanceof APoint) - current=(APoint)nodes.elementAt(i); - if(nodes.elementAt((i+1)%degree) instanceof APoint) - next=(APoint)nodes.elementAt((i+1)%degree); - - // If both APoints exist, calculate the normalized vector - if(next!=null&¤t!=null) { - - normalized[i]=new double[3]; - r=next.minus(current); - - // Check values and determine normalized vector. - if(r.x==0) - if(r.y>0) { - normalized[i][0]=1.0; - normalized[i][1]=0.0; - normalized[i][2]=1.0; - } else if(r.y<0) { // on the negative y-Axis - normalized[i][0]=-1.0; - normalized[i][1]=0.0; - normalized[i][2]=1.0; - } - - if(r.y==0) - if(r.x>0) { // on the positive x-Axis - normalized[i][0]=0.0; - normalized[i][1]=-1.0; - normalized[i][2]=1.0; - } else if(r.x<0) { // on the negative x-Axis - normalized[i][0]=0.0; - normalized[i][1]=1.0; - normalized[i][2]=1.0; - } - - if(r.y!=0) - if(r.x>0) { // right of the y-Axis - double x_val=r.y/r.x; - double length=Math.sqrt(x_val*x_val+1); - - normalized[i][0]=x_val/length; - normalized[i][1]=-1.0/length; - normalized[i][2]=1.0; - } else if(r.x<0) { // left of the y-Axis - double x_val=-r.y/r.x; - double length=Math.sqrt(x_val*x_val+1); - - normalized[i][0]=x_val/length; - normalized[i][1]=1.0/length; - normalized[i][2]=1.0; - } - distances[i]=-current.dot_product(normalized[i]); - } - } - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/ACommandHistory.java b/graphics/AtlantisJava/src/atlantis/utils/ACommandHistory.java deleted file mode 100755 index b226d78b0fa..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/ACommandHistory.java +++ /dev/null @@ -1,213 +0,0 @@ -package atlantis.utils; - -import java.util.Vector; -import javax.swing.text.JTextComponent; - - -/** - * Implementation of simple command history (up and down - * arrows) and tab completion based upon the already typed commands. - * No cross-sessions commands history so far. - * - * @author Zdenek Maxa - */ -public class ACommandHistory extends Vector -{ - // the component upon which the history operates - private JTextComponent comp = null; - // item on the size() position of the history (content of the text field) - private String tempItem = ""; - private int pointer = 0; - private int tabPointer = 0; // help pointer when doing tab completion - private String tabItem = null; - - - // ---------------------------------------------------------------------- - public ACommandHistory(JTextComponent compoment) - { - super(); - this.comp = compoment; - this.pointer = 0; - this.tabPointer = 0; - this.tempItem = ""; - this.nullTabItem(); - - } // ACommandHistory() -------------------------------------------------- - - - /** - * add the item into the history container, if it's already there it's - * removed first and then added (placed to the end) - * @param item String - */ - public void add(String item) - { - if(super.contains(item)) - { - super.remove(item); - } - super.add(item); - pointer = super.size(); - nullTabItem(); - - } // add() -------------------------------------------------------------- - - - /** - * erase the content of the tabItem string upon which the tab-completion - * searching is performed - */ - public void nullTabItem() - { - this.tabItem = null; - - } // nullTabItem() ------------------------------------------------------ - - - private String getItem() - { - if(pointer < super.size()) - { - return super.get(pointer).toString(); - } - else - { - return tempItem; - } - - } // getItem() ---------------------------------------------------------- - - - - private void desc() - { - if(pointer > 0) - { - pointer--; - } - - } // desc() ------------------------------------------------------------- - - - - private void inc() - { - if(pointer < super.size()) - { - pointer++; - } - - } // inc() -------------------------------------------------------------- - - - - /** - * compares the actual content of the text field with the history item - * on the matching position. if they differ (user changed the item in the - * text field) the item in the history (or the tempItem attribute - the - * last item, not yet added to the container) gets updated - */ - private void compareAndUpdate() - { - String currItem = comp.getText(); - if(pointer < super.size()) - { - String histItem = super.get(pointer).toString(); - if(! histItem.equals(currItem)) - { - super.remove(pointer); - super.add(pointer, currItem); - } - } - else - { - if(! tempItem.equals(currItem)) - { - tempItem = currItem; - } - } - - } // compareAndUpdate() ------------------------------------------------- - - - - /** - * up-arrow handler - it will decrease the pointer and return former - * command - */ - public void upArrow() - { - if(! super.isEmpty()) - { - compareAndUpdate(); - desc(); - comp.setText(getItem()); - } - nullTabItem(); - - } // upArrow() ---------------------------------------------------------- - - - - /** - * down-arrow handler - it will increase the pointer toward the more - * recent commands - */ - public void downArrow() - { - if(! super.isEmpty()) - { - compareAndUpdate(); - inc(); - comp.setText(getItem()); - } - nullTabItem(); - - } // downArrow() -------------------------------------------------------- - - - - /** - * tabulator handler, tab-completion - */ - public void tabulator() - { - // check tabItem - first or subsequent tab-key hit? - if(tabItem == null) - { - tabItem = comp.getText().trim(); - if("".equals(tabItem) || tabItem == null) - { - nullTabItem(); - return; - } - } - - if(! super.isEmpty()) - { - compareAndUpdate(); - - if(tabPointer >= super.size()) - { - tabPointer = 0; // rotate again from the beginning - } - - for( ; tabPointer < super.size(); tabPointer++) - { - String item = super.get(tabPointer).toString(); - if(item.startsWith(tabItem)) - { - pointer = tabPointer; - comp.setText(item); - tabPointer++; // for next iteration (next tab hit) - break; - } - } - - } // if(! super.isEmpty()) [container empty] - - } // tabulator() -------------------------------------------------------- - - - -} // class ACommandHistory ================================================== diff --git a/graphics/AtlantisJava/src/atlantis/utils/AHashMap.java b/graphics/AtlantisJava/src/atlantis/utils/AHashMap.java deleted file mode 100755 index 6e4f5f1c9d4..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AHashMap.java +++ /dev/null @@ -1,201 +0,0 @@ -package atlantis.utils; - -import java.util.HashMap; -import atlantis.Atlantis; - -/** - * Based on a standard Hashmap with an modified interface - */ - -public class AHashMap extends HashMap -{ - - private static ALogger logger = ALogger.getLogger(AHashMap.class); - - private void printWarningMessage(String msg) - { - logger.warn("AHashMap: " + msg); - } - - - public AHashMap(int num) - { - super(num); - } - - public AHashMap put(String name, int i) - { - put(name, new Integer(i)); - return this; - } - - public float[] getFloatArray(String name) - { - Object temp = get(name); - if(temp == null) - { - printWarningMessage("getFloatArray(): can't find float array named " + - name); - return null; - } - else - { - return (float[]) temp; - } - } // getFloatArray() ------------------------------------------------------- - - public float[][][] getFloatArray3D(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getFloatArray3D(): can't find 3D float array named " - + name); - } - return (float[][][]) temp; - } - - public String[] getStringArray(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getStringArray(): can't find String array named " - + name); - } - return (String[]) temp; - } - - public String[][] getStringArray2D(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getStringArray2D(): can't find String array named " - + name); - } - return (String[][]) temp; - } - - - public int[] getIntArray(String name) - { - Object temp = get(name); - - if(temp == null && !name.equals("sub")) - { - printWarningMessage("getIntArray(): can't find int array named " + - name); - } - return (int[]) temp; - } - - - public int[][] getIntArray2D(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getIntArray2D(): can't find 2D int array named " + - name); - } - return (int[][]) temp; - } - - - public int getInt(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getInt(): can't find int named " + name); - } - return ((Integer) temp).intValue(); - } - - public long getLong(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getLong(): can't find int named " + name); - return -1; - } - return ((Long) temp).longValue(); - } - - public float getFloat(String name) - { - Object temp = get(name); - - if(temp == null) - { - printWarningMessage("getFloat(): can't find int named " + name); - return -1; - } - return ((Float) temp).floatValue(); - } - - - public float[] getUnknownFloatArray(String name) - { - Object temp = get(name); - - if(temp == null) - return new float[getInt("numData")]; - return (float[]) temp; - } - - public long[] getUnknownLongArray(String name) - { - Object temp = get(name); - - if(temp == null) - return new long[getInt("numData")]; - return (long[]) temp; - } - - - public int[] getUnknownIntArray(String name) - { - Object temp = get(name); - - if(temp == null) - return new int[getInt("numData")]; - return (int[]) temp; - } - - - public float[] getUnsureFloatArray(String name) - { - Object temp = get(name); - - if(temp == null) - return null; - return (float[]) temp; - } - - public int[] getUnsureIntArray(String name) - { - Object temp = get(name); - - if(temp == null) - return null; - return (int[]) temp; - } - - public String[] getUnsureStringArray(String name) - { - Object temp = get(name); - - if(temp == null) - return null; - return (String[]) temp; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AIdDictionary.java b/graphics/AtlantisJava/src/atlantis/utils/AIdDictionary.java deleted file mode 100644 index 9d04ec7239c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AIdDictionary.java +++ /dev/null @@ -1,152 +0,0 @@ -package atlantis.utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * Class representing an identifier dictionary, used for decoding of compact IDs. - * - * @author Eric Jansen - */ -class AIdDictionary extends AIdField { - - private HashMap<String, Node> subregions = null; - private HashMap<String, Node> labels = null; - private HashMap<String, List<AIdRange>> ranges = new HashMap<String, List<AIdRange>>(); - - /** - * Empty constructor, used to create a placeholder dictionary that - * can be initialized later. - */ - AIdDictionary() {} - - /** - * Construct and initialize dictionary from an <IdDictionary> XML node. - * @param dict dictionary XML node - * @throws AAtlantisException - */ - AIdDictionary(Node dict) throws AAtlantisException { - initialize(dict); - } - - /** - * Initializes a dictionary from an <IdDictionary> XML node. - * @param dict dictionary XML node - * @throws AAtlantisException - */ - final void initialize(Node dict) throws AAtlantisException { - - this.dictionary = this; - - NodeList nodes = dict.getChildNodes(); - - for (int i=0; i<nodes.getLength(); i++) { - Node node = nodes.item(i); - - if (node.getNodeType() == Node.ELEMENT_NODE) { - - if ("field".equals(node.getNodeName())) { - String fieldName = node.getAttributes().getNamedItem("name").getNodeValue(); - if (labels == null) { - labels = new HashMap<String, Node>(); - } - labels.put(fieldName, node); - - } else if ("subregion".equals(node.getNodeName())) { - String subregionName = node.getAttributes().getNamedItem("name").getNodeValue(); - if (subregions == null) { - subregions = new HashMap<String, Node>(); - } - subregions.put(subregionName, node); - - } else if ("region".equals(node.getNodeName())) { - parseRegion(node, null, 0); - - } else if ("alternate_regions".equals(node.getNodeName())) { - NodeList altnodes = node.getChildNodes(); - - for (int j=0; j<altnodes.getLength(); j++) { - Node altnode = altnodes.item(j); - if (altnode.getNodeType() == Node.ELEMENT_NODE - && "region".equals(altnode.getNodeName())) { - parseRegion(altnode, null, 0); - } - } - } - } - } - - // Clean up the HashMaps, they are only needed during initialization. - ranges = null; - labels = null; - subregions = null; - } - - /** - * Returns true if the dictionary contains labels for the named field. - * @param fieldName name of the field - * @return true if labels are present - */ - boolean hasLabels(String fieldName) { - return labels.containsKey(fieldName); - } - - /** - * Returns the <field> node containing the labels for the named field. - * @param fieldName name of the field - * @return <field> XML node - * @throws AAtlantisException - */ - Node getLabels(String fieldName) throws AAtlantisException { - if (labels.containsKey(fieldName)) { - return labels.get(fieldName); - } else { - throw new AAtlantisException("Labels for field '"+fieldName+"' not found"); - } - } - - /** - * Returns the <subregion> node containing the named subregion. - * @param subRegionName name of the subregion - * @return <subregion> XML node - * @throws AAtlantisException - */ - Node getSubRegion(String subRegionName) throws AAtlantisException { - if (subregions.containsKey(subRegionName)) { - return subregions.get(subRegionName); - } else { - throw new AAtlantisException("Subregion '"+subRegionName+"' not found"); - } - } - - /** - * One AIdRange object for every unique field range is kept inside the dictionary. - * It serves to collect all possible values for the named field. Due to the tree - * structure of the identifiers multiple AIdFields with the same name might be - * created, but they will always have the same range. The first AIdField with a - * certain name will be the parent of the range, but it is only used for decoding - * of labelled fields. The field name has to be set before creating the range in the - * dictionary. - * @param field named identifier field - * @return global range corresponding to the named field - */ - AIdRange getRange(String group, int level) throws AAtlantisException { - - List<AIdRange> range; - if (ranges.containsKey(group)) { - range = ranges.get(group); - } else { - range = new ArrayList<AIdRange>(); - ranges.put(group, range); - } - - while (range.size() <= level) { - range.add(new AIdRange()); - } - - return range.get(level); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AIdField.java b/graphics/AtlantisJava/src/atlantis/utils/AIdField.java deleted file mode 100644 index a1f9c7d8d8d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AIdField.java +++ /dev/null @@ -1,537 +0,0 @@ -package atlantis.utils; - -import java.util.HashMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * Class representing a single field in an identifier. Each field has a parent, - * a range of allowed values and child fields that may depend on the value of the - * current field. The possible values of a field will determine the number of bits - * needed to store it in the compact identifier. The AIdField tree is capable of - * encoding and decoding these compact identifiers. - * - * @author Eric Jsnsen - */ -class AIdField { - - /** - * Dictionary that this field belongs to. The dictionary is used to keep track - * of the possible values of a field, - */ - protected AIdDictionary dictionary = null; - - /** Parent field in the identifier tree. */ - private AIdField parent = null; - - /** Level of nesting this field is at. */ - private int level = 0; - - /** Field name. */ - private String name = null; - - /** All known values found for this field in the dictionary. */ - private AIdRange fieldRange = null; - - /** Map of value ranges to child AIdField objects, inverse of parent. */ - private HashMap<AIdRange, AIdField> children = new HashMap<AIdRange, AIdField>(); - - /** Map of string labels in case of an enumerated field. */ - private HashMap<Integer, String> labels = null; - - /** Reference to idHelper for retrieving dictionaries. */ - protected static ANewIdHelper idHelper = ANewIdHelper.instance(); - - /** - * Empty constructor. - */ - protected AIdField() {} - - /** - * Constructor, setting dictionary and parent field. - * @param dict dictionary the field belongs to - * @param parentField parent field - */ - protected AIdField(AIdDictionary dict, AIdField parentField) { - - dictionary = dict; - if (parentField != null) { - parent = parentField; - level = parent.getLevel()+1; - } - } - - /** - * Get the name of the field. - * @return field name - */ - String getName() { - return name; - } - - /** - * Get the nesting level of the field. - * @return nesting level - */ - int getLevel() { - return level; - } - - /** - * Obtain the value of the named field from a compact identifier. - * @param fieldName field name - * @param id compact identifier - * @return value of the given field in the identifier - * @throws AAtlantisException - */ - public int get(String fieldName, long id) throws AAtlantisException { - if (id > Integer.MAX_VALUE) { - return get(fieldName, id, 64); - } else { - return get(fieldName, id, 32); - } - } - - /** - * Obtain the string value of the named field from a compact identifier. - * @param fieldName field name - * @param id compact identifier - * @return value of the given field in the identifier - * @throws AAtlantisException - */ - public String getString(String fieldName, long id) throws AAtlantisException { - if (id > Integer.MAX_VALUE) { - return getString(fieldName, id, 64); - } else { - return getString(fieldName, id, 32); - } - } - - /** - * Internal version of get(String, long), propagating the bit offset in - * the compact identifier. - * @param fieldName field name - * @param id compact identifier - * @param offset bit offset accumulated from parent fields - * @return value of the given field in the identifier - * @throws AAtlantisException - */ - private int get(String fieldName, long id, int offset) throws AAtlantisException { - - if (fieldRange == null) { - throw new AAtlantisException("No range known for identifier field" - + " '" + name + "' while decoding '" + fieldName + "'"); - } - - // The following code is duplicated a few times in this class. This is - // necessary to extract the value but also update offset at the same time. - int bits = fieldRange.bits(); - offset -= bits; - int mask = (int)(Math.pow(2, bits)) - 1; - - int value; - try { - value = fieldRange.get((int)(id >> offset & mask)); - } catch (AAtlantisException e) { - throw new AAtlantisException("Unable to decode identifier field" - + " '" + name + "': " + e); - } - - if (fieldName.equals(name)) { - // This is me, return value - return value; - } else { - // Find the correct child to delegate this ID to - for(AIdRange range : children.keySet()) { - if (range.contains(value)) { - return children.get(range).get(fieldName, id, offset); - } - } - } - - throw new AAtlantisException("Invalid identifier '" + id + "'"); - } - - /** - * Internal version of get(String, long), propagating the bit offset in - * the compact identifier. - * @param fieldName field name - * @param id compact identifier - * @param offset bit offset accumulated from parent fields - * @return value of the given field in the identifier - * @throws AAtlantisException - */ - private String getString(String fieldName, long id, int offset) throws AAtlantisException { - - if (fieldRange == null) { - throw new AAtlantisException("No range known for identifier field" - + " '" + name + "' while decoding '" + fieldName + "'"); - } - - // The following code is duplicated a few times in this class. This is - // necessary to extract the value but also update offset at the same time. - int bits = fieldRange.bits(); - offset -= bits; - int mask = (int)(Math.pow(2, bits)) - 1; - - int value; - try { - value = fieldRange.get((int)(id >> offset & mask)); - } catch (AAtlantisException e) { - throw new AAtlantisException("Unable to decode identifier field" - + " '" + name + "': " + e); - } - - if (fieldName.equals(name)) { - // This is me, return value - return getLabel(value); - } else { - // Find the correct child to delegate this ID to - for(AIdRange range : children.keySet()) { - if (range.contains(value)) { - return children.get(range).getString(fieldName, id, offset); - } - } - } - - throw new AAtlantisException("Invalid identifier '" + id + "'"); - } - - /** - * Convert a compact identifier into a "/" delimited expanded identifier. - * @param id compact identifier - * @return expanded identifier, fields delimited by "/" - */ - public String getFullIdentifier(long id) throws AAtlantisException { - - StringBuilder s = new StringBuilder(); - if (id > Integer.MAX_VALUE) { - getFullIdentifier(id, 64, s); - } else { - getFullIdentifier(id, 32, s); - } - return s.toString(); - } - - /** - * Internal version of getFullIdentifier(long), passing the bit offset a - * StringBuilder object. The output is appended to the StringBuilder object. - * @param id compact identifier - */ - private void getFullIdentifier(long id, int offset, StringBuilder s) throws AAtlantisException { - - // The following code is duplicated a few times in this class. This is - // necessary to extract the value but also update offset at the same time. - int bits = fieldRange.bits(); - offset -= bits; - int mask = (int)(Math.pow(2, bits)) - 1; - - int value; - try { - value = fieldRange.get((int)(id >> offset & mask)); - } catch (AAtlantisException e) { - throw new AAtlantisException("Unable to decode identifier field" - + " '" + name + "': " + e.getMessage()); - } - - if (hasLabels()) { - s.append(getLabel(value));//.append("=").append(value); - } else { - s.append(value); - } - - if (children != null) { - for (AIdRange range : children.keySet()) { - if (range.contains(value)) { - AIdField child = children.get(range); - if (child != null && !child.isEmpty()) { - s.append("/"); - child.getFullIdentifier(id, offset, s); - } - return; - } - } - - throw new AAtlantisException("Invalid identifier '" + id + "', " - + "field '" + name +"' does not allow value " + value + " " - + "(partially decoded: '" + s.toString() + "')"); - } - } - - /** - * Parses a <region> element in the XML file. This method should be - * called on an AIdField instance that represents the first field in the - * region. Children will be added by recursively calling this method. - * @param region XML element to parse - * @param start Starting child element - * @return Last child parsed - * @throws AAtlantisException - */ - AIdField parseRegion(Node region, String group, int start) throws AAtlantisException { - NodeList nodes = region.getChildNodes(); - - if (start == 0) { - // In a new region, first set the group all parsed elements belong to (if any). - Node groupNode = region.getAttributes().getNamedItem("group"); - if (groupNode != null) { - group = groupNode.getNodeValue(); - } - } - - for (int i=start; i<nodes.getLength(); i++) { - Node node = nodes.item(i); - - /* Select only elements, not the text in between. */ - if (node.getNodeType() == Node.ELEMENT_NODE) { - - if ("range".equals(node.getNodeName())) { - - // The first <range> encountered is for the current AIdFied. For the - // given values of this field, the next will be a child. For example, - // when called with: - // - // <range field="subdet" value="2" /> - // <range field="part" value=1" /> - // ... - // - // This field will become "subdet". In case the value of this field - // in the identifier is "2", the next field in the chain is "part". - // More values of "part" will probably be added later, plus other - // values of "subdet" for which the next field is not "part" but - // something different. - if (name == null) { - name = node.getAttributes().getNamedItem("field").getNodeValue(); - if (dictionary.hasLabels(name)) { - parseLabels(dictionary.getLabels(name)); - } - - fieldRange = dictionary.getRange(group, level); - } - - AIdRange range = new AIdRange(this, group, node); - - // Fields are sometimes repeated without specifying any allowed values, - // in that case we allow all existing values (so we copy fieldRange). - if (range.isEmpty() && !fieldRange.isEmpty()) { - range.add(fieldRange); - } - - // If this particular range is already present, give the next - // node (i+1) to the correct child and tell it to parse it. - if (children.containsKey(range) && children.get(range) != null) { - - return children.get(range).parseRegion(region, group, i+1); - } - - // If there is another range that fully contains this range, we add the - // current node there. This is a reasonable shortcut, since we are not - // interested in fully validating IDs (i.e. raise an exception when an - // RPC identifier is presented for a muon station that should not contain - // RPCs), this is a reasonable shortcut. - for (AIdRange childRange : children.keySet()) { - if (childRange.contains(range)) { - return children.get(childRange).parseRegion(region, group, i+1); - } - } - - if (group != null && !group.equals("")) { - - // Two ranges within the same group means that they should be - // considered to lead to the same child. In that case expand - // the range using AIdRange.add(). - for (AIdRange childRange : children.keySet()) { - if (group.equals(childRange.group())) { - AIdField child = children.get(childRange); - - if (child != null) { - fieldRange.add(range); - children.remove(childRange); - childRange.add(range); - children.put(childRange, child); - return child.parseRegion(region, group, i+1); - } - } - } - } - - fieldRange.add(range); - - AIdField child = new AIdField(dictionary, this); - AIdField retfield = child.parseRegion(region, group, i+1); - if (retfield instanceof AIdDictionary) { - children.put(range, retfield); - } else { - children.put(range, child); - } - - return retfield; - - } else if ("dictionary".equals(node.getNodeName())) { - - // A dictionary is a reference to another file. The AIdDictionary class - // inherits from AIdField and can will act as the first field in the - // dictionary. Dictionaries are initialized one by one, so when a dictionary - // does not exist yet, it is created empty so that it can be initialized later. - String dictName = node.getAttributes().getNamedItem("name").getNodeValue(); - if (idHelper.hasDictionary(dictName)) { - return idHelper.getDictionary(dictName); - } else { - AIdDictionary dict = new AIdDictionary(); - idHelper.addDictionary(dictName, dict); - return dict; - } - - } else if ("reference".equals(node.getNodeName())) { - - // A reference is a link to a <subregion> element. The elements within the - // subregion are parsed as if they were present instead of the reference. - String reference = node.getAttributes().getNamedItem("subregion").getNodeValue(); - AIdField child = parseRegion(dictionary.getSubRegion(reference), group, 0); - - // After parsing the subregion, we need to continue with the current region. - AIdField retfield = child.parseRegion(region, group, i+1); - return retfield; - } - } - } - - // Reached the end of a region or subregion, - // return the last object parsed (which is us). - return this; - } - - /** - * Parse a <field> object in the XML file. - * @param field XML element to parse - * @throws AAtlantisException - */ - private void parseLabels(Node field) throws AAtlantisException { - - labels = new HashMap<Integer, String>(); - int lastValue = 0; - - NodeList nodes = field.getChildNodes(); - for (int i=0; i<nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - - if (node.getNodeName().equals("label")) { - String label = node.getAttributes().getNamedItem("name").getNodeValue(); - Integer value; - - Node valueNode = node.getAttributes().getNamedItem("value"); - if (valueNode == null) { - value = lastValue+1; - } else { - value = Integer.parseInt(valueNode.getNodeValue().replaceAll("\\+", "")); - } - - labels.put(value, label); - lastValue = value.intValue(); - } - } - } - } - - /** - * Check if this field has string labels. - * @return true if string labels are present - */ - boolean hasLabels() { - return labels != null && labels.size() > 0; - } - - /** - * Check if this field is empty/uninitialized. Fields at the end of the tree - * will remain in this state, during construction all newly initialized fields - * will be in this state. - * @return - */ - boolean isEmpty() { - return name == null; - } - - /** - * Return label corresponding to an integer value. - * @param value field value - * @return label - */ - String getLabel(Integer value) { - if (labels.containsKey(value)) { - return labels.get(value); - } else { - return "?"; - } - } - - /** - * Convert a field value as it appears in the XML file into a true integer. - * For example "+2" is converted into 2 and labelled fields are converted - * into their integer equivalents. - * @param fieldName field name (for label lookup) - * @param value "raw" field value in the XML - * @return integer value - * @throws AAtlantisException - */ - protected int valueToInt(String fieldName, String value) throws AAtlantisException { - - try { - return Integer.parseInt(value.replaceAll("\\+", "")); - } catch (NumberFormatException e) { - return labelToInt(fieldName, value); - } - } - - /** - * Convert a field label into an integer value. - * @param fieldName field name - * @param label value of the labelled field - * @return integer label - * @throws AAtlantisException - */ - protected int labelToInt(String fieldName, String label) throws AAtlantisException { - if (labels != null) { - if (labels.containsValue(label)) { - for (Integer value : labels.keySet()) { - if (label.equals(labels.get(value))) { - return value; - } - } - } - } - - throw new AAtlantisException("Field/label not found in" - +" dictionary: " + fieldName + "/" + label); - } - - /** - * Convert the field structure into a printable form, starting from this node. - * @return string representation of the identifier tree - */ - @Override - public String toString() { - return toString(""); - } - - /** - * Private version of toString(), used recursively and passing an indentation - * string to print the entire tree structure. - * @param indent identation string, appended to all lines - * @return string representation of the identifier tree - */ - private String toString(String indent) { - StringBuilder s = new StringBuilder(); - - s.append(indent).append(name).append(" ").append(fieldRange).append("\n"); - - for (AIdRange range : children.keySet()) { - s.append(indent).append(range).append("\n"); - AIdField child = children.get(range); - if (child != null) { - s.append(child.toString(indent + " ")); - } - } - - return s.toString(); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AIdHelper.java b/graphics/AtlantisJava/src/atlantis/utils/AIdHelper.java deleted file mode 100755 index 48561f8232e..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AIdHelper.java +++ /dev/null @@ -1,599 +0,0 @@ -package atlantis.utils; - -import java.util.ArrayList; - -/** - * This class contains methods for extracting various properties from the 32 bit - * identifiers used for hits. It works very similarly to the IdHelpers in Athena, - * hence its name. - * - * @author Eric Jansen - */ -public class AIdHelper { - - private static ANewIdHelper idHelper = null; - - /** - * Returns the decoded athena identifier (id) as a string, resp. an - * array of strings: first item is the full id expanded (decoded) and - * particular subparts are separated by "/" in one sting, further - * interesting subparts of the decoded id are provided in the following - * items of the array with an explanation given. - * So far (2009-01-20), this is implemented only for LAr and Tile, for - * other subsystems only first array item is returned with the expanded - * id. - * @param id int compact identifier - * @return String decoded identifier - */ - public static String[] getFullIdentifier(long id) - { - // more than 10 items should not be necessary - ArrayList<String> r = new ArrayList<String>(10); - String s = null; - - try - { - switch (subDetector(id)) - { - case 2: - switch (indetPart(id)) - { - case 1: - // Pixel identifiers are complicated and we don't use them anyway. - throw new AAtlantisException("Pixel identifiers not implemented: " + id); - case 2: - s = "2/2/" + sctBarrelEndcap(id) + "/" + - sctLayerDisk(id) + "/" + sctPhiModule(id) + "/" + - sctEtaModule(id) + "/" + sctPhiIndex(id) + "/" + - sctEtaIndex(id); - r.add(s); - return r.toArray(new String[r.size()]); - case 3: - - int part = 3; - int barrelEndcap = trtBarrelEndcap(id); - int layerWheel = trtLayerWheel(id); - int phiModule = trtPhiModule(id); - int strawLayer = trtStrawLayer(id); - int straw = trtStraw(id); - - s = "2" + "/" + part + "/" + barrelEndcap + "/" + - layerWheel + "/" + phiModule + "/" + strawLayer + - "/" + straw; - r.add(s); - r.add("barrel-endcap: " + barrelEndcap); - r.add("layer wheel: " + layerWheel); - r.add("phi module: " + phiModule); - r.add("straw layer: " + strawLayer); - r.add("straw: " + straw); - return r.toArray(new String[r.size()]); - - default: - throw new AAtlantisException("Invalid identifier: " + id); - } - case 4: - int part = larPart(id); - int sampling = part < 3 ? 0 : larSampling(id); - int eta = larEta(id); - int phi = larPhi(id); - - if(part == 1) // LAr barrel, LAr endcap - { - int barrelEndcap = larBarrelEndcap(id); - int region = larRegion(id); - s = "4/" + part + "/" + barrelEndcap + "/" + - sampling + "/" + region + "/" + eta + "/" + phi; - r.add(s); - if(barrelEndcap == 1) - { - //r.add("barrel A"); - r.add("EMBA"); - } - else if(barrelEndcap == -1) - { - //r.add("barrel C"); - r.add("EMBC"); - } - else if(barrelEndcap == 2 || barrelEndcap == 3) - { - //r.add("endcap A"); - r.add("EMECA"); - } - else if(barrelEndcap == -2 || barrelEndcap == -3) - { - //r.add("endcap C"); - r.add("EMECC"); - } - } - else if(part == 2) // HEC - { - int posNeg = larBarrelEndcap(id); - int region = larRegion(id); - s = "4/" + part + "/" + posNeg + "/" + sampling + "/" + - region + "/" + eta + "/" + phi; - r.add(s); - if(posNeg == 2) - { - //r.add("A"); - r.add("HECA"); - } - else if(posNeg == -2) - { - //r.add("C"); - r.add("HECC"); - } - } - else if(part == 3) // FCAL - { - int posNeg = larBarrelEndcap(id); - s = "4/" + part + "/" + posNeg + "/" + sampling + "/" + - eta + "/" + phi; - r.add(s); - if(posNeg == 2) - { - //r.add("A"); - r.add("FCALA"); - } - else if(posNeg == -2) - { - //r.add("C"); - r.add("FCALC"); - } - } - else - { - throw new AAtlantisException("Invalid identifier: " + id); - } - - r.add("sampling: " + sampling); // sampling remains - - return r.toArray(new String[r.size()]); - - case 5: - // tile calorimeter (first number of full id is 5) - int section = tileSection(id); - int side = tileSide(id); - int module = tileModule(id); - int tower = tileTower(id); - sampling = tileSampling(id); - int pmt = tilePmt(id); - int adc = tileAdc(id); - - s = "5/" + section + "/" + side + "/" + module + "/" + - tower + "/" + sampling + "/" + pmt + "/" + adc; - r.add(s); - - r.add("section: " + section); - r.add("side: " + side); - r.add("module: " + module); - r.add("tower: " + tower); - r.add("sampling: " + sampling); - r.add("PMT: " + pmt); - r.add("ADC: " + adc); - - return r.toArray(new String[r.size()]); - - case 7: - String technology = technology(id); - if (technology.equals("MDT")) - { - s = "7/" + stationName(id) + "/" + stationEta(id) + - "/" + stationPhi(id) + "/" + "MDT/" + - mdtMultiLayer(id) + "/" + mdtTubeLayer(id) + "/" + - mdtTube(id); - r.add(s); - return r.toArray(new String[r.size()]); - } - else if (technology.equals("RPC")) - { - s = "7/" + stationName(id) + "/" + stationEta(id) + "/" + - stationPhi(id) + "/" + "RPC/" + rpcDoubletR(id) + "/" + - rpcDoubletZ(id) + "/" + rpcDoubletPhi(id) + "/" + - rpcGasGap(id) + "/" + rpcMeasuresPhi(id) + "/" + - rpcStrip(id); - r.add(s); - return r.toArray(new String[r.size()]); - } - else if (technology == "TGC") - { - s = "7/" + stationName(id) + "/" + stationEta(id) + - "/" + stationPhi(id) + "/" + "TGC/" + tgcGasGap(id) + - "/" + tgcIsStrip(id) + "/" + tgcChannel(id); - r.add(s); - return r.toArray(new String[r.size()]); - } - else if (technology == "CSC") - { - s = "7/" + stationName(id) + "/" + stationEta(id) + "/" + - stationPhi(id) + "/" + "CSC/" + cscChamberLayer(id) + - "/" + cscWireLayer(id) + "/" + cscMeasuresPhi(id) + - "/" + cscStrip(id); - r.add(s); - return r.toArray(new String[r.size()]); - } - else - { - throw new AAtlantisException("Invalid identifier: " + id); - } - default: - throw new AAtlantisException("Not yet implemented for identifier: " + id); - } - } - catch (AAtlantisException e) - { - s = id + " (unable to decode: " + e.getMessage() + ")"; - r.add(s); - return r.toArray(new String[r.size()]); - } - - } // getFullIdentifier() ------------------------------------------------ - - - - /** @deprecated */ - public static int subDetector(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("subdet", id); - } - - /** @deprecated */ - public static int indetPart(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("part", id); - } - - /** @deprecated */ - public static int trtBarrelEndcap(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("barrel_endcap", id); - } - - - /** @deprecated */ - public static int trtLayerWheel(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("layer_or_wheel", id); - } - - /** @deprecated */ - public static int trtPhiModule(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("phi_sector", id); - } - - /** @deprecated */ - public static int trtStrawLayer(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("straw_layer", id); - } - - /** @deprecated */ - public static int trtStraw(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("straw", id); - } - - /** @deprecated */ - public static final int sctBarrelEndcap(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("barrel_endcap", id); - } - - /** @deprecated */ - public static int sctLayerDisk(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("layer", id); - } - - /** @deprecated */ - public static int sctPhiModule(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("phi_module", id); - } - - /** @deprecated */ - public static int sctEtaModule(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("eta_module", id); - } - - /** @deprecated */ - public static int sctPhiIndex(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("side", id); // This seems odd, phi_index <-> side? - } - - /** @deprecated */ - public static int sctEtaIndex(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("strip", id); - } - - /** @deprecated */ - public static int larPart(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("part", id); - } - - /** @deprecated */ - public static int larBarrelEndcap(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("barrel-endcap", id); - } - - /** @deprecated */ - public static int larPosNeg(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("pos_neg", id); - } - - /** @deprecated */ - public static int larSampling(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("sampling", id); - } - - /** @deprecated */ - public static int larRegion(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("region", id); - } - - /** @deprecated */ - public static int larEta(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - if (larPart(id) < 3) { - return idHelper.get("eta", id); - } else { - return idHelper.get("eta-fcal", id); - } - } - - /** @deprecated */ - public static int larPhi(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - if (larPart(id) < 3) { - return idHelper.get("phi", id); - } else { - return idHelper.get("phi-fcal", id); - } - } - - /** @deprecated */ - public static int larModule(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("module", id); - } - - - /** @deprecated */ - public static boolean larIsBarrel(long id) throws AAtlantisException - { - switch(Math.abs(larBarrelEndcap(id))) - { - case 1: - return true; // yes, it's barrel - case 2: - return false; // is endcap - case 3: - return false; // is endcap - default: - throw new AAtlantisException("Not a LAr identifier: " + id); - } - } - - /** @deprecated */ - public static int tileSection(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("section", id); - } - - /** @deprecated */ - public static int tileSide(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("side", id); - } - - /** @deprecated */ - public static int tileModule(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("module", id); - } - - /** @deprecated */ - public static int tileTower(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("tower", id); - } - - /** @deprecated */ - public static int tileSampling(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("sampling", id); - } - - /** @deprecated */ - public static int tilePmt(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("pmt", id); - } - - /** @deprecated */ - public static int tileAdc(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("adc", id); - } - - - /** - * Decodes Athena 32-bit ID to following form (5 is Tile): - * 5/section/side/module/tower/sampling/pmt/adc - official identifier - * - * Identifier used by TileCal collaboration, conversion is clear from the - * code and is explained in Sasha Solodkov's email on 2006-09-18 - * - * @param id int - * @return String - */ - public static String getDecodedTileIndentifier(long id) - { - try - { - int sec = tileSection(id); - int side = tileSide(id); - int mod = tileModule(id); - int tow = tileTower(id); - int samp = tileSampling(id); - - // section/side/module into decoded form - String secSideMod = "\n[could not work out section/side]"; - mod++; - if(sec == 1 && side == 1) secSideMod = "LBA" + mod; - if(sec == 1 && side == -1) secSideMod = "LBC" + mod; - if(sec == 2 && side == 1) secSideMod = "EBA" + mod; - if(sec == 3 && side == 1) secSideMod = "EBA" + mod; - if(sec == 2 && side == -1) secSideMod = "EBC" + mod; - if(sec == 3 && side == -1) secSideMod = "EBC" + mod; - - // sampling/tower into decoded form - String sampTow = "\n[could not work out sampling/tower]"; - if(samp == 0) sampTow = "A" + (int)(tow + 1); - if(samp == 1) sampTow = "B" + (int)(tow + 1); - if(samp == 2) sampTow = "D" + (int)(tow/2); - if(samp == 3) - { - if(tow == 10) sampTow = "E1"; - if(tow == 11) sampTow = "E2"; - if(tow == 13) sampTow = "E3"; - if(tow == 15) sampTow = "E4"; - } - - return secSideMod + " " + sampTow; - } - catch (AAtlantisException e) - { - return id + " (unable to decode: " + e.getMessage() + ")"; - } - } - - - /** @deprecated */ - public static String stationName(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.getString("stationName", id); - } - - /** @deprecated */ - public static String technology(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.getString("technology", id); - } - - /** @deprecated */ - public static int stationEta(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("stationEta", id); - } - - /** @deprecated */ - public static int stationPhi(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("stationPhi", id); - } - - /** @deprecated */ - public static int mdtMultiLayer(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("multiLayer", id); - } - - /** @deprecated */ - public static int mdtTubeLayer(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("tubeLayer", id); - } - - /** @deprecated */ - public static int mdtTube(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("tube", id); - } - - /** @deprecated */ - public static int rpcDoubletR(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("doubletR", id); - } - - /** @deprecated */ - public static int rpcDoubletZ(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("doubletZ", id); - } - - /** @deprecated */ - public static int rpcDoubletPhi(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("doubletPhi", id); - } - - /** @deprecated */ - public static int rpcGasGap(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("rpcGasGap", id); - } - - /** @deprecated */ - public static int rpcMeasuresPhi(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("rpcMeasuresPhi", id); - } - - /** @deprecated */ - public static int rpcStrip(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("rpcStrip", id); - } - - /** @deprecated */ - public static int tgcGasGap(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("tgcGasGap", id); - } - - /** @deprecated */ - public static int tgcIsStrip(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("isStrip", id); - } - - /** @deprecated */ - public static int tgcChannel(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("channel", id); - } - - /** @deprecated */ - public static int cscChamberLayer(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("chamberLayer", id); - } - - /** @deprecated */ - public static int cscWireLayer(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("wireLayer", id); - } - - /** @deprecated */ - public static int cscMeasuresPhi(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("cscMeasuresPhi", id); - } - - /** @deprecated */ - public static int cscStrip(long id) throws AAtlantisException { - if (idHelper == null) idHelper = ANewIdHelper.instance(); - return idHelper.get("cscStrip", id); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AIdRange.java b/graphics/AtlantisJava/src/atlantis/utils/AIdRange.java deleted file mode 100644 index b38d5523882..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AIdRange.java +++ /dev/null @@ -1,392 +0,0 @@ -package atlantis.utils; - -import java.util.Arrays; -import org.w3c.dom.Node; - - -/** - * Class representing a range of possible values for an identifier field. - * - * @author Eric Jansen - */ -class AIdRange { - - /** Group the field belongs to, ranges of the same group should be merged. */ - private String group = null; - - /** Parent field, needed only for printing of labelled fields. */ - AIdField parent = null; - - /** A discrete range with values specified in this array. */ - private int[] values = null; - - /** A continuous range from min to max (if values == null). */ - private int minValue, maxValue; - - /** - * Empty constructor, creates an empty range. - */ - AIdRange() { - this.values = new int[0]; - } - - /** - * Continuous range constructor, contains all values >= minValue <= maxValue. - * @param minValue first value in the range - * @param maxValue last value in the range - * @throws AAtlantisException - */ - AIdRange(int minValue, int maxValue) throws AAtlantisException { - - if (minValue > maxValue) { - throw new AAtlantisException("Invalid range: " + minValue + " -> " + maxValue); - } - - this.minValue = minValue; - this.maxValue = maxValue; - } - - /** - * Discrete range constructor, contains the values given in values[]. - * @param values ordered array of values - */ - AIdRange(int[] values) { - this.values = values; - } - - /** - * XML constructor, initialize the range from a <range> element. - * @param parent id field the values belong to - * @param group group this field belongs to - * @param node <range> XML element - * @throws AAtlantisException - */ - AIdRange(AIdField parent, String group, Node node) throws AAtlantisException { - - String fieldName = node.getAttributes().getNamedItem("field").getNodeValue(); - this.parent = parent; - this.group = group; - - Node minValueAttr = node.getAttributes().getNamedItem("minvalue"); - Node maxValueAttr = node.getAttributes().getNamedItem("maxvalue"); - - if (minValueAttr != null && maxValueAttr != null) { - - minValue = parent.valueToInt(fieldName, minValueAttr.getNodeValue()); - maxValue = parent.valueToInt(fieldName, maxValueAttr.getNodeValue()); - - if (minValue > maxValue) { - throw new AAtlantisException("Invalid range: " + minValue + " -> " + maxValue); - } - - } else { - Node valueAttr = node.getAttributes().getNamedItem("value"); - Node valuesAttr = node.getAttributes().getNamedItem("values"); - - if (valueAttr != null) { - values = new int[1]; - values[0] = parent.valueToInt(fieldName, valueAttr.getNodeValue()); - } else if (valuesAttr != null) { - String[] list = valuesAttr.getNodeValue().split(" "); - values = new int[list.length]; - for (int i=0; i<list.length; i++) { - values[i] = parent.valueToInt(fieldName, list[i]); - } - } else { - values = new int[0]; - } - } - } - - /** - * Get group name for this range. - * @return group name - */ - String group() { - return group; - } - - /** - * Check if the range contains value. - * @param value value to check - * @return true if value is part of this range - */ - boolean contains(int value) { - if (values == null) { - if (value >= minValue && value <= maxValue) { - return true; - } else { - return false; - } - } else { - for (int val : values) { - if (val == value) { - return true; - } - } - return false; - } - } - - /** - * Check if the range fully contains another range. - * @param range range to check - * @return true if all values in the argument are in this range - */ - boolean contains(AIdRange range) { - if (range.values == null) { - for (int value=range.minValue; value<=range.maxValue; value++) { - if (!this.contains(value)) return false; - } - } else { - for (int value : range.values) { - if (!this.contains(value)) return false; - } - } - - return true; - } - - /** - * Check if this range equals another. - * @param obj other range - * @return true if obj is an AIdRange object and its values match - */ - @Override - public boolean equals(Object obj) { - - if (!(obj instanceof AIdRange)) { - return false; - } - - AIdRange other = (AIdRange)obj; - - if (values == null && other.values == null) { - - // Continuous range, check boundaries - if (minValue == other.minValue && maxValue == other.maxValue) { - return true; - } else { - return false; - } - - } else if (values == null) { - - // Continuous and discrete range - if (other.values.length == maxValue - minValue + 1 - && other.values[other.values.length-1] == maxValue - && other.values[0] == minValue) { - return true; - } else { - return false; - } - - } else if (other.values == null) { - - // Discrete and continuous range - if (values.length == other.maxValue - other.minValue + 1 - && values[values.length-1] == other.maxValue - && values[0] == other.minValue) { - return true; - } else { - return false; - } - - } else { - - // Discrete range, check length and individual entries - if (values.length != other.values.length) { - return false; - } else { - for (int i=0; i<values.length; i++) { - if (values[i] != other.values[i]) { - return false; - } - } - - return true; - } - } - } - - /** - * Check if the range specifies any values or not. - * @return true if the range is empty, false if not - */ - public boolean isEmpty() { - return values != null && values.length == 0; - } - - /** - * Hash code to facilitate lookups. - * @return hash - */ - @Override - public int hashCode() { - int hash = 7; - hash = 89 * hash + Arrays.hashCode(this.values); - hash = 89 * hash + this.minValue; - hash = 89 * hash + this.maxValue; - return hash; - } - - /** - * Merge the given range with the current one. - * @param other range to be added to the current range - * @return current range after new range has been added - * @throws AAtlantisException - */ - AIdRange add(AIdRange other) throws AAtlantisException { - - if (values == null && other.values == null) { - - // Both are continuous ranges, find min and max values. - minValue = Math.min(minValue, other.minValue); - maxValue = Math.max(maxValue, other.maxValue); - - } else if (values == null || other.values == null) { - - // One is continous, the other is discrete. - if (values == null) { - - if (other.values.length > 0) { - // If the discrete range is not empty, find min and max values. - minValue = Math.min(minValue, other.values[0]); - maxValue = Math.max(maxValue, other.values[other.values.length-1]); - } - - // If we add an empty range, there is nothing to be done. - - } else { - - if (values.length > 0) { - // If the discrete range is not empty, find min and max values. - minValue = Math.min(values[0], other.minValue); - maxValue = Math.max(values[values.length-1], other.maxValue); - values = null; - } else { - // if this is an empty range, copy min and max from the other. - minValue = other.minValue; - maxValue = other.maxValue; - values = null; - } - } - - } else { - - // Both ranges are discrete, count how many unique elements. - int numValues = values.length; - for (int value : other.values) { - if (!this.contains(value)) { - numValues++; - } - } - - // Merge two arrays, skipping duplicates and keeping order. - int[] newValues = new int[numValues]; - for (int i=0, j=0, k=0; i<numValues; i++) { - if (j == values.length) { - - newValues[i] = other.values[k++]; - - } else if (k == other.values.length) { - - newValues[i] = values[j++]; - - } else { - - if (this.values[j] == other.values[k]) { - newValues[i] = values[j++]; - k++; - } else if (values[j] < other.values[k]) { - newValues[i] = values[j++]; - } else { - newValues[i] = other.values[k++]; - } - } - } - - values = newValues; - } - - return this; - } - - /** - * Check the allowed values and return the number of bits needed to encode them. - * @return number of bits - */ - int bits() { - - // Cound how many values this field can have. - int numValues; - if (values != null) { - numValues = values.length; - } else { - numValues = maxValue - minValue + 1; - } - - if (numValues <= 2) { - // A field takes at least 1 bit, so return 1. - return 1; - } else { - // The number of bits required to store numValues different values. - return (int)(Math.ceil(Math.log(numValues) / Math.log(2))); - } - } - - /** - * Get the field value corresponding to the given range index. For example - * for a field that has range [ -2, 0, +2 ], get(0) will return -2. - * @param index, decoded from compact identifier - * @return field value - * @throws AAtlantisException - */ - int get(int index) throws AAtlantisException { - if (values != null) { - if (index < values.length) { - return values[index]; - } else { - throw new AAtlantisException("Invalid field index: " + index); - } - } else { - if (minValue + index <= maxValue) { - return minValue + index; - } else { - throw new AAtlantisException("Invalid field value: " + index); - } - } - } - - /** - * Convert the range into a convenient form for printing. - * @return formatted string representing range - */ - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - s.append("[ "); - - if (values == null) { - if (parent != null && parent.hasLabels()) { - String minLabel = parent.getLabel(minValue); - String maxLabel = parent.getLabel(maxValue); - s.append(minLabel).append("=").append(minValue); - s.append(" -> ").append(maxLabel).append("=").append(maxValue); - } else { - s.append(minValue).append(" -> ").append(maxValue).append(" "); - } - } else { - for (int value : values) { - if (parent != null && parent.hasLabels()) { - String label = parent.getLabel(value); - s.append(label).append("=").append(value).append(" "); - } else { - s.append(value).append(" "); - } - } - } - s.append("]"); - return s.toString(); - } -} \ No newline at end of file diff --git a/graphics/AtlantisJava/src/atlantis/utils/AIntHashtable.java b/graphics/AtlantisJava/src/atlantis/utils/AIntHashtable.java deleted file mode 100755 index 04b0adbcd5f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AIntHashtable.java +++ /dev/null @@ -1,79 +0,0 @@ -package atlantis.utils; - - -// does not copy input arrays for efficiency -// these arrays must not be modified ! - -public class AIntHashtable { - - int size; - int shift; - int[] key; - int[] value; - int[] next; - int[] first; - - /* - public AIntHashtable(int size) { - this.size=size; - shift=0; - count = 0; - key = new int[size]; - value = new int[size]; - next = new int[size]; - first = new int[size]; - for (int i = 0; i < size; ++i) - first[i] = -1; - } - */ - - public AIntHashtable(int[] key, int[] value) { - this.size=key.length; - this.key=key; - this.value=value; - // - int mask=0; - for(int i=0; i<size; ++i) { - mask=mask|key[i]; - if((mask&1)==1) break; - } - shift=0; - for(int i=0; i<size; ++i) { - if((mask>>i&1)==1) break; - shift++; - } - // - next=new int[size]; - first=new int[size]; - for(int i=0; i<size; ++i) - first[i]=-1; - for(int i=0; i<size; ++i) { - int index=(key[i]>>shift)%size; - if(index<0) index=-index; - this.next[i]=first[index]; - first[index]=i; - } - } - - public AIntHashtable(int[] key) { - this(key, makeIndexArray(key.length)); - } - - private static int[] makeIndexArray(int length) { - int[] temp=new int[length]; - for(int i=0; i<length; ++i) - temp[i]=i; - return temp; - } - - public int get(int key) { - if(size<=0) return -1; - int index=(key>>shift)%size; - if(index<0) index=-index; - for(int e=first[index]; e!=-1; e=next[e]) - if(this.key[e]==key) - return value[e]; - return -1; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/ALogger.java b/graphics/AtlantisJava/src/atlantis/utils/ALogger.java deleted file mode 100644 index 3079c193173..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/ALogger.java +++ /dev/null @@ -1,213 +0,0 @@ -package atlantis.utils; - -import java.io.IOException; -import java.io.File; -import java.util.Properties; - -import org.apache.log4j.Logger; -import org.apache.log4j.Level; -import org.apache.log4j.PatternLayout; -import org.apache.log4j.PropertyConfigurator; -import org.apache.log4j.FileAppender; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.Layout; - - - -/** - * The class is a common wrapper for logging facility, uses - * apache-logging library log4j (more complex and powerful than Java - * native java.util.logging (e.g. flushing is automated, allows customised - * message logs layout, different levels for different sources, etc). - * Because it is subclassing from Logger, it needs LoggerFactory mechanism - * to be in place. Reference to it is given via Properties, if more - * complex properties are to be defined, it will be put in a file (such - * properties file must be accessed generically so that it is load in - * correctly no matter whether Atlantis is run locally (and have distribution - * directories available) or from a .jar file (webstart execution). - * - * @author Zdenek Maxa - */ -public final class ALogger extends Logger -{ - // the class is a singleton, reference to itself - private static Logger root = null; - - // it's enough to instantiate a factory once and for all - private static ALoggerFactory loggerFactory = new ALoggerFactory(); - - // logging layouts definition (format characters explained at PatternLayout class) - private static final String CONSOLE_LOGGING_LAYOUT = - "%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n"; - // %c - cathegory (must be specified at .getLogger(Class.class)) - private static final String FILE_LOGGING_LAYOUT = - "%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n (%c thread:%t)%n"; - // contains some format characters which are slow - *only* for debugging - private static final String FILE_LOGGING_LAYOUT_FULL = - "%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n (%c.%M() [line %L], thread:%t)%n"; - - - - // logging levels as defined in org.apache.log4j.Level - // this variable is used via a getter method to print out command - // line options help - private static String stringLevels = - Level.TRACE.toString() + ", " + // int value: 10000 - Level.DEBUG.toString() + ", " + // int value: 10000 - Level.INFO.toString() + ", " + // int value: 20000 - Level.WARN.toString() + ", " + // int value: 30000 - Level.ERROR.toString() + ", " + // int value: 30000 - Level.FATAL.toString(); // int value: 50000 - - // default logging level (if it wasn't specified or was incorrect) - private static Level defaultLevel = Level.INFO; - - - /** - * The constructor must be protected so that it is visible - * from ALoggerFactory. Should not be instantiated directly, but via - * .getInstance() - * @param name - */ - protected ALogger(String name) - { - super(name); - - } // ALogger() ---------------------------------------------------------- - - - - /** - * initialize(String[] options) - * Initializes the logger - * @param level severity level as read from the command line option - * @param destination destination to write logs to, as read from the command line - */ - public static void initialize(String level, String destination) - { - - // set logging level, if level contains nonsense, set default - Level currentLevel = Level.toLevel(level, defaultLevel); - - - // set properties - LogggerFactory - // log4j.loggerFactory=atlantis.utils.ALoggerFactory - // this may also be done via properties file (if necessary for - // more complex logging configuration without necessity to - // recompile). properties file is contains pairs key=value - // caution: must be accessed generically (so that it also - // works when atlantis is packed in a .jar file) - // without setting LoggerFactory - ClassCastException when getting - // Logger via ALogger.getLogger("Atlantis"); - Properties up = new Properties(); - up.setProperty("log4j.loggerFactory", - "atlantis.utils.ALoggerFactory"); - PropertyConfigurator.configure(up); - - // if instantiated this way - // logger = new ALogger(); - // -> NullPointerException when adding appender - - // all loggers created afterwards will have properties of this root logger - root = Logger.getRootLogger(); - - root.setLevel(currentLevel); - - - // logging will always be done to console (System.out - stdout) - - Layout consoleLayout = new PatternLayout(CONSOLE_LOGGING_LAYOUT); - ConsoleAppender ca = new ConsoleAppender(consoleLayout, - ConsoleAppender.SYSTEM_OUT); - ca.setImmediateFlush(true); - root.addAppender(ca); - - root.info("Logging to console (System.out) initialised"); - - // if a file was specified as logging destination, then logs - // will be duplicated to that file as well - if(destination != null) - { - // check if the file already exists - File f = new File(destination); - boolean fileExists = false; - if(f.exists()) - { - fileExists = true; - } - try - { - // some file was specified on the command line - Layout fileLayout = new PatternLayout(FILE_LOGGING_LAYOUT); - // if the file exists, it will be appended to - FileAppender fa = new FileAppender(fileLayout, destination); - fa.setImmediateFlush(true); - root.addAppender(fa); - if(fileExists) - { - String msg = "================================== " + - "Log file " + destination + " exists, " + - "opening it for appending"; - root.warn(msg); - } - root.warn("Logging to " + destination + " initialised"); - } - catch(IOException ex) - { - root.warn("Can't write log messages to: "+ destination); - } - } - - } // initialize() ------------------------------------------------------- - - - - public static ALogger getLogger(String name) - { - if(root != null) - { - return (ALogger) Logger.getLogger(name, loggerFactory); - } - else - { - // logger hasn't been initialised yet, initialise with - // default values (i.e. logging only to console with INFO level) - try - { - initialize(defaultLevel.toString(),null); - } - catch(Exception ex) - { - // this exception should never occur - ex.printStackTrace(); - } - return (ALogger) Logger.getLogger(name, loggerFactory); - } - - } // getLogger() -------------------------------------------------------- - - - - public static ALogger getLogger(Class clazz) - { - return ALogger.getLogger(clazz.getName()); - - } // getLogger() -------------------------------------------------------- - - - - public void forcedLog(String fqcn, Object msg, Throwable t) - { - super.forcedLog(fqcn, Level.ALL, msg, t); - - } // forcedLog() -------------------------------------------------------- - - - - public static String getStringLevels() - { - return stringLevels; - - } // getStringLevels() -------------------------------------------------- - -} // class ALogger ========================================================== diff --git a/graphics/AtlantisJava/src/atlantis/utils/ALoggerFactory.java b/graphics/AtlantisJava/src/atlantis/utils/ALoggerFactory.java deleted file mode 100644 index f4b5a772b9f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/ALoggerFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package atlantis.utils; - -import org.apache.log4j.Logger; -import org.apache.log4j.spi.LoggerFactory; - -/** - * LoggerFactory as used by ALogger - necessary when subclassing Logger - * @author Zdenek Maxa - */ -public class ALoggerFactory implements LoggerFactory -{ - - /** - * The constructor should be public as it will be called by - * configurators in different packages. - */ - public ALoggerFactory() { } - - - public Logger makeNewLoggerInstance(String name) - { - return new ALogger(name); - } - -} // class ALoggerFactory =================================================== diff --git a/graphics/AtlantisJava/src/atlantis/utils/AMath.java b/graphics/AtlantisJava/src/atlantis/utils/AMath.java deleted file mode 100755 index f52b826ab65..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AMath.java +++ /dev/null @@ -1,328 +0,0 @@ -package atlantis.utils; - -import java.awt.geom.Point2D; - - -/** - * Contains generally useful constants and mathematical functions - * and functions for formatting - */ -public class AMath -{ - final public static double TWO_PI = 2. * Math.PI; - final public static double PI_BY_8 = Math.PI / 8.; - - // Constant giving the unicode value of a small Greek eta. - final static public String ETA = "\u03B7"; - // Constant giving the unicode value of a small Greek lambda. - final static public String LAMBDA = "\u03BB"; - // Unicode capital Lambda - final static public String LAMBDACAP = "\u039B"; - // Unicode lowercase gamma - final static public String GAMMA = "\u03B3"; - // Constant giving the unicode value of a small Greek rho. - final static public String RHO = "\u03C1"; - // Constant giving the unicode value of a small Greek phi. - // final static public String PHI = "\u03C6"; // small - final static public String PHI = "\u03A6"; // capital - // Constant giving the unicode value of degrees symbol. - final static public String DEGREES = "\u00B0"; - // Constant giving the unicode value of a capital Greek delta. - final static public String DELTA = "\u0394"; - // final static public String PRIME = "\u00b4"; - final static public String PRIME = "'"; - final static public String MICRO = "\u00b5"; - final static public String TIMES = "\u00d7"; - final static public String ASYMP = "\u2248"; - final static public String PROP = "\u221D"; - final static public String RADIC = "\u221A"; - - final static public String PLUSMINUS = "\u00b1"; - final static public String NOTEQUAL = "\u2260"; - final static public String LESSEQUAL = "\u2264"; - final static public String GREATEREQUAL = "\u2265"; - final static public String PION = "\u03C0"; - final static public String SIGMA = "\u03A3"; - final static public String TAU = "\u03C4"; - final static public String XI = "\u039E"; - final static public String OMEGA = "\u03A9"; - final static public String MU = "\u03BC"; - - final static public String RARROW = "\u279D"; // right arrow - final static public String DOT = "\u00b7"; // middle dot - - - /** - * Use the unicode overline diacritical mark to place an overline over the preceeding character - * - */ - final static public String OVERLINE = "\u0305"; - // superscript plus and minus - final static public String SUPPLUS = "\u207A"; - final static public String SUPMINUS = "\u207B"; - - - /** - * Returns eta with respect to z = 0. - * @param z double z coordinate - * @param rho double eta coordinate - * @return double eta - */ - public static double etaAbs(double z, double rho) { - double zrho = z / rho; - return Math.log(zrho + Math.sqrt(zrho * zrho + 1.)); - } - - public static double tanLambda(double eta) - { - double e = Math.exp(eta); - return 0.5 * (e-1./e); - } - - public static double lambda(double eta) - { - double e = Math.exp(eta); - return Math.atan(0.5 * (e-1./e)); - } - - public static double getPFromPttL(double pT, double tL) - { - return Math.abs(pT / Math.cos(Math.atan(tL))); - } - - public static double getPtFromPtL(double p, double tL) - { - return Math.abs(p * Math.cos(Math.atan(tL))); - } - - /** - * Force phi into range [0,360) degrees. - * @param phi angle in degrees - * @return equivalent angle in range [0,360) degrees - */ - public static double nearestPhiDegrees(double phi) - { - while(phi >= 360.) - { - phi -= 360; - } - while(phi < 0.) - { - phi += 360; - } - return phi; - } - - /** - * Force phi into range [0,2 pi) radians. - * @param phi angle in radians - * @return equivalent angle in range [0,2 pi) radians - */ - public static double nearestPhiRadians(double phi) - { - while(phi >= TWO_PI) - { - phi -= TWO_PI; - } - while(phi<0.) - { - phi += TWO_PI; - } - return phi; - } - - /** - * Force phi into range [phiMid-180,phiMid+360) degrees. - * @param phi angle in degrees - * @param phiMid mid-point of required phi range - * @return equivalent angle in range [phiMid-180,phiMid+360) degrees - */ - public static double nearestPhiDegrees(double phi, double phiMid) - { - while(phi-phiMid >= 180.) - { - phi -= 360; - } - while(phi-phiMid < -180.) - { - phi += 360; - } - return phi; - } - - /** - * Force phi into range [phiMid-pi,phiMid+pi) radians. - * @param phi angle in degrees - * @param phiMid phiMid mid-point of required phi range - * @return equivalent angle in range [phiMid-pi,phiMid+pi) radians - */ - public static double nearestPhiRadians(double phi, double phiMid) - { - while(phi - phiMid >= Math.PI) - { - phi -= TWO_PI; - } - while(phi - phiMid < -Math.PI) - { - phi += TWO_PI; - } - return phi; - } - - public static double[] splitLineIntoPieces(double[] input, int numPieces) - { - if(input.length != 2) - { - return input; - } - double[] output = new double[numPieces + 1]; - for(int p = 0; p < numPieces + 1; p++) - { - output[p] = input[0] + - (input[1] - input[0]) * (double) p / (double) numPieces; - } - return output; - } - -/** - * "Stretches" the values in the input array over a longer array. - * A number numPieces[i] of equally spaced values between input[i] and input[i+1] - * are put into the output array. So the numPieces array must have the same length - * as the input array, and the length of the output array is the sum of the - * elements of numPieces. For example: - * input = {0.0, 1.0, 5.0} numPieces = {2, 4, 1} - * output = {0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0} - * The output array must already exist and have the correct number of entries, - * otherwise this method will do nothin. - * Only used by ATGCData.getYXUser(). - * @param input array to stretch - * @param output stretched array - * @param numPieces number of output elements corresponding to each input element - */ - public static void splitArrayIntoPieces(double[] input, double[] output, int[] numPieces) - { - // Previously had "output = (double[]) input.clone();" but this is not - // passed back to the calling code so no point. - if(input.length != numPieces.length) return; - - int totalNumPieces = 0; - for (int num : numPieces) totalNumPieces += num; - if(totalNumPieces != output.length) return; - - int index = 0; - for(int i = 0; i < input.length; i++) { - int nextI = (i + 1) % input.length; // "loop back" to start of input - double start = input[i]; - double end = input[nextI]; - for(int p = 0; p < numPieces[i]; p++) - { - output[index++] = start + - (end - start) * (double) p / (double) numPieces[i]; - } - } - } - - /** - * Calculate angle between two 3-vectors represented by Point2D.Double - * objects. - * @param p1 - * @param p2 - * @return angle [radians] - */ - public static double getAngle(Point2D.Double p1, Point2D.Double p2) - { - double dx = p2.x - p1.x; - double dy = p2.y - p1.y; - return Math.atan2(dy, dx); - } - - public static Point2D.Double intersectionPoint( - Point2D.Double p1, Point2D.Double p2, Point2D.Double p3, Point2D.Double p4) - { - - double u = ((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x)) / - ((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y)); - return new Point2D.Double(p1.x+u*(p2.x-p1.x), p1.y+u*(p2.y-p1.y)); - } - - public static Point2D.Double intersectionPoint( - Point2D.Double p1, AVector v1, Point2D.Double p3, AVector v3) - { - Point2D.Double p2 = new Point2D.Double(p1.x+v1.dx, p1.y+v1.dy); - Point2D.Double p4 = new Point2D.Double(p3.x+v3.dx, p3.y+v3.dy); - - return intersectionPoint(p1, p2, p3, p4); - } - - - public static double[] xBox(double x,double dx) - { - return new double[] {x-dx,x-dx,x+dx,x+dx}; - } - - public static double[] yBox(double y,double dy) - { - return new double[] {y-dy,y+dy,y+dy,y-dy}; - } - - /** - * Returns the sign of a double value. - * Unlike Math.signum() it never returns zero. - */ - public static double getSign(double value) { - return (value > 0) ? 1.0 : -1.0; - } - - /** - * Returns the sign of a int value. - * Unlike Math.signum() it never returns zero. - * - */ - public static int getSign(int value) { - return (value > 0) ? 1 : -1; - } - - public static float maxAbsInArray(float[] floatArray) - { - float maxAbs = Math.abs(floatArray[0]); - for(int i=1; i<floatArray.length; ++i) - { - maxAbs = Math.max(Math.abs(floatArray[i]), maxAbs); - } - return maxAbs; - } - - public static float minAbsInArray(float[] floatArray) - { - float minAbs = Math.abs(floatArray[0]); - for(int i=1; i<floatArray.length; ++i) - { - minAbs = Math.min(Math.abs(floatArray[i]), minAbs); - } - return minAbs; - } - - public static float minNonZeroAbsInArray(float[] floatArray) - { - float minAbs = Math.abs(floatArray[0]); - for(int i=1; i<floatArray.length; ++i) - { - if(minAbs == 0.0f && floatArray[i] != 0.0f) - minAbs = floatArray[i]; - else - minAbs = Math.min(Math.abs(floatArray[i]), minAbs); - } - return minAbs; - } - - public static float deltaR(float phi1, float eta1, float phi2, float eta2){ - - float deta=Math.abs(eta1-eta2); - float dphi=Math.abs(phi1-phi2); - if(dphi>Math.PI) - dphi=(float)(Math.PI*2.0f)-dphi; - float dr=(float)Math.sqrt(deta*deta+dphi*dphi); - return dr; - } - -} // class AMath ------------------------------------------------------------- diff --git a/graphics/AtlantisJava/src/atlantis/utils/ANewIdHelper.java b/graphics/AtlantisJava/src/atlantis/utils/ANewIdHelper.java deleted file mode 100644 index 5de597b6684..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/ANewIdHelper.java +++ /dev/null @@ -1,157 +0,0 @@ -package atlantis.utils; - -import java.util.HashMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * Helper tool for decoding compact readout channel identifiers. - * - * @author Eric Jansen - */ -public final class ANewIdHelper { - - /** Singleton instance. */ - private static ANewIdHelper instance = null; - - /** Link to ATLAS dictionary. */ - private AIdDictionary atlas = null; - - /** Collection of named (sub-)dictionaries. */ - private HashMap<String, AIdDictionary> dictionaries = null; - - /** Logging facility. */ - public static ALogger logger = ALogger.getLogger(ANewIdHelper.class); - - /** - * Static construct method, initializes ANewIdHelper from XML dictionaries. - * @param rootNode XML root node of type IdDict. - */ - public synchronized static void construct(Node rootNode) throws AAtlantisException { - if (instance == null) instance = new ANewIdHelper(); - try { - instance.initialize(rootNode); - } catch (AAtlantisException e) { - throw new AAtlantisException("Error initializing ANewIdHelper: " + e.getMessage()); - - } - } - - /** - * Obtain instance of ANewIdHelper. - * @return ANewIdHelper instance. - */ - public synchronized static ANewIdHelper instance() { - if (instance == null) { - throw new Error("Attempted to access ANewIdHelper instance before initialization."); - } - return instance; - } - - /** - * Private constructor. - */ - private ANewIdHelper() {}; - - /** - * Non-static, private initialization method. - * @param rootNode XML root node of type IdDict. - */ - private void initialize(Node rootNode) throws AAtlantisException { - NodeList nodes = rootNode.getChildNodes(); - for (int i=0; i<nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if ("IdDictionary".equals(node.getNodeName())) { - String name = node.getAttributes().getNamedItem("name").getNodeValue(); - try { - if (dictionaries != null && dictionaries.containsKey(name)) { - AIdDictionary dictionary = dictionaries.get(name); - dictionary.initialize(node); - } else { - if (dictionaries == null) { - dictionaries = new HashMap<String,AIdDictionary>(); - } - dictionaries.put(name, new AIdDictionary(node)); - } - } catch (AAtlantisException e) { - logger.error("Exception occurred while initializing IdHelper:" + e.getMessage()); - } - } - } - } - - if (dictionaries.containsKey("ATLAS")) { - atlas = dictionaries.get("ATLAS"); - } else { - throw new AAtlantisException("No 'ATLAS' dictionary found"); - } - } - - /** - * Check for presence of a named dictionary. - * @param dictName dictionary name. - * @return true if dictionary is present, false is not. - */ - boolean hasDictionary(String dictName) { - return dictionaries.containsKey(dictName); - } - - /** - * Return pointer to an existing named dictionary. - * @param dictName dictionary name - * @return dictionary object - */ - AIdDictionary getDictionary(String dictName) throws AAtlantisException { - if (dictionaries != null && dictionaries.containsKey(dictName)) { - return dictionaries.get(dictName); - } else { - throw new AAtlantisException("Dictionary " + dictName + " could not be found"); - } - } - - /** - * Add a named dictionary to the idHelper. - * @param dictName dictionary name - * @param dict dictionary - */ - void addDictionary(String dictName, AIdDictionary dict) { - if (dictionaries == null){ - dictionaries = new HashMap<String,AIdDictionary>(); - } - dictionaries.put(dictName, dict); - } - - /** - * Convert a compact identifier into a "/" delimited expanded identifier. - * @param id compact identifier - * @return expanded identifier, fields delimited by "/" - */ - public String getFullIdentifier(long id) throws AAtlantisException { - return atlas.getFullIdentifier(id); - } - - /** - * Extract named field from a compact identifier. - * @param field identifier field name - * @param id compact identifier - * @return value of named field - */ - public int get(String field, long id) throws AAtlantisException { - return atlas.get(field, id); - } - - /** - * Extract string value of a named field from a compact identifier. For - * example: - * get("stationName", id) = 49 - * getString("stationName", id) = "EIS" - * - * @param field identifier field name - * @param id compact identifier - * @return string value of named field - */ - public String getString(String field, long id) throws AAtlantisException { - return atlas.getString(field, id); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/APoint.java b/graphics/AtlantisJava/src/atlantis/utils/APoint.java deleted file mode 100755 index 38c9d1fd4ad..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/APoint.java +++ /dev/null @@ -1,72 +0,0 @@ -package atlantis.utils; - - -/** - * Used by APolygon and AClipPolygon in order to perform clipping. - */ -public class APoint { - - public double x, y; - - public APoint(APoint p) { - this.x=p.x; - this.y=p.y; - } - - public APoint(double x, double y) { - this.x=x; - this.y=y; - } - - public double dot_product(double[] normPoint) { - if(normPoint==null||normPoint.length!=3) - return 0.0; - else - return x*normPoint[0]+y*normPoint[1]; - } - - public APoint minus(APoint cgp) { - if(cgp==null) - return new APoint(this); - else - return new APoint(x-cgp.x, y-cgp.y); - } - - public APoint plus(APoint cgp) { - if(cgp==null) - return new APoint(this); - else - return new APoint(x+cgp.x, y+cgp.y); - } - - public void scalar_multiply(double d) { - x*=d; - y*=d; - } - - public boolean inside(double[] normalizedVector, double distance) { - if(normalizedVector==null||normalizedVector.length!=3) return false; - double k=dot_product(normalizedVector)+distance; - - return(k<=0); - } - - public double calculate_tls(APoint secondPoint, APoint clipNode, double[] normalized) { - APoint dv1, dv2; - - dv1=minus(clipNode); - dv2=secondPoint.minus(this); - return -(dv1.dot_product(normalized)/dv2.dot_product(normalized)); - } - - public APoint point_of_intersection(APoint second, double tls) { - if(second!=null) { - APoint v=second.minus(this); - - if(v!=null) v.scalar_multiply(tls); - return plus(v); - } else - return null; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/APolygon.java b/graphics/AtlantisJava/src/atlantis/utils/APolygon.java deleted file mode 100755 index 9a0c4e33bc3..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/APolygon.java +++ /dev/null @@ -1,238 +0,0 @@ -package atlantis.utils; - - -import java.util.Vector; -import java.awt.geom.*; - - -/** - * Used in the process of clipping. - */ - -public class APolygon { - protected Vector nodes=new Vector(5, 10); - - public APolygon() {} - - public APolygon(double[] x, double[] y) { - for(int i=0; i<x.length; i++) - nodes.addElement(new APoint(x[i], y[i])); - - if(getSignedArea()<0) { - Vector newNodes=new Vector(5, 10); - - for(int i=nodes.size()-1; i>=0; i--) - newNodes.addElement(nodes.elementAt(i)); - nodes=newNodes; - } - } - - public void addPoint(double x, double y) { - nodes.addElement(new APoint(x, y)); - } - - public double getSignedArea() { - APoint p; - double[] x=new double[nodes.size()]; - double[] y=new double[nodes.size()]; - - for(int i=0; i<nodes.size(); i++) { - p=(APoint)nodes.elementAt(i); - x[i]=p.x; - y[i]=p.y; - } - - return getSignedArea(x, y); - } - - // this function returns the ABSOLUT VALUE of the area - public double getArea() { - return Math.abs(getSignedArea()); - } - - public static double getSignedArea(double[] x, double[] y) { - if(x.length!=y.length) - throw new Error("x.length != y.length"); - if(x.length==0) return 0; - - double s=0; - - for(int i=0; i<x.length-1; i++) - s+=x[i]*y[i+1]-x[i+1]*y[i]; - - s+=x[x.length-1]*y[0]-x[0]*y[x.length-1]; - return s/2; - } - - public static double getArea(double[] x, double[] y) { - return Math.abs(getSignedArea(x, y)); - } - - public static Point2D.Double getCenter(double[] x, double[] y, Point2D.Double p) { - if(x.length==0 || y.length==0) return null; - if(p==null) p=new Point2D.Double(0, 0); - - double s=0, v; - - for(int i=0; i<x.length-1; i++) { - v=x[i]*y[i+1]-x[i+1]*y[i]; - s+=v; - p.x+=(x[i]+x[i+1])*v; - p.y+=(y[i]+y[i+1])*v; - } - - v=x[x.length-1]*y[0]-x[0]*y[x.length-1]; - s+=v; - p.x+=(x[x.length-1]+x[0])*v; - p.y+=(y[x.length-1]+y[0])*v; - - double f=1/(6*s/2); - - p.setLocation(p.x*f, p.y*f); - return p; - } - - public static void scale(double[] x, double[] y, double factor) { - Point2D.Double center=APolygon.getCenter(x, y, null); - - for(int i=0; i<x.length; i++) { - x[i]=(x[i]-center.x)*factor+center.x; - y[i]=(y[i]-center.y)*factor+center.y; - } - } - - /* - public boolean isClockwise() { - if (getArea() < 0) - return true; - else - return false; - } - */ - - public APoint getNode(int index) { - if(index>=0&&index<nodes.size()) - return(APoint)(nodes.elementAt(index)); - else - return null; - } - - public int nrNodes() { - return nodes.size(); - } - - public boolean clip(AClipPolygon clipPolygon) { - int i=0; - int limit=clipPolygon.nrNodes(); - - APoint node=null; - double[] normalized=new double[3]; - double distance=0.0; - - for(i=0; i<limit; i++) { - normalized=clipPolygon.get_normalized(i); - node=clipPolygon.getNode(i); - distance=clipPolygon.get_distance(i); - if(normalized!=null&&node!=null&& !Double.isNaN(distance)) - s_h_clip_poly(normalized, node, distance); - } - - return(nodes.size()>0); - } - - public void s_h_clip_poly(double[] normalized, APoint node, double distance) { - int degree=nodes.size(); - APoint s=null, p=null, q=null; - boolean s_inside, p_inside; - double tls=0.0; - Vector keptNodes=new Vector(); - - if(degree>0&&nodes.elementAt(degree-1) instanceof APoint) - s=(APoint)nodes.elementAt(degree-1); - - for(int i=0; i<nodes.size(); i++) { - if(nodes.elementAt(i) instanceof APoint) { - p=(APoint)nodes.elementAt(i); - s_inside=s.inside(normalized, distance); - p_inside=p.inside(normalized, distance); - if(s_inside) - if(!p_inside) { - tls=s.calculate_tls(p, node, normalized); - q=s.point_of_intersection(p, tls); - keptNodes.addElement(q); - } else - keptNodes.addElement(p); - else if(p_inside) { - tls=s.calculate_tls(p, node, normalized); - q=s.point_of_intersection(p, tls); - keptNodes.addElement(q); - keptNodes.addElement(p); - } - } - s=p; - } - nodes=keptNodes; - } - - public double[][] getPolygon() { - int nrPoints=nodes.size(); - double[][] coord=new double[nrPoints][nrPoints]; - - if(nrPoints>0) - for(int i=0; i<nrPoints; i++) { - APoint aPoint=getNode(i); - - if(aPoint!=null) { - coord[0][i]=aPoint.x; - coord[1][i]=aPoint.y; - } - } - return coord; - } - - public double[] getX() { - int nrPoints=nodes.size(); - double[] coord=new double[nrPoints]; - - if(nrPoints>0) - for(int i=0; i<nrPoints; i++) { - APoint aPoint=getNode(i); - - if(aPoint!=null) - coord[i]=aPoint.x; - } - return coord; - } - - public double[] getY() { - int nrPoints=nodes.size(); - double[] coord=new double[nrPoints]; - - if(nrPoints>0) - for(int i=0; i<nrPoints; i++) { - APoint aPoint=getNode(i); - - if(aPoint!=null) - coord[i]=aPoint.y; - } - return coord; - } - - public String toString() { - StringBuilder s = new StringBuilder(); - int limit=nodes.size(); - - s.append("x:{ "); - for(int i=0; i<limit; i++) { - s.append(((APoint)nodes.elementAt(i)).x); - s.append(" :: "); - } - s.append(" }\ny:{ "); - for(int i=0; i<limit; i++) { - s.append(((APoint)nodes.elementAt(i)).y); - s.append(" :: "); - } - return s.toString(); - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/AUtilities.java b/graphics/AtlantisJava/src/atlantis/utils/AUtilities.java deleted file mode 100755 index 0c01e84f099..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AUtilities.java +++ /dev/null @@ -1,243 +0,0 @@ -package atlantis.utils; - -import java.io.FileNotFoundException; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.File; -import java.util.Date; -import java.text.SimpleDateFormat; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.RenderingHints; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import javax.swing.SwingUtilities; -import javax.swing.ImageIcon; - - -/** - * - * @author Gary Taylor, Zdenek Maxa - */ -public class AUtilities -{ - public static ALogger logger = ALogger.getLogger(AUtilities.class); - - private static final String dateFormat = "yyyy-MM-dd-HH-mm-ss"; - - - private AUtilities() - { - } // AUtilities() ------------------------------------------------------- - - - /** - * Allow Ctrl+click as alternative to right-click so can use single-button - * mouse on the Mac computer - */ - public static boolean isRightMouseButton(MouseEvent e) - { - return SwingUtilities.isRightMouseButton(e) || - e.isControlDown(); - - } // isRightMouseButton() ----------------------------------------------- - - /** - * Returns string with current data and time formatted according to - * dateFomat attribute (currently: yyyy-MM-dd-HH-mm-ss) - * @return String - */ - public static String getDateTimeString() - { - String r = null; - Date d = new Date(System.currentTimeMillis()); - SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); - r = sdf.format(d); - return r; - - } // getDateTimeString() ------------------------------------------------ - - - /** - * Returns last directory and file name from fullPath which is assumed to be - * some path to a file. This method assumes it is used when a file is retrieved - * from a .jar file. - * @param fullPath - */ - private static String getLastDirectoryAndFileName(String fullPath) - { - // if running on Windows, Atlantis.fileSep is '\', but accessing a .jar - // file uses '/' as file separator - so replace all '\' occurrences - // '/' (troubles when running via webstart (from jar file (/ as file - // separator) on windows (uses \ as file separator)) - logger.debug("Trying to extract last directory and filename, input: " + fullPath); - char[] charArray = fullPath.replaceAll("\\\\", "/").toCharArray(); - int sepOccurence = 0; // file separator (e.g. '/') occurrence counter - int i; - for(i = fullPath.length() - 1; i > 0; i--) - { - // compare only to '/', even on Windows '\' was already replaced - // by '/' - if(charArray[i] == '/') - { - sepOccurence++; - } - if(sepOccurence == 2) - { - // i variable now holds second file separator occurrence from end - break; - } - } - - String relPath = null; - - if(sepOccurence == 0) - { - logger.warn("No file separator found in the file path: " + fullPath); - relPath = fullPath; - } - else if(i == 0) - { - logger.warn("The path looks like relative path already, using: " + - fullPath); - relPath = fullPath; - } - else - { - relPath = new String(charArray).substring(i + 1); - logger.debug("Last directory and filename result: " + relPath); - } - - return relPath; - - } // getLastDirectoryAndFileName() -------------------------------------- - - - - /** - * Reads either locally (full path in fileName) or from atlantis.jar. Using - * this method for reading files makes Atlantis running either with runtime - * distribution directories (e.g. img, geometry, etc) or from .jar file - * (everything including runtime directories packed in a jar file) - * transparent. Having everything in .jar files is a requirement for - * running as Java WebStart. - * This method is used for files (text, xml) as InputStream. - * @param fileName - full path - */ - public static InputStream getFileAsStream(String fileName) throws AAtlantisException - { - InputStream is = null; - - if(fileName == null || "".equals(fileName)) - { - String m = "Input parameter fileName is null or empty"; - logger.debug(m); - throw new AAtlantisException(m); - } - - try - { - logger.debug("Trying to access file: " + fileName + " ..."); - is = new FileInputStream(fileName); - logger.debug("Reading " + fileName + " successful."); - } - catch(FileNotFoundException fnfe) - { - logger.warn(fileName + " not found, trying atlantis.jar ... "); - - // need to get file name and the last directory from the full path - String relPath = getLastDirectoryAndFileName(fileName); - - ClassLoader cl = AUtilities.class.getClassLoader(); - is = cl.getResourceAsStream(relPath); - if(is == null) - { - String m = fileName + " doesn't exist, reading " + relPath + - " from atlantis.jar failed."; - logger.error(m); - throw new AAtlantisException(m); - } - logger.debug(fileName + " reading from atlantis.jar successful."); - } - - return is; - - } // getFileAsStream() -------------------------------------------------- - - - - /** - * Reads either locally (full path in fileName) or from atlantis.jar. Using - * this method for reading files makes Atlantis running either with runtime - * distribution directories (e.g. img, geometry, etc) or from .jar file - * (everything including runtime directories packed in a jar file) - * transparent. Having everything in .jar files is a requirement for - * running as Java WebStart. - * This method is used for reading images. - * @param fileName - full path - */ - public static ImageIcon getFileAsImageIcon(String fileName) - { - - ImageIcon ii = null; - - if(fileName == null || "".equals(fileName)) - { - String m = "Input parameter fileName is null or empty, can't get ImageIcon"; - logger.debug(m); - return null; - } - - File test = new File(fileName); - if(test.exists() && test.canRead()) - { - ii = new ImageIcon(fileName); - logger.debug("Reading " + fileName + " successful."); - } - else - { - logger.debug(fileName + " not found, trying atlantis.jar ... "); - - // need to get file name and the last directory from the full path - String relPath = getLastDirectoryAndFileName(fileName); - - ClassLoader cl = AUtilities.class.getClassLoader(); - try { - ii = new ImageIcon(cl.getResource(relPath)); - logger.debug(fileName + " reading from atlantis.jar successful."); - } - catch (Throwable e) { - String m = "Failed to read "+ fileName + " from " + relPath + - " in atlantis.jar"; - logger.debug(m); - } - } - - return ii; - - } // getFileAsImageIcon() ----------------------------------------------- - - // Function used to rescale an Image and return an ImageIcon - // - public static ImageIcon scale(Image src, double scale, boolean antiAlias) { - int w = (int)(scale*src.getWidth(null)); - int h = (int)(scale*src.getHeight(null)); - int type = BufferedImage.TYPE_INT_ARGB; - BufferedImage dst = new BufferedImage(w, h, type); - Graphics2D g2 = dst.createGraphics(); - if(antiAlias) // Render png High Quality when AntiAliasing selected - { - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); - g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - } - else // else render it for speed. - { - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); - g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); - } - g2.drawImage(src, 0, 0, w, h, null); - g2.dispose(); - return new ImageIcon(dst); - } // ------- scale() - -} // class AUtilities ======================================================= diff --git a/graphics/AtlantisJava/src/atlantis/utils/AVector.java b/graphics/AtlantisJava/src/atlantis/utils/AVector.java deleted file mode 100755 index 2d3f7b8c976..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/AVector.java +++ /dev/null @@ -1,84 +0,0 @@ -package atlantis.utils; - - -import java.awt.geom.Point2D; - - -/** - * Provides basic 2D vector operations. - */ - -public class AVector { - - public double dx, dy; - - public AVector(double dx, double dy) { - set(dx, dy); - } - - public AVector(double x1, double y1, double x2, double y2) { - set(x2-x1, y2-y1); - } - - public AVector(Point2D p1, Point2D p2) { - this(p1.getX(), p1.getY(), p2.getX(), p2.getY()); - } - - public AVector set(double dx, double dy) { - this.dx=dx; - this.dy=dy; - return this; - } - - public AVector getUnitary() { - double r=Math.sqrt(dx*dx+dy*dy); - - return new AVector(dx/r, dy/r); - } - - public AVector makeUnitary() { - double r=Math.sqrt(dx*dx+dy*dy); - - dx/=r; - dy/=r; - return this; - } - - public AVector rotate(double alpha) { - double sin=Math.sin(alpha); - double cos=Math.cos(alpha); - double dx_prime=dx*cos-dy*sin; - double dy_prime=dx*sin+dy*cos; - - dx=dx_prime; - dy=dy_prime; - return this; - } - - public AVector scale(double factor) { - dx*=factor; - dy*=factor; - return this; - } - - public AVector invert() { - dx*=-1; - dy*=-1; - return this; - } - - public double modulus() { - return Math.sqrt(dx*dx+dy*dy); - } - - public AVector add(AVector v) { - dx+=v.dx; - dy+=v.dy; - return this; - } - - public String toString() { - return "AVector[dx="+dx+", dy="+dy+"]"; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/package.html b/graphics/AtlantisJava/src/atlantis/utils/package.html deleted file mode 100644 index ba4e3fa430d..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<html> -<head></head> -<body> -<p>Helper classes.</p> -</body> -</html> diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AArrayParser.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AArrayParser.java deleted file mode 100755 index 027bd7e0f74..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AArrayParser.java +++ /dev/null @@ -1,36 +0,0 @@ -package atlantis.utils.xml; - -/** - * The superclass of Integer and Float array parsers used e.g. in parseing - * arrays stored in xml files - */ - -public abstract class AArrayParser -{ - protected int count; - protected int state; - protected int sign; - protected boolean finished; - - protected static final char space = ' '; - protected static final char cariage = '\n'; - protected static final char zero = '0'; - protected static final char nine = '9'; - protected static final char minus = '-'; - protected static final char plus = '+'; - protected static final char dot = '.'; - protected static final char smallExp = 'e'; - protected static final char bigExp = 'E'; - - public abstract void parse(char[] ch, int start, int end); - - public abstract Object getArray(); - - /** - * @return Returns the count. - */ - public int getCount() - { - return count; - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AFloatArrayParser.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AFloatArrayParser.java deleted file mode 100755 index 413eb6ccc87..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AFloatArrayParser.java +++ /dev/null @@ -1,255 +0,0 @@ -package atlantis.utils.xml; - -/** - * The parser used to generate arrays of float values. - */ - -public class AFloatArrayParser extends AArrayParser -{ - private final static int SKIPPING_BLANKS = 0; - private final static int CHECKING_MINUS = 1; - private final static int CHECKING_INF1 = 2; - private final static int CHECKING_INF2 = 3; - private final static int CHECKING_INF3 = 4; - private final static int READING_INT = 5; - private final static int CHECKING_DOT = 6; - private final static int READING_FLOAT = 7; - private final static int CHECKING_EXP = 8; - private final static int CHECKING_EXP_SIGN = 9; - private final static int READING_EXP = 10; - private final static int FINISHING = 11; - private final static int IGNORE = 12; - - private static double[] powers = new double[200 * 2]; - private float[] array; - private float number = 0; - private int floatDigits = 0; - private int exp = 0; - private int expSign = 1; - private boolean isInf = false; - - static - { - for(int i = 0; i < 2 * 200; i++) - powers[i] = Math.pow(10, i - 200); - } - - public AFloatArrayParser(int size) - { - array = new float[size]; - count = 0; - if(size == 0) - state = IGNORE; - else - state = SKIPPING_BLANKS; - sign = 1; - } - - public void parse(char[] ch, int start, int length) - { - if(state == IGNORE) - { - finished = true; - return; - } - - int end = start + length; - nextChar: for(int i = start; i < end; i++) - { - char c = ch[i]; - thisChar: while(true) - { - - switch(state) - { - - case SKIPPING_BLANKS: - if(c == space || c == cariage) - continue nextChar; - else - { - finished = false; - state++; - continue thisChar; - } - - case CHECKING_MINUS: - if(c == minus) - { - sign = -1; - state++; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case CHECKING_INF1: - if(c == 'i' || c == 'I') - { - state++; - continue nextChar; - } - else - { - state = READING_INT; - continue thisChar; - } - - case CHECKING_INF2: - if(c == 'n' || c == 'N') - { - state++; - continue nextChar; - } - else - { - state = FINISHING; - continue thisChar; - } - - case CHECKING_INF3: - if(c == 'f' || c == 'F') - { - state = FINISHING; - isInf = true; - continue nextChar; - } - else - { - state = FINISHING; - continue thisChar; - } - - case READING_INT: - if(c >= zero && c <= nine) - { - number = number * 10 + c - zero; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case CHECKING_DOT: - if(c == dot) - { - state++; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case READING_FLOAT: - if(c >= zero && c <= nine) - { - number = number * 10 + c - zero; - floatDigits++; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case CHECKING_EXP: - if(c == smallExp || c == bigExp) - { - state++; - continue nextChar; - } - else - { - state = FINISHING; - continue thisChar; - } - - case CHECKING_EXP_SIGN: - if(c == minus) - { - expSign = -1; - state++; - continue nextChar; - } - if(c == plus) - { - expSign = +1; - state++; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case READING_EXP: - if(c >= zero && c <= nine) - { - exp = exp * 10 + c - zero; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case FINISHING: - if(c == space || c == cariage) - { - try - { - if(isInf) - { - if(sign == 1) - array[count] = Float.POSITIVE_INFINITY; - else - array[count] = Float.NEGATIVE_INFINITY; - isInf = false; - } - else - array[count] = (float) (number * sign * powers[expSign * exp - floatDigits + 200]); - } - catch(IndexOutOfBoundsException e) - { - // the real number of data is more than the - // expected number of data - throw new IndexOutOfBoundsException("more"); - } - state = SKIPPING_BLANKS; - sign = 1; - exp = 0; - expSign = 1; - floatDigits = 0; - number = 0; - count++; - finished = true; - continue nextChar; - } - else - { - throw new NumberFormatException("" + c); - } - } - } // while true - } // for - } - - public Object getArray() - { - if(!finished) - array[count] = (float) (number * sign * powers[expSign * exp - - floatDigits + 200]); - return array; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AIntArrayParser.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AIntArrayParser.java deleted file mode 100755 index 74ed17a767f..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AIntArrayParser.java +++ /dev/null @@ -1,126 +0,0 @@ -package atlantis.utils.xml; - -/** - * The parser used to generate arrays of integer values. - */ - -public class AIntArrayParser extends AArrayParser -{ - private final static int SKIPPING_BLANKS = 0; - private final static int CHECKING_MINUS = 1; - private final static int READING_INT = 2; - private final static int FINISHING = 3; - private final static int IGNORE = 4; - - private int[] array; - private long number = 0; - - public AIntArrayParser(int size) - { - array = new int[size]; - count = 0; - if(size == 0) - state = IGNORE; - else - state = SKIPPING_BLANKS; - sign = 1; - } - - public void parse(char[] ch, int start, int length) - { - if(state == IGNORE) - { - finished = true; - return; - } - - int end = start + length; - nextChar: for(int i = start; i < end; i++) - { - char c = ch[i]; - thisChar: while(true) - { - switch(state) - { - case READING_INT: - if(c >= zero && c <= nine) - { - number = number * 10 + c - zero; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - case SKIPPING_BLANKS: - if(c == space || c == cariage) - continue nextChar; - else - { - finished = false; - state++; - continue thisChar; - } - case CHECKING_MINUS: - if(c == minus) - { - sign = -1; - state++; - continue nextChar; - } - else - { - state++; - continue thisChar; - } - case FINISHING: - if(c == space || c == cariage) - { - try - { - // This is a hack to make 64-bit identifiers work without - // using long internally. It works because for most - // identifiers only the most significant 32 bits are - // actually used. Proper support for 64-bit integer - // identifiers needs to be implemented asap (#618). - // -- EJ 09/2012 - if (number > Integer.MAX_VALUE && number >> 32 != 0) { - number = number >> 32; - } - array[count] = (int)number * sign; - } - catch(IndexOutOfBoundsException e) - { - // the real number of data is more than the - // expected number of data - throw new IndexOutOfBoundsException("more"); - } - number = 0; - count++; - sign = 1; - state = SKIPPING_BLANKS; - finished = true; - continue nextChar; - } - else - { - throw new NumberFormatException("" + c); - } - } - } // while true - } // for - } - - public Object getArray() - { - if(!finished) { - if (number > Integer.MAX_VALUE) { - number = number >> 32; - } - array[count] = (int)number * sign; - } - return array; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AStringArrayParser.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AStringArrayParser.java deleted file mode 100755 index 1029bbb4a6c..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AStringArrayParser.java +++ /dev/null @@ -1,103 +0,0 @@ -package atlantis.utils.xml; - -/** - * The parser used to generate arrays of integer values. - */ - -public class AStringArrayParser extends AArrayParser -{ - private final static int SKIPPING_BLANKS = 0; - private final static int READING_STRING = 1; - private final static int FINISHING = 2; - private final static int IGNORE = 3; - - StringBuffer buffer; - private String[] array; - - public AStringArrayParser(int size) - { - array = new String[size]; - buffer = new StringBuffer(20); - count = 0; - if(size == 0) - state = IGNORE; - else - state = SKIPPING_BLANKS; - } - - public void parse(char[] ch, int start, int length) - { - if(state == IGNORE) - { - finished = true; - return; - } - - int end = start + length; - nextChar: for(int i = start; i < end; i++) - { - char c = ch[i]; - thisChar: while(true) - { - - switch(state) - { - - case READING_STRING: - if(!(c == space || c == cariage)) - { - buffer.append(c); - continue nextChar; - } - else - { - state++; - continue thisChar; - } - - case SKIPPING_BLANKS: - if(c == space || c == cariage) - continue nextChar; - else - { - finished = false; - state++; - continue thisChar; - } - - case FINISHING: - if(c == space || c == cariage) - { - try - { - array[count++] = new String(buffer); - } - catch(IndexOutOfBoundsException e) - { - // the real number of data is more than the - // expected number of data - throw new IndexOutOfBoundsException("more"); - } - - buffer.setLength(0); - state = SKIPPING_BLANKS; - finished = true; - continue nextChar; - } - else - { - throw new NumberFormatException("" + c); - } - } - } // while true - } // for - } - - public Object getArray() - { - if(!finished && array.length > 0) - array[count] = new String(buffer); - return array; - } - -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLEntityResolver.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLEntityResolver.java deleted file mode 100644 index 0b7a7274a48..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLEntityResolver.java +++ /dev/null @@ -1,40 +0,0 @@ -package atlantis.utils.xml; - -import atlantis.utils.AAtlantisException; -import atlantis.utils.ALogger; -import atlantis.utils.AUtilities; -import java.io.IOException; -import java.io.InputStream; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Entity resolver, used for relaying XML file includes to AUtilities. - * AUtilities.getFileAsStream() handles including files that are located in - * the webstart jar file. - * - * @author Eric Jansen - */ -public class AXMLEntityResolver implements EntityResolver { - - public static ALogger logger = ALogger.getLogger(AXMLEntityResolver.class); - - @Override - public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { - - InputStream input = null; - try { - if (systemId.startsWith("file://")) { - systemId = systemId.substring(7); - } - input = AUtilities.getFileAsStream(systemId); - } catch (AAtlantisException e) { - - logger.error("Could not resolve external entity" - +" '"+systemId+"': " + e.getMessage()); - } - - return new InputSource(input); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLErrorHandler.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLErrorHandler.java deleted file mode 100755 index fddab8ec5db..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLErrorHandler.java +++ /dev/null @@ -1,127 +0,0 @@ -package atlantis.utils.xml; - -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXParseException; - -import atlantis.utils.ALogger; - -/** - * Used in the XML processing code to catch and store the possible exceptions and errors. - */ -public class AXMLErrorHandler implements ErrorHandler { - - //the logger - private final ALogger logger = ALogger.getLogger(AXMLErrorHandler.class); - /** - * Thee different error states encountered in XML parsing - */ - public enum ErrorState { - - NO_ERROR, // no error - IGNORED_DATA, // the given data will be ignored - UNKNOWN_TAG, // unknown tag - INVALID_DATA, // the given data is not valid (e.g. string instead of int) - OTHER_ERROR, // some other error - FATAL_ERROR // some fatal error - event has to be aborted - } - - //Store the current error state - private ErrorState errorState = ErrorState.NO_ERROR; - //Store the exception causing the error - private Throwable cause = null; - - /** - * @return the current error state of the parser - */ - public ErrorState getErrorState() { - return errorState; - } - - /** - * @return the cause of the last error - */ - public Throwable getErrorCause(){ - return cause; - } - - /** - * Set the error state of the parser - * @param errorState The errorState to set. - * @param cause the cause of the error - */ - public void setError(ErrorState errorState, Throwable cause) { - - //check that the user had actually given a cause for all errors - if (cause == null && (errorState != ErrorState.NO_ERROR )) - throw new IllegalArgumentException("Cause can not be NULL"); - - this.errorState = errorState; - - //force cause null for NO_ERROR - if (errorState == ErrorState.NO_ERROR) - this.cause = null; - else - this.cause = cause; - } - - /** - * Handles all errors occurding during parsing - * @param exception the SAXParseException causing the error - */ - public void error(SAXParseException exception) { - - //Only keep the first error, ignore subsequents - if ( getErrorState() != ErrorState.NO_ERROR ) return; - - //Decode error from exception message (is there no better way?! - String errorMessage = exception.getMessage(); - - //Check for undeclared elements - if ( errorMessage.startsWith("Element type") && - errorMessage.indexOf("must be declared") >= 0) { - // an undeclared element is found in event file - // errorMessage - Element type "elementName" must be declared. - setError(ErrorState.UNKNOWN_TAG,exception); - return; - - } else if (errorMessage.startsWith("The content of element type") && - errorMessage.indexOf("must match") >= 0) { - /* errorMessage - The content of element type "elementName" must - match ... - - this error will occur if any undeclared element is found. - */ - setError(ErrorState.INVALID_DATA,exception); - return; - } else { - // an untreated error (e.g. undeclared attributes, etc.) - // supposed to be corrected by modifying event.dtd or retrievers - logger.error("Parsing XML in line " + exception.getLineNumber() + ": " + errorMessage); - setError(ErrorState.OTHER_ERROR,exception); - return; - } - - } - - /** - * Handle warning exceptions - * @param exception the SAX exception - */ - public void warning(SAXParseException exception) { - //Write a warning output, otherwise ignore - logger.warn("Parsing XML at position " + exception.getLineNumber() + ", " + exception.getColumnNumber() + " :: " + exception.getMessage()); - } - - /** - * Handle fatal exceptions - * @param exception the SAX exception - */ - public void fatalError(SAXParseException exception) { - //Only fatal exceptions are handled by global exception handler - String m = "Fatal error while parsing XML, line: " + - exception.getLineNumber() + " column: " + - exception.getColumnNumber() + " reason: " + - exception.getMessage(); - logger.fatal(m); - System.exit(1); - } -} diff --git a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLUtils.java b/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLUtils.java deleted file mode 100755 index c745a476690..00000000000 --- a/graphics/AtlantisJava/src/atlantis/utils/xml/AXMLUtils.java +++ /dev/null @@ -1,38 +0,0 @@ -package atlantis.utils.xml; - - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - - -/** - * Provides some basic XML utilities which are not present in the XML library. - */ -public class AXMLUtils -{ - public static Node getChild(Node node, String name) - { - NodeList childs = node.getChildNodes(); - - for (int i = 0; i < childs.getLength(); i++) - { - Node child = childs.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) - { - if (child.getNodeName().equals(name)) - return child; - } - } - return null; - } - - public static String tryAttribut(NamedNodeMap attributes, String attName) - { - Node node = attributes.getNamedItem(attName); - - return (node != null) ? node.getNodeValue() : null; - } - -} diff --git a/graphics/AtlantisJava/src/overview.html b/graphics/AtlantisJava/src/overview.html deleted file mode 100644 index ebe0e3f52e9..00000000000 --- a/graphics/AtlantisJava/src/overview.html +++ /dev/null @@ -1,25 +0,0 @@ -<html> -<head></head> -<body> - -<p>Atlantis is an event display for the ATLAS experiment at -CERN's Large Hadron Collider.</p> - -<p>The primary goals of the program are the visual investigation and - the understanding of the physics of complete events. Secondary goals - are to help develop reconstruction and analysis algorithms, to - facilitate debugging during commisioning and to provided a tool for - creating pictures and animations for publications, presentations and - exhibitions.</p> - -<p>Atlantis is based on the ALEPH event display DALI.</p> - -<p>Atlantis is written entirely in Java. JiveXML (event converter) is - a C++ interface between Atlantis and the Athena ATLAS offline SW - framework.</p> - -<p>Atlantis event visualisation is a fast, interactive and intuitive - application allowing study of complete ATLAS events.</p> - -</body> -</html> diff --git a/graphics/AtlantisJava/test/events/emptyEvent.xml b/graphics/AtlantisJava/test/events/emptyEvent.xml deleted file mode 100644 index 575abcaba0b..00000000000 --- a/graphics/AtlantisJava/test/events/emptyEvent.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0"?> -<?xml-stylesheet type="text/xsl" href="JiveXML_event.xsl"?> -<?ATLAS Release: "dummy"?> -<!DOCTYPE Event SYSTEM "event.dtd"> -<Event version="dummy" runNumber="1" eventNumber="1" lumiBlock="1" dateTime="" eventProperty=""> -</Event> diff --git a/graphics/AtlantisJava/test/events/muonCollections.xml b/graphics/AtlantisJava/test/events/muonCollections.xml deleted file mode 100644 index c9281c94d4d..00000000000 --- a/graphics/AtlantisJava/test/events/muonCollections.xml +++ /dev/null @@ -1,240 +0,0 @@ -<?xml version="1.0"?> -<?xml-stylesheet type="text/xsl" href="JiveXML_event.xsl"?> -<?ATLAS Release: "dummy"?> -<!DOCTYPE Event SYSTEM "event.dtd"> -<Event version="dummy" runNumber="1" eventNumber="1" lumiBlock="1" dateTime="" eventProperty=""> - -<!-- Test event with two muon track collections, ConvertedMBoyMuonSpectroOnlyTracks and ConvertedMBoyTracks, - each containing two tracks. Edited down from JiveXML_105200_190249.xml. --> - -<Track count="2" storeGateKey="ConvertedMBoyMuonSpectroOnlyTracks"> - -<barcode> -0 0 -</barcode> -<chi2> -11.516 97.6254 -</chi2> -<cotTheta> --0.769442 1.26983 -</cotTheta> -<covMatrix multiple="15"> -19219.9 -213.586 22.2079 -47.5008 0.526573 0.135968 0.532181 -0.384001 -0.00148101 0.00808431 --0.0402467 0.104992 0.000158801 -0.00114179 0.00470875 54908.6 11775 4453.41 -220.818 -39.2807 -1.26332 -73.45 -46.6243 0.226787 0.609096 -77.0102 42.0205 0.986568 -0.892189 6.4339 - -</covMatrix> -<d0> -0 0 -</d0> -<driftSign multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 -</driftSign> -<hits multiple="36"> -2100232864 2100236992 2100241088 2100245216 2100249472 2100249504 2100253568 2100253600 2100257728 2100261824 -1730609632 1730613760 1730617856 1730621984 1730626336 1730626368 1730630432 1730630464 1730634592 1730638688 -1647284976 1647284336 1647286000 1647285364 1646731264 1646731296 1646739744 1646743840 1646747968 1646748000 -1646772976 1646772272 1646774000 1646773300 1680278368 1680282464 1680286592 1680295072 1680299168 1680303296 -1680315180 1680314384 1618215712 1618219840 1618219872 1618223968 1618228096 1618228128 2035453088 2035451984 -1802240896 1802245024 1802245056 1802249152 1802253280 1802257568 1802261664 1802261696 1802265824 1802269952 -1651803772 1651803200 1651769920 1651774016 1651778144 1651786592 1651790688 1651794816 1651823224 1651822616 -1651823644 1684836392 -</hits> -<id> -0 1 -</id> -<isOutlier multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 1 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 1 1 1 0 1 1 0 0 -0 0 -</isOutlier> -<nPixHits> -0 0 -</nPixHits> -<nSCTHits> -0 0 -</nSCTHits> -<nTRTHits> -0 0 -</nTRTHits> -<numDoF> -32 19 -</numDoF> -<numHits> -42 30 -</numHits> -<numPolyline> -42 30 -</numPolyline> -<phi0> --0.799777 2.98857 -</phi0> -<polylineX multiple="36"> -362.371 364.017 365.663 367.309 381.139 382.149 382.786 383.796 385.443 387.09 -415.16 416.809 418.457 420.106 433.955 434.965 435.605 436.614 438.264 439.914 -471.844 471.844 473.398 473.398 485.111 486.12 509.514 511.168 512.822 513.83 -519.096 519.096 520.65 520.65 646.788 648.447 650.105 674.583 676.242 677.902 -682.726 682.726 -477.38 -479.179 -480.655 -482.454 -484.254 -485.73 -578.526 -578.526 --594.877 -597.01 -598.693 -600.825 -602.958 -620.809 -622.98 -624.767 -626.938 -630.896 --683.109 -683.109 -690.955 -693.412 -695.868 -731.028 -733.561 -736.094 -744.69 -744.69 --746.92 -979.54 -</polylineX> -<polylineY multiple="36"> --372.719 -374.414 -376.108 -377.802 -392.037 -393.077 -393.732 -394.773 -396.468 -398.163 --427.056 -428.753 -430.451 -432.148 -446.404 -447.443 -448.102 -449.141 -450.839 -452.538 --485.408 -485.408 -487.007 -487.007 -499.066 -500.104 -524.189 -525.892 -527.594 -528.632 --534.054 -534.054 -535.654 -535.654 -665.539 -667.248 -668.956 -694.165 -695.875 -697.584 --702.553 -702.553 85.6237 85.754 85.8609 85.9913 86.1216 86.2285 88.9471 88.9471 -89.0356 89.0428 89.0486 89.0558 89.063 89.101 89.1036 89.1058 89.1083 89.1131 -89.1739 89.1739 89.1895 89.1953 89.2011 89.329 89.3419 89.3547 89.4028 89.4028 -89.4162 92.8672 -</polylineY> -<polylineZ multiple="36"> --392.694 -394.508 -396.321 -398.134 -413.36 -414.472 -415.172 -416.284 -418.096 -419.908 --450.754 -452.563 -454.373 -456.182 -471.371 -472.478 -473.179 -474.285 -476.093 -477.901 --512.838 -512.838 -514.536 -514.536 -527.329 -528.43 -553.946 -555.748 -557.549 -558.648 --564.384 -564.384 -566.076 -566.076 -702.92 -704.714 -706.508 -732.968 -734.761 -736.554 --741.766 -741.766 624.853 627.02 628.798 630.966 633.133 634.911 734.06 734.06 -749.096 750.985 752.476 754.365 756.254 771.538 773.328 774.802 776.592 779.856 -819.572 819.572 825.126 826.836 828.545 851.948 853.557 855.167 860.549 860.549 -861.929 979.729 -</polylineZ> -<pt> -55.8412 -1.03551 -</pt> -<trackAuthor> -9 9 -</trackAuthor> -<z0> --319.781 549.784 -</z0> -</Track> - -<Track count="2" storeGateKey="ConvertedMBoyTracks"> - -<barcode> -0 0 -</barcode> -<chi2> -11.516 97.6254 -</chi2> -<cotTheta> --0.770806 1.3117 -</cotTheta> -<covMatrix multiple="15"> -82352.8 -562.768 12126.3 -112.852 1.11282 0.199247 2.26463 -40.4407 -0.00427538 0.146613 --0.0227186 0.948083 0.00233271 -0.00250997 0.00411825 1.41767e+07 175813 5.07167e+07 -38589 17704.2 -133.741 5445.87 -130132 -66.2113 351.292 -4460.38 20560 25.2706 -57.2321 21.1558 - -</covMatrix> -<d0> -0.493352 11.5304 -</d0> -<driftSign multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 -</driftSign> -<hits multiple="36"> -2100232864 2100236992 2100241088 2100245216 2100249472 2100249504 2100253568 2100253600 2100257728 2100261824 -1730609632 1730613760 1730617856 1730621984 1730626336 1730626368 1730630432 1730630464 1730634592 1730638688 -1647284976 1647284336 1647286000 1647285364 1646731264 1646731296 1646739744 1646743840 1646747968 1646748000 -1646772976 1646772272 1646774000 1646773300 1680278368 1680282464 1680286592 1680295072 1680299168 1680303296 -1680315180 1680314384 1618215712 1618219840 1618219872 1618223968 1618228096 1618228128 2035453088 2035451984 -1802240896 1802245024 1802245056 1802249152 1802253280 1802257568 1802261664 1802261696 1802265824 1802269952 -1651803772 1651803200 1651769920 1651774016 1651778144 1651786592 1651790688 1651794816 1651823224 1651822616 -1651823644 1684836392 -</hits> -<id> -0 1 -</id> -<isOutlier multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 1 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 1 1 1 0 1 1 0 0 -0 0 -</isOutlier> -<nPixHits> -0 0 -</nPixHits> -<nSCTHits> -0 0 -</nSCTHits> -<nTRTHits> -0 0 -</nTRTHits> -<numDoF> -32 19 -</numDoF> -<numHits> -42 30 -</numHits> -<numPolyline> -42 30 -</numPolyline> -<phi0> --0.790721 2.76041 -</phi0> -<polylineX multiple="36"> -362.371 364.017 365.663 367.309 381.139 382.149 382.786 383.796 385.443 387.09 -415.16 416.809 418.457 420.106 433.955 434.965 435.605 436.614 438.264 439.914 -471.844 471.844 473.398 473.398 485.111 486.12 509.514 511.168 512.822 513.83 -519.096 519.096 520.65 520.65 646.788 648.447 650.105 674.583 676.242 677.902 -682.726 682.726 -477.38 -479.179 -480.655 -482.454 -484.254 -485.73 -578.526 -578.526 --594.877 -597.01 -598.693 -600.825 -602.958 -620.809 -622.98 -624.767 -626.938 -630.896 --683.109 -683.109 -690.955 -693.412 -695.868 -731.028 -733.561 -736.094 -744.69 -744.69 --746.92 -979.54 -</polylineX> -<polylineY multiple="36"> --372.719 -374.414 -376.108 -377.802 -392.037 -393.077 -393.732 -394.773 -396.468 -398.163 --427.056 -428.753 -430.451 -432.148 -446.404 -447.443 -448.102 -449.141 -450.839 -452.538 --485.408 -485.408 -487.007 -487.007 -499.066 -500.104 -524.189 -525.892 -527.594 -528.632 --534.054 -534.054 -535.654 -535.654 -665.539 -667.248 -668.956 -694.165 -695.875 -697.584 --702.553 -702.553 85.6237 85.754 85.8609 85.9913 86.1216 86.2285 88.9471 88.9471 -89.0356 89.0428 89.0486 89.0558 89.063 89.101 89.1036 89.1058 89.1083 89.1131 -89.1739 89.1739 89.1895 89.1953 89.2011 89.329 89.3419 89.3547 89.4028 89.4028 -89.4162 92.8672 -</polylineY> -<polylineZ multiple="36"> --392.694 -394.508 -396.321 -398.134 -413.36 -414.472 -415.172 -416.284 -418.096 -419.908 --450.754 -452.563 -454.373 -456.182 -471.371 -472.478 -473.179 -474.285 -476.093 -477.901 --512.838 -512.838 -514.536 -514.536 -527.329 -528.43 -553.946 -555.748 -557.549 -558.648 --564.384 -564.384 -566.076 -566.076 -702.92 -704.714 -706.508 -732.968 -734.761 -736.554 --741.766 -741.766 624.853 627.02 628.798 630.966 633.133 634.911 734.06 734.06 -749.096 750.985 752.476 754.365 756.254 771.538 773.328 774.802 776.592 779.856 -819.572 819.572 825.126 826.836 828.545 851.948 853.557 855.167 860.549 860.549 -861.929 979.729 -</polylineZ> -<pt> -58.6356 -3.08337 -</pt> -<trackAuthor> -9 9 -</trackAuthor> -<z0> -7.67828 -4.26881 -</z0> -</Track> -</Event> - diff --git a/graphics/AtlantisJava/test/events/muonCollections2.xml b/graphics/AtlantisJava/test/events/muonCollections2.xml deleted file mode 100644 index 36c046de320..00000000000 --- a/graphics/AtlantisJava/test/events/muonCollections2.xml +++ /dev/null @@ -1,291 +0,0 @@ -<?xml version="1.0"?> -<?xml-stylesheet type="text/xsl" href="JiveXML_event.xsl"?> -<?ATLAS Release: "dummy"?> -<!DOCTYPE Event SYSTEM "event.dtd"> - -<Event version="dummy" runNumber="2" eventNumber="2" lumiBlock="2" dateTime="" eventProperty=""> - -<!-- Test event with two muon track collections, ConvertedMBoyTracks and - ConvertedMuIdCBTracks, each containing 2 tracks. - Edited down from JiveXML_105200_190249.xml. ---> - -<Track count="2" storeGateKey="ConvertedMBoyTracks"> -<barcode> -0 0 -</barcode> -<chi2> -11.516 97.6254 -</chi2> -<cotTheta> --0.770806 1.3117 -</cotTheta> -<covMatrix multiple="15"> -82352.8 -562.768 12126.3 -112.852 1.11282 0.199247 2.26463 -40.4407 -0.00427538 0.146613 --0.0227186 0.948083 0.00233271 -0.00250997 0.00411825 1.41767e+07 175813 5.07167e+07 -38589 17704.2 -133.741 5445.87 -130132 -66.2113 351.292 -4460.38 20560 25.2706 -57.2321 21.1558 - -</covMatrix> -<d0> -0.493352 11.5304 -</d0> -<driftSign multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 -</driftSign> -<hits multiple="36"> -2100232864 2100236992 2100241088 2100245216 2100249472 2100249504 2100253568 2100253600 2100257728 2100261824 -1730609632 1730613760 1730617856 1730621984 1730626336 1730626368 1730630432 1730630464 1730634592 1730638688 -1647284976 1647284336 1647286000 1647285364 1646731264 1646731296 1646739744 1646743840 1646747968 1646748000 -1646772976 1646772272 1646774000 1646773300 1680278368 1680282464 1680286592 1680295072 1680299168 1680303296 -1680315180 1680314384 1618215712 1618219840 1618219872 1618223968 1618228096 1618228128 2035453088 2035451984 -1802240896 1802245024 1802245056 1802249152 1802253280 1802257568 1802261664 1802261696 1802265824 1802269952 -1651803772 1651803200 1651769920 1651774016 1651778144 1651786592 1651790688 1651794816 1651823224 1651822616 -1651823644 1684836392 -</hits> -<id> -0 1 -</id> -<isOutlier multiple="36"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 1 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 1 1 1 0 1 1 0 0 -0 0 -</isOutlier> -<nPixHits> -0 0 -</nPixHits> -<nSCTHits> -0 0 -</nSCTHits> -<nTRTHits> -0 0 -</nTRTHits> -<numDoF> -32 19 -</numDoF> -<numHits> -42 30 -</numHits> -<numPolyline> -42 30 -</numPolyline> -<phi0> --0.790721 2.76041 -</phi0> -<polylineX multiple="36"> -362.371 364.017 365.663 367.309 381.139 382.149 382.786 383.796 385.443 387.09 -415.16 416.809 418.457 420.106 433.955 434.965 435.605 436.614 438.264 439.914 -471.844 471.844 473.398 473.398 485.111 486.12 509.514 511.168 512.822 513.83 -519.096 519.096 520.65 520.65 646.788 648.447 650.105 674.583 676.242 677.902 -682.726 682.726 -477.38 -479.179 -480.655 -482.454 -484.254 -485.73 -578.526 -578.526 --594.877 -597.01 -598.693 -600.825 -602.958 -620.809 -622.98 -624.767 -626.938 -630.896 --683.109 -683.109 -690.955 -693.412 -695.868 -731.028 -733.561 -736.094 -744.69 -744.69 --746.92 -979.54 -</polylineX> -<polylineY multiple="36"> --372.719 -374.414 -376.108 -377.802 -392.037 -393.077 -393.732 -394.773 -396.468 -398.163 --427.056 -428.753 -430.451 -432.148 -446.404 -447.443 -448.102 -449.141 -450.839 -452.538 --485.408 -485.408 -487.007 -487.007 -499.066 -500.104 -524.189 -525.892 -527.594 -528.632 --534.054 -534.054 -535.654 -535.654 -665.539 -667.248 -668.956 -694.165 -695.875 -697.584 --702.553 -702.553 85.6237 85.754 85.8609 85.9913 86.1216 86.2285 88.9471 88.9471 -89.0356 89.0428 89.0486 89.0558 89.063 89.101 89.1036 89.1058 89.1083 89.1131 -89.1739 89.1739 89.1895 89.1953 89.2011 89.329 89.3419 89.3547 89.4028 89.4028 -89.4162 92.8672 -</polylineY> -<polylineZ multiple="36"> --392.694 -394.508 -396.321 -398.134 -413.36 -414.472 -415.172 -416.284 -418.096 -419.908 --450.754 -452.563 -454.373 -456.182 -471.371 -472.478 -473.179 -474.285 -476.093 -477.901 --512.838 -512.838 -514.536 -514.536 -527.329 -528.43 -553.946 -555.748 -557.549 -558.648 --564.384 -564.384 -566.076 -566.076 -702.92 -704.714 -706.508 -732.968 -734.761 -736.554 --741.766 -741.766 624.853 627.02 628.798 630.966 633.133 634.911 734.06 734.06 -749.096 750.985 752.476 754.365 756.254 771.538 773.328 774.802 776.592 779.856 -819.572 819.572 825.126 826.836 828.545 851.948 853.557 855.167 860.549 860.549 -861.929 979.729 -</polylineZ> -<pt> -58.6356 -3.08337 -</pt> -<trackAuthor> -9 9 -</trackAuthor> -<z0> -7.67828 -4.26881 -</z0> -</Track> - - -<Track count="2" storeGateKey="ConvertedMuIdCBTracks"> - -<barcode> -0 0 -</barcode> -<chi2> -42.814 49.7505 -</chi2> -<cotTheta> --0.771556 1.27815 -</cotTheta> -<covMatrix multiple="15"> -0.00826928 0.00161205 0.524101 -0.000787796 -0.000158775 9.16577e-05 -9.49e-05 -0.0391607 1.23985e-05 0.00336271 --0.00155346 -0.000959667 0.000188491 8.20954e-05 0.00144041 0.169634 -0.0124204 0.789371 -0.0337235 0.00136704 -0.00730118 0.0015583 -0.128944 -0.000194753 0.02396 -0.0501037 0.0144917 0.0149698 -0.00297823 0.352475 - -</covMatrix> -<d0> -0.089879 -0.11419 -</d0> -<driftSign multiple="75.5"> -0 0 0 0 0 0 0 0 0 0 -0 1 1 -1 1 -1 -1 -1 -1 -1 --1 1 -1 -1 1 1 -1 1 -1 -1 --1 -1 1 1 -1 1 -1 1 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 -1 -1 -1 -1 --1 -1 -1 1 1 1 -1 -1 -1 1 --1 1 -1 -1 -1 -1 -1 1 1 1 --1 -1 -1 1 -1 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 -</driftSign> -<hits multiple="75.5"> -2725184265 2888627033 3047989021 168699032 168697991 171025537 171024522 173350018 173348972 175676530 -175675510 331359616 331360672 331361728 331362752 331364832 331384384 331386400 331388416 331390464 -331392480 331395520 331396544 331398560 331399584 331401600 331405664 331416928 331419008 331422144 -331424224 331427360 331428384 331430464 331432576 331433600 331435680 331436736 2100232864 2100236992 -2100241088 2100245216 2100249472 2100249504 2100253568 2100253600 2100257728 2100261824 1730609632 1730613760 -1730617856 1730621984 1730626336 1730630432 1730630464 1730634592 1730638688 1647286000 1647285364 1646731264 -1646731296 1646739744 1646743840 1646747968 1646748000 1646773300 1646774000 1680278368 1680282464 1680286592 -1680295072 1680299168 1680303296 1680314384 1680315180 2706406253 2855456339 3002378023 168253015 168251976 -170483061 170482036 172713122 172712111 174909133 174908084 383784512 383786592 383788640 383789664 -383790720 383791680 383792736 383793760 383812192 383814272 383816288 383818368 383820416 383821440 -383822496 383823520 383825536 383827616 383846048 383848128 383850144 383851168 383853216 383855296 -383857312 383859392 383877824 383882944 383885024 1618215712 1618219840 1618219872 1618223968 1618228096 -1618228128 2035453096 2035451984 1802240896 1802245024 1802245056 1802249152 1802253280 1802257568 1802261664 -1802261696 1802265824 1802269952 1651803772 1651803200 1651769920 1651774016 1651778144 1651786592 1651790688 -1651794816 1651823224 1651823644 1684800672 1684804768 1684808896 1684817248 1684821312 1684825440 1684838064 -1684837408 -</hits> -<id> -0 1 -</id> -<isOutlier multiple="75.5"> -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 1 1 1 1 1 -1 0 0 0 0 0 0 0 0 0 -0 0 1 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 -0 -</isOutlier> -<nPixHits> -3 3 -</nPixHits> -<nSCTHits> -8 8 -</nSCTHits> -<nTRTHits> -27 29 -</nTRTHits> -<numDoF> -73 67 -</numDoF> -<numHits> -75 76 -</numHits> -<numPolyline> -75 76 -</numPolyline> -<phi0> --0.792403 2.83724 -</phi0> -<polylineX multiple="75.5"> -3.76812 6.33631 8.61433 21.2214 21.2854 26.2311 26.295 31.4707 31.5345 36.4392 -36.5029 44.1987 44.685 45.1907 45.675 46.6756 49.9041 50.7914 51.6869 52.5953 -53.5071 54.8868 55.3573 56.2911 56.7603 57.7053 59.6133 61.3182 62.2339 63.6216 -64.5559 65.9688 66.4364 67.3895 68.3545 68.8261 69.7947 70.2729 361.985 363.632 -365.28 366.928 380.774 381.786 382.423 383.434 385.083 386.732 414.834 416.484 -418.135 419.786 433.65 435.302 436.313 437.964 439.616 471.581 472.359 484.864 -485.874 509.294 510.949 512.605 513.614 519.664 519.664 646.717 648.378 650.038 -674.541 676.203 677.864 682.699 682.699 -4.69928 -8.49491 -11.7275 -28.6103 -28.6966 --35.5786 -35.6658 -43.2266 -43.3145 -49.3888 -49.4759 -62.7019 -63.94 -65.41 -66.0181 --66.6494 -67.4119 -68.0438 -68.6522 -70.5337 -71.7754 -73.1723 -74.4154 -75.8909 -76.4981 --77.1352 -77.7425 -79.1421 -80.3877 -82.3188 -83.5658 -84.9682 -85.5738 -87.0543 -88.3031 --89.7074 -90.9573 -92.824 -96.0854 -97.3375 -477.031 -478.837 -480.315 -482.129 -483.948 --485.428 -578.457 -578.457 -594.879 -597.008 -598.688 -600.823 -602.96 -620.821 -622.986 --624.768 -626.94 -630.918 -683.109 -683.109 -691.068 -693.535 -696.015 -731.403 -733.952 --736.508 -744.69 -745.805 -927.496 -930.236 -932.976 -967.838 -969.536 -972.29 -979.54 --980.655 -</polylineX> -<polylineY multiple="75.5"> --3.69527 -6.30342 -8.61847 -21.4575 -21.5229 -26.5724 -26.6377 -31.9298 -31.995 -37.0174 --37.0826 -44.9778 -45.4772 -45.9968 -46.4943 -47.5225 -50.8422 -51.7552 -52.6767 -53.6118 --54.5506 -55.9717 -56.4564 -57.4187 -57.9022 -58.8765 -60.8442 -62.6033 -63.5486 -64.9814 --65.9465 -67.4063 -67.8896 -68.8748 -69.8726 -70.3604 -71.3623 -71.8571 -373.106 -374.798 --376.49 -378.183 -392.402 -393.442 -394.096 -395.135 -396.828 -398.522 -427.384 -429.079 --430.774 -432.47 -446.71 -448.406 -449.444 -451.141 -452.837 -485.67 -486.469 -499.314 --500.351 -524.41 -526.11 -527.811 -528.848 -535.063 -535.063 -665.602 -667.309 -669.015 --694.196 -695.903 -697.61 -702.579 -702.579 1.57025 2.70537 3.64723 8.20767 8.22939 -9.91078 9.93148 11.6655 11.6851 12.9935 13.0117 15.5953 15.8191 16.081 16.1881 -16.2985 16.4308 16.5395 16.6435 16.9605 17.1658 17.3931 17.5922 17.8246 17.9191 -18.0174 18.1104 18.3221 18.5071 18.7879 18.9655 19.1617 19.2453 19.4468 19.6134 -19.7969 19.9571 20.1911 20.5846 20.7305 72.212 72.4473 72.6375 72.8677 73.0952 -73.2777 81.2266 81.2266 82.1853 82.3048 82.3986 82.5175 82.6355 83.5933 83.7065 -83.7992 83.9127 84.1196 86.7554 86.7554 87.1596 87.2851 87.4124 89.2493 89.3834 -89.5192 89.9559 90.0156 100.839 101.018 101.197 103.504 103.618 103.802 104.29 -104.366 -</polylineY> -<polylineZ multiple="75.5"> -3.50153 0.677387 -1.82855 -15.7119 -15.7825 -21.2359 -21.3064 -27.0176 -27.088 -32.5043 --32.5746 -41.0812 -41.619 -42.1784 -42.7141 -43.821 -47.3938 -48.3761 -49.3675 -50.3733 --51.383 -52.9113 -53.4324 -54.4669 -54.9867 -56.034 -58.1486 -60.0387 -61.0541 -62.5931 --63.6294 -65.1968 -65.7157 -66.7733 -67.8442 -68.3677 -69.4429 -69.9738 -392.695 -394.508 --396.321 -398.134 -413.359 -414.471 -415.172 -416.284 -418.095 -419.907 -450.752 -452.562 --454.371 -456.181 -471.369 -473.178 -474.284 -476.092 -477.9 -512.837 -513.686 -527.328 --528.429 -553.945 -555.747 -557.549 -558.648 -565.23 -565.23 -702.927 -704.721 -706.516 --732.978 -734.772 -736.565 -741.784 -741.784 13.9188 18.9826 23.283 45.5935 45.7069 -54.7381 54.8523 64.7366 64.8514 72.7677 72.881 90.0479 91.6506 93.5526 94.3391 -95.1555 96.1413 96.9581 97.7443 100.175 101.778 103.581 105.185 107.087 107.87 -108.691 109.474 111.277 112.881 115.367 116.972 118.776 119.555 121.458 123.063 -124.868 126.473 128.87 133.055 134.661 625.142 627.308 629.076 631.238 633.399 -635.154 734.06 734.06 749.091 750.989 752.48 754.369 756.247 771.525 773.326 -774.801 776.589 779.835 819.417 819.417 824.967 826.666 828.354 851.354 852.938 -854.512 859.492 860.163 951.515 952.693 953.866 968.469 969.167 970.296 973.262 -973.717 -</polylineZ> -<pt> -59.5287 -3.02081 -</pt> -<trackAuthor> -1 1 -</trackAuthor> -<z0> -7.57297 7.58689 -</z0> -</Track> - -</Event> diff --git a/graphics/AtlantisJava/test/events/rvxEvent.xml b/graphics/AtlantisJava/test/events/rvxEvent.xml deleted file mode 100644 index 21c7b7ca07e..00000000000 --- a/graphics/AtlantisJava/test/events/rvxEvent.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0"?> -<?xml-stylesheet type="text/xsl" href="JiveXML_event.xsl"?> -<?ATLAS Release: "dummy"?> -<!DOCTYPE Event SYSTEM "event.dtd"> -<Event version="dummy" runNumber="1" eventNumber="1" lumiBlock="1" dateTime="" eventProperty=""> - -<RVx count="4" storeGateKey=""> - -<chi2> -13.3549 13.3549 0.979663 0.979663 -</chi2> -<covMatrix multiple="6"> -3145 1516.27 739.31 230.495 111.531 34.7901 3145 1516.27 739.31 230.495 -111.531 34.7901 0.0057955 0.00580698 0.0161258 0.00385126 0.0066793 0.172986 0.0057955 0.00580698 -0.0161258 0.00385126 0.0066793 0.172986 -</covMatrix> -<numTracks> -2 2 29 0 -</numTracks> -<primVxCand> -2 2 1 0 -</primVxCand> -<sgkey> -TrackParticleCandidate TrackParticleCandidate TrackParticleCandidate TrackParticleCandidate -</sgkey> -<tracks multiple="8.25"> -41 33 41 33 0 1 2 3 4 5 -6 7 8 9 10 11 12 13 14 15 -16 17 18 19 20 21 22 23 24 25 -26 27 28 -</tracks> -<x> -35.1249 35.1249 -0.0114638 -0.0114638 -</x> -<y> -18.3795 18.3795 0.0945006 0.0945006 -</y> -<z> -7.44812 7.44812 5.03257 5.03257 -</z> -</RVx> - - -</Event> diff --git a/graphics/AtlantisJava/test/events/rvxInconsistentEvent.xml b/graphics/AtlantisJava/test/events/rvxInconsistentEvent.xml deleted file mode 100644 index 3c745253f7c..00000000000 --- a/graphics/AtlantisJava/test/events/rvxInconsistentEvent.xml +++ /dev/null @@ -1,258 +0,0 @@ -<?xml version="1.0"?> -<?xml-stylesheet type="text/xsl" href="JiveXML_event.xsl"?> -<?ATLAS Release: "dummy"?> -<!DOCTYPE Event SYSTEM "event.dtd"> -<Event version="dummy" runNumber="1" eventNumber="1" lumiBlock="1" dateTime="" eventProperty=""> - -<RVx count="4" storeGateKey=""> - -<chi2> -13.3549 13.3549 0.979663 0.979663 -</chi2> -<covMatrix multiple="6"> -3145 1516.27 739.31 230.495 111.531 34.7901 3145 1516.27 739.31 230.495 -111.531 34.7901 0.0057955 0.00580698 0.0161258 0.00385126 0.0066793 0.172986 0.0057955 0.00580698 -0.0161258 0.00385126 0.0066793 0.172986 -</covMatrix> -<numTracks> -2 2 29 0 -</numTracks> -<primVxCand> -2 2 1 0 -</primVxCand> -<sgkey> -TrackParticleCandidate TrackParticleCandidate TrackParticleCandidate TrackParticleCandidate -</sgkey> -<tracks multiple="544.5"> --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 41 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 33 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 41 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 33 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 0 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 2 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 3 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 4 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 5 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 6 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 7 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -8 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 9 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 10 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 11 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 12 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 13 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 14 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 15 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 16 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 17 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -18 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 19 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 20 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 21 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 22 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 23 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 24 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 25 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 26 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 27 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -28 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -1 -1 --1 -1 -1 -1 -1 -1 -1 -1 -</tracks> -<x> -35.1249 35.1249 -0.0114638 -0.0114638 -</x> -<y> -18.3795 18.3795 0.0945006 0.0945006 -</y> -<z> -7.44812 7.44812 5.03257 5.03257 -</z> -</RVx> - - -</Event> diff --git a/graphics/AtlantisJava/test/src/atlantis/AtlantisHeadlessTestCase.java b/graphics/AtlantisJava/test/src/atlantis/AtlantisHeadlessTestCase.java deleted file mode 100644 index 25f0a50137d..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/AtlantisHeadlessTestCase.java +++ /dev/null @@ -1,38 +0,0 @@ -package atlantis; - - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import testutils.TeeOutputStream; -import testutils.TestUtils; - -public class AtlantisHeadlessTestCase { - ByteArrayOutputStream stdOutCopy = new ByteArrayOutputStream(); - protected String eventFileName = null; // Event file to give on the command line - - /** Start Atlantis in headless mode. - */ - protected void startHeadlessMode() { - // Redirect standard output to ByteArrayOutputStream as well as normal System.out - TeeOutputStream teeOut = new TeeOutputStream(System.out,stdOutCopy); - System.setOut(new PrintStream(teeOut)); - - String atlantisHomeDir = Atlantis.getHomeDirectory(); - String testEventsDir = atlantisHomeDir+"/test/events"; - TestUtils.setPropertyIfNotSet("atlantis.test.events",testEventsDir); - - System.setProperty("java.awt.headless", "true"); - String[] args = {"--debug","DEBUG"}; - if (eventFileName!=null) { - String[] newArgs = new String[args.length+1]; - for (int i=0; i<args.length; ++i) { - newArgs[i] = args[i]; - } - String eventsDirectory = System.getProperty("atlantis.test.events"); - newArgs[args.length] = eventsDirectory+"/"+eventFileName; - args = newArgs; - } - Atlantis.main(args); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/HeadlessTest.java b/graphics/AtlantisJava/test/src/atlantis/HeadlessTest.java deleted file mode 100644 index 759ea917c95..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/HeadlessTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package atlantis; - -import org.fest.swing.timing.Condition; -import org.junit.Test; -import static org.fest.swing.timing.Pause.pause; -import static org.fest.swing.timing.Timeout.timeout; - -public class HeadlessTest extends AtlantisHeadlessTestCase { - - @Test - /** Start Atlantis in headless mode and make sure it doesn't crash part-way through. - * Atlantis.initAtlantis catches all Exceptions so we check for "Atlantis Ready" in - * the output console. - */ - public void testHeadlessMode() { - startHeadlessMode(); - pause(new Condition("output to contain \"Atlantis Ready\"") { - public boolean test() {return stdOutCopy.toString().contains("Atlantis Ready");} - },timeout(10000)); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/InconsistentEventTest.java b/graphics/AtlantisJava/test/src/atlantis/InconsistentEventTest.java deleted file mode 100644 index 5dbfffcd532..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/InconsistentEventTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package atlantis; - -import static org.fest.swing.timing.Pause.pause; -import static org.fest.swing.timing.Timeout.timeout; -import static org.junit.Assert.*; - -import org.fest.swing.timing.Condition; -import org.junit.Before; -import org.junit.Test; - -/** - * Test for bug#556, where a JiveXML file from Atlas release 17 causes an error - * on startup when the file is given on the command line, though not when it is - * opened after Atlantis has started. - * - * @author waugh - * - */ -public class InconsistentEventTest extends AtlantisHeadlessTestCase { - @Before - public void setUp() { - eventFileName = "rel17vtxEvent.xml"; - System.setProperty("java.awt.headless", "true"); - startHeadlessMode(); - } - - @Test - public void loadEvent() { - pause(new Condition("output to contain \"Atlantis Ready\"") { - public boolean test() {return stdOutCopy.toString().contains("Atlantis Ready");} - },timeout(10000)); - String output = stdOutCopy.toString(); - assertTrue("Could not find or parse event ",output.contains("Parsing event")); - assertFalse("Error reading event",output.contains("Can not read events")); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/NoTracksElementTest.java b/graphics/AtlantisJava/test/src/atlantis/NoTracksElementTest.java deleted file mode 100644 index e761ec038c1..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/NoTracksElementTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package atlantis; - -import static org.fest.swing.timing.Pause.pause; -import static org.fest.swing.timing.Timeout.timeout; -import static org.junit.Assert.*; - -import org.fest.swing.timing.Condition; -import org.junit.Before; -import org.junit.Test; - -/** - * Test for bug#552, where a JiveXML file contains a "numTracks" element but - * not a corresponding "tracks" element in the "RVx" section, as in some - * of the events from the Hypatia masterclass. - * - * @author waugh - * - */ -public class NoTracksElementTest extends AtlantisHeadlessTestCase { - @Before - public void setUp() { - eventFileName = "masterclassMuonEvents.zip"; - System.setProperty("java.awt.headless", "true"); - startHeadlessMode(); - } - - @Test - public void loadEvent() { - pause(new Condition("output to contain \"Atlantis Ready\"") { - public boolean test() {return stdOutCopy.toString().contains("Atlantis Ready");} - },timeout(10000)); - String output = stdOutCopy.toString(); - assertTrue("Could not find or parse event ",output.contains("Parsing event")); - assertFalse("Error when constructing RVx",output.contains("Error when constructing RVx")); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleBorderTest.java b/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleBorderTest.java deleted file mode 100644 index 9ec8b4504a8..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleBorderTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package atlantis.canvas; - -import static org.junit.Assert.*; - -import org.junit.Test; - -public class AScaleBorderTest { - - @Test - public void testGetNumDecimalPlaces() { - assertEquals("Wrong number of decimal places",0,AScaleBorder.getNumDecimalPlaces(1.0)); - assertEquals("Wrong number of decimal places",0,AScaleBorder.getNumDecimalPlaces(10.0)); - assertEquals("Wrong number of decimal places",1,AScaleBorder.getNumDecimalPlaces(0.5)); - assertEquals("Wrong number of decimal places",2,AScaleBorder.getNumDecimalPlaces(0.02)); - assertEquals("Wrong number of decimal places",0,AScaleBorder.getNumDecimalPlaces(-2.0)); - assertEquals("Wrong number of decimal places",1,AScaleBorder.getNumDecimalPlaces(-0.5)); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleTest.java b/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleTest.java deleted file mode 100644 index 75b0e7c5882..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/canvas/AScaleTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package atlantis.canvas; - -import static org.junit.Assert.*; - -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; - -import org.junit.Assert; -import org.junit.Test; - -public class AScaleTest { - - private static final double TOLERANCE = 0.00001; - - @Test - public void testCalculateScale() { - AScale scale = AScale.calculateScale(0, 10, 100, 3, 7, 0, 0, null); - for (double label : scale.labelValues) { - System.out.println("label = "+label); - } - for (double pos : scale.labelPositions) { - System.out.println("position: "+pos); - } - System.out.println("Primary tick marks = " + scale.primaryTicks); - GeneralPath primaryTicks = scale.primaryTicks; - PathIterator iterPTicks = primaryTicks.getPathIterator(null); - double[] coords = new double[2]; - int i = 0; - while (!iterPTicks.isDone()) { - int type = iterPTicks.currentSegment(coords); - System.out.format("point %d has type %d%n",i,type); - System.out.print("Coords: "); - for (int j=0; j<2; ++j) { - System.out.format(" %f", coords[j]); - } - System.out.println(); - i++; - iterPTicks.next(); - } - } - - @Test - public void testRoundNumbers() { - assertEquals("Wrong rounding", 5.0, AScale.getRoundNumber(9.0), TOLERANCE); - assertEquals("Wrong rounding", -5.0, AScale.getRoundNumber(-9.0), TOLERANCE); - assertEquals("Wrong rounding", 1.0, AScale.getRoundNumber(1.01), TOLERANCE); - assertEquals("Wrong rounding", 500.0, AScale.getRoundNumber(999.0), TOLERANCE); - } - - @Test - public void testGetScaleIntervals() { - double[] intervals, expectedValues; - intervals = AScale.getScaleIntervals(-11.0,11.0); - expectedValues = new double[] {10.0, 5.0, 1.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-110.0,110.0); - expectedValues = new double[] {100.0, 50.0, 10.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-51.0,51.0); - expectedValues = new double[] {50.0, 10.0, 5.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-50.0,50.0); - expectedValues = new double[] {50.0, 10.0, 5.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-49.0,49.0); - expectedValues = new double[] {40.0, 20.0, 5.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(1.0,49.0); - expectedValues = new double[] {20.0, 10.0, 2.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(1.0,101.0); - expectedValues = new double[] {50.0, 10.0, 5.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-101.0,-1.0); - expectedValues = new double[] {50.0, 10.0, 5.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(-9.5,9.5); - expectedValues = new double[] {5.0, 1.0, 0.5}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(19.0,61.0); - expectedValues = new double[] {20.0, 10.0, 2.0}; - assertArrayEquals("Wrong intervals", expectedValues, intervals, TOLERANCE); - intervals = AScale.getScaleIntervals(0.0,0.0); - assertNull("Intervals should be null for invalid input",intervals); - } - - @Test - public void testGetScaleValues() { - double[] values; - double[] expectedValues; - values = AScale.getScaleValues(0.0, 1.0, 1.0); - expectedValues = new double[] {0.0, 1.0}; - assertArrayEquals("Wrong scale values", expectedValues, values, TOLERANCE); - values = AScale.getScaleValues(-0.1, 1.1, 1.0); - expectedValues = new double[] {0.0, 1.0}; - assertArrayEquals("Wrong scale values", expectedValues, values, TOLERANCE); - } - - @Test - public void testInterpolate() { - float result = AScale.interpolate(0.5, 10.0, 0.0, 1.0); - assertEquals("Wrong interpolated value",5.0,result,TOLERANCE); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/canvas/AWindowTest.java b/graphics/AtlantisJava/test/src/atlantis/canvas/AWindowTest.java deleted file mode 100644 index 076249c9993..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/canvas/AWindowTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package atlantis.canvas; - -import static org.junit.Assert.*; - -import org.junit.Test; - -public class AWindowTest { - - @Test - public void test() { - AWindow window = new AWindow("dummyName","dummyProjection","dummyGroup",1); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/data/AHelixTest.java b/graphics/AtlantisJava/test/src/atlantis/data/AHelixTest.java deleted file mode 100644 index b55aecf4db0..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/data/AHelixTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -package atlantis.data; - -import atlantis.parameters.APar; -import atlantis.utils.AMath; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * - * @author ejansen - */ - -@RunWith(Parameterized.class) -public class AHelixTest { - - private static final double TOLERANCE = 0.001; - private static final double CURVATURE = 100/0.6; - - private float d0, z0, phi0, cotanTheta, pt; - private AHelix helix; - - public AHelixTest(float d0, float z0, float phi0, float cotanTheta, float pt) { - this.d0 = d0; - this.z0 = z0; - this.phi0 = phi0; - this.cotanTheta = cotanTheta; - this.pt = pt; - } - - @Parameters - public static Collection helices() { - Collection data = new ArrayList<Object[]>(); - - for (int charge=-1; charge<=1; charge+=2) { - for (float d0=-1.f; d0<=1.f; d0+=1.f) { - for (float phi0=-(float)Math.PI; phi0<Math.PI; phi0+=Math.PI/4) { - float pt = 20.f; - - data.add(new Object[] {d0, 0.0f, phi0, 0.5f, charge*pt}); - } - } - } - - return data; - } - - @Before - public void setUp() { - APar.constructDummyForTesting(); - helix = new AHelix(d0, z0, (float)Math.toDegrees(phi0), cotanTheta, pt); - } - - @Test - public void testBackwardsCompatibility() { - AOldHelix oldHelix = new AOldHelix(d0, z0, (float)Math.toDegrees(phi0), cotanTheta, pt); - - assertArrayEquals(oldHelix.getPar(), helix.getPar(), TOLERANCE); - assertEquals(oldHelix.eta, helix.eta(), TOLERANCE); - assertEquals(oldHelix.startPhi, helix.getAlphaMin(), TOLERANCE); - assertEquals(oldHelix.rhoVertex, helix.getRhoVtx(), TOLERANCE); - } - - @Test - public void testD0() { - // The alpha=0 point should be at distance d0 - double rho = helix.getRho(0); - assertEquals(Math.abs(d0), rho, TOLERANCE); - } - - @Test - public void testCenterCoordinates() { - // Check the center of the circle against a separate calculation - double charge = Math.signum(pt); - double rC = CURVATURE * Math.abs(pt); - double xC = (rC - charge * d0) * Math.cos(phi0 - charge * Math.PI / 2); - double yC = (rC - charge * d0) * Math.sin(phi0 - charge * Math.PI / 2); - assertEquals(xC, helix.getXc(), TOLERANCE); - assertEquals(yC, helix.getYc(), TOLERANCE); - } - - @Test - public void testEndPoint() { - // End the helix at 1m from the beam pipe and check that the last point is at 1m - double alphaMax = helix.getAlphaCylinder(100., 250.); - assertEquals(100., helix.getRho(alphaMax), TOLERANCE); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/data/AOldHelixTest.java b/graphics/AtlantisJava/test/src/atlantis/data/AOldHelixTest.java deleted file mode 100644 index 39b5077be33..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/data/AOldHelixTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package atlantis.data; - -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; - -import atlantis.parameters.APar; - -import static java.lang.Math.PI; - -public class AOldHelixTest { - /** Arbitrary tolerance for floating-point comparisons */ - private static final double TOLERANCE = 0.00001; - - @Before - public void setUp() throws Exception { - APar.constructDummyForTesting(); - } - - @Test - public void helixFromNominalVertex() { - // Input: rhoVtx,phiVtx,zVtx,pt,phi,eta,charge - // Start at (0,0,0), pt=2, eta=0 so perp to z axis - // phi = 0 (arbitrary), positive charge (+1) - // Expect all params 0 except ptInverse = 0.5 - AOldHelix helix = new AOldHelix(0,0,0,2,0,0,1); - assertHelixParametersEqual("Wrong helix parameters.",0,0,0,0,0.5,helix.getPar()); - // charge = -1 so ptInverse changes sign - helix = new AOldHelix(0,0,0,2,0,0,-1); - assertHelixParametersEqual("Wrong helix parameters.",0,0,0,0,-0.5,helix.getPar()); - } - - @Test - public void helixStartingAtPCA() { - /* Input: rhoVtx,phiVtx,zVtx,pt,phi,eta,charge - * Circular track (pz=0) starting at point closest to beam, at non-zero z. - * Perpendicular to line from beam to starting vertex: phi = phiVtx + PI/2 - * Start in upwards direction, from point to the right of the beam axis, */ - AOldHelix helix = new AOldHelix(0.1f,0,0.25f,1,(float)(PI/2),0,1); - double[] actualParameters = helix.getPar(); - /* Closest approach is where we started so phi at PCA is same as phi at start. - * Note that d0 is negative. */ - assertHelixParametersEqual("",-0.1,0.25,PI/2,0,1,actualParameters); - /* Same starting position and direction, but negative particle. - * No change to d0, which is still negative. */ - helix = new AOldHelix(0.1f,0,0.25f,1,(float)(PI/2),0,-1); - actualParameters = helix.getPar(); - assertHelixParametersEqual("",-0.1,0.25,PI/2,0,-1,actualParameters); - /* - * Positive and negative particles, now starting in same direction (upwards) - * but from a starting position to the left of the beam. - * This time d0 is positive. - */ - helix = new AOldHelix(0.1f,(float)PI,0.25f,1,(float)(PI/2),0,1); - actualParameters = helix.getPar(); - assertHelixParametersEqual("",0.1,0.25,PI/2,0,1,actualParameters); - helix = new AOldHelix(0.1f,(float)PI,0.25f,1,(float)(PI/2),0,-1); - actualParameters = helix.getPar(); - assertHelixParametersEqual("",0.1,0.25,PI/2,0,-1,actualParameters); - } - - protected void assertHelixParametersEqual(String message, double d0, double z0, - double phi0, double tL, double ptInverse, double[] actualParameters) { - assertD0Equals(message,d0,actualParameters); - assertZ0Equals(message,z0,actualParameters); - assertPhi0Equals(message,phi0,actualParameters); - assertTLEquals(message,tL,actualParameters); - assertPtInverseEquals(message,ptInverse,actualParameters); - } - - protected void assertD0Equals(String message, double expected, double[] actualParameters) { - assertEquals(message+" Wrong d0.",expected,actualParameters[0],TOLERANCE); - } - - protected void assertZ0Equals(String message, double expected, double[] actualParameters) { - assertEquals(message+" Wrong z0.",expected,actualParameters[1],TOLERANCE); - } - - protected void assertPhi0Equals(String message, double expected, double[] actualParameters) { - assertEquals(message+" Wrong phi0.",expected,actualParameters[2],TOLERANCE); - } - - protected void assertTLEquals(String message, double expected, double[] actualParameters) { - assertEquals(message+" Wrong tL.",expected,actualParameters[3],TOLERANCE); - } - - protected void assertPtInverseEquals(String message, double expected, double[] actualParameters) { - assertEquals(message+" Wrong ptInverse.",expected,actualParameters[4],TOLERANCE); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/event/AEventInfoTest.java b/graphics/AtlantisJava/test/src/atlantis/event/AEventInfoTest.java deleted file mode 100644 index 8c541eecb5e..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/event/AEventInfoTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package atlantis.event; - -import static org.junit.Assert.*; - -import org.junit.Test; - -public class AEventInfoTest { - private static final long eventNumber=12345; - private static final long runNumber=123; - - @Test - public void testAEventInfoCreation() { - AEventInfo e = new AEventInfo(eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - assertAEventInfo(e,eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - } - - /** - * Create AEventInfo object with null or other special values for parameters. - */ - @Test - public void testAEventInfoCreationChecks() { - AEventInfo e1 = new AEventInfo(eventNumber,runNumber,null,null,null,null); - assertAEventInfo(e1,eventNumber,runNumber,"n/a","n/a","default","default"); - AEventInfo e2 = new AEventInfo(eventNumber,runNumber,null,null,"blah-1","blah-1"); - assertAEventInfo(e2,eventNumber,runNumber,"n/a","n/a","default","default"); - } - - @Test - public void testAEventCopyConstructor() { - AEventInfo e0 = new AEventInfo(eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - AEventInfo e = new AEventInfo(e0); - assertAEventInfo(e,eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - } - - @Test - public void testHashCode() { - // Check different run/event numbers give different hash codes - AEventInfo e1 = new AEventInfo(eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - AEventInfo e2 = new AEventInfo(eventNumber+1,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - AEventInfo e3 = new AEventInfo(eventNumber,runNumber+1,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - int h1 = e1.hashCode(); - int h2 = e2.hashCode(); - int h3 = e3.hashCode(); - assertTrue("hash codes should be different for e1,e2",h2!=h1); - assertTrue("hash codes should be different for e1,e3",h1!=h3); - assertTrue("hash codes should be different for e2,e3",h2!=h3); - } - - @Test - public void testEqualsAEventInfo() { - AEventInfo e1a = new AEventInfo(eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - AEventInfo e1b = new AEventInfo(eventNumber,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - AEventInfo e2 = new AEventInfo(eventNumber+1,runNumber,"TIME","SOURCE","LUMIBLOCK","EVENTPROPERTIES"); - assertTrue("equals should return true for e1a,e1b",e1a.equals(e1b)); - assertFalse("equals should return false for e1a,e2",e1a.equals(e2)); - } - - /** Check values in AEventInfo object */ - private void assertAEventInfo(AEventInfo eventInfo, long event, long run, String time, String source, String lumiBlock, String eventProperties) { - assertEquals("event number not set correctly",event,eventInfo.getEventNumber()); - assertEquals("run number not set correctly",run,eventInfo.getRunNumber()); - assertEquals("time not set correctly",time,eventInfo.getDateTime()); - assertEquals("source not set correctly",source,eventInfo.getSourceName()); - assertEquals("source not set correctly",lumiBlock,eventInfo.getLumiBlock()); - assertEquals("event properties not set correctly",eventProperties,eventInfo.getEventProperties()); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/graphics/ACoordTest.java b/graphics/AtlantisJava/test/src/atlantis/graphics/ACoordTest.java deleted file mode 100644 index 24f5de94ef3..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/graphics/ACoordTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package atlantis.graphics; - -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import atlantis.parameters.APar; -import static org.junit.Assert.*; - -public class ACoordTest { - private static final double TOLERANCE = 0.001; - - @BeforeClass - public static void setUpOnce() throws Exception { - APar.constructDummyForTesting(); - } - - @Test - public void constructACoordWithOnePoint() { - ACoord coord = new ACoord(0.0, 0.0, 0); - Point2D.Double point = new Point2D.Double(0.0,0.0); - assertContainsPoints(coord,point); - } - - @Test - public void constructACoordWithOneArrayOfPoints() { - double[] h = {0.0, 1.0, -1.0, 2.5}; - double[] v = {0.0, 0.0, 1.0, -2.5}; - ACoord coord = new ACoord(h,v); - Point2D.Double[] expectedPoints = createPointsArray(h,v); - assertContainsPoints(coord,expectedPoints); - } - - /** - * Currently just checks first set of points, i.e. x = hv[0][0][i], y = [1][0][i] - * @param coord - * @param points - */ - protected static void assertContainsPoints(ACoord coord, Point2D.Double... points) { - double[] x = coord.hv[0][0]; - double[] y = coord.hv[1][0]; - int xLen = x.length; - int yLen = y.length; - assertTrue(String.format( - "Numbers of x and y coordinates are not equal: %d, %d",xLen,yLen), - xLen==yLen); - assertTrue(String.format( - "Wrong number of points: expected %d, found %d",points.length,xLen), - points.length==xLen); - int i=0; - for (Point2D.Double point : points) { - Point2D.Double hvPoint = new Point2D.Double(x[i],y[i]); - double distance = hvPoint.distance(point); - if (distance>TOLERANCE) { - fail(String.format("Didn't find expected points. First difference is point %d: expected (%f,%f), found (%f,%f)", - i,point.x,point.y,hvPoint.x,hvPoint.y)); - } - i++; - } - } - - private Point2D.Double[] createPointsArray(double[] x, double[] y) { - Point2D.Double[] points = new Point2D.Double[x.length]; - for (int i=0; i<x.length; i++) { - points[i] = new Point2D.Double(x[i], y[i]); - } - return points; - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/list/AListManagerTest.java b/graphics/AtlantisJava/test/src/atlantis/list/AListManagerTest.java deleted file mode 100644 index 3b2e70bd5bf..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/list/AListManagerTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package atlantis.list; - -import static org.junit.Assert.*; - -import org.junit.Test; - -import atlantis.utils.A4Vector; - -public class AListManagerTest { - private static final double TOLERANCE = 0.00001; - - @Test - public void testTotalEt() { - Summarizer summ = new Summarizer(); - A4Vector pos = new A4Vector(3.0,0,0,4.0); - String posDescription = "A positive 4vector"; - A4Vector neg = new A4Vector(-3.0,0,0,4.0); - String negDescription = "A negative 4vector"; - summ.addAndGetInfo(pos, posDescription); - summ.addAndGetInfo(neg, negDescription); - double totalEt = summ.getTotalEt(); - assertEquals(totalEt,10.0,TOLERANCE); - } - - @Test - public void testTotalPt() { - Summarizer summ = new Summarizer(); - A4Vector pos = new A4Vector(3.0,0,0,4.0); - String posDescription = "A positive 4vector"; - A4Vector neg = new A4Vector(-3.0,0,0,4.0); - String negDescription = "A negative 4vector"; - summ.addAndGetInfo(pos, posDescription); - summ.addAndGetInfo(neg, negDescription); - double totalPt = summ.getTotalPt(); - assertEquals(totalPt,0.0,TOLERANCE); - } - - @Test - public void testTotalMt() { - Summarizer summ = new Summarizer(); - A4Vector pos = new A4Vector(3.0,0,0,4.0); - String posDescription = "A positive 4vector"; - A4Vector neg = new A4Vector(-3.0,0,0,4.0); - String negDescription = "A negative 4vector"; - summ.addAndGetInfo(pos, posDescription); - summ.addAndGetInfo(neg, negDescription); - double totalMt = summ.getTotalMt(); - assertEquals(totalMt,10.0,TOLERANCE); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/parameters/AAbstractParameterTest.java b/graphics/AtlantisJava/test/src/atlantis/parameters/AAbstractParameterTest.java deleted file mode 100644 index c2df08a2a55..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/parameters/AAbstractParameterTest.java +++ /dev/null @@ -1,120 +0,0 @@ -package atlantis.parameters; - -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; - -import testutils.AtlantisInit; - -import atlantis.canvas.ACanvas; - -/** - * Tests for AAbstractParameter. - * @author waugh - * - */ -public class AAbstractParameterTest { - /** Arbitrary tolerance for floating-point comparisons */ - private static final double TOLERANCE = 0.00001; - - private AAbstractParameter parameter; - - @Before - public void setUp() throws Exception { - AtlantisInit.init(); - APar.constructDummyForTesting(); - ACanvas.constructDummyForTesting(); - parameter = new AAbstractParameter("name", "screen name", null, 0, 0, null, null, false, false, false, 0, 0, 0) { - {wCount = 1; data = new AParameterData(wCount);} - public void setD(double v) {} - public void setI(int v) {} - public void refresh() {} - }; - } - - @Test - public void testAAbstractParameter() { - assertNotNull(parameter); - } - - @Test - public void testSaveAndRestoreDefaults() { - // Access member variables directly since set and other methods rely on - // information about existing windows. Rely on uninitialized - // APar.currentIndex being zero. - - // Set value, status etc. - parameter.valueType = AAbstractParameter.FLOAT; - parameter.data.setValue(1.0); - parameter.data.setStatus(false); - parameter.data.setOperator(""); - parameter.range = AAbstractParameter.resolvePossibleValues("0:10", AAbstractParameter.FLOAT); - parameter._setD(1.0); - parameter.hasStatus = true; - parameter.setStatus(true); - parameter._setOperator("A"); // no restriction on value of operator? - parameter.setScope(AAbstractParameter.LOCAL); - // Save current settings as defaults then change them - parameter.saveDefaults(); - parameter._setD(2.0); - parameter.setStatus(false); - parameter._setOperator("B"); - parameter.setScope(AAbstractParameter.GLOBAL); - // Make sure the current settings have changed - double value = parameter.getD(); - boolean status = parameter.getStatus(); - String operator = parameter.getOperator(); - int scope = parameter.getScope(); - assertEquals("parameter value not changed from default",2.0,value,TOLERANCE); - assertEquals("parameter status not changed from default",false,status); - assertEquals("parameter operator not changed from default","B",operator); - assertEquals("parameter scope not changed from default",AAbstractParameter.GLOBAL,scope); - // Then restore defaults and verify the original settings are back - parameter.restoreDefaults(); - double restoredValue = parameter.getD(); - boolean restoredStatus = parameter.getStatus(); - String restoredOperator = parameter.getOperator(); - int restoredScope = parameter.getScope(); - assertEquals("parameter value not set to default",1.0,restoredValue,TOLERANCE); - assertEquals("parameter status not set to default",true,restoredStatus); - assertEquals("parameter operator not set to default","A",restoredOperator); - assertEquals("parameter scope not set to default",AAbstractParameter.LOCAL,restoredScope); - } - - @Test - public void testPossibleValuesFloat() { - parameter.valueType = AAbstractParameter.FLOAT; - String possibleValues = "1.0:2.0,3.0:4.5"; - parameter.range = AAbstractParameter.resolvePossibleValues(possibleValues, AAbstractParameter.FLOAT); - assertValidValue(parameter,possibleValues,1.2); - assertValidValue(parameter,possibleValues,4.4); - assertInvalidValue(parameter,possibleValues,0.9); - assertInvalidValue(parameter,possibleValues,2.1); - assertInvalidValue(parameter,possibleValues,9.9); - assertInvalidValue(parameter,possibleValues,-1.2); - } - - @Test - public void testPossibleValuesInt() { - parameter.valueType = AAbstractParameter.INT; - String possibleValues = "1,2,4"; - parameter.range = AAbstractParameter.resolvePossibleValues(possibleValues, AAbstractParameter.FLOAT); - assertValidValue(parameter,possibleValues,1); - assertValidValue(parameter,possibleValues,2); - assertValidValue(parameter,possibleValues,4); - assertInvalidValue(parameter,possibleValues,3); - assertInvalidValue(parameter,possibleValues,-1); - } - - private static void assertValidValue(AAbstractParameter parameter, String possibleValues, double value) { - boolean validated = parameter.validateValue(value); - assertTrue(String.format("Value %f incorrectly fails validation with possible values %s",value,possibleValues),validated); - } - - private static void assertInvalidValue(AAbstractParameter parameter, String possibleValues, double value) { - boolean validated = parameter.validateValue(value); - assertFalse(String.format("Value %f incorrectly passes validation with possible values %s",value,possibleValues),validated); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/parameters/AParameterDataTest.java b/graphics/AtlantisJava/test/src/atlantis/parameters/AParameterDataTest.java deleted file mode 100644 index afab7d5293a..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/parameters/AParameterDataTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package atlantis.parameters; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * We don't test the methods that call APar to find out the current window, - * which is not defined in unit tests. - * - * @author waugh - * - */ -public class AParameterDataTest { - private static final int numWindows = 3; - private static final double TOLERANCE = 0.001; - - private AParameterData paramData; - - @Before - public void setUp() { - APar.constructDummyForTesting(); - paramData = new AParameterData(numWindows); - } - - @Test - /** - * Check default values for all windows. - */ - public void constructDefault() { - for (int iWindow=0; iWindow<numWindows; ++iWindow) { - AParameterState state = paramData.getState(iWindow); - assertValuesEqual("Default state is wrong.",0.0,false,"",state); - } - } - - @Test - /** - * Copy values from window 1 to window 2. - */ - public void copyValues() { - paramData.setValue(1, 1.0); - paramData.setStatus(1, true); - paramData.setOperator(1, "+"); - paramData.copy(1, 2); - AParameterState state = paramData.getState(2); - assertValuesEqual("Copied state is wrong.",1.0,true,"+",state); - } - - @Test - public void saveAndRestoreValues() { - paramData.setValue(1, 1.0); - paramData.setStatus(1, true); - paramData.setOperator(1, "+"); - paramData.saveDefaults(); - paramData.setValue(1, 2.0); - paramData.setStatus(1, false); - paramData.setOperator(1, "-"); - AParameterState state = paramData.getState(1); - assertValuesEqual("Set state is wrong.",2.0,false,"-",state); - paramData.restoreDefaults(); - state = paramData.getState(1); - assertValuesEqual("Restored state is wrong.",1.0,true,"+",state); - } - - @Test - public void testGlobalize() { - paramData.setValue(1, 1.0); - paramData.setStatus(1, true); - paramData.setOperator(1, "+"); - paramData.globalize(1); - for (int iWindow=0; iWindow<numWindows; ++iWindow) { - AParameterState state = paramData.getState(iWindow); - assertValuesEqual("State wrong after globalization.",1.0,true,"+",state); - } - } - - private static void assertValuesEqual(String message, double value, boolean status, String operator, AParameterState actual) { - assertEquals(message+" Wrong value.",value,actual.value,TOLERANCE); - assertEquals(message+" Wrong status.",status,actual.status); - assertEquals(message+" Wrong operator.",operator,actual.operator); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/utils/A3VectorTest.java b/graphics/AtlantisJava/test/src/atlantis/utils/A3VectorTest.java deleted file mode 100644 index 0b88546b31d..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/utils/A3VectorTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package atlantis.utils; - -import static org.junit.Assert.*; - -import org.junit.Test; - -/** - * Tests for A3Vector class. Initial rather clumsy implementation just to get started. - * @author waugh - * - */ -public class A3VectorTest { - /** Arbitrary tolerance for floating-point comparisons */ - private static final double TOLERANCE = 0.00001; - - @Test - public void testA3Vector() { - A3Vector v = new A3Vector(); - assertA3VectorEquals("three-vector",0.0,0.0,0.0,v,TOLERANCE); - } - - @Test - public void testA3VectorDoubleDoubleDouble() { - A3Vector v = new A3Vector(1.0,-2.5,3.3); - assertA3VectorEquals("three-vector",1.0,-2.5,3.3,v,TOLERANCE); - } - - @Test - public void testFromEtaPhiR() { - A3Vector v = A3Vector.fromEtaPhiR(0.0, Math.PI, 2.0); - assertA3VectorEquals("three-vector",-2.0,0.0,0.0,v,TOLERANCE); - } - - @Test - public void testFromRhoPhiZ() { - A3Vector v = A3Vector.fromRhoPhiZ(1.0, Math.PI, 1.0); - assertA3VectorEquals("three-vector",-1.0,0.0,1.0,v,TOLERANCE); - } - - @Test - public void testGetNormalized() { - A3Vector v0 = new A3Vector(1.0,1.0,1.0); - double a = 1 / Math.sqrt(3); - A3Vector v = v0.getNormalized(); - assertA3VectorEquals("three-vector",a,a,a,v,TOLERANCE); - } - - @Test - public void testNormalize() { - A3Vector v = new A3Vector(1.0,1.0,1.0); - v.normalize(); - double a = 1 / Math.sqrt(3); - assertA3VectorEquals("three-vector",a,a,a,v,TOLERANCE); - } - - @Test - public void testMagnitude() { - A3Vector v = new A3Vector(1.0,1.0,1.0); - double r = v.magnitude(); - double rExpected = Math.sqrt(3); - assertEquals("magnitude calculation",rExpected,r,TOLERANCE); - } - - @Test - public void testScale() { - A3Vector v = new A3Vector(1.0,1.0,1.0); - v.scale(0.5); - assertA3VectorEquals("three-vector",0.5,0.5,0.5,v,TOLERANCE); - } - - @Test - public void testAdd() { - A3Vector v = new A3Vector(1.0,2.0,3.0); - A3Vector v0 = new A3Vector(0.0,1.0,-0.5); - v.add(v0); - assertA3VectorEquals("three-vector",1.0,3.0,2.5,v,TOLERANCE); - } - - @Test - public void testSubtract() { - A3Vector v = new A3Vector(1.0,2.0,3.0); - A3Vector v0 = new A3Vector(0.0,1.0,-0.5); - v.subtract(v0); - assertA3VectorEquals("three-vector",1.0,1.0,3.5,v,TOLERANCE); - } - - /** - * Check given A3Vector has expected components - */ - private static void assertA3VectorEquals(String message, double x, double y, double z, - A3Vector v, double delta) { - if (Math.abs(v.x-x)>delta || Math.abs(v.y-y)>delta || - Math.abs(v.z-z)>delta) { - String vExpected = String.format("<%f,%f,%f>", x,y,z); - String vActual = String.format("<%f,%f,%f>", v.x,v.y,v.z); - String summary = message+" "+ - "expected:"+vExpected+" but was:"+vActual; - fail(summary); - } - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/utils/A4VectorTest.java b/graphics/AtlantisJava/test/src/atlantis/utils/A4VectorTest.java deleted file mode 100644 index 03fb94f2001..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/utils/A4VectorTest.java +++ /dev/null @@ -1,128 +0,0 @@ -package atlantis.utils; - - -import static org.junit.Assert.*; - -import org.junit.Test; - -/** - * Tests for A4Vector class. - */ -public class A4VectorTest { - /** Arbitrary tolerance for floating-point comparisons */ - private static final double TOLERANCE = 0.00001; - - @Test - public void testA4Vector() { - A4Vector v = new A4Vector(); - assertA4VectorEquals("construct zero 4-vector",0.0,0.0,0.0,0.0,v,TOLERANCE); - } - - @Test - public void testA4VectorDoubleDoubleDoubleDouble() { - // fourth argument is mass, not energy - // use 3-4-5 numbers for simple arithmetic - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - assertA4VectorEquals("construct 4-vector",2.0,2.0,-1.0,5.0,v,TOLERANCE); - } - - @Test - public void testA4VectorA3VectorDouble() { - A3Vector v3 = new A3Vector(2.0,2.0,-1.0); - A4Vector v = new A4Vector(v3,4.0); - assertA4VectorEquals("construct 4-vector",2.0,2.0,-1.0,5.0,v,TOLERANCE); - } - - @Test - public void testSet() { - A4Vector v = new A4Vector(); - v.set(2.0,2.0,-1.0,4.0); - assertA4VectorEquals("set 4-vector",2.0,2.0,-1.0,5.0,v,TOLERANCE); - } - - @Test - public void testSetPtEtaPhiM() { - A4Vector v1 = new A4Vector(); - v1.setPtEtaPhiM(1.0, 0.0, 0.0, 0.0); - assertA4VectorEquals("set 4-vector",1.0,0.0,0.0,1.0,v1,TOLERANCE); - // test with negative pT - A4Vector v2 = new A4Vector(); - v2.setPtEtaPhiM(-1.0, 0.0, 0.0, 0.0); - assertA4VectorEquals("set 4-vector",1.0,0.0,0.0,1.0,v2,TOLERANCE); - } - - @Test - public void testGetP() { - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - double p = v.getP(); - assertEquals(3.0,p,TOLERANCE); - } - - @Test - public void testGetPt() { - A4Vector v = new A4Vector(0.3,0.4,-1.0,4.0); - double pt = v.getPt(); - assertEquals(0.5,pt,TOLERANCE); - } - - @Test - public void testGetE() { - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - double e = v.getE(); - assertEquals(5.0,e,TOLERANCE); - } - - @Test - public void testgetEt() { - A4Vector v = new A4Vector(1.0,1.0,2.0,3.0); - double et = v.getEt(); - double x = Math.sqrt(5.0); - assertEquals(x,et,TOLERANCE); - } - - @Test - public void testGetMass() { - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - double m = v.getMass(); - assertEquals(4.0,m,TOLERANCE); - } - - @Test - public void testGetMt() { - A4Vector v = new A4Vector(1.0,1.0,2.0,3.0); - double mt = v.getMt(); - double x = Math.sqrt(3.0); - assertEquals(x,mt,TOLERANCE); - } - - @Test - public void testAddDoubleDoubleDoubleDouble() { - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - v.add(2.2,2.2,-1.1,4.4); - assertA4VectorEquals("add 4-vectors",4.2,4.2,-2.1,10.5,v,TOLERANCE); - } - - @Test - public void testAddA4Vector() { - A4Vector v = new A4Vector(2.0,2.0,-1.0,4.0); - A4Vector v2 = new A4Vector(2.2,2.2,-1.1,4.4); - v.add(v2); - assertA4VectorEquals("add 4-vectors",4.2,4.2,-2.1,10.5,v,TOLERANCE); - } - - /** - * Check given A4Vector has expected components - */ - private static void assertA4VectorEquals(String message, double px, double py, double pz, double e, - A4Vector v, double delta) { - if (Math.abs(v.px-px)>delta || Math.abs(v.py-py)>delta || - Math.abs(v.pz-pz)>delta || Math.abs(v.e-e)>delta) { - String vExpected = String.format("<%f,%f,%f,%f>", px,py,pz,e); - String vActual = String.format("<%f,%f,%f,%f>", v.px,v.py,v.pz,v.e); - String summary = message+" "+ - "expected:"+vExpected+" but was:"+vActual; - fail(summary); - } - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/utils/AIdRangeTest.java b/graphics/AtlantisJava/test/src/atlantis/utils/AIdRangeTest.java deleted file mode 100644 index cae60427953..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/utils/AIdRangeTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package atlantis.utils; - -import static org.junit.Assert.assertEquals; -import org.junit.Test; - -/** - * Test for the IdHelper range class used to represent - * possible values of an identifier field. - * - * @author Eric Jansen - */ -public class AIdRangeTest { - - public AIdRangeTest() {} - - @Test - public void testEmptyRange() throws Exception { - AIdRange a = new AIdRange(); - AIdRange b = new AIdRange(new int[] {1, 2}); - - a.add(b); - assertEquals(a, b); - - b.add(a); - assertEquals(a, b); - } - - @Test - public void testContainsRange() throws Exception { - AIdRange a = new AIdRange(1, 3); - AIdRange b = new AIdRange(new int[] {1, 2, 4}); - AIdRange c = new AIdRange(1, 2); - - assert(a.contains(c)); - assert(b.contains(c)); - assert(!a.contains(b)); - assert(!b.contains(a)); - } - - @Test - public void testContainsValue() throws Exception { - AIdRange a = new AIdRange(-5, 5); - AIdRange b = new AIdRange(new int[] {-1, 3, 9}); - - assert(!a.contains(-6)); - assert(a.contains(-5)); - assert(a.contains(2)); - assert(a.contains(5)); - assert(!a.contains(6)); - - assert(b.contains(-1)); - assert(!b.contains(2)); - assert(b.contains(3)); - assert(b.contains(9)); - } - - @Test - public void testAddRange() throws Exception { - AIdRange a = new AIdRange(new int[] {-1, 0, 1, 2, 5, 6}); - AIdRange b = new AIdRange(new int[] {-1, 1, 2, 6}); - AIdRange c = new AIdRange(new int[] {0, 1, 2, 5}); - - b.add(c); - assert(a.equals(b)); - - AIdRange d = new AIdRange(-5, 5); - AIdRange e = new AIdRange(new int[] {-5, -4}); - AIdRange f = new AIdRange(-3, 5); - - e.add(f); - assert(d.equals(e)); - - AIdRange g = new AIdRange(0, 2); - AIdRange h = new AIdRange(new int[] {0, 1}); - AIdRange i = new AIdRange(new int[] {1, 2}); - - h.add(i); - assert(g.equals(h)); // comparing [ 0 -> 2 ] to [ 0 1 2 ] - } - - @Test - public void testToString() throws Exception { - AIdRange a = new AIdRange(-2, 15); - AIdRange b = new AIdRange(new int[] {2, 3, 5}); - AIdRange c = new AIdRange(); - assertEquals("[ -2 -> 15 ]", a.toString()); - assertEquals("[ 2 3 5 ]", b.toString()); - assertEquals("[ ]", c.toString()); - } -} diff --git a/graphics/AtlantisJava/test/src/atlantis/utils/AMathTest.java b/graphics/AtlantisJava/test/src/atlantis/utils/AMathTest.java deleted file mode 100644 index 8bb888866ac..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/utils/AMathTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * - */ -package atlantis.utils; - -import static org.junit.Assert.*; -import org.junit.Test; - -import static java.lang.Math.PI; - -/** - * @author waugh - * - */ -public class AMathTest { - /** Arbitrary tolerance for floating-point comparisons */ - private static final double TOLERANCE = 0.00001; - - /** - * Test method for {@link atlantis.utils.AMath#nearestPhiDegrees(double)}. - */ - @Test - public void testNearestPhiDegreesDouble() { - assertEquals("Wrong value for phi",0.,AMath.nearestPhiDegrees(0.),TOLERANCE); - assertEquals("Wrong value for phi",0.,AMath.nearestPhiDegrees(360.),TOLERANCE); - assertEquals("Wrong value for phi",180.,AMath.nearestPhiDegrees(180.),TOLERANCE); - assertEquals("Wrong value for phi",1.,AMath.nearestPhiDegrees(1.),TOLERANCE); - assertEquals("Wrong value for phi",359.,AMath.nearestPhiDegrees(-1.),TOLERANCE); - } - - /** - * Test method for {@link atlantis.utils.AMath#nearestPhiRadians(double)}. - */ - @Test - public void testNearestPhiRadiansDouble() { - assertEquals("Wrong value for phi",0.,AMath.nearestPhiRadians(0.),TOLERANCE); - assertEquals("Wrong value for phi",0.,AMath.nearestPhiRadians(2*PI),TOLERANCE); - assertEquals("Wrong value for phi",PI,AMath.nearestPhiRadians(PI),TOLERANCE); - assertEquals("Wrong value for phi",0.1,AMath.nearestPhiRadians(0.1),TOLERANCE); - assertEquals("Wrong value for phi",2*PI-0.1,AMath.nearestPhiRadians(-0.1),TOLERANCE); - } - - /** - * Test method for {@link atlantis.utils.AMath#nearestPhiDegrees(double, double)}. - */ - @Test - public void testNearestPhiDegreesDoubleDouble() { - double phiMid = 360; // range [180,540) - assertEquals("Wrong value for phi",180.,AMath.nearestPhiDegrees(180.0,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",180.,AMath.nearestPhiDegrees(540.0,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",360.,AMath.nearestPhiDegrees(360.0,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",361.,AMath.nearestPhiDegrees(1.0,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",539.,AMath.nearestPhiDegrees(179.0,phiMid),TOLERANCE); - } - - /** - * Test method for {@link atlantis.utils.AMath#nearestPhiRadians(double, double)}. - */ - @Test - public void testNearestPhiRadiansDoubleDouble() { - double phiMid = 2*PI; // range [180,540) - assertEquals("Wrong value for phi",PI,AMath.nearestPhiRadians(PI,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",PI,AMath.nearestPhiRadians(PI,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",2*PI,AMath.nearestPhiRadians(2*PI,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",2*PI+0.1,AMath.nearestPhiRadians(0.1,phiMid),TOLERANCE); - assertEquals("Wrong value for phi",3*PI-0.1,AMath.nearestPhiRadians(PI-0.1,phiMid),TOLERANCE); - } - -} diff --git a/graphics/AtlantisJava/test/src/atlantis/utils/ANewIdHelperTest.java b/graphics/AtlantisJava/test/src/atlantis/utils/ANewIdHelperTest.java deleted file mode 100644 index bad4515a8e3..00000000000 --- a/graphics/AtlantisJava/test/src/atlantis/utils/ANewIdHelperTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package atlantis.utils; - -import atlantis.globals.AGlobals; -import atlantis.utils.xml.AXMLErrorHandler; -import java.io.InputStream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import org.junit.BeforeClass; -import org.junit.Test; -import org.w3c.dom.Document; -import testutils.AtlantisInit; - -/** - * Tests for the ANewIdHelper class. Tests are performed by fully - * decoding compact identifiers of several subsystems. - * - * @author Eric Jansen - */ -public class ANewIdHelperTest { - - public ANewIdHelperTest() {} - - @BeforeClass - public static void setUpClass() throws Exception { - AtlantisInit.init(); - String geometryBase = AGlobals.instance().getHomeDirectory() + "geometry/"; - InputStream isIdDict = AUtilities.getFileAsStream(geometryBase + "ATLAS_IDS.xml"); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(true); - DocumentBuilder parser = factory.newDocumentBuilder(); - parser.setErrorHandler(new AXMLErrorHandler()); - - Document xmlDictDoc = parser.parse(isIdDict, geometryBase); - ANewIdHelper.construct(xmlDictDoc.getDocumentElement()); - - System.out.println("The loaded identifier structure is:\n" - + ANewIdHelper.instance().getDictionary("ATLAS")); - } - - @Test - public void testPixel() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("InnerDetector/Pixel/negative_endcap/0/15/0/86/76", idHelper.getFullIdentifier(8661285809946624l)); - } - - @Test - public void testSCT() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("InnerDetector/SCT/negative_endcap/1/23/2/0/683", idHelper.getFullIdentifier(137085611)); - assertEquals("InnerDetector/SCT/positive_endcap/8/50/0/1/609", idHelper.getFullIdentifier(219756129)); - } - - @Test - public void testTRT() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("InnerDetector/TRT/negative_endcap/2/2/6/7", idHelper.getFullIdentifier(270604512)); - assertEquals("InnerDetector/TRT/negative_endcap/11/1/7/9", idHelper.getFullIdentifier(280010016)); - assertEquals("InnerDetector/TRT/negative_barrel/9/0/18/7", idHelper.getFullIdentifier(311445728)); - assertEquals("InnerDetector/TRT/positive_barrel/5/2/22/10", idHelper.getFullIdentifier(340875584)); - assertEquals("InnerDetector/TRT/positive_endcap/7/10/1/13", idHelper.getFullIdentifier(376767904)); - assertEquals("InnerDetector/TRT/positive_endcap/31/13/7/18", idHelper.getFullIdentifier(402038336)); - } - - @Test - public void testLAr() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("LArCalorimeter/LArEM/negative-endcap-outer-wheel/2/1/37/72", idHelper.getFullIdentifier(3225785215439863808l)); - assertEquals("LArCalorimeter/LArEM/positive-barrel/1/0/167/15", idHelper.getFullIdentifier(765546014)); - assertEquals("LArCalorimeter/LArEM/negative-barrel/2/0/4/113", idHelper.getFullIdentifier(759171298)); - } - - @Test - public void testTILE() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("TileCalorimeter/Barrel/positive/28/0/1/0/0", idHelper.getFullIdentifier(1149698064)); - assertEquals("TileCalorimeter/Extended-barrel/negative/0/14/0/0/0", idHelper.getFullIdentifier(1207963136)); - } - - @Test - public void testHEC() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("LArCalorimeter/LArHEC/negative-endcap-outer-wheel/1/0/5/22", idHelper.getFullIdentifier(815095808)); - assertEquals("LArCalorimeter/LArHEC/negative-endcap-outer-wheel/2/0/6/22", idHelper.getFullIdentifier(823746560)); - assertEquals("LArCalorimeter/LArHEC/positive-endcap-outer-wheel/2/1/2/20", idHelper.getFullIdentifier(860438528)); - assertEquals("LArCalorimeter/LArHEC/positive-endcap-outer-wheel/3/0/8/0", idHelper.getFullIdentifier(866123776)); - assertEquals("LArCalorimeter/LArHEC/positive-endcap-outer-wheel/3/1/3/29", idHelper.getFullIdentifier(869126144)); - } - - @Test - public void testFCAL() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("LArCalorimeter/LArFCAL/negative-endcap-outer-wheel/1/4/13", idHelper.getFullIdentifier(873046016)); - assertEquals("LArCalorimeter/LArFCAL/negative-endcap-outer-wheel/1/45/0", idHelper.getFullIdentifier(878313472)); - assertEquals("LArCalorimeter/LArFCAL/positive-endcap-outer-wheel/1/3/0", idHelper.getFullIdentifier(906362880)); - assertEquals("LArCalorimeter/LArFCAL/positive-endcap-outer-wheel/2/23/14", idHelper.getFullIdentifier(917487616)); - assertEquals("LArCalorimeter/LArFCAL/positive-endcap-outer-wheel/3/15/15", idHelper.getFullIdentifier(924835840)); - } - - @Test - public void testMDT() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("MuonSpectrometer/BIL/-6/1/MDT/1/3/1", idHelper.getFullIdentifier(6922067811640541184l)); - assertEquals("MuonSpectrometer/BIL/-6/2/MDT/2/2/34", idHelper.getFullIdentifier(1611748384)); - assertEquals("MuonSpectrometer/BIL/1/5/MDT/1/2/3", idHelper.getFullIdentifier(1615597632)); - assertEquals("MuonSpectrometer/BOL/1/5/MDT/1/2/7", idHelper.getFullIdentifier(1682706624)); - assertEquals("MuonSpectrometer/EOL/2/3/MDT/2/1/6", idHelper.getFullIdentifier(1884438688)); - assertEquals("MuonSpectrometer/EIS/-1/6/MDT/2/3/36", idHelper.getFullIdentifier(2050843744)); - } - - @Test - public void testRPC() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("MuonSpectrometer/BML/-6/6/RPC/1/2/2/2/0/4", idHelper.getFullIdentifier(1645583372)); - } - - @Test - public void testCSC() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("MuonSpectrometer/CSS/-1/1/CSC/2/4/0/6", idHelper.getFullIdentifier(2064056960)); - } - - @Test - public void testTGC() throws Exception { - ANewIdHelper idHelper = ANewIdHelper.instance(); - assertEquals("MuonSpectrometer/T4E/1/10/TGC/2/1/15", idHelper.getFullIdentifier(2035436656)); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/AAssert.java b/graphics/AtlantisJava/test/src/guitest/AAssert.java deleted file mode 100644 index 0010a959487..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/AAssert.java +++ /dev/null @@ -1,28 +0,0 @@ -package guitest; - -import static org.junit.Assert.*; - -import java.util.Arrays; - -/** - * Useful assertion methods for tests. - * @author waugh - * - */ -public class AAssert { - public static void assertArrayEqualsIgnoreOrder(String message, - Object[] expecteds, Object[] actuals) { - int lengthExp = expecteds.length; - int lengthAct = actuals.length; - if (lengthAct!=lengthExp) fail(message+ - ": array lengths differed, "+ - String.format("expected.length=%d,actual.length=%d",lengthExp,lengthAct)); - Object[] copyExpecteds = new Object[lengthExp]; - System.arraycopy(expecteds,0,copyExpecteds,0,lengthExp); - Object[] copyActuals = new Object[lengthAct]; - System.arraycopy(actuals,0,copyActuals,0,lengthAct); - Arrays.sort(copyExpecteds); - Arrays.sort(copyActuals); - assertArrayEquals(message,copyExpecteds,copyActuals); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/AtlantisGUIFixture.java b/graphics/AtlantisJava/test/src/guitest/AtlantisGUIFixture.java deleted file mode 100644 index 5d49d4fae4e..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/AtlantisGUIFixture.java +++ /dev/null @@ -1,141 +0,0 @@ -package guitest; - -import java.awt.Dialog; -import java.io.File; - -import org.fest.swing.core.BasicComponentFinder; -import org.fest.swing.core.ComponentFinder; -import org.fest.swing.core.ComponentFoundCondition; -import org.fest.swing.core.Robot; -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.core.matcher.FrameMatcher; -import org.fest.swing.core.matcher.JButtonMatcher; -import org.fest.swing.data.TableCell; -import org.fest.swing.data.TableCellByColumnId; -import org.fest.swing.exception.ComponentLookupException; -import org.fest.swing.fixture.DialogFixture; -import org.fest.swing.fixture.FrameFixture; -import org.fest.swing.fixture.JButtonFixture; -import org.fest.swing.fixture.JFileChooserFixture; -import org.fest.swing.fixture.JTabbedPaneFixture; -import org.fest.swing.fixture.JTableCellFixture; -import org.fest.swing.fixture.JTableFixture; -import org.fest.swing.fixture.JToolBarFixture; -import org.fest.swing.timing.Pause; - -import static org.junit.Assert.*; - -import atlantis.gui.AGUI; - -/** - * Fixture for testing the Atlantis GUI (class AGUI). - * @author waugh - * - */ -public class AtlantisGUIFixture extends FrameFixture { - private Robot robot; - private ComponentFinder finder; - private FrameFixture guiFixture; - - /** - * Construct and return AtlantisGUIFixture using specified robot. - * @param robot the robot to use - * @return fixture for the Atlantis GUI - */ - public static AtlantisGUIFixture getFixture(Robot robot) { - ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy(); - FrameMatcher matcherGuiTitle = FrameMatcher.withTitle("Atlantis GUI"); - ComponentFoundCondition guiFound = new ComponentFoundCondition("Atlantis GUI found", - finder, matcherGuiTitle); - Pause.pause(guiFound,30000); - AGUI gui = (AGUI) guiFound.found(); - return new AtlantisGUIFixture(robot,gui); - } - - /** - * Construct AtlantisGUIFixture. - * @param robot - */ - public AtlantisGUIFixture(Robot robot, AGUI gui) { - super(robot,gui); - this.robot = robot; - this.finder = BasicComponentFinder.finderWithCurrentAwtHierarchy(); - this.guiFixture = new FrameFixture(robot,gui); - } - - /** Find AParametersTable for given supergroup and group */ - protected JTableFixture findParametersTable(String superGroup, String group) { - JTabbedPaneFixture tabs = guiFixture.tabbedPane("parameterGroups"); - tabs.selectTab(superGroup); - JTabbedPaneFixture subTabs = guiFixture.tabbedPane(superGroup); - subTabs.selectTab(group); - JTableFixture parametersTable = guiFixture.table(group); - return parametersTable; - } - - /** - * Find table cell containing given parameter. - * @param superGroup - * @param group - * @param parameter - * @return - */ - protected JTableCellFixture findParameterCell(String superGroup, String group, String parameter) { - JTableFixture table = findParametersTable(superGroup,group); - TableCell cellName = table.cell(parameter); - int row = cellName.row; // Row containing cell with specified name - JTableCellFixture cellValue = table.cell(TableCellByColumnId.row(row).columnId("Value")); - return cellValue; - } - - /** Find button in GUI with given text */ - protected JButtonFixture findGuiButton(String text) { - JButtonMatcher matcher = JButtonMatcher.withText(text); - return guiFixture.button(matcher); - } - - /** - * Open file using GUI - * @param file event file - */ - protected void openEventFile(File file) { - guiFixture.menuItemWithPath("File", "Read Event Locally").click(); - // Sometimes we have more than one "Open" dialog, but should be only one showing - Dialog dialogOpen = finder.find(DialogMatcher.withTitle("Open").andShowing()); - DialogFixture fixtureDialogOpen = new DialogFixture(robot,dialogOpen); - JFileChooserFixture fileChooser = fixtureDialogOpen.fileChooser(); - fileChooser.selectFile(file); - fileChooser.approve(); - } - - /** - * Open file using GUI and fail if there is a problem - * @param file event file - */ - protected void openEventFileAndCheck(File file) { - openEventFile(file); - try { - Dialog dialogInvalid = finder.find(DialogMatcher.withTitle("Invalid source")); - fail("Failed to open event: found invalid source dialog"); - } - catch (ComponentLookupException e) { - // OK: no warning dialog! - } - } - - /** - * Get a fixture for the event source tool bar. - * @return - */ - public JToolBarFixture findEventSourceToolBar() { - return new JToolBarFixture(robot,"Atlantis event source toolbar"); - } - - /** - * Get a fixture for the interactions tool bar. - * @return - */ - public JToolBarFixture findInteractionToolBar() { - return new JToolBarFixture(robot,"Atlantis interaction toolbar"); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/AtlantisGuiTestCase.java b/graphics/AtlantisJava/test/src/guitest/AtlantisGuiTestCase.java deleted file mode 100644 index 6c69d170207..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/AtlantisGuiTestCase.java +++ /dev/null @@ -1,100 +0,0 @@ -package guitest; - -import java.awt.Frame; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import org.fest.swing.core.BasicComponentFinder; -import org.fest.swing.core.BasicRobot; -import org.fest.swing.core.ComponentFinder; -import org.fest.swing.core.Robot; -import org.fest.swing.core.matcher.FrameMatcher; -import org.fest.swing.edt.FailOnThreadViolationRepaintManager; -import org.fest.swing.fixture.FrameFixture; -import org.fest.swing.security.NoExitSecurityManagerInstaller; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; - -import testutils.AtlantisInit; -import testutils.TeeOutputStream; -import testutils.TestUtils; - -import atlantis.Atlantis; -import atlantis.globals.AGlobals; - -public class AtlantisGuiTestCase { - protected Robot robot; - protected ComponentFinder finder; - protected FrameFixture canvasFixture; - protected AtlantisGUIFixture guiFixture; - ByteArrayOutputStream stdOutCopy = new ByteArrayOutputStream(); - private static NoExitSecurityManagerInstaller noExitSecurityManagerInstaller; - - /** Time [ms] to pause at end of test for easier viewing */ - protected long pauseLength = 0; - - /** - * Install NoExitSecurityManager because JUnit gets upset if the forked JVM exits - */ - @BeforeClass - public static void setUpOnce() { - noExitSecurityManagerInstaller = NoExitSecurityManagerInstaller.installNoExitSecurityManager(); - } - - @AfterClass - public static void tearDownOnce() { - noExitSecurityManagerInstaller.uninstall(); - } - - @Before - public void setUp() { - startAtlantis(); - } - - protected void startAtlantis() { - AtlantisInit.init(); - String atlantisHomeDir=AGlobals.instance().getHomeDirectory(); - String testEventsDir = atlantisHomeDir+"/test/events"; - TestUtils.setPropertyIfNotSet("atlantis.test.events",testEventsDir); - - // Omit this for now since Atlantis main does not do set-up on EDT - // FailOnThreadViolationRepaintManager.install(); - - finder = BasicComponentFinder.finderWithCurrentAwtHierarchy(); - robot = BasicRobot.robotWithCurrentAwtHierarchy(); - - // Redirect standard output to ByteArrayOutputStream as well as normal System.out - TeeOutputStream teeOut = new TeeOutputStream(System.out,stdOutCopy); - System.setOut(new PrintStream(teeOut)); - - // Launch Atlantis application - String[] args = {"--debug","DEBUG"}; - Atlantis.main(args); - // Don't use ACrashReporter to handle uncaught exceptions - Thread.setDefaultUncaughtExceptionHandler(null); - - // Get fixtures for the GUI and Canvas - guiFixture = AtlantisGUIFixture.getFixture(robot); - FrameMatcher matcherCanvasTitle = FrameMatcher.withTitle("Atlantis Canvas"); - // Cannot cast to ACanvas because the ACanvas is actually a JPanel that creates its own - // parent JFrame. - Frame canvas = finder.find(matcherCanvasTitle); - canvasFixture = new FrameFixture(robot,canvas); - } - - @After - public void tearDown() { - pause(pauseLength); - } - - /** Pause for a second so can see end result on screen */ - protected static void pause(long duration) { - try { - Thread.sleep(duration); - } catch (InterruptedException e) { - // allow to return if interrupted - } - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/EnumeratorParameterTest.java b/graphics/AtlantisJava/test/src/guitest/EnumeratorParameterTest.java deleted file mode 100644 index 5b9c2fb1c64..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/EnumeratorParameterTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package guitest; - -import org.junit.Test; -import org.fest.swing.fixture.JComboBoxFixture; -import org.fest.swing.fixture.JTableCellFixture; - -public class EnumeratorParameterTest extends AtlantisGuiTestCase { - - @Test - public void test() { - JTableCellFixture cell = guiFixture.findParameterCell("MuonDet","Track","Track Collections"); - cell.click(); - JComboBoxFixture comboBox = guiFixture.comboBox("Track Collections"); - String[] contents = comboBox.contents(); - comboBox.selectItem("All"); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/EventSourceToolBarTest.java b/graphics/AtlantisJava/test/src/guitest/EventSourceToolBarTest.java deleted file mode 100644 index 15bb2f5481a..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/EventSourceToolBarTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package guitest; - -import org.fest.swing.fixture.JToolBarFixture; -import org.junit.Test; - -public class EventSourceToolBarTest extends AtlantisGuiTestCase { - @Test - public void testEventSourceToolBar() { - JToolBarFixture toolBarFixture = guiFixture.findEventSourceToolBar(); - toolBarFixture.radioButton("Sequential mode").click(); - toolBarFixture.radioButton("Loop mode").click(); - toolBarFixture.radioButton("Random mode").click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/InteractionToolBarTest.java b/graphics/AtlantisJava/test/src/guitest/InteractionToolBarTest.java deleted file mode 100644 index ffe8a982a40..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/InteractionToolBarTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package guitest; - -import java.awt.event.KeyEvent; - -import org.fest.swing.fixture.JComboBoxFixture; -import org.fest.swing.fixture.JTextComponentFixture; -import org.fest.swing.fixture.JToolBarFixture; -import org.junit.Test; - -import static guitest.AAssert.*; - -public class InteractionToolBarTest extends AtlantisGuiTestCase { - @Test - public void testInteractionToolBar() { - JToolBarFixture toolBarFixture = guiFixture.findInteractionToolBar(); - - toolBarFixture.toggleButton("ZMR").click(); - - toolBarFixture.toggleButton("RubberBand").click(); - JComboBoxFixture rubberBandComboBox = toolBarFixture.comboBox(); - String[] listRubberBand = rubberBandComboBox.contents(); - String[] expectedRubberBand = {"RectangleYX","RotatedRectangle","Parallelogram", - "Square","XSkew","YSkew","XSlice","YSlice"}; - assertArrayEqualsIgnoreOrder("Didn't find expected rubberband list",expectedRubberBand,listRubberBand); - - toolBarFixture.toggleButton("Pick").click(); - JComboBoxFixture pickComboBox = toolBarFixture.comboBox(); - String[] listPick = pickComboBox.contents(); - String[] expectedPick = {"Event Data","Detectors"}; - assertArrayEqualsIgnoreOrder("Didn't find expected pick list",expectedPick,listPick); - - toolBarFixture.toggleButton("SyncCursors").click(); - - toolBarFixture.toggleButton("FishEye").click(); - JTextComponentFixture textBox = toolBarFixture.textBox(); - textBox.setText(""); // deleteText() does not work - textBox.enterText("5.0"); // this does not press "enter", so... - textBox.pressAndReleaseKeys(KeyEvent.VK_ENTER); // we do it here - toolBarFixture.checkBox().click(); // turn off fish-eye - toolBarFixture.checkBox().click(); // turn it on again - - toolBarFixture.toggleButton("Clock").click(); - toolBarFixture.checkBox().click(); // turn on clock transformation - toolBarFixture.checkBox().click(); // turn it on again - - toolBarFixture.toggleButton("Scale").click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/LoadEventFailureTest.java b/graphics/AtlantisJava/test/src/guitest/LoadEventFailureTest.java deleted file mode 100644 index 48e2cabb35b..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/LoadEventFailureTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package guitest; - -import java.awt.Dialog; -import java.io.File; -import org.junit.Test; -import static org.junit.Assert.*; -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.exception.ComponentLookupException; - -public class LoadEventFailureTest extends AtlantisGuiTestCase { - @Test - public void loadEvent() { - guiFixture.openEventFile(new File("/nosuchfile")); - try { - Dialog dialogInvalid = finder.find(DialogMatcher.withTitle("Invalid source")); - // OK, correctly failed to open file - } - catch (ComponentLookupException e) { - fail("Did not find invalid source dialog when opening non-existent event file"); - } - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/LoadEventTest.java b/graphics/AtlantisJava/test/src/guitest/LoadEventTest.java deleted file mode 100644 index 7bfcaef27e6..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/LoadEventTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package guitest; - -import static org.junit.Assert.*; - -import java.awt.Dialog; -import java.io.File; - -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.exception.ComponentLookupException; -import org.junit.Test; - -public class LoadEventTest extends AtlantisGuiTestCase { - @Test - public void loadEvent() { - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFile(new File(eventsDirectory,"muonCollections.xml")); - try { - Dialog dialogInvalid = finder.find(DialogMatcher.withTitle("Invalid source")); - fail("Failed to open event: found invalid source dialog"); - } - catch (ComponentLookupException e) { - // OK - } - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/LoadEventWithInvalidRecVertexDataTest.java b/graphics/AtlantisJava/test/src/guitest/LoadEventWithInvalidRecVertexDataTest.java deleted file mode 100644 index 7cb70d7e2c5..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/LoadEventWithInvalidRecVertexDataTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package guitest; - -import static org.junit.Assert.*; - -import java.awt.Dialog; -import java.io.File; - -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.exception.ComponentLookupException; -import org.junit.Test; - -public class LoadEventWithInvalidRecVertexDataTest extends AtlantisGuiTestCase { - @Test - public void loadEvent() { - String output = stdOutCopy.toString(); - assertTrue("Output does not contain \"Atlantis Ready\"",output.contains("Atlantis Ready")); - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFile(new File(eventsDirectory,"rvxInconsistentEvent.xml")); - try { - Dialog dialogInvalid = finder.find(DialogMatcher.withTitle("Invalid source")); - fail("Failed to open event: found invalid source dialog"); - } - catch (ComponentLookupException e) { - // OK - } - output = stdOutCopy.toString(); - assertTrue("Failed to detect inconsistent track numbers",output.contains("RVx: numbers of tracks are inconsistent.")); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/LoadEventWithValidRecVertexDataTest.java b/graphics/AtlantisJava/test/src/guitest/LoadEventWithValidRecVertexDataTest.java deleted file mode 100644 index 846af19bf93..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/LoadEventWithValidRecVertexDataTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package guitest; - -import static org.junit.Assert.*; - -import java.awt.Dialog; -import java.io.File; - -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.exception.ComponentLookupException; -import org.junit.Test; - -public class LoadEventWithValidRecVertexDataTest extends AtlantisGuiTestCase { - @Test - public void loadEvent() { - String output = stdOutCopy.toString(); - assertTrue("Output does not contain \"Atlantis Ready\"",output.contains("Atlantis Ready")); - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFile(new File(eventsDirectory,"rvxEvent.xml")); - try { - Dialog dialogInvalid = finder.find(DialogMatcher.withTitle("Invalid source")); - fail("Failed to open event: found invalid source dialog"); - } - catch (ComponentLookupException e) { - // OK - } - output = stdOutCopy.toString(); - assertFalse("Inconsistent data incorrectly detected",output.contains("RVx: numbers of tracks are inconsistent.")); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/LoadEventsManyTimesTest.java b/graphics/AtlantisJava/test/src/guitest/LoadEventsManyTimesTest.java deleted file mode 100644 index d395260b2f4..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/LoadEventsManyTimesTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package guitest; - -import java.io.File; -import org.junit.Test; -import org.fest.swing.fixture.JButtonFixture; -import org.fest.swing.fixture.JToolBarFixture; - -public class LoadEventsManyTimesTest extends AtlantisGuiTestCase { - - private static final int numEvents = 9; - private static final int numRepeats = 3; - - @Test(timeout=45000) - public void readEvents() { - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFileAndCheck(new File(eventsDirectory,"masterclassMuonEvents.zip")); - JToolBarFixture toolBarFixture = guiFixture.findEventSourceToolBar(); - JButtonFixture nextButton = toolBarFixture.button("nextButton"); - JButtonFixture previousButton = toolBarFixture.button("previousButton"); - for (int i=0; i<numRepeats; i++) { - for (int iEvent=0; iEvent<(numEvents-1); iEvent++) { - System.out.println("Click number "+iEvent); - nextButton.click(); - } - for (int iEvent=0; iEvent<(numEvents-1); iEvent++) { - System.out.println("Click number "+iEvent); - previousButton.click(); - } - } - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsEmptyTest.java b/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsEmptyTest.java deleted file mode 100644 index dddeb873b61..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsEmptyTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package guitest; - -import java.io.File; -import org.junit.Test; -import org.fest.swing.fixture.JComboBoxFixture; -import org.fest.swing.fixture.JTableCellFixture; -import static guitest.AAssert.*; - -/** - * Check list of muon track collections for Trac bug #507 - * Should be empty in empty event! - * @author waugh - * - */ -public class MuonTrackCollectionsEmptyTest extends AtlantisGuiTestCase { - @Test - public void loadEvents() { - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFileAndCheck(new File(eventsDirectory,"muonCollections.xml")); - checkMuonTrackCollections("ConvertedMBoyTracks", - "ConvertedMBoyMuonSpectroOnlyTracks", - "All"); - guiFixture.openEventFileAndCheck(new File(eventsDirectory,"emptyEvent.xml")); - checkMuonTrackCollections("None"); - } - - private void checkMuonTrackCollections(String... expected) { - String[] contents = getMuonTrackCollections(); - assertArrayEqualsIgnoreOrder("Didn't find expected collections",expected,contents); - } - - private String[] getMuonTrackCollections() { - JTableCellFixture cell = guiFixture.findParameterCell("MuonDet","Track","Track Collections"); - cell.click(); - JComboBoxFixture comboBox = guiFixture.comboBox("Track Collections"); - String[] contents = comboBox.contents(); - return contents; - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsTest.java b/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsTest.java deleted file mode 100644 index 8ee5814913a..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/MuonTrackCollectionsTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package guitest; - -import java.io.File; -import org.junit.Test; -import org.fest.swing.fixture.JComboBoxFixture; -import org.fest.swing.fixture.JTableCellFixture; -import static guitest.AAssert.*; - -/** - * Check list of muon track collections for Trac bug #507 - * @author waugh - * - */ -public class MuonTrackCollectionsTest extends AtlantisGuiTestCase { - @Test - public void loadEvents() { - String eventsDirectory = System.getProperty("atlantis.test.events"); - guiFixture.openEventFileAndCheck(new File(eventsDirectory,"muonCollections.xml")); - checkMuonTrackCollections("ConvertedMBoyTracks", - "ConvertedMBoyMuonSpectroOnlyTracks", - "All"); - guiFixture.openEventFileAndCheck(new File(eventsDirectory,"muonCollections2.xml")); - checkMuonTrackCollections("ConvertedMBoyTracks", - "ConvertedMuIdCBTracks", - "All"); - } - - private void checkMuonTrackCollections(String... expected) { - String[] contents = getMuonTrackCollections(); - assertArrayEqualsIgnoreOrder("Didn't find expected collections",expected,contents); - } - - private String[] getMuonTrackCollections() { - JTableCellFixture cell = guiFixture.findParameterCell("MuonDet","Track","Track Collections"); - cell.click(); - JComboBoxFixture comboBox = guiFixture.comboBox("Track Collections"); - String[] contents = comboBox.contents(); - return contents; - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/OverlayTest.java b/graphics/AtlantisJava/test/src/guitest/OverlayTest.java deleted file mode 100644 index d35ca958746..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/OverlayTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package guitest; - -import org.junit.Test; -import org.fest.swing.data.TableCellByColumnId; -import org.fest.swing.fixture.JTableCellFixture; -import org.fest.swing.fixture.JTableFixture; - -public class OverlayTest extends AtlantisGuiTestCase { - - @Test - public void testOverlay() { - JTableFixture table = guiFixture.findParametersTable("Appearance","Logo"); - int row = 0; - JTableCellFixture check = table.cell(TableCellByColumnId.row(row).columnId("Name")); - //check the box to show logo - check.click(); - //change the x position - JTableCellFixture logox = guiFixture.findParameterCell("Appearance","Logo", "Logo X"); - logox.enterValue("0.5\n"); - //resize - JTableCellFixture size = guiFixture.findParameterCell("Appearance","Logo", "Logo Size"); - size.enterValue("0.7\n"); - size.click(); - //now uncheck the box - check.click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/ProjectionsTest.java b/graphics/AtlantisJava/test/src/guitest/ProjectionsTest.java deleted file mode 100644 index 3b32476ab89..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/ProjectionsTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package guitest; - -import org.fest.swing.fixture.JPanelFixture; -import org.junit.Test; - -import static atlantis.utils.AMath.*; // for Greek letters - -public class ProjectionsTest extends AtlantisGuiTestCase { - @Test - public void testWindowControls() { - JPanelFixture windowControls = guiFixture.panel("windowControl"); - windowControls.label("W").click(); - guiFixture.findParametersTable("Projection","YX").click(); - guiFixture.findParametersTable("Projection",PHI+ETA).click(); - guiFixture.findParametersTable("Projection",RHO+"Z").click(); - guiFixture.findParametersTable("Projection",PHI+RHO).click(); - guiFixture.findParametersTable("Projection",PHI+"Z").click(); - guiFixture.findParametersTable("Projection","X'Z").click(); - guiFixture.findParametersTable("Projection","Y'Z").click(); - guiFixture.findParametersTable("Projection","3DBox").click(); - guiFixture.findParametersTable("Projection","LegoPlot").click(); - guiFixture.findParametersTable("Projection","Event Info").click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/ReadNextAndPreviousEventTest.java b/graphics/AtlantisJava/test/src/guitest/ReadNextAndPreviousEventTest.java deleted file mode 100644 index 4849224a4a4..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/ReadNextAndPreviousEventTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package guitest; - -import java.awt.Dialog; - -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.core.matcher.JButtonMatcher; -import org.fest.swing.fixture.DialogFixture; -import org.fest.swing.fixture.JButtonFixture; -import org.fest.swing.fixture.JToolBarFixture; -import org.junit.Test; - -public class ReadNextAndPreviousEventTest extends AtlantisGuiTestCase { - - @Test - public void readNextThenPreviousEvent() { - JToolBarFixture toolBarFixture = guiFixture.findEventSourceToolBar(); - JButtonFixture nextButton = toolBarFixture.button("nextButton"); - JButtonFixture previousButton = toolBarFixture.button("previousButton"); - nextButton.click(); - previousButton.click(); - guiFixture.menuItemWithPath("File", "Exit").click(); - DialogMatcher matcherConfirmExit = DialogMatcher.withTitle("Exit Atlantis"); - Dialog dialogConfirmExit = finder.find(matcherConfirmExit); - DialogFixture fixtureDialogConfirmExit = new DialogFixture(robot,dialogConfirmExit); - // fixtureDialogConfirmExit.button(JButtonMatcher.withText("Yes")).click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/StartAndExitTest.java b/graphics/AtlantisJava/test/src/guitest/StartAndExitTest.java deleted file mode 100644 index ec93dce67c4..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/StartAndExitTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package guitest; - -import java.awt.Dialog; -import org.junit.Test; -import org.fest.swing.core.matcher.DialogMatcher; -import org.fest.swing.core.matcher.JButtonMatcher; -import org.fest.swing.fixture.DialogFixture; - -public class StartAndExitTest extends AtlantisGuiTestCase { - - @Test - public void atlantisStarts() { - guiFixture.menuItemWithPath("File", "Exit").click(); - DialogMatcher matcherConfirmExit = DialogMatcher.withTitle("Exit Atlantis"); - Dialog dialogConfirmExit = finder.find(matcherConfirmExit); - DialogFixture fixtureDialogConfirmExit = new DialogFixture(robot,dialogConfirmExit); - fixtureDialogConfirmExit.button(JButtonMatcher.withText("Yes")).click(); - } -} diff --git a/graphics/AtlantisJava/test/src/guitest/TabsTest.java b/graphics/AtlantisJava/test/src/guitest/TabsTest.java deleted file mode 100644 index 11ba9148e3b..00000000000 --- a/graphics/AtlantisJava/test/src/guitest/TabsTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package guitest; - -import org.junit.Test; -import org.fest.swing.fixture.JTableFixture; - -public class TabsTest extends AtlantisGuiTestCase { - - @Test - public void testTabs() { - JTableFixture table = guiFixture.findParametersTable("MuonDet","Segment"); - // Click on cell: does nothing but checks we have found required cell - table.cell(table.cell("Segment Collections")).click(); - guiFixture.findParametersTable("Projection","YX"); - guiFixture.findParametersTable("Data","Data"); - guiFixture.findParametersTable("Cuts","Calo"); - guiFixture.findParametersTable("InDet","SpacePoint"); - guiFixture.findParametersTable("Calo","HEC"); - guiFixture.findParametersTable("MuonDet","MDT"); - guiFixture.findParametersTable("Objects","Muon"); - guiFixture.findParametersTable("Detector","Geo"); - guiFixture.findParametersTable("Appearance","Logo"); - } -} diff --git a/graphics/AtlantisJava/test/src/testutils/AtlantisInit.java b/graphics/AtlantisJava/test/src/testutils/AtlantisInit.java deleted file mode 100644 index d1732aec9f8..00000000000 --- a/graphics/AtlantisJava/test/src/testutils/AtlantisInit.java +++ /dev/null @@ -1,20 +0,0 @@ -package testutils; - -import atlantis.Atlantis; -import atlantis.globals.AGlobals; - -/** - * Do Atlantis initialization for tests: things that would be set up by main() in the - * full application, and require access to protected Atlantis members. - * - * @author waugh - * - */ -public class AtlantisInit extends Atlantis { - - public static void init() { - String homeDirectory = Atlantis.getHomeDirectory(); - AGlobals.instance().setHomeDirectory(homeDirectory); - } - -} diff --git a/graphics/AtlantisJava/test/src/testutils/TeeOutputStream.java b/graphics/AtlantisJava/test/src/testutils/TeeOutputStream.java deleted file mode 100644 index e490cc19821..00000000000 --- a/graphics/AtlantisJava/test/src/testutils/TeeOutputStream.java +++ /dev/null @@ -1,34 +0,0 @@ -package testutils; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * Wraps any number of OutputStreams and directs input to all of them. - * @author waugh - * - */ -public class TeeOutputStream extends OutputStream { - private List<OutputStream> streams; - - /** - * Create a TeeOutputStream that writes to the given OutputStreams. - * @param outputStreams the OutputStreams to be wrapped - */ - public TeeOutputStream(OutputStream... outputStreams) { - streams = new ArrayList<OutputStream>(); - for (OutputStream stream : outputStreams) { - streams.add(stream); - } - } - - @Override - public void write(int b) throws IOException { - for (OutputStream stream : streams) { - stream.write(b); - } - } - -} diff --git a/graphics/AtlantisJava/test/src/testutils/TestUtils.java b/graphics/AtlantisJava/test/src/testutils/TestUtils.java deleted file mode 100644 index d9b58032914..00000000000 --- a/graphics/AtlantisJava/test/src/testutils/TestUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package testutils; - -public class TestUtils { - - /** - * Set system property if it doesn't already have a value. - * Useful in providing sensible defaults for properties set in build file when - * using Ant. - * @param key - * @param value - */ - public static void setPropertyIfNotSet(String key, String value) { - String old = System.getProperty(key); - if (old==null) System.setProperty(key,value); - } - -} -- GitLab